Home | History | Annotate | Download | only in brillo
      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