blob: e8f0e1f958d397f9550723b82795a32611cbbc4f [file] [log] [blame]
/*
*
* 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 Weave TLV implementation.
*
*/
#include "ToolCommon.h"
#include <nlbyteorder.h>
#include <nltest.h>
#include <Weave/Core/WeaveCore.h>
#include <Weave/Core/WeaveTLV.h>
#include <Weave/Core/WeaveTLVDebug.hpp>
#include <Weave/Core/WeaveTLVUtilities.hpp>
#include <Weave/Core/WeaveTLVData.hpp>
#include <Weave/Core/WeaveCircularTLVBuffer.h>
#include <Weave/Support/RandUtils.h>
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
#include <lwip/init.h>
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
using namespace nl;
using namespace nl::Weave::TLV;
#define TOOL_NAME "TestCASE"
static bool HandleOption(const char *progName, OptionSet *optSet, int id, const char *name, const char *arg);
enum
{
TestProfile_1 = 0xAABBCCDD,
TestProfile_2 = 0x11223344
};
static const char sLargeString [] =
"START..."
"!123456789ABCDEF@123456789ABCDEF#123456789ABCDEF$123456789ABCDEF%123456789ABCDEF^123456789ABCDEF&123456789ABCDEF*123456789ABCDEF"
"01234567(9ABCDEF01234567)9ABCDEF01234567-9ABCDEF01234567=9ABCDEF01234567[9ABCDEF01234567]9ABCDEF01234567;9ABCDEF01234567'9ABCDEF"
"...END";
void Abort()
{
abort();
}
void TestAndOpenContainer(nlTestSuite *inSuite, TLVReader& reader, TLVType type, uint64_t tag, TLVReader& containerReader)
{
NL_TEST_ASSERT(inSuite, reader.GetType() == type);
NL_TEST_ASSERT(inSuite, reader.GetTag() == tag);
NL_TEST_ASSERT(inSuite, reader.GetLength() == 0);
WEAVE_ERROR err = reader.OpenContainer(containerReader);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
NL_TEST_ASSERT(inSuite, containerReader.GetContainerType() == type);
}
template<class T>
void TestAndEnterContainer(nlTestSuite *inSuite, T& t, TLVType type, uint64_t tag, TLVType& outerContainerType)
{
NL_TEST_ASSERT(inSuite, t.GetType() == type);
NL_TEST_ASSERT(inSuite, t.GetTag() == tag);
NL_TEST_ASSERT(inSuite, t.GetLength() == 0);
TLVType expectedContainerType = t.GetContainerType();
WEAVE_ERROR err = t.EnterContainer(outerContainerType);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
NL_TEST_ASSERT(inSuite, outerContainerType == expectedContainerType);
NL_TEST_ASSERT(inSuite, t.GetContainerType() == type);
}
template<class T>
void TestNext(nlTestSuite *inSuite, T& t)
{
WEAVE_ERROR err = t.Next();
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
}
void TestSkip(nlTestSuite *inSuite, TLVReader& reader)
{
WEAVE_ERROR err = reader.Skip();
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
}
void TestMove(nlTestSuite *inSuite, TLVUpdater& updater)
{
WEAVE_ERROR err = updater.Move();
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
}
template<class T>
void TestEnd(nlTestSuite *inSuite, T& t)
{
WEAVE_ERROR err;
err = t.Next();
NL_TEST_ASSERT(inSuite, err == WEAVE_END_OF_TLV);
}
void TestEndAndCloseContainer(nlTestSuite *inSuite, TLVReader& reader, TLVReader& containerReader)
{
WEAVE_ERROR err;
TestEnd<TLVReader>(inSuite, containerReader);
err = reader.CloseContainer(containerReader);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
}
template<class T>
void TestEndAndExitContainer(nlTestSuite *inSuite, T& t, TLVType outerContainerType)
{
WEAVE_ERROR err;
TestEnd<T>(inSuite, t);
err = t.ExitContainer(outerContainerType);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
NL_TEST_ASSERT(inSuite, t.GetContainerType() == outerContainerType);
}
template<class S, class T>
void TestGet(nlTestSuite *inSuite, S& s, TLVType type, uint64_t tag, T expectedVal)
{
NL_TEST_ASSERT(inSuite, s.GetType() == type);
NL_TEST_ASSERT(inSuite, s.GetTag() == tag);
NL_TEST_ASSERT(inSuite, s.GetLength() == 0);
T val;
WEAVE_ERROR err = s.Get(val);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
NL_TEST_ASSERT(inSuite, val == expectedVal);
}
void ForEachElement(nlTestSuite *inSuite, TLVReader& reader, void *context, void (*cb)(nlTestSuite *inSuite, TLVReader& reader, void *context))
{
WEAVE_ERROR err;
while (true)
{
err = reader.Next();
if (err == WEAVE_END_OF_TLV)
{
return;
}
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
if (cb != NULL)
{
cb(inSuite, reader, context);
}
if (TLVTypeIsContainer(reader.GetType()))
{
TLVType outerContainerType;
err = reader.EnterContainer(outerContainerType);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
ForEachElement(inSuite, reader, context, cb);
err = reader.ExitContainer(outerContainerType);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
}
}
}
/**
* context
*/
struct TestTLVContext
{
nlTestSuite *mSuite;
int mEvictionCount;
int mEvictedBytes;
};
void TestNull(nlTestSuite *inSuite, TLVReader& reader, uint64_t tag)
{
NL_TEST_ASSERT(inSuite, reader.GetType() == kTLVType_Null);
NL_TEST_ASSERT(inSuite, reader.GetTag() == tag);
NL_TEST_ASSERT(inSuite, reader.GetLength() == 0);
}
void TestString(nlTestSuite *inSuite, TLVReader& reader, uint64_t tag, const char *expectedVal)
{
NL_TEST_ASSERT(inSuite, reader.GetType() == kTLVType_UTF8String);
NL_TEST_ASSERT(inSuite, reader.GetTag() == tag);
uint32_t expectedLen = strlen(expectedVal);
NL_TEST_ASSERT(inSuite, reader.GetLength() == expectedLen);
char *val = (char *)malloc(expectedLen + 1);
WEAVE_ERROR err = reader.GetString(val, expectedLen + 1);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
NL_TEST_ASSERT(inSuite, memcmp(val, expectedVal, expectedLen + 1) == 0);
free(val);
}
void TestDupString(nlTestSuite *inSuite, TLVReader& reader, uint64_t tag, const char *expectedVal)
{
NL_TEST_ASSERT(inSuite, reader.GetType() == kTLVType_UTF8String);
NL_TEST_ASSERT(inSuite, reader.GetTag() == tag);
uint32_t expectedLen = strlen(expectedVal);
NL_TEST_ASSERT(inSuite, reader.GetLength() == expectedLen);
char *val = (char *)malloc(expectedLen + 1);
WEAVE_ERROR err = reader.DupString(val);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
NL_TEST_ASSERT(inSuite, memcmp(val, expectedVal, expectedLen + 1) == 0);
free(val);
}
void TestDupBytes(nlTestSuite *inSuite, TLVReader& reader, uint64_t tag, const uint8_t *expectedVal, uint32_t expectedLen)
{
NL_TEST_ASSERT(inSuite, reader.GetType() == kTLVType_UTF8String);
NL_TEST_ASSERT(inSuite, reader.GetTag() == tag);
NL_TEST_ASSERT(inSuite, reader.GetLength() == expectedLen);
uint8_t *val = (uint8_t *)malloc(expectedLen);
WEAVE_ERROR err = reader.DupBytes(val, expectedLen);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
NL_TEST_ASSERT(inSuite, memcmp(val, expectedVal, expectedLen) == 0);
free(val);
}
void TestBufferContents(nlTestSuite *inSuite, PacketBuffer *buf, const uint8_t *expectedVal, uint32_t expectedLen)
{
while (buf != NULL)
{
uint16_t len = buf->DataLength();
NL_TEST_ASSERT(inSuite, len <= expectedLen);
NL_TEST_ASSERT(inSuite, memcmp(buf->Start(), expectedVal, len) == 0);
expectedVal += len;
expectedLen -= len;
buf = buf->Next();
}
NL_TEST_ASSERT(inSuite, expectedLen == 0);
}
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, 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
};
static const uint8_t Encoding1_DataMacro [] =
{
nlWeaveTLV_STRUCTURE(nlWeaveTLV_TAG_FULLY_QUALIFIED_6Bytes(TestProfile_1, 1)),
nlWeaveTLV_BOOL(nlWeaveTLV_TAG_FULLY_QUALIFIED_6Bytes(TestProfile_1, 2), true),
nlWeaveTLV_BOOL(nlWeaveTLV_TAG_IMPLICIT_PROFILE_2Bytes(2), false),
nlWeaveTLV_ARRAY(nlWeaveTLV_TAG_CONTEXT_SPECIFIC(0)),
nlWeaveTLV_INT8(nlWeaveTLV_TAG_ANONYMOUS, 42),
nlWeaveTLV_INT8(nlWeaveTLV_TAG_ANONYMOUS, -17),
nlWeaveTLV_INT32(nlWeaveTLV_TAG_ANONYMOUS, -170000),
nlWeaveTLV_UINT64(nlWeaveTLV_TAG_ANONYMOUS, 40000000000ULL),
nlWeaveTLV_STRUCTURE(nlWeaveTLV_TAG_ANONYMOUS),
nlWeaveTLV_END_OF_CONTAINER,
nlWeaveTLV_PATH(nlWeaveTLV_TAG_ANONYMOUS),
nlWeaveTLV_NULL(nlWeaveTLV_TAG_FULLY_QUALIFIED_6Bytes(TestProfile_1, 17)),
nlWeaveTLV_NULL(nlWeaveTLV_TAG_IMPLICIT_PROFILE_4Bytes(900000)),
nlWeaveTLV_STRUCTURE(nlWeaveTLV_TAG_IMPLICIT_PROFILE_4Bytes(4000000000ULL)),
nlWeaveTLV_UTF8_STRING_2ByteLength(nlWeaveTLV_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'),
nlWeaveTLV_END_OF_CONTAINER,
nlWeaveTLV_END_OF_CONTAINER,
nlWeaveTLV_END_OF_CONTAINER,
nlWeaveTLV_UTF8_STRING_1ByteLength(nlWeaveTLV_TAG_FULLY_QUALIFIED_6Bytes(TestProfile_1, 5), sizeof("This is a test") - 1,
'T', 'h', 'i', 's', ' ', 'i', 's', ' ', 'a', ' ', 't', 'e', 's', 't'),
nlWeaveTLV_FLOAT32(nlWeaveTLV_TAG_IMPLICIT_PROFILE_2Bytes(65535),
0x33, 0x33, 0x8f, 0x41), // (float)17.9
nlWeaveTLV_FLOAT64(nlWeaveTLV_TAG_IMPLICIT_PROFILE_4Bytes(65536),
0x66, 0x66, 0x66, 0x66, 0x66, 0xE6, 0x31, 0x40), // (double)17.9
nlWeaveTLV_END_OF_CONTAINER
};
void WriteEncoding1(nlTestSuite *inSuite, TLVWriter& writer)
{
WEAVE_ERROR err;
TLVWriter writer2;
err = writer.OpenContainer(ProfileTag(TestProfile_1, 1), kTLVType_Structure, writer2);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer2.PutBoolean(ProfileTag(TestProfile_1, 2), true);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer2.PutBoolean(ProfileTag(TestProfile_2, 2), false);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
{
TLVWriter writer3;
err = writer2.OpenContainer(ContextTag(0), kTLVType_Array, writer3);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer3.Put(AnonymousTag, 42);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer3.Put(AnonymousTag, -17);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer3.Put(AnonymousTag, -170000);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer3.Put(AnonymousTag, (uint64_t) 40000000000ULL);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
{
TLVWriter writer4;
err = writer3.OpenContainer(AnonymousTag, kTLVType_Structure, writer4);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer3.CloseContainer(writer4);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
}
{
TLVWriter writer5;
err = writer3.OpenContainer(AnonymousTag, kTLVType_Path, writer5);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer5.PutNull(ProfileTag(TestProfile_1, 17));
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer5.PutNull(ProfileTag(TestProfile_2, 900000));
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
{
TLVType outerContainerType;
err = writer5.StartContainer(ProfileTag(TestProfile_2, 4000000000ULL), kTLVType_Structure, outerContainerType);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer5.PutString(CommonTag(70000), sLargeString);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer5.EndContainer(outerContainerType);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
}
err = writer3.CloseContainer(writer5);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
}
err = writer2.CloseContainer(writer3);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
}
err = writer2.PutString(ProfileTag(TestProfile_1, 5), "This is a test");
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer2.Put(ProfileTag(TestProfile_2, 65535), (float)17.9);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer2.Put(ProfileTag(TestProfile_2, 65536), (double)17.9);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer.CloseContainer(writer2);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer.Finalize();
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
}
void WriteEmptyEncoding(nlTestSuite *inSuite, TLVWriter& writer)
{
WEAVE_ERROR err;
TLVWriter writer2;
err = writer.OpenContainer(ProfileTag(TestProfile_1, 1), kTLVType_Structure, writer2);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
{
TLVWriter writer3;
err = writer2.OpenContainer(ProfileTag(TestProfile_1, 256), kTLVType_Array, writer3);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer2.CloseContainer(writer3);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
}
err = writer.CloseContainer(writer2);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer.Finalize();
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
}
void ReadEncoding1(nlTestSuite *inSuite, TLVReader& reader)
{
TestNext<TLVReader>(inSuite, reader);
{
TLVReader reader2;
TestAndOpenContainer(inSuite, reader, kTLVType_Structure, ProfileTag(TestProfile_1, 1), reader2);
TestNext<TLVReader>(inSuite, reader2);
TestGet<TLVReader, bool>(inSuite, reader2, kTLVType_Boolean, ProfileTag(TestProfile_1, 2), true);
TestNext<TLVReader>(inSuite, reader2);
TestGet<TLVReader, bool>(inSuite, reader2, kTLVType_Boolean, ProfileTag(TestProfile_2, 2), false);
TestNext<TLVReader>(inSuite, reader2);
{
TLVReader reader3;
TestAndOpenContainer(inSuite, reader2, kTLVType_Array, ContextTag(0), reader3);
TestNext<TLVReader>(inSuite, reader3);
TestGet<TLVReader, int8_t>(inSuite, reader3, kTLVType_SignedInteger, AnonymousTag, 42);
TestGet<TLVReader, int16_t>(inSuite, reader3, kTLVType_SignedInteger, AnonymousTag, 42);
TestGet<TLVReader, int32_t>(inSuite, reader3, kTLVType_SignedInteger, AnonymousTag, 42);
TestGet<TLVReader, int64_t>(inSuite, reader3, kTLVType_SignedInteger, AnonymousTag, 42);
TestGet<TLVReader, uint8_t>(inSuite, reader3, kTLVType_SignedInteger, AnonymousTag, 42);
TestGet<TLVReader, uint16_t>(inSuite, reader3, kTLVType_SignedInteger, AnonymousTag, 42);
TestGet<TLVReader, uint32_t>(inSuite, reader3, kTLVType_SignedInteger, AnonymousTag, 42);
TestGet<TLVReader, uint64_t>(inSuite, reader3, kTLVType_SignedInteger, AnonymousTag, 42);
TestNext<TLVReader>(inSuite, reader3);
TestGet<TLVReader, int8_t>(inSuite, reader3, kTLVType_SignedInteger, AnonymousTag, -17);
TestGet<TLVReader, int16_t>(inSuite, reader3, kTLVType_SignedInteger, AnonymousTag, -17);
TestGet<TLVReader, int32_t>(inSuite, reader3, kTLVType_SignedInteger, AnonymousTag, -17);
TestGet<TLVReader, int64_t>(inSuite, reader3, kTLVType_SignedInteger, AnonymousTag, -17);
TestNext<TLVReader>(inSuite, reader3);
TestGet<TLVReader, int32_t>(inSuite, reader3, kTLVType_SignedInteger, AnonymousTag, -170000);
TestGet<TLVReader, int64_t>(inSuite, reader3, kTLVType_SignedInteger, AnonymousTag, -170000);
TestNext<TLVReader>(inSuite, reader3);
TestGet<TLVReader, int64_t>(inSuite, reader3, kTLVType_UnsignedInteger, AnonymousTag, 40000000000ULL);
TestGet<TLVReader, uint64_t>(inSuite, reader3, kTLVType_UnsignedInteger, AnonymousTag, 40000000000ULL);
TestNext<TLVReader>(inSuite, reader3);
{
TLVReader reader4;
TestAndOpenContainer(inSuite, reader3, kTLVType_Structure, AnonymousTag, reader4);
TestEndAndCloseContainer(inSuite, reader3, reader4);
}
TestNext<TLVReader>(inSuite, reader3);
{
TLVReader reader5;
TestAndOpenContainer(inSuite, reader3, kTLVType_Path, AnonymousTag, reader5);
TestNext<TLVReader>(inSuite, reader5);
TestNull(inSuite, reader5, ProfileTag(TestProfile_1, 17));
TestNext<TLVReader>(inSuite, reader5);
TestNull(inSuite, reader5, ProfileTag(TestProfile_2, 900000));
TestNext<TLVReader>(inSuite, reader5);
{
TLVType outerContainerType;
TestAndEnterContainer<TLVReader>(inSuite, reader5, kTLVType_Structure, ProfileTag(TestProfile_2, 4000000000ULL), outerContainerType);
TestNext<TLVReader>(inSuite, reader5);
TestString(inSuite, reader5, CommonTag(70000), sLargeString);
TestEndAndExitContainer<TLVReader>(inSuite, reader5, outerContainerType);
}
TestEndAndCloseContainer(inSuite, reader3, reader5);
}
TestEndAndCloseContainer(inSuite, reader2, reader3);
}
TestNext<TLVReader>(inSuite, reader2);
TestString(inSuite, reader2, ProfileTag(TestProfile_1, 5), "This is a test");
TestNext<TLVReader>(inSuite, reader2);
TestGet<TLVReader, double>(inSuite, reader2, kTLVType_FloatingPointNumber, ProfileTag(TestProfile_2, 65535), (float)17.9);
TestNext<TLVReader>(inSuite, reader2);
TestGet<TLVReader, double>(inSuite, reader2, kTLVType_FloatingPointNumber, ProfileTag(TestProfile_2, 65536), (double)17.9);
TestEndAndCloseContainer(inSuite, reader, reader2);
}
TestEnd<TLVReader>(inSuite, reader);
}
void WriteEncoding2(nlTestSuite *inSuite, TLVWriter& writer)
{
WEAVE_ERROR err;
{ // Container 1
TLVWriter writer1;
err = writer.OpenContainer(ProfileTag(TestProfile_1, 1), kTLVType_Structure, writer1);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer1.PutBoolean(ProfileTag(TestProfile_1, 2), true);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer1.PutBoolean(ProfileTag(TestProfile_2, 2), false);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer.CloseContainer(writer1);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
}
{ // Container 2
TLVWriter writer1;
err = writer.OpenContainer(ProfileTag(TestProfile_2, 1), kTLVType_Structure, writer1);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer1.PutBoolean(ProfileTag(TestProfile_2, 2), false);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer1.PutBoolean(ProfileTag(TestProfile_1, 2), true);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer.CloseContainer(writer1);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
}
err = writer.Finalize();
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
}
void WriteEncoding3(nlTestSuite *inSuite, TLVWriter& writer)
{
WEAVE_ERROR err;
{ // Container 1
TLVWriter writer1;
err = writer.OpenContainer(ProfileTag(TestProfile_1, 1), kTLVType_Structure, writer1);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer1.PutBoolean(ProfileTag(TestProfile_2, 2), false);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer.CloseContainer(writer1);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
}
err = writer.Finalize();
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
}
void ReadEncoding3(nlTestSuite *inSuite, TLVReader& reader)
{
TLVReader reader2;
TestAndOpenContainer(inSuite, reader, kTLVType_Structure, ProfileTag(TestProfile_1, 1), reader2);
TestNext<TLVReader>(inSuite, reader2);
TestGet<TLVReader, bool>(inSuite, reader2, kTLVType_Boolean, ProfileTag(TestProfile_2, 2), false);
TestEndAndCloseContainer(inSuite, reader, reader2);
}
static const uint8_t Encoding5_DataMacro [] =
{
nlWeaveTLV_STRUCTURE(nlWeaveTLV_TAG_FULLY_QUALIFIED_6Bytes(TestProfile_1, 1)),
nlWeaveTLV_BOOL(nlWeaveTLV_TAG_FULLY_QUALIFIED_6Bytes(TestProfile_1, 2), true),
nlWeaveTLV_BOOL(nlWeaveTLV_TAG_IMPLICIT_PROFILE_2Bytes(2), false),
nlWeaveTLV_BOOL(nlWeaveTLV_TAG_FULLY_QUALIFIED_6Bytes(TestProfile_1, 2), false),
nlWeaveTLV_BOOL(nlWeaveTLV_TAG_IMPLICIT_PROFILE_2Bytes(2), true),
nlWeaveTLV_STRUCTURE(nlWeaveTLV_TAG_FULLY_QUALIFIED_6Bytes(TestProfile_1, 1)),
nlWeaveTLV_BOOL(nlWeaveTLV_TAG_FULLY_QUALIFIED_6Bytes(TestProfile_1, 2), true),
nlWeaveTLV_BOOL(nlWeaveTLV_TAG_IMPLICIT_PROFILE_2Bytes(2), false),
nlWeaveTLV_END_OF_CONTAINER,
nlWeaveTLV_STRUCTURE(nlWeaveTLV_TAG_IMPLICIT_PROFILE_2Bytes(1)),
nlWeaveTLV_BOOL(nlWeaveTLV_TAG_IMPLICIT_PROFILE_2Bytes(2), false),
nlWeaveTLV_BOOL(nlWeaveTLV_TAG_FULLY_QUALIFIED_6Bytes(TestProfile_1, 2), true),
nlWeaveTLV_END_OF_CONTAINER,
nlWeaveTLV_END_OF_CONTAINER,
nlWeaveTLV_STRUCTURE(nlWeaveTLV_TAG_IMPLICIT_PROFILE_2Bytes(1)),
nlWeaveTLV_BOOL(nlWeaveTLV_TAG_IMPLICIT_PROFILE_2Bytes(2), false),
nlWeaveTLV_BOOL(nlWeaveTLV_TAG_FULLY_QUALIFIED_6Bytes(TestProfile_1, 2), true),
nlWeaveTLV_END_OF_CONTAINER,
};
void WriteEncoding5(nlTestSuite *inSuite, TLVWriter& writer)
{
WEAVE_ERROR err;
{ // Container 1
TLVWriter writer1;
err = writer.OpenContainer(ProfileTag(TestProfile_1, 1), kTLVType_Structure, writer1);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer1.PutBoolean(ProfileTag(TestProfile_1, 2), true);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer1.PutBoolean(ProfileTag(TestProfile_2, 2), false);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer1.PutBoolean(ProfileTag(TestProfile_1, 2), false);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer1.PutBoolean(ProfileTag(TestProfile_2, 2), true);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
{ // Inner Container 1
TLVWriter writer2;
err = writer1.OpenContainer(ProfileTag(TestProfile_1, 1), kTLVType_Structure, writer2);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer2.PutBoolean(ProfileTag(TestProfile_1, 2), true);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer2.PutBoolean(ProfileTag(TestProfile_2, 2), false);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer1.CloseContainer(writer2);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
}
{ // Inner Container 2
TLVWriter writer2;
err = writer1.OpenContainer(ProfileTag(TestProfile_2, 1), kTLVType_Structure, writer2);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer2.PutBoolean(ProfileTag(TestProfile_2, 2), false);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer2.PutBoolean(ProfileTag(TestProfile_1, 2), true);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer1.CloseContainer(writer2);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
}
err = writer.CloseContainer(writer1);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
}
{ // Container 2
TLVWriter writer1;
err = writer.OpenContainer(ProfileTag(TestProfile_2, 1), kTLVType_Structure, writer1);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer1.PutBoolean(ProfileTag(TestProfile_2, 2), false);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer1.PutBoolean(ProfileTag(TestProfile_1, 2), true);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer.CloseContainer(writer1);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
}
err = writer.Finalize();
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
}
/**
* AppendEncoding2()
*
* This function appends two boolean types and two container types to the first
* container.
*
* The boolean types are-
* <TestProfile_1, 2, false>
* <TestProfile_2, 2, true>
*
* The two new container types are-
* <TestProfile_1, 1, kTLVType_Structure, <TestProfile_1, 2, true> <TestProfile_2, 2, false> >,
* <TestProfile_2, 1, kTLVType_Structure, <TestProfile_2, 2, false> <TestProfile_1, 2, true> >
*/
void AppendEncoding2(nlTestSuite *inSuite, uint8_t *buf, uint32_t dataLen, uint32_t maxLen, uint32_t& updatedLen)
{
WEAVE_ERROR err;
TLVUpdater updater;
err = updater.Init(buf, dataLen, maxLen);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
updater.SetImplicitProfileId(TestProfile_2);
TestNext<TLVUpdater>(inSuite, updater);
{
TLVType outerContainerType;
TestAndEnterContainer<TLVUpdater>(inSuite, updater, kTLVType_Structure, ProfileTag(TestProfile_1, 1), outerContainerType);
TestNext<TLVUpdater>(inSuite, updater);
// Move the element without modification
TestMove(inSuite, updater);
TestNext<TLVUpdater>(inSuite, updater);
// Read and copy the element with/without modification
TestGet<TLVUpdater, bool>(inSuite, updater, kTLVType_Boolean, ProfileTag(TestProfile_2, 2), false);
err = updater.PutBoolean(ProfileTag(TestProfile_2, 2), false);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
// TestEnd and add data at the end of the container
TestEnd<TLVUpdater>(inSuite, updater);
// Put new values in the encoding using the updater
// Add <TestProfile_1, 2, false>
err = updater.PutBoolean(ProfileTag(TestProfile_1, 2), false);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
// Add <TestProfile_2, 2, true>
err = updater.PutBoolean(ProfileTag(TestProfile_2, 2), true);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
// Add a new container
{
TLVType outerContainerType1;
err = updater.StartContainer(ProfileTag(TestProfile_1, 1), kTLVType_Structure, outerContainerType1);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
// Add <TestProfile_1, 2, true>
err = updater.PutBoolean(ProfileTag(TestProfile_1, 2), true);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
// Add <TestProfile_1, 2, true>
err = updater.PutBoolean(ProfileTag(TestProfile_2, 2), false);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
// Close the container
err = updater.EndContainer(outerContainerType1);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
}
// Add another new container
{
TLVType outerContainerType1;
err = updater.StartContainer(ProfileTag(TestProfile_2, 1), kTLVType_Structure, outerContainerType1);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
// Add <TestProfile_2, 2, false>
err = updater.PutBoolean(ProfileTag(TestProfile_2, 2), false);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
// Add <TestProfile_1, 2, true>
err = updater.PutBoolean(ProfileTag(TestProfile_1, 2), true);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
// Close the container
err = updater.EndContainer(outerContainerType1);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
}
TestEndAndExitContainer<TLVUpdater>(inSuite, updater, outerContainerType);
}
TestNext<TLVUpdater>(inSuite, updater);
// Move the container unmodified
TestMove(inSuite, updater);
TestEnd<TLVUpdater>(inSuite, updater);
err = updater.Finalize();
NL_TEST_ASSERT(inSuite, err == WEAVE_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-
* <TestProfile_1, 2, false>
* <TestProfile_2, 2, true>
*
* The two new container types are-
* <TestProfile_1, 1, kTLVType_Structure, <TestProfile_1, 2, true> <TestProfile_2, 2, false> >,
* <TestProfile_2, 1, kTLVType_Structure, <TestProfile_2, 2, false> <TestProfile_1, 2, true> >
*/
void FindAppendEncoding2(nlTestSuite *inSuite, uint8_t *buf, uint32_t dataLen, uint32_t maxLen, uint32_t& updatedLen, bool findContainer)
{
WEAVE_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 = nl::Weave::TLV::Utilities::Find(reader, ProfileTag(TestProfile_1, 1), tagReader);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = tagReader.EnterContainer(outerContainerType);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
do {
err = tagReader.Next();
} while (err != WEAVE_END_OF_TLV);
TestEnd<TLVReader>(inSuite, tagReader);
// Init a TLVUpdater using the TLVReader
err = updater.Init(tagReader, maxLen - dataLen);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
}
else
{
// Find
TLVReader tagReader;
err = nl::Weave::TLV::Utilities::Find(reader, ProfileTag(TestProfile_2, 2), tagReader);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
// Test Find(recurse = true)
TLVReader tagReader2;
err = nl::Weave::TLV::Utilities::Find(reader, ProfileTag(TestProfile_2, 2), tagReader2, true);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
//
// Test Find(recurse = false)
TLVReader tagReader3;
err = nl::Weave::TLV::Utilities::Find(reader, ProfileTag(TestProfile_2, 2), tagReader3, false);
NL_TEST_ASSERT(inSuite, err == WEAVE_ERROR_TLV_TAG_NOT_FOUND);
// Init a TLVUpdater using the TLVReader
err = updater.Init(tagReader, maxLen - dataLen);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
TestNext<TLVUpdater>(inSuite, updater);
// Move the element without modification
TestMove(inSuite, updater);
}
// Put new values in the encoding using the updater
// Add <TestProfile_1, 2, false>
err = updater.PutBoolean(ProfileTag(TestProfile_1, 2), false);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
// Add <TestProfile_2, 2, true>
err = updater.PutBoolean(ProfileTag(TestProfile_2, 2), true);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
// Add a new container
{
TLVType outerContainerType1;
err = updater.StartContainer(ProfileTag(TestProfile_1, 1), kTLVType_Structure, outerContainerType1);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
// Add <TestProfile_1, 2, true>
err = updater.PutBoolean(ProfileTag(TestProfile_1, 2), true);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
// Add <TestProfile_1, 2, true>
err = updater.PutBoolean(ProfileTag(TestProfile_2, 2), false);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
// Close the container
err = updater.EndContainer(outerContainerType1);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
}
// Add another new container
{
TLVType outerContainerType1;
err = updater.StartContainer(ProfileTag(TestProfile_2, 1), kTLVType_Structure, outerContainerType1);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
// Add <TestProfile_2, 2, false>
err = updater.PutBoolean(ProfileTag(TestProfile_2, 2), false);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
// Add <TestProfile_1, 2, true>
err = updater.PutBoolean(ProfileTag(TestProfile_1, 2), true);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
// Close the container
err = updater.EndContainer(outerContainerType1);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
}
// Move everything else unmodified
updater.MoveUntilEnd();
TestEnd<TLVUpdater>(inSuite, updater);
err = updater.Finalize();
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
updatedLen = updater.GetLengthWritten();
}
void AppendEncoding3(nlTestSuite *inSuite, uint8_t *buf, uint32_t dataLen, uint32_t maxLen, uint32_t& updatedLen)
{
WEAVE_ERROR err;
TLVUpdater updater;
err = updater.Init(buf, dataLen, maxLen);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
updater.SetImplicitProfileId(TestProfile_2);
TestNext<TLVUpdater>(inSuite, updater);
{
TLVType outerContainerType;
TestAndEnterContainer<TLVUpdater>(inSuite, updater, kTLVType_Structure, ProfileTag(TestProfile_1, 1), outerContainerType);
TestNext<TLVUpdater>(inSuite, updater);
// Move the element without modification
TestMove(inSuite, updater);
// Put new value in the encoding using the updater
// Add <TestProfile_2, 2, true>
err = updater.PutBoolean(ProfileTag(TestProfile_2, 2), true);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
TestEndAndExitContainer<TLVUpdater>(inSuite, updater, outerContainerType);
}
TestEnd<TLVUpdater>(inSuite, updater);
err = updater.Finalize();
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
updatedLen = updater.GetLengthWritten();
}
void AppendEncoding4(nlTestSuite *inSuite, uint8_t *buf, uint32_t dataLen, uint32_t maxLen, uint32_t& updatedLen)
{
WEAVE_ERROR err;
TLVUpdater updater;
err = updater.Init(buf, dataLen, maxLen);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
updater.SetImplicitProfileId(TestProfile_2);
// Add a new container
{
TLVType outerContainerType;
err = updater.StartContainer(ProfileTag(TestProfile_1, 1), kTLVType_Structure, outerContainerType);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
// Add <TestProfile_1, 2, true>
err = updater.PutBoolean(ProfileTag(TestProfile_2, 2), false);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
// Close the container
err = updater.EndContainer(outerContainerType);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
}
err = updater.Finalize();
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
updatedLen = updater.GetLengthWritten();
}
void DeleteEncoding5(nlTestSuite *inSuite, uint8_t *buf, uint32_t dataLen, uint32_t maxLen, uint32_t& updatedLen)
{
WEAVE_ERROR err;
TLVUpdater updater;
err = updater.Init(buf, dataLen, maxLen);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
updater.SetImplicitProfileId(TestProfile_2);
TestNext<TLVUpdater>(inSuite, updater);
{
TLVType outerContainerType;
TestAndEnterContainer<TLVUpdater>(inSuite, updater, kTLVType_Structure, ProfileTag(TestProfile_1, 1), outerContainerType);
TestNext<TLVUpdater>(inSuite, updater);
TestMove(inSuite, updater);
TestNext<TLVUpdater>(inSuite, updater);
TestMove(inSuite, updater);
TestNext<TLVUpdater>(inSuite, updater);
// Get the value to inspect and skip writing it
TestGet<TLVUpdater, bool>(inSuite, updater, kTLVType_Boolean, ProfileTag(TestProfile_1, 2), false);
TestNext<TLVUpdater>(inSuite, updater);
// Skip the next boolean type and don't copy by doing nothing
TestNext<TLVUpdater>(inSuite, 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<TLVReader>(inSuite, reader, kTLVType_Structure, ProfileTag(TestProfile_1, 1), containerType);
TestNext<TLVReader>(inSuite, reader);
// If the container's first element has the tag <TestProfile_1, 2>
// skip the whole container, and if NOT copy the container
if (reader.GetTag() != ProfileTag(TestProfile_1, 2))
TestMove(inSuite, updater);
}
TestNext<TLVUpdater>(inSuite, updater);
// Skip the next container and don't copy by doing nothing
TestEndAndExitContainer<TLVUpdater>(inSuite, updater, outerContainerType);
}
// Move everything else unmodified
updater.MoveUntilEnd();
TestEnd<TLVUpdater>(inSuite, updater);
err = updater.Finalize();
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
updatedLen = updater.GetLengthWritten();
}
void ReadAppendedEncoding2(nlTestSuite *inSuite, TLVReader& reader)
{
TestNext<TLVReader>(inSuite, reader);
{ // Container 1
TLVReader reader1;
TestAndOpenContainer(inSuite, reader, kTLVType_Structure, ProfileTag(TestProfile_1, 1), reader1);
TestNext<TLVReader>(inSuite, reader1);
TestGet<TLVReader, bool>(inSuite, reader1, kTLVType_Boolean, ProfileTag(TestProfile_1, 2), true);
TestNext<TLVReader>(inSuite, reader1);
TestGet<TLVReader, bool>(inSuite, reader1, kTLVType_Boolean, ProfileTag(TestProfile_2, 2), false);
TestNext<TLVReader>(inSuite, reader1);
TestGet<TLVReader, bool>(inSuite, reader1, kTLVType_Boolean, ProfileTag(TestProfile_1, 2), false);
TestNext<TLVReader>(inSuite, reader1);
TestGet<TLVReader, bool>(inSuite, reader1, kTLVType_Boolean, ProfileTag(TestProfile_2, 2), true);
TestNext<TLVReader>(inSuite, reader1);
{
TLVReader reader2;
TestAndOpenContainer(inSuite, reader1, kTLVType_Structure, ProfileTag(TestProfile_1, 1), reader2);
TestNext<TLVReader>(inSuite, reader2);
TestGet<TLVReader, bool>(inSuite, reader2, kTLVType_Boolean, ProfileTag(TestProfile_1, 2), true);
TestNext<TLVReader>(inSuite, reader2);
TestGet<TLVReader, bool>(inSuite, reader2, kTLVType_Boolean, ProfileTag(TestProfile_2, 2), false);
TestEndAndCloseContainer(inSuite, reader1, reader2);
}
TestNext<TLVReader>(inSuite, reader1);
{
TLVReader reader2;
TestAndOpenContainer(inSuite, reader1, kTLVType_Structure, ProfileTag(TestProfile_2, 1), reader2);
TestNext<TLVReader>(inSuite, reader2);
TestGet<TLVReader, bool>(inSuite, reader2, kTLVType_Boolean, ProfileTag(TestProfile_2, 2), false);
TestNext<TLVReader>(inSuite, reader2);
TestGet<TLVReader, bool>(inSuite, reader2, kTLVType_Boolean, ProfileTag(TestProfile_1, 2), true);
TestEndAndCloseContainer(inSuite, reader1, reader2);
}
TestEndAndCloseContainer(inSuite, reader, reader1);
}
TestNext<TLVReader>(inSuite, reader);
{ // Container 2
TLVReader reader1;
TestAndOpenContainer(inSuite, reader, kTLVType_Structure, ProfileTag(TestProfile_2, 1), reader1);
TestNext<TLVReader>(inSuite, reader1);
TestGet<TLVReader, bool>(inSuite, reader1, kTLVType_Boolean, ProfileTag(TestProfile_2, 2), false);
TestNext<TLVReader>(inSuite, reader1);
TestGet<TLVReader, bool>(inSuite, reader1, kTLVType_Boolean, ProfileTag(TestProfile_1, 2), true);
TestEndAndCloseContainer(inSuite, reader, reader1);
}
TestEnd<TLVReader>(inSuite, reader);
}
void ReadAppendedEncoding3(nlTestSuite *inSuite, TLVReader& reader)
{
TestNext<TLVReader>(inSuite, reader);
{ // Container 1
TLVReader reader1;
TestAndOpenContainer(inSuite, reader, kTLVType_Structure, ProfileTag(TestProfile_1, 1), reader1);
TestNext<TLVReader>(inSuite, reader1);
TestGet<TLVReader, bool>(inSuite, reader1, kTLVType_Boolean, ProfileTag(TestProfile_2, 2), false);
TestNext<TLVReader>(inSuite, reader1);
TestGet<TLVReader, bool>(inSuite, reader1, kTLVType_Boolean, ProfileTag(TestProfile_2, 2), true);
TestEndAndCloseContainer(inSuite, reader, reader1);
}
TestEnd<TLVReader>(inSuite, reader);
}
void ReadAppendedEncoding4(nlTestSuite *inSuite, TLVReader& reader)
{
TestNext<TLVReader>(inSuite, reader);
{ // Container 1
TLVReader reader1;
TestAndOpenContainer(inSuite, reader, kTLVType_Structure, ProfileTag(TestProfile_1, 1), reader1);
TestNext<TLVReader>(inSuite, reader1);
TestGet<TLVReader, bool>(inSuite, reader1, kTLVType_Boolean, ProfileTag(TestProfile_2, 2), false);
TestEndAndCloseContainer(inSuite, reader, reader1);
}
TestEnd<TLVReader>(inSuite, reader);
}
void ReadDeletedEncoding5(nlTestSuite *inSuite, TLVReader& reader)
{
TestNext<TLVReader>(inSuite, reader);
{ // Container 1
TLVReader reader1;
TestAndOpenContainer(inSuite, reader, kTLVType_Structure, ProfileTag(TestProfile_1, 1), reader1);
TestNext<TLVReader>(inSuite, reader1);
TestGet<TLVReader, bool>(inSuite, reader1, kTLVType_Boolean, ProfileTag(TestProfile_1, 2), true);
TestNext<TLVReader>(inSuite, reader1);
TestGet<TLVReader, bool>(inSuite, reader1, kTLVType_Boolean, ProfileTag(TestProfile_2, 2), false);
TestEndAndCloseContainer(inSuite, reader, reader1);
}
TestNext<TLVReader>(inSuite, reader);
{ // Container 2
TLVReader reader1;
TestAndOpenContainer(inSuite, reader, kTLVType_Structure, ProfileTag(TestProfile_2, 1), reader1);
TestNext<TLVReader>(inSuite, reader1);
TestGet<TLVReader, bool>(inSuite, reader1, kTLVType_Boolean, ProfileTag(TestProfile_2, 2), false);
TestNext<TLVReader>(inSuite, reader1);
TestGet<TLVReader, bool>(inSuite, reader1, kTLVType_Boolean, ProfileTag(TestProfile_1, 2), true);
TestEndAndCloseContainer(inSuite, reader, reader1);
}
TestEnd<TLVReader>(inSuite, reader);
}
/**
* Test Simple Write and Reader
*/
void CheckSimpleWriteRead(nlTestSuite *inSuite, void *inContext)
{
uint8_t buf[2048];
TLVWriter writer;
TLVReader reader;
writer.Init(buf, sizeof(buf));
writer.ImplicitProfileId = TestProfile_2;
WriteEncoding1(inSuite, 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
NL_TEST_ASSERT(inSuite, encodedLen == sizeof(Encoding1));
NL_TEST_ASSERT(inSuite, memcmp(buf, Encoding1, encodedLen) == 0);
reader.Init(buf, encodedLen);
reader.ImplicitProfileId = TestProfile_2;
ReadEncoding1(inSuite, reader);
}
/**
* 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 SimpleDumpWriter(const char *aFormat, ...)
{
va_list args;
va_start(args, aFormat);
vprintf(aFormat, args);
va_end(args);
}
/**
* Test Pretty Printer
*/
void CheckPrettyPrinter(nlTestSuite *inSuite, void *inContext)
{
uint8_t buf[2048];
TLVWriter writer;
TLVReader reader;
writer.Init(buf, sizeof(buf));
writer.ImplicitProfileId = TestProfile_2;
WriteEncoding1(inSuite, writer);
uint32_t encodedLen = writer.GetLengthWritten();
NL_TEST_ASSERT(inSuite, encodedLen == sizeof(Encoding1));
NL_TEST_ASSERT(inSuite, memcmp(buf, Encoding1, encodedLen) == 0);
reader.Init(buf, encodedLen);
reader.ImplicitProfileId = TestProfile_2;
nl::Weave::TLV::Debug::Dump(reader, SimpleDumpWriter);
}
/**
* Test Data Macros
*/
void CheckDataMacro(nlTestSuite *inSuite, void *inContext)
{
NL_TEST_ASSERT(inSuite, sizeof(Encoding1_DataMacro) == sizeof(Encoding1));
NL_TEST_ASSERT(inSuite, memcmp(Encoding1, Encoding1_DataMacro, sizeof(Encoding1)) == 0);
uint8_t buf[2048];
TLVWriter writer;
writer.Init(buf, sizeof(buf));
writer.ImplicitProfileId = TestProfile_2;
WriteEncoding5(inSuite, writer);
uint32_t encodedLen = writer.GetLengthWritten();
NL_TEST_ASSERT(inSuite, sizeof(Encoding5_DataMacro) == encodedLen);
NL_TEST_ASSERT(inSuite, memcmp(buf, Encoding5_DataMacro, encodedLen) == 0);
}
static WEAVE_ERROR NullIterateHandler(const TLVReader &aReader, size_t aDepth, void *aContext)
{
(void)aReader;
(void)aDepth;
(void)aContext;
return WEAVE_NO_ERROR;
}
/**
* Test Weave TLV Utilities
*/
void CheckWeaveTLVUtilities(nlTestSuite *inSuite, void *inContext)
{
uint8_t buf[2048];
TLVWriter writer;
TLVReader reader, reader1;
WEAVE_ERROR err = WEAVE_NO_ERROR;
writer.Init(buf, sizeof(buf));
writer.ImplicitProfileId = TestProfile_2;
WriteEncoding1(inSuite, writer);
uint32_t encodedLen = writer.GetLengthWritten();
NL_TEST_ASSERT(inSuite, encodedLen == sizeof(Encoding1));
NL_TEST_ASSERT(inSuite, memcmp(buf, Encoding1, encodedLen) == 0);
reader.Init(buf, encodedLen);
reader.ImplicitProfileId = TestProfile_2;
reader1.Init(reader);
err = reader1.Next();
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
// Find
TLVReader tagReader;
err = nl::Weave::TLV::Utilities::Find(reader, ProfileTag(TestProfile_2, 65536), tagReader);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
// Find with reader positioned "on" the element of interest
err = nl::Weave::TLV::Utilities::Find(reader1, ProfileTag(TestProfile_1, 1), tagReader);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
// Find a tag that's not present
err = nl::Weave::TLV::Utilities::Find(reader, ProfileTag(TestProfile_2, 1024), tagReader);
NL_TEST_ASSERT(inSuite, err == WEAVE_ERROR_TLV_TAG_NOT_FOUND);
// Count
size_t count;
const size_t expectedCount = 17;
err = nl::Weave::TLV::Utilities::Count(reader, count);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
NL_TEST_ASSERT(inSuite, count == expectedCount);
// Count with reader already positioned "on" the first element in the encoding
err = nl::Weave::TLV::Utilities::Count(reader1, count);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
NL_TEST_ASSERT(inSuite, count == expectedCount);
// Iterate
err = nl::Weave::TLV::Utilities::Iterate(reader, NullIterateHandler, NULL);
NL_TEST_ASSERT(inSuite, err == WEAVE_END_OF_TLV);
}
/**
* Test Weave TLV Empty Find
*/
void CheckWeaveTLVEmptyFind(nlTestSuite *inSuite, void *inContext)
{
uint8_t buf[30];
TLVWriter writer;
TLVReader reader;
WEAVE_ERROR err = WEAVE_NO_ERROR;
writer.Init(buf, sizeof(buf));
writer.ImplicitProfileId = TestProfile_2;
WriteEmptyEncoding(inSuite, writer);
uint32_t encodedLen = writer.GetLengthWritten();
reader.Init(buf, encodedLen);
reader.ImplicitProfileId = TestProfile_2;
// Find the empty container
TLVReader tagReader;
err = nl::Weave::TLV::Utilities::Find(reader, ProfileTag(TestProfile_1, 256), tagReader);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
}
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
};
void WriteAppendReadTest0(nlTestSuite *inSuite)
{
uint8_t buf[74];
uint32_t updatedLen;
TLVWriter writer;
TLVReader reader;
writer.Init(buf, sizeof(buf));
writer.ImplicitProfileId = TestProfile_2;
WriteEncoding2(inSuite, 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
NL_TEST_ASSERT(inSuite, encodedLen == sizeof(Encoding2));
NL_TEST_ASSERT(inSuite, memcmp(buf, Encoding2, encodedLen) == 0);
// Append new data into encoding
AppendEncoding2(inSuite, 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
NL_TEST_ASSERT(inSuite, updatedLen == sizeof(AppendedEncoding2));
NL_TEST_ASSERT(inSuite, memcmp(buf, AppendedEncoding2, updatedLen) == 0);
reader.Init(buf, updatedLen);
reader.ImplicitProfileId = TestProfile_2;
ReadAppendedEncoding2(inSuite, reader);
}
void WriteFindAppendReadTest(nlTestSuite *inSuite, bool findContainer)
{
uint8_t buf[74];
uint32_t updatedLen;
TLVWriter writer;
TLVReader reader;
writer.Init(buf, sizeof(buf));
writer.ImplicitProfileId = TestProfile_2;
WriteEncoding2(inSuite, 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
NL_TEST_ASSERT(inSuite, encodedLen == sizeof(Encoding2));
NL_TEST_ASSERT(inSuite, memcmp(buf, Encoding2, encodedLen) == 0);
// Append new data into encoding
FindAppendEncoding2(inSuite, 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
NL_TEST_ASSERT(inSuite, updatedLen == sizeof(AppendedEncoding2));
NL_TEST_ASSERT(inSuite, memcmp(buf, AppendedEncoding2, updatedLen) == 0);
reader.Init(buf, updatedLen);
reader.ImplicitProfileId = TestProfile_2;
ReadAppendedEncoding2(inSuite, reader);
}
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
};
void WriteAppendReadTest1(nlTestSuite *inSuite)
{
uint8_t buf[14];
uint32_t updatedLen;
TLVWriter writer;
TLVReader reader;
writer.Init(buf, sizeof(buf));
writer.ImplicitProfileId = TestProfile_2;
WriteEncoding3(inSuite, 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
NL_TEST_ASSERT(inSuite, encodedLen == sizeof(Encoding3));
NL_TEST_ASSERT(inSuite, memcmp(buf, Encoding3, encodedLen) == 0);
// Append new data into encoding
AppendEncoding3(inSuite, 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
NL_TEST_ASSERT(inSuite, updatedLen == sizeof(AppendedEncoding3));
NL_TEST_ASSERT(inSuite, memcmp(buf, AppendedEncoding3, updatedLen) == 0);
reader.Init(buf, updatedLen);
reader.ImplicitProfileId = TestProfile_2;
ReadAppendedEncoding3(inSuite, reader);
}
uint8_t AppendedEncoding4[] =
{
// Container 1
0xD5, 0xBB, 0xAA, 0xDD, 0xCC, 0x01, 0x00,
0x88, 0x02, 0x00,
0x18,
};
void AppendReadTest(nlTestSuite *inSuite)
{
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(inSuite, 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
NL_TEST_ASSERT(inSuite, updatedLen == sizeof(AppendedEncoding4));
NL_TEST_ASSERT(inSuite, memcmp(buf, AppendedEncoding4, updatedLen) == 0);
TLVReader reader;
reader.Init(buf, updatedLen);
reader.ImplicitProfileId = TestProfile_2;
ReadAppendedEncoding4(inSuite, reader);
}
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
};
void WriteDeleteReadTest(nlTestSuite *inSuite)
{
uint8_t buf[74];
uint32_t updatedLen;
TLVWriter writer;
TLVReader reader;
writer.Init(buf, sizeof(buf));
writer.ImplicitProfileId = TestProfile_2;
WriteEncoding5(inSuite, 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
NL_TEST_ASSERT(inSuite, encodedLen == sizeof(Encoding5));
NL_TEST_ASSERT(inSuite, memcmp(buf, Encoding5, encodedLen) == 0);
// Delete some elements from the encoding
DeleteEncoding5(inSuite, buf, encodedLen, sizeof(buf), updatedLen);
NL_TEST_ASSERT(inSuite, updatedLen == sizeof(DeletedEncoding5));
NL_TEST_ASSERT(inSuite, memcmp(buf, DeletedEncoding5, updatedLen) == 0);
reader.Init(buf, updatedLen);
reader.ImplicitProfileId = TestProfile_2;
ReadDeletedEncoding5(inSuite, reader);
}
/**
* Test Packet Buffer
*/
void CheckPacketBuffer(nlTestSuite *inSuite, void *inContext)
{
PacketBuffer *buf = PacketBuffer::New(0);
TLVWriter writer;
TLVReader reader;
writer.Init(buf);
writer.ImplicitProfileId = TestProfile_2;
WriteEncoding1(inSuite, writer);
TestBufferContents(inSuite, buf, Encoding1, sizeof(Encoding1));
reader.Init(buf);
reader.ImplicitProfileId = TestProfile_2;
ReadEncoding1(inSuite, reader);
reader.Init(buf, buf->MaxDataLength(), false);
reader.ImplicitProfileId = TestProfile_2;
ReadEncoding1(inSuite, reader);
PacketBuffer::Free(buf);
}
WEAVE_ERROR CountEvictedMembers(WeaveCircularTLVBuffer &inBuffer, void * inAppData, TLVReader &inReader)
{
TestTLVContext *context = static_cast<TestTLVContext *>(inAppData);
WEAVE_ERROR err;
// "Process" the first element in the reader
err = inReader.Next();
NL_TEST_ASSERT(context->mSuite, err == WEAVE_NO_ERROR);
err = inReader.Skip();
NL_TEST_ASSERT(context->mSuite, err == WEAVE_NO_ERROR);
context->mEvictionCount++;
context->mEvictedBytes += inReader.GetLengthRead();
return WEAVE_NO_ERROR;
}
void CheckCircularTLVBufferSimple(nlTestSuite *inSuite, void *inContext)
{
// 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 = static_cast<TestTLVContext *>(inContext);
WeaveCircularTLVBuffer buffer(backingStore, 30);
writer.Init(&buffer);
writer.ImplicitProfileId = TestProfile_2;
context->mEvictionCount = 0;
context->mEvictedBytes = 0;
buffer.mProcessEvictedElement = CountEvictedMembers;
buffer.mAppData = inContext;
writer.PutBoolean(ProfileTag(TestProfile_1, 2), true);
WriteEncoding3(inSuite, writer);
WriteEncoding3(inSuite, writer);
WriteEncoding3(inSuite, writer);
NL_TEST_ASSERT(inSuite, context->mEvictionCount == 2);
NL_TEST_ASSERT(inSuite, context->mEvictedBytes == 18);
NL_TEST_ASSERT(inSuite, buffer.DataLength() == 22);
NL_TEST_ASSERT(inSuite, (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<TLVReader>(inSuite, reader);
ReadEncoding3(inSuite, reader);
TestNext<TLVReader>(inSuite, reader);
ReadEncoding3(inSuite, reader);
// Check that the reader is out of data
TestEnd<TLVReader>(inSuite, reader);
}
void CheckCircularTLVBufferEvictStraddlingEvent(nlTestSuite *inSuite, void *inContext)
{
// 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 = static_cast<TestTLVContext *>(inContext);
uint8_t backingStore[30];
CircularTLVWriter writer;
CircularTLVReader reader;
WeaveCircularTLVBuffer buffer(backingStore, 30);
writer.Init(&buffer);
writer.ImplicitProfileId = TestProfile_2;
context->mEvictionCount = 0;
context->mEvictedBytes = 0;
buffer.mProcessEvictedElement = CountEvictedMembers;
buffer.mAppData = inContext;
writer.PutBoolean(ProfileTag(TestProfile_1, 2), true);
WriteEncoding3(inSuite, writer);
WriteEncoding3(inSuite, writer);
WriteEncoding3(inSuite, writer);
WriteEncoding3(inSuite, writer);
// the write below will evict an element that straddles the buffer boundary.
WriteEncoding3(inSuite, writer);
WriteEncoding3(inSuite, writer);
WriteEncoding3(inSuite, writer);
WriteEncoding3(inSuite, writer);
NL_TEST_ASSERT(inSuite, writer.GetLengthWritten() == (8 * 11 + 7)); // 8 writes of Encoding3 (11 bytes each) and 7 bytes for the initial boolean.
NL_TEST_ASSERT(inSuite, buffer.DataLength() == 22);
NL_TEST_ASSERT(inSuite, (buffer.DataLength() + context->mEvictedBytes) == writer.GetLengthWritten());
NL_TEST_ASSERT(inSuite, context->mEvictionCount == 7);
// At this point the buffer should contain 2 instances of Encoding3.
reader.Init(&buffer);
reader.ImplicitProfileId = TestProfile_2;
TestNext<TLVReader>(inSuite, reader);
ReadEncoding3(inSuite, reader);
TestNext<TLVReader>(inSuite, reader);
ReadEncoding3(inSuite, reader);
// Check that the reader is out of data
TestEnd<TLVReader>(inSuite, reader);
}
void CheckCircularTLVBufferEdge(nlTestSuite *inSuite, void *inContext)
{
TestTLVContext *context = static_cast<TestTLVContext *>(inContext);
WEAVE_ERROR err;
uint8_t backingStore[7];
uint8_t backingStore1[14];
CircularTLVWriter writer;
CircularTLVReader reader;
TLVWriter writer1;
WeaveCircularTLVBuffer buffer(backingStore, sizeof(backingStore));
WeaveCircularTLVBuffer buffer1(backingStore1, sizeof(backingStore1));
writer.Init(&buffer);
writer.ImplicitProfileId = TestProfile_2;
context->mEvictionCount = 0;
context->mEvictedBytes = 0;
buffer.mProcessEvictedElement = CountEvictedMembers;
buffer.mAppData = inContext;
// Test eviction for an element that fits in the underlying buffer exactly
err = writer.PutBoolean(ProfileTag(TestProfile_1, 2), true);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer.PutBoolean(ProfileTag(TestProfile_1, 2), false);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer.Finalize();
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
// At this point the buffer should contain only the boolean we just wrote
reader.Init(&buffer);
reader.ImplicitProfileId = TestProfile_2;
TestNext<TLVReader>(inSuite, reader);
TestGet<TLVReader, bool>(inSuite, reader, kTLVType_Boolean, ProfileTag(TestProfile_1, 2), false);
// Check that the reader is out of data
TestEnd<TLVReader>(inSuite, reader);
// verify that an element larger than the underlying buffer fails out.
err = writer.OpenContainer(ProfileTag(TestProfile_1, 1), kTLVType_Structure, writer1);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer1.PutBoolean(ProfileTag(TestProfile_2, 2), false);
NL_TEST_ASSERT(inSuite, err == WEAVE_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);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer.Finalize();
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
reader.Init(&buffer1);
reader.ImplicitProfileId = TestProfile_2;
TestNext<TLVReader>(inSuite, reader);
TestGet<TLVReader, bool>(inSuite, reader, kTLVType_Boolean, ProfileTag(TestProfile_1, 2), true);
TestEnd<TLVReader>(inSuite, reader);
buffer1.EvictHead();
reader.Init(&buffer1);
reader.ImplicitProfileId = TestProfile_2;
TestEnd<TLVReader>(inSuite, reader);
}
writer.Init(&buffer1);
writer.ImplicitProfileId = TestProfile_2;
context->mEvictionCount = 0;
context->mEvictedBytes = 0;
buffer1.mProcessEvictedElement = CountEvictedMembers;
buffer1.mAppData = inContext;
// Two elements fit in the buffer exactly
err = writer.PutBoolean(ProfileTag(TestProfile_1, 2), true);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer.PutBoolean(ProfileTag(TestProfile_1, 2), false);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer.Finalize();
// Verify that we can read out two elements from the buffer
reader.Init(&buffer1);
reader.ImplicitProfileId = TestProfile_2;
TestNext<TLVReader>(inSuite, reader);
TestGet<TLVReader, bool>(inSuite, reader, kTLVType_Boolean, ProfileTag(TestProfile_1, 2), true);
TestNext<TLVReader>(inSuite, reader);
TestGet<TLVReader, bool>(inSuite, reader, kTLVType_Boolean, ProfileTag(TestProfile_1, 2), false);
TestEnd<TLVReader>(inSuite, 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<TLVReader>(inSuite, reader);
TestGet<TLVReader, bool>(inSuite, reader, kTLVType_Boolean, ProfileTag(TestProfile_1, 2), false);
// Check that the reader is out of data
TestEnd<TLVReader>(inSuite, 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);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer.Finalize();
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
// Verify that we can read out two elements from the buffer
reader.Init(&buffer1);
reader.ImplicitProfileId = TestProfile_2;
TestNext<TLVReader>(inSuite, reader);
TestGet<TLVReader, bool>(inSuite, reader, kTLVType_Boolean, ProfileTag(TestProfile_1, 2), false);
TestNext<TLVReader>(inSuite, reader);
TestGet<TLVReader, bool>(inSuite, reader, kTLVType_Boolean, ProfileTag(TestProfile_1, 2), true);
TestEnd<TLVReader>(inSuite, 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<TLVReader>(inSuite, reader);
}
void CheckWeaveTLVPutStringF(nlTestSuite *inSuite, void *inContext)
{
const size_t bufsize = 24;
char strBuffer[bufsize];
char valStr[bufsize];
uint8_t backingStore[bufsize];
TLVWriter writer;
TLVReader reader;
size_t num = 1;
WEAVE_ERROR err = WEAVE_NO_ERROR;
writer.Init(backingStore, bufsize);
snprintf(strBuffer, sizeof(strBuffer), "Sample string %zu", num);
err = writer.PutStringF(ProfileTag(TestProfile_1, 1), "Sample string %zu", num);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer.Finalize();
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
reader.Init(backingStore, writer.GetLengthWritten());
err = reader.Next();
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = reader.GetString(valStr, 256);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
NL_TEST_ASSERT(inSuite, strncmp(valStr, strBuffer, 256) == 0);
}
void CheckWeaveTLVPutStringFCircular(nlTestSuite *inSuite, void *inContext)
{
const size_t bufsize = 40;
char strBuffer[bufsize];
char valStr[bufsize];
uint8_t backingStore[bufsize];
CircularTLVWriter writer;
CircularTLVReader reader;
WeaveCircularTLVBuffer buffer(backingStore, bufsize);
size_t num = 1;
WEAVE_ERROR err = WEAVE_NO_ERROR;
// Initial test: Verify that a straight printf works as expected into continuous buffer.
writer.Init(&buffer);
snprintf(strBuffer, sizeof(strBuffer), "Sample string %zu", num);
err = writer.PutBoolean(ProfileTag(TestProfile_1, 2), true);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer.Finalize();
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer.PutStringF(ProfileTag(TestProfile_1, 1), "Sample string %zu", num);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer.Finalize();
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
reader.Init(&buffer);
//Skip over the initial element
err = reader.Next();
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = reader.Next();
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = reader.GetString(valStr, bufsize);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
NL_TEST_ASSERT(inSuite, 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 %zu", num);
err = writer.PutStringF(ProfileTag(TestProfile_1, 1), "Sample string %zu", num);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer.Finalize();
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
reader.Init(&buffer);
err = reader.Next();
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = reader.GetString(valStr, bufsize);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
NL_TEST_ASSERT(inSuite, strncmp(valStr, strBuffer, bufsize) == 0);
}
void CheckWeaveTLVSkipCircular(nlTestSuite *inSuite, void * inContext)
{
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;
WeaveCircularTLVBuffer buffer(backingStore, bufsize);
WEAVE_ERROR err = WEAVE_NO_ERROR;
writer.Init(&buffer);
err = writer.PutString(AnonymousTag, testString);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer.PutString(AnonymousTag, testString);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer.PutString(AnonymousTag, testString); // This event straddles the boundary
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer.PutString(AnonymousTag, testString); // This one does not.
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer.Finalize();
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
reader.Init(&buffer);
err = reader.Next(); // position the reader at the straddling element
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = reader.Skip(); // // Test that the buf ptr is handled correctly within the ReadData() function.
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
}
/**
* Test Buffer Overflow
*/
void CheckBufferOverflow(nlTestSuite *inSuite, void *inContext)
{
TLVWriter writer;
TLVReader reader;
PacketBuffer *buf = PacketBuffer::New(0);
uint16_t maxDataLen = buf->MaxDataLength();
uint16_t reserve = (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/decoding to overlap the
// end of the buffer and the beginning of the next.
for ( ; reserve < maxDataLen; reserve++)
{
buf->SetStart(buf->Start() + reserve);
writer.Init(buf);
writer.GetNewBuffer = TLVWriter::GetNewPacketBuffer;
writer.ImplicitProfileId = TestProfile_2;
WriteEncoding1(inSuite, writer);
TestBufferContents(inSuite, buf, Encoding1, sizeof(Encoding1));
reader.Init(buf, 0xFFFFFFFFUL, true);
reader.ImplicitProfileId = TestProfile_2;
ReadEncoding1(inSuite, reader);
PacketBuffer::Free(buf);
buf = PacketBuffer::New(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 D2 debug builds. More details can be found at
* jira://SAPPHIRE-10921.
*
*/
const uint8_t IdentifyResponseBuf[] =
{
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,
};
const uint32_t IdentifyResponseLen = 53;
void CheckSapphire10921(nlTestSuite *inSuite, void *inContext)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
TLVReader reader;
reader.Init(IdentifyResponseBuf, IdentifyResponseLen);
reader.ImplicitProfileId = kWeaveProfile_DeviceDescription;
err = reader.Next();
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
NL_TEST_ASSERT(inSuite, reader.GetTag() == 0xe00000001);
}
/**
* Test Weave TLV Writer Copy Container
*/
void TestWeaveTLVWriterCopyContainer(nlTestSuite *inSuite)
{
uint8_t buf[2048];
TLVWriter writer;
TLVReader reader;
reader.Init(Encoding1, sizeof(Encoding1));
reader.ImplicitProfileId = TestProfile_2;
TestNext<TLVReader>(inSuite, reader);
writer.Init(buf, sizeof(buf));
writer.ImplicitProfileId = TestProfile_2;
WEAVE_ERROR err = writer.CopyContainer(reader);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
uint32_t encodedLen = writer.GetLengthWritten();
NL_TEST_ASSERT(inSuite, encodedLen == sizeof(Encoding1));
int memcmpRes = memcmp(buf, Encoding1, encodedLen);
NL_TEST_ASSERT(inSuite, memcmpRes == 0);
}
/**
* Test Weave TLV Writer Copy Element
*/
void TestWeaveTLVWriterCopyElement(nlTestSuite *inSuite)
{
WEAVE_ERROR err;
uint8_t expectedBuf[2048], testBuf[2048];
uint32_t expectedLen, testLen;
TLVWriter writer;
TLVType outerContainerType;
enum { kRepeatCount = 3 };
writer.Init(expectedBuf, sizeof(expectedBuf));
writer.ImplicitProfileId = TestProfile_2;
err = writer.StartContainer(AnonymousTag, kTLVType_Structure, outerContainerType);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
for (int i = 0; i < kRepeatCount; i++)
{
WriteEncoding1(inSuite, writer);
}
err = writer.EndContainer(outerContainerType);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer.Finalize();
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
expectedLen= writer.GetLengthWritten();
writer.Init(testBuf, sizeof(testBuf));
writer.ImplicitProfileId = TestProfile_2;
err = writer.StartContainer(AnonymousTag, kTLVType_Structure, outerContainerType);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
for (int i = 0; i < kRepeatCount; i++)
{
TLVReader reader;
reader.Init(Encoding1, sizeof(Encoding1));
reader.ImplicitProfileId = TestProfile_2;
TestNext<TLVReader>(inSuite, reader);
err = writer.CopyElement(reader);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
}
err = writer.EndContainer(outerContainerType);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer.Finalize();
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
testLen = writer.GetLengthWritten();
NL_TEST_ASSERT(inSuite, testLen == expectedLen);
int memcmpRes = memcmp(testBuf, expectedBuf, testLen);
NL_TEST_ASSERT(inSuite, memcmpRes == 0);
}
void PreserveSizeWrite(nlTestSuite *inSuite, TLVWriter& writer, bool preserveSize)
{
WEAVE_ERROR err;
TLVWriter writer2;
// kTLVTagControl_FullyQualified_8Bytes
err = writer.Put(ProfileTag(TestProfile_1, 4000000000ULL), (int64_t) 40000000000ULL, true);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer.Put(ProfileTag(TestProfile_1, 4000000000ULL), (int16_t) 12345, true);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer.Put(ProfileTag(TestProfile_1, 4000000000ULL), (float) 1.0);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer.OpenContainer(ProfileTag(TestProfile_1, 1), kTLVType_Structure, writer2);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
{
TLVWriter writer3;
err = writer2.OpenContainer(ContextTag(0), kTLVType_Array, writer3);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer3.Put(AnonymousTag, (uint8_t) 42, preserveSize);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer3.Put(AnonymousTag, (uint16_t) 42, preserveSize);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer3.Put(AnonymousTag, (uint32_t) 42, preserveSize);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer3.Put(AnonymousTag, (uint64_t) 40000000000ULL, preserveSize);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer3.Put(AnonymousTag, (int8_t) -17, preserveSize);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer3.Put(AnonymousTag, (int16_t) -17, preserveSize);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer3.Put(AnonymousTag, (int32_t) -170000, preserveSize);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer3.Put(AnonymousTag, (int64_t) -170000, preserveSize);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
// the below cases are for full coverage of PUTs
err = writer3.Put(AnonymousTag, (uint64_t) 65535, false);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer3.Put(AnonymousTag, (int64_t) 32767, false);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer3.Put(AnonymousTag, (int64_t) 40000000000ULL, false);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer2.CloseContainer(writer3);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
}
err = writer.CloseContainer(writer2);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer.Finalize();
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
}
/**
* Test Weave TLV Writer with Preserve Size
*/
void TestWeaveTLVWriterPreserveSize(nlTestSuite *inSuite)
{
uint8_t buf[2048];
TLVWriter writer;
writer.Init(buf, sizeof(buf));
writer.ImplicitProfileId = TestProfile_2;
PreserveSizeWrite(inSuite, writer, true);
uint32_t encodedLen = writer.GetLengthWritten();
NL_TEST_ASSERT(inSuite, encodedLen == 105);
}
/**
* Test error handling of Weave TLV Writer
*/
void TestWeaveTLVWriterErrorHandling(nlTestSuite *inSuite)
{
WEAVE_ERROR err;
uint8_t buf[2048];
TLVWriter writer, writer2, writer3;
writer.Init(buf, sizeof(buf));
writer.ImplicitProfileId = TestProfile_2;
// OpenContainer() for non-container
err = writer.OpenContainer(ProfileTag(TestProfile_1, 1), kTLVType_Boolean, writer2);
NL_TEST_ASSERT(inSuite, err == WEAVE_ERROR_WRONG_TLV_TYPE);
// CloseContainer() for non-container
err = writer.CloseContainer(writer2);
NL_TEST_ASSERT(inSuite, err == WEAVE_ERROR_INCORRECT_STATE);
// OpenContainer() failure
err = writer.OpenContainer(ProfileTag(TestProfile_1, 1), kTLVType_Structure, writer2);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer2.OpenContainer(ProfileTag(TestProfile_1, 1), kTLVType_Structure, writer3);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
// CloseContainer() failure
err = writer.CloseContainer(writer2);
NL_TEST_ASSERT(inSuite, err == WEAVE_ERROR_TLV_CONTAINER_OPEN);
// StartContainer()
TLVType outerContainerType;
err = writer.StartContainer(ProfileTag(TestProfile_2, 4000000000ULL), kTLVType_Boolean, outerContainerType);
NL_TEST_ASSERT(inSuite, err == WEAVE_ERROR_WRONG_TLV_TYPE);
// EndContainer()
outerContainerType = kTLVType_Boolean;
err = writer.EndContainer(outerContainerType);
NL_TEST_ASSERT(inSuite, err == WEAVE_ERROR_INCORRECT_STATE);
// PutPreEncodedContainer()
TLVReader reader;
reader.Init(buf, 2048);
err = writer.PutPreEncodedContainer(ProfileTag(TestProfile_2, 4000000000ULL), kTLVType_Boolean, reader.GetReadPoint(), reader.GetRemainingLength());
NL_TEST_ASSERT(inSuite, err == WEAVE_ERROR_INVALID_ARGUMENT);
}
/**
* Test Weave TLV Writer
*/
void CheckWeaveTLVWriter(nlTestSuite *inSuite, void *inContext)
{
TestWeaveTLVWriterCopyContainer(inSuite);
TestWeaveTLVWriterCopyElement(inSuite);
TestWeaveTLVWriterPreserveSize(inSuite);
TestWeaveTLVWriterErrorHandling(inSuite);
}
void SkipNonContainer(nlTestSuite *inSuite)
{
TLVReader reader;
const uint8_t *readpoint1 = NULL;
const uint8_t *readpoint2 = NULL;
reader.Init(Encoding1, sizeof(Encoding1));
reader.ImplicitProfileId = TestProfile_2;
TestSkip(inSuite, reader);
readpoint1 = reader.GetReadPoint();
// Skip again, to check the operation is idempotent
TestSkip(inSuite, reader);
readpoint2 = reader.GetReadPoint();
NL_TEST_ASSERT(inSuite, readpoint1 == readpoint2);
}
void SkipContainer(nlTestSuite *inSuite)
{
TLVReader reader;
const uint8_t *readpoint1 = NULL;
const uint8_t *readpoint2 = NULL;
reader.Init(Encoding1, sizeof(Encoding1));
reader.ImplicitProfileId = TestProfile_2;
TestNext<TLVReader>(inSuite, reader);
TestSkip(inSuite, reader);
readpoint1 = reader.GetReadPoint();
// Skip again, to check the operation is idempotent
TestSkip(inSuite, reader);
readpoint2 = reader.GetReadPoint();
NL_TEST_ASSERT(inSuite, readpoint1 == readpoint2);
}
void NextContainer(nlTestSuite *inSuite)
{
TLVReader reader;
reader.Init(Encoding1, sizeof(Encoding1));
reader.ImplicitProfileId = TestProfile_2;
TestNext<TLVReader>(inSuite, reader);
WEAVE_ERROR err = reader.Next();
NL_TEST_ASSERT(inSuite, err == WEAVE_END_OF_TLV);
}
/**
* Test Weave TLV Reader Skip functions
*/
void TestWeaveTLVReaderSkip(nlTestSuite *inSuite)
{
SkipNonContainer(inSuite);
SkipContainer(inSuite);
NextContainer(inSuite);
}
/**
* Test Weave TLV Reader Dup functions
*/
void TestWeaveTLVReaderDup(nlTestSuite *inSuite)
{
TLVReader reader;
reader.Init(Encoding1, sizeof(Encoding1));
reader.ImplicitProfileId = TestProfile_2;
TestNext<TLVReader>(inSuite, reader);
{
TLVReader reader2;
TestAndOpenContainer(inSuite, reader, kTLVType_Structure, ProfileTag(TestProfile_1, 1), reader2);
TestNext<TLVReader>(inSuite, reader2);
TestGet<TLVReader, bool>(inSuite, reader2, kTLVType_Boolean, ProfileTag(TestProfile_1, 2), true);
TestNext<TLVReader>(inSuite, reader2);
TestGet<TLVReader, bool>(inSuite, reader2, kTLVType_Boolean, ProfileTag(TestProfile_2, 2), false);
TestNext<TLVReader>(inSuite, reader2);
{
TLVReader reader3;
TestAndOpenContainer(inSuite, reader2, kTLVType_Array, ContextTag(0), reader3);
TestNext<TLVReader>(inSuite, reader3);
TestGet<TLVReader, int8_t>(inSuite, reader3, kTLVType_SignedInteger, AnonymousTag, 42);
TestGet<TLVReader, int16_t>(inSuite, reader3, kTLVType_SignedInteger, AnonymousTag, 42);
TestGet<TLVReader, int32_t>(inSuite, reader3, kTLVType_SignedInteger, AnonymousTag, 42);
TestGet<TLVReader, int64_t>(inSuite, reader3, kTLVType_SignedInteger, AnonymousTag, 42);
TestGet<TLVReader, uint32_t>(inSuite, reader3, kTLVType_SignedInteger, AnonymousTag, 42);
TestGet<TLVReader, uint64_t>(inSuite, reader3, kTLVType_SignedInteger, AnonymousTag, 42);
TestNext<TLVReader>(inSuite, reader3);
TestGet<TLVReader, int8_t>(inSuite, reader3, kTLVType_SignedInteger, AnonymousTag, -17);
TestGet<TLVReader, int16_t>(inSuite, reader3, kTLVType_SignedInteger, AnonymousTag, -17);
TestGet<TLVReader, int32_t>(inSuite, reader3, kTLVType_SignedInteger, AnonymousTag, -17);
TestGet<TLVReader, int64_t>(inSuite, reader3, kTLVType_SignedInteger, AnonymousTag, -17);
TestNext<TLVReader>(inSuite, reader3);
TestGet<TLVReader, int32_t>(inSuite, reader3, kTLVType_SignedInteger, AnonymousTag, -170000);
TestGet<TLVReader, int64_t>(inSuite, reader3, kTLVType_SignedInteger, AnonymousTag, -170000);
TestNext<TLVReader>(inSuite, reader3);
TestGet<TLVReader, int64_t>(inSuite, reader3, kTLVType_UnsignedInteger, AnonymousTag, 40000000000ULL);
TestGet<TLVReader, uint64_t>(inSuite, reader3, kTLVType_UnsignedInteger, AnonymousTag, 40000000000ULL);
TestNext<TLVReader>(inSuite, reader3);
{
TLVReader reader4;
TestAndOpenContainer(inSuite, reader3, kTLVType_Structure, AnonymousTag, reader4);
TestEndAndCloseContainer(inSuite, reader3, reader4);
}
TestNext<TLVReader>(inSuite, reader3);
{
TLVReader reader5;
TestAndOpenContainer(inSuite, reader3, kTLVType_Path, AnonymousTag, reader5);
TestNext<TLVReader>(inSuite, reader5);
TestNull(inSuite, reader5, ProfileTag(TestProfile_1, 17));
TestNext<TLVReader>(inSuite, reader5);
TestNull(inSuite, reader5, ProfileTag(TestProfile_2, 900000));
TestNext<TLVReader>(inSuite, reader5);
{
TLVType outerContainerType;
TestAndEnterContainer<TLVReader>(inSuite, reader5, kTLVType_Structure, ProfileTag(TestProfile_2, 4000000000ULL), outerContainerType);
TestNext<TLVReader>(inSuite, reader5);
TestDupString(inSuite, reader5, CommonTag(70000), sLargeString);
TestEndAndExitContainer<TLVReader>(inSuite, reader5, outerContainerType);
}
TestEndAndCloseContainer(inSuite, reader3, reader5);
}
TestEndAndCloseContainer(inSuite, reader2, reader3);
}
TestNext<TLVReader>(inSuite, reader2);
TestDupBytes(inSuite, reader2, ProfileTag(TestProfile_1, 5), (uint8_t *)("This is a test"), 14);
TestNext<TLVReader>(inSuite, reader2);
TestGet<TLVReader, double>(inSuite, reader2, kTLVType_FloatingPointNumber, ProfileTag(TestProfile_2, 65535), (float)17.9);
TestNext<TLVReader>(inSuite, reader2);
TestGet<TLVReader, double>(inSuite, reader2, kTLVType_FloatingPointNumber, ProfileTag(TestProfile_2, 65536), (double)17.9);
TestEndAndCloseContainer(inSuite, reader, reader2);
}
TestEnd<TLVReader>(inSuite, reader);
}
/**
* Test error handling of Weave TLV Reader
*/
void TestWeaveTLVReaderErrorHandling(nlTestSuite *inSuite)
{
WEAVE_ERROR err;
uint8_t buf[2048];
TLVReader reader;
reader.Init(buf, sizeof(buf));
reader.ImplicitProfileId = TestProfile_2;
// Get(bool&)
bool val;
err = reader.Get(val);
NL_TEST_ASSERT(inSuite, err == WEAVE_ERROR_WRONG_TLV_TYPE);
// Get(double&)
double numD;
err = reader.Get(numD);
NL_TEST_ASSERT(inSuite, err == WEAVE_ERROR_WRONG_TLV_TYPE);
// Get(uint64_t&)
uint64_t num;
err = reader.Get(num);
NL_TEST_ASSERT(inSuite, err == WEAVE_ERROR_WRONG_TLV_TYPE);
// GetBytes()
uint8_t bBuf[16];
err = reader.GetBytes(bBuf, sizeof(bBuf));
NL_TEST_ASSERT(inSuite, err == WEAVE_ERROR_WRONG_TLV_TYPE);
// GetString()
char sBuf[16];
err = reader.GetString(sBuf, sizeof(sBuf));
NL_TEST_ASSERT(inSuite, err == WEAVE_ERROR_WRONG_TLV_TYPE);
// OpenContainer()
TLVReader reader2;
err = reader.OpenContainer(reader2);
NL_TEST_ASSERT(inSuite, err == WEAVE_ERROR_INCORRECT_STATE);
// CloseContainer()
err = reader.CloseContainer(reader2);
NL_TEST_ASSERT(inSuite, err == WEAVE_ERROR_INCORRECT_STATE);
// EnterContainer()
TLVType outerContainerType = kTLVType_Boolean;
err = reader.EnterContainer(outerContainerType);
NL_TEST_ASSERT(inSuite, err == WEAVE_ERROR_INCORRECT_STATE);
// DupString()
char *str = (char *)malloc(16);
err = reader.DupString(str);
NL_TEST_ASSERT(inSuite, err == WEAVE_ERROR_WRONG_TLV_TYPE);
free(str);
// GetDataPtr()
const uint8_t *data = (uint8_t *)malloc(16);
err = reader.GetDataPtr(data);
NL_TEST_ASSERT(inSuite, err == WEAVE_ERROR_WRONG_TLV_TYPE);
free((void *)data);
}
/**
* Test Weave TLV Reader in a use case
*/
void TestWeaveTLVReaderInPractice(nlTestSuite *inSuite)
{
uint8_t buf[2048];
TLVWriter writer;
TLVReader reader;
writer.Init(buf, sizeof(buf));
writer.ImplicitProfileId = TestProfile_2;
PreserveSizeWrite(inSuite, writer, true);
reader.Init(buf, sizeof(buf));
TestNext<TLVReader>(inSuite, reader);
TestGet<TLVReader, int64_t>(inSuite, reader, kTLVType_SignedInteger, ProfileTag(TestProfile_1, 4000000000ULL), (int64_t) 40000000000ULL);
TestNext<TLVReader>(inSuite, reader);
TestGet<TLVReader, int64_t>(inSuite, reader, kTLVType_SignedInteger, ProfileTag(TestProfile_1, 4000000000ULL), (int16_t) 12345);
TestNext<TLVReader>(inSuite, reader);
TestGet<TLVReader, double>(inSuite, reader, kTLVType_FloatingPointNumber, ProfileTag(TestProfile_1, 4000000000ULL), (float) 1.0);
}
void TestWeaveTLVReader_NextOverContainer_ProcessElement(nlTestSuite *inSuite, TLVReader& reader, void *context)
{
WEAVE_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);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
ForEachElement(inSuite, readerClone1, NULL, NULL);
err = readerClone1.ExitContainer(outerContainerType);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
nextRes1 = readerClone1.Next();
NL_TEST_ASSERT(inSuite, nextRes1 == WEAVE_NO_ERROR || nextRes1 == WEAVE_END_OF_TLV);
// For the other reader, skip over the entire container using the Next() method.
nextRes2 = readerClone2.Next();
NL_TEST_ASSERT(inSuite, nextRes2 == WEAVE_NO_ERROR || nextRes2 == WEAVE_END_OF_TLV);
// Verify the two readers end up in the same state/position.
NL_TEST_ASSERT(inSuite, nextRes1 == nextRes2);
NL_TEST_ASSERT(inSuite, readerClone1.GetType() == readerClone2.GetType());
NL_TEST_ASSERT(inSuite, readerClone1.GetReadPoint() == readerClone2.GetReadPoint());
}
}
/**
* Test using Weave TLV Reader Next() method to skip over containers.
*/
void TestWeaveTLVReader_NextOverContainer(nlTestSuite *inSuite)
{
TLVReader reader;
reader.Init(Encoding1, sizeof(Encoding1));
reader.ImplicitProfileId = TestProfile_2;
ForEachElement(inSuite, reader, NULL, TestWeaveTLVReader_NextOverContainer_ProcessElement);
}
void TestWeaveTLVReader_SkipOverContainer_ProcessElement(nlTestSuite *inSuite, TLVReader& reader, void *context)
{
WEAVE_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);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
ForEachElement(inSuite, readerClone1, NULL, NULL);
err = readerClone1.ExitContainer(outerContainerType);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
// For the other reader, skip over the entire container using the Skip() method.
err = readerClone2.Skip();
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
// Verify the two readers end up in the same state/position.
NL_TEST_ASSERT(inSuite, readerClone1.GetType() == readerClone2.GetType());
NL_TEST_ASSERT(inSuite, readerClone1.GetReadPoint() == readerClone2.GetReadPoint());
}
}
/**
* Test using Weave TLV Reader Skip() method to skip over containers.
*/
void TestWeaveTLVReader_SkipOverContainer(nlTestSuite *inSuite)
{
TLVReader reader;
reader.Init(Encoding1, sizeof(Encoding1));
reader.ImplicitProfileId = TestProfile_2;
ForEachElement(inSuite, reader, NULL, TestWeaveTLVReader_SkipOverContainer_ProcessElement);
}
/**
* Test Weave TLV Reader
*/
void CheckWeaveTLVReader(nlTestSuite *inSuite, void *inContext)
{
TestWeaveTLVReaderSkip(inSuite);
TestWeaveTLVReaderDup(inSuite);
TestWeaveTLVReaderErrorHandling(inSuite);
TestWeaveTLVReaderInPractice(inSuite);
TestWeaveTLVReader_NextOverContainer(inSuite);
TestWeaveTLVReader_SkipOverContainer(inSuite);
}
/**
* Test Weave TLV Items
*/
static void TestItems(nlTestSuite *inSuite, void *inContext)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
uint8_t sBuffer[256];
TLVWriter writer;
writer.Init(sBuffer, sizeof(sBuffer));
TLVWriter writer2;
err = writer.OpenContainer(AnonymousTag, kTLVType_Array, writer2);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
{
err = writer2.PutBoolean(AnonymousTag, true);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer2.Put(AnonymousTag, static_cast<int8_t>(-1));
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer2.Put(AnonymousTag, static_cast<int16_t>(-2));
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer2.Put(AnonymousTag, static_cast<int32_t>(-3));
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer2.Put(AnonymousTag, static_cast<int64_t>(-4));
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer2.Put(AnonymousTag, static_cast<float>(-5.5));
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer2.Put(AnonymousTag, static_cast<double>(-3.14159265358979323846));
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
}
err = writer.CloseContainer(writer2);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer.OpenContainer(AnonymousTag, kTLVType_Array, writer2);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
{
err = writer2.PutBoolean(AnonymousTag, false);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer2.Put(AnonymousTag, static_cast<int8_t>(1));
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer2.Put(AnonymousTag, static_cast<int16_t>(2));
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer2.Put(AnonymousTag, static_cast<int32_t>(3));
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer2.Put(AnonymousTag, static_cast<int64_t>(4));
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer2.Put(AnonymousTag, static_cast<uint8_t>(5));
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer2.Put(AnonymousTag, static_cast<uint16_t>(6));
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer2.Put(AnonymousTag, static_cast<uint32_t>(7));
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer2.Put(AnonymousTag, static_cast<uint64_t>(8));
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer2.Put(AnonymousTag, static_cast<float>(9.9));
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer2.Put(AnonymousTag, static_cast<double>(3.14159265358979323846));
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
}
err = writer.CloseContainer(writer2);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer.Finalize();
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
}
/**
* Test Weave TLV Containers
*/
static void TestContainers(nlTestSuite *inSuite, void *inContext)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
TLVWriter writer;
uint8_t sBuffer[256];
writer.Init(sBuffer, sizeof(sBuffer));
TLVWriter writer2;
err = writer.OpenContainer(AnonymousTag, kTLVType_Array, writer2);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
TLVType type = writer2.GetContainerType();
NL_TEST_ASSERT(inSuite, type == kTLVType_Array);
err = writer.CloseContainer(writer2);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer.OpenContainer(AnonymousTag, kTLVType_Structure, writer2);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
type = writer2.GetContainerType();
NL_TEST_ASSERT(inSuite, type == kTLVType_Structure);
err = writer.CloseContainer(writer2);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer.Finalize();
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
}
/**
* Test Weave TLV Basics
*/
static void CheckWeaveTLVBasics(nlTestSuite *inSuite, void *inContext)
{
TestItems(inSuite, inContext);
TestContainers(inSuite, inContext);
}
/**
* Test Weave TLV Updater
*/
static void CheckWeaveUpdater(nlTestSuite *inSuite, void *inContext)
{
WriteAppendReadTest0(inSuite);
WriteAppendReadTest1(inSuite);
WriteFindAppendReadTest(inSuite, false); // Find an element
WriteFindAppendReadTest(inSuite, true); // Find a container
AppendReadTest(inSuite);
WriteDeleteReadTest(inSuite);
}
/**
* Test TLV CloseContainer symbol reservations
*/
class OptimisticTLVWriter : public TLVWriter
{
public:
void Init(uint8_t *buf, uint32_t maxLen);
};
void OptimisticTLVWriter::Init(uint8_t *buf, uint32_t maxLen)
{
TLVWriter::Init(buf, maxLen);
SetCloseContainerReserved(false);
}
static void CheckCloseContainerReserve(nlTestSuite *inSuite, void *inContext)
{
// 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];
WEAVE_ERROR err = WEAVE_NO_ERROR;
TLVWriter writer1;
OptimisticTLVWriter writer2;
TLVWriter innerWriter1, innerWriter2;
TLVType container1, container2;
writer1.Init(buf, sizeof(buf));
err = writer1.OpenContainer(AnonymousTag, kTLVType_Array, innerWriter1);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = innerWriter1.OpenContainer(AnonymousTag, kTLVType_Structure, innerWriter2);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = innerWriter2.PutBoolean(ProfileTag(TestProfile_1, 2), true);
NL_TEST_ASSERT(inSuite, err == WEAVE_ERROR_BUFFER_TOO_SMALL);
err = innerWriter1.CloseContainer(innerWriter2);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer1.CloseContainer(innerWriter1);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
writer2.Init(buf, sizeof(buf));
err = writer2.OpenContainer(AnonymousTag, kTLVType_Array, innerWriter1);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = innerWriter1.OpenContainer(AnonymousTag, kTLVType_Structure, innerWriter2);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = innerWriter2.PutBoolean(ProfileTag(TestProfile_1, 2), true);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = innerWriter1.CloseContainer(innerWriter2);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer2.CloseContainer(innerWriter1);
NL_TEST_ASSERT(inSuite, err == WEAVE_ERROR_BUFFER_TOO_SMALL);
// test the same scheme works on the Start/End container
writer1.Init(buf, sizeof(buf));
err = writer1.StartContainer(AnonymousTag, kTLVType_Array, container1);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer1.StartContainer(AnonymousTag, kTLVType_Structure, container2);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer1.PutBoolean(ProfileTag(TestProfile_1, 2), true);
NL_TEST_ASSERT(inSuite, err == WEAVE_ERROR_BUFFER_TOO_SMALL);
err = writer1.EndContainer(container2);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer1.EndContainer(container1);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
writer2.Init(buf, sizeof(buf));
err = writer2.StartContainer(AnonymousTag, kTLVType_Array, container1);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer2.StartContainer(AnonymousTag, kTLVType_Structure, container2);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer2.PutBoolean(ProfileTag(TestProfile_1, 2), true);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer2.EndContainer(container2);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer2.EndContainer(container1);
NL_TEST_ASSERT(inSuite, err == WEAVE_ERROR_BUFFER_TOO_SMALL);
// Test that the reservations work for the empty containers
writer1.Init(buf1, sizeof(buf1));
err = writer1.OpenContainer(ProfileTag(TestProfile_1, 2), kTLVType_Structure, innerWriter1);
NL_TEST_ASSERT(inSuite, err == WEAVE_ERROR_BUFFER_TOO_SMALL);
err = writer1.CloseContainer(innerWriter1);
NL_TEST_ASSERT(inSuite, err != WEAVE_NO_ERROR);
writer2.Init(buf1, sizeof(buf1));
err = writer2.OpenContainer(ProfileTag(TestProfile_1, 2), kTLVType_Structure, innerWriter1);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer2.CloseContainer(innerWriter1);
NL_TEST_ASSERT(inSuite, err == WEAVE_ERROR_BUFFER_TOO_SMALL);
writer1.Init(buf1, sizeof(buf1));
err = writer1.StartContainer(ProfileTag(TestProfile_1, 2), kTLVType_Structure, container1);
NL_TEST_ASSERT(inSuite, err == WEAVE_ERROR_BUFFER_TOO_SMALL);
err = writer1.EndContainer(container1);
NL_TEST_ASSERT(inSuite, err != WEAVE_NO_ERROR);
writer2.Init(buf1, sizeof(buf1));
err = writer2.StartContainer(ProfileTag(TestProfile_1, 2), kTLVType_Structure, container1);
NL_TEST_ASSERT(inSuite, err == WEAVE_NO_ERROR);
err = writer2.EndContainer(container1);
NL_TEST_ASSERT(inSuite, err == WEAVE_ERROR_BUFFER_TOO_SMALL);
}
static WEAVE_ERROR ReadFuzzedEncoding1(nlTestSuite *inSuite, TLVReader& reader)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
#define FUZZ_CHECK_VAL(TYPE, VAL) \
do { \
TYPE val; \
err = reader.Get(val); \
SuccessOrExit(err); \
VerifyOrExit(val == (VAL), err = WEAVE_ERROR_INVALID_ARGUMENT); \
} while (0)
#define FUZZ_CHECK_STRING(VAL) \
do { \
char buf[sizeof(VAL)]; \
VerifyOrExit(reader.GetLength() == strlen(VAL), err = WEAVE_ERROR_INVALID_ADDRESS); \
err = reader.GetString(buf, sizeof(buf)); \
SuccessOrExit(err); \
VerifyOrExit(strcmp(buf, (VAL)) == 0, err = WEAVE_ERROR_INVALID_ADDRESS); \
} while (0)
err = reader.Next(kTLVType_Structure, ProfileTag(TestProfile_1, 1));
SuccessOrExit(err);
{
TLVType outerContainer1Type;
err = reader.EnterContainer(outerContainer1Type);
SuccessOrExit(err);
err = reader.Next(kTLVType_Boolean, ProfileTag(TestProfile_1, 2));
SuccessOrExit(err);
FUZZ_CHECK_VAL(bool, true);
err = reader.Next(kTLVType_Boolean, ProfileTag(TestProfile_2, 2));
SuccessOrExit(err);
FUZZ_CHECK_VAL(bool, false);
err = reader.Next(kTLVType_Array, ContextTag(0));
SuccessOrExit(err);
{
TLVType outerContainer2Type;
err = reader.EnterContainer(outerContainer2Type);
SuccessOrExit(err);
err = reader.Next(kTLVType_SignedInteger, AnonymousTag);
SuccessOrExit(err);
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);
err = reader.Next(kTLVType_SignedInteger, AnonymousTag);
SuccessOrExit(err);
FUZZ_CHECK_VAL(int8_t, -17);
FUZZ_CHECK_VAL(int16_t, -17);
FUZZ_CHECK_VAL(int32_t, -17);
FUZZ_CHECK_VAL(int64_t, -17);
err = reader.Next(kTLVType_SignedInteger, AnonymousTag);
SuccessOrExit(err);
FUZZ_CHECK_VAL(int32_t, -170000);
FUZZ_CHECK_VAL(int64_t, -170000);
err = reader.Next(kTLVType_UnsignedInteger, AnonymousTag);
SuccessOrExit(err);
FUZZ_CHECK_VAL(int64_t, 40000000000ULL);
FUZZ_CHECK_VAL(uint64_t, 40000000000ULL);
err = reader.Next(kTLVType_Structure, AnonymousTag);
SuccessOrExit(err);
{
TLVType outerContainer3Type;
err = reader.EnterContainer(outerContainer3Type);
SuccessOrExit(err);
err = reader.ExitContainer(outerContainer3Type);
SuccessOrExit(err);
}
err = reader.Next(kTLVType_Path, AnonymousTag);
SuccessOrExit(err);
{
TLVType outerContainer3Type;
err = reader.EnterContainer(outerContainer3Type);
SuccessOrExit(err);
err = reader.Next(kTLVType_Null, ProfileTag(TestProfile_1, 17));
SuccessOrExit(err);
err = reader.Next(kTLVType_Null, ProfileTag(TestProfile_2, 900000));
SuccessOrExit(err);
err = reader.Next(kTLVType_Structure, ProfileTag(TestProfile_2, 4000000000ULL));
SuccessOrExit(err);
{
TLVType outerContainer4Type;
err = reader.EnterContainer(outerContainer4Type);
SuccessOrExit(err);
err = reader.Next(kTLVType_UTF8String, CommonTag(70000));
SuccessOrExit(err);
FUZZ_CHECK_STRING(sLargeString);
err = reader.ExitContainer(outerContainer4Type);
SuccessOrExit(err);
}
err = reader.ExitContainer(outerContainer3Type);
SuccessOrExit(err);
}
err = reader.ExitContainer(outerContainer2Type);
SuccessOrExit(err);
}
err = reader.Next(kTLVType_UTF8String, ProfileTag(TestProfile_1, 5));
SuccessOrExit(err);
FUZZ_CHECK_STRING("This is a test");
err = reader.Next(kTLVType_FloatingPointNumber, ProfileTag(TestProfile_2, 65535));
SuccessOrExit(err);
FUZZ_CHECK_VAL(double, (float)17.9);
err = reader.Next(kTLVType_FloatingPointNumber, ProfileTag(TestProfile_2, 65536));
SuccessOrExit(err);
FUZZ_CHECK_VAL(double, (double)17.9);
err = reader.ExitContainer(outerContainer1Type);
SuccessOrExit(err);
}
err = reader.Next();
if (err == WEAVE_END_OF_TLV)
err = WEAVE_NO_ERROR;
exit:
return err;
}
static uint32_t gFuzzTestDurationSecs = 5;
static uint8_t gFixedFuzzMask = 0;
static void TLVReaderFuzzTest(nlTestSuite *inSuite, void *inContext)
{
time_t now, endTime;
uint8_t fuzzedData[sizeof(Encoding1)];
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
};
memcpy(fuzzedData, Encoding1, sizeof(fuzzedData));
time(&now);
endTime = now + gFuzzTestDurationSecs + 1;
srand(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 = gFixedFuzzMask;
while (fuzzMask == 0)
fuzzMask = GetRandU8();
fuzzedData[i] ^= fuzzMask;
}
TLVReader reader;
reader.Init(fuzzedData, sizeof(fuzzedData));
reader.ImplicitProfileId = TestProfile_2;
WEAVE_ERROR readRes = ReadFuzzedEncoding1(inSuite, reader);
NL_TEST_ASSERT(inSuite, readRes != WEAVE_NO_ERROR);
if (readRes == WEAVE_NO_ERROR)
{
printf("Unexpected success of fuzz test: offset %u, original value 0x%02X, mutated value 0x%02X\n",
(unsigned)i, (unsigned)origVal, (unsigned)fuzzedData[i]);
ExitNow();
}
time(&now);
if (now >= endTime)
ExitNow();
fuzzedData[i] = origVal;
}
if (m < sizeof(sFixedFuzzVals))
m++;
}
exit:
return;
}
// Test Suite
/**
* Test Suite that lists all the test functions.
*/
static const nlTest sTests[] = {
NL_TEST_DEF("Simple Write Read Test", CheckSimpleWriteRead),
NL_TEST_DEF("Inet Buffer Test", CheckPacketBuffer),
NL_TEST_DEF("Buffer Overflow Test", CheckBufferOverflow),
NL_TEST_DEF("Pretty Print Test", CheckPrettyPrinter),
NL_TEST_DEF("Data Macro Test", CheckDataMacro),
NL_TEST_DEF("SAPPHIRE-10921 Test", CheckSapphire10921),
NL_TEST_DEF("Weave TLV Basics", CheckWeaveTLVBasics),
NL_TEST_DEF("Weave TLV Writer", CheckWeaveTLVWriter),
NL_TEST_DEF("Weave TLV Reader", CheckWeaveTLVReader),
NL_TEST_DEF("Weave TLV Utilities", CheckWeaveTLVUtilities),
NL_TEST_DEF("Weave TLV Updater", CheckWeaveUpdater),
NL_TEST_DEF("Weave TLV Empty Find", CheckWeaveTLVEmptyFind),
NL_TEST_DEF("Weave Circular TLV buffer, simple", CheckCircularTLVBufferSimple),
NL_TEST_DEF("Weave Circular TLV buffer, straddle", CheckCircularTLVBufferEvictStraddlingEvent),
NL_TEST_DEF("Weave Circular TLV buffer, edge", CheckCircularTLVBufferEdge),
NL_TEST_DEF("Weave TLV Printf", CheckWeaveTLVPutStringF),
NL_TEST_DEF("Weave TLV Printf, Circular TLV buf", CheckWeaveTLVPutStringFCircular),
NL_TEST_DEF("Weave TLV Skip non-contiguous", CheckWeaveTLVSkipCircular),
NL_TEST_DEF("Weave TLV Check reserve", CheckCloseContainerReserve),
NL_TEST_DEF("Weave TLV Reader Fuzz Test", TLVReaderFuzzTest),
NL_TEST_SENTINEL()
};
/**
* Set up the test suite.
*/
static int TestSetup(void *inContext)
{
return (SUCCESS);
}
/**
* Tear down the test suite.
*/
static int TestTeardown(void *inContext)
{
return (SUCCESS);
}
static OptionDef gToolOptionDefs[] =
{
{ "fuzz-duration", kArgumentRequired, 'f' },
{ "fuzz-mask", kArgumentRequired, 'm' },
{ NULL }
};
static const char *const gToolOptionHelp =
" -f, --fuzz-duration <seconds>\n"
" Fuzzing duration in seconds.\n"
"\n"
" -m, --fuzz-mask <int>\n"
" Use the specified fuzzing mask, rather than the built-in set of fuzzing values.\n"
"\n"
;
static OptionSet gToolOptions =
{
HandleOption,
gToolOptionDefs,
"GENERAL OPTIONS",
gToolOptionHelp
};
static HelpOptions gHelpOptions(
TOOL_NAME,
"Usage: " TOOL_NAME " [<options...>]\n",
WEAVE_VERSION_STRING "\n" WEAVE_TOOL_COPYRIGHT,
"Unit tests for Weave TLV encoder/decoder.\n"
);
static OptionSet *gToolOptionSets[] =
{
&gToolOptions,
&gHelpOptions,
NULL
};
static bool HandleOption(const char *progName, OptionSet *optSet, int id, const char *name, const char *arg)
{
switch (id)
{
case 'f':
if (!ParseInt(arg, gFuzzTestDurationSecs))
{
PrintArgError("%s: Invalid value specified for fuzz duration: %s\n", progName, arg);
return false;
}
break;
case 'm':
if (!ParseInt(arg, gFixedFuzzMask))
{
PrintArgError("%s: Invalid value specified for fixed fuzz mask: %s\n", arg);
return false;
}
break;
default:
PrintArgError("%s: INTERNAL ERROR: Unhandled option: %s\n", progName, name);
return false;
}
return true;
}
/**
* Main
*/
int main(int argc, char *argv[])
{
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
lwip_init();
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
nlTestSuite theSuite = {
"weave-tlv",
&sTests[0],
TestSetup,
TestTeardown
};
TestTLVContext context;
if (!ParseArgs(TOOL_NAME, argc, argv, gToolOptionSets))
{
exit(EXIT_FAILURE);
}
context.mSuite = &theSuite;
// Generate machine-readable, comma-separated value (CSV) output.
nl_test_set_output_style(OUTPUT_CSV);
// Run test suit against one context
nlTestRunner(&theSuite, &context);
return nlTestRunnerStats(&theSuite);
}