// // Copyright (C) 2012 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #include "shill/key_file_store.h" #include <sys/stat.h> #include <memory> #include <set> #include <string> #include <vector> #include <base/files/file_enumerator.h> #include <base/files/file_util.h> #include <base/files/scoped_temp_dir.h> #include <base/stl_util.h> #include <base/strings/string_number_conversions.h> #include <base/strings/stringprintf.h> #include <gtest/gtest.h> #include "shill/key_value_store.h" using base::FileEnumerator; using base::FilePath; using std::set; using std::string; using std::unique_ptr; using std::vector; using testing::Test; namespace shill { namespace { const char kPlainText[] = "This is a test!"; const char kROT47Text[] = "rot47:%9:D :D 2 E6DEP"; } // namespace class KeyFileStoreTest : public Test { public: KeyFileStoreTest() {} virtual void SetUp() { ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); test_file_ = temp_dir_.path().Append("test-key-file-store"); store_.reset(new KeyFileStore(test_file_)); } virtual void TearDown() { ASSERT_TRUE(temp_dir_.Delete()); } protected: string ReadKeyFile(); void WriteKeyFile(string data); base::ScopedTempDir temp_dir_; FilePath test_file_; unique_ptr<KeyFileStore> store_; }; string KeyFileStoreTest::ReadKeyFile() { string data; EXPECT_TRUE(base::ReadFileToString(test_file_, &data)); return data; } void KeyFileStoreTest::WriteKeyFile(string data) { EXPECT_EQ(data.size(), base::WriteFile(test_file_, data.data(), data.size())); } TEST_F(KeyFileStoreTest, OpenClose) { EXPECT_FALSE(store_->key_file_); EXPECT_FALSE(store_->IsNonEmpty()); ASSERT_TRUE(store_->Open()); EXPECT_TRUE(store_->key_file_); EXPECT_EQ(1, store_->crypto_.cryptos_.size()); ASSERT_TRUE(store_->Close()); EXPECT_FALSE(store_->key_file_); FileEnumerator file_enumerator(temp_dir_.path(), false /* not recursive */, FileEnumerator::FILES); // Verify that the file actually got written with the right name. EXPECT_EQ(test_file_.value(), file_enumerator.Next().value()); FileEnumerator::FileInfo file_info = file_enumerator.GetInfo(); // Verify that the profile is a regular file, readable and writeable by the // owner only. EXPECT_EQ(S_IFREG | S_IRUSR | S_IWUSR, file_info.stat().st_mode); ASSERT_TRUE(store_->Open()); EXPECT_TRUE(store_->key_file_); ASSERT_TRUE(store_->Close()); EXPECT_FALSE(store_->key_file_); ASSERT_TRUE(store_->Open()); // Replace file with directory, to force Flush() to fail. ASSERT_TRUE(base::DeleteFile(test_file_, false)); ASSERT_TRUE(base::CreateDirectory(test_file_)); ASSERT_FALSE(store_->Close()); EXPECT_FALSE(store_->key_file_); } TEST_F(KeyFileStoreTest, OpenFail) { WriteKeyFile("garbage\n"); EXPECT_FALSE(store_->Open()); EXPECT_FALSE(store_->key_file_); } TEST_F(KeyFileStoreTest, MarkAsCorrupted) { EXPECT_FALSE(store_->MarkAsCorrupted()); EXPECT_FALSE(store_->IsNonEmpty()); WriteKeyFile("garbage\n"); EXPECT_TRUE(store_->IsNonEmpty()); EXPECT_TRUE(base::PathExists(test_file_)); EXPECT_TRUE(store_->MarkAsCorrupted()); EXPECT_FALSE(store_->IsNonEmpty()); EXPECT_FALSE(base::PathExists(test_file_)); EXPECT_TRUE(base::PathExists(FilePath(test_file_.value() + ".corrupted"))); } TEST_F(KeyFileStoreTest, GetGroups) { static const char kGroupA[] = "g-a"; static const char kGroupB[] = "g-b"; static const char kGroupC[] = "g-c"; WriteKeyFile(base::StringPrintf("[%s]\n" "[%s]\n" "[%s]\n", kGroupA, kGroupB, kGroupC)); EXPECT_TRUE(store_->IsNonEmpty()); ASSERT_TRUE(store_->Open()); set<string> groups = store_->GetGroups(); EXPECT_EQ(3, groups.size()); EXPECT_TRUE(ContainsKey(groups, kGroupA)); EXPECT_TRUE(ContainsKey(groups, kGroupB)); EXPECT_TRUE(ContainsKey(groups, kGroupC)); EXPECT_FALSE(ContainsKey(groups, "g-x")); ASSERT_TRUE(store_->Close()); } TEST_F(KeyFileStoreTest, GetGroupsWithKey) { static const char kGroupA[] = "g-a"; static const char kGroupB[] = "g-b"; static const char kGroupC[] = "g-c"; static const char kKeyA[] = "k-a"; static const char kKeyB[] = "k-b"; static const char kValue[] = "true"; WriteKeyFile(base::StringPrintf("[%s]\n" "%s=%s\n" "[%s]\n" "%s=%s\n" "%s=%s\n" "[%s]\n" "%s=%s\n", kGroupA, kKeyA, kValue, kGroupB, kKeyA, kValue, kKeyB, kValue, kGroupC, kKeyB, kValue)); EXPECT_TRUE(store_->IsNonEmpty()); ASSERT_TRUE(store_->Open()); set<string> groups_a = store_->GetGroupsWithKey(kKeyA); EXPECT_EQ(2, groups_a.size()); EXPECT_TRUE(ContainsKey(groups_a, kGroupA)); EXPECT_TRUE(ContainsKey(groups_a, kGroupB)); set<string> groups_b = store_->GetGroupsWithKey(kKeyB); EXPECT_EQ(2, groups_b.size()); EXPECT_TRUE(ContainsKey(groups_b, kGroupB)); EXPECT_TRUE(ContainsKey(groups_b, kGroupC)); ASSERT_TRUE(store_->Close()); } TEST_F(KeyFileStoreTest, ContainsGroup) { static const char kGroupA[] = "group-a"; static const char kGroupB[] = "group-b"; static const char kGroupC[] = "group-c"; WriteKeyFile(base::StringPrintf("[%s]\n" "[%s]\n" "[%s]\n", kGroupA, kGroupB, kGroupC)); ASSERT_TRUE(store_->Open()); EXPECT_TRUE(store_->ContainsGroup(kGroupA)); EXPECT_TRUE(store_->ContainsGroup(kGroupB)); EXPECT_TRUE(store_->ContainsGroup(kGroupC)); EXPECT_FALSE(store_->ContainsGroup("group-d")); ASSERT_TRUE(store_->Close()); } TEST_F(KeyFileStoreTest, GetGroupsWithProperties) { static const char kGroupA[] = "group-a"; static const char kGroupB[] = "group-b"; static const char kGroupC[] = "group-c"; static const char kAttributeA[] = "attr-a"; static const char kAttributeB[] = "attr-b"; static const char kAttributeC[] = "attr-c"; static const char kValueA_0[] = "val-a"; static const char kValueA_1[] = "val-b"; static const int kValueB_0 = 1; static const int kValueB_1 = 2; static const bool kValueC_0 = true; static const char kValueC_0_string[] = "true"; static const bool kValueC_1 = false; static const char kValueC_1_string[] = "false"; WriteKeyFile(base::StringPrintf("[%s]\n" "%s=%s\n" "%s=%d\n" "%s=%s\n" "[%s]\n" "%s=%s\n" "%s=%d\n" "%s=%s\n" "[%s]\n" "%s=%s\n" "%s=%d\n" "%s=%s\n", kGroupA, kAttributeA, kValueA_0, kAttributeB, kValueB_0, kAttributeC, kValueC_0_string, kGroupB, kAttributeA, kValueA_0, kAttributeB, kValueB_1, kAttributeC, kValueC_0_string, kGroupC, kAttributeA, kValueA_0, kAttributeB, kValueB_0, kAttributeC, kValueC_1_string)); ASSERT_TRUE(store_->Open()); { KeyValueStore args; args.SetString(kAttributeA, kValueA_0); args.SetInt(kAttributeB, kValueB_0); set<string> results = store_->GetGroupsWithProperties(args); EXPECT_EQ(2, results.size()); EXPECT_TRUE(results.find(kGroupA) != results.end()); EXPECT_TRUE(results.find(kGroupC) != results.end()); } { KeyValueStore args; args.SetString(kAttributeA, kValueA_0); args.SetBool(kAttributeC, kValueC_0); set<string> results = store_->GetGroupsWithProperties(args); EXPECT_EQ(2, results.size()); EXPECT_TRUE(results.find(kGroupA) != results.end()); EXPECT_TRUE(results.find(kGroupB) != results.end()); } { KeyValueStore args; args.SetBool(kAttributeC, kValueC_1); set<string> results = store_->GetGroupsWithProperties(args); EXPECT_EQ(1, results.size()); EXPECT_TRUE(results.find(kGroupC) != results.end()); } { KeyValueStore args; args.SetString(kAttributeA, kValueA_0); set<string> results = store_->GetGroupsWithProperties(args); EXPECT_EQ(3, results.size()); EXPECT_TRUE(results.find(kGroupA) != results.end()); EXPECT_TRUE(results.find(kGroupB) != results.end()); EXPECT_TRUE(results.find(kGroupC) != results.end()); } { KeyValueStore args; args.SetString(kAttributeA, kValueA_1); set<string> results = store_->GetGroupsWithProperties(args); EXPECT_EQ(0, results.size()); } ASSERT_TRUE(store_->Close()); } TEST_F(KeyFileStoreTest, DeleteKey) { static const char kGroup[] = "the-group"; static const char kKeyDead[] = "dead"; static const char kKeyAlive[] = "alive"; const int kValueAlive = 3; WriteKeyFile(base::StringPrintf("[%s]\n" "%s=5\n" "%s=%d\n", kGroup, kKeyDead, kKeyAlive, kValueAlive)); ASSERT_TRUE(store_->Open()); EXPECT_TRUE(store_->DeleteKey(kGroup, kKeyDead)); EXPECT_TRUE(store_->DeleteKey(kGroup, "random-key")); EXPECT_FALSE(store_->DeleteKey("random-group", kKeyAlive)); ASSERT_TRUE(store_->Close()); EXPECT_EQ(base::StringPrintf("[%s]\n" "%s=%d\n", kGroup, kKeyAlive, kValueAlive), ReadKeyFile()); } TEST_F(KeyFileStoreTest, DeleteGroup) { static const char kGroupA[] = "group-a"; static const char kGroupB[] = "group-b"; static const char kGroupC[] = "group-c"; WriteKeyFile(base::StringPrintf("[%s]\n" "[%s]\n" "key-to-be-deleted=true\n" "[%s]\n", kGroupA, kGroupB, kGroupC)); ASSERT_TRUE(store_->Open()); EXPECT_TRUE(store_->DeleteGroup(kGroupB)); EXPECT_TRUE(store_->DeleteGroup("group-d")); ASSERT_TRUE(store_->Close()); EXPECT_EQ(base::StringPrintf("[%s]\n" "\n" "[%s]\n", kGroupA, kGroupC), ReadKeyFile()); } TEST_F(KeyFileStoreTest, GetString) { static const char kGroup[] = "something"; static const char kKey[] = "foo"; static const char kValue[] = "bar"; WriteKeyFile(base::StringPrintf("[%s]\n" "%s=%s\n", kGroup, kKey, kValue)); ASSERT_TRUE(store_->Open()); string value; EXPECT_TRUE(store_->GetString(kGroup, kKey, &value)); EXPECT_EQ(kValue, value); EXPECT_FALSE(store_->GetString("something-else", kKey, &value)); EXPECT_FALSE(store_->GetString(kGroup, "bar", &value)); EXPECT_TRUE(store_->GetString(kGroup, kKey, nullptr)); ASSERT_TRUE(store_->Close()); } TEST_F(KeyFileStoreTest, SetString) { static const char kGroup[] = "string-group"; static const char kKey1[] = "test-string"; static const char kValue1[] = "foo"; static const char kKey2[] = "empty-string"; static const char kValue2[] = ""; ASSERT_TRUE(store_->Open()); ASSERT_TRUE(store_->SetString(kGroup, kKey1, kValue1)); ASSERT_TRUE(store_->SetString(kGroup, kKey2, kValue2)); ASSERT_TRUE(store_->Close()); EXPECT_EQ(base::StringPrintf("[%s]\n" "%s=%s\n" "%s=%s\n", kGroup, kKey1, kValue1, kKey2, kValue2), ReadKeyFile()); } TEST_F(KeyFileStoreTest, GetBool) { static const char kGroup[] = "boo"; static const char kKeyTrue[] = "foo"; static const char kKeyFalse[] = "bar"; static const char kKeyBad[] = "zoo"; WriteKeyFile(base::StringPrintf("[%s]\n" "%s=true\n" "%s=false\n" "%s=moo\n", kGroup, kKeyTrue, kKeyFalse, kKeyBad)); ASSERT_TRUE(store_->Open()); { bool value = true; EXPECT_TRUE(store_->GetBool(kGroup, kKeyFalse, &value)); EXPECT_FALSE(value); } { bool value = false; EXPECT_TRUE(store_->GetBool(kGroup, kKeyTrue, &value)); EXPECT_TRUE(value); } { bool value; EXPECT_FALSE(store_->GetBool(kGroup, kKeyBad, &value)); EXPECT_FALSE(store_->GetBool(kGroup, "unknown", &value)); EXPECT_FALSE(store_->GetBool("unknown", kKeyTrue, &value)); } EXPECT_TRUE(store_->GetBool(kGroup, kKeyFalse, nullptr)); ASSERT_TRUE(store_->Close()); } TEST_F(KeyFileStoreTest, SetBool) { static const char kGroup[] = "bool-group"; static const char kKeyTrue[] = "test-true-bool"; static const char kKeyFalse[] = "test-false-bool"; ASSERT_TRUE(store_->Open()); ASSERT_TRUE(store_->SetBool(kGroup, kKeyTrue, true)); ASSERT_TRUE(store_->SetBool(kGroup, kKeyFalse, false)); ASSERT_TRUE(store_->Close()); EXPECT_EQ(base::StringPrintf("[%s]\n" "%s=true\n" "%s=false\n", kGroup, kKeyTrue, kKeyFalse), ReadKeyFile()); } TEST_F(KeyFileStoreTest, GetInt) { static const char kGroup[] = "numbers"; static const char kKeyPos[] = "pos"; static const char kKeyNeg[] = "neg"; static const char kKeyBad[] = "bad"; const int kValuePos = 50; const int kValueNeg = -20; static const char kValueBad[] = "nan"; WriteKeyFile(base::StringPrintf("[%s]\n" "%s=%d\n" "%s=%d\n" "%s=%s\n", kGroup, kKeyPos, kValuePos, kKeyNeg, kValueNeg, kKeyBad, kValueBad)); ASSERT_TRUE(store_->Open()); { int value = 0; EXPECT_TRUE(store_->GetInt(kGroup, kKeyNeg, &value)); EXPECT_EQ(kValueNeg, value); } { int value = 0; EXPECT_TRUE(store_->GetInt(kGroup, kKeyPos, &value)); EXPECT_EQ(kValuePos, value); } { int value; EXPECT_FALSE(store_->GetInt(kGroup, kKeyBad, &value)); EXPECT_FALSE(store_->GetInt(kGroup, "invalid", &value)); EXPECT_FALSE(store_->GetInt("invalid", kKeyPos, &value)); } EXPECT_TRUE(store_->GetInt(kGroup, kKeyPos, nullptr)); ASSERT_TRUE(store_->Close()); } TEST_F(KeyFileStoreTest, SetInt) { static const char kGroup[] = "int-group"; static const char kKey1[] = "test-int"; static const char kKey2[] = "test-negative"; const int kValue1 = 5; const int kValue2 = -10; ASSERT_TRUE(store_->Open()); ASSERT_TRUE(store_->SetInt(kGroup, kKey1, kValue1)); ASSERT_TRUE(store_->SetInt(kGroup, kKey2, kValue2)); ASSERT_TRUE(store_->Close()); EXPECT_EQ(base::StringPrintf("[%s]\n" "%s=%d\n" "%s=%d\n", kGroup, kKey1, kValue1, kKey2, kValue2), ReadKeyFile()); } TEST_F(KeyFileStoreTest, GetUint64) { static const char kGroup[] = "numbers"; static const char kKeyGood[] = "good"; static const char kKeyBad[] = "bad"; const uint64_t kValueGood = 0xFEDCBA9876543210LL; static const char kValueBad[] = "nan"; // Use base::Uint64ToString() instead of using something like "%llu" // (not correct for native 64 bit architectures) or PRIu64 (does not // work correctly using cros_workon_make due to include intricacies). WriteKeyFile(base::StringPrintf("[%s]\n" "%s=%s\n" "%s=%s\n", kGroup, kKeyGood, base::Uint64ToString(kValueGood).c_str(), kKeyBad, kValueBad)); ASSERT_TRUE(store_->Open()); { uint64_t value = 0; EXPECT_TRUE(store_->GetUint64(kGroup, kKeyGood, &value)); EXPECT_EQ(kValueGood, value); } { uint64_t value; EXPECT_FALSE(store_->GetUint64(kGroup, kKeyBad, &value)); EXPECT_FALSE(store_->GetUint64(kGroup, "invalid", &value)); EXPECT_FALSE(store_->GetUint64("invalid", kKeyGood, &value)); } EXPECT_TRUE(store_->GetUint64(kGroup, kKeyGood, nullptr)); ASSERT_TRUE(store_->Close()); } TEST_F(KeyFileStoreTest, SetUint64) { static const char kGroup[] = "int-group"; static const char kKey[] = "test-int"; const uint64_t kValue = 0xFEDCBA9876543210LL; ASSERT_TRUE(store_->Open()); ASSERT_TRUE(store_->SetUint64(kGroup, kKey, kValue)); ASSERT_TRUE(store_->Close()); EXPECT_EQ(base::StringPrintf("[%s]\n" "%s=%s\n", kGroup, kKey, base::Uint64ToString(kValue).c_str()), ReadKeyFile()); } TEST_F(KeyFileStoreTest, GetStringList) { static const char kGroup[] = "string-lists"; static const char kKeyEmpty[] = "empty"; static const char kKeyEmptyValue[] = "empty-value"; static const char kKeyValueEmpty[] = "value-empty"; static const char kKeyValueEmptyValue[] = "value-empty-value"; static const char kKeyValues[] = "values"; static const char kValue[] = "value"; static const char kValue2[] = "value2"; static const char kValue3[] = "value3"; WriteKeyFile(base::StringPrintf("[%s]\n" "%s=\n" "%s=;%s\n" "%s=%s;;\n" "%s=%s;;%s\n" "%s=%s;%s;%s\n", kGroup, kKeyEmpty, kKeyEmptyValue, kValue, kKeyValueEmpty, kValue, kKeyValueEmptyValue, kValue, kValue2, kKeyValues, kValue, kValue2, kValue3)); ASSERT_TRUE(store_->Open()); vector<string> value; EXPECT_TRUE(store_->GetStringList(kGroup, kKeyValues, &value)); ASSERT_EQ(3, value.size()); EXPECT_EQ(kValue, value[0]); EXPECT_EQ(kValue2, value[1]); EXPECT_EQ(kValue3, value[2]); EXPECT_TRUE(store_->GetStringList(kGroup, kKeyEmptyValue, &value)); ASSERT_EQ(2, value.size()); EXPECT_EQ("", value[0]); EXPECT_EQ(kValue, value[1]); EXPECT_TRUE(store_->GetStringList(kGroup, kKeyValueEmpty, &value)); ASSERT_EQ(2, value.size()); EXPECT_EQ(kValue, value[0]); EXPECT_EQ("", value[1]); EXPECT_TRUE(store_->GetStringList(kGroup, kKeyEmpty, &value)); ASSERT_EQ(0, value.size()); EXPECT_TRUE(store_->GetStringList(kGroup, kKeyValueEmptyValue, &value)); ASSERT_EQ(3, value.size()); EXPECT_EQ(kValue, value[0]); EXPECT_EQ("", value[1]); EXPECT_EQ(kValue2, value[2]); EXPECT_FALSE(store_->GetStringList("unknown-string-lists", kKeyEmpty, &value)); EXPECT_FALSE(store_->GetStringList(kGroup, "some-key", &value)); EXPECT_TRUE(store_->GetStringList(kGroup, kKeyValues, nullptr)); ASSERT_TRUE(store_->Close()); } TEST_F(KeyFileStoreTest, SetStringList) { static const char kGroup[] = "strings"; static const char kKeyEmpty[] = "e"; static const char kKeyEmptyValue[] = "ev"; static const char kKeyValueEmpty[] = "ve"; static const char kKeyValueEmptyValue[] = "vev"; static const char kKeyValues[] = "v"; static const char kValue[] = "abc"; static const char kValue2[] = "pqr"; static const char kValue3[] = "xyz"; ASSERT_TRUE(store_->Open()); { vector<string> value; ASSERT_TRUE(store_->SetStringList(kGroup, kKeyEmpty, value)); } { vector<string> value; value.push_back(""); value.push_back(kValue); ASSERT_TRUE(store_->SetStringList(kGroup, kKeyEmptyValue, value)); } { vector<string> value; value.push_back(kValue); value.push_back(""); ASSERT_TRUE(store_->SetStringList(kGroup, kKeyValueEmpty, value)); } { vector<string> value; value.push_back(kValue); value.push_back(""); value.push_back(kValue2); ASSERT_TRUE(store_->SetStringList(kGroup, kKeyValueEmptyValue, value)); } { vector<string> value; value.push_back(kValue); value.push_back(kValue2); value.push_back(kValue3); ASSERT_TRUE(store_->SetStringList(kGroup, kKeyValues, value)); } ASSERT_TRUE(store_->Close()); EXPECT_EQ(base::StringPrintf("[%s]\n" "%s=\n" "%s=;%s;\n" "%s=%s;;\n" "%s=%s;;%s;\n" "%s=%s;%s;%s;\n", kGroup, kKeyEmpty, kKeyEmptyValue, kValue, kKeyValueEmpty, kValue, kKeyValueEmptyValue, kValue, kValue2, kKeyValues, kValue, kValue2, kValue3), ReadKeyFile()); } TEST_F(KeyFileStoreTest, GetCryptedString) { static const char kGroup[] = "crypto-group"; static const char kKey[] = "secret"; WriteKeyFile(base::StringPrintf("[%s]\n" "%s=%s\n", kGroup, kKey, kROT47Text)); ASSERT_TRUE(store_->Open()); string value; EXPECT_TRUE(store_->GetCryptedString(kGroup, kKey, &value)); EXPECT_EQ(kPlainText, value); EXPECT_FALSE(store_->GetCryptedString("something-else", kKey, &value)); EXPECT_FALSE(store_->GetCryptedString(kGroup, "non-secret", &value)); EXPECT_TRUE(store_->GetCryptedString(kGroup, kKey, nullptr)); ASSERT_TRUE(store_->Close()); } TEST_F(KeyFileStoreTest, SetCryptedString) { static const char kGroup[] = "crypted-string-group"; static const char kKey[] = "test-string"; ASSERT_TRUE(store_->Open()); ASSERT_TRUE(store_->SetCryptedString(kGroup, kKey, kPlainText)); ASSERT_TRUE(store_->Close()); EXPECT_EQ(base::StringPrintf("[%s]\n" "%s=%s\n", kGroup, kKey, kROT47Text), ReadKeyFile()); } TEST_F(KeyFileStoreTest, PersistAcrossClose) { static const char kGroup[] = "string-group"; static const char kKey1[] = "test-string"; static const char kValue1[] = "foo"; static const char kKey2[] = "empty-string"; static const char kValue2[] = ""; ASSERT_TRUE(store_->Open()); ASSERT_TRUE(store_->SetString(kGroup, kKey1, kValue1)); ASSERT_TRUE(store_->Close()); ASSERT_TRUE(store_->Open()); ASSERT_TRUE(store_->SetString(kGroup, kKey2, kValue2)); string value; ASSERT_TRUE(store_->GetString(kGroup, kKey1, &value)); ASSERT_EQ(kValue1, value); ASSERT_TRUE(store_->GetString(kGroup, kKey2, &value)); ASSERT_EQ(kValue2, value); ASSERT_TRUE(store_->Close()); } namespace { class ReadOnlyKeyFileStore : public KeyFileStore { public: explicit ReadOnlyKeyFileStore(const base::FilePath& path) : KeyFileStore(path) {} bool Flush() override { return true; } }; bool OpenCheckClose(const FilePath& path, const string& group, const string& key, const string& expected_value) { ReadOnlyKeyFileStore store(path); // Don't modify file owned by caller. EXPECT_TRUE(store.Open()); string value; bool could_get = store.GetString(group, key, &value); store.Close(); return could_get && expected_value == value; } TEST_F(KeyFileStoreTest, Flush) { static const char kGroup[] = "string-group"; static const char kKey1[] = "test-string"; static const char kValue1[] = "foo"; static const char kKey2[] = "empty-string"; static const char kValue2[] = ""; ASSERT_TRUE(store_->Open()); ASSERT_TRUE(store_->SetString(kGroup, kKey1, kValue1)); ASSERT_TRUE(store_->Flush()); ASSERT_TRUE(OpenCheckClose(test_file_, kGroup, kKey1, kValue1)); ASSERT_TRUE(store_->SetString(kGroup, kKey2, kValue2)); ASSERT_TRUE(store_->Flush()); ASSERT_TRUE(OpenCheckClose(test_file_, kGroup, kKey2, kValue2)); EXPECT_TRUE(store_->DeleteKey(kGroup, kKey1)); ASSERT_TRUE(store_->Flush()); ASSERT_FALSE(OpenCheckClose(test_file_, kGroup, kKey1, kValue1)); } } // namespace TEST_F(KeyFileStoreTest, EmptyFile) { ASSERT_TRUE(store_->Open()); ASSERT_TRUE(store_->Close()); EXPECT_FALSE(store_->IsNonEmpty()); } TEST_F(KeyFileStoreTest, SetHeader) { ASSERT_TRUE(store_->Open()); ASSERT_TRUE(store_->SetHeader("this is a test")); ASSERT_TRUE(store_->Close()); EXPECT_TRUE(store_->IsNonEmpty()); ASSERT_TRUE(store_->Open()); } TEST_F(KeyFileStoreTest, Combo) { static const char kGroupA[] = "square"; static const char kGroupB[] = "circle"; static const char kGroupC[] = "triangle"; static const char kGroupX[] = "pentagon"; static const char kKeyString[] = "color"; static const char kKeyStringList[] = "alternative-colors"; static const char kKeyInt[] = "area"; static const char kKeyBool[] = "visible"; static const char kValueStringA[] = "blue"; static const char kValueStringB[] = "red"; static const char kValueStringC[] = "yellow"; static const char kValueStringCNew[] = "purple"; const int kValueIntA = 5; const int kValueIntB = 10; const int kValueIntBNew = 333; WriteKeyFile(base::StringPrintf("[%s]\n" "%s=%s\n" "%s=%s;%s\n" "%s=%d\n" "[%s]\n" "%s=%s\n" "%s=%s;%s\n" "%s=%d\n" "%s=true\n" "[%s]\n" "%s=%s\n" "%s=false\n", kGroupA, kKeyString, kValueStringA, kKeyStringList, kValueStringB, kValueStringC, kKeyInt, kValueIntA, kGroupB, kKeyString, kValueStringB, kKeyStringList, kValueStringA, kValueStringC, kKeyInt, kValueIntB, kKeyBool, kGroupC, kKeyString, kValueStringC, kKeyBool)); ASSERT_TRUE(store_->Open()); EXPECT_TRUE(store_->ContainsGroup(kGroupA)); EXPECT_TRUE(store_->ContainsGroup(kGroupB)); EXPECT_TRUE(store_->ContainsGroup(kGroupC)); EXPECT_FALSE(store_->ContainsGroup(kGroupX)); set<string> groups = store_->GetGroups(); EXPECT_EQ(3, groups.size()); EXPECT_TRUE(ContainsKey(groups, kGroupA)); EXPECT_TRUE(ContainsKey(groups, kGroupB)); EXPECT_TRUE(ContainsKey(groups, kGroupC)); EXPECT_FALSE(ContainsKey(groups, kGroupX)); { string value; EXPECT_TRUE(store_->GetString(kGroupB, kKeyString, &value)); EXPECT_EQ(kValueStringB, value); EXPECT_TRUE(store_->GetString(kGroupA, kKeyString, &value)); EXPECT_EQ(kValueStringA, value); EXPECT_TRUE(store_->GetString(kGroupC, kKeyString, &value)); EXPECT_EQ(kValueStringC, value); } { vector<string> value; EXPECT_TRUE(store_->GetStringList(kGroupB, kKeyStringList, &value)); ASSERT_EQ(2, value.size()); EXPECT_EQ(kValueStringA, value[0]); EXPECT_EQ(kValueStringC, value[1]); EXPECT_TRUE(store_->GetStringList(kGroupA, kKeyStringList, &value)); ASSERT_EQ(2, value.size()); EXPECT_EQ(kValueStringB, value[0]); EXPECT_EQ(kValueStringC, value[1]); EXPECT_FALSE(store_->GetStringList(kGroupC, kKeyStringList, &value)); } { int value = 0; EXPECT_TRUE(store_->GetInt(kGroupB, kKeyInt, &value)); EXPECT_EQ(kValueIntB, value); EXPECT_TRUE(store_->GetInt(kGroupA, kKeyInt, &value)); EXPECT_EQ(kValueIntA, value); EXPECT_FALSE(store_->GetInt(kGroupC, kKeyInt, &value)); } { bool value = false; EXPECT_TRUE(store_->GetBool(kGroupB, kKeyBool, &value)); EXPECT_TRUE(value); EXPECT_TRUE(store_->GetBool(kGroupC, kKeyBool, &value)); EXPECT_FALSE(value); EXPECT_FALSE(store_->GetBool(kGroupA, kKeyBool, &value)); } EXPECT_TRUE(store_->DeleteGroup(kGroupA)); EXPECT_TRUE(store_->DeleteGroup(kGroupA)); EXPECT_FALSE(store_->ContainsGroup(kGroupA)); EXPECT_TRUE(store_->ContainsGroup(kGroupB)); EXPECT_TRUE(store_->ContainsGroup(kGroupC)); groups = store_->GetGroups(); EXPECT_EQ(2, groups.size()); EXPECT_FALSE(ContainsKey(groups, kGroupA)); EXPECT_TRUE(ContainsKey(groups, kGroupB)); EXPECT_TRUE(ContainsKey(groups, kGroupC)); EXPECT_TRUE(store_->SetBool(kGroupB, kKeyBool, false)); EXPECT_TRUE(store_->SetInt(kGroupB, kKeyInt, kValueIntBNew)); EXPECT_TRUE(store_->SetString(kGroupC, kKeyString, kValueStringCNew)); store_->SetStringList(kGroupB, kKeyStringList, vector<string>(1, kValueStringB)); EXPECT_TRUE(store_->DeleteKey(kGroupB, kKeyString)); EXPECT_TRUE(store_->DeleteKey(kGroupB, kKeyString)); { string value; EXPECT_FALSE(store_->GetString(kGroupB, kKeyString, &value)); EXPECT_FALSE(store_->GetString(kGroupA, kKeyString, &value)); EXPECT_TRUE(store_->GetString(kGroupC, kKeyString, &value)); EXPECT_EQ(kValueStringCNew, value); } { vector<string> value; EXPECT_TRUE(store_->GetStringList(kGroupB, kKeyStringList, &value)); ASSERT_EQ(1, value.size()); EXPECT_EQ(kValueStringB, value[0]); EXPECT_FALSE(store_->GetStringList(kGroupA, kKeyStringList, &value)); EXPECT_FALSE(store_->GetStringList(kGroupC, kKeyStringList, &value)); } { int value = 0; EXPECT_TRUE(store_->GetInt(kGroupB, kKeyInt, &value)); EXPECT_EQ(kValueIntBNew, value); EXPECT_FALSE(store_->GetInt(kGroupA, kKeyInt, &value)); EXPECT_FALSE(store_->GetInt(kGroupC, kKeyInt, &value)); } { bool value = false; EXPECT_TRUE(store_->GetBool(kGroupB, kKeyBool, &value)); EXPECT_FALSE(value); EXPECT_TRUE(store_->GetBool(kGroupC, kKeyBool, &value)); EXPECT_FALSE(value); EXPECT_FALSE(store_->GetBool(kGroupA, kKeyBool, &value)); } ASSERT_TRUE(store_->Close()); EXPECT_EQ(base::StringPrintf("[%s]\n" "%s=%s;\n" "%s=%d\n" "%s=false\n" "\n" "[%s]\n" "%s=%s\n" "%s=false\n", kGroupB, kKeyStringList, kValueStringB, kKeyInt, kValueIntBNew, kKeyBool, kGroupC, kKeyString, kValueStringCNew, kKeyBool), ReadKeyFile()); } } // namespace shill