blob: 702953d8f98a13bfd9eebde0bd35b93da13f2d6d [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>
9
10#include <base/files/file_util.h>
11#include <base/files/scoped_temp_dir.h>
Daniel Erat9ee4e712015-01-27 10:29:07 -070012#include <base/logging.h>
Alex Deymoedf1a2b2014-09-23 12:05:56 -070013#include <base/strings/string_util.h>
14#include <gtest/gtest.h>
15
16using base::FilePath;
17using base::ReadFileToString;
18using std::map;
19using std::string;
20
21namespace chromeos {
22
23class KeyValueStoreTest : public ::testing::Test {
24 public:
25 void SetUp() override {
26 CHECK(temp_dir_.CreateUniqueTempDir());
27 temp_file_ = temp_dir_.path().Append("temp.conf");
28 }
29
30 protected:
Daniel Erat9ee4e712015-01-27 10:29:07 -070031 // Returns the value from |store_| corresponding to |key|, or an empty string
32 // if the key is not present. Crashes if the store returns an empty value.
33 string GetNonemptyStringValue(const string& key) {
34 string value;
35 if (store_.GetString(key, &value))
36 CHECK(!value.empty());
37 return value;
38 }
39
Alex Deymoedf1a2b2014-09-23 12:05:56 -070040 base::FilePath temp_file_;
41 base::ScopedTempDir temp_dir_;
42 KeyValueStore store_; // KeyValueStore under test.
43};
44
45TEST_F(KeyValueStoreTest, CommentsAreIgnored) {
Daniel Erat9ee4e712015-01-27 10:29:07 -070046 string blob = "# comment\nA=B\n\n\n#another=comment\n # leading spaces\n";
Alex Deymoedf1a2b2014-09-23 12:05:56 -070047 ASSERT_EQ(blob.size(), base::WriteFile(temp_file_, blob.data(), blob.size()));
Daniel Erat9ee4e712015-01-27 10:29:07 -070048 ASSERT_TRUE(store_.Load(temp_file_));
Alex Deymoedf1a2b2014-09-23 12:05:56 -070049
Daniel Erat9ee4e712015-01-27 10:29:07 -070050 ASSERT_TRUE(store_.Save(temp_file_));
Alex Deymoedf1a2b2014-09-23 12:05:56 -070051 string read_blob;
52 ASSERT_TRUE(ReadFileToString(FilePath(temp_file_), &read_blob));
53 EXPECT_EQ("A=B\n", read_blob);
54}
55
56TEST_F(KeyValueStoreTest, EmptyTest) {
57 ASSERT_EQ(0, base::WriteFile(temp_file_, "", 0));
Daniel Erat9ee4e712015-01-27 10:29:07 -070058 ASSERT_TRUE(store_.Load(temp_file_));
Alex Deymoedf1a2b2014-09-23 12:05:56 -070059
Daniel Erat9ee4e712015-01-27 10:29:07 -070060 ASSERT_TRUE(store_.Save(temp_file_));
Alex Deymoedf1a2b2014-09-23 12:05:56 -070061 string read_blob;
62 ASSERT_TRUE(ReadFileToString(FilePath(temp_file_), &read_blob));
63 EXPECT_EQ("", read_blob);
64}
65
66TEST_F(KeyValueStoreTest, LoadAndReloadTest) {
Daniel Erat9ee4e712015-01-27 10:29:07 -070067 string blob = "A=B\nC=\nFOO=BAR=BAZ\nBAR=BAX\nMISSING=NEWLINE";
Alex Deymoedf1a2b2014-09-23 12:05:56 -070068 ASSERT_EQ(blob.size(), base::WriteFile(temp_file_, blob.data(), blob.size()));
Daniel Erat9ee4e712015-01-27 10:29:07 -070069 ASSERT_TRUE(store_.Load(temp_file_));
Alex Deymoedf1a2b2014-09-23 12:05:56 -070070
Alex Vakulenko05d29042015-01-13 09:39:25 -080071 map<string, string> expected = {{"A", "B"},
72 {"C", ""},
Alex Vakulenko05d29042015-01-13 09:39:25 -080073 {"FOO", "BAR=BAZ"},
74 {"BAR", "BAX"},
75 {"MISSING", "NEWLINE"}};
Alex Deymoedf1a2b2014-09-23 12:05:56 -070076
Daniel Erat9ee4e712015-01-27 10:29:07 -070077 // Test expected values.
Alex Deymoedf1a2b2014-09-23 12:05:56 -070078 string value;
79 for (const auto& it : expected) {
80 EXPECT_TRUE(store_.GetString(it.first, &value));
81 EXPECT_EQ(it.second, value) << "Testing key: " << it.first;
82 }
83
84 // Save, load and test again.
Daniel Erat9ee4e712015-01-27 10:29:07 -070085 ASSERT_TRUE(store_.Save(temp_file_));
Alex Deymoedf1a2b2014-09-23 12:05:56 -070086 KeyValueStore new_store;
Daniel Erat9ee4e712015-01-27 10:29:07 -070087 ASSERT_TRUE(new_store.Load(temp_file_));
Alex Deymoedf1a2b2014-09-23 12:05:56 -070088
89 for (const auto& it : expected) {
90 EXPECT_TRUE(new_store.GetString(it.first, &value)) << "key: " << it.first;
91 EXPECT_EQ(it.second, value) << "key: " << it.first;
92 }
93}
94
95TEST_F(KeyValueStoreTest, SimpleBooleanTest) {
96 bool result;
97 EXPECT_FALSE(store_.GetBoolean("A", &result));
98
99 store_.SetBoolean("A", true);
100 EXPECT_TRUE(store_.GetBoolean("A", &result));
101 EXPECT_TRUE(result);
102
103 store_.SetBoolean("A", false);
104 EXPECT_TRUE(store_.GetBoolean("A", &result));
105 EXPECT_FALSE(result);
106}
107
108TEST_F(KeyValueStoreTest, BooleanParsingTest) {
109 string blob = "TRUE=true\nfalse=false\nvar=false\nDONT_SHOUT=TRUE\n";
110 ASSERT_EQ(blob.size(), base::WriteFile(temp_file_, blob.data(), blob.size()));
Daniel Erat9ee4e712015-01-27 10:29:07 -0700111 ASSERT_TRUE(store_.Load(temp_file_));
Alex Deymoedf1a2b2014-09-23 12:05:56 -0700112
113 map<string, bool> expected = {
114 {"TRUE", true}, {"false", false}, {"var", false}};
115 bool value;
116 EXPECT_FALSE(store_.GetBoolean("DONT_SHOUT", &value));
117 string str_value;
118 EXPECT_TRUE(store_.GetString("DONT_SHOUT", &str_value));
119
Daniel Erat9ee4e712015-01-27 10:29:07 -0700120 // Test expected values.
Alex Deymoedf1a2b2014-09-23 12:05:56 -0700121 for (const auto& it : expected) {
122 EXPECT_TRUE(store_.GetBoolean(it.first, &value)) << "key: " << it.first;
123 EXPECT_EQ(it.second, value) << "key: " << it.first;
124 }
125}
126
Daniel Erat9ee4e712015-01-27 10:29:07 -0700127TEST_F(KeyValueStoreTest, TrimWhitespaceAroundKey) {
128 string blob = " a=1\nb =2\n c =3\n";
129 ASSERT_EQ(blob.size(), base::WriteFile(temp_file_, blob.data(), blob.size()));
130 ASSERT_TRUE(store_.Load(temp_file_));
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
146TEST_F(KeyValueStoreTest, IgnoreWhitespaceLine) {
147 string blob = "a=1\n \t \nb=2";
148 ASSERT_EQ(blob.size(), base::WriteFile(temp_file_, blob.data(), blob.size()));
149 ASSERT_TRUE(store_.Load(temp_file_));
150
151 EXPECT_EQ("1", GetNonemptyStringValue("a"));
152 EXPECT_EQ("2", GetNonemptyStringValue("b"));
153}
154
155TEST_F(KeyValueStoreTest, RejectEmptyKeys) {
156 string blob = "=1";
157 ASSERT_EQ(blob.size(), base::WriteFile(temp_file_, blob.data(), blob.size()));
158 EXPECT_FALSE(store_.Load(temp_file_));
159
160 blob = " =2";
161 ASSERT_EQ(blob.size(), base::WriteFile(temp_file_, blob.data(), blob.size()));
162 EXPECT_FALSE(store_.Load(temp_file_));
163
164 // Trying to set an empty (after trimming) key should fail an assert.
165 EXPECT_DEATH(store_.SetString(" ", "3"), "");
166 EXPECT_DEATH(store_.SetBoolean(" ", "4"), "");
167}
168
169TEST_F(KeyValueStoreTest, RejectBogusLines) {
170 string blob = "a=1\nbogus\nb=2";
171 ASSERT_EQ(blob.size(), base::WriteFile(temp_file_, blob.data(), blob.size()));
172 EXPECT_FALSE(store_.Load(temp_file_));
173}
174
175TEST_F(KeyValueStoreTest, MultilineValue) {
176 string blob = "a=foo\nb=bar\\\n baz \\ \nc=3\n";
177 ASSERT_EQ(blob.size(), base::WriteFile(temp_file_, blob.data(), blob.size()));
178 ASSERT_TRUE(store_.Load(temp_file_));
179
180 EXPECT_EQ("foo", GetNonemptyStringValue("a"));
181 EXPECT_EQ("bar baz \\ ", GetNonemptyStringValue("b"));
182 EXPECT_EQ("3", GetNonemptyStringValue("c"));
183}
184
185TEST_F(KeyValueStoreTest, UnterminatedMultilineValue) {
186 string blob = "a=foo\\";
187 ASSERT_EQ(blob.size(), base::WriteFile(temp_file_, blob.data(), blob.size()));
188 EXPECT_FALSE(store_.Load(temp_file_));
189
190 blob = "a=foo\\\n";
191 ASSERT_EQ(blob.size(), base::WriteFile(temp_file_, blob.data(), blob.size()));
192 EXPECT_FALSE(store_.Load(temp_file_));
193
194 blob = "a=foo\\\n\n# blah\n";
195 ASSERT_EQ(blob.size(), base::WriteFile(temp_file_, blob.data(), blob.size()));
196 EXPECT_FALSE(store_.Load(temp_file_));
197}
198
Alex Deymoedf1a2b2014-09-23 12:05:56 -0700199} // namespace chromeos