blob: c1a99d9de982aac6368d3bfc15120c0417f99685 [file] [log] [blame]
Alex Deymoedf1a2b2014-09-23 12:05:56 -07001// 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 <chromeos/key_value_store.h>
6
7#include <map>
8#include <string>
Aaron Kemp35babde2015-02-25 11:08:20 -05009#include <vector>
Alex Deymoedf1a2b2014-09-23 12:05:56 -070010
11#include <base/files/file_util.h>
12#include <base/files/scoped_temp_dir.h>
Daniel Erat9ee4e712015-01-27 10:29:07 -070013#include <base/logging.h>
Alex Deymoedf1a2b2014-09-23 12:05:56 -070014#include <base/strings/string_util.h>
Aaron Kemp35babde2015-02-25 11:08:20 -050015#include <chromeos/map_utils.h>
Alex Deymoedf1a2b2014-09-23 12:05:56 -070016#include <gtest/gtest.h>
17
18using base::FilePath;
19using base::ReadFileToString;
20using std::map;
21using std::string;
Aaron Kemp35babde2015-02-25 11:08:20 -050022using std::vector;
Alex Deymoedf1a2b2014-09-23 12:05:56 -070023
24namespace chromeos {
25
26class KeyValueStoreTest : public ::testing::Test {
27 public:
28 void SetUp() override {
29 CHECK(temp_dir_.CreateUniqueTempDir());
30 temp_file_ = temp_dir_.path().Append("temp.conf");
31 }
32
33 protected:
Daniel Erat9ee4e712015-01-27 10:29:07 -070034 // Returns the value from |store_| corresponding to |key|, or an empty string
35 // if the key is not present. Crashes if the store returns an empty value.
36 string GetNonemptyStringValue(const string& key) {
37 string value;
38 if (store_.GetString(key, &value))
39 CHECK(!value.empty());
40 return value;
41 }
42
Alex Deymoedf1a2b2014-09-23 12:05:56 -070043 base::FilePath temp_file_;
44 base::ScopedTempDir temp_dir_;
45 KeyValueStore store_; // KeyValueStore under test.
46};
47
48TEST_F(KeyValueStoreTest, CommentsAreIgnored) {
Daniel Erat9ee4e712015-01-27 10:29:07 -070049 string blob = "# comment\nA=B\n\n\n#another=comment\n # leading spaces\n";
Alex Deymoedf1a2b2014-09-23 12:05:56 -070050 ASSERT_EQ(blob.size(), base::WriteFile(temp_file_, blob.data(), blob.size()));
Daniel Erat9ee4e712015-01-27 10:29:07 -070051 ASSERT_TRUE(store_.Load(temp_file_));
Alex Deymoedf1a2b2014-09-23 12:05:56 -070052
Daniel Erat9ee4e712015-01-27 10:29:07 -070053 ASSERT_TRUE(store_.Save(temp_file_));
Alex Deymoedf1a2b2014-09-23 12:05:56 -070054 string read_blob;
55 ASSERT_TRUE(ReadFileToString(FilePath(temp_file_), &read_blob));
56 EXPECT_EQ("A=B\n", read_blob);
57}
58
59TEST_F(KeyValueStoreTest, EmptyTest) {
60 ASSERT_EQ(0, base::WriteFile(temp_file_, "", 0));
Daniel Erat9ee4e712015-01-27 10:29:07 -070061 ASSERT_TRUE(store_.Load(temp_file_));
Alex Deymoedf1a2b2014-09-23 12:05:56 -070062
Daniel Erat9ee4e712015-01-27 10:29:07 -070063 ASSERT_TRUE(store_.Save(temp_file_));
Alex Deymoedf1a2b2014-09-23 12:05:56 -070064 string read_blob;
65 ASSERT_TRUE(ReadFileToString(FilePath(temp_file_), &read_blob));
66 EXPECT_EQ("", read_blob);
67}
68
69TEST_F(KeyValueStoreTest, LoadAndReloadTest) {
Daniel Erat9ee4e712015-01-27 10:29:07 -070070 string blob = "A=B\nC=\nFOO=BAR=BAZ\nBAR=BAX\nMISSING=NEWLINE";
Alex Deymoedf1a2b2014-09-23 12:05:56 -070071 ASSERT_EQ(blob.size(), base::WriteFile(temp_file_, blob.data(), blob.size()));
Daniel Erat9ee4e712015-01-27 10:29:07 -070072 ASSERT_TRUE(store_.Load(temp_file_));
Alex Deymoedf1a2b2014-09-23 12:05:56 -070073
Alex Vakulenko05d29042015-01-13 09:39:25 -080074 map<string, string> expected = {{"A", "B"},
75 {"C", ""},
Alex Vakulenko05d29042015-01-13 09:39:25 -080076 {"FOO", "BAR=BAZ"},
77 {"BAR", "BAX"},
78 {"MISSING", "NEWLINE"}};
Alex Deymoedf1a2b2014-09-23 12:05:56 -070079
Daniel Erat9ee4e712015-01-27 10:29:07 -070080 // Test expected values.
Alex Deymoedf1a2b2014-09-23 12:05:56 -070081 string value;
82 for (const auto& it : expected) {
83 EXPECT_TRUE(store_.GetString(it.first, &value));
84 EXPECT_EQ(it.second, value) << "Testing key: " << it.first;
85 }
86
87 // Save, load and test again.
Daniel Erat9ee4e712015-01-27 10:29:07 -070088 ASSERT_TRUE(store_.Save(temp_file_));
Alex Deymoedf1a2b2014-09-23 12:05:56 -070089 KeyValueStore new_store;
Daniel Erat9ee4e712015-01-27 10:29:07 -070090 ASSERT_TRUE(new_store.Load(temp_file_));
Alex Deymoedf1a2b2014-09-23 12:05:56 -070091
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
98TEST_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
111TEST_F(KeyValueStoreTest, BooleanParsingTest) {
112 string blob = "TRUE=true\nfalse=false\nvar=false\nDONT_SHOUT=TRUE\n";
113 ASSERT_EQ(blob.size(), base::WriteFile(temp_file_, blob.data(), blob.size()));
Daniel Erat9ee4e712015-01-27 10:29:07 -0700114 ASSERT_TRUE(store_.Load(temp_file_));
Alex Deymoedf1a2b2014-09-23 12:05:56 -0700115
116 map<string, bool> expected = {
117 {"TRUE", true}, {"false", false}, {"var", false}};
118 bool value;
119 EXPECT_FALSE(store_.GetBoolean("DONT_SHOUT", &value));
120 string str_value;
121 EXPECT_TRUE(store_.GetString("DONT_SHOUT", &str_value));
122
Daniel Erat9ee4e712015-01-27 10:29:07 -0700123 // Test expected values.
Alex Deymoedf1a2b2014-09-23 12:05:56 -0700124 for (const auto& it : expected) {
125 EXPECT_TRUE(store_.GetBoolean(it.first, &value)) << "key: " << it.first;
126 EXPECT_EQ(it.second, value) << "key: " << it.first;
127 }
128}
129
Daniel Erat9ee4e712015-01-27 10:29:07 -0700130TEST_F(KeyValueStoreTest, TrimWhitespaceAroundKey) {
131 string blob = " a=1\nb =2\n c =3\n";
132 ASSERT_EQ(blob.size(), base::WriteFile(temp_file_, blob.data(), blob.size()));
133 ASSERT_TRUE(store_.Load(temp_file_));
134
135 EXPECT_EQ("1", GetNonemptyStringValue("a"));
136 EXPECT_EQ("2", GetNonemptyStringValue("b"));
137 EXPECT_EQ("3", GetNonemptyStringValue("c"));
138
139 // Keys should also be trimmed when setting new values.
140 store_.SetString(" foo ", "4");
141 EXPECT_EQ("4", GetNonemptyStringValue("foo"));
142
143 store_.SetBoolean(" bar ", true);
144 bool value = false;
145 ASSERT_TRUE(store_.GetBoolean("bar", &value));
146 EXPECT_TRUE(value);
147}
148
149TEST_F(KeyValueStoreTest, IgnoreWhitespaceLine) {
150 string blob = "a=1\n \t \nb=2";
151 ASSERT_EQ(blob.size(), base::WriteFile(temp_file_, blob.data(), blob.size()));
152 ASSERT_TRUE(store_.Load(temp_file_));
153
154 EXPECT_EQ("1", GetNonemptyStringValue("a"));
155 EXPECT_EQ("2", GetNonemptyStringValue("b"));
156}
157
158TEST_F(KeyValueStoreTest, RejectEmptyKeys) {
159 string blob = "=1";
160 ASSERT_EQ(blob.size(), base::WriteFile(temp_file_, blob.data(), blob.size()));
161 EXPECT_FALSE(store_.Load(temp_file_));
162
163 blob = " =2";
164 ASSERT_EQ(blob.size(), base::WriteFile(temp_file_, blob.data(), blob.size()));
165 EXPECT_FALSE(store_.Load(temp_file_));
166
167 // Trying to set an empty (after trimming) key should fail an assert.
168 EXPECT_DEATH(store_.SetString(" ", "3"), "");
169 EXPECT_DEATH(store_.SetBoolean(" ", "4"), "");
170}
171
172TEST_F(KeyValueStoreTest, RejectBogusLines) {
173 string blob = "a=1\nbogus\nb=2";
174 ASSERT_EQ(blob.size(), base::WriteFile(temp_file_, blob.data(), blob.size()));
175 EXPECT_FALSE(store_.Load(temp_file_));
176}
177
178TEST_F(KeyValueStoreTest, MultilineValue) {
179 string blob = "a=foo\nb=bar\\\n baz \\ \nc=3\n";
180 ASSERT_EQ(blob.size(), base::WriteFile(temp_file_, blob.data(), blob.size()));
181 ASSERT_TRUE(store_.Load(temp_file_));
182
183 EXPECT_EQ("foo", GetNonemptyStringValue("a"));
184 EXPECT_EQ("bar baz \\ ", GetNonemptyStringValue("b"));
185 EXPECT_EQ("3", GetNonemptyStringValue("c"));
186}
187
188TEST_F(KeyValueStoreTest, UnterminatedMultilineValue) {
189 string blob = "a=foo\\";
190 ASSERT_EQ(blob.size(), base::WriteFile(temp_file_, blob.data(), blob.size()));
191 EXPECT_FALSE(store_.Load(temp_file_));
192
193 blob = "a=foo\\\n";
194 ASSERT_EQ(blob.size(), base::WriteFile(temp_file_, blob.data(), blob.size()));
195 EXPECT_FALSE(store_.Load(temp_file_));
196
197 blob = "a=foo\\\n\n# blah\n";
198 ASSERT_EQ(blob.size(), base::WriteFile(temp_file_, blob.data(), blob.size()));
199 EXPECT_FALSE(store_.Load(temp_file_));
200}
201
Aaron Kemp35babde2015-02-25 11:08:20 -0500202TEST_F(KeyValueStoreTest, GetKeys) {
203 map<string, string> entries = {
204 {"1", "apple"}, {"2", "banana"}, {"3", "cherry"}
205 };
206 for (const auto& it : entries) {
207 store_.SetString(it.first, it.second);
208 }
209
210 vector<string> keys = GetMapKeysAsVector(entries);
211 EXPECT_EQ(keys, store_.GetKeys());
212}
213
Alex Deymoedf1a2b2014-09-23 12:05:56 -0700214} // namespace chromeos