/* * Copyright (c) 2021, The OpenThread Authors. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holder nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "test_platform.h" #include #include #include "test_util.hpp" #include "common/code_utils.hpp" #include "common/heap_data.hpp" #include "common/heap_string.hpp" namespace ot { void PrintString(const char *aName, const Heap::String &aString) { if (aString.IsNull()) { printf("%s = (null)\n", aName); } else { printf("%s = [%zu] \"%s\"\n", aName, strlen(aString.AsCString()), aString.AsCString()); } } void VerifyString(const char *aName, const Heap::String &aString, const char *aExpectedString) { PrintString(aName, aString); if (aExpectedString == nullptr) { VerifyOrQuit(aString.IsNull()); VerifyOrQuit(aString.AsCString() == nullptr); VerifyOrQuit(aString != "something"); } else { VerifyOrQuit(!aString.IsNull()); VerifyOrQuit(aString.AsCString() != nullptr); VerifyOrQuit(strcmp(aString.AsCString(), aExpectedString) == 0, "String content is incorrect"); VerifyOrQuit(aString != nullptr); } VerifyOrQuit(aString == aExpectedString); } // Function returning a `Heap::String` by value. Heap::String GetName(void) { Heap::String name; SuccessOrQuit(name.Set("name")); return name; } void TestHeapString(void) { Heap::String str1; Heap::String str2; const char *oldBuffer; printf("====================================================================================\n"); printf("TestHeapString\n\n"); printf("------------------------------------------------------------------------------------\n"); printf("After constructor\n\n"); VerifyString("str1", str1, nullptr); printf("------------------------------------------------------------------------------------\n"); printf("Set(const char *aCstring)\n\n"); SuccessOrQuit(str1.Set("hello")); VerifyString("str1", str1, "hello"); oldBuffer = str1.AsCString(); SuccessOrQuit(str1.Set("0123456789")); VerifyString("str1", str1, "0123456789"); printf("\tDid reuse its old buffer: %s\n", str1.AsCString() == oldBuffer ? "yes" : "no"); oldBuffer = str1.AsCString(); SuccessOrQuit(str1.Set("9876543210")); VerifyString("str1", str1, "9876543210"); printf("\tDid reuse its old buffer (same length): %s\n", str1.AsCString() == oldBuffer ? "yes" : "no"); printf("------------------------------------------------------------------------------------\n"); printf("Set(const Heap::String &)\n\n"); SuccessOrQuit(str2.Set(str1)); VerifyString("str2", str2, str1.AsCString()); SuccessOrQuit(str1.Set(nullptr)); VerifyString("str1", str1, nullptr); SuccessOrQuit(str2.Set(str1)); VerifyString("str2", str2, nullptr); printf("------------------------------------------------------------------------------------\n"); printf("Free()\n\n"); str1.Free(); VerifyString("str1", str1, nullptr); SuccessOrQuit(str1.Set("hello again")); VerifyString("str1", str1, "hello again"); str1.Free(); VerifyString("str1", str1, nullptr); printf("------------------------------------------------------------------------------------\n"); printf("Set() move semantics\n\n"); SuccessOrQuit(str1.Set("old name")); PrintString("str1", str1); SuccessOrQuit(str1.Set(GetName()), "Set() with move semantics failed"); VerifyString("str1", str1, "name"); printf("------------------------------------------------------------------------------------\n"); printf("operator==() with two null string\n\n"); str1.Free(); str2.Free(); VerifyString("str1", str1, nullptr); VerifyString("str2", str2, nullptr); VerifyOrQuit(str1 == str2, "operator==() failed with two null strings"); printf("\n -- PASS\n"); } void PrintData(const Heap::Data &aData) { DumpBuffer("data", aData.GetBytes(), aData.GetLength()); } static const uint8_t kTestValue = 0x77; // Function returning a `Heap::Data` by value. Heap::Data GetData(void) { Heap::Data data; SuccessOrQuit(data.SetFrom(&kTestValue, sizeof(kTestValue))); return data; } void VerifyData(const Heap::Data &aData, const uint8_t *aBytes, uint16_t aLength) { static constexpr uint16_t kMaxLength = 100; uint8_t buffer[kMaxLength]; PrintData(aData); VerifyOrQuit(aData.Matches(aBytes, aLength)); VerifyOrQuit(!aData.Matches(aBytes, aLength + 1)); if (aLength == 0) { VerifyOrQuit(aData.IsNull()); VerifyOrQuit(aData.GetBytes() == nullptr); VerifyOrQuit(aData.GetLength() == 0); VerifyOrQuit(aData.Matches(nullptr, 0)); } else { VerifyOrQuit(!aData.IsNull()); VerifyOrQuit(aData.GetBytes() != nullptr); VerifyOrQuit(aData.GetLength() == aLength); VerifyOrQuit(memcmp(aData.GetBytes(), aBytes, aLength) == 0, "Data content is incorrect"); aData.CopyBytesTo(buffer); VerifyOrQuit(memcmp(buffer, aBytes, aLength) == 0, "CopyBytesTo() failed"); VerifyOrQuit(aData.Matches(buffer, aLength)); buffer[aLength - 1]++; VerifyOrQuit(!aData.Matches(buffer, aLength)); } } template void VerifyData(const Heap::Data &aData, const uint8_t (&aArray)[kLength]) { VerifyData(aData, &aArray[0], kLength); } void TestHeapData(void) { Instance *instance; MessagePool *messagePool; Message *message; Heap::Data data; uint16_t offset; const uint8_t *oldBuffer; static const uint8_t kData1[] = {10, 20, 3, 15, 100, 0, 60, 16}; static const uint8_t kData2[] = "OpenThread HeapData"; static const uint8_t kData3[] = {0xaa, 0xbb, 0xcc}; static const uint8_t kData4[] = {0x11, 0x22, 0x33}; instance = static_cast(testInitInstance()); VerifyOrQuit(instance != nullptr, "Null OpenThread instance"); messagePool = &instance->Get(); VerifyOrQuit((message = messagePool->Allocate(Message::kTypeIp6)) != nullptr); message->SetOffset(0); printf("\n\n====================================================================================\n"); printf("TestHeapData\n\n"); printf("------------------------------------------------------------------------------------\n"); printf("After constructor\n"); VerifyData(data, nullptr, 0); VerifyOrQuit(data.Matches(nullptr, 0)); VerifyOrQuit(data.Matches(kData1, 0)); VerifyOrQuit(!data.Matches(kData1, 1)); printf("------------------------------------------------------------------------------------\n"); printf("SetFrom(aBuffer, aLength)\n"); SuccessOrQuit(data.SetFrom(kData1, sizeof(kData1))); VerifyData(data, kData1); SuccessOrQuit(data.SetFrom(kData2, sizeof(kData2))); VerifyData(data, kData2); SuccessOrQuit(data.SetFrom(kData3, sizeof(kData3))); VerifyData(data, kData3); oldBuffer = data.GetBytes(); SuccessOrQuit(data.SetFrom(kData4, sizeof(kData4))); VerifyData(data, kData4); VerifyOrQuit(oldBuffer == data.GetBytes(), "did not reuse old buffer on same data length"); SuccessOrQuit(data.SetFrom(kData4, 0)); VerifyData(data, nullptr, 0); printf("------------------------------------------------------------------------------------\n"); printf("SetFrom(aMessage)\n"); SuccessOrQuit(message->Append(kData2)); SuccessOrQuit(data.SetFrom(*message)); VerifyData(data, kData2); SuccessOrQuit(message->Append(kData3)); SuccessOrQuit(data.SetFrom(*message)); PrintData(data); VerifyOrQuit(data.GetLength() == message->GetLength()); message->SetOffset(sizeof(kData2)); SuccessOrQuit(data.SetFrom(*message)); VerifyData(data, kData3); SuccessOrQuit(message->Append(kData4)); offset = 0; SuccessOrQuit(data.SetFrom(*message, offset, sizeof(kData2))); VerifyData(data, kData2); offset = sizeof(kData2); SuccessOrQuit(data.SetFrom(*message, offset, sizeof(kData3))); VerifyData(data, kData3); offset += sizeof(kData3); SuccessOrQuit(data.SetFrom(*message, offset, sizeof(kData4))); VerifyData(data, kData4); VerifyOrQuit(data.SetFrom(*message, offset, sizeof(kData4) + 1) == kErrorParse); VerifyOrQuit(data.SetFrom(*message, 0, message->GetLength() + 1) == kErrorParse); VerifyOrQuit(data.SetFrom(*message, 1, message->GetLength()) == kErrorParse); printf("------------------------------------------------------------------------------------\n"); printf("Free()\n"); data.Free(); VerifyData(data, nullptr, 0); data.Free(); VerifyData(data, nullptr, 0); printf("------------------------------------------------------------------------------------\n"); printf("CopyBytesTo(aMessage)\n"); SuccessOrQuit(message->SetLength(0)); SuccessOrQuit(data.CopyBytesTo(*message)); VerifyOrQuit(message->GetLength() == 0, "CopyBytesTo() failed"); SuccessOrQuit(data.SetFrom(kData1, sizeof(kData1))); VerifyData(data, kData1); SuccessOrQuit(data.CopyBytesTo(*message)); VerifyOrQuit(message->GetLength() == data.GetLength(), "CopyBytesTo() failed"); VerifyOrQuit(message->Compare(0, kData1), "CopyBytesTo() failed"); printf("------------------------------------------------------------------------------------\n"); printf("SetFrom() move semantics\n\n"); data.SetFrom(GetData()); VerifyData(data, &kTestValue, sizeof(kTestValue)); printf("\n -- PASS\n"); } } // namespace ot int main(void) { ot::TestHeapString(); ot::TestHeapData(); printf("\nAll tests passed.\n"); return 0; }