| /* |
| * Copyright (c) 2016, 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 "common/appender.hpp" |
| #include "common/debug.hpp" |
| #include "common/instance.hpp" |
| #include "common/message.hpp" |
| #include "common/random.hpp" |
| |
| #include "test_platform.h" |
| #include "test_util.hpp" |
| |
| namespace ot { |
| |
| void TestMessage(void) |
| { |
| enum : uint16_t |
| { |
| kMaxSize = (kBufferSize * 3 + 24), |
| kOffsetStep = 101, |
| kLengthStep = 21, |
| }; |
| |
| Instance * instance; |
| MessagePool *messagePool; |
| Message * message; |
| Message * message2; |
| uint8_t writeBuffer[kMaxSize]; |
| uint8_t readBuffer[kMaxSize]; |
| uint8_t zeroBuffer[kMaxSize]; |
| |
| printf("TestMessage\n"); |
| |
| memset(zeroBuffer, 0, sizeof(zeroBuffer)); |
| |
| instance = static_cast<Instance *>(testInitInstance()); |
| VerifyOrQuit(instance != nullptr); |
| |
| messagePool = &instance->Get<MessagePool>(); |
| |
| Random::NonCrypto::FillBuffer(writeBuffer, kMaxSize); |
| |
| VerifyOrQuit((message = messagePool->Allocate(Message::kTypeIp6)) != nullptr); |
| SuccessOrQuit(message->SetLength(kMaxSize)); |
| message->WriteBytes(0, writeBuffer, kMaxSize); |
| SuccessOrQuit(message->Read(0, readBuffer, kMaxSize)); |
| VerifyOrQuit(memcmp(writeBuffer, readBuffer, kMaxSize) == 0); |
| VerifyOrQuit(message->CompareBytes(0, readBuffer, kMaxSize)); |
| VerifyOrQuit(message->Compare(0, readBuffer)); |
| VerifyOrQuit(message->GetLength() == kMaxSize); |
| |
| for (uint16_t offset = 0; offset < kMaxSize; offset++) |
| { |
| for (uint16_t length = 0; length <= kMaxSize - offset; length++) |
| { |
| for (uint16_t i = 0; i < length; i++) |
| { |
| writeBuffer[offset + i]++; |
| } |
| |
| message->WriteBytes(offset, &writeBuffer[offset], length); |
| |
| SuccessOrQuit(message->Read(0, readBuffer, kMaxSize)); |
| VerifyOrQuit(memcmp(writeBuffer, readBuffer, kMaxSize) == 0); |
| VerifyOrQuit(message->Compare(0, writeBuffer)); |
| |
| memset(readBuffer, 0, sizeof(readBuffer)); |
| SuccessOrQuit(message->Read(offset, readBuffer, length)); |
| VerifyOrQuit(memcmp(readBuffer, &writeBuffer[offset], length) == 0); |
| VerifyOrQuit(memcmp(&readBuffer[length], zeroBuffer, kMaxSize - length) == 0, "read after length"); |
| |
| VerifyOrQuit(message->CompareBytes(offset, &writeBuffer[offset], length)); |
| |
| if (length == 0) |
| { |
| continue; |
| } |
| |
| // Change the first byte, and then last byte, and verify that |
| // `CompareBytes()` correctly fails. |
| |
| writeBuffer[offset]++; |
| VerifyOrQuit(!message->CompareBytes(offset, &writeBuffer[offset], length)); |
| writeBuffer[offset]--; |
| |
| writeBuffer[offset + length - 1]++; |
| VerifyOrQuit(!message->CompareBytes(offset, &writeBuffer[offset], length)); |
| writeBuffer[offset + length - 1]--; |
| } |
| |
| // Verify `ReadBytes()` behavior when requested read length goes beyond available bytes in the message. |
| |
| for (uint16_t length = kMaxSize - offset + 1; length <= kMaxSize + 1; length++) |
| { |
| uint16_t readLength; |
| |
| memset(readBuffer, 0, sizeof(readBuffer)); |
| readLength = message->ReadBytes(offset, readBuffer, length); |
| |
| VerifyOrQuit(readLength < length, "Message::ReadBytes() returned longer length"); |
| VerifyOrQuit(readLength == kMaxSize - offset); |
| VerifyOrQuit(memcmp(readBuffer, &writeBuffer[offset], readLength) == 0); |
| VerifyOrQuit(memcmp(&readBuffer[readLength], zeroBuffer, kMaxSize - readLength) == 0, "read after length"); |
| |
| VerifyOrQuit(!message->CompareBytes(offset, readBuffer, length)); |
| VerifyOrQuit(message->CompareBytes(offset, readBuffer, readLength)); |
| } |
| } |
| |
| VerifyOrQuit(message->GetLength() == kMaxSize); |
| |
| // Test `Message::CopyTo()` behavior. |
| |
| VerifyOrQuit((message2 = messagePool->Allocate(Message::kTypeIp6)) != nullptr); |
| SuccessOrQuit(message2->SetLength(kMaxSize)); |
| |
| for (uint16_t srcOffset = 0; srcOffset < kMaxSize; srcOffset += kOffsetStep) |
| { |
| for (uint16_t dstOffset = 0; dstOffset < kMaxSize; dstOffset += kOffsetStep) |
| { |
| for (uint16_t length = 0; length <= kMaxSize - dstOffset; length += kLengthStep) |
| { |
| uint16_t bytesCopied; |
| |
| message2->WriteBytes(0, zeroBuffer, kMaxSize); |
| |
| bytesCopied = message->CopyTo(srcOffset, dstOffset, length, *message2); |
| |
| if (srcOffset + length <= kMaxSize) |
| { |
| VerifyOrQuit(bytesCopied == length, "CopyTo() failed"); |
| } |
| else |
| { |
| VerifyOrQuit(bytesCopied == kMaxSize - srcOffset, "CopyTo() failed"); |
| } |
| |
| SuccessOrQuit(message2->Read(0, readBuffer, kMaxSize)); |
| |
| VerifyOrQuit(memcmp(&readBuffer[0], zeroBuffer, dstOffset) == 0, "read before length"); |
| VerifyOrQuit(memcmp(&readBuffer[dstOffset], &writeBuffer[srcOffset], bytesCopied) == 0); |
| VerifyOrQuit( |
| memcmp(&readBuffer[dstOffset + bytesCopied], zeroBuffer, kMaxSize - bytesCopied - dstOffset) == 0, |
| "read after length"); |
| |
| VerifyOrQuit(message->CompareBytes(srcOffset, *message2, dstOffset, bytesCopied)); |
| VerifyOrQuit(message2->CompareBytes(dstOffset, *message, srcOffset, bytesCopied)); |
| } |
| } |
| } |
| |
| // Verify `CopyTo()` with same source and destination message and a backward copy. |
| |
| for (uint16_t srcOffset = 0; srcOffset < kMaxSize; srcOffset++) |
| { |
| uint16_t bytesCopied; |
| |
| message->WriteBytes(0, writeBuffer, kMaxSize); |
| |
| bytesCopied = message->CopyTo(srcOffset, 0, kMaxSize, *message); |
| VerifyOrQuit(bytesCopied == kMaxSize - srcOffset, "CopyTo() failed"); |
| |
| SuccessOrQuit(message->Read(0, readBuffer, kMaxSize)); |
| |
| VerifyOrQuit(memcmp(&readBuffer[0], &writeBuffer[srcOffset], bytesCopied) == 0, |
| "CopyTo() changed before srcOffset"); |
| VerifyOrQuit(memcmp(&readBuffer[bytesCopied], &writeBuffer[bytesCopied], kMaxSize - bytesCopied) == 0, |
| "CopyTo() write error"); |
| } |
| |
| // Verify `AppendBytesFromMessage()` with two different messages as source and destination. |
| |
| message->WriteBytes(0, writeBuffer, kMaxSize); |
| |
| for (uint16_t srcOffset = 0; srcOffset < kMaxSize; srcOffset += kOffsetStep) |
| { |
| for (uint16_t dstOffset = 0; dstOffset < kMaxSize; dstOffset += kOffsetStep) |
| { |
| for (uint16_t length = 0; length <= kMaxSize - srcOffset; length += kLengthStep) |
| { |
| IgnoreError(message2->SetLength(0)); |
| SuccessOrQuit(message2->AppendBytes(zeroBuffer, dstOffset)); |
| |
| SuccessOrQuit(message2->AppendBytesFromMessage(*message, srcOffset, length)); |
| |
| VerifyOrQuit(message2->CompareBytes(dstOffset, *message, srcOffset, length)); |
| } |
| |
| VerifyOrQuit(message2->AppendBytesFromMessage(*message, srcOffset, kMaxSize - srcOffset + 1) == |
| kErrorParse); |
| } |
| } |
| |
| // Verify `AppendBytesFromMessage()` with the same message as source and destination. |
| |
| for (uint16_t srcOffset = 0; srcOffset < kMaxSize; srcOffset += kOffsetStep) |
| { |
| uint16_t size = kMaxSize; |
| |
| for (uint16_t length = 0; length <= kMaxSize - srcOffset; length++) |
| { |
| // Reset the `message` to its original size. |
| IgnoreError(message->SetLength(size)); |
| |
| SuccessOrQuit(message->AppendBytesFromMessage(*message, srcOffset, length)); |
| |
| VerifyOrQuit(message->CompareBytes(size, *message, srcOffset, length)); |
| } |
| } |
| |
| message->Free(); |
| message2->Free(); |
| |
| testFreeInstance(instance); |
| } |
| |
| void TestAppender(void) |
| { |
| const uint8_t kData1[] = {0x01, 0x02, 0x03, 0x04}; |
| const uint8_t kData2[] = {0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa}; |
| |
| static constexpr uint16_t kMaxBufferSize = sizeof(kData1) * 2 + sizeof(kData2); |
| |
| Instance * instance; |
| Message * message; |
| uint8_t buffer[kMaxBufferSize]; |
| uint8_t zeroBuffer[kMaxBufferSize]; |
| Appender bufAppender(buffer, sizeof(buffer)); |
| Data<kWithUint16Length> data; |
| |
| printf("TestAppender\n"); |
| |
| instance = static_cast<Instance *>(testInitInstance()); |
| VerifyOrQuit(instance != nullptr); |
| |
| message = instance->Get<MessagePool>().Allocate(Message::kTypeIp6); |
| VerifyOrQuit(message != nullptr); |
| |
| memset(buffer, 0, sizeof(buffer)); |
| memset(zeroBuffer, 0, sizeof(zeroBuffer)); |
| |
| // Test Buffer Appender |
| VerifyOrQuit(bufAppender.GetType() == Appender::kBuffer); |
| VerifyOrQuit(bufAppender.GetBufferStart() == buffer); |
| VerifyOrQuit(bufAppender.GetAppendedLength() == 0); |
| |
| SuccessOrQuit(bufAppender.AppendBytes(kData1, sizeof(kData1))); |
| DumpBuffer("Data1", buffer, sizeof(buffer)); |
| VerifyOrQuit(bufAppender.GetAppendedLength() == sizeof(kData1)); |
| VerifyOrQuit(bufAppender.GetBufferStart() == buffer); |
| VerifyOrQuit(memcmp(buffer, kData1, sizeof(kData1)) == 0); |
| VerifyOrQuit(memcmp(buffer + sizeof(kData1), zeroBuffer, sizeof(buffer) - sizeof(kData1)) == 0); |
| |
| SuccessOrQuit(bufAppender.AppendBytes(kData2, sizeof(kData2))); |
| DumpBuffer("Data1+Data2", buffer, sizeof(buffer)); |
| VerifyOrQuit(bufAppender.GetAppendedLength() == sizeof(kData1) + sizeof(kData2)); |
| VerifyOrQuit(bufAppender.GetBufferStart() == buffer); |
| VerifyOrQuit(memcmp(buffer, kData1, sizeof(kData1)) == 0); |
| VerifyOrQuit(memcmp(buffer + sizeof(kData1), kData2, sizeof(kData2)) == 0); |
| VerifyOrQuit(memcmp(buffer + sizeof(kData1) + sizeof(kData2), zeroBuffer, |
| sizeof(buffer) - sizeof(kData1) - sizeof(kData2)) == 0); |
| |
| VerifyOrQuit(bufAppender.Append(kData2) == kErrorNoBufs); |
| |
| SuccessOrQuit(bufAppender.AppendBytes(kData1, sizeof(kData1))); |
| DumpBuffer("Data1+Data2+Data1", buffer, sizeof(buffer)); |
| VerifyOrQuit(bufAppender.GetAppendedLength() == sizeof(kData1) + sizeof(kData2) + sizeof(kData1)); |
| VerifyOrQuit(bufAppender.GetBufferStart() == buffer); |
| VerifyOrQuit(memcmp(buffer, kData1, sizeof(kData1)) == 0); |
| VerifyOrQuit(memcmp(buffer + sizeof(kData1), kData2, sizeof(kData2)) == 0); |
| VerifyOrQuit(memcmp(buffer + sizeof(kData1) + sizeof(kData2), kData1, sizeof(kData1)) == 0); |
| |
| VerifyOrQuit(bufAppender.Append<uint8_t>(0) == kErrorNoBufs); |
| |
| bufAppender.GetAsData(data); |
| VerifyOrQuit(data.GetBytes() == buffer); |
| VerifyOrQuit(data.GetLength() == sizeof(buffer)); |
| |
| // Test Message Appender |
| |
| SuccessOrQuit(message->Append(kData2)); |
| VerifyOrQuit(message->Compare(0, kData2)); |
| |
| { |
| Appender msgAppender(*message); |
| uint16_t offset = message->GetLength(); |
| |
| VerifyOrQuit(msgAppender.GetType() == Appender::kMessage); |
| |
| SuccessOrQuit(msgAppender.AppendBytes(kData1, sizeof(kData1))); |
| VerifyOrQuit(msgAppender.GetAppendedLength() == sizeof(kData1)); |
| |
| VerifyOrQuit(message->GetLength() == sizeof(kData2) + sizeof(kData1)); |
| VerifyOrQuit(message->Compare(offset, kData1)); |
| |
| SuccessOrQuit(msgAppender.AppendBytes(kData2, sizeof(kData2))); |
| VerifyOrQuit(msgAppender.GetAppendedLength() == sizeof(kData1) + sizeof(kData2)); |
| VerifyOrQuit(message->Compare(offset, kData1)); |
| VerifyOrQuit(message->Compare(offset + sizeof(kData1), kData2)); |
| } |
| |
| message->Free(); |
| testFreeInstance(instance); |
| } |
| |
| } // namespace ot |
| |
| int main(void) |
| { |
| ot::TestMessage(); |
| ot::TestAppender(); |
| printf("All tests passed\n"); |
| return 0; |
| } |