blob: 578183685d8575aeb1ee3fad714c850fa1882e69 [file] [log] [blame]
/*
*
* Copyright (c) 2024 Project CHIP Authors
* 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.
*/
#include <cstdint>
#include <functional>
#include <utility>
#include <pw_unit_test/framework.h>
#include <lib/support/ReadOnlyBuffer.h>
#include <lib/core/CHIPError.h>
#include <lib/core/DataModelTypes.h>
#include <lib/support/BitFlags.h>
#include <lib/support/BitMask.h>
#include <lib/support/Span.h>
using namespace chip;
using namespace chip::detail;
namespace {
class TestMetadataList : public ::testing::Test
{
public:
static void SetUpTestSuite() { ASSERT_EQ(chip::Platform::MemoryInit(), CHIP_NO_ERROR); }
static void TearDownTestSuite() { chip::Platform::MemoryShutdown(); }
};
template <typename T>
struct IdAndValue
{
uint32_t id;
T value;
bool operator==(const IdAndValue & other) const
{
return (this == &other) || ((this->id == other.id) && (this->value == other.value));
}
};
TEST_F(TestMetadataList, ListBuilderWorks)
{
ReadOnlyBufferBuilder<IdAndValue<int>> list1;
EXPECT_EQ(list1.Size(), 0u);
EXPECT_TRUE(list1.IsEmpty());
ASSERT_EQ(list1.EnsureAppendCapacity(3), CHIP_NO_ERROR);
EXPECT_EQ(list1.Size(), 0u);
EXPECT_TRUE(list1.IsEmpty());
ASSERT_EQ(list1.EnsureAppendCapacity(2), CHIP_NO_ERROR);
// Values can be appended until the capacity.
EXPECT_EQ(list1.Append({ 0xA1, 111 }), CHIP_NO_ERROR);
EXPECT_EQ(list1.Size(), 1u);
EXPECT_EQ(list1.Append({ 0xA2, 222 }), CHIP_NO_ERROR);
EXPECT_EQ(list1.Size(), 2u);
// capacity is 3 because of the largest ensure
EXPECT_EQ(list1.Append({ 0xA3, 333 }), CHIP_NO_ERROR);
EXPECT_EQ(list1.Size(), 3u);
EXPECT_EQ(list1.Append({ 0xA4, 444 }), CHIP_ERROR_BUFFER_TOO_SMALL);
EXPECT_EQ(list1.Size(), 3u);
ReadOnlyBufferBuilder<IdAndValue<int>> list2 = std::move(list1);
// Moved-from list is "empty", un-Metadata and span is empty.
EXPECT_EQ(list1.Size(), 0u); // NOLINT(bugprone-use-after-move)
EXPECT_TRUE(list1.IsEmpty()); // NOLINT(bugprone-use-after-move)
EXPECT_TRUE(list1.TakeBuffer().empty()); // NOLINT(bugprone-use-after-move)
// Moved-to list has storage.
EXPECT_EQ(list2.Size(), 3u);
EXPECT_FALSE(list2.IsEmpty());
// A span can be obtained over the list.
auto contents = list2.TakeBuffer();
EXPECT_EQ(contents.size(), 3u);
// contents takes ownersip of the list and clears it (and has no capacity)
EXPECT_TRUE(list2.IsEmpty());
EXPECT_EQ(list2.Append({ 1, 2 }), CHIP_ERROR_BUFFER_TOO_SMALL);
size_t idx = 0;
for (const auto & element : contents)
{
size_t oneBasedIndex = idx + 1;
EXPECT_EQ(element.id, 0xA0u + oneBasedIndex);
EXPECT_EQ(element.value, 111 * static_cast<int>(oneBasedIndex));
++idx;
}
EXPECT_EQ(idx, 3u);
}
TEST_F(TestMetadataList, ListBuilderConvertersWorks)
{
{
ReadOnlyBufferBuilder<int> list;
std::array<int, 3> kArray{ 1, 2, 3 };
EXPECT_EQ(list.ReferenceExisting(Span<const int>(kArray)), CHIP_NO_ERROR);
auto list2 = std::move(list);
EXPECT_EQ(list.Size(), 0u); // NOLINT(bugprone-use-after-move)
auto list2Span = list2.TakeBuffer();
EXPECT_TRUE(list2.IsEmpty()); // took over
EXPECT_EQ(list2Span.size(), 3u);
EXPECT_EQ(list2Span[0], 1);
EXPECT_EQ(list2Span[1], 2);
EXPECT_EQ(list2Span[2], 3);
}
{
ReadOnlyBufferBuilder<int> list;
std::array<int, 3> kArray{ 1, 2, 3 };
std::array<int, 3> kArray2{ 4, 5, 6 };
EXPECT_EQ(list.ReferenceExisting(Span<const int>(kArray)), CHIP_NO_ERROR);
EXPECT_EQ(list.ReferenceExisting(Span<const int>(kArray2)), CHIP_NO_ERROR);
auto list2 = std::move(list);
EXPECT_EQ(list.Size(), 0u); // NOLINT(bugprone-use-after-move)
auto list2Span = list2.TakeBuffer();
EXPECT_TRUE(list2.IsEmpty()); // took over
EXPECT_EQ(list2Span.size(), 6u);
EXPECT_EQ(list2Span[0], 1);
EXPECT_EQ(list2Span[1], 2);
EXPECT_EQ(list2Span[2], 3);
EXPECT_EQ(list2Span[3], 4);
EXPECT_EQ(list2Span[4], 5);
EXPECT_EQ(list2Span[5], 6);
}
{
ReadOnlyBufferBuilder<int> list;
EXPECT_EQ(list.Append(10), CHIP_ERROR_BUFFER_TOO_SMALL);
EXPECT_EQ(list.EnsureAppendCapacity(5), CHIP_NO_ERROR);
EXPECT_EQ(list.Append(10), CHIP_NO_ERROR);
EXPECT_EQ(list.Append(11), CHIP_NO_ERROR);
std::array<int, 3> kArray{ 1, 2, 3 };
EXPECT_EQ(list.ReferenceExisting(Span<const int>(kArray)), CHIP_NO_ERROR);
auto list2 = std::move(list);
EXPECT_EQ(list.Size(), 0u); // NOLINT(bugprone-use-after-move)
auto list2Span = list2.TakeBuffer();
EXPECT_TRUE(list2.IsEmpty()); // took over
EXPECT_EQ(list2Span.size(), 5u);
EXPECT_EQ(list2Span[0], 10);
EXPECT_EQ(list2Span[1], 11);
EXPECT_EQ(list2Span[2], 1);
EXPECT_EQ(list2Span[3], 2);
EXPECT_EQ(list2Span[4], 3);
}
{
ReadOnlyBufferBuilder<int> list;
EXPECT_EQ(list.Append(10), CHIP_ERROR_BUFFER_TOO_SMALL);
EXPECT_EQ(list.EnsureAppendCapacity(1), CHIP_NO_ERROR);
EXPECT_EQ(list.Append(10), CHIP_NO_ERROR);
EXPECT_EQ(list.Append(11), CHIP_ERROR_BUFFER_TOO_SMALL);
std::array<int, 3> kArray{ 1, 2, 3 };
EXPECT_EQ(list.AppendElements(Span<const int>(kArray)), CHIP_NO_ERROR);
EXPECT_EQ(list.ReferenceExisting(Span<const int>(kArray)), CHIP_NO_ERROR);
auto list2 = std::move(list);
EXPECT_EQ(list.Size(), 0u); // NOLINT(bugprone-use-after-move)
auto list2Span = list2.TakeBuffer();
EXPECT_TRUE(list2.IsEmpty()); // took over
EXPECT_EQ(list2Span.size(), 7u);
EXPECT_EQ(list2Span[0], 10);
EXPECT_EQ(list2Span[1], 1);
EXPECT_EQ(list2Span[2], 2);
EXPECT_EQ(list2Span[3], 3);
EXPECT_EQ(list2Span[4], 1);
EXPECT_EQ(list2Span[5], 2);
EXPECT_EQ(list2Span[6], 3);
}
}
TEST_F(TestMetadataList, BufferMoveOperationsWork)
{
{
using LIST = ReadOnlyBufferBuilder<int>;
LIST movedFromList{};
ASSERT_EQ(movedFromList.EnsureAppendCapacity(3), CHIP_NO_ERROR);
EXPECT_EQ(movedFromList.Append(10), CHIP_NO_ERROR);
EXPECT_EQ(movedFromList.Append(11), CHIP_NO_ERROR);
EXPECT_EQ(movedFromList.Append(12), CHIP_NO_ERROR);
LIST movedToList{ std::move(movedFromList) };
ASSERT_EQ(movedFromList.Size(), size_t{ 0 }); // NOLINT(bugprone-use-after-move)
ASSERT_TRUE(movedFromList.IsEmpty()); // NOLINT(bugprone-use-after-move)
ASSERT_EQ(movedToList.Size(), size_t{ 3 });
ASSERT_FALSE(movedToList.IsEmpty());
auto movedToListSpan = movedToList.TakeBuffer();
EXPECT_EQ(movedToListSpan[0], 10);
EXPECT_EQ(movedToListSpan[1], 11);
EXPECT_EQ(movedToListSpan[2], 12);
}
{
using LIST = ReadOnlyBufferBuilder<int>;
LIST movedFromList{};
LIST movedToList{};
ASSERT_EQ(movedFromList.EnsureAppendCapacity(3), CHIP_NO_ERROR);
ASSERT_EQ(movedToList.EnsureAppendCapacity(3), CHIP_NO_ERROR);
EXPECT_EQ(movedFromList.Append(10), CHIP_NO_ERROR);
EXPECT_EQ(movedFromList.Append(11), CHIP_NO_ERROR);
EXPECT_EQ(movedFromList.Append(12), CHIP_NO_ERROR);
movedToList = std::move(movedFromList);
ASSERT_EQ(movedFromList.Size(), size_t{ 0 }); // NOLINT(bugprone-use-after-move)
ASSERT_TRUE(movedFromList.IsEmpty()); // NOLINT(bugprone-use-after-move)
ASSERT_EQ(movedToList.Size(), size_t{ 3 });
ASSERT_FALSE(movedToList.IsEmpty());
}
}
} // namespace