1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <brillo/key_value_store.h>
6
7 #include <map>
8 #include <string>
9 #include <vector>
10
11 #include <base/files/file_util.h>
12 #include <base/files/scoped_temp_dir.h>
13 #include <base/logging.h>
14 #include <base/strings/string_util.h>
15 #include <brillo/map_utils.h>
16 #include <gtest/gtest.h>
17
18 using base::FilePath;
19 using base::ReadFileToString;
20 using std::map;
21 using std::string;
22 using std::vector;
23
24 namespace brillo {
25
26 class KeyValueStoreTest : public ::testing::Test {
27 protected:
28 // Returns the value from |store_| corresponding to |key|, or an empty string
29 // if the key is not present. Crashes if the store returns an empty value.
GetNonemptyStringValue(const string & key)30 string GetNonemptyStringValue(const string& key) {
31 string value;
32 if (store_.GetString(key, &value))
33 CHECK(!value.empty());
34 return value;
35 }
36
37 KeyValueStore store_; // KeyValueStore under test.
38 };
39
TEST_F(KeyValueStoreTest,LoadAndSaveFromFile)40 TEST_F(KeyValueStoreTest, LoadAndSaveFromFile) {
41 base::ScopedTempDir temp_dir_;
42 CHECK(temp_dir_.CreateUniqueTempDir());
43 base::FilePath temp_file_ = temp_dir_.path().Append("temp.conf");
44 base::FilePath saved_temp_file_ = temp_dir_.path().Append("saved_temp.conf");
45
46 string blob = "A=B\n# Comment\n";
47 ASSERT_EQ(blob.size(), base::WriteFile(temp_file_, blob.data(), blob.size()));
48 ASSERT_TRUE(store_.Load(temp_file_));
49
50 string value;
51 EXPECT_TRUE(store_.GetString("A", &value));
52 EXPECT_EQ("B", value);
53
54 ASSERT_TRUE(store_.Save(saved_temp_file_));
55 string read_blob;
56 ASSERT_TRUE(ReadFileToString(FilePath(saved_temp_file_), &read_blob));
57 EXPECT_EQ("A=B\n", read_blob);
58 }
59
TEST_F(KeyValueStoreTest,CommentsAreIgnored)60 TEST_F(KeyValueStoreTest, CommentsAreIgnored) {
61 EXPECT_TRUE(store_.LoadFromString(
62 "# comment\nA=B\n\n\n#another=comment\n # leading spaces\n"));
63 EXPECT_EQ("A=B\n", store_.SaveToString());
64 }
65
TEST_F(KeyValueStoreTest,EmptyTest)66 TEST_F(KeyValueStoreTest, EmptyTest) {
67 EXPECT_TRUE(store_.LoadFromString(""));
68 EXPECT_EQ("", store_.SaveToString());
69 }
70
TEST_F(KeyValueStoreTest,LoadAndReloadTest)71 TEST_F(KeyValueStoreTest, LoadAndReloadTest) {
72 EXPECT_TRUE(store_.LoadFromString(
73 "A=B\nC=\nFOO=BAR=BAZ\nBAR=BAX\nMISSING=NEWLINE"));
74
75 map<string, string> expected = {{"A", "B"},
76 {"C", ""},
77 {"FOO", "BAR=BAZ"},
78 {"BAR", "BAX"},
79 {"MISSING", "NEWLINE"}};
80
81 // Test expected values.
82 string value;
83 for (const auto& it : expected) {
84 EXPECT_TRUE(store_.GetString(it.first, &value));
85 EXPECT_EQ(it.second, value) << "Testing key: " << it.first;
86 }
87
88 // Save, load and test again.
89 KeyValueStore new_store;
90 ASSERT_TRUE(new_store.LoadFromString(store_.SaveToString()));
91
92 for (const auto& it : expected) {
93 EXPECT_TRUE(new_store.GetString(it.first, &value)) << "key: " << it.first;
94 EXPECT_EQ(it.second, value) << "key: " << it.first;
95 }
96 }
97
TEST_F(KeyValueStoreTest,SimpleBooleanTest)98 TEST_F(KeyValueStoreTest, SimpleBooleanTest) {
99 bool result;
100 EXPECT_FALSE(store_.GetBoolean("A", &result));
101
102 store_.SetBoolean("A", true);
103 EXPECT_TRUE(store_.GetBoolean("A", &result));
104 EXPECT_TRUE(result);
105
106 store_.SetBoolean("A", false);
107 EXPECT_TRUE(store_.GetBoolean("A", &result));
108 EXPECT_FALSE(result);
109 }
110
TEST_F(KeyValueStoreTest,BooleanParsingTest)111 TEST_F(KeyValueStoreTest, BooleanParsingTest) {
112 string blob = "TRUE=true\nfalse=false\nvar=false\nDONT_SHOUT=TRUE\n";
113 EXPECT_TRUE(store_.LoadFromString(blob));
114
115 map<string, bool> expected = {
116 {"TRUE", true}, {"false", false}, {"var", false}};
117 bool value;
118 EXPECT_FALSE(store_.GetBoolean("DONT_SHOUT", &value));
119 string str_value;
120 EXPECT_TRUE(store_.GetString("DONT_SHOUT", &str_value));
121
122 // Test expected values.
123 for (const auto& it : expected) {
124 EXPECT_TRUE(store_.GetBoolean(it.first, &value)) << "key: " << it.first;
125 EXPECT_EQ(it.second, value) << "key: " << it.first;
126 }
127 }
128
TEST_F(KeyValueStoreTest,TrimWhitespaceAroundKey)129 TEST_F(KeyValueStoreTest, TrimWhitespaceAroundKey) {
130 EXPECT_TRUE(store_.LoadFromString(" a=1\nb =2\n c =3\n"));
131
132 EXPECT_EQ("1", GetNonemptyStringValue("a"));
133 EXPECT_EQ("2", GetNonemptyStringValue("b"));
134 EXPECT_EQ("3", GetNonemptyStringValue("c"));
135
136 // Keys should also be trimmed when setting new values.
137 store_.SetString(" foo ", "4");
138 EXPECT_EQ("4", GetNonemptyStringValue("foo"));
139
140 store_.SetBoolean(" bar ", true);
141 bool value = false;
142 ASSERT_TRUE(store_.GetBoolean("bar", &value));
143 EXPECT_TRUE(value);
144 }
145
TEST_F(KeyValueStoreTest,IgnoreWhitespaceLine)146 TEST_F(KeyValueStoreTest, IgnoreWhitespaceLine) {
147 EXPECT_TRUE(store_.LoadFromString("a=1\n \t \nb=2"));
148
149 EXPECT_EQ("1", GetNonemptyStringValue("a"));
150 EXPECT_EQ("2", GetNonemptyStringValue("b"));
151 }
152
TEST_F(KeyValueStoreTest,RejectEmptyKeys)153 TEST_F(KeyValueStoreTest, RejectEmptyKeys) {
154 EXPECT_FALSE(store_.LoadFromString("=1"));
155 EXPECT_FALSE(store_.LoadFromString(" =2"));
156
157 // Trying to set an empty (after trimming) key should fail an assert.
158 EXPECT_DEATH(store_.SetString(" ", "3"), "");
159 EXPECT_DEATH(store_.SetBoolean(" ", "4"), "");
160 }
161
TEST_F(KeyValueStoreTest,RejectBogusLines)162 TEST_F(KeyValueStoreTest, RejectBogusLines) {
163 EXPECT_FALSE(store_.LoadFromString("a=1\nbogus\nb=2"));
164 }
165
TEST_F(KeyValueStoreTest,MultilineValue)166 TEST_F(KeyValueStoreTest, MultilineValue) {
167 EXPECT_TRUE(store_.LoadFromString("a=foo\nb=bar\\\n baz \\ \nc=3\n"));
168
169 EXPECT_EQ("foo", GetNonemptyStringValue("a"));
170 EXPECT_EQ("bar baz \\ ", GetNonemptyStringValue("b"));
171 EXPECT_EQ("3", GetNonemptyStringValue("c"));
172 }
173
TEST_F(KeyValueStoreTest,UnterminatedMultilineValue)174 TEST_F(KeyValueStoreTest, UnterminatedMultilineValue) {
175 EXPECT_FALSE(store_.LoadFromString("a=foo\\"));
176 EXPECT_FALSE(store_.LoadFromString("a=foo\\\n"));
177 EXPECT_FALSE(store_.LoadFromString("a=foo\\\n\n# blah\n"));
178 }
179
TEST_F(KeyValueStoreTest,GetKeys)180 TEST_F(KeyValueStoreTest, GetKeys) {
181 map<string, string> entries = {
182 {"1", "apple"}, {"2", "banana"}, {"3", "cherry"}
183 };
184 for (const auto& it : entries) {
185 store_.SetString(it.first, it.second);
186 }
187
188 vector<string> keys = GetMapKeysAsVector(entries);
189 EXPECT_EQ(keys, store_.GetKeys());
190 }
191
192 } // namespace brillo
193