diff --git a/test/unit/StorageTest.cpp b/test/unit/StorageTest.cpp new file mode 100644 index 0000000000..38cbb863f3 --- /dev/null +++ b/test/unit/StorageTest.cpp @@ -0,0 +1,268 @@ +/*----------------------------------------------------------------------------*/ +/* Copyright (c) FIRST 2015. All Rights Reserved. */ +/* Open Source Software - may be modified and shared by FRC teams. The code */ +/* must be accompanied by the FIRST BSD license file in the root directory of */ +/* the project. */ +/*----------------------------------------------------------------------------*/ + +#include "Storage.h" + +#include "gtest/gtest.h" + +namespace nt { + +class StorageTest : public ::testing::Test { + public: + void PopulateTrue() { + storage.SetEntryTypeValue("foo", Value::MakeBoolean(true)); + ASSERT_EQ(1u, updates().size()); + updates().pop(); + } + + Storage::EntriesMap& entries() { return storage.m_entries; } + Storage::UpdateQueue& updates() { return storage.updates(); } + Storage storage; +}; + +TEST_F(StorageTest, Construct) { + ASSERT_TRUE(entries().empty()); + ASSERT_TRUE(updates().empty()); +} + +TEST_F(StorageTest, FindEntryNotExist) { + ASSERT_FALSE(storage.FindEntry("foo")); + ASSERT_TRUE(entries().empty()); +} + +TEST_F(StorageTest, FindEntryExist) { + auto entry1 = storage.GetEntry("foo"); + auto entry = storage.FindEntry("foo"); + ASSERT_TRUE(bool(entry)); + ASSERT_EQ(entry1, entry); + ASSERT_FALSE(storage.FindEntry("bar")); +} + +TEST_F(StorageTest, GetEntryNotExist) { + auto entry = storage.GetEntry("foo"); + ASSERT_TRUE(bool(entry)); + ASSERT_EQ(1u, entries().size()); + + EXPECT_FALSE(entry->value()); + EXPECT_EQ(0u, entry->flags()); + EXPECT_EQ(0xffffu, entry->id()); + EXPECT_EQ(SequenceNumber(), entry->seq_num()); +} + +TEST_F(StorageTest, GetEntryValueNotExist) { + ASSERT_FALSE(storage.GetEntryValue("foo")); + ASSERT_TRUE(entries().empty()); +} + +TEST_F(StorageTest, GetEntryValueExist) { + auto value = Value::MakeBoolean(true); + storage.SetEntryTypeValue("foo", value); + ASSERT_EQ(1u, updates().size()); + updates().pop(); + ASSERT_EQ(value, storage.GetEntryValue("foo")); +} + +TEST_F(StorageTest, SetEntryTypeValueAssignNew) { + // brand new entry + auto value = Value::MakeBoolean(true); + storage.SetEntryTypeValue("foo", value); + auto entry = storage.GetEntry("foo"); + EXPECT_EQ(value, entry->value()); + ASSERT_EQ(1u, updates().size()); + auto update = updates().pop(); + EXPECT_EQ(entry, update.entry); + EXPECT_EQ(Storage::Update::kAssign, update.kind); +} + +TEST_F(StorageTest, SetEntryTypeValueAssignTypeChange) { + PopulateTrue(); + // update with different type results in assignment message + auto value = Value::MakeDouble(0.0); + storage.SetEntryTypeValue("foo", value); + auto entry = storage.GetEntry("foo"); + EXPECT_EQ(value, entry->value()); + ASSERT_EQ(1u, updates().size()); + auto update = updates().pop(); + EXPECT_EQ(entry, update.entry); + EXPECT_EQ(Storage::Update::kAssign, update.kind); +} + +TEST_F(StorageTest, SetEntryTypeValueEqualValue) { + PopulateTrue(); + // update with same type and same value: change value contents but no update + // message is issued (minimizing bandwidth usage) + auto value = Value::MakeBoolean(true); + storage.SetEntryTypeValue("foo", value); + auto entry = storage.GetEntry("foo"); + EXPECT_EQ(value, entry->value()); + ASSERT_TRUE(updates().empty()); +} + +TEST_F(StorageTest, SetEntryTypeValueDifferentValue) { + PopulateTrue(); + // update with same type and different value results in value update message + auto value = Value::MakeBoolean(false); + storage.SetEntryTypeValue("foo", value); + auto entry = storage.GetEntry("foo"); + EXPECT_EQ(value, entry->value()); + ASSERT_EQ(1u, updates().size()); + auto update = updates().pop(); + EXPECT_EQ(entry, update.entry); + EXPECT_EQ(Storage::Update::kValueUpdate, update.kind); +} + +TEST_F(StorageTest, SetEntryTypeValueEmptyName) { + auto value = Value::MakeBoolean(true); + storage.SetEntryTypeValue("", value); + ASSERT_TRUE(entries().empty()); + ASSERT_TRUE(updates().empty()); +} + +TEST_F(StorageTest, SetEntryTypeValueEmptyValue) { + storage.SetEntryTypeValue("foo", nullptr); + ASSERT_TRUE(entries().empty()); + ASSERT_TRUE(updates().empty()); +} + +TEST_F(StorageTest, SetEntryValueAssignNew) { + // brand new entry + auto value = Value::MakeBoolean(true); + EXPECT_TRUE(storage.SetEntryValue("foo", value)); + auto entry = storage.GetEntry("foo"); + EXPECT_EQ(value, entry->value()); + ASSERT_EQ(1u, updates().size()); + auto update = updates().pop(); + EXPECT_EQ(entry, update.entry); + EXPECT_EQ(Storage::Update::kAssign, update.kind); +} + +TEST_F(StorageTest, SetEntryValueAssignTypeChange) { + PopulateTrue(); + // update with different type results in error and no message + auto value = Value::MakeDouble(0.0); + EXPECT_FALSE(storage.SetEntryValue("foo", value)); + auto entry = storage.GetEntry("foo"); + EXPECT_NE(value, entry->value()); + ASSERT_TRUE(updates().empty()); +} + +TEST_F(StorageTest, SetEntryValueEqualValue) { + PopulateTrue(); + // update with same type and same value: change value contents but no update + // message is issued (minimizing bandwidth usage) + auto value = Value::MakeBoolean(true); + EXPECT_TRUE(storage.SetEntryValue("foo", value)); + auto entry = storage.GetEntry("foo"); + EXPECT_EQ(value, entry->value()); + ASSERT_TRUE(updates().empty()); +} + +TEST_F(StorageTest, SetEntryValueDifferentValue) { + PopulateTrue(); + // update with same type and different value results in value update message + auto value = Value::MakeBoolean(false); + EXPECT_TRUE(storage.SetEntryValue("foo", value)); + auto entry = storage.GetEntry("foo"); + EXPECT_EQ(value, entry->value()); + ASSERT_EQ(1u, updates().size()); + auto update = updates().pop(); + EXPECT_EQ(entry, update.entry); + EXPECT_EQ(Storage::Update::kValueUpdate, update.kind); +} + +TEST_F(StorageTest, SetEntryValueEmptyName) { + auto value = Value::MakeBoolean(true); + EXPECT_TRUE(storage.SetEntryValue("", value)); + ASSERT_TRUE(entries().empty()); + ASSERT_TRUE(updates().empty()); +} + +TEST_F(StorageTest, SetEntryValueEmptyValue) { + EXPECT_TRUE(storage.SetEntryValue("foo", nullptr)); + ASSERT_TRUE(entries().empty()); + ASSERT_TRUE(updates().empty()); +} + +TEST_F(StorageTest, SetEntryFlagsNew) { + // flags setting doesn't create an entry + storage.SetEntryFlags("foo", 0u); + ASSERT_TRUE(entries().empty()); + ASSERT_TRUE(updates().empty()); +} + +TEST_F(StorageTest, SetEntryFlagsEqualValue) { + PopulateTrue(); + // update with same value: no update message is issued (minimizing bandwidth + // usage) + storage.SetEntryFlags("foo", 0u); + auto entry = storage.GetEntry("foo"); + EXPECT_EQ(0u, entry->flags()); + ASSERT_TRUE(updates().empty()); +} + +TEST_F(StorageTest, SetEntryFlagsDifferentValue) { + PopulateTrue(); + // update with different value results in flags update message + storage.SetEntryFlags("foo", 1u); + auto entry = storage.GetEntry("foo"); + EXPECT_EQ(1u, entry->flags()); + ASSERT_EQ(1u, updates().size()); + auto update = updates().pop(); + EXPECT_EQ(entry, update.entry); + EXPECT_EQ(Storage::Update::kFlagsUpdate, update.kind); +} + +TEST_F(StorageTest, SetEntryFlagsEmptyName) { + storage.SetEntryFlags("", 0u); + ASSERT_TRUE(entries().empty()); + ASSERT_TRUE(updates().empty()); +} + +TEST_F(StorageTest, GetEntryFlagsNotExist) { + ASSERT_EQ(0u, storage.GetEntryFlags("foo")); + ASSERT_TRUE(entries().empty()); +} + +TEST_F(StorageTest, GetEntryFlagsExist) { + PopulateTrue(); + storage.SetEntryFlags("foo", 1u); + while (!updates().empty()) updates().pop(); + ASSERT_EQ(1u, storage.GetEntryFlags("foo")); +} + +TEST_F(StorageTest, DeleteEntryNotExist) { + storage.DeleteEntry("foo"); + ASSERT_TRUE(updates().empty()); +} + +TEST_F(StorageTest, DeleteEntryExist) { + PopulateTrue(); + auto entry = storage.GetEntry("foo"); + storage.DeleteEntry("foo"); + ASSERT_TRUE(entries().empty()); + ASSERT_EQ(1u, updates().size()); + auto update = updates().pop(); + EXPECT_EQ(entry, update.entry); + EXPECT_EQ(Storage::Update::kDelete, update.kind); +} + +TEST_F(StorageTest, DeleteAllEntriesEmpty) { + storage.DeleteAllEntries(); + ASSERT_TRUE(updates().empty()); +} + +TEST_F(StorageTest, DeleteAllEntries) { + PopulateTrue(); + storage.DeleteAllEntries(); + ASSERT_TRUE(entries().empty()); + ASSERT_EQ(1u, updates().size()); + auto update = updates().pop(); + EXPECT_EQ(nullptr, update.entry); + EXPECT_EQ(Storage::Update::kDeleteAll, update.kind); +} + +} // namespace nt