blob: 624b83ec2ce62d8a7c4f9f796a0cefadb1678125 [file] [log] [blame]
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/sqlite_proto/key_value_table.h"
#include "base/memory/scoped_refptr.h"
#include "components/sqlite_proto/test_proto.pb.h"
#include "sql/database.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using ::testing::ElementsAre;
using ::testing::Pair;
using ::testing::UnorderedElementsAre;
namespace sqlite_proto {
namespace {
MATCHER_P(EqualsProto,
message,
"Match a proto Message equal to the matcher's argument.") {
std::string expected_serialized, actual_serialized;
message.SerializeToString(&expected_serialized);
arg.SerializeToString(&actual_serialized);
return expected_serialized == actual_serialized;
}
bool CreateProtoTable(sql::Database* db) {
const char kCreateProtoTableStatementTemplate[] =
"CREATE TABLE my_table ( "
"key TEXT, "
"proto BLOB, "
"PRIMARY KEY(key))";
return db->Execute(kCreateProtoTableStatementTemplate);
}
} // namespace
class KeyValueTableTest : public ::testing::Test {
public:
KeyValueTableTest() {
CHECK(db_.OpenInMemory());
CHECK(CreateProtoTable(&db_));
}
~KeyValueTableTest() override = default;
protected:
sql::Database db_;
KeyValueTable<TestProto> table_{"my_table"};
};
TEST_F(KeyValueTableTest, Empty) {
std::map<std::string, TestProto> my_data;
table_.GetAllData(&my_data, &db_);
EXPECT_TRUE(my_data.empty());
}
TEST_F(KeyValueTableTest, PutAndGet) {
TestProto element;
element.set_value(1);
table_.UpdateData("a", element, &db_);
TestProto second_element;
second_element.set_value(2);
table_.UpdateData("b", second_element, &db_);
std::map<std::string, TestProto> my_data;
table_.GetAllData(&my_data, &db_);
EXPECT_THAT(my_data,
UnorderedElementsAre(Pair("a", EqualsProto(element)),
Pair("b", EqualsProto(second_element))));
}
TEST_F(KeyValueTableTest, Update) {
TestProto element;
element.set_value(1);
TestProto superseding_element;
superseding_element.set_value(2);
table_.UpdateData("a", element, &db_);
table_.UpdateData("a", superseding_element, &db_);
std::map<std::string, TestProto> my_data;
table_.GetAllData(&my_data, &db_);
EXPECT_THAT(my_data,
ElementsAre(Pair("a", EqualsProto(superseding_element))));
}
TEST_F(KeyValueTableTest, DeleteNonexistent) {
TestProto element;
element.set_value(1);
table_.UpdateData("a", element, &db_);
// Deleting a nonexistent key should no-op.
table_.DeleteData(std::vector<std::string>{"b"}, &db_);
std::map<std::string, TestProto> my_data;
table_.GetAllData(&my_data, &db_);
EXPECT_THAT(my_data, ElementsAre(Pair("a", EqualsProto(element))));
}
TEST_F(KeyValueTableTest, Delete) {
TestProto element;
element.set_value(1);
table_.UpdateData("a", element, &db_);
table_.DeleteData(std::vector<std::string>{"a"}, &db_);
std::map<std::string, TestProto> my_data;
table_.GetAllData(&my_data, &db_);
EXPECT_TRUE(my_data.empty());
}
TEST_F(KeyValueTableTest, DeleteAll) {
TestProto element;
element.set_value(1);
table_.UpdateData("a", element, &db_);
table_.UpdateData("b", element, &db_);
table_.DeleteAllData(&db_);
std::map<std::string, TestProto> my_data;
table_.GetAllData(&my_data, &db_);
EXPECT_TRUE(my_data.empty());
}
// Storing an element with a default proto value (zero byte size) should work;
// this can be useful since a default value can have different semantics from a
// missing value.
TEST_F(KeyValueTableTest, PutGetDefaultValue) {
TestProto element;
table_.UpdateData("a", element, &db_);
ASSERT_EQ(element.ByteSize(), 0);
std::map<std::string, TestProto> my_data;
table_.GetAllData(&my_data, &db_);
EXPECT_THAT(my_data, ElementsAre(Pair("a", EqualsProto(element))));
}
} // namespace sqlite_proto