blob: 6efe1cce2e7eef8f9cecefef3fddc5f3714f6cc7 [file] [log] [blame]
/*
*
* Copyright (c) 2022 Project CHIP Authors
*
* 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 <lib/core/StringBuilderAdapters.h>
#include <pw_unit_test/framework.h>
#include <app/util/binding-table.h>
#include <app/util/config.h>
#include <lib/support/DefaultStorageKeyAllocator.h>
#include <lib/support/TestPersistentStorageDelegate.h>
using chip::BindingTable;
namespace {
void VerifyTableSame(BindingTable & table, const std::vector<EmberBindingTableEntry> & expected)
{
ASSERT_EQ(table.Size(), expected.size());
auto iter1 = table.begin();
auto iter2 = expected.begin();
while (iter2 != expected.end())
{
EXPECT_EQ(*iter1, *iter2);
++iter1;
++iter2;
}
EXPECT_EQ(iter1, table.end());
}
void VerifyRestored(chip::TestPersistentStorageDelegate & storage, const std::vector<EmberBindingTableEntry> & expected)
{
BindingTable restoredTable;
restoredTable.SetPersistentStorage(&storage);
EXPECT_EQ(restoredTable.LoadFromStorage(), CHIP_NO_ERROR);
VerifyTableSame(restoredTable, expected);
}
TEST(TestBindingTable, TestEmptyBindingTable)
{
BindingTable table;
chip::TestPersistentStorageDelegate testStorage;
table.SetPersistentStorage(&testStorage);
EXPECT_EQ(table.Size(), 0u);
EXPECT_EQ(table.begin(), table.end());
}
TEST(TestBindingTable, TestAdd)
{
BindingTable table;
chip::TestPersistentStorageDelegate testStorage;
table.SetPersistentStorage(&testStorage);
EmberBindingTableEntry unusedEntry;
unusedEntry.type = MATTER_UNUSED_BINDING;
EXPECT_EQ(table.Add(unusedEntry), CHIP_ERROR_INVALID_ARGUMENT);
for (uint8_t i = 0; i < MATTER_BINDING_TABLE_SIZE; i++)
{
EXPECT_EQ(table.Add(EmberBindingTableEntry::ForNode(0, i, 0, 0, std::nullopt)), CHIP_NO_ERROR);
}
EXPECT_EQ(table.Add(EmberBindingTableEntry::ForNode(0, 0, 0, 0, std::nullopt)), CHIP_ERROR_NO_MEMORY);
EXPECT_EQ(table.Size(), MATTER_BINDING_TABLE_SIZE);
auto iter = table.begin();
for (uint8_t i = 0; i < MATTER_BINDING_TABLE_SIZE; i++)
{
EXPECT_NE(iter, table.end());
EXPECT_EQ(iter->nodeId, i);
EXPECT_EQ(iter.GetIndex(), i);
++iter;
}
EXPECT_EQ(iter, table.end());
}
TEST(TestBindingTable, TestRemoveThenAdd)
{
BindingTable table;
chip::TestPersistentStorageDelegate testStorage;
table.SetPersistentStorage(&testStorage);
EXPECT_EQ(table.Add(EmberBindingTableEntry::ForNode(0, 0, 0, 0, std::nullopt)), CHIP_NO_ERROR);
auto iter = table.begin();
EXPECT_EQ(table.RemoveAt(iter), CHIP_NO_ERROR);
EXPECT_EQ(iter, table.end());
EXPECT_EQ(table.Size(), 0u);
EXPECT_EQ(table.begin(), table.end());
for (uint8_t i = 0; i < MATTER_BINDING_TABLE_SIZE; i++)
{
EXPECT_EQ(table.Add(EmberBindingTableEntry::ForNode(0, i, 0, 0, std::nullopt)), CHIP_NO_ERROR);
}
iter = table.begin();
++iter;
EXPECT_EQ(table.RemoveAt(iter), CHIP_NO_ERROR);
EXPECT_EQ(table.Size(), MATTER_BINDING_TABLE_SIZE - 1);
EXPECT_EQ(iter->nodeId, 2u);
EXPECT_EQ(iter.GetIndex(), 2u);
auto iterCheck = table.begin();
++iterCheck;
EXPECT_EQ(iter, iterCheck);
EXPECT_EQ(table.Add(EmberBindingTableEntry::ForNode(0, 1, 0, 0, std::nullopt)), CHIP_NO_ERROR);
EXPECT_EQ(table.Size(), MATTER_BINDING_TABLE_SIZE);
iter = table.begin();
for (uint8_t i = 0; i < MATTER_BINDING_TABLE_SIZE - 1; i++)
{
++iter;
}
EXPECT_EQ(iter->nodeId, 1u);
EXPECT_EQ(iter.GetIndex(), 1u);
++iter;
EXPECT_EQ(iter, table.end());
iter = table.begin();
EXPECT_EQ(table.RemoveAt(iter), CHIP_NO_ERROR);
EXPECT_EQ(table.Size(), MATTER_BINDING_TABLE_SIZE - 1);
EXPECT_EQ(iter, table.begin());
EXPECT_EQ(iter.GetIndex(), 2u);
EXPECT_EQ(iter->nodeId, 2u);
EXPECT_EQ(table.GetAt(0).type, MATTER_UNUSED_BINDING);
}
TEST(TestBindingTable, TestPersistentStorage)
{
chip::TestPersistentStorageDelegate testStorage;
BindingTable table;
chip::Optional<chip::ClusterId> cluster = chip::MakeOptional<chip::ClusterId>(static_cast<chip::ClusterId>(UINT16_MAX + 6));
std::vector<EmberBindingTableEntry> expected = {
EmberBindingTableEntry::ForNode(0, 0, 0, 0, std::nullopt),
EmberBindingTableEntry::ForNode(1, 1, 0, 0, cluster.std_optional()),
EmberBindingTableEntry::ForGroup(2, 2, 0, std::nullopt),
EmberBindingTableEntry::ForGroup(3, 3, 0, cluster.std_optional()),
};
table.SetPersistentStorage(&testStorage);
EXPECT_EQ(table.Add(expected[0]), CHIP_NO_ERROR);
EXPECT_EQ(table.Add(expected[1]), CHIP_NO_ERROR);
EXPECT_EQ(table.Add(expected[2]), CHIP_NO_ERROR);
EXPECT_EQ(table.Add(expected[3]), CHIP_NO_ERROR);
VerifyRestored(testStorage, expected);
// Verify storage untouched if add fails
testStorage.AddPoisonKey(chip::DefaultStorageKeyAllocator::BindingTableEntry(4).KeyName());
EXPECT_NE(table.Add(EmberBindingTableEntry::ForNode(4, 4, 0, 0, std::nullopt)), CHIP_NO_ERROR);
VerifyRestored(testStorage, expected);
testStorage.ClearPoisonKeys();
// Verify storage untouched if removing head fails
testStorage.AddPoisonKey(chip::DefaultStorageKeyAllocator::BindingTable().KeyName());
auto iter = table.begin();
EXPECT_NE(table.RemoveAt(iter), CHIP_NO_ERROR);
VerifyTableSame(table, expected);
testStorage.ClearPoisonKeys();
VerifyRestored(testStorage, expected);
// Verify storage untouched if removing other nodes fails
testStorage.AddPoisonKey(chip::DefaultStorageKeyAllocator::BindingTableEntry(0).KeyName());
iter = table.begin();
++iter;
EXPECT_NE(table.RemoveAt(iter), CHIP_NO_ERROR);
VerifyTableSame(table, expected);
testStorage.ClearPoisonKeys();
VerifyRestored(testStorage, expected);
// Verify removing head
iter = table.begin();
EXPECT_EQ(table.RemoveAt(iter), CHIP_NO_ERROR);
VerifyTableSame(table, { expected[1], expected[2], expected[3] });
VerifyRestored(testStorage, { expected[1], expected[2], expected[3] });
// Verify removing other nodes
++iter;
EXPECT_EQ(table.RemoveAt(iter), CHIP_NO_ERROR);
VerifyTableSame(table, { expected[1], expected[3] });
VerifyRestored(testStorage, { expected[1], expected[3] });
}
} // namespace