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. 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 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 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 66 TEST_F(KeyValueStoreTest, EmptyTest) { 67 EXPECT_TRUE(store_.LoadFromString("")); 68 EXPECT_EQ("", store_.SaveToString()); 69 } 70 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 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 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 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 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 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 162 TEST_F(KeyValueStoreTest, RejectBogusLines) { 163 EXPECT_FALSE(store_.LoadFromString("a=1\nbogus\nb=2")); 164 } 165 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 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 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