• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <utility>
10 #include <vector>
11 
12 #include <base/files/file_util.h>
13 #include <base/files/scoped_temp_dir.h>
14 #include <base/logging.h>
15 #include <base/strings/string_util.h>
16 #include <brillo/map_utils.h>
17 #include <gtest/gtest.h>
18 
19 using base::FilePath;
20 using base::ReadFileToString;
21 using std::map;
22 using std::string;
23 using std::vector;
24 
25 namespace brillo {
26 
27 class KeyValueStoreTest : public ::testing::Test {
28  protected:
29   // Returns the value from |store_| corresponding to |key|, or an empty string
30   // if the key is not present. Crashes if the store returns an empty value.
GetNonemptyStringValue(const string & key)31   string GetNonemptyStringValue(const string& key) {
32     string value;
33     if (store_.GetString(key, &value))
34       CHECK(!value.empty());
35     return value;
36   }
37 
38   KeyValueStore store_;  // KeyValueStore under test.
39 };
40 
TEST_F(KeyValueStoreTest,MoveConstructor)41 TEST_F(KeyValueStoreTest, MoveConstructor) {
42   store_.SetBoolean("a_boolean", true);
43   store_.SetString("a_string", "a_value");
44 
45   KeyValueStore moved_to(std::move(store_));
46   bool b_value = false;
47   EXPECT_TRUE(moved_to.GetBoolean("a_boolean", &b_value));
48   EXPECT_TRUE(b_value);
49 
50   std::string s_value;
51   EXPECT_TRUE(moved_to.GetString("a_string", &s_value));
52   EXPECT_EQ(s_value, "a_value");
53 }
54 
TEST_F(KeyValueStoreTest,MoveAssignmentOperator)55 TEST_F(KeyValueStoreTest, MoveAssignmentOperator) {
56   store_.SetBoolean("a_boolean", true);
57   store_.SetString("a_string", "a_value");
58 
59   KeyValueStore moved_to;
60   moved_to = std::move(store_);
61   bool b_value = false;
62   EXPECT_TRUE(moved_to.GetBoolean("a_boolean", &b_value));
63   EXPECT_TRUE(b_value);
64 
65   std::string s_value;
66   EXPECT_TRUE(moved_to.GetString("a_string", &s_value));
67   EXPECT_EQ(s_value, "a_value");
68 }
69 
TEST_F(KeyValueStoreTest,LoadAndSaveFromFile)70 TEST_F(KeyValueStoreTest, LoadAndSaveFromFile) {
71   base::ScopedTempDir temp_dir_;
72   CHECK(temp_dir_.CreateUniqueTempDir());
73   base::FilePath temp_file_ = temp_dir_.GetPath().Append("temp.conf");
74   base::FilePath saved_temp_file_ =
75       temp_dir_.GetPath().Append("saved_temp.conf");
76 
77   string blob = "A=B\n# Comment\n";
78   ASSERT_EQ(blob.size(), base::WriteFile(temp_file_, blob.data(), blob.size()));
79   ASSERT_TRUE(store_.Load(temp_file_));
80 
81   string value;
82   EXPECT_TRUE(store_.GetString("A", &value));
83   EXPECT_EQ("B", value);
84 
85   ASSERT_TRUE(store_.Save(saved_temp_file_));
86   string read_blob;
87   ASSERT_TRUE(ReadFileToString(FilePath(saved_temp_file_), &read_blob));
88   EXPECT_EQ("A=B\n", read_blob);
89 }
90 
TEST_F(KeyValueStoreTest,CommentsAreIgnored)91 TEST_F(KeyValueStoreTest, CommentsAreIgnored) {
92   EXPECT_TRUE(store_.LoadFromString(
93       "# comment\nA=B\n\n\n#another=comment\n  # leading spaces\n"));
94   EXPECT_EQ("A=B\n", store_.SaveToString());
95 }
96 
TEST_F(KeyValueStoreTest,EmptyTest)97 TEST_F(KeyValueStoreTest, EmptyTest) {
98   EXPECT_TRUE(store_.LoadFromString(""));
99   EXPECT_EQ("", store_.SaveToString());
100 }
101 
TEST_F(KeyValueStoreTest,LoadAndReloadTest)102 TEST_F(KeyValueStoreTest, LoadAndReloadTest) {
103   EXPECT_TRUE(store_.LoadFromString(
104       "A=B\nC=\nFOO=BAR=BAZ\nBAR=BAX\nMISSING=NEWLINE"));
105 
106   map<string, string> expected = {{"A", "B"},
107                                   {"C", ""},
108                                   {"FOO", "BAR=BAZ"},
109                                   {"BAR", "BAX"},
110                                   {"MISSING", "NEWLINE"}};
111 
112   // Test expected values.
113   string value;
114   for (const auto& it : expected) {
115     EXPECT_TRUE(store_.GetString(it.first, &value));
116     EXPECT_EQ(it.second, value) << "Testing key: " << it.first;
117   }
118 
119   // Save, load and test again.
120   KeyValueStore new_store;
121   ASSERT_TRUE(new_store.LoadFromString(store_.SaveToString()));
122 
123   for (const auto& it : expected) {
124     EXPECT_TRUE(new_store.GetString(it.first, &value)) << "key: " << it.first;
125     EXPECT_EQ(it.second, value) << "key: " << it.first;
126   }
127 }
128 
TEST_F(KeyValueStoreTest,MultipleLoads)129 TEST_F(KeyValueStoreTest, MultipleLoads) {
130   // The internal state is not cleared before loading.
131   EXPECT_TRUE(store_.LoadFromString("A=B\n"));
132   EXPECT_TRUE(store_.LoadFromString("B=C\n"));
133   EXPECT_EQ(2, store_.GetKeys().size());
134 }
135 
TEST_F(KeyValueStoreTest,PartialLoad)136 TEST_F(KeyValueStoreTest, PartialLoad) {
137   // The 2nd line is broken, but the pair from the first line should be kept.
138   EXPECT_FALSE(store_.LoadFromString("A=B\n=\n"));
139   EXPECT_EQ(1, store_.GetKeys().size());
140 }
141 
TEST_F(KeyValueStoreTest,Clear)142 TEST_F(KeyValueStoreTest, Clear) {
143   EXPECT_TRUE(store_.LoadFromString("A=B\n"));
144   EXPECT_EQ(1, store_.GetKeys().size());
145   store_.Clear();
146   EXPECT_EQ(0, store_.GetKeys().size());
147 }
148 
TEST_F(KeyValueStoreTest,SimpleBooleanTest)149 TEST_F(KeyValueStoreTest, SimpleBooleanTest) {
150   bool result;
151   EXPECT_FALSE(store_.GetBoolean("A", &result));
152 
153   store_.SetBoolean("A", true);
154   EXPECT_TRUE(store_.GetBoolean("A", &result));
155   EXPECT_TRUE(result);
156 
157   store_.SetBoolean("A", false);
158   EXPECT_TRUE(store_.GetBoolean("A", &result));
159   EXPECT_FALSE(result);
160 }
161 
TEST_F(KeyValueStoreTest,BooleanParsingTest)162 TEST_F(KeyValueStoreTest, BooleanParsingTest) {
163   string blob = "TRUE=true\nfalse=false\nvar=false\nDONT_SHOUT=TRUE\n";
164   EXPECT_TRUE(store_.LoadFromString(blob));
165 
166   map<string, bool> expected = {
167       {"TRUE", true}, {"false", false}, {"var", false}};
168   bool value;
169   EXPECT_FALSE(store_.GetBoolean("DONT_SHOUT", &value));
170   string str_value;
171   EXPECT_TRUE(store_.GetString("DONT_SHOUT", &str_value));
172 
173   // Test expected values.
174   for (const auto& it : expected) {
175     EXPECT_TRUE(store_.GetBoolean(it.first, &value)) << "key: " << it.first;
176     EXPECT_EQ(it.second, value) << "key: " << it.first;
177   }
178 }
179 
TEST_F(KeyValueStoreTest,TrimWhitespaceAroundKey)180 TEST_F(KeyValueStoreTest, TrimWhitespaceAroundKey) {
181   EXPECT_TRUE(store_.LoadFromString("  a=1\nb  =2\n c =3\n"));
182 
183   EXPECT_EQ("1", GetNonemptyStringValue("a"));
184   EXPECT_EQ("2", GetNonemptyStringValue("b"));
185   EXPECT_EQ("3", GetNonemptyStringValue("c"));
186 
187   // Keys should also be trimmed when setting new values.
188   store_.SetString(" foo ", "4");
189   EXPECT_EQ("4", GetNonemptyStringValue("foo"));
190 
191   store_.SetBoolean(" bar ", true);
192   bool value = false;
193   ASSERT_TRUE(store_.GetBoolean("bar", &value));
194   EXPECT_TRUE(value);
195 }
196 
TEST_F(KeyValueStoreTest,IgnoreWhitespaceLine)197 TEST_F(KeyValueStoreTest, IgnoreWhitespaceLine) {
198   EXPECT_TRUE(store_.LoadFromString("a=1\n \t \nb=2"));
199 
200   EXPECT_EQ("1", GetNonemptyStringValue("a"));
201   EXPECT_EQ("2", GetNonemptyStringValue("b"));
202 }
203 
TEST_F(KeyValueStoreTest,RejectEmptyKeys)204 TEST_F(KeyValueStoreTest, RejectEmptyKeys) {
205   EXPECT_FALSE(store_.LoadFromString("=1"));
206   EXPECT_FALSE(store_.LoadFromString(" =2"));
207 
208   // Trying to set an empty (after trimming) key should fail an assert.
209   EXPECT_DEATH(store_.SetString(" ", "3"), "");
210   EXPECT_DEATH(store_.SetBoolean(" ", "4"), "");
211 }
212 
TEST_F(KeyValueStoreTest,RejectBogusLines)213 TEST_F(KeyValueStoreTest, RejectBogusLines) {
214   EXPECT_FALSE(store_.LoadFromString("a=1\nbogus\nb=2"));
215 }
216 
TEST_F(KeyValueStoreTest,MultilineValue)217 TEST_F(KeyValueStoreTest, MultilineValue) {
218   EXPECT_TRUE(store_.LoadFromString("a=foo\nb=bar\\\n  baz \\ \nc=3\n"));
219 
220   EXPECT_EQ("foo", GetNonemptyStringValue("a"));
221   EXPECT_EQ("bar  baz \\ ", GetNonemptyStringValue("b"));
222   EXPECT_EQ("3", GetNonemptyStringValue("c"));
223 }
224 
TEST_F(KeyValueStoreTest,UnterminatedMultilineValue)225 TEST_F(KeyValueStoreTest, UnterminatedMultilineValue) {
226   EXPECT_FALSE(store_.LoadFromString("a=foo\\"));
227   EXPECT_FALSE(store_.LoadFromString("a=foo\\\n"));
228   EXPECT_FALSE(store_.LoadFromString("a=foo\\\n\n# blah\n"));
229 }
230 
TEST_F(KeyValueStoreTest,GetKeys)231 TEST_F(KeyValueStoreTest, GetKeys) {
232   map<string, string> entries = {
233     {"1", "apple"}, {"2", "banana"}, {"3", "cherry"}
234   };
235   for (const auto& it : entries) {
236     store_.SetString(it.first, it.second);
237   }
238 
239   vector<string> keys = GetMapKeysAsVector(entries);
240   EXPECT_EQ(keys, store_.GetKeys());
241 }
242 
243 }  // namespace brillo
244