/* * * Copyright (c) 2020-2023 Project CHIP Authors * Copyright (c) 2013-2017 Nest Labs, Inc. * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file * This file implements unit tests for the CHIP TLV implementation. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace chip; using namespace chip::TLV; enum { TestProfile_1 = 0xAABBCCDD, TestProfile_2 = 0x11223344, TestProfile_3 = 0x11223355 }; // clang-format off static const char sLargeString [] = "START..." "!123456789ABCDEF@123456789ABCDEF#123456789ABCDEF$123456789ABCDEF%123456789ABCDEF^123456789ABCDEF&123456789ABCDEF*123456789ABCDEF" "01234567(9ABCDEF01234567)9ABCDEF01234567-9ABCDEF01234567=9ABCDEF01234567[9ABCDEF01234567]9ABCDEF01234567;9ABCDEF01234567'9ABCDEF" "...END"; // clang-format on void TestAndOpenContainer(TLVReader & reader, TLVType type, Tag tag, TLVReader & containerReader) { EXPECT_EQ(reader.GetType(), type); EXPECT_EQ(reader.GetTag(), tag); EXPECT_EQ(reader.GetLength(), 0u); CHIP_ERROR err = reader.OpenContainer(containerReader); EXPECT_EQ(err, CHIP_NO_ERROR); EXPECT_EQ(containerReader.GetContainerType(), type); } template void TestAndEnterContainer(T & t, TLVType type, Tag tag, TLVType & outerContainerType) { EXPECT_EQ(t.GetType(), type); EXPECT_EQ(t.GetTag(), tag); EXPECT_EQ(t.GetLength(), 0u); TLVType expectedContainerType = t.GetContainerType(); CHIP_ERROR err = t.EnterContainer(outerContainerType); EXPECT_EQ(err, CHIP_NO_ERROR); EXPECT_EQ(outerContainerType, expectedContainerType); EXPECT_EQ(t.GetContainerType(), type); } template void TestNext(T & t) { CHIP_ERROR err = t.Next(); EXPECT_EQ(err, CHIP_NO_ERROR); } void TestSkip(TLVReader & reader) { CHIP_ERROR err = reader.Skip(); EXPECT_EQ(err, CHIP_NO_ERROR); } void TestMove(TLVUpdater & updater) { CHIP_ERROR err = updater.Move(); EXPECT_EQ(err, CHIP_NO_ERROR); } template void TestEnd(T & t) { CHIP_ERROR err; err = t.Next(); EXPECT_EQ(err, CHIP_END_OF_TLV); } void TestEndAndCloseContainer(TLVReader & reader, TLVReader & containerReader) { CHIP_ERROR err; TestEnd(containerReader); err = reader.CloseContainer(containerReader); EXPECT_EQ(err, CHIP_NO_ERROR); } template void TestEndAndExitContainer(T & t, TLVType outerContainerType) { CHIP_ERROR err; TestEnd(t); err = t.ExitContainer(outerContainerType); EXPECT_EQ(err, CHIP_NO_ERROR); EXPECT_EQ(t.GetContainerType(), outerContainerType); } #define TEST_GET(s, type, tag, expectedVal, expectedErr) \ do \ { \ EXPECT_EQ(s.GetType(), type); \ EXPECT_EQ(s.GetTag(), tag); \ EXPECT_EQ(s.GetLength(), 0u); \ \ decltype(expectedVal) __val; \ CHIP_ERROR __err = s.Get(__val); \ EXPECT_EQ(__err, expectedErr); \ if (__err == CHIP_NO_ERROR) \ { \ EXPECT_EQ(__val, expectedVal); \ } \ } while (false) #define TEST_GET_NOERROR(s, type, tag, expectedVal) TEST_GET(s, type, tag, expectedVal, CHIP_NO_ERROR) void ForEachElement(TLVReader & reader, void * context, void (*cb)(TLVReader & reader, void * context)) { CHIP_ERROR err; while (true) { err = reader.Next(); if (err == CHIP_END_OF_TLV) { return; } EXPECT_EQ(err, CHIP_NO_ERROR); if (cb != nullptr) { cb(reader, context); } if (TLVTypeIsContainer(reader.GetType())) { TLVType outerContainerType; err = reader.EnterContainer(outerContainerType); EXPECT_EQ(err, CHIP_NO_ERROR); ForEachElement(reader, context, cb); err = reader.ExitContainer(outerContainerType); EXPECT_EQ(err, CHIP_NO_ERROR); } } } /** * context */ struct TestTLVContext { int mEvictionCount = 0; uint32_t mEvictedBytes = 0; }; class TestTLV : public ::testing::Test { public: static TestTLVContext ctx; static void SetUpTestSuite() { ASSERT_EQ(chip::Platform::MemoryInit(), CHIP_NO_ERROR); } static void TearDownTestSuite() { chip::Platform::MemoryShutdown(); } }; TestTLVContext TestTLV::ctx; void TestNull(TLVReader & reader, Tag tag) { EXPECT_EQ(reader.GetType(), kTLVType_Null); EXPECT_EQ(reader.GetTag(), tag); EXPECT_EQ(reader.GetLength(), 0u); } void TestString(TLVReader & reader, Tag tag, const char * expectedVal) { EXPECT_EQ(reader.GetType(), kTLVType_UTF8String); EXPECT_EQ(reader.GetTag(), tag); size_t expectedLen = strlen(expectedVal); EXPECT_EQ(reader.GetLength(), expectedLen); chip::Platform::ScopedMemoryBuffer valBuffer; char * val = static_cast(valBuffer.Alloc(expectedLen + 1).Get()); CHIP_ERROR err = reader.GetString(val, static_cast(expectedLen) + 1); EXPECT_EQ(err, CHIP_NO_ERROR); EXPECT_EQ(memcmp(val, expectedVal, expectedLen + 1), 0); } void TestDupString(TLVReader & reader, Tag tag, const char * expectedVal) { EXPECT_EQ(reader.GetType(), kTLVType_UTF8String); EXPECT_EQ(reader.GetTag(), tag); size_t expectedLen = strlen(expectedVal); EXPECT_EQ(reader.GetLength(), expectedLen); char * val = nullptr; CHIP_ERROR err = reader.DupString(val); EXPECT_EQ(err, CHIP_NO_ERROR); ASSERT_NE(val, nullptr); EXPECT_EQ(memcmp(val, expectedVal, expectedLen + 1), 0); chip::Platform::MemoryFree(val); } void TestDupBytes(TLVReader & reader, Tag tag, const uint8_t * expectedVal, uint32_t expectedLen) { EXPECT_EQ(reader.GetType(), kTLVType_UTF8String); EXPECT_EQ(reader.GetTag(), tag); EXPECT_EQ(reader.GetLength(), expectedLen); uint8_t * val = nullptr; CHIP_ERROR err = reader.DupBytes(val, expectedLen); EXPECT_EQ(err, CHIP_NO_ERROR); ASSERT_NE(val, nullptr); EXPECT_EQ(memcmp(val, expectedVal, expectedLen), 0); chip::Platform::MemoryFree(val); } void TestBufferContents(const System::PacketBufferHandle & buffer, const uint8_t * expectedVal, size_t expectedLen) { System::PacketBufferHandle buf = buffer.Retain(); while (!buf.IsNull()) { size_t len = buf->DataLength(); EXPECT_LE(len, expectedLen); EXPECT_EQ(memcmp(buf->Start(), expectedVal, len), 0); expectedVal += len; expectedLen -= len; buf.Advance(); } EXPECT_EQ(expectedLen, 0u); } // clang-format off static const uint8_t Encoding1[] = { 0xD5, 0xBB, 0xAA, 0xDD, 0xCC, 0x01, 0x00, 0xC9, 0xBB, 0xAA, 0xDD, 0xCC, 0x02, 0x00, 0x88, 0x02, 0x00, 0x36, 0x00, 0x00, 0x2A, 0x00, 0xEF, 0x02, 0xF0, 0x67, 0xFD, 0xFF, 0x07, 0x00, 0x90, 0x2F, 0x50, 0x09, 0x00, 0x00, 0x00, 0x15, 0x18, 0x17, 0xD4, 0xBB, 0xAA, 0xDD, 0xCC, 0x11, 0x00, 0xB4, 0xA0, 0xBB, 0x0D, 0x00, 0x14, 0xB5, 0x00, 0x28, 0x6B, 0xEE, 0x6D, 0x70, 0x11, 0x01, 0x00, 0x0E, 0x01, 0x53, 0x54, 0x41, 0x52, 0x54, 0x2E, 0x2E, 0x2E, 0x21, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x40, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x23, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x24, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x25, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x5E, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x26, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x2A, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x28, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x29, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x2D, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x3D, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x5B, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x5D, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x3B, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x27, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x2E, 0x2E, 0x2E, 0x45, 0x4E, 0x44, 0x18, 0x18, 0x18, 0xCC, 0xBB, 0xAA, 0xDD, 0xCC, 0x05, 0x00, 0x0E, 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x74, 0x65, 0x73, 0x74, 0x8A, 0xFF, 0xFF, 0x33, 0x33, 0x8F, 0x41, 0xAB, 0x00, 0x00, 0x01, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0xE6, 0x31, 0x40, 0x18 }; // clang-format on // clang-format off static const uint8_t Encoding1_DataMacro [] = { CHIP_TLV_STRUCTURE(CHIP_TLV_TAG_FULLY_QUALIFIED_6Bytes(TestProfile_1, 1)), CHIP_TLV_BOOL(CHIP_TLV_TAG_FULLY_QUALIFIED_6Bytes(TestProfile_1, 2), true), CHIP_TLV_BOOL(CHIP_TLV_TAG_IMPLICIT_PROFILE_2Bytes(2), false), CHIP_TLV_ARRAY(CHIP_TLV_TAG_CONTEXT_SPECIFIC(0)), CHIP_TLV_INT8(CHIP_TLV_TAG_ANONYMOUS, 42), CHIP_TLV_INT8(CHIP_TLV_TAG_ANONYMOUS, -17), CHIP_TLV_INT32(CHIP_TLV_TAG_ANONYMOUS, -170000), CHIP_TLV_UINT64(CHIP_TLV_TAG_ANONYMOUS, 40000000000ULL), CHIP_TLV_STRUCTURE(CHIP_TLV_TAG_ANONYMOUS), CHIP_TLV_END_OF_CONTAINER, CHIP_TLV_LIST(CHIP_TLV_TAG_ANONYMOUS), CHIP_TLV_NULL(CHIP_TLV_TAG_FULLY_QUALIFIED_6Bytes(TestProfile_1, 17)), CHIP_TLV_NULL(CHIP_TLV_TAG_IMPLICIT_PROFILE_4Bytes(900000)), CHIP_TLV_NULL(CHIP_TLV_TAG_ANONYMOUS), CHIP_TLV_STRUCTURE(CHIP_TLV_TAG_IMPLICIT_PROFILE_4Bytes(4000000000ULL)), CHIP_TLV_UTF8_STRING_2ByteLength(CHIP_TLV_TAG_COMMON_PROFILE_4Bytes(70000), sizeof(sLargeString) - 1, 'S', 'T', 'A', 'R', 'T', '.', '.', '.', '!', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', '@', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', '#', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', '$', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', '%', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', '^', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', '&', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', '*', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', '0', '1', '2', '3', '4', '5', '6', '7', '(', '9', 'A', 'B', 'C', 'D', 'E', 'F', '0', '1', '2', '3', '4', '5', '6', '7', ')', '9', 'A', 'B', 'C', 'D', 'E', 'F', '0', '1', '2', '3', '4', '5', '6', '7', '-', '9', 'A', 'B', 'C', 'D', 'E', 'F', '0', '1', '2', '3', '4', '5', '6', '7', '=', '9', 'A', 'B', 'C', 'D', 'E', 'F', '0', '1', '2', '3', '4', '5', '6', '7', '[', '9', 'A', 'B', 'C', 'D', 'E', 'F', '0', '1', '2', '3', '4', '5', '6', '7', ']', '9', 'A', 'B', 'C', 'D', 'E', 'F', '0', '1', '2', '3', '4', '5', '6', '7', ';', '9', 'A', 'B', 'C', 'D', 'E', 'F', '0', '1', '2', '3', '4', '5', '6', '7', '\'', '9', 'A', 'B', 'C', 'D', 'E', 'F', '.', '.', '.', 'E', 'N', 'D'), CHIP_TLV_END_OF_CONTAINER, CHIP_TLV_END_OF_CONTAINER, CHIP_TLV_END_OF_CONTAINER, CHIP_TLV_UTF8_STRING_1ByteLength(CHIP_TLV_TAG_FULLY_QUALIFIED_6Bytes(TestProfile_1, 5), sizeof("This is a test") - 1, 'T', 'h', 'i', 's', ' ', 'i', 's', ' ', 'a', ' ', 't', 'e', 's', 't'), CHIP_TLV_FLOAT32(CHIP_TLV_TAG_IMPLICIT_PROFILE_2Bytes(65535), 0x33, 0x33, 0x8f, 0x41), // (float)17.9 CHIP_TLV_FLOAT64(CHIP_TLV_TAG_IMPLICIT_PROFILE_4Bytes(65536), 0x66, 0x66, 0x66, 0x66, 0x66, 0xE6, 0x31, 0x40), // (double)17.9 CHIP_TLV_END_OF_CONTAINER }; // clang-format on static CHIP_ERROR WriteIntMinMax(TLVWriter & writer) { CHIP_ERROR err; err = writer.Put(AnonymousTag(), static_cast(INT8_MIN)); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer.Put(AnonymousTag(), static_cast(INT8_MAX)); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer.Put(AnonymousTag(), static_cast(INT16_MIN)); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer.Put(AnonymousTag(), static_cast(INT16_MAX)); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer.Put(AnonymousTag(), static_cast(INT32_MIN)); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer.Put(AnonymousTag(), static_cast(INT32_MAX)); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer.Put(AnonymousTag(), static_cast(INT64_MIN)); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer.Put(AnonymousTag(), static_cast(INT64_MAX)); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer.Put(AnonymousTag(), static_cast(UINT8_MAX)); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer.Put(AnonymousTag(), static_cast(UINT16_MAX)); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer.Put(AnonymousTag(), static_cast(UINT32_MAX)); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer.Put(AnonymousTag(), static_cast(UINT64_MAX)); EXPECT_EQ(err, CHIP_NO_ERROR); return err; } static void CheckIntMinMax(TLVReader & reader) { // Writer did Put(AnonymousTag(), static_cast(INT8_MIN)) TEST_GET_NOERROR(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(INT8_MIN)); TEST_GET_NOERROR(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(INT8_MIN)); TEST_GET_NOERROR(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(INT8_MIN)); TEST_GET_NOERROR(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(INT8_MIN)); TEST_GET(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_WRONG_TLV_TYPE); TEST_GET(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_WRONG_TLV_TYPE); TEST_GET(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_WRONG_TLV_TYPE); TEST_GET(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_WRONG_TLV_TYPE); TestNext(reader); // Writer did Put(AnonymousTag(), static_cast(INT8_MAX)) TEST_GET_NOERROR(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(INT8_MAX)); TEST_GET_NOERROR(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(INT8_MAX)); TEST_GET_NOERROR(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(INT8_MAX)); TEST_GET_NOERROR(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(INT8_MAX)); TEST_GET(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_WRONG_TLV_TYPE); TEST_GET(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_WRONG_TLV_TYPE); TEST_GET(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_WRONG_TLV_TYPE); TEST_GET(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_WRONG_TLV_TYPE); TestNext(reader); // Writer did Put(AnonymousTag(), static_cast(INT16_MIN)) TEST_GET(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_INVALID_INTEGER_VALUE); TEST_GET_NOERROR(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(INT16_MIN)); TEST_GET_NOERROR(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(INT16_MIN)); TEST_GET_NOERROR(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(INT16_MIN)); TEST_GET(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_WRONG_TLV_TYPE); TEST_GET(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_WRONG_TLV_TYPE); TEST_GET(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_WRONG_TLV_TYPE); TEST_GET(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_WRONG_TLV_TYPE); TestNext(reader); // Writer did Put(AnonymousTag(), static_cast(INT16_MAX)) TEST_GET(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_INVALID_INTEGER_VALUE); TEST_GET_NOERROR(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(INT16_MAX)); TEST_GET_NOERROR(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(INT16_MAX)); TEST_GET_NOERROR(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(INT16_MAX)); TEST_GET(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_WRONG_TLV_TYPE); TEST_GET(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_WRONG_TLV_TYPE); TEST_GET(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_WRONG_TLV_TYPE); TEST_GET(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_WRONG_TLV_TYPE); TestNext(reader); // Writer did Put(AnonymousTag(), static_cast(INT32_MIN)) TEST_GET(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_INVALID_INTEGER_VALUE); TEST_GET(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_INVALID_INTEGER_VALUE); TEST_GET_NOERROR(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(INT32_MIN)); TEST_GET_NOERROR(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(INT32_MIN)); TEST_GET(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_WRONG_TLV_TYPE); TEST_GET(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_WRONG_TLV_TYPE); TEST_GET(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_WRONG_TLV_TYPE); TEST_GET(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_WRONG_TLV_TYPE); TestNext(reader); // Writer did Put(AnonymousTag(), static_cast(INT32_MAX)) TEST_GET(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_INVALID_INTEGER_VALUE); TEST_GET(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_INVALID_INTEGER_VALUE); TEST_GET_NOERROR(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(INT32_MAX)); TEST_GET_NOERROR(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(INT32_MAX)); TEST_GET(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_WRONG_TLV_TYPE); TEST_GET(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_WRONG_TLV_TYPE); TEST_GET(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_WRONG_TLV_TYPE); TEST_GET(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_WRONG_TLV_TYPE); TestNext(reader); // Writer did Put(AnonymousTag(), static_cast(INT64_MIN)) TEST_GET(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_INVALID_INTEGER_VALUE); TEST_GET(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_INVALID_INTEGER_VALUE); TEST_GET(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_INVALID_INTEGER_VALUE); TEST_GET_NOERROR(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(INT64_MIN)); TEST_GET(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_WRONG_TLV_TYPE); TEST_GET(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_WRONG_TLV_TYPE); TEST_GET(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_WRONG_TLV_TYPE); TEST_GET(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_WRONG_TLV_TYPE); TestNext(reader); // Writer did Put(AnonymousTag(), static_cast(INT64_MAX)) TEST_GET(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_INVALID_INTEGER_VALUE); TEST_GET(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_INVALID_INTEGER_VALUE); TEST_GET(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_INVALID_INTEGER_VALUE); TEST_GET_NOERROR(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(INT64_MAX)); TEST_GET(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_WRONG_TLV_TYPE); TEST_GET(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_WRONG_TLV_TYPE); TEST_GET(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_WRONG_TLV_TYPE); TEST_GET(reader, kTLVType_SignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_WRONG_TLV_TYPE); TestNext(reader); // Writer did Put(AnonymousTag(), static_cast(UINT8_MAX)) TEST_GET(reader, kTLVType_UnsignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_WRONG_TLV_TYPE); TEST_GET(reader, kTLVType_UnsignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_WRONG_TLV_TYPE); TEST_GET(reader, kTLVType_UnsignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_WRONG_TLV_TYPE); TEST_GET(reader, kTLVType_UnsignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_WRONG_TLV_TYPE); TEST_GET_NOERROR(reader, kTLVType_UnsignedInteger, AnonymousTag(), static_cast(UINT8_MAX)); TEST_GET_NOERROR(reader, kTLVType_UnsignedInteger, AnonymousTag(), static_cast(UINT8_MAX)); TEST_GET_NOERROR(reader, kTLVType_UnsignedInteger, AnonymousTag(), static_cast(UINT8_MAX)); TEST_GET_NOERROR(reader, kTLVType_UnsignedInteger, AnonymousTag(), static_cast(UINT8_MAX)); TestNext(reader); // Writer did Put(AnonymousTag(), static_cast(UINT16_MAX)) TEST_GET(reader, kTLVType_UnsignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_WRONG_TLV_TYPE); TEST_GET(reader, kTLVType_UnsignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_WRONG_TLV_TYPE); TEST_GET(reader, kTLVType_UnsignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_WRONG_TLV_TYPE); TEST_GET(reader, kTLVType_UnsignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_WRONG_TLV_TYPE); TEST_GET(reader, kTLVType_UnsignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_INVALID_INTEGER_VALUE); TEST_GET_NOERROR(reader, kTLVType_UnsignedInteger, AnonymousTag(), static_cast(UINT16_MAX)); TEST_GET_NOERROR(reader, kTLVType_UnsignedInteger, AnonymousTag(), static_cast(UINT16_MAX)); TEST_GET_NOERROR(reader, kTLVType_UnsignedInteger, AnonymousTag(), static_cast(UINT16_MAX)); TestNext(reader); // Writer did Put(AnonymousTag(), static_cast(UINT32_MAX)) TEST_GET(reader, kTLVType_UnsignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_WRONG_TLV_TYPE); TEST_GET(reader, kTLVType_UnsignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_WRONG_TLV_TYPE); TEST_GET(reader, kTLVType_UnsignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_WRONG_TLV_TYPE); TEST_GET(reader, kTLVType_UnsignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_WRONG_TLV_TYPE); TEST_GET(reader, kTLVType_UnsignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_INVALID_INTEGER_VALUE); TEST_GET(reader, kTLVType_UnsignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_INVALID_INTEGER_VALUE); TEST_GET_NOERROR(reader, kTLVType_UnsignedInteger, AnonymousTag(), static_cast(UINT32_MAX)); TEST_GET_NOERROR(reader, kTLVType_UnsignedInteger, AnonymousTag(), static_cast(UINT32_MAX)); TestNext(reader); // Writer did Put(AnonymousTag(), static_cast(UINT64_MAX)) TEST_GET(reader, kTLVType_UnsignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_WRONG_TLV_TYPE); TEST_GET(reader, kTLVType_UnsignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_WRONG_TLV_TYPE); TEST_GET(reader, kTLVType_UnsignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_WRONG_TLV_TYPE); TEST_GET(reader, kTLVType_UnsignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_WRONG_TLV_TYPE); TEST_GET(reader, kTLVType_UnsignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_INVALID_INTEGER_VALUE); TEST_GET(reader, kTLVType_UnsignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_INVALID_INTEGER_VALUE); TEST_GET(reader, kTLVType_UnsignedInteger, AnonymousTag(), static_cast(0), CHIP_ERROR_INVALID_INTEGER_VALUE); TEST_GET_NOERROR(reader, kTLVType_UnsignedInteger, AnonymousTag(), static_cast(UINT64_MAX)); } void WriteEncoding1(TLVWriter & writer) { CHIP_ERROR err; TLVWriter writer2; err = writer.OpenContainer(ProfileTag(TestProfile_1, 1), kTLVType_Structure, writer2); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer2.PutBoolean(ProfileTag(TestProfile_1, 2), true); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer2.PutBoolean(ProfileTag(TestProfile_2, 2), false); EXPECT_EQ(err, CHIP_NO_ERROR); { TLVWriter writer3; err = writer2.OpenContainer(ContextTag(0), kTLVType_Array, writer3); EXPECT_EQ(err, CHIP_NO_ERROR); // TODO(#1306): expand coverage of inttype encoding tests. err = writer3.Put(AnonymousTag(), static_cast(42)); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer3.Put(AnonymousTag(), static_cast(-17)); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer3.Put(AnonymousTag(), static_cast(-170000)); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer3.Put(AnonymousTag(), static_cast(40000000000ULL)); EXPECT_EQ(err, CHIP_NO_ERROR); { TLVWriter writer4; err = writer3.OpenContainer(AnonymousTag(), kTLVType_Structure, writer4); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer3.CloseContainer(writer4); EXPECT_EQ(err, CHIP_NO_ERROR); } { TLVWriter writer5; err = writer3.OpenContainer(AnonymousTag(), kTLVType_List, writer5); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer5.PutNull(ProfileTag(TestProfile_1, 17)); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer5.PutNull(ProfileTag(TestProfile_2, 900000)); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer5.PutNull(AnonymousTag()); EXPECT_EQ(err, CHIP_NO_ERROR); { TLVType outerContainerType; err = writer5.StartContainer(ProfileTag(TestProfile_2, 4000000000ULL), kTLVType_Structure, outerContainerType); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer5.PutString(CommonTag(70000), sLargeString); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer5.EndContainer(outerContainerType); EXPECT_EQ(err, CHIP_NO_ERROR); } err = writer3.CloseContainer(writer5); EXPECT_EQ(err, CHIP_NO_ERROR); } err = writer2.CloseContainer(writer3); EXPECT_EQ(err, CHIP_NO_ERROR); } err = writer2.PutString(ProfileTag(TestProfile_1, 5), "This is a test"); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer2.Put(ProfileTag(TestProfile_2, 65535), static_cast(17.9)); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer2.Put(ProfileTag(TestProfile_2, 65536), 17.9); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer.CloseContainer(writer2); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer.Finalize(); EXPECT_EQ(err, CHIP_NO_ERROR); } void WriteEmptyEncoding(TLVWriter & writer) { CHIP_ERROR err; TLVWriter writer2; err = writer.OpenContainer(ProfileTag(TestProfile_1, 1), kTLVType_Structure, writer2); EXPECT_EQ(err, CHIP_NO_ERROR); { TLVWriter writer3; err = writer2.OpenContainer(ProfileTag(TestProfile_1, 256), kTLVType_Array, writer3); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer2.CloseContainer(writer3); EXPECT_EQ(err, CHIP_NO_ERROR); } err = writer.CloseContainer(writer2); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer.Finalize(); EXPECT_EQ(err, CHIP_NO_ERROR); } void ReadEncoding1(TLVReader & reader) { TestNext(reader); { TLVReader reader2; TestAndOpenContainer(reader, kTLVType_Structure, ProfileTag(TestProfile_1, 1), reader2); TestNext(reader2); TEST_GET_NOERROR(reader2, kTLVType_Boolean, ProfileTag(TestProfile_1, 2), true); TestNext(reader2); TEST_GET_NOERROR(reader2, kTLVType_Boolean, ProfileTag(TestProfile_2, 2), false); TestNext(reader2); { TLVReader reader3; TestAndOpenContainer(reader2, kTLVType_Array, ContextTag(0), reader3); TestNext(reader3); TEST_GET_NOERROR(reader3, kTLVType_SignedInteger, AnonymousTag(), static_cast(42)); TEST_GET_NOERROR(reader3, kTLVType_SignedInteger, AnonymousTag(), static_cast(42)); TEST_GET_NOERROR(reader3, kTLVType_SignedInteger, AnonymousTag(), static_cast(42)); TEST_GET_NOERROR(reader3, kTLVType_SignedInteger, AnonymousTag(), static_cast(42)); TEST_GET(reader3, kTLVType_SignedInteger, AnonymousTag(), static_cast(42), CHIP_ERROR_WRONG_TLV_TYPE); TEST_GET(reader3, kTLVType_SignedInteger, AnonymousTag(), static_cast(42), CHIP_ERROR_WRONG_TLV_TYPE); TEST_GET(reader3, kTLVType_SignedInteger, AnonymousTag(), static_cast(42), CHIP_ERROR_WRONG_TLV_TYPE); TEST_GET(reader3, kTLVType_SignedInteger, AnonymousTag(), static_cast(42), CHIP_ERROR_WRONG_TLV_TYPE); TestNext(reader3); TEST_GET_NOERROR(reader3, kTLVType_SignedInteger, AnonymousTag(), static_cast(-17)); TEST_GET_NOERROR(reader3, kTLVType_SignedInteger, AnonymousTag(), static_cast(-17)); TEST_GET_NOERROR(reader3, kTLVType_SignedInteger, AnonymousTag(), static_cast(-17)); TEST_GET_NOERROR(reader3, kTLVType_SignedInteger, AnonymousTag(), static_cast(-17)); TEST_GET(reader3, kTLVType_SignedInteger, AnonymousTag(), static_cast(-17), CHIP_ERROR_WRONG_TLV_TYPE); TestNext(reader3); TEST_GET_NOERROR(reader3, kTLVType_SignedInteger, AnonymousTag(), static_cast(-170000)); TEST_GET_NOERROR(reader3, kTLVType_SignedInteger, AnonymousTag(), static_cast(-170000)); TestNext(reader3); TEST_GET(reader3, kTLVType_UnsignedInteger, AnonymousTag(), static_cast(40000000000ULL), CHIP_ERROR_WRONG_TLV_TYPE); TEST_GET_NOERROR(reader3, kTLVType_UnsignedInteger, AnonymousTag(), static_cast(40000000000ULL)); TestNext(reader3); { TLVReader reader4; TestAndOpenContainer(reader3, kTLVType_Structure, AnonymousTag(), reader4); TestEndAndCloseContainer(reader3, reader4); } TestNext(reader3); { TLVReader reader5; TestAndOpenContainer(reader3, kTLVType_List, AnonymousTag(), reader5); TestNext(reader5); TestNull(reader5, ProfileTag(TestProfile_1, 17)); TestNext(reader5); TestNull(reader5, ProfileTag(TestProfile_2, 900000)); TestNext(reader5); TestNull(reader5, AnonymousTag()); TestNext(reader5); { TLVType outerContainerType; TestAndEnterContainer(reader5, kTLVType_Structure, ProfileTag(TestProfile_2, 4000000000ULL), outerContainerType); TestNext(reader5); TestString(reader5, CommonTag(70000), sLargeString); TestEndAndExitContainer(reader5, outerContainerType); } TestEndAndCloseContainer(reader3, reader5); } TestEndAndCloseContainer(reader2, reader3); } TestNext(reader2); TestString(reader2, ProfileTag(TestProfile_1, 5), "This is a test"); TestNext(reader2); TEST_GET_NOERROR(reader2, kTLVType_FloatingPointNumber, ProfileTag(TestProfile_2, 65535), 17.9f); TEST_GET_NOERROR(reader2, kTLVType_FloatingPointNumber, ProfileTag(TestProfile_2, 65535), static_cast(17.9f)); TestNext(reader2); TEST_GET_NOERROR(reader2, kTLVType_FloatingPointNumber, ProfileTag(TestProfile_2, 65536), 17.9); TestEndAndCloseContainer(reader, reader2); } TestEnd(reader); } void WriteEncoding2(TLVWriter & writer) { CHIP_ERROR err; { // Container 1 TLVWriter writer1; err = writer.OpenContainer(ProfileTag(TestProfile_1, 1), kTLVType_Structure, writer1); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer1.PutBoolean(ProfileTag(TestProfile_1, 2), true); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer1.PutBoolean(ProfileTag(TestProfile_2, 2), false); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer.CloseContainer(writer1); EXPECT_EQ(err, CHIP_NO_ERROR); } { // Container 2 TLVWriter writer1; err = writer.OpenContainer(ProfileTag(TestProfile_2, 1), kTLVType_Structure, writer1); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer1.PutBoolean(ProfileTag(TestProfile_2, 2), false); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer1.PutBoolean(ProfileTag(TestProfile_1, 2), true); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer.CloseContainer(writer1); EXPECT_EQ(err, CHIP_NO_ERROR); } err = writer.Finalize(); EXPECT_EQ(err, CHIP_NO_ERROR); } void WriteEncoding3(TLVWriter & writer) { CHIP_ERROR err; { // Container 1 TLVWriter writer1; err = writer.OpenContainer(ProfileTag(TestProfile_1, 1), kTLVType_Structure, writer1); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer1.PutBoolean(ProfileTag(TestProfile_2, 2), false); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer.CloseContainer(writer1); EXPECT_EQ(err, CHIP_NO_ERROR); } err = writer.Finalize(); EXPECT_EQ(err, CHIP_NO_ERROR); } void ReadEncoding3(TLVReader & reader) { TLVReader reader2; TestAndOpenContainer(reader, kTLVType_Structure, ProfileTag(TestProfile_1, 1), reader2); TestNext(reader2); TEST_GET_NOERROR(reader2, kTLVType_Boolean, ProfileTag(TestProfile_2, 2), false); TestEndAndCloseContainer(reader, reader2); } // clang-format off static const uint8_t Encoding5_DataMacro [] = { CHIP_TLV_STRUCTURE(CHIP_TLV_TAG_FULLY_QUALIFIED_6Bytes(TestProfile_1, 1)), CHIP_TLV_BOOL(CHIP_TLV_TAG_FULLY_QUALIFIED_6Bytes(TestProfile_1, 2), true), CHIP_TLV_BOOL(CHIP_TLV_TAG_IMPLICIT_PROFILE_2Bytes(2), false), CHIP_TLV_BOOL(CHIP_TLV_TAG_FULLY_QUALIFIED_6Bytes(TestProfile_1, 2), false), CHIP_TLV_BOOL(CHIP_TLV_TAG_IMPLICIT_PROFILE_2Bytes(2), true), CHIP_TLV_STRUCTURE(CHIP_TLV_TAG_FULLY_QUALIFIED_6Bytes(TestProfile_1, 1)), CHIP_TLV_BOOL(CHIP_TLV_TAG_FULLY_QUALIFIED_6Bytes(TestProfile_1, 2), true), CHIP_TLV_BOOL(CHIP_TLV_TAG_IMPLICIT_PROFILE_2Bytes(2), false), CHIP_TLV_END_OF_CONTAINER, CHIP_TLV_STRUCTURE(CHIP_TLV_TAG_IMPLICIT_PROFILE_2Bytes(1)), CHIP_TLV_BOOL(CHIP_TLV_TAG_IMPLICIT_PROFILE_2Bytes(2), false), CHIP_TLV_BOOL(CHIP_TLV_TAG_FULLY_QUALIFIED_6Bytes(TestProfile_1, 2), true), CHIP_TLV_END_OF_CONTAINER, CHIP_TLV_END_OF_CONTAINER, CHIP_TLV_STRUCTURE(CHIP_TLV_TAG_IMPLICIT_PROFILE_2Bytes(1)), CHIP_TLV_BOOL(CHIP_TLV_TAG_IMPLICIT_PROFILE_2Bytes(2), false), CHIP_TLV_BOOL(CHIP_TLV_TAG_FULLY_QUALIFIED_6Bytes(TestProfile_1, 2), true), CHIP_TLV_END_OF_CONTAINER, }; // clang-format on void WriteEncoding5(TLVWriter & writer) { CHIP_ERROR err; { // Container 1 TLVWriter writer1; err = writer.OpenContainer(ProfileTag(TestProfile_1, 1), kTLVType_Structure, writer1); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer1.PutBoolean(ProfileTag(TestProfile_1, 2), true); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer1.PutBoolean(ProfileTag(TestProfile_2, 2), false); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer1.PutBoolean(ProfileTag(TestProfile_1, 2), false); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer1.PutBoolean(ProfileTag(TestProfile_2, 2), true); EXPECT_EQ(err, CHIP_NO_ERROR); { // Inner Container 1 TLVWriter writer2; err = writer1.OpenContainer(ProfileTag(TestProfile_1, 1), kTLVType_Structure, writer2); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer2.PutBoolean(ProfileTag(TestProfile_1, 2), true); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer2.PutBoolean(ProfileTag(TestProfile_2, 2), false); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer1.CloseContainer(writer2); EXPECT_EQ(err, CHIP_NO_ERROR); } { // Inner Container 2 TLVWriter writer2; err = writer1.OpenContainer(ProfileTag(TestProfile_2, 1), kTLVType_Structure, writer2); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer2.PutBoolean(ProfileTag(TestProfile_2, 2), false); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer2.PutBoolean(ProfileTag(TestProfile_1, 2), true); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer1.CloseContainer(writer2); EXPECT_EQ(err, CHIP_NO_ERROR); } err = writer.CloseContainer(writer1); EXPECT_EQ(err, CHIP_NO_ERROR); } { // Container 2 TLVWriter writer1; err = writer.OpenContainer(ProfileTag(TestProfile_2, 1), kTLVType_Structure, writer1); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer1.PutBoolean(ProfileTag(TestProfile_2, 2), false); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer1.PutBoolean(ProfileTag(TestProfile_1, 2), true); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer.CloseContainer(writer1); EXPECT_EQ(err, CHIP_NO_ERROR); } err = writer.Finalize(); EXPECT_EQ(err, CHIP_NO_ERROR); } /** * AppendEncoding2() * * This function appends two boolean types and two container types to the first * container. * * The boolean types are- * * * * The two new container types are- * >, * > */ void AppendEncoding2(uint8_t * buf, uint32_t dataLen, uint32_t maxLen, uint32_t & updatedLen) { CHIP_ERROR err; TLVUpdater updater; err = updater.Init(buf, dataLen, maxLen); EXPECT_EQ(err, CHIP_NO_ERROR); updater.SetImplicitProfileId(TestProfile_2); TestNext(updater); { TLVType outerContainerType; TestAndEnterContainer(updater, kTLVType_Structure, ProfileTag(TestProfile_1, 1), outerContainerType); TestNext(updater); // Move the element without modification TestMove(updater); TestNext(updater); // Read and copy the element with/without modification TEST_GET_NOERROR(updater, kTLVType_Boolean, ProfileTag(TestProfile_2, 2), false); err = updater.PutBoolean(ProfileTag(TestProfile_2, 2), false); EXPECT_EQ(err, CHIP_NO_ERROR); // TestEnd and add data at the end of the container TestEnd(updater); // Put new values in the encoding using the updater // Add err = updater.PutBoolean(ProfileTag(TestProfile_1, 2), false); EXPECT_EQ(err, CHIP_NO_ERROR); // Add err = updater.PutBoolean(ProfileTag(TestProfile_2, 2), true); EXPECT_EQ(err, CHIP_NO_ERROR); // Add a new container { TLVType outerContainerType1; err = updater.StartContainer(ProfileTag(TestProfile_1, 1), kTLVType_Structure, outerContainerType1); EXPECT_EQ(err, CHIP_NO_ERROR); // Add err = updater.PutBoolean(ProfileTag(TestProfile_1, 2), true); EXPECT_EQ(err, CHIP_NO_ERROR); // Add err = updater.PutBoolean(ProfileTag(TestProfile_2, 2), false); EXPECT_EQ(err, CHIP_NO_ERROR); // Close the container err = updater.EndContainer(outerContainerType1); EXPECT_EQ(err, CHIP_NO_ERROR); } // Add another new container { TLVType outerContainerType1; err = updater.StartContainer(ProfileTag(TestProfile_2, 1), kTLVType_Structure, outerContainerType1); EXPECT_EQ(err, CHIP_NO_ERROR); // Add err = updater.PutBoolean(ProfileTag(TestProfile_2, 2), false); EXPECT_EQ(err, CHIP_NO_ERROR); // Add err = updater.PutBoolean(ProfileTag(TestProfile_1, 2), true); EXPECT_EQ(err, CHIP_NO_ERROR); // Close the container err = updater.EndContainer(outerContainerType1); EXPECT_EQ(err, CHIP_NO_ERROR); } TestEndAndExitContainer(updater, outerContainerType); } TestNext(updater); // Move the container unmodified TestMove(updater); TestEnd(updater); err = updater.Finalize(); EXPECT_EQ(err, CHIP_NO_ERROR); updatedLen = updater.GetLengthWritten(); } /** * FindAppendEncoding2() * * This function appends two boolean types and two container types to the first * container. It is very similar to AppendEncoding2() above except for the fact * that it uses TLVUtilities::Find() to find the element of interest before * appending new data. * * The boolean types are- * * * * The two new container types are- * >, * > */ void FindAppendEncoding2(uint8_t * buf, uint32_t dataLen, uint32_t maxLen, uint32_t & updatedLen, bool findContainer) { CHIP_ERROR err; TLVReader reader; TLVUpdater updater; // Initialize a reader reader.Init(buf, dataLen); reader.ImplicitProfileId = TestProfile_2; if (findContainer) { // Find the container TLVReader tagReader; TLVType outerContainerType; err = chip::TLV::Utilities::Find(reader, ProfileTag(TestProfile_1, 1), tagReader); EXPECT_EQ(err, CHIP_NO_ERROR); err = tagReader.EnterContainer(outerContainerType); EXPECT_EQ(err, CHIP_NO_ERROR); do { err = tagReader.Next(); } while (err != CHIP_END_OF_TLV); TestEnd(tagReader); // Init a TLVUpdater using the TLVReader err = updater.Init(tagReader, maxLen - dataLen); EXPECT_EQ(err, CHIP_NO_ERROR); } else { // Find TLVReader tagReader; err = chip::TLV::Utilities::Find(reader, ProfileTag(TestProfile_2, 2), tagReader); EXPECT_EQ(err, CHIP_NO_ERROR); // Test Find(recurse = true) TLVReader tagReader2; err = chip::TLV::Utilities::Find(reader, ProfileTag(TestProfile_2, 2), tagReader2, true); EXPECT_EQ(err, CHIP_NO_ERROR); // // Test Find(recurse = false) TLVReader tagReader3; err = chip::TLV::Utilities::Find(reader, ProfileTag(TestProfile_2, 2), tagReader3, false); EXPECT_EQ(err, CHIP_ERROR_TLV_TAG_NOT_FOUND); // Init a TLVUpdater using the TLVReader err = updater.Init(tagReader, maxLen - dataLen); EXPECT_EQ(err, CHIP_NO_ERROR); TestNext(updater); // Move the element without modification TestMove(updater); } // Put new values in the encoding using the updater // Add err = updater.PutBoolean(ProfileTag(TestProfile_1, 2), false); EXPECT_EQ(err, CHIP_NO_ERROR); // Add err = updater.PutBoolean(ProfileTag(TestProfile_2, 2), true); EXPECT_EQ(err, CHIP_NO_ERROR); // Add a new container { TLVType outerContainerType1; err = updater.StartContainer(ProfileTag(TestProfile_1, 1), kTLVType_Structure, outerContainerType1); EXPECT_EQ(err, CHIP_NO_ERROR); // Add err = updater.PutBoolean(ProfileTag(TestProfile_1, 2), true); EXPECT_EQ(err, CHIP_NO_ERROR); // Add err = updater.PutBoolean(ProfileTag(TestProfile_2, 2), false); EXPECT_EQ(err, CHIP_NO_ERROR); // Close the container err = updater.EndContainer(outerContainerType1); EXPECT_EQ(err, CHIP_NO_ERROR); } // Add another new container { TLVType outerContainerType1; err = updater.StartContainer(ProfileTag(TestProfile_2, 1), kTLVType_Structure, outerContainerType1); EXPECT_EQ(err, CHIP_NO_ERROR); // Add err = updater.PutBoolean(ProfileTag(TestProfile_2, 2), false); EXPECT_EQ(err, CHIP_NO_ERROR); // Add err = updater.PutBoolean(ProfileTag(TestProfile_1, 2), true); EXPECT_EQ(err, CHIP_NO_ERROR); // Close the container err = updater.EndContainer(outerContainerType1); EXPECT_EQ(err, CHIP_NO_ERROR); } // Move everything else unmodified updater.MoveUntilEnd(); TestEnd(updater); err = updater.Finalize(); EXPECT_EQ(err, CHIP_NO_ERROR); updatedLen = updater.GetLengthWritten(); } void AppendEncoding3(uint8_t * buf, uint32_t dataLen, uint32_t maxLen, uint32_t & updatedLen) { CHIP_ERROR err; TLVUpdater updater; err = updater.Init(buf, dataLen, maxLen); EXPECT_EQ(err, CHIP_NO_ERROR); updater.SetImplicitProfileId(TestProfile_2); TestNext(updater); { TLVType outerContainerType; TestAndEnterContainer(updater, kTLVType_Structure, ProfileTag(TestProfile_1, 1), outerContainerType); TestNext(updater); // Move the element without modification TestMove(updater); // Put new value in the encoding using the updater // Add err = updater.PutBoolean(ProfileTag(TestProfile_2, 2), true); EXPECT_EQ(err, CHIP_NO_ERROR); TestEndAndExitContainer(updater, outerContainerType); } TestEnd(updater); err = updater.Finalize(); EXPECT_EQ(err, CHIP_NO_ERROR); updatedLen = updater.GetLengthWritten(); } void AppendEncoding4(uint8_t * buf, uint32_t dataLen, uint32_t maxLen, uint32_t & updatedLen) { CHIP_ERROR err; TLVUpdater updater; err = updater.Init(buf, dataLen, maxLen); EXPECT_EQ(err, CHIP_NO_ERROR); updater.SetImplicitProfileId(TestProfile_2); // Add a new container { TLVType outerContainerType; err = updater.StartContainer(ProfileTag(TestProfile_1, 1), kTLVType_Structure, outerContainerType); EXPECT_EQ(err, CHIP_NO_ERROR); // Add err = updater.PutBoolean(ProfileTag(TestProfile_2, 2), false); EXPECT_EQ(err, CHIP_NO_ERROR); // Close the container err = updater.EndContainer(outerContainerType); EXPECT_EQ(err, CHIP_NO_ERROR); } err = updater.Finalize(); EXPECT_EQ(err, CHIP_NO_ERROR); updatedLen = updater.GetLengthWritten(); } void DeleteEncoding5(uint8_t * buf, uint32_t dataLen, uint32_t maxLen, uint32_t & updatedLen) { CHIP_ERROR err; TLVUpdater updater; err = updater.Init(buf, dataLen, maxLen); EXPECT_EQ(err, CHIP_NO_ERROR); updater.SetImplicitProfileId(TestProfile_2); TestNext(updater); { TLVType outerContainerType; TestAndEnterContainer(updater, kTLVType_Structure, ProfileTag(TestProfile_1, 1), outerContainerType); TestNext(updater); TestMove(updater); TestNext(updater); TestMove(updater); TestNext(updater); // Get the value to inspect and skip writing it TEST_GET_NOERROR(updater, kTLVType_Boolean, ProfileTag(TestProfile_1, 2), false); TestNext(updater); // Skip the next boolean type and don't copy by doing nothing TestNext(updater); // Read ahead into the next container and decide whether to skip or // not based on elements in the container { TLVReader reader; TLVType containerType; updater.GetReader(reader); TestAndEnterContainer(reader, kTLVType_Structure, ProfileTag(TestProfile_1, 1), containerType); TestNext(reader); // If the container's first element has the tag // skip the whole container, and if NOT copy the container if (reader.GetTag() != ProfileTag(TestProfile_1, 2)) TestMove(updater); } TestNext(updater); // Skip the next container and don't copy by doing nothing TestEndAndExitContainer(updater, outerContainerType); } // Move everything else unmodified updater.MoveUntilEnd(); TestEnd(updater); err = updater.Finalize(); EXPECT_EQ(err, CHIP_NO_ERROR); updatedLen = updater.GetLengthWritten(); } void ReadAppendedEncoding2(TLVReader & reader) { TestNext(reader); { // Container 1 TLVReader reader1; TestAndOpenContainer(reader, kTLVType_Structure, ProfileTag(TestProfile_1, 1), reader1); TestNext(reader1); TEST_GET_NOERROR(reader1, kTLVType_Boolean, ProfileTag(TestProfile_1, 2), true); TestNext(reader1); TEST_GET_NOERROR(reader1, kTLVType_Boolean, ProfileTag(TestProfile_2, 2), false); TestNext(reader1); TEST_GET_NOERROR(reader1, kTLVType_Boolean, ProfileTag(TestProfile_1, 2), false); TestNext(reader1); TEST_GET_NOERROR(reader1, kTLVType_Boolean, ProfileTag(TestProfile_2, 2), true); TestNext(reader1); { TLVReader reader2; TestAndOpenContainer(reader1, kTLVType_Structure, ProfileTag(TestProfile_1, 1), reader2); TestNext(reader2); TEST_GET_NOERROR(reader2, kTLVType_Boolean, ProfileTag(TestProfile_1, 2), true); TestNext(reader2); TEST_GET_NOERROR(reader2, kTLVType_Boolean, ProfileTag(TestProfile_2, 2), false); TestEndAndCloseContainer(reader1, reader2); } TestNext(reader1); { TLVReader reader2; TestAndOpenContainer(reader1, kTLVType_Structure, ProfileTag(TestProfile_2, 1), reader2); TestNext(reader2); TEST_GET_NOERROR(reader2, kTLVType_Boolean, ProfileTag(TestProfile_2, 2), false); TestNext(reader2); TEST_GET_NOERROR(reader2, kTLVType_Boolean, ProfileTag(TestProfile_1, 2), true); TestEndAndCloseContainer(reader1, reader2); } TestEndAndCloseContainer(reader, reader1); } TestNext(reader); { // Container 2 TLVReader reader1; TestAndOpenContainer(reader, kTLVType_Structure, ProfileTag(TestProfile_2, 1), reader1); TestNext(reader1); TEST_GET_NOERROR(reader1, kTLVType_Boolean, ProfileTag(TestProfile_2, 2), false); TestNext(reader1); TEST_GET_NOERROR(reader1, kTLVType_Boolean, ProfileTag(TestProfile_1, 2), true); TestEndAndCloseContainer(reader, reader1); } TestEnd(reader); } void ReadAppendedEncoding3(TLVReader & reader) { TestNext(reader); { // Container 1 TLVReader reader1; TestAndOpenContainer(reader, kTLVType_Structure, ProfileTag(TestProfile_1, 1), reader1); TestNext(reader1); TEST_GET_NOERROR(reader1, kTLVType_Boolean, ProfileTag(TestProfile_2, 2), false); TestNext(reader1); TEST_GET_NOERROR(reader1, kTLVType_Boolean, ProfileTag(TestProfile_2, 2), true); TestEndAndCloseContainer(reader, reader1); } TestEnd(reader); } void ReadAppendedEncoding4(TLVReader & reader) { TestNext(reader); { // Container 1 TLVReader reader1; TestAndOpenContainer(reader, kTLVType_Structure, ProfileTag(TestProfile_1, 1), reader1); TestNext(reader1); TEST_GET_NOERROR(reader1, kTLVType_Boolean, ProfileTag(TestProfile_2, 2), false); TestEndAndCloseContainer(reader, reader1); } TestEnd(reader); } void ReadDeletedEncoding5(TLVReader & reader) { TestNext(reader); { // Container 1 TLVReader reader1; TestAndOpenContainer(reader, kTLVType_Structure, ProfileTag(TestProfile_1, 1), reader1); TestNext(reader1); TEST_GET_NOERROR(reader1, kTLVType_Boolean, ProfileTag(TestProfile_1, 2), true); TestNext(reader1); TEST_GET_NOERROR(reader1, kTLVType_Boolean, ProfileTag(TestProfile_2, 2), false); TestEndAndCloseContainer(reader, reader1); } TestNext(reader); { // Container 2 TLVReader reader1; TestAndOpenContainer(reader, kTLVType_Structure, ProfileTag(TestProfile_2, 1), reader1); TestNext(reader1); TEST_GET_NOERROR(reader1, kTLVType_Boolean, ProfileTag(TestProfile_2, 2), false); TestNext(reader1); TEST_GET_NOERROR(reader1, kTLVType_Boolean, ProfileTag(TestProfile_1, 2), true); TestEndAndCloseContainer(reader, reader1); } TestEnd(reader); } /** * Test Simple Write and Reader */ TEST_F(TestTLV, CheckSimpleWriteRead) { uint8_t buf[2048]; TLVWriter writer; TLVReader reader; uint32_t remainingFreedLen; writer.Init(buf); writer.ImplicitProfileId = TestProfile_2; remainingFreedLen = writer.GetRemainingFreeLength(); EXPECT_EQ(sizeof(buf), remainingFreedLen); WriteEncoding1(writer); uint32_t encodedLen = writer.GetLengthWritten(); #ifdef DUMP_ENCODING for (uint32_t i = 0; i < encodedLen; i++) { if (i != 0 && i % 16 == 0) printf("\n"); printf("0x%02X, ", buf[i]); } printf("\n"); #endif EXPECT_EQ(encodedLen, sizeof(Encoding1)); EXPECT_EQ(memcmp(buf, Encoding1, encodedLen), 0); reader.Init(buf, encodedLen); reader.ImplicitProfileId = TestProfile_2; ReadEncoding1(reader); } TEST_F(TestTLV, TestIntMinMax) { CHIP_ERROR err; uint8_t buf[2048]; TLVWriter writer, writer1; TLVReader reader, reader1; writer.Init(buf, sizeof(buf)); writer.ImplicitProfileId = TestProfile_3; err = writer.OpenContainer(ProfileTag(TestProfile_3, 1), kTLVType_Array, writer1); EXPECT_EQ(err, CHIP_NO_ERROR); WriteIntMinMax(writer1); err = writer.CloseContainer(writer1); EXPECT_EQ(err, CHIP_NO_ERROR); reader.Init(buf, sizeof(buf)); reader.ImplicitProfileId = TestProfile_3; TestNext(reader); TestAndOpenContainer(reader, kTLVType_Array, ProfileTag(TestProfile_3, 1), reader1); TestNext(reader1); CheckIntMinMax(reader1); TestEndAndCloseContainer(reader, reader1); } /** * Log the specified message in the form of @a aFormat. * * @param[in] aFormat A pointer to a NULL-terminated C string with * C Standard Library-style format specifiers * containing the log message to be formatted and * logged. * @param[in] ... An argument list whose elements should correspond * to the format specifiers in @a aFormat. * */ void ENFORCE_FORMAT(1, 2) SimpleDumpWriter(const char * aFormat, ...) { va_list args; va_start(args, aFormat); vprintf(aFormat, args); va_end(args); } /** * Test Pretty Printer */ TEST_F(TestTLV, CheckPrettyPrinter) { uint8_t buf[2048]; TLVWriter writer; TLVReader reader; writer.Init(buf); writer.ImplicitProfileId = TestProfile_2; WriteEncoding1(writer); uint32_t encodedLen = writer.GetLengthWritten(); EXPECT_EQ(encodedLen, sizeof(Encoding1)); EXPECT_EQ(memcmp(buf, Encoding1, encodedLen), 0); reader.Init(buf, encodedLen); reader.ImplicitProfileId = TestProfile_2; chip::TLV::Debug::Dump(reader, SimpleDumpWriter); } static char gStringDumpWriterBuf[128] = { 0 }; static size_t gStringDumpWriterLengthWritten = 0; /** * Log the specified message in the form of @a aFormat. * * @param[in] aFormat A pointer to a NULL-terminated C string with * C Standard Library-style format specifiers * containing the log message to be formatted and * logged. * @param[in] ... An argument list whose elements should correspond * to the format specifiers in @a aFormat. * */ void ENFORCE_FORMAT(1, 2) StringDumpWriter(const char * aFormat, ...) { va_list args; va_start(args, aFormat); gStringDumpWriterLengthWritten += static_cast(vsprintf(&gStringDumpWriterBuf[gStringDumpWriterLengthWritten], aFormat, args)); va_end(args); } /** * Test Octet String Pretty Printer */ TEST_F(TestTLV, CheckOctetStringPrettyPrinter) { const uint8_t testOctetString[] = { 0x62, 0xFA, 0x82, 0x33, 0x59, 0xAC, 0xFA, 0xA9 }; const char expectedPrint[] = "0x04, tag[Common Profile (2 Bytes)]: 0x0::0x0::0x0, type: Octet String (0x10), length: 8, value: hex:62FA823359ACFAA9\n"; uint8_t encodedBuf[128] = { 0 }; TLVWriter writer; writer.Init(encodedBuf); EXPECT_EQ(CHIP_NO_ERROR, writer.PutBytes(CommonTag(0), testOctetString, sizeof(testOctetString))); EXPECT_EQ(CHIP_NO_ERROR, writer.Finalize()); TLVReader reader; reader.Init(encodedBuf, writer.GetLengthWritten()); chip::TLV::Debug::Dump(reader, StringDumpWriter); EXPECT_STREQ(expectedPrint, gStringDumpWriterBuf); } /** * Test Data Macros */ TEST_F(TestTLV, CheckDataMacro) { EXPECT_EQ(sizeof(Encoding1_DataMacro), sizeof(Encoding1)); EXPECT_EQ(memcmp(Encoding1, Encoding1_DataMacro, sizeof(Encoding1)), 0); uint8_t buf[2048]; TLVWriter writer; writer.Init(buf); writer.ImplicitProfileId = TestProfile_2; WriteEncoding5(writer); uint32_t encodedLen = writer.GetLengthWritten(); EXPECT_EQ(sizeof(Encoding5_DataMacro), encodedLen); EXPECT_EQ(memcmp(buf, Encoding5_DataMacro, encodedLen), 0); } static CHIP_ERROR NullIterateHandler(const TLVReader & aReader, size_t aDepth, void * aContext) { (void) aReader; (void) aDepth; (void) aContext; return CHIP_NO_ERROR; } static CHIP_ERROR FindContainerWithElement(const TLVReader & aReader, size_t aDepth, void * aContext) { TLVReader reader; TLVReader result; Tag * tag = static_cast(aContext); CHIP_ERROR err = CHIP_NO_ERROR; TLVType containerType; reader.Init(aReader); if (TLVTypeIsContainer(reader.GetType())) { ReturnErrorOnFailure(reader.EnterContainer(containerType)); err = chip::TLV::Utilities::Find(reader, *tag, result, false); // Map a successful find (CHIP_NO_ERROR) onto a signal that the element has been found. if (err == CHIP_NO_ERROR) { err = CHIP_ERROR_SENTINEL; } // Map a failed find attempt to NO_ERROR else if (err == CHIP_ERROR_TLV_TAG_NOT_FOUND) { err = CHIP_NO_ERROR; } } return err; } /** * Test CHIP TLV Utilities */ TEST_F(TestTLV, CheckTLVUtilities) { uint8_t buf[2048]; TLVWriter writer; TLVReader reader, reader1; CHIP_ERROR err = CHIP_NO_ERROR; writer.Init(buf); writer.ImplicitProfileId = TestProfile_2; WriteEncoding1(writer); uint32_t encodedLen = writer.GetLengthWritten(); EXPECT_EQ(encodedLen, sizeof(Encoding1)); EXPECT_EQ(memcmp(buf, Encoding1, encodedLen), 0); reader.Init(buf, encodedLen); reader.ImplicitProfileId = TestProfile_2; reader1.Init(reader); err = reader1.Next(); EXPECT_EQ(err, CHIP_NO_ERROR); // Find a tag TLVReader tagReader; err = chip::TLV::Utilities::Find(reader, ProfileTag(TestProfile_2, 65536), tagReader); EXPECT_EQ(err, CHIP_NO_ERROR); // Find with reader positioned "on" the element of interest err = chip::TLV::Utilities::Find(reader1, ProfileTag(TestProfile_1, 1), tagReader); EXPECT_EQ(err, CHIP_NO_ERROR); // Find a tag that's not present err = chip::TLV::Utilities::Find(reader, ProfileTag(TestProfile_2, 1024), tagReader); EXPECT_EQ(err, CHIP_ERROR_TLV_TAG_NOT_FOUND); // Find with a predicate { uint8_t buf1[74]; writer.Init(buf1); writer.ImplicitProfileId = TestProfile_2; WriteEncoding2(writer); // Initialize a reader reader1.Init(buf1, writer.GetLengthWritten()); reader1.ImplicitProfileId = TestProfile_2; // position the reader on the first element reader1.Next(); Tag tag = ProfileTag(TestProfile_1, 1); err = chip::TLV::Utilities::Find(reader1, FindContainerWithElement, &tag, tagReader, false); EXPECT_EQ(err, CHIP_ERROR_TLV_TAG_NOT_FOUND); tag = ProfileTag(TestProfile_2, 2); err = chip::TLV::Utilities::Find(reader1, FindContainerWithElement, &tag, tagReader, false); EXPECT_EQ(err, CHIP_NO_ERROR); EXPECT_EQ(tagReader.GetType(), kTLVType_Structure); EXPECT_EQ(tagReader.GetTag(), ProfileTag(TestProfile_1, 1)); // Position the reader on the second element reader1.Next(); err = chip::TLV::Utilities::Find(reader1, FindContainerWithElement, &tag, tagReader, false); EXPECT_EQ(err, CHIP_NO_ERROR); EXPECT_EQ(tagReader.GetType(), kTLVType_Structure); EXPECT_EQ(tagReader.GetTag(), ProfileTag(TestProfile_2, 1)); } // Count size_t count; const size_t expectedCount = 18; reader1.Init(reader); reader1.Next(); err = chip::TLV::Utilities::Count(reader, count); EXPECT_EQ(err, CHIP_NO_ERROR); EXPECT_EQ(count, expectedCount); // Count with reader already positioned "on" the first element in the encoding err = chip::TLV::Utilities::Count(reader1, count); EXPECT_EQ(err, CHIP_NO_ERROR); EXPECT_EQ(count, expectedCount); // Iterate err = chip::TLV::Utilities::Iterate(reader, NullIterateHandler, nullptr); EXPECT_EQ(err, CHIP_END_OF_TLV); } /** * Test CHIP TLV Empty Find */ TEST_F(TestTLV, CheckTLVEmptyFind) { uint8_t buf[30]; TLVWriter writer; TLVReader reader; CHIP_ERROR err = CHIP_NO_ERROR; writer.Init(buf); writer.ImplicitProfileId = TestProfile_2; WriteEmptyEncoding(writer); uint32_t encodedLen = writer.GetLengthWritten(); reader.Init(buf, encodedLen); reader.ImplicitProfileId = TestProfile_2; // Find the empty container TLVReader tagReader; err = chip::TLV::Utilities::Find(reader, ProfileTag(TestProfile_1, 256), tagReader); EXPECT_EQ(err, CHIP_NO_ERROR); } // clang-format off uint8_t Encoding2[] = { // Container 1 0xD5, 0xBB, 0xAA, 0xDD, 0xCC, 0x01, 0x00, 0xC9, 0xBB, 0xAA, 0xDD, 0xCC, 0x02, 0x00, 0x88, 0x02, 0x00, 0x18, // Container 2 0x95, 0x01, 0x00, 0x88, 0x02, 0x00, 0xC9, 0xBB, 0xAA, 0xDD, 0xCC, 0x02, 0x00, 0x18 }; uint8_t AppendedEncoding2[] = { // Container 1 0xD5, 0xBB, 0xAA, 0xDD, 0xCC, 0x01, 0x00, 0xC9, 0xBB, 0xAA, 0xDD, 0xCC, 0x02, 0x00, 0x88, 0x02, 0x00, 0xC8, 0xBB, 0xAA, 0xDD, 0xCC, 0x02, 0x00, 0x89, 0x02, 0x00, 0xD5, 0xBB, 0xAA, 0xDD, 0xCC, 0x01, 0x00, 0xC9, 0xBB, 0xAA, 0xDD, 0xCC, 0x02, 0x00, 0x88, 0x02, 0x00, 0x18, 0x95, 0x01, 0x00, 0x88, 0x02, 0x00, 0xC9, 0xBB, 0xAA, 0xDD, 0xCC, 0x02, 0x00, 0x18, 0x18, // Container 2 0x95, 0x01, 0x00, 0x88, 0x02, 0x00, 0xC9, 0xBB, 0xAA, 0xDD, 0xCC, 0x02, 0x00, 0x18 }; // clang-format on void WriteAppendReadTest0() { uint8_t buf[74]; uint32_t updatedLen; TLVWriter writer; TLVReader reader; writer.Init(buf); writer.ImplicitProfileId = TestProfile_2; WriteEncoding2(writer); uint32_t encodedLen = writer.GetLengthWritten(); #ifdef DUMP_ENCODING printf("Initial encoding:\n"); for (uint32_t i = 0; i < encodedLen; i++) { if (i != 0 && i % 16 == 0) printf("\n"); printf("0x%02X, ", buf[i]); } printf("\n"); #endif EXPECT_EQ(encodedLen, sizeof(Encoding2)); EXPECT_EQ(memcmp(buf, Encoding2, encodedLen), 0); // Append new data into encoding AppendEncoding2(buf, encodedLen, sizeof(buf), updatedLen); #ifdef DUMP_ENCODING printf("Updated encoding:\n"); for (uint32_t i = 0; i < updatedLen; i++) { if (i != 0 && i % 16 == 0) printf("\n"); printf("0x%02X, ", buf[i]); } printf("\n"); #endif EXPECT_EQ(updatedLen, sizeof(AppendedEncoding2)); EXPECT_EQ(memcmp(buf, AppendedEncoding2, updatedLen), 0); reader.Init(buf, updatedLen); reader.ImplicitProfileId = TestProfile_2; ReadAppendedEncoding2(reader); } void WriteFindAppendReadTest(bool findContainer) { uint8_t buf[74]; uint32_t updatedLen; TLVWriter writer; TLVReader reader; writer.Init(buf); writer.ImplicitProfileId = TestProfile_2; WriteEncoding2(writer); uint32_t encodedLen = writer.GetLengthWritten(); #ifdef DUMP_ENCODING printf("Initial encoding:\n"); for (uint32_t i = 0; i < encodedLen; i++) { if (i != 0 && i % 16 == 0) printf("\n"); printf("0x%02X, ", buf[i]); } printf("\n"); #endif EXPECT_EQ(encodedLen, sizeof(Encoding2)); EXPECT_EQ(memcmp(buf, Encoding2, encodedLen), 0); // Append new data into encoding FindAppendEncoding2(buf, encodedLen, sizeof(buf), updatedLen, findContainer); #ifdef DUMP_ENCODING printf("Updated encoding:\n"); for (uint32_t i = 0; i < updatedLen; i++) { if (i != 0 && i % 16 == 0) printf("\n"); printf("0x%02X, ", buf[i]); } printf("\n"); #endif EXPECT_EQ(updatedLen, sizeof(AppendedEncoding2)); EXPECT_EQ(memcmp(buf, AppendedEncoding2, updatedLen), 0); reader.Init(buf, updatedLen); reader.ImplicitProfileId = TestProfile_2; ReadAppendedEncoding2(reader); } // clang-format off uint8_t Encoding3[] = { // Container 1 0xD5, 0xBB, 0xAA, 0xDD, 0xCC, 0x01, 0x00, 0x88, 0x02, 0x00, 0x18, }; uint8_t AppendedEncoding3[] = { // Container 1 0xD5, 0xBB, 0xAA, 0xDD, 0xCC, 0x01, 0x00, 0x88, 0x02, 0x00, 0x89, 0x02, 0x00, 0x18 }; // clang-format on void WriteAppendReadTest1() { uint8_t buf[14]; uint32_t updatedLen; TLVWriter writer; TLVReader reader; writer.Init(buf); writer.ImplicitProfileId = TestProfile_2; WriteEncoding3(writer); uint32_t encodedLen = writer.GetLengthWritten(); #ifdef DUMP_ENCODING printf("Initial encoding:\n"); for (uint32_t i = 0; i < encodedLen; i++) { if (i != 0 && i % 16 == 0) printf("\n"); printf("0x%02X, ", buf[i]); } printf("\n"); #endif EXPECT_EQ(encodedLen, sizeof(Encoding3)); EXPECT_EQ(memcmp(buf, Encoding3, encodedLen), 0); // Append new data into encoding AppendEncoding3(buf, encodedLen, sizeof(buf), updatedLen); #ifdef DUMP_ENCODING printf("Updated encoding:\n"); for (uint32_t i = 0; i < updatedLen; i++) { if (i != 0 && i % 16 == 0) printf("\n"); printf("0x%02X, ", buf[i]); } printf("\n"); #endif EXPECT_EQ(updatedLen, sizeof(AppendedEncoding3)); EXPECT_EQ(memcmp(buf, AppendedEncoding3, updatedLen), 0); reader.Init(buf, updatedLen); reader.ImplicitProfileId = TestProfile_2; ReadAppendedEncoding3(reader); } // clang-format off uint8_t AppendedEncoding4[] = { // Container 1 0xD5, 0xBB, 0xAA, 0xDD, 0xCC, 0x01, 0x00, 0x88, 0x02, 0x00, 0x18, }; // clang-format on void AppendReadTest() { uint8_t buf[11]; uint32_t updatedLen; memset(buf, 0, sizeof(buf)); #ifdef DUMP_ENCODING printf("Initial encoding:\n"); for (uint32_t i = 0; i < sizeof(buf); i++) { if (i != 0 && i % 16 == 0) printf("\n"); printf("0x%02X, ", buf[i]); } printf("\n"); #endif // Append new data to encoding AppendEncoding4(buf, 0, sizeof(buf), updatedLen); #ifdef DUMP_ENCODING printf("Updated encoding:\n"); for (uint32_t i = 0; i < updatedLen; i++) { if (i != 0 && i % 16 == 0) printf("\n"); printf("0x%02X, ", buf[i]); } printf("\n"); #endif EXPECT_EQ(updatedLen, sizeof(AppendedEncoding4)); EXPECT_EQ(memcmp(buf, AppendedEncoding4, updatedLen), 0); TLVReader reader; reader.Init(buf, updatedLen); reader.ImplicitProfileId = TestProfile_2; ReadAppendedEncoding4(reader); } // clang-format off uint8_t Encoding5[] = { // Container 1 0xD5, 0xBB, 0xAA, 0xDD, 0xCC, 0x01, 0x00, 0xC9, 0xBB, 0xAA, 0xDD, 0xCC, 0x02, 0x00, 0x88, 0x02, 0x00, 0xC8, 0xBB, 0xAA, 0xDD, 0xCC, 0x02, 0x00, 0x89, 0x02, 0x00, 0xD5, 0xBB, 0xAA, 0xDD, 0xCC, 0x01, 0x00, 0xC9, 0xBB, 0xAA, 0xDD, 0xCC, 0x02, 0x00, 0x88, 0x02, 0x00, 0x18, 0x95, 0x01, 0x00, 0x88, 0x02, 0x00, 0xC9, 0xBB, 0xAA, 0xDD, 0xCC, 0x02, 0x00, 0x18, 0x18, // Container 2 0x95, 0x01, 0x00, 0x88, 0x02, 0x00, 0xC9, 0xBB, 0xAA, 0xDD, 0xCC, 0x02, 0x00, 0x18 }; uint8_t DeletedEncoding5[] = { // Container 1 0xD5, 0xBB, 0xAA, 0xDD, 0xCC, 0x01, 0x00, 0xC9, 0xBB, 0xAA, 0xDD, 0xCC, 0x02, 0x00, 0x88, 0x02, 0x00, 0x18, // Container 2 0x95, 0x01, 0x00, 0x88, 0x02, 0x00, 0xC9, 0xBB, 0xAA, 0xDD, 0xCC, 0x02, 0x00, 0x18 }; // clang-format on void WriteDeleteReadTest() { uint8_t buf[74]; uint32_t updatedLen; TLVWriter writer; TLVReader reader; writer.Init(buf); writer.ImplicitProfileId = TestProfile_2; WriteEncoding5(writer); uint32_t encodedLen = writer.GetLengthWritten(); #ifdef DUMP_ENCODING for (uint32_t i = 0; i < encodedLen; i++) { if (i != 0 && i % 16 == 0) printf("\n"); printf("0x%02X, ", buf[i]); } printf("\n"); #endif EXPECT_EQ(encodedLen, sizeof(Encoding5)); EXPECT_EQ(memcmp(buf, Encoding5, encodedLen), 0); // Delete some elements from the encoding DeleteEncoding5(buf, encodedLen, sizeof(buf), updatedLen); EXPECT_EQ(updatedLen, sizeof(DeletedEncoding5)); EXPECT_EQ(memcmp(buf, DeletedEncoding5, updatedLen), 0); reader.Init(buf, updatedLen); reader.ImplicitProfileId = TestProfile_2; ReadDeletedEncoding5(reader); } /** * Test Packet Buffer */ TEST_F(TestTLV, CheckPacketBuffer) { System::PacketBufferHandle buf = System::PacketBufferHandle::New(sizeof(Encoding1), 0); System::PacketBufferTLVWriter writer; System::PacketBufferTLVReader reader; writer.Init(buf.Retain()); writer.ImplicitProfileId = TestProfile_2; WriteEncoding1(writer); TestBufferContents(buf, Encoding1, sizeof(Encoding1)); reader.Init(buf.Retain()); reader.ImplicitProfileId = TestProfile_2; ReadEncoding1(reader); reader.Init(buf.Retain()); reader.ImplicitProfileId = TestProfile_2; ReadEncoding1(reader); } CHIP_ERROR CountEvictedMembers(TLVCircularBuffer & inBuffer, void * inAppData, TLVReader & inReader) { TestTLVContext * context = static_cast(inAppData); CHIP_ERROR err; // "Process" the first element in the reader err = inReader.Next(); EXPECT_EQ(err, CHIP_NO_ERROR); err = inReader.Skip(); EXPECT_EQ(err, CHIP_NO_ERROR); context->mEvictionCount++; context->mEvictedBytes += inReader.GetLengthRead(); return CHIP_NO_ERROR; } TEST_F(TestTLV, CheckCircularTLVBufferSimple) { // Write 40 bytes as 4 separate events into a 30 byte buffer. On // completion of the test, the buffer should contain 2 elements // and 2 elements should have been evicted in the last call to // WriteEncoding. uint8_t backingStore[30]; CircularTLVWriter writer; CircularTLVReader reader; TestTLVContext * context = &TestTLV::ctx; TLVCircularBuffer buffer(backingStore, 30); writer.Init(buffer); writer.ImplicitProfileId = TestProfile_2; context->mEvictionCount = 0; context->mEvictedBytes = 0; buffer.mProcessEvictedElement = CountEvictedMembers; buffer.mAppData = &TestTLV::ctx; writer.PutBoolean(ProfileTag(TestProfile_1, 2), true); WriteEncoding3(writer); WriteEncoding3(writer); WriteEncoding3(writer); EXPECT_EQ(context->mEvictionCount, 2); EXPECT_EQ(context->mEvictedBytes, 18u); EXPECT_EQ(buffer.DataLength(), 22u); EXPECT_EQ((buffer.DataLength() + context->mEvictedBytes), writer.GetLengthWritten()); // At this point the buffer should contain 2 instances of Encoding3. reader.Init(buffer); reader.ImplicitProfileId = TestProfile_2; TestNext(reader); ReadEncoding3(reader); TestNext(reader); ReadEncoding3(reader); // Check that the reader is out of data TestEnd(reader); } TEST_F(TestTLV, CheckCircularTLVBufferStartMidway) { // Write 40 bytes as 4 separate events into a 30 byte buffer. On // completion of the test, the buffer should contain 2 elements // and 2 elements should have been evicted in the last call to // WriteEncoding. uint8_t backingStore[30]; CircularTLVWriter writer; CircularTLVReader reader; TestTLVContext * context = &TestTLV::ctx; TLVCircularBuffer buffer(backingStore, 30, &(backingStore[15])); writer.Init(buffer); writer.ImplicitProfileId = TestProfile_2; context->mEvictionCount = 0; context->mEvictedBytes = 0; buffer.mProcessEvictedElement = CountEvictedMembers; buffer.mAppData = &TestTLV::ctx; writer.PutBoolean(ProfileTag(TestProfile_1, 2), true); WriteEncoding3(writer); WriteEncoding3(writer); WriteEncoding3(writer); EXPECT_EQ(context->mEvictionCount, 2); EXPECT_EQ(context->mEvictedBytes, 18u); EXPECT_EQ(buffer.DataLength(), 22u); EXPECT_EQ((buffer.DataLength() + context->mEvictedBytes), writer.GetLengthWritten()); // At this point the buffer should contain 2 instances of Encoding3. reader.Init(buffer); reader.ImplicitProfileId = TestProfile_2; TestNext(reader); ReadEncoding3(reader); TestNext(reader); ReadEncoding3(reader); // Check that the reader is out of data TestEnd(reader); } TEST_F(TestTLV, CheckCircularTLVBufferEvictStraddlingEvent) { // Write 95 bytes to the buffer as 9 different TLV elements: 1 // 7-byte element and 8 11-byte elements. // On completion of the test, the buffer should contain 2 elements // and 7 elements should have been evicted in the last call to // WriteEncoding. TestTLVContext * context = &TestTLV::ctx; uint8_t backingStore[30]; CircularTLVWriter writer; CircularTLVReader reader; TLVCircularBuffer buffer(backingStore, 30); writer.Init(buffer); writer.ImplicitProfileId = TestProfile_2; context->mEvictionCount = 0; context->mEvictedBytes = 0; buffer.mProcessEvictedElement = CountEvictedMembers; buffer.mAppData = &TestTLV::ctx; writer.PutBoolean(ProfileTag(TestProfile_1, 2), true); WriteEncoding3(writer); WriteEncoding3(writer); WriteEncoding3(writer); WriteEncoding3(writer); // the write below will evict an element that straddles the buffer boundary. WriteEncoding3(writer); WriteEncoding3(writer); WriteEncoding3(writer); WriteEncoding3(writer); EXPECT_EQ(writer.GetLengthWritten(), (8u * 11 + 7)); // 8 writes of Encoding3 (11 bytes each) and 7 bytes for the initial boolean. EXPECT_EQ(buffer.DataLength(), 22u); EXPECT_EQ((buffer.DataLength() + context->mEvictedBytes), writer.GetLengthWritten()); EXPECT_EQ(context->mEvictionCount, 7); // At this point the buffer should contain 2 instances of Encoding3. reader.Init(buffer); reader.ImplicitProfileId = TestProfile_2; TestNext(reader); ReadEncoding3(reader); TestNext(reader); ReadEncoding3(reader); // Check that the reader is out of data TestEnd(reader); } TEST_F(TestTLV, CheckCircularTLVBufferEdge) { TestTLVContext * context = &TestTLV::ctx; CHIP_ERROR err; uint8_t backingStore[7]; uint8_t backingStore1[14]; CircularTLVWriter writer; CircularTLVReader reader; TLVWriter writer1; TLVCircularBuffer buffer(backingStore, sizeof(backingStore)); TLVCircularBuffer buffer1(backingStore1, sizeof(backingStore1)); writer.Init(buffer); writer.ImplicitProfileId = TestProfile_2; context->mEvictionCount = 0; context->mEvictedBytes = 0; buffer.mProcessEvictedElement = CountEvictedMembers; buffer.mAppData = &TestTLV::ctx; // Test eviction for an element that fits in the underlying buffer exactly err = writer.PutBoolean(ProfileTag(TestProfile_1, 2), true); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer.PutBoolean(ProfileTag(TestProfile_1, 2), false); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer.Finalize(); EXPECT_EQ(err, CHIP_NO_ERROR); // At this point the buffer should contain only the boolean we just wrote reader.Init(buffer); reader.ImplicitProfileId = TestProfile_2; TestNext(reader); TEST_GET_NOERROR(reader, kTLVType_Boolean, ProfileTag(TestProfile_1, 2), false); // Check that the reader is out of data TestEnd(reader); // verify that an element larger than the underlying buffer fails out. err = writer.OpenContainer(ProfileTag(TestProfile_1, 1), kTLVType_Structure, writer1); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer1.PutBoolean(ProfileTag(TestProfile_2, 2), false); EXPECT_EQ(err, CHIP_END_OF_TLV); // Verify reader correctness // Write an element that takes half of the buffer, and evict it. // Do it 2 times, so we test what happens when the head is at the // middle and at the end of the buffer but the buffer is empty. int i = 0; for (i = 0; i < 2; i++) { writer.Init(buffer1); writer.ImplicitProfileId = TestProfile_2; err = writer.PutBoolean(ProfileTag(TestProfile_1, 2), true); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer.Finalize(); EXPECT_EQ(err, CHIP_NO_ERROR); reader.Init(buffer1); reader.ImplicitProfileId = TestProfile_2; TestNext(reader); TEST_GET_NOERROR(reader, kTLVType_Boolean, ProfileTag(TestProfile_1, 2), true); TestEnd(reader); buffer1.EvictHead(); reader.Init(buffer1); reader.ImplicitProfileId = TestProfile_2; TestEnd(reader); } writer.Init(buffer1); writer.ImplicitProfileId = TestProfile_2; context->mEvictionCount = 0; context->mEvictedBytes = 0; buffer1.mProcessEvictedElement = CountEvictedMembers; buffer1.mAppData = &TestTLV::ctx; // Two elements fit in the buffer exactly err = writer.PutBoolean(ProfileTag(TestProfile_1, 2), true); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer.PutBoolean(ProfileTag(TestProfile_1, 2), false); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer.Finalize(); // Verify that we can read out two elements from the buffer reader.Init(buffer1); reader.ImplicitProfileId = TestProfile_2; TestNext(reader); TEST_GET_NOERROR(reader, kTLVType_Boolean, ProfileTag(TestProfile_1, 2), true); TestNext(reader); TEST_GET_NOERROR(reader, kTLVType_Boolean, ProfileTag(TestProfile_1, 2), false); TestEnd(reader); // Check that the eviction works as expected buffer1.EvictHead(); // At this point the buffer should contain only the second boolean reader.Init(buffer1); reader.ImplicitProfileId = TestProfile_2; TestNext(reader); TEST_GET_NOERROR(reader, kTLVType_Boolean, ProfileTag(TestProfile_1, 2), false); // Check that the reader is out of data TestEnd(reader); // Write another boolean, verify that the buffer is full and contains two booleans writer.Init(buffer1); writer.ImplicitProfileId = TestProfile_2; err = writer.PutBoolean(ProfileTag(TestProfile_1, 2), true); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer.Finalize(); EXPECT_EQ(err, CHIP_NO_ERROR); // Verify that we can read out two elements from the buffer reader.Init(buffer1); reader.ImplicitProfileId = TestProfile_2; TestNext(reader); TEST_GET_NOERROR(reader, kTLVType_Boolean, ProfileTag(TestProfile_1, 2), false); TestNext(reader); TEST_GET_NOERROR(reader, kTLVType_Boolean, ProfileTag(TestProfile_1, 2), true); TestEnd(reader); // Evict the elements from the buffer, verfiy that we have an // empty reader on our hands buffer1.EvictHead(); buffer1.EvictHead(); reader.Init(buffer1); reader.ImplicitProfileId = TestProfile_2; TestEnd(reader); } TEST_F(TestTLV, CheckTLVPutStringF) { const size_t bufsize = 24; char strBuffer[bufsize]; char valStr[bufsize]; uint8_t backingStore[bufsize]; TLVWriter writer; TLVReader reader; size_t num = 1; CHIP_ERROR err = CHIP_NO_ERROR; writer.Init(backingStore, bufsize); snprintf(strBuffer, sizeof(strBuffer), "Sample string %u", static_cast(num)); err = writer.PutStringF(ProfileTag(TestProfile_1, 1), "Sample string %u", static_cast(num)); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer.Finalize(); EXPECT_EQ(err, CHIP_NO_ERROR); reader.Init(backingStore, writer.GetLengthWritten()); err = reader.Next(); EXPECT_EQ(err, CHIP_NO_ERROR); err = reader.GetString(valStr, bufsize); EXPECT_EQ(err, CHIP_NO_ERROR); EXPECT_EQ(strncmp(valStr, strBuffer, bufsize), 0); } TEST_F(TestTLV, CheckTLVPutStringSpan) { const size_t bufsize = 24; char strBuffer[bufsize] = "Sample string"; char valStr[bufsize]; uint8_t backingStore[bufsize]; TLVWriter writer; TLVReader reader; CHIP_ERROR err = CHIP_NO_ERROR; Span strSpan; // // Write a string that has a size that exceeds 32-bits. This is only possible // on platforms where size_t is bigger than uint32_t. // if (sizeof(size_t) > sizeof(uint32_t)) { writer.Init(backingStore, bufsize); snprintf(strBuffer, sizeof(strBuffer), "Sample string"); strSpan = { strBuffer, static_cast(0xffffffffff) }; err = writer.PutString(ProfileTag(TestProfile_1, 1), strSpan); EXPECT_NE(err, CHIP_NO_ERROR); } { writer.Init(backingStore, bufsize); snprintf(strBuffer, sizeof(strBuffer), "Sample string"); strSpan = { strBuffer, strlen("Sample string") }; err = writer.PutString(ProfileTag(TestProfile_1, 1), strSpan); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer.Finalize(); EXPECT_EQ(err, CHIP_NO_ERROR); reader.Init(backingStore, writer.GetLengthWritten()); err = reader.Next(); EXPECT_EQ(err, CHIP_NO_ERROR); err = reader.GetString(valStr, bufsize); EXPECT_EQ(err, CHIP_NO_ERROR); EXPECT_EQ(strncmp(valStr, strBuffer, bufsize), 0); } } TEST_F(TestTLV, CheckTLVPutStringFCircular) { const size_t bufsize = 40; char strBuffer[bufsize]; char valStr[bufsize]; uint8_t backingStore[bufsize]; CircularTLVWriter writer; CircularTLVReader reader; TLVCircularBuffer buffer(backingStore, bufsize); size_t num = 1; CHIP_ERROR err = CHIP_NO_ERROR; // Initial test: Verify that a straight printf works as expected into continuous buffer. writer.Init(buffer); snprintf(strBuffer, sizeof(strBuffer), "Sample string %u", static_cast(num)); err = writer.PutBoolean(ProfileTag(TestProfile_1, 2), true); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer.Finalize(); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer.PutStringF(ProfileTag(TestProfile_1, 1), "Sample string %u", static_cast(num)); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer.Finalize(); EXPECT_EQ(err, CHIP_NO_ERROR); reader.Init(buffer); // Skip over the initial element err = reader.Next(); EXPECT_EQ(err, CHIP_NO_ERROR); err = reader.Next(); EXPECT_EQ(err, CHIP_NO_ERROR); err = reader.GetString(valStr, bufsize); EXPECT_EQ(err, CHIP_NO_ERROR); EXPECT_EQ(strncmp(valStr, strBuffer, bufsize), 0); // Verify that the PutStringF will handle correctly the case with the discontinuous buffer // This print will both stradle the boundary of the buffer and displace the previous two elements. num = 2; snprintf(strBuffer, sizeof(strBuffer), "Sample string %u", static_cast(num)); err = writer.PutStringF(ProfileTag(TestProfile_1, 1), "Sample string %u", static_cast(num)); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer.Finalize(); EXPECT_EQ(err, CHIP_NO_ERROR); reader.Init(buffer); err = reader.Next(); EXPECT_EQ(err, CHIP_NO_ERROR); err = reader.GetString(valStr, bufsize); EXPECT_EQ(err, CHIP_NO_ERROR); EXPECT_EQ(strncmp(valStr, strBuffer, bufsize), 0); } TEST_F(TestTLV, CheckTLVByteSpan) { const size_t bufSize = 14; uint8_t bytesBuffer[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 }; uint8_t backingStore[bufSize]; TLVWriter writer; TLVReader reader; CHIP_ERROR err = CHIP_NO_ERROR; writer.Init(backingStore); ByteSpan writerSpan(bytesBuffer); err = writer.Put(ProfileTag(TestProfile_1, 1), writerSpan); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer.Finalize(); EXPECT_EQ(err, CHIP_NO_ERROR); reader.Init(backingStore, writer.GetLengthWritten()); err = reader.Next(); EXPECT_EQ(err, CHIP_NO_ERROR); chip::ByteSpan readerSpan; err = reader.Get(readerSpan); EXPECT_EQ(err, CHIP_NO_ERROR); EXPECT_EQ(memcmp(readerSpan.data(), bytesBuffer, sizeof(bytesBuffer)), 0); } #define IS1_CHAR "\x1F" TEST_F(TestTLV, CheckTLVCharSpan) { struct CharSpanTestCase { const char * testString; const char * expectedString; }; // clang-format off static CharSpanTestCase sCharSpanTestCases[] = { // Test String Expected String from Get() // ================================================================================================== { "This is a test case #0", "This is a test case #0" }, { "This is a test case #1" IS1_CHAR "Test Localized String Identifier", "This is a test case #1" }, { "This is a test case #2 " IS1_CHAR "abc" IS1_CHAR "def", "This is a test case #2 " }, { "This is a test case #3" IS1_CHAR, "This is a test case #3" }, { "Thé" IS1_CHAR, "Thé" }, { IS1_CHAR " abc " IS1_CHAR " def", "" }, }; // clang-format on for (auto & testCase : sCharSpanTestCases) { uint8_t backingStore[100]; TLVWriter writer; TLVReader reader; CHIP_ERROR err = CHIP_NO_ERROR; writer.Init(backingStore); err = writer.PutString(ProfileTag(TestProfile_1, 1), testCase.testString); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer.Finalize(); EXPECT_EQ(err, CHIP_NO_ERROR); reader.Init(backingStore, writer.GetLengthWritten()); err = reader.Next(); EXPECT_EQ(err, CHIP_NO_ERROR); chip::CharSpan readerSpan; err = reader.Get(readerSpan); EXPECT_EQ(err, CHIP_NO_ERROR); EXPECT_EQ(strlen(testCase.expectedString), readerSpan.size()); EXPECT_EQ(memcmp(readerSpan.data(), testCase.expectedString, strlen(testCase.expectedString)), 0); } } TEST_F(TestTLV, CheckTLVGetLocalizedStringIdentifier) { struct CharSpanTestCase { const char * testString; Optional expectedLSID; CHIP_ERROR expectedResult; }; // clang-format off static CharSpanTestCase sCharSpanTestCases[] = { // Test String Expected LocalizedStringIdentifier from Get() Expected Return // ============================================================================================================================================= { "This is a test case #0", chip::Optional(), CHIP_NO_ERROR }, { "This is a test case #1" IS1_CHAR "0123", chip::Optional(), CHIP_ERROR_INVALID_TLV_ELEMENT }, { "This is a test case #2" IS1_CHAR "123" IS1_CHAR "3210", chip::Optional(0x123), CHIP_NO_ERROR }, { "This is a test case #3" IS1_CHAR "012", chip::Optional(), CHIP_ERROR_INVALID_TLV_ELEMENT }, { "This is a test case #3" IS1_CHAR "12", chip::Optional(0x12), CHIP_NO_ERROR }, { "Thé" IS1_CHAR "", chip::Optional(), CHIP_NO_ERROR }, { "Thé" IS1_CHAR "7", chip::Optional(0x7), CHIP_NO_ERROR }, { "Thé" IS1_CHAR "1FA", chip::Optional(0x1FA), CHIP_NO_ERROR }, { "" IS1_CHAR "1FA", chip::Optional(0x1FA), CHIP_NO_ERROR }, { "Thé" IS1_CHAR "1FAB", chip::Optional(0x1FAB), CHIP_NO_ERROR }, { "Thé" IS1_CHAR "1FAb", chip::Optional(), CHIP_ERROR_INVALID_TLV_ELEMENT }, { "Thé" IS1_CHAR "1FABC", chip::Optional(), CHIP_ERROR_INVALID_TLV_ELEMENT }, { "Thé" IS1_CHAR "1FA" IS1_CHAR "", chip::Optional(0x1FA), CHIP_NO_ERROR }, { "Thé" IS1_CHAR "1FA" IS1_CHAR "F8sa===", chip::Optional(0x1FA), CHIP_NO_ERROR }, }; // clang-format on for (auto & testCase : sCharSpanTestCases) { uint8_t backingStore[100]; TLVWriter writer; TLVReader reader; CHIP_ERROR err = CHIP_NO_ERROR; writer.Init(backingStore); err = writer.PutString(ProfileTag(TestProfile_1, 1), testCase.testString); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer.Finalize(); EXPECT_EQ(err, CHIP_NO_ERROR); reader.Init(backingStore, writer.GetLengthWritten()); err = reader.Next(); EXPECT_EQ(err, CHIP_NO_ERROR); Optional readerLSID; err = reader.Get(readerLSID); EXPECT_EQ(testCase.expectedResult, err); EXPECT_EQ(testCase.expectedLSID, readerLSID); } // Error case: A case of TLVReader buffer underrun. // Expected error after Next() call is: CHIP_ERROR_TLV_UNDERRUN { uint8_t backingStore[100]; TLVWriter writer; TLVReader reader; CHIP_ERROR err = CHIP_NO_ERROR; writer.Init(backingStore); err = writer.PutString(ProfileTag(TestProfile_1, 1), sCharSpanTestCases[2].testString); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer.Finalize(); EXPECT_EQ(err, CHIP_NO_ERROR); reader.Init(backingStore, writer.GetLengthWritten() - 1); err = reader.Next(); EXPECT_EQ(err, CHIP_ERROR_TLV_UNDERRUN); } // Error case: the reader is on a bytestring, not utf-8 string. // Expected error after Get(Optional &) call is: CHIP_ERROR_WRONG_TLV_TYPE { uint8_t backingStore[100]; TLVWriter writer; TLVReader reader; CHIP_ERROR err = CHIP_NO_ERROR; writer.Init(backingStore); err = writer.PutBytes(ProfileTag(TestProfile_1, 1), reinterpret_cast(sCharSpanTestCases[2].testString), static_cast(strlen(sCharSpanTestCases[2].testString))); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer.Finalize(); EXPECT_EQ(err, CHIP_NO_ERROR); reader.Init(backingStore, writer.GetLengthWritten()); err = reader.Next(); EXPECT_EQ(err, CHIP_NO_ERROR); Optional readerLSID; err = reader.Get(readerLSID); EXPECT_EQ(err, CHIP_ERROR_WRONG_TLV_TYPE); EXPECT_EQ(readerLSID, Optional()); } } TEST_F(TestTLV, CheckTLVSkipCircular) { const size_t bufsize = 40; // large enough s.t. 2 elements fit, 3rd causes eviction uint8_t backingStore[bufsize]; char testString[] = "Sample string"; // 13 characters, without the trailing NULL, add 3 bytes for anon tag // Any pair of reader and writer would work here, either PacketBuffer based or CircularTLV based. CircularTLVWriter writer; CircularTLVReader reader; TLVCircularBuffer buffer(backingStore, bufsize); CHIP_ERROR err = CHIP_NO_ERROR; writer.Init(buffer); err = writer.PutString(AnonymousTag(), testString); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer.PutString(AnonymousTag(), testString); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer.PutString(AnonymousTag(), testString); // This event straddles the boundary EXPECT_EQ(err, CHIP_NO_ERROR); err = writer.PutString(AnonymousTag(), testString); // This one does not. EXPECT_EQ(err, CHIP_NO_ERROR); err = writer.Finalize(); EXPECT_EQ(err, CHIP_NO_ERROR); reader.Init(buffer); err = reader.Next(); // position the reader at the straddling element EXPECT_EQ(err, CHIP_NO_ERROR); err = reader.Skip(); // // Test that the buf ptr is handled correctly within the ReadData() function. EXPECT_EQ(err, CHIP_NO_ERROR); } /** * Test Buffer Overflow */ TEST_F(TestTLV, CheckBufferOverflow) { System::PacketBufferTLVReader reader; System::PacketBufferHandle buf = System::PacketBufferHandle::New(sizeof(Encoding1), 0); uint32_t maxDataLen = static_cast(buf->MaxDataLength()); uint32_t reserve = static_cast((sizeof(Encoding1) < maxDataLen) ? (maxDataLen - sizeof(Encoding1)) + 2 : 0); // Repeatedly write and read a TLV encoding to a chain of PacketBuffers. Use progressively larger // and larger amounts of space in the first buffer to force the encoding to overlap the // end of the buffer and the beginning of the next. for (; reserve < maxDataLen; reserve++) { buf->SetStart(buf->Start() + reserve); { System::PacketBufferTLVWriter writer; // Scope for writer because we want it to go out of scope before we // mess with the chain after writing is done. writer.Init(buf.Retain(), /* useChainedBuffers = */ true); writer.ImplicitProfileId = TestProfile_2; WriteEncoding1(writer); } TestBufferContents(buf, Encoding1, sizeof(Encoding1)); // Compact the buffer, since we don't allow reading from chained // buffers. buf->CompactHead(); reader.Init(buf.Retain()); reader.ImplicitProfileId = TestProfile_2; ReadEncoding1(reader); buf = System::PacketBufferHandle::New(sizeof(Encoding1), 0); } } /** * Test case to verify the correctness of TLVReader::GetTag() * * TLVReader::GetTag() does not return the correct tag value when the * the compiler optimization level contains strict aliasing. In the below * example, the returned tag value would be 0xe, instead of 0xe00000001. * * The issue has been spotted on debug builds. * */ // clang-format off static const uint8_t sIdentifyResponseBuf[] = { 0xD5, 0x00, 0x00, 0x0E, 0x00, 0x01, 0x00, 0x25, 0x00, 0x5A, 0x23, 0x24, 0x01, 0x07, 0x24, 0x02, 0x05, 0x25, 0x03, 0x22, 0x1E, 0x2C, 0x04, 0x10, 0x30, 0x34, 0x41, 0x41, 0x30, 0x31, 0x41, 0x43, 0x32, 0x33, 0x31, 0x34, 0x30, 0x30, 0x4C, 0x50, 0x2C, 0x09, 0x06, 0x31, 0x2E, 0x34, 0x72, 0x63, 0x35, 0x24, 0x0C, 0x01, 0x18, }; // clang-format on static const uint32_t kIdentifyResponseLen = 53; TEST_F(TestTLV, CheckStrictAliasing) { const uint32_t kProfile_Id = 0x0000000e; CHIP_ERROR err = CHIP_NO_ERROR; TLVReader reader; reader.Init(sIdentifyResponseBuf, kIdentifyResponseLen); reader.ImplicitProfileId = kProfile_Id; err = reader.Next(); EXPECT_EQ(err, CHIP_NO_ERROR); EXPECT_EQ(reader.GetTag(), ProfileTag(kProfile_Id, 1)); } /** * Test CHIP TLV Writer Copy Container */ void TestTLVWriterCopyContainer() { uint8_t buf[2048]; { TLVWriter writer; TLVReader reader; reader.Init(Encoding1); reader.ImplicitProfileId = TestProfile_2; TestNext(reader); writer.Init(buf); writer.ImplicitProfileId = TestProfile_2; CHIP_ERROR err = writer.CopyContainer(reader); EXPECT_EQ(err, CHIP_NO_ERROR); uint32_t encodedLen = writer.GetLengthWritten(); EXPECT_EQ(encodedLen, sizeof(Encoding1)); int memcmpRes = memcmp(buf, Encoding1, encodedLen); EXPECT_EQ(memcmpRes, 0); } { TLVWriter writer; writer.Init(buf); writer.ImplicitProfileId = TestProfile_2; CHIP_ERROR err = writer.CopyContainer(ProfileTag(TestProfile_1, 1), Encoding1, sizeof(Encoding1)); EXPECT_EQ(err, CHIP_NO_ERROR); uint32_t encodedLen = writer.GetLengthWritten(); EXPECT_EQ(encodedLen, sizeof(Encoding1)); int memcmpRes = memcmp(buf, Encoding1, encodedLen); EXPECT_EQ(memcmpRes, 0); } } /** * Test CHIP TLV Writer Copy Element */ void TestTLVWriterCopyElement() { CHIP_ERROR err; uint8_t expectedBuf[2048], testBuf[2048]; uint32_t expectedLen, testLen; TLVWriter writer; TLVType outerContainerType; enum { kRepeatCount = 3 }; writer.Init(expectedBuf); writer.ImplicitProfileId = TestProfile_2; err = writer.StartContainer(AnonymousTag(), kTLVType_Structure, outerContainerType); EXPECT_EQ(err, CHIP_NO_ERROR); for (int i = 0; i < kRepeatCount; i++) { WriteEncoding1(writer); } err = writer.EndContainer(outerContainerType); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer.Finalize(); EXPECT_EQ(err, CHIP_NO_ERROR); expectedLen = writer.GetLengthWritten(); writer.Init(testBuf); writer.ImplicitProfileId = TestProfile_2; err = writer.StartContainer(AnonymousTag(), kTLVType_Structure, outerContainerType); EXPECT_EQ(err, CHIP_NO_ERROR); for (int i = 0; i < kRepeatCount; i++) { TLVReader reader; reader.Init(Encoding1); reader.ImplicitProfileId = TestProfile_2; TestNext(reader); err = writer.CopyElement(reader); EXPECT_EQ(err, CHIP_NO_ERROR); } err = writer.EndContainer(outerContainerType); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer.Finalize(); EXPECT_EQ(err, CHIP_NO_ERROR); testLen = writer.GetLengthWritten(); EXPECT_EQ(testLen, expectedLen); int memcmpRes = memcmp(testBuf, expectedBuf, testLen); EXPECT_EQ(memcmpRes, 0); } void PreserveSizeWrite(TLVWriter & writer, bool preserveSize) { CHIP_ERROR err; TLVWriter writer2; // TLVTagControl::FullyQualified_8Bytes err = writer.Put(ProfileTag(TestProfile_1, 4000000000ULL), static_cast(40000000000ULL), true); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer.Put(ProfileTag(TestProfile_1, 4000000000ULL), static_cast(12345), true); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer.Put(ProfileTag(TestProfile_1, 4000000000ULL), static_cast(1.0)); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer.OpenContainer(ProfileTag(TestProfile_1, 1), kTLVType_Structure, writer2); EXPECT_EQ(err, CHIP_NO_ERROR); { TLVWriter writer3; err = writer2.OpenContainer(ContextTag(0), kTLVType_Array, writer3); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer3.Put(AnonymousTag(), static_cast(42), preserveSize); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer3.Put(AnonymousTag(), static_cast(42), preserveSize); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer3.Put(AnonymousTag(), static_cast(42), preserveSize); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer3.Put(AnonymousTag(), static_cast(40000000000ULL), preserveSize); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer3.Put(AnonymousTag(), static_cast(-17), preserveSize); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer3.Put(AnonymousTag(), static_cast(-17), preserveSize); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer3.Put(AnonymousTag(), static_cast(-170000), preserveSize); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer3.Put(AnonymousTag(), static_cast(-170000), preserveSize); EXPECT_EQ(err, CHIP_NO_ERROR); // the below cases are for full coverage of PUTs err = writer3.Put(AnonymousTag(), static_cast(65535), false); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer3.Put(AnonymousTag(), static_cast(32767), false); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer3.Put(AnonymousTag(), static_cast(40000000000ULL), false); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer2.CloseContainer(writer3); EXPECT_EQ(err, CHIP_NO_ERROR); } err = writer.CloseContainer(writer2); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer.Finalize(); EXPECT_EQ(err, CHIP_NO_ERROR); } /** * Test CHIP TLV Writer with Preserve Size */ void TestTLVWriterPreserveSize() { uint8_t buf[2048]; TLVWriter writer; writer.Init(buf); writer.ImplicitProfileId = TestProfile_2; PreserveSizeWrite(writer, true); uint32_t encodedLen = writer.GetLengthWritten(); EXPECT_EQ(encodedLen, 105u); } /** * Test error handling of CHIP TLV Writer */ void TestTLVWriterErrorHandling() { CHIP_ERROR err; uint8_t buf[2048]; TLVWriter writer, writer2, writer3; writer.Init(buf); writer.ImplicitProfileId = TestProfile_2; // OpenContainer() for non-container err = writer.OpenContainer(ProfileTag(TestProfile_1, 1), kTLVType_Boolean, writer2); EXPECT_EQ(err, CHIP_ERROR_WRONG_TLV_TYPE); // Since OpenContainer failed, writer2 remains uninitialized. writer2.Init(nullptr, 0); // CloseContainer() for non-container err = writer.CloseContainer(writer2); EXPECT_EQ(err, CHIP_ERROR_INCORRECT_STATE); // OpenContainer() failure err = writer.OpenContainer(ProfileTag(TestProfile_1, 1), kTLVType_Structure, writer2); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer2.OpenContainer(ProfileTag(TestProfile_1, 1), kTLVType_Structure, writer3); EXPECT_EQ(err, CHIP_NO_ERROR); // CloseContainer() failure err = writer.CloseContainer(writer2); EXPECT_EQ(err, CHIP_ERROR_TLV_CONTAINER_OPEN); // StartContainer() TLVType outerContainerType; err = writer.StartContainer(ProfileTag(TestProfile_2, 4000000000ULL), kTLVType_Boolean, outerContainerType); EXPECT_EQ(err, CHIP_ERROR_WRONG_TLV_TYPE); // EndContainer() outerContainerType = kTLVType_Boolean; err = writer.EndContainer(outerContainerType); EXPECT_EQ(err, CHIP_ERROR_INCORRECT_STATE); // PutPreEncodedContainer() TLVReader reader; reader.Init(buf, 2048); err = writer.PutPreEncodedContainer(ProfileTag(TestProfile_2, 4000000000ULL), kTLVType_Boolean, reader.GetReadPoint(), reader.GetRemainingLength()); EXPECT_EQ(err, CHIP_ERROR_INVALID_ARGUMENT); } void TestTLVEmptyString() { uint8_t buf[2]; TLVWriter writer; CHIP_ERROR err; ByteSpan s; writer.Init(buf); err = writer.PutString(AnonymousTag(), nullptr, 0); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer.Finalize(); EXPECT_EQ(err, CHIP_NO_ERROR); TLVReader reader; reader.Init(buf); err = reader.Next(); EXPECT_EQ(err, CHIP_NO_ERROR); err = reader.Get(s); EXPECT_EQ(err, CHIP_NO_ERROR); EXPECT_EQ(s.data(), nullptr); EXPECT_EQ(s.size(), 0u); } /** * Test CHIP TLV Writer */ TEST_F(TestTLV, CheckTLVWriter) { TestTLVWriterCopyContainer(); TestTLVWriterCopyElement(); TestTLVWriterPreserveSize(); TestTLVWriterErrorHandling(); TestTLVEmptyString(); } void SkipNonContainer() { TLVReader reader; const uint8_t * readpoint1 = nullptr; const uint8_t * readpoint2 = nullptr; reader.Init(Encoding1); reader.ImplicitProfileId = TestProfile_2; TestSkip(reader); readpoint1 = reader.GetReadPoint(); // Skip again, to check the operation is idempotent TestSkip(reader); readpoint2 = reader.GetReadPoint(); EXPECT_EQ(readpoint1, readpoint2); } void SkipContainer() { TLVReader reader; const uint8_t * readpoint1 = nullptr; const uint8_t * readpoint2 = nullptr; reader.Init(Encoding1); reader.ImplicitProfileId = TestProfile_2; TestNext(reader); TestSkip(reader); readpoint1 = reader.GetReadPoint(); // Skip again, to check the operation is idempotent TestSkip(reader); readpoint2 = reader.GetReadPoint(); EXPECT_EQ(readpoint1, readpoint2); } void NextContainer() { TLVReader reader; reader.Init(Encoding1); reader.ImplicitProfileId = TestProfile_2; TestNext(reader); CHIP_ERROR err = reader.Next(); EXPECT_EQ(err, CHIP_END_OF_TLV); } /** * Test CHIP TLV Reader Skip functions */ void TestTLVReaderSkip() { SkipNonContainer(); SkipContainer(); NextContainer(); } /** * Test CHIP TLV Reader Dup functions */ void TestTLVReaderDup() { TLVReader reader; reader.Init(Encoding1); reader.ImplicitProfileId = TestProfile_2; TestNext(reader); { TLVReader reader2; TestAndOpenContainer(reader, kTLVType_Structure, ProfileTag(TestProfile_1, 1), reader2); TestNext(reader2); TEST_GET_NOERROR(reader2, kTLVType_Boolean, ProfileTag(TestProfile_1, 2), true); TestNext(reader2); TEST_GET_NOERROR(reader2, kTLVType_Boolean, ProfileTag(TestProfile_2, 2), false); TestNext(reader2); { TLVReader reader3; TestAndOpenContainer(reader2, kTLVType_Array, ContextTag(0), reader3); TestNext(reader3); TEST_GET_NOERROR(reader3, kTLVType_SignedInteger, AnonymousTag(), static_cast(42)); TEST_GET_NOERROR(reader3, kTLVType_SignedInteger, AnonymousTag(), static_cast(42)); TEST_GET_NOERROR(reader3, kTLVType_SignedInteger, AnonymousTag(), static_cast(42)); TEST_GET_NOERROR(reader3, kTLVType_SignedInteger, AnonymousTag(), static_cast(42)); TEST_GET(reader3, kTLVType_SignedInteger, AnonymousTag(), static_cast(42), CHIP_ERROR_WRONG_TLV_TYPE); TEST_GET(reader3, kTLVType_SignedInteger, AnonymousTag(), static_cast(42), CHIP_ERROR_WRONG_TLV_TYPE); TestNext(reader3); TEST_GET_NOERROR(reader3, kTLVType_SignedInteger, AnonymousTag(), static_cast(-17)); TEST_GET_NOERROR(reader3, kTLVType_SignedInteger, AnonymousTag(), static_cast(-17)); TEST_GET_NOERROR(reader3, kTLVType_SignedInteger, AnonymousTag(), static_cast(-17)); TEST_GET_NOERROR(reader3, kTLVType_SignedInteger, AnonymousTag(), static_cast(-17)); TestNext(reader3); TEST_GET_NOERROR(reader3, kTLVType_SignedInteger, AnonymousTag(), static_cast(-170000)); TEST_GET_NOERROR(reader3, kTLVType_SignedInteger, AnonymousTag(), static_cast(-170000)); TestNext(reader3); TEST_GET(reader3, kTLVType_UnsignedInteger, AnonymousTag(), static_cast(40000000000ULL), CHIP_ERROR_WRONG_TLV_TYPE); TEST_GET_NOERROR(reader3, kTLVType_UnsignedInteger, AnonymousTag(), static_cast(40000000000ULL)); TestNext(reader3); { TLVReader reader4; TestAndOpenContainer(reader3, kTLVType_Structure, AnonymousTag(), reader4); TestEndAndCloseContainer(reader3, reader4); } TestNext(reader3); { TLVReader reader5; TestAndOpenContainer(reader3, kTLVType_List, AnonymousTag(), reader5); TestNext(reader5); TestNull(reader5, ProfileTag(TestProfile_1, 17)); TestNext(reader5); TestNull(reader5, ProfileTag(TestProfile_2, 900000)); TestNext(reader5); TestNull(reader5, AnonymousTag()); TestNext(reader5); { TLVType outerContainerType; TestAndEnterContainer(reader5, kTLVType_Structure, ProfileTag(TestProfile_2, 4000000000ULL), outerContainerType); TestNext(reader5); TestDupString(reader5, CommonTag(70000), sLargeString); TestEndAndExitContainer(reader5, outerContainerType); } TestEndAndCloseContainer(reader3, reader5); } TestEndAndCloseContainer(reader2, reader3); } TestNext(reader2); TestDupBytes(reader2, ProfileTag(TestProfile_1, 5), reinterpret_cast("This is a test"), 14); TestNext(reader2); TEST_GET_NOERROR(reader2, kTLVType_FloatingPointNumber, ProfileTag(TestProfile_2, 65535), 17.9f); TEST_GET_NOERROR(reader2, kTLVType_FloatingPointNumber, ProfileTag(TestProfile_2, 65535), static_cast(17.9f)); TestNext(reader2); TEST_GET_NOERROR(reader2, kTLVType_FloatingPointNumber, ProfileTag(TestProfile_2, 65536), 17.9); TestEndAndCloseContainer(reader, reader2); } TestEnd(reader); } /** * Test error handling of CHIP TLV Reader */ void TestTLVReaderErrorHandling() { CHIP_ERROR err; uint8_t buf[2048] = { 0 }; TLVReader reader; reader.Init(buf); reader.ImplicitProfileId = TestProfile_2; // Get(bool&) bool val; err = reader.Get(val); EXPECT_EQ(err, CHIP_ERROR_WRONG_TLV_TYPE); // Get(float&) float numF; err = reader.Get(numF); EXPECT_EQ(err, CHIP_ERROR_WRONG_TLV_TYPE); // Get(double&) double numD; err = reader.Get(numD); EXPECT_EQ(err, CHIP_ERROR_WRONG_TLV_TYPE); // Get(uint64_t&) uint64_t num; err = reader.Get(num); EXPECT_EQ(err, CHIP_ERROR_WRONG_TLV_TYPE); // GetBytes() uint8_t bBuf[16]; err = reader.GetBytes(bBuf, sizeof(bBuf)); EXPECT_EQ(err, CHIP_ERROR_WRONG_TLV_TYPE); // GetString() char sBuf[16]; err = reader.GetString(sBuf, sizeof(sBuf)); EXPECT_EQ(err, CHIP_ERROR_WRONG_TLV_TYPE); // OpenContainer() TLVReader reader2; err = reader.OpenContainer(reader2); EXPECT_EQ(err, CHIP_ERROR_INCORRECT_STATE); // CloseContainer() err = reader.CloseContainer(reader2); EXPECT_EQ(err, CHIP_ERROR_INCORRECT_STATE); // EnterContainer() TLVType outerContainerType = kTLVType_Boolean; err = reader.EnterContainer(outerContainerType); EXPECT_EQ(err, CHIP_ERROR_INCORRECT_STATE); // DupString() char * str = static_cast(chip::Platform::MemoryAlloc(16)); err = reader.DupString(str); EXPECT_EQ(err, CHIP_ERROR_WRONG_TLV_TYPE); chip::Platform::MemoryFree(str); // GetDataPtr() const uint8_t * data = static_cast(chip::Platform::MemoryAlloc(16)); err = reader.GetDataPtr(data); EXPECT_EQ(err, CHIP_ERROR_WRONG_TLV_TYPE); chip::Platform::MemoryFree(const_cast(data)); } void TestTLVReaderExpect() { // Prepare some test data uint8_t buffer[20]; TLVWriter writer; writer.Init(buffer, sizeof(buffer)); TLVType outerContainer; EXPECT_EQ(CHIP_NO_ERROR, writer.StartContainer(AnonymousTag(), kTLVType_Structure, outerContainer)); EXPECT_EQ(CHIP_NO_ERROR, writer.PutBoolean(ContextTag(23), false)); EXPECT_EQ(CHIP_NO_ERROR, writer.EndContainer(outerContainer)); TLVReader reader; reader.Init(buffer, writer.GetLengthWritten()); // Positioned before the first element EXPECT_EQ(reader.GetType(), kTLVType_NotSpecified); EXPECT_EQ(reader.Expect(AnonymousTag()), CHIP_ERROR_WRONG_TLV_TYPE); EXPECT_EQ(reader.Expect(ContextTag(23)), CHIP_ERROR_WRONG_TLV_TYPE); EXPECT_EQ(reader.Expect(kTLVType_Boolean, AnonymousTag()), CHIP_ERROR_WRONG_TLV_TYPE); // Positioned on kTLVType_Structure / AnonymousTag(), EXPECT_EQ(CHIP_NO_ERROR, reader.Next()); EXPECT_EQ(reader.GetType(), kTLVType_Structure); EXPECT_EQ(reader.GetTag(), AnonymousTag()); EXPECT_EQ(reader.Expect(ContextTag(23)), CHIP_ERROR_UNEXPECTED_TLV_ELEMENT); EXPECT_EQ(CHIP_NO_ERROR, reader.Expect(AnonymousTag())); EXPECT_EQ(reader.Expect(kTLVType_SignedInteger, AnonymousTag()), CHIP_ERROR_WRONG_TLV_TYPE); EXPECT_EQ(CHIP_NO_ERROR, reader.Expect(kTLVType_Structure, AnonymousTag())); // Positioned before first struct element EXPECT_EQ(CHIP_NO_ERROR, reader.EnterContainer(outerContainer)); EXPECT_EQ(reader.GetType(), kTLVType_NotSpecified); EXPECT_EQ(reader.Expect(AnonymousTag()), CHIP_ERROR_WRONG_TLV_TYPE); EXPECT_EQ(reader.Expect(ContextTag(23)), CHIP_ERROR_WRONG_TLV_TYPE); EXPECT_EQ(reader.Expect(kTLVType_Boolean, AnonymousTag()), CHIP_ERROR_WRONG_TLV_TYPE); // Positioned on kTLVType_Boolean / ContextTag(23) EXPECT_EQ(CHIP_NO_ERROR, reader.Next()); EXPECT_EQ(reader.GetType(), kTLVType_Boolean); EXPECT_EQ(reader.GetTag(), ContextTag(23)); EXPECT_EQ(reader.Expect(AnonymousTag()), CHIP_ERROR_UNEXPECTED_TLV_ELEMENT); EXPECT_EQ(reader.Expect(ContextTag(42)), CHIP_ERROR_UNEXPECTED_TLV_ELEMENT); EXPECT_EQ(CHIP_NO_ERROR, reader.Expect(ContextTag(23))); EXPECT_EQ(reader.Expect(kTLVType_SignedInteger, ContextTag(23)), CHIP_ERROR_WRONG_TLV_TYPE); EXPECT_EQ(CHIP_NO_ERROR, reader.Expect(kTLVType_Boolean, ContextTag(23))); } /** * Test that CHIP TLV reader returns an error when a read is requested that * would truncate the output. */ void TestTLVReaderTruncatedReads() { uint8_t buf[2048]; TLVWriter writer; TLVReader reader; CHIP_ERROR err; float outF; // Setup: Write some values into the buffer writer.Init(buf); writer.ImplicitProfileId = TestProfile_2; err = writer.Put(AnonymousTag(), double{ 12.5 }); EXPECT_EQ(err, CHIP_NO_ERROR); // Test reading values from the buffer reader.Init(buf); TestNext(reader); TEST_GET_NOERROR(reader, kTLVType_FloatingPointNumber, AnonymousTag(), 12.5); err = reader.Get(outF); EXPECT_EQ(err, CHIP_ERROR_WRONG_TLV_TYPE); } /** * Test CHIP TLV Reader in a use case */ void TestTLVReaderInPractice() { uint8_t buf[2048]; TLVWriter writer; TLVReader reader; writer.Init(buf); writer.ImplicitProfileId = TestProfile_2; PreserveSizeWrite(writer, true); reader.Init(buf); TestNext(reader); TEST_GET_NOERROR(reader, kTLVType_SignedInteger, ProfileTag(TestProfile_1, 4000000000ULL), static_cast(40000000000ULL)); TestNext(reader); TEST_GET_NOERROR(reader, kTLVType_SignedInteger, ProfileTag(TestProfile_1, 4000000000ULL), static_cast(12345)); TestNext(reader); TEST_GET_NOERROR(reader, kTLVType_FloatingPointNumber, ProfileTag(TestProfile_1, 4000000000ULL), static_cast(1.0)); } void TestTLVReader_NextOverContainer_ProcessElement(TLVReader & reader, void * context) { CHIP_ERROR err, nextRes1, nextRes2; TLVType outerContainerType; // If the current element is a container... if (TLVTypeIsContainer(reader.GetType())) { // Make two copies of the reader TLVReader readerClone1 = reader; TLVReader readerClone2 = reader; // Manually advance one of the readers to the element immediately after the container (if any). err = readerClone1.EnterContainer(outerContainerType); EXPECT_EQ(err, CHIP_NO_ERROR); ForEachElement(readerClone1, nullptr, nullptr); err = readerClone1.ExitContainer(outerContainerType); EXPECT_EQ(err, CHIP_NO_ERROR); nextRes1 = readerClone1.Next(); EXPECT_TRUE(nextRes1 == CHIP_NO_ERROR || nextRes1 == CHIP_END_OF_TLV); // For the other reader, skip over the entire container using the Next() method. nextRes2 = readerClone2.Next(); EXPECT_TRUE(nextRes2 == CHIP_NO_ERROR || nextRes2 == CHIP_END_OF_TLV); // Verify the two readers end up in the same state/position. EXPECT_EQ(nextRes1, nextRes2); EXPECT_EQ(readerClone1.GetType(), readerClone2.GetType()); EXPECT_EQ(readerClone1.GetReadPoint(), readerClone2.GetReadPoint()); } } /** * Test using CHIP TLV Reader Next() method to skip over containers. */ void TestTLVReader_NextOverContainer() { TLVReader reader; reader.Init(Encoding1); reader.ImplicitProfileId = TestProfile_2; ForEachElement(reader, nullptr, TestTLVReader_NextOverContainer_ProcessElement); } void TestTLVReader_SkipOverContainer_ProcessElement(TLVReader & reader, void * context) { CHIP_ERROR err; TLVType outerContainerType; // If the current element is a container... if (TLVTypeIsContainer(reader.GetType())) { // Make two copies of the reader TLVReader readerClone1 = reader; TLVReader readerClone2 = reader; // Manually advance one of the readers to immediately after the container. err = readerClone1.EnterContainer(outerContainerType); EXPECT_EQ(err, CHIP_NO_ERROR); ForEachElement(readerClone1, nullptr, nullptr); err = readerClone1.ExitContainer(outerContainerType); EXPECT_EQ(err, CHIP_NO_ERROR); // For the other reader, skip over the entire container using the Skip() method. err = readerClone2.Skip(); EXPECT_EQ(err, CHIP_NO_ERROR); // Verify the two readers end up in the same state/position. EXPECT_EQ(readerClone1.GetType(), readerClone2.GetType()); EXPECT_EQ(readerClone1.GetReadPoint(), readerClone2.GetReadPoint()); } } /** * Test using CHIP TLV Reader Skip() method to skip over containers. */ void TestTLVReader_SkipOverContainer() { TLVReader reader; reader.Init(Encoding1); reader.ImplicitProfileId = TestProfile_2; ForEachElement(reader, nullptr, TestTLVReader_SkipOverContainer_ProcessElement); } /** * Tests using an uninitialized TLVReader. */ void TestTLVReaderUninitialized() { TLVReader reader; EXPECT_EQ(reader.GetType(), kTLVType_NotSpecified); EXPECT_EQ(reader.GetLength(), 0u); EXPECT_EQ(reader.GetControlByte(), kTLVControlByte_NotSpecified); EXPECT_EQ(reader.GetContainerType(), kTLVType_NotSpecified); EXPECT_EQ(reader.GetLengthRead(), 0u); EXPECT_EQ(reader.GetRemainingLength(), 0u); EXPECT_EQ(reader.GetTotalLength(), 0u); EXPECT_EQ(reader.GetBackingStore(), nullptr); EXPECT_EQ(reader.IsElementDouble(), false); EXPECT_EQ(reader.GetReadPoint(), nullptr); EXPECT_EQ(reader.ImplicitProfileId, kProfileIdNotSpecified); EXPECT_EQ(reader.AppData, nullptr); } /** * Test CHIP TLV Reader */ TEST_F(TestTLV, CheckTLVReader) { TestTLVReaderSkip(); TestTLVReaderDup(); TestTLVReaderErrorHandling(); TestTLVReaderExpect(); TestTLVReaderTruncatedReads(); TestTLVReaderInPractice(); TestTLVReader_NextOverContainer(); TestTLVReader_SkipOverContainer(); TestTLVReaderUninitialized(); } /** * Test CHIP TLV Items */ static void TestItems() { CHIP_ERROR err = CHIP_NO_ERROR; uint8_t sBuffer[256]; TLVWriter writer; writer.Init(sBuffer); TLVWriter writer2; err = writer.OpenContainer(AnonymousTag(), kTLVType_Array, writer2); EXPECT_EQ(err, CHIP_NO_ERROR); { err = writer2.PutBoolean(AnonymousTag(), true); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer2.Put(AnonymousTag(), static_cast(-1)); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer2.Put(AnonymousTag(), static_cast(-2)); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer2.Put(AnonymousTag(), static_cast(-3)); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer2.Put(AnonymousTag(), static_cast(-4)); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer2.Put(AnonymousTag(), static_cast(-5.5)); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer2.Put(AnonymousTag(), static_cast(-3.14159265358979323846)); EXPECT_EQ(err, CHIP_NO_ERROR); } err = writer.CloseContainer(writer2); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer.OpenContainer(AnonymousTag(), kTLVType_Array, writer2); EXPECT_EQ(err, CHIP_NO_ERROR); { err = writer2.PutBoolean(AnonymousTag(), false); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer2.Put(AnonymousTag(), static_cast(1)); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer2.Put(AnonymousTag(), static_cast(2)); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer2.Put(AnonymousTag(), static_cast(3)); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer2.Put(AnonymousTag(), static_cast(4)); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer2.Put(AnonymousTag(), static_cast(5)); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer2.Put(AnonymousTag(), static_cast(6)); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer2.Put(AnonymousTag(), static_cast(7)); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer2.Put(AnonymousTag(), static_cast(8)); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer2.Put(AnonymousTag(), static_cast(9.9)); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer2.Put(AnonymousTag(), static_cast(3.14159265358979323846)); EXPECT_EQ(err, CHIP_NO_ERROR); } err = writer.CloseContainer(writer2); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer.Finalize(); EXPECT_EQ(err, CHIP_NO_ERROR); } /** * Test CHIP TLV Containers */ static void TestContainers() { CHIP_ERROR err = CHIP_NO_ERROR; TLVWriter writer; uint8_t sBuffer[256]; writer.Init(sBuffer); TLVWriter writer2; err = writer.OpenContainer(AnonymousTag(), kTLVType_Array, writer2); EXPECT_EQ(err, CHIP_NO_ERROR); TLVType type = writer2.GetContainerType(); EXPECT_EQ(type, kTLVType_Array); err = writer.CloseContainer(writer2); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer.OpenContainer(AnonymousTag(), kTLVType_Structure, writer2); EXPECT_EQ(err, CHIP_NO_ERROR); type = writer2.GetContainerType(); EXPECT_EQ(type, kTLVType_Structure); err = writer.CloseContainer(writer2); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer.Finalize(); EXPECT_EQ(err, CHIP_NO_ERROR); } /** * Test CHIP TLV Basics */ TEST_F(TestTLV, CheckTLVBasics) { TestItems(); TestContainers(); } /** * Test CHIP TLV Updater */ TEST_F(TestTLV, CheckCHIPUpdater) { WriteAppendReadTest0(); WriteAppendReadTest1(); WriteFindAppendReadTest(false); // Find an element WriteFindAppendReadTest(true); // Find a container AppendReadTest(); WriteDeleteReadTest(); } /** * Test TLV CloseContainer symbol reservations */ class OptimisticTLVWriter : public TLVWriter { public: void Init(uint8_t * buf, size_t maxLen); }; void OptimisticTLVWriter::Init(uint8_t * buf, size_t maxLen) { TLVWriter::Init(buf, maxLen); SetCloseContainerReserved(false); } TEST_F(TestTLV, CheckCloseContainerReserve) { // We are writing the structure looking like: // // [{TestProfile_1:2: true}] // // the above should consume 11 bytes in the TLV encoding. The // chosen buffer is too small for that, this test verifies that we // fail in the right places in the code. With the standard // TLVWriter, we now make provisions to reserve the space for the // CloseContainer tag in the OpenContainer call. As a result, we // expect to error out when we attempt to write out the value for // the TestProfile_1:2 tag. In contrast, the // `OptimisticTLVWriter` implements the earlier TLVWriter behavior // and fails out in the last CloseContainer call. The error // caught there is different because we run up against the mMaxLen // rather than mRemainingLen check. uint8_t buf[10]; uint8_t buf1[7]; CHIP_ERROR err = CHIP_NO_ERROR; TLVWriter writer1; OptimisticTLVWriter writer2; TLVWriter innerWriter1, innerWriter2; TLVType container1, container2; writer1.Init(buf); err = writer1.OpenContainer(AnonymousTag(), kTLVType_Array, innerWriter1); EXPECT_EQ(err, CHIP_NO_ERROR); err = innerWriter1.OpenContainer(AnonymousTag(), kTLVType_Structure, innerWriter2); EXPECT_EQ(err, CHIP_NO_ERROR); err = innerWriter2.PutBoolean(ProfileTag(TestProfile_1, 2), true); EXPECT_EQ(err, CHIP_ERROR_BUFFER_TOO_SMALL); err = innerWriter1.CloseContainer(innerWriter2); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer1.CloseContainer(innerWriter1); EXPECT_EQ(err, CHIP_NO_ERROR); writer2.Init(buf, sizeof(buf)); err = writer2.OpenContainer(AnonymousTag(), kTLVType_Array, innerWriter1); EXPECT_EQ(err, CHIP_NO_ERROR); err = innerWriter1.OpenContainer(AnonymousTag(), kTLVType_Structure, innerWriter2); EXPECT_EQ(err, CHIP_NO_ERROR); err = innerWriter2.PutBoolean(ProfileTag(TestProfile_1, 2), true); EXPECT_EQ(err, CHIP_NO_ERROR); err = innerWriter1.CloseContainer(innerWriter2); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer2.CloseContainer(innerWriter1); EXPECT_EQ(err, CHIP_ERROR_BUFFER_TOO_SMALL); // test the same scheme works on the Start/End container writer1.Init(buf); err = writer1.StartContainer(AnonymousTag(), kTLVType_Array, container1); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer1.StartContainer(AnonymousTag(), kTLVType_Structure, container2); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer1.PutBoolean(ProfileTag(TestProfile_1, 2), true); EXPECT_EQ(err, CHIP_ERROR_BUFFER_TOO_SMALL); err = writer1.EndContainer(container2); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer1.EndContainer(container1); EXPECT_EQ(err, CHIP_NO_ERROR); writer2.Init(buf, sizeof(buf)); err = writer2.StartContainer(AnonymousTag(), kTLVType_Array, container1); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer2.StartContainer(AnonymousTag(), kTLVType_Structure, container2); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer2.PutBoolean(ProfileTag(TestProfile_1, 2), true); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer2.EndContainer(container2); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer2.EndContainer(container1); EXPECT_EQ(err, CHIP_ERROR_BUFFER_TOO_SMALL); // Test that the reservations work for the empty containers writer1.Init(buf1); err = writer1.OpenContainer(ProfileTag(TestProfile_1, 2), kTLVType_Structure, innerWriter1); EXPECT_EQ(err, CHIP_ERROR_BUFFER_TOO_SMALL); err = writer1.CloseContainer(innerWriter1); EXPECT_NE(err, CHIP_NO_ERROR); writer2.Init(buf1, sizeof(buf1)); err = writer2.OpenContainer(ProfileTag(TestProfile_1, 2), kTLVType_Structure, innerWriter1); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer2.CloseContainer(innerWriter1); EXPECT_EQ(err, CHIP_ERROR_BUFFER_TOO_SMALL); writer1.Init(buf1); err = writer1.StartContainer(ProfileTag(TestProfile_1, 2), kTLVType_Structure, container1); EXPECT_EQ(err, CHIP_ERROR_BUFFER_TOO_SMALL); err = writer1.EndContainer(container1); EXPECT_NE(err, CHIP_NO_ERROR); writer2.Init(buf1, sizeof(buf1)); err = writer2.StartContainer(ProfileTag(TestProfile_1, 2), kTLVType_Structure, container1); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer2.EndContainer(container1); EXPECT_EQ(err, CHIP_ERROR_BUFFER_TOO_SMALL); // Test that the reservations work if the writer has a maxLen of 0. writer1.Init(buf1, 0); err = writer1.OpenContainer(ProfileTag(TestProfile_1, 2), kTLVType_Structure, innerWriter1); EXPECT_EQ(err, CHIP_ERROR_BUFFER_TOO_SMALL); err = writer1.StartContainer(AnonymousTag(), kTLVType_Array, container1); EXPECT_EQ(err, CHIP_ERROR_BUFFER_TOO_SMALL); // Test again all cases from 0 to the length of buf1 for (uint32_t maxLen = 0; maxLen <= sizeof(buf); maxLen++) { // Open/CloseContainer writer1.Init(buf, maxLen); err = writer1.OpenContainer(AnonymousTag(), kTLVType_Array, innerWriter1); if (err == CHIP_NO_ERROR) err = innerWriter1.OpenContainer(AnonymousTag(), kTLVType_Structure, innerWriter2); if (err == CHIP_NO_ERROR) err = innerWriter2.PutBoolean(ProfileTag(TestProfile_1, 2), true); if (err == CHIP_NO_ERROR) err = innerWriter1.CloseContainer(innerWriter2); if (err == CHIP_NO_ERROR) err = writer1.CloseContainer(innerWriter1); EXPECT_EQ(err, CHIP_ERROR_BUFFER_TOO_SMALL); // Start/EndContainer writer1.Init(buf, maxLen); if (err == CHIP_NO_ERROR) err = writer1.StartContainer(AnonymousTag(), kTLVType_Array, container1); if (err == CHIP_NO_ERROR) err = writer1.StartContainer(AnonymousTag(), kTLVType_Structure, container2); if (err == CHIP_NO_ERROR) err = writer1.PutBoolean(ProfileTag(TestProfile_1, 2), true); if (err == CHIP_NO_ERROR) err = writer1.EndContainer(container2); if (err == CHIP_NO_ERROR) err = writer1.EndContainer(container1); EXPECT_EQ(err, CHIP_ERROR_BUFFER_TOO_SMALL); } } static CHIP_ERROR ReadFuzzedEncoding1(TLVReader & reader) { CHIP_ERROR err = CHIP_NO_ERROR; #define FUZZ_CHECK_VAL(TYPE, VAL) \ do \ { \ TYPE val; \ ReturnErrorOnFailure(reader.Get(val)); \ VerifyOrReturnError(val == (VAL), CHIP_ERROR_INVALID_ARGUMENT); \ } while (0) #define FUZZ_CHECK_STRING(VAL) \ do \ { \ char buf[sizeof(VAL)]; \ VerifyOrReturnError(reader.GetLength() == strlen(VAL), CHIP_ERROR_INVALID_ADDRESS); \ ReturnErrorOnFailure(reader.GetString(buf, sizeof(buf))); \ VerifyOrReturnError(strcmp(buf, (VAL)) == 0, CHIP_ERROR_INVALID_ADDRESS); \ } while (0) ReturnErrorOnFailure(reader.Next(kTLVType_Structure, ProfileTag(TestProfile_1, 1))); { TLVType outerContainer1Type; ReturnErrorOnFailure(reader.EnterContainer(outerContainer1Type)); ReturnErrorOnFailure(reader.Next(kTLVType_Boolean, ProfileTag(TestProfile_1, 2))); FUZZ_CHECK_VAL(bool, true); ReturnErrorOnFailure(reader.Next(kTLVType_Boolean, ProfileTag(TestProfile_2, 2))); FUZZ_CHECK_VAL(bool, false); ReturnErrorOnFailure(reader.Next(kTLVType_Array, ContextTag(0))); { TLVType outerContainer2Type; ReturnErrorOnFailure(reader.EnterContainer(outerContainer2Type)); ReturnErrorOnFailure(reader.Next(kTLVType_SignedInteger, AnonymousTag())); FUZZ_CHECK_VAL(int8_t, 42); FUZZ_CHECK_VAL(int16_t, 42); FUZZ_CHECK_VAL(int32_t, 42); FUZZ_CHECK_VAL(int64_t, 42); FUZZ_CHECK_VAL(uint8_t, 42); FUZZ_CHECK_VAL(uint16_t, 42); FUZZ_CHECK_VAL(uint32_t, 42); FUZZ_CHECK_VAL(uint64_t, 42); ReturnErrorOnFailure(reader.Next(kTLVType_SignedInteger, AnonymousTag())); FUZZ_CHECK_VAL(int8_t, -17); FUZZ_CHECK_VAL(int16_t, -17); FUZZ_CHECK_VAL(int32_t, -17); FUZZ_CHECK_VAL(int64_t, -17); ReturnErrorOnFailure(reader.Next(kTLVType_SignedInteger, AnonymousTag())); FUZZ_CHECK_VAL(int32_t, -170000); FUZZ_CHECK_VAL(int64_t, -170000); ReturnErrorOnFailure(reader.Next(kTLVType_UnsignedInteger, AnonymousTag())); FUZZ_CHECK_VAL(int64_t, 40000000000ULL); FUZZ_CHECK_VAL(uint64_t, 40000000000ULL); ReturnErrorOnFailure(reader.Next(kTLVType_Structure, AnonymousTag())); { TLVType outerContainer3Type; ReturnErrorOnFailure(reader.EnterContainer(outerContainer3Type)); ReturnErrorOnFailure(reader.ExitContainer(outerContainer3Type)); } ReturnErrorOnFailure(reader.Next(kTLVType_List, AnonymousTag())); { TLVType outerContainer3Type; ReturnErrorOnFailure(reader.EnterContainer(outerContainer3Type)); ReturnErrorOnFailure(reader.Next(kTLVType_Null, ProfileTag(TestProfile_1, 17))); ReturnErrorOnFailure(reader.Next(kTLVType_Null, ProfileTag(TestProfile_2, 900000))); ReturnErrorOnFailure(reader.Next(kTLVType_Null, AnonymousTag())); ReturnErrorOnFailure(reader.Next(kTLVType_Structure, ProfileTag(TestProfile_2, 4000000000ULL))); { TLVType outerContainer4Type; ReturnErrorOnFailure(reader.EnterContainer(outerContainer4Type)); ReturnErrorOnFailure(reader.Next(kTLVType_UTF8String, CommonTag(70000))); FUZZ_CHECK_STRING(sLargeString); ReturnErrorOnFailure(reader.ExitContainer(outerContainer4Type)); } ReturnErrorOnFailure(reader.ExitContainer(outerContainer3Type)); } ReturnErrorOnFailure(reader.ExitContainer(outerContainer2Type)); } ReturnErrorOnFailure(reader.Next(kTLVType_UTF8String, ProfileTag(TestProfile_1, 5))); FUZZ_CHECK_STRING("This is a test"); ReturnErrorOnFailure(reader.Next(kTLVType_FloatingPointNumber, ProfileTag(TestProfile_2, 65535))); FUZZ_CHECK_VAL(double, (float) 17.9); ReturnErrorOnFailure(reader.Next(kTLVType_FloatingPointNumber, ProfileTag(TestProfile_2, 65536))); FUZZ_CHECK_VAL(double, (double) 17.9); ReturnErrorOnFailure(reader.ExitContainer(outerContainer1Type)); } err = reader.Next(); if (err == CHIP_END_OF_TLV) err = CHIP_NO_ERROR; return CHIP_NO_ERROR; } static uint64_t sFuzzTestDurationMillis = 5000; static uint8_t sFixedFuzzMask = 0; TEST_F(TestTLV, TLVReaderFuzzTest) { uint64_t now, endTime; uint8_t fuzzedData[sizeof(Encoding1)]; // clang-format off static uint8_t sFixedFuzzVals[] = { 0x00, 0x01, 0xFF, 0x20, // 1-byte signed integer with context tag 0x21, // 2-byte signed integer with context tag 0x22, // 4-byte signed integer with context tag 0x23, // 8-byte signed integer with context tag 0x24, // 1-byte unsigned integer with context tag 0x25, // 1-byte unsigned integer with context tag 0x26, // 1-byte unsigned integer with context tag 0x27, // 1-byte unsigned integer with context tag 0x28, // Boolean false with context tag 0x29, // Boolean true with context tag 0x27, // UTF-8 string with 1-byte length and context tag 0x30, // Byte string with 1-byte length and context tag 0x35, // Structure with context tag 0x36, // Array with context tag 0x18, // End of container }; // clang-format on memcpy(fuzzedData, Encoding1, sizeof(fuzzedData)); now = chip::test_utils::TimeMonotonicMillis(); endTime = now + sFuzzTestDurationMillis + 1; srand(static_cast(now)); size_t m = 0; while (true) { for (size_t i = 0; i < sizeof(fuzzedData); i++) { uint8_t origVal = fuzzedData[i]; if (m < sizeof(sFixedFuzzVals)) { if (origVal == sFixedFuzzVals[m]) continue; fuzzedData[i] = sFixedFuzzVals[m]; } else { uint8_t fuzzMask = sFixedFuzzMask; while (fuzzMask == 0) fuzzMask = static_cast(rand() & 0xFF); fuzzedData[i] ^= fuzzMask; } TLVReader reader; reader.Init(fuzzedData); reader.ImplicitProfileId = TestProfile_2; CHIP_ERROR readRes = ReadFuzzedEncoding1(reader); EXPECT_NE(readRes, CHIP_NO_ERROR); if (readRes == CHIP_NO_ERROR) { printf("Unexpected success of fuzz test: offset %u, original value 0x%02X, mutated value 0x%02X\n", static_cast(i), static_cast(origVal), static_cast(fuzzedData[i])); return; } now = chip::test_utils::TimeMonotonicMillis(); if (now >= endTime) return; fuzzedData[i] = origVal; } if (m < sizeof(sFixedFuzzVals)) m++; } } static void AssertCanReadString(ContiguousBufferTLVReader & reader, const char * expectedString) { Span str; CHIP_ERROR err = reader.GetStringView(str); EXPECT_EQ(err, CHIP_NO_ERROR); EXPECT_EQ(str.size(), strlen(expectedString)); EXPECT_EQ(strncmp(str.data(), expectedString, str.size()), 0); } static void AssertCannotReadString(ContiguousBufferTLVReader & reader) { Span str; CHIP_ERROR err = reader.GetStringView(str); EXPECT_NE(err, CHIP_NO_ERROR); } TEST_F(TestTLV, CheckGetStringView) { uint8_t buf[256]; static const char testString[] = "This is a test"; { TLVWriter writer; writer.Init(buf); CHIP_ERROR err = writer.PutString(CommonTag(0), testString); EXPECT_EQ(err, CHIP_NO_ERROR); // First check that basic read from entire buffer works. ContiguousBufferTLVReader reader; reader.Init(buf); reader.Next(); AssertCanReadString(reader, testString); // Now check that read from a buffer bounded by the number of bytes // written works. reader.Init(buf, writer.GetLengthWritten()); reader.Next(); AssertCanReadString(reader, testString); // Now check that read from a buffer bounded by fewer than the number of // bytes written fails. reader.Init(buf, writer.GetLengthWritten() - 1); reader.Next(); AssertCannotReadString(reader); } { // Check that an integer cannot be read as a string. TLVWriter writer; writer.Init(buf); CHIP_ERROR err = writer.Put(CommonTag(0), static_cast(5)); EXPECT_EQ(err, CHIP_NO_ERROR); ContiguousBufferTLVReader reader; reader.Init(buf); reader.Next(); AssertCannotReadString(reader); } { // Check that an octet string cannot be read as a string. TLVWriter writer; writer.Init(buf); CHIP_ERROR err = writer.PutBytes(CommonTag(0), reinterpret_cast(testString), static_cast(strlen(testString))); EXPECT_EQ(err, CHIP_NO_ERROR); ContiguousBufferTLVReader reader; reader.Init(buf); reader.Next(); AssertCannotReadString(reader); } { // Check that a manually constructed string can be read as a string. const uint8_t shortString[] = { CHIP_TLV_UTF8_STRING_2ByteLength(CHIP_TLV_TAG_COMMON_PROFILE_2Bytes(0), 2, 'a', 'b') }; ContiguousBufferTLVReader reader; reader.Init(shortString); reader.Next(); AssertCanReadString(reader, "ab"); } { // Check that a manually constructed string with bogus length cannot be read as a string. const uint8_t shortString[] = { CHIP_TLV_UTF8_STRING_2ByteLength(CHIP_TLV_TAG_COMMON_PROFILE_2Bytes(0), 3, 'a', 'b') }; ContiguousBufferTLVReader reader; reader.Init(shortString); reader.Next(); AssertCannotReadString(reader); } } static void AssertCanReadBytes(ContiguousBufferTLVReader & reader, const ByteSpan & expectedBytes) { ByteSpan bytes; CHIP_ERROR err = reader.GetByteView(bytes); EXPECT_EQ(err, CHIP_NO_ERROR); EXPECT_TRUE(bytes.data_equal(expectedBytes)); } static void AssertCannotReadBytes(ContiguousBufferTLVReader & reader) { ByteSpan bytes; CHIP_ERROR err = reader.GetByteView(bytes); EXPECT_NE(err, CHIP_NO_ERROR); } TEST_F(TestTLV, CheckGetByteView) { uint8_t buf[256]; const uint8_t testBytes[] = { 'T', 'h', 'i', 's', 'i', 's', 'a', 't', 'e', 's', 't', '\0' }; { TLVWriter writer; writer.Init(buf); CHIP_ERROR err = writer.PutBytes(CommonTag(0), testBytes, sizeof(testBytes)); EXPECT_EQ(err, CHIP_NO_ERROR); // First check that basic read from entire buffer works. ContiguousBufferTLVReader reader; reader.Init(buf); reader.Next(); AssertCanReadBytes(reader, ByteSpan(testBytes)); // Now check that read from a buffer bounded by the number of bytes // written works. reader.Init(buf, writer.GetLengthWritten()); reader.Next(); AssertCanReadBytes(reader, ByteSpan(testBytes)); // Now check that read from a buffer bounded by fewer than the number of // bytes written fails. reader.Init(buf, writer.GetLengthWritten() - 1); reader.Next(); AssertCannotReadBytes(reader); } { // Check that an integer cannot be read as an octet string. TLVWriter writer; writer.Init(buf); CHIP_ERROR err = writer.Put(CommonTag(0), static_cast(5)); EXPECT_EQ(err, CHIP_NO_ERROR); ContiguousBufferTLVReader reader; reader.Init(buf); reader.Next(); AssertCannotReadBytes(reader); } { // Check that an string cannot be read as an octet string. TLVWriter writer; writer.Init(buf); CHIP_ERROR err = writer.PutString(CommonTag(0), reinterpret_cast(testBytes)); EXPECT_EQ(err, CHIP_NO_ERROR); ContiguousBufferTLVReader reader; reader.Init(buf); reader.Next(); AssertCannotReadBytes(reader); } { // Check that a manually constructed octet string can be read as octet string. const uint8_t shortBytes[] = { CHIP_TLV_BYTE_STRING_2ByteLength(CHIP_TLV_TAG_COMMON_PROFILE_2Bytes(0), 2, 1, 2) }; ContiguousBufferTLVReader reader; reader.Init(shortBytes); reader.Next(); const uint8_t expectedBytes[] = { 1, 2 }; AssertCanReadBytes(reader, ByteSpan(expectedBytes)); } { // Check that a manually constructed octet string with bogus length // cannot be read as an octet string. const uint8_t shortBytes[] = { CHIP_TLV_BYTE_STRING_2ByteLength(CHIP_TLV_TAG_COMMON_PROFILE_2Bytes(0), 3, 1, 2) }; ContiguousBufferTLVReader reader; reader.Init(shortBytes); reader.Next(); AssertCannotReadBytes(reader); } } TEST_F(TestTLV, CheckTLVScopedBuffer) { Platform::ScopedMemoryBuffer buf; CHIP_ERROR err; buf.Calloc(64); ASSERT_NE(buf.Get(), nullptr); { ScopedBufferTLVWriter writer(std::move(buf), 64); EXPECT_EQ(buf.Get(), nullptr); // // NOLINT(bugprone-use-after-move) err = writer.Put(TLV::AnonymousTag(), (uint8_t) 33); EXPECT_EQ(err, CHIP_NO_ERROR); err = writer.Finalize(buf); EXPECT_EQ(err, CHIP_NO_ERROR); ASSERT_NE(buf.Get(), nullptr); err = writer.Put(TLV::AnonymousTag(), (uint8_t) 33); EXPECT_NE(err, CHIP_NO_ERROR); } { ScopedBufferTLVReader reader; uint8_t val; reader.Init(std::move(buf), 64); err = reader.Next(); EXPECT_EQ(err, CHIP_NO_ERROR); err = reader.Get(val); EXPECT_EQ(err, CHIP_NO_ERROR); EXPECT_EQ(val, 33); reader.TakeBuffer(buf); ASSERT_NE(buf.Get(), nullptr); err = reader.Get(val); EXPECT_NE(err, CHIP_NO_ERROR); } } TEST_F(TestTLV, TestUninitializedWriter) { { TLVWriter writer; EXPECT_FALSE(writer.IsInitialized()); } { TLVWriter writer; EXPECT_EQ(writer.Finalize(), CHIP_ERROR_INCORRECT_STATE); } { TLVWriter writer; EXPECT_EQ(writer.ReserveBuffer(123), CHIP_ERROR_INCORRECT_STATE); } { TLVWriter writer; EXPECT_EQ(writer.UnreserveBuffer(123), CHIP_ERROR_INCORRECT_STATE); } { TLVWriter writer; uint8_t v = 3; EXPECT_EQ(writer.Put(ContextTag(1), v), CHIP_ERROR_INCORRECT_STATE); } { TLVWriter writer; int8_t v = 3; bool preserveSize = true; EXPECT_EQ(writer.Put(ContextTag(1), v, preserveSize), CHIP_ERROR_INCORRECT_STATE); } { TLVWriter writer; int16_t v = 3; EXPECT_EQ(writer.Put(ContextTag(1), v), CHIP_ERROR_INCORRECT_STATE); } { TLVWriter writer; int16_t v = 3; bool preserveSize = true; EXPECT_EQ(writer.Put(ContextTag(1), v, preserveSize), CHIP_ERROR_INCORRECT_STATE); } { TLVWriter writer; int32_t v = 3; EXPECT_EQ(writer.Put(ContextTag(1), v), CHIP_ERROR_INCORRECT_STATE); } { TLVWriter writer; int32_t v = 3; bool preserveSize = true; EXPECT_EQ(writer.Put(ContextTag(1), v, preserveSize), CHIP_ERROR_INCORRECT_STATE); } { TLVWriter writer; int64_t v = 3; EXPECT_EQ(writer.Put(ContextTag(1), v), CHIP_ERROR_INCORRECT_STATE); } { TLVWriter writer; int64_t v = 3; bool preserveSize = true; EXPECT_EQ(writer.Put(ContextTag(1), v, preserveSize), CHIP_ERROR_INCORRECT_STATE); } { TLVWriter writer; uint8_t v = 3; EXPECT_EQ(writer.Put(ContextTag(1), v), CHIP_ERROR_INCORRECT_STATE); } { TLVWriter writer; uint8_t v = 3; bool preserveSize = true; EXPECT_EQ(writer.Put(ContextTag(1), v, preserveSize), CHIP_ERROR_INCORRECT_STATE); } { TLVWriter writer; uint16_t v = 3; EXPECT_EQ(writer.Put(ContextTag(1), v), CHIP_ERROR_INCORRECT_STATE); } { TLVWriter writer; uint16_t v = 3; bool preserveSize = true; EXPECT_EQ(writer.Put(ContextTag(1), v, preserveSize), CHIP_ERROR_INCORRECT_STATE); } { TLVWriter writer; uint32_t v = 3; EXPECT_EQ(writer.Put(ContextTag(1), v), CHIP_ERROR_INCORRECT_STATE); } { TLVWriter writer; uint32_t v = 3; bool preserveSize = true; EXPECT_EQ(writer.Put(ContextTag(1), v, preserveSize), CHIP_ERROR_INCORRECT_STATE); } { TLVWriter writer; uint64_t v = 3; EXPECT_EQ(writer.Put(ContextTag(1), v), CHIP_ERROR_INCORRECT_STATE); } { TLVWriter writer; uint64_t v = 3; bool preserveSize = true; EXPECT_EQ(writer.Put(ContextTag(1), v, preserveSize), CHIP_ERROR_INCORRECT_STATE); } { TLVWriter writer; double v = 1.23; EXPECT_EQ(writer.Put(ContextTag(1), v), CHIP_ERROR_INCORRECT_STATE); } { TLVWriter writer; float v = 1.23f; EXPECT_EQ(writer.Put(ContextTag(1), v), CHIP_ERROR_INCORRECT_STATE); } { TLVWriter writer; bool v = true; EXPECT_EQ(writer.PutBoolean(ContextTag(1), v), CHIP_ERROR_INCORRECT_STATE); } { TLVWriter writer; bool v = true; EXPECT_EQ(writer.Put(ContextTag(1), v), CHIP_ERROR_INCORRECT_STATE); } { TLVWriter writer; const uint8_t buf[] = { 1, 2, 3 }; EXPECT_EQ(writer.PutBytes(ContextTag(1), buf, static_cast(sizeof(buf))), CHIP_ERROR_INCORRECT_STATE); } { TLVWriter writer; const char * buf = "abc"; EXPECT_EQ(writer.PutString(ContextTag(1), buf), CHIP_ERROR_INCORRECT_STATE); } { TLVWriter writer; const char * buf = "abc"; EXPECT_EQ(writer.PutString(ContextTag(1), buf, static_cast(strlen(buf))), CHIP_ERROR_INCORRECT_STATE); } { TLVWriter writer; CharSpan str = "abc"_span; EXPECT_EQ(writer.PutString(ContextTag(1), str), CHIP_ERROR_INCORRECT_STATE); } { TLVWriter writer; EXPECT_EQ(writer.PutStringF(ContextTag(1), "%d", 1), CHIP_ERROR_INCORRECT_STATE); } { TLVWriter writer; EXPECT_EQ(writer.PutNull(ContextTag(1)), CHIP_ERROR_INCORRECT_STATE); } { const uint8_t buf[]{ 0, 0, 0 }; TLVReader reader; reader.Init(buf); TLVWriter writer; EXPECT_EQ(writer.CopyElement(reader), CHIP_ERROR_INCORRECT_STATE); } { const uint8_t buf[]{ 0, 0, 0 }; TLVReader reader; reader.Init(buf); TLVWriter writer; EXPECT_EQ(writer.CopyElement(ContextTag(1), reader), CHIP_ERROR_INCORRECT_STATE); } { TLVWriter writer; TLVType outerContainerType; EXPECT_EQ(writer.StartContainer(ContextTag(1), TLVType::kTLVType_Structure, outerContainerType), CHIP_ERROR_INCORRECT_STATE); } { TLVWriter writer; TLVType outerContainerType = TLVType::kTLVType_Structure; EXPECT_EQ(writer.EndContainer(outerContainerType), CHIP_ERROR_INCORRECT_STATE); } { TLVWriter innerWriter; uint8_t buf[]{ 0, 0, 0 }; innerWriter.Init(buf); EXPECT_TRUE(innerWriter.IsInitialized()); TLVWriter writer; EXPECT_EQ(writer.OpenContainer(ContextTag(1), TLVType::kTLVType_Structure, innerWriter), CHIP_ERROR_INCORRECT_STATE); } { TLVWriter innerWriter; uint8_t buf[]{ 0, 0, 0 }; innerWriter.Init(buf); EXPECT_TRUE(innerWriter.IsInitialized()); TLVWriter writer; EXPECT_EQ(writer.CloseContainer(innerWriter), CHIP_ERROR_INCORRECT_STATE); } { uint8_t buf[]{ 0, 0, 0 }; TLVWriter writer; EXPECT_EQ( writer.PutPreEncodedContainer(ContextTag(1), TLVType::kTLVType_Structure, buf, static_cast(sizeof(buf))), CHIP_ERROR_INCORRECT_STATE); } { const uint8_t buf[]{ 0, 0, 0 }; TLVReader reader; reader.Init(buf); TLVWriter writer; EXPECT_EQ(writer.CopyContainer(reader), CHIP_ERROR_INCORRECT_STATE); } { const uint8_t buf[]{ 0, 0, 0 }; TLVReader reader; reader.Init(buf); TLVWriter writer; EXPECT_EQ(writer.CopyContainer(ContextTag(1), reader), CHIP_ERROR_INCORRECT_STATE); } { uint8_t buf[]{ 0, 0, 0 }; TLVWriter writer; EXPECT_EQ(writer.CopyContainer(ContextTag(1), buf, static_cast(sizeof(buf))), CHIP_ERROR_INCORRECT_STATE); } }