| /* |
| * Copyright (c) 2022, 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 <string.h> |
| |
| #include <openthread/config.h> |
| |
| #include "test_util.hpp" |
| |
| #include "common/heap_array.hpp" |
| #include "common/type_traits.hpp" |
| |
| namespace ot { |
| |
| // Counters tracking number of times `Entry` constructor and |
| // destructor are invoked. These are used to verify that the `Array` |
| // properly calls constructor/destructor when allocating and copying |
| // array buffer. |
| static uint16_t sConstructorCalls = 0; |
| static uint16_t sDestructorCalls = 0; |
| |
| class Entry |
| { |
| public: |
| Entry(void) |
| : mValue(0) |
| , mInitialized(true) |
| { |
| sConstructorCalls++; |
| } |
| |
| explicit Entry(uint16_t aValue) |
| : mValue(aValue) |
| , mInitialized(true) |
| { |
| sConstructorCalls++; |
| } |
| |
| Entry(const Entry &aEntry) |
| : mValue(aEntry.mValue) |
| , mInitialized(true) |
| { |
| sConstructorCalls++; |
| } |
| |
| ~Entry(void) { sDestructorCalls++; } |
| |
| uint16_t GetValue(void) const { return mValue; } |
| void SetValue(uint16_t aValue) { mValue = aValue; } |
| bool IsInitialized(void) const { return mInitialized; } |
| bool operator==(const Entry &aOther) const { return mValue == aOther.mValue; } |
| bool Matches(uint16_t aValue) const { return mValue == aValue; } |
| |
| private: |
| uint16_t mValue; |
| bool mInitialized; |
| }; |
| |
| template <typename EntryType> |
| void VerifyEntry(const EntryType &aEntry, const Heap::Array<EntryType, 2> &aArray, int aExpectedValue) |
| { |
| // Verify the entry in a given array with an expected value. |
| // Specializations of this template are defined below for `EntryType` |
| // being `uint16_t` or `Entry` class. |
| |
| OT_UNUSED_VARIABLE(aEntry); |
| OT_UNUSED_VARIABLE(aArray); |
| OT_UNUSED_VARIABLE(aExpectedValue); |
| |
| VerifyOrQuit(false, "Specializations of this template method MUST be used instead"); |
| } |
| |
| template <> void VerifyEntry(const uint16_t &aEntry, const Heap::Array<uint16_t, 2> &aArray, int aExpectedValue) |
| { |
| OT_UNUSED_VARIABLE(aArray); |
| VerifyOrQuit(aEntry == static_cast<uint16_t>(aExpectedValue)); |
| } |
| |
| template <> void VerifyEntry(const Entry &aEntry, const Heap::Array<Entry, 2> &aArray, int aExpectedValue) |
| { |
| VerifyOrQuit(aEntry.IsInitialized()); |
| VerifyOrQuit(aEntry.GetValue() == static_cast<uint16_t>(aExpectedValue)); |
| |
| VerifyOrQuit(aArray.ContainsMatching(aEntry.GetValue())); |
| VerifyOrQuit(aArray.FindMatching(aEntry.GetValue()) == &aEntry); |
| } |
| |
| template <typename EntryType, typename... Args> void VerifyArray(const Heap::Array<EntryType, 2> &aArray, Args... aArgs) |
| { |
| // Verify that array content matches the `aArgs` sequence |
| // (which can be empty). |
| |
| constexpr uint16_t kUnusedValue = 0xffff; |
| |
| int values[] = {aArgs..., 0}; |
| uint16_t index = 0; |
| |
| printf(" - Array (len:%u, capacity:%u) = { ", aArray.GetLength(), aArray.GetCapacity()); |
| |
| VerifyOrQuit(aArray.GetLength() == sizeof...(aArgs)); |
| |
| if (aArray.GetLength() == 0) |
| { |
| VerifyOrQuit(aArray.AsCArray() == nullptr); |
| VerifyOrQuit(aArray.Front() == nullptr); |
| VerifyOrQuit(aArray.Back() == nullptr); |
| } |
| else |
| { |
| VerifyOrQuit(aArray.AsCArray() != nullptr); |
| } |
| |
| for (const EntryType &entry : aArray) |
| { |
| VerifyOrQuit(index < aArray.GetLength()); |
| |
| VerifyEntry(entry, aArray, values[index]); |
| |
| VerifyOrQuit(aArray.Contains(entry)); |
| VerifyOrQuit(aArray.Find(entry) == &entry); |
| VerifyOrQuit(aArray.IndexOf(entry) == index); |
| |
| if (index == 0) |
| { |
| VerifyOrQuit(aArray.Front() == &entry); |
| } |
| |
| if (index == aArray.GetLength()) |
| { |
| VerifyOrQuit(aArray.Back() == &entry); |
| } |
| |
| printf("%u ", values[index]); |
| |
| index++; |
| } |
| |
| VerifyOrQuit(index == aArray.GetLength()); |
| |
| VerifyOrQuit(!aArray.Contains(EntryType(kUnusedValue))); |
| VerifyOrQuit(aArray.Find(EntryType(kUnusedValue)) == nullptr); |
| |
| if (TypeTraits::IsSame<EntryType, Entry>::kValue) |
| { |
| printf("} (constructor-calls:%u, destructor-calls:%u)\n", sConstructorCalls, sDestructorCalls); |
| VerifyOrQuit(sConstructorCalls - sDestructorCalls == aArray.GetLength()); |
| } |
| else |
| { |
| printf("}\n"); |
| } |
| } |
| |
| void TestHeapArrayOfUint16(void) |
| { |
| Heap::Array<uint16_t, 2> array; |
| Heap::Array<uint16_t, 2> array2; |
| uint16_t *entry; |
| |
| printf("\n\n====================================================================================\n"); |
| printf("TestHeapArrayOfUint16\n\n"); |
| |
| printf("------------------------------------------------------------------------------------\n"); |
| printf("After constructor\n"); |
| VerifyOrQuit(array.GetCapacity() == 0); |
| VerifyArray(array); |
| |
| printf("------------------------------------------------------------------------------------\n"); |
| printf("PushBack(aEntry)\n"); |
| |
| SuccessOrQuit(array.PushBack(1)); |
| VerifyArray(array, 1); |
| VerifyOrQuit(array.GetCapacity() == 2); |
| |
| SuccessOrQuit(array.PushBack(2)); |
| VerifyArray(array, 1, 2); |
| VerifyOrQuit(array.GetCapacity() == 2); |
| |
| SuccessOrQuit(array.PushBack(3)); |
| VerifyArray(array, 1, 2, 3); |
| VerifyOrQuit(array.GetCapacity() == 4); |
| |
| printf("------------------------------------------------------------------------------------\n"); |
| printf("entry = PushBack()\n"); |
| |
| entry = array.PushBack(); |
| VerifyOrQuit(entry != nullptr); |
| *entry = 4; |
| VerifyArray(array, 1, 2, 3, 4); |
| VerifyOrQuit(array.GetCapacity() == 4); |
| |
| entry = array.PushBack(); |
| VerifyOrQuit(entry != nullptr); |
| *entry = 5; |
| VerifyArray(array, 1, 2, 3, 4, 5); |
| VerifyOrQuit(array.GetCapacity() == 6); |
| |
| printf("------------------------------------------------------------------------------------\n"); |
| printf("Clear()\n"); |
| |
| array.Clear(); |
| VerifyArray(array); |
| VerifyOrQuit(array.GetCapacity() == 6); |
| |
| *array.PushBack() = 11; |
| SuccessOrQuit(array.PushBack(22)); |
| SuccessOrQuit(array.PushBack(33)); |
| SuccessOrQuit(array.PushBack(44)); |
| *array.PushBack() = 55; |
| |
| VerifyArray(array, 11, 22, 33, 44, 55); |
| VerifyOrQuit(array.GetCapacity() == 6); |
| |
| SuccessOrQuit(array.PushBack(66)); |
| SuccessOrQuit(array.PushBack(77)); |
| VerifyArray(array, 11, 22, 33, 44, 55, 66, 77); |
| VerifyOrQuit(array.GetCapacity() == 8); |
| |
| printf("------------------------------------------------------------------------------------\n"); |
| printf("PopBack()\n"); |
| |
| array.PopBack(); |
| VerifyArray(array, 11, 22, 33, 44, 55, 66); |
| VerifyOrQuit(array.GetCapacity() == 8); |
| |
| array.PopBack(); |
| array.PopBack(); |
| array.PopBack(); |
| array.PopBack(); |
| array.PopBack(); |
| VerifyArray(array, 11); |
| VerifyOrQuit(array.GetCapacity() == 8); |
| |
| array.PopBack(); |
| VerifyArray(array); |
| VerifyOrQuit(array.GetCapacity() == 8); |
| |
| array.PopBack(); |
| VerifyArray(array); |
| VerifyOrQuit(array.GetCapacity() == 8); |
| |
| for (uint16_t num = 0; num < 11; num++) |
| { |
| SuccessOrQuit(array.PushBack(num + 0x100)); |
| } |
| |
| VerifyArray(array, 0x100, 0x101, 0x102, 0x103, 0x104, 0x105, 0x106, 0x107, 0x108, 0x109, 0x10a); |
| VerifyOrQuit(array.GetCapacity() == 12); |
| |
| printf("------------------------------------------------------------------------------------\n"); |
| printf("Free()\n"); |
| |
| array.Free(); |
| VerifyArray(array); |
| VerifyOrQuit(array.GetCapacity() == 0); |
| |
| array.Free(); |
| VerifyArray(array); |
| VerifyOrQuit(array.GetCapacity() == 0); |
| |
| printf("------------------------------------------------------------------------------------\n"); |
| printf("ReserveCapacity()\n"); |
| |
| SuccessOrQuit(array.ReserveCapacity(5)); |
| VerifyArray(array); |
| VerifyOrQuit(array.GetCapacity() == 5); |
| |
| SuccessOrQuit(array.PushBack(0)); |
| VerifyArray(array, 0); |
| VerifyOrQuit(array.GetCapacity() == 5); |
| |
| for (uint16_t num = 1; num < 5; num++) |
| { |
| SuccessOrQuit(array.PushBack(num)); |
| } |
| |
| VerifyArray(array, 0, 1, 2, 3, 4); |
| VerifyOrQuit(array.GetCapacity() == 5); |
| |
| SuccessOrQuit(array.PushBack(5)); |
| VerifyArray(array, 0, 1, 2, 3, 4, 5); |
| VerifyOrQuit(array.GetCapacity() == 7); |
| |
| SuccessOrQuit(array.ReserveCapacity(3)); |
| VerifyArray(array, 0, 1, 2, 3, 4, 5); |
| VerifyOrQuit(array.GetCapacity() == 7); |
| |
| SuccessOrQuit(array.ReserveCapacity(10)); |
| VerifyArray(array, 0, 1, 2, 3, 4, 5); |
| VerifyOrQuit(array.GetCapacity() == 10); |
| |
| printf("------------------------------------------------------------------------------------\n"); |
| printf("TakeFrom()\n"); |
| |
| for (uint16_t num = 0; num < 7; num++) |
| { |
| SuccessOrQuit(array2.PushBack(num + 0x20)); |
| } |
| |
| VerifyArray(array2, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26); |
| |
| array2.TakeFrom(static_cast<Heap::Array<uint16_t, 2> &&>(array)); |
| |
| VerifyArray(array); |
| VerifyOrQuit(array.GetCapacity() == 0); |
| |
| VerifyArray(array2, 0, 1, 2, 3, 4, 5); |
| VerifyOrQuit(array2.GetCapacity() == 10); |
| |
| printf("\n -- PASS\n"); |
| } |
| |
| void TestHeapArray(void) |
| { |
| VerifyOrQuit(sConstructorCalls == 0); |
| VerifyOrQuit(sDestructorCalls == 0); |
| |
| printf("\n\n====================================================================================\n"); |
| printf("TestHeapArray\n\n"); |
| |
| { |
| Heap::Array<Entry, 2> array; |
| Heap::Array<Entry, 2> array2; |
| Entry *entry; |
| |
| printf("------------------------------------------------------------------------------------\n"); |
| printf("After constructor\n"); |
| VerifyOrQuit(array.GetCapacity() == 0); |
| VerifyArray(array); |
| |
| printf("------------------------------------------------------------------------------------\n"); |
| printf("PushBack(aEntry)\n"); |
| |
| SuccessOrQuit(array.PushBack(Entry(1))); |
| VerifyArray(array, 1); |
| VerifyOrQuit(array.GetCapacity() == 2); |
| |
| SuccessOrQuit(array.PushBack(Entry(2))); |
| VerifyArray(array, 1, 2); |
| VerifyOrQuit(array.GetCapacity() == 2); |
| |
| SuccessOrQuit(array.PushBack(Entry(3))); |
| VerifyArray(array, 1, 2, 3); |
| VerifyOrQuit(array.GetCapacity() == 4); |
| |
| entry = array.PushBack(); |
| VerifyOrQuit(entry != nullptr); |
| VerifyOrQuit(entry->IsInitialized()); |
| VerifyOrQuit(entry->GetValue() == 0); |
| entry->SetValue(4); |
| VerifyArray(array, 1, 2, 3, 4); |
| VerifyOrQuit(array.GetCapacity() == 4); |
| |
| entry = array.PushBack(); |
| VerifyOrQuit(entry != nullptr); |
| VerifyOrQuit(entry->IsInitialized()); |
| VerifyOrQuit(entry->GetValue() == 0); |
| entry->SetValue(5); |
| VerifyArray(array, 1, 2, 3, 4, 5); |
| VerifyOrQuit(array.GetCapacity() == 6); |
| |
| printf("------------------------------------------------------------------------------------\n"); |
| printf("PopBack()\n"); |
| |
| array.PopBack(); |
| VerifyArray(array, 1, 2, 3, 4); |
| VerifyOrQuit(array.GetCapacity() == 6); |
| |
| array.PopBack(); |
| VerifyArray(array, 1, 2, 3); |
| VerifyOrQuit(array.GetCapacity() == 6); |
| |
| SuccessOrQuit(array.PushBack(Entry(7))); |
| VerifyArray(array, 1, 2, 3, 7); |
| VerifyOrQuit(array.GetCapacity() == 6); |
| |
| array.PopBack(); |
| VerifyArray(array, 1, 2, 3); |
| VerifyOrQuit(array.GetCapacity() == 6); |
| |
| printf("------------------------------------------------------------------------------------\n"); |
| printf("Clear()\n"); |
| |
| array.Clear(); |
| VerifyArray(array); |
| VerifyOrQuit(array.GetCapacity() == 6); |
| |
| for (uint16_t num = 0; num < 11; num++) |
| { |
| SuccessOrQuit(array.PushBack(Entry(num))); |
| } |
| |
| VerifyArray(array, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10); |
| VerifyOrQuit(array.GetCapacity() == 12); |
| |
| printf("------------------------------------------------------------------------------------\n"); |
| printf("Free()\n"); |
| array.Free(); |
| VerifyArray(array); |
| VerifyOrQuit(array.GetCapacity() == 0); |
| |
| printf("------------------------------------------------------------------------------------\n"); |
| printf("ReserveCapacity()\n"); |
| |
| SuccessOrQuit(array.ReserveCapacity(5)); |
| VerifyArray(array); |
| VerifyOrQuit(array.GetCapacity() == 5); |
| |
| SuccessOrQuit(array.PushBack(Entry(0))); |
| VerifyArray(array, 0); |
| VerifyOrQuit(array.GetCapacity() == 5); |
| |
| for (uint16_t num = 1; num < 5; num++) |
| { |
| SuccessOrQuit(array.PushBack(Entry(num))); |
| } |
| |
| VerifyArray(array, 0, 1, 2, 3, 4); |
| VerifyOrQuit(array.GetCapacity() == 5); |
| |
| SuccessOrQuit(array.PushBack(Entry(5))); |
| VerifyArray(array, 0, 1, 2, 3, 4, 5); |
| VerifyOrQuit(array.GetCapacity() == 7); |
| |
| SuccessOrQuit(array.ReserveCapacity(3)); |
| VerifyArray(array, 0, 1, 2, 3, 4, 5); |
| VerifyOrQuit(array.GetCapacity() == 7); |
| |
| SuccessOrQuit(array.ReserveCapacity(10)); |
| VerifyArray(array, 0, 1, 2, 3, 4, 5); |
| VerifyOrQuit(array.GetCapacity() == 10); |
| |
| printf("------------------------------------------------------------------------------------\n"); |
| printf("TakeFrom()\n"); |
| |
| for (uint16_t num = 0; num < 7; num++) |
| { |
| SuccessOrQuit(array2.PushBack(Entry(num + 0x20))); |
| } |
| |
| array2.TakeFrom(static_cast<Heap::Array<Entry, 2> &&>(array)); |
| |
| VerifyOrQuit(array.GetLength() == 0); |
| VerifyOrQuit(array.GetCapacity() == 0); |
| |
| VerifyArray(array2, 0, 1, 2, 3, 4, 5); |
| VerifyOrQuit(array2.GetCapacity() == 10); |
| } |
| |
| printf("------------------------------------------------------------------------------------\n"); |
| printf("Array destructor\n"); |
| printf(" - (constructor-calls:%u, destructor-calls:%u)\n", sConstructorCalls, sDestructorCalls); |
| VerifyOrQuit(sConstructorCalls == sDestructorCalls, |
| "Array destructor failed to invoke destructor on all its existing entries"); |
| |
| printf("\n -- PASS\n"); |
| } |
| |
| } // namespace ot |
| |
| int main(void) |
| { |
| ot::TestHeapArrayOfUint16(); |
| ot::TestHeapArray(); |
| printf("\nAll tests passed.\n"); |
| return 0; |
| } |