You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
193 lines
5.7 KiB
193 lines
5.7 KiB
// Copyright (c) 2010 The Chromium OS 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 <brillo/key_value_store.h> |
|
|
|
#include <map> |
|
#include <string> |
|
#include <vector> |
|
|
|
#include <base/files/file_util.h> |
|
#include <base/files/scoped_temp_dir.h> |
|
#include <base/logging.h> |
|
#include <base/strings/string_util.h> |
|
#include <brillo/map_utils.h> |
|
#include <gtest/gtest.h> |
|
|
|
using base::FilePath; |
|
using base::ReadFileToString; |
|
using std::map; |
|
using std::string; |
|
using std::vector; |
|
|
|
namespace brillo { |
|
|
|
class KeyValueStoreTest : public ::testing::Test { |
|
protected: |
|
// Returns the value from |store_| corresponding to |key|, or an empty string |
|
// if the key is not present. Crashes if the store returns an empty value. |
|
string GetNonemptyStringValue(const string& key) { |
|
string value; |
|
if (store_.GetString(key, &value)) |
|
CHECK(!value.empty()); |
|
return value; |
|
} |
|
|
|
KeyValueStore store_; // KeyValueStore under test. |
|
}; |
|
|
|
TEST_F(KeyValueStoreTest, LoadAndSaveFromFile) { |
|
base::ScopedTempDir temp_dir_; |
|
CHECK(temp_dir_.CreateUniqueTempDir()); |
|
base::FilePath temp_file_ = temp_dir_.GetPath().Append("temp.conf"); |
|
base::FilePath saved_temp_file_ = |
|
temp_dir_.GetPath().Append("saved_temp.conf"); |
|
|
|
string blob = "A=B\n# Comment\n"; |
|
ASSERT_EQ(blob.size(), base::WriteFile(temp_file_, blob.data(), blob.size())); |
|
ASSERT_TRUE(store_.Load(temp_file_)); |
|
|
|
string value; |
|
EXPECT_TRUE(store_.GetString("A", &value)); |
|
EXPECT_EQ("B", value); |
|
|
|
ASSERT_TRUE(store_.Save(saved_temp_file_)); |
|
string read_blob; |
|
ASSERT_TRUE(ReadFileToString(FilePath(saved_temp_file_), &read_blob)); |
|
EXPECT_EQ("A=B\n", read_blob); |
|
} |
|
|
|
TEST_F(KeyValueStoreTest, CommentsAreIgnored) { |
|
EXPECT_TRUE(store_.LoadFromString( |
|
"# comment\nA=B\n\n\n#another=comment\n # leading spaces\n")); |
|
EXPECT_EQ("A=B\n", store_.SaveToString()); |
|
} |
|
|
|
TEST_F(KeyValueStoreTest, EmptyTest) { |
|
EXPECT_TRUE(store_.LoadFromString("")); |
|
EXPECT_EQ("", store_.SaveToString()); |
|
} |
|
|
|
TEST_F(KeyValueStoreTest, LoadAndReloadTest) { |
|
EXPECT_TRUE(store_.LoadFromString( |
|
"A=B\nC=\nFOO=BAR=BAZ\nBAR=BAX\nMISSING=NEWLINE")); |
|
|
|
map<string, string> expected = {{"A", "B"}, |
|
{"C", ""}, |
|
{"FOO", "BAR=BAZ"}, |
|
{"BAR", "BAX"}, |
|
{"MISSING", "NEWLINE"}}; |
|
|
|
// Test expected values. |
|
string value; |
|
for (const auto& it : expected) { |
|
EXPECT_TRUE(store_.GetString(it.first, &value)); |
|
EXPECT_EQ(it.second, value) << "Testing key: " << it.first; |
|
} |
|
|
|
// Save, load and test again. |
|
KeyValueStore new_store; |
|
ASSERT_TRUE(new_store.LoadFromString(store_.SaveToString())); |
|
|
|
for (const auto& it : expected) { |
|
EXPECT_TRUE(new_store.GetString(it.first, &value)) << "key: " << it.first; |
|
EXPECT_EQ(it.second, value) << "key: " << it.first; |
|
} |
|
} |
|
|
|
TEST_F(KeyValueStoreTest, SimpleBooleanTest) { |
|
bool result; |
|
EXPECT_FALSE(store_.GetBoolean("A", &result)); |
|
|
|
store_.SetBoolean("A", true); |
|
EXPECT_TRUE(store_.GetBoolean("A", &result)); |
|
EXPECT_TRUE(result); |
|
|
|
store_.SetBoolean("A", false); |
|
EXPECT_TRUE(store_.GetBoolean("A", &result)); |
|
EXPECT_FALSE(result); |
|
} |
|
|
|
TEST_F(KeyValueStoreTest, BooleanParsingTest) { |
|
string blob = "TRUE=true\nfalse=false\nvar=false\nDONT_SHOUT=TRUE\n"; |
|
EXPECT_TRUE(store_.LoadFromString(blob)); |
|
|
|
map<string, bool> expected = { |
|
{"TRUE", true}, {"false", false}, {"var", false}}; |
|
bool value; |
|
EXPECT_FALSE(store_.GetBoolean("DONT_SHOUT", &value)); |
|
string str_value; |
|
EXPECT_TRUE(store_.GetString("DONT_SHOUT", &str_value)); |
|
|
|
// Test expected values. |
|
for (const auto& it : expected) { |
|
EXPECT_TRUE(store_.GetBoolean(it.first, &value)) << "key: " << it.first; |
|
EXPECT_EQ(it.second, value) << "key: " << it.first; |
|
} |
|
} |
|
|
|
TEST_F(KeyValueStoreTest, TrimWhitespaceAroundKey) { |
|
EXPECT_TRUE(store_.LoadFromString(" a=1\nb =2\n c =3\n")); |
|
|
|
EXPECT_EQ("1", GetNonemptyStringValue("a")); |
|
EXPECT_EQ("2", GetNonemptyStringValue("b")); |
|
EXPECT_EQ("3", GetNonemptyStringValue("c")); |
|
|
|
// Keys should also be trimmed when setting new values. |
|
store_.SetString(" foo ", "4"); |
|
EXPECT_EQ("4", GetNonemptyStringValue("foo")); |
|
|
|
store_.SetBoolean(" bar ", true); |
|
bool value = false; |
|
ASSERT_TRUE(store_.GetBoolean("bar", &value)); |
|
EXPECT_TRUE(value); |
|
} |
|
|
|
TEST_F(KeyValueStoreTest, IgnoreWhitespaceLine) { |
|
EXPECT_TRUE(store_.LoadFromString("a=1\n \t \nb=2")); |
|
|
|
EXPECT_EQ("1", GetNonemptyStringValue("a")); |
|
EXPECT_EQ("2", GetNonemptyStringValue("b")); |
|
} |
|
|
|
TEST_F(KeyValueStoreTest, RejectEmptyKeys) { |
|
EXPECT_FALSE(store_.LoadFromString("=1")); |
|
EXPECT_FALSE(store_.LoadFromString(" =2")); |
|
|
|
// Trying to set an empty (after trimming) key should fail an assert. |
|
EXPECT_DEATH(store_.SetString(" ", "3"), ""); |
|
EXPECT_DEATH(store_.SetBoolean(" ", "4"), ""); |
|
} |
|
|
|
TEST_F(KeyValueStoreTest, RejectBogusLines) { |
|
EXPECT_FALSE(store_.LoadFromString("a=1\nbogus\nb=2")); |
|
} |
|
|
|
TEST_F(KeyValueStoreTest, MultilineValue) { |
|
EXPECT_TRUE(store_.LoadFromString("a=foo\nb=bar\\\n baz \\ \nc=3\n")); |
|
|
|
EXPECT_EQ("foo", GetNonemptyStringValue("a")); |
|
EXPECT_EQ("bar baz \\ ", GetNonemptyStringValue("b")); |
|
EXPECT_EQ("3", GetNonemptyStringValue("c")); |
|
} |
|
|
|
TEST_F(KeyValueStoreTest, UnterminatedMultilineValue) { |
|
EXPECT_FALSE(store_.LoadFromString("a=foo\\")); |
|
EXPECT_FALSE(store_.LoadFromString("a=foo\\\n")); |
|
EXPECT_FALSE(store_.LoadFromString("a=foo\\\n\n# blah\n")); |
|
} |
|
|
|
TEST_F(KeyValueStoreTest, GetKeys) { |
|
map<string, string> entries = { |
|
{"1", "apple"}, {"2", "banana"}, {"3", "cherry"} |
|
}; |
|
for (const auto& it : entries) { |
|
store_.SetString(it.first, it.second); |
|
} |
|
|
|
vector<string> keys = GetMapKeysAsVector(entries); |
|
EXPECT_EQ(keys, store_.GetKeys()); |
|
} |
|
|
|
} // namespace brillo
|
|
|