1//
2// Copyright (C) 2012 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8//      http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16
17#include "shill/key_file_store.h"
18
19#include <sys/stat.h>
20
21#include <memory>
22#include <set>
23#include <string>
24#include <vector>
25
26#include <base/files/file_enumerator.h>
27#include <base/files/file_util.h>
28#include <base/files/scoped_temp_dir.h>
29#include <base/stl_util.h>
30#include <base/strings/string_number_conversions.h>
31#include <base/strings/stringprintf.h>
32#include <gtest/gtest.h>
33
34#include "shill/key_value_store.h"
35
36using base::FileEnumerator;
37using base::FilePath;
38using std::set;
39using std::string;
40using std::unique_ptr;
41using std::vector;
42using testing::Test;
43
44namespace shill {
45
46namespace {
47const char kPlainText[] = "This is a test!";
48const char kROT47Text[] = "rot47:%9:D :D 2 E6DEP";
49}  // namespace
50
51class KeyFileStoreTest : public Test {
52 public:
53  KeyFileStoreTest() {}
54
55  virtual void SetUp() {
56    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
57    test_file_ = temp_dir_.path().Append("test-key-file-store");
58    store_.reset(new KeyFileStore(test_file_));
59  }
60
61  virtual void TearDown() {
62    ASSERT_TRUE(temp_dir_.Delete());
63  }
64
65 protected:
66  string ReadKeyFile();
67  void WriteKeyFile(string data);
68
69  base::ScopedTempDir temp_dir_;
70  FilePath test_file_;
71  unique_ptr<KeyFileStore> store_;
72};
73
74string KeyFileStoreTest::ReadKeyFile() {
75  string data;
76  EXPECT_TRUE(base::ReadFileToString(test_file_, &data));
77  return data;
78}
79
80void KeyFileStoreTest::WriteKeyFile(string data) {
81  EXPECT_EQ(data.size(),
82            base::WriteFile(test_file_, data.data(), data.size()));
83}
84
85TEST_F(KeyFileStoreTest, OpenClose) {
86  EXPECT_FALSE(store_->key_file_);
87
88  EXPECT_FALSE(store_->IsNonEmpty());
89  ASSERT_TRUE(store_->Open());
90  EXPECT_TRUE(store_->key_file_);
91  EXPECT_EQ(1, store_->crypto_.cryptos_.size());
92  ASSERT_TRUE(store_->Close());
93  EXPECT_FALSE(store_->key_file_);
94  FileEnumerator file_enumerator(temp_dir_.path(),
95                                 false /* not recursive */,
96                                 FileEnumerator::FILES);
97
98  // Verify that the file actually got written with the right name.
99  EXPECT_EQ(test_file_.value(), file_enumerator.Next().value());
100  FileEnumerator::FileInfo file_info = file_enumerator.GetInfo();
101
102  // Verify that the profile is a regular file, readable and writeable by the
103  // owner only.
104  EXPECT_EQ(S_IFREG | S_IRUSR | S_IWUSR, file_info.stat().st_mode);
105
106  ASSERT_TRUE(store_->Open());
107  EXPECT_TRUE(store_->key_file_);
108  ASSERT_TRUE(store_->Close());
109  EXPECT_FALSE(store_->key_file_);
110
111  ASSERT_TRUE(store_->Open());
112  // Replace file with directory, to force Flush() to fail.
113  ASSERT_TRUE(base::DeleteFile(test_file_, false));
114  ASSERT_TRUE(base::CreateDirectory(test_file_));
115  ASSERT_FALSE(store_->Close());
116  EXPECT_FALSE(store_->key_file_);
117}
118
119TEST_F(KeyFileStoreTest, OpenFail) {
120  WriteKeyFile("garbage\n");
121  EXPECT_FALSE(store_->Open());
122  EXPECT_FALSE(store_->key_file_);
123}
124
125TEST_F(KeyFileStoreTest, MarkAsCorrupted) {
126  EXPECT_FALSE(store_->MarkAsCorrupted());
127  EXPECT_FALSE(store_->IsNonEmpty());
128  WriteKeyFile("garbage\n");
129  EXPECT_TRUE(store_->IsNonEmpty());
130  EXPECT_TRUE(base::PathExists(test_file_));
131  EXPECT_TRUE(store_->MarkAsCorrupted());
132  EXPECT_FALSE(store_->IsNonEmpty());
133  EXPECT_FALSE(base::PathExists(test_file_));
134  EXPECT_TRUE(base::PathExists(FilePath(test_file_.value() + ".corrupted")));
135}
136
137TEST_F(KeyFileStoreTest, GetGroups) {
138  static const char kGroupA[] = "g-a";
139  static const char kGroupB[] = "g-b";
140  static const char kGroupC[] = "g-c";
141  WriteKeyFile(base::StringPrintf("[%s]\n"
142                                  "[%s]\n"
143                                  "[%s]\n",
144                                  kGroupA, kGroupB, kGroupC));
145  EXPECT_TRUE(store_->IsNonEmpty());
146  ASSERT_TRUE(store_->Open());
147  set<string> groups = store_->GetGroups();
148  EXPECT_EQ(3, groups.size());
149  EXPECT_TRUE(ContainsKey(groups, kGroupA));
150  EXPECT_TRUE(ContainsKey(groups, kGroupB));
151  EXPECT_TRUE(ContainsKey(groups, kGroupC));
152  EXPECT_FALSE(ContainsKey(groups, "g-x"));
153  ASSERT_TRUE(store_->Close());
154}
155
156TEST_F(KeyFileStoreTest, GetGroupsWithKey) {
157  static const char kGroupA[] = "g-a";
158  static const char kGroupB[] = "g-b";
159  static const char kGroupC[] = "g-c";
160  static const char kKeyA[] = "k-a";
161  static const char kKeyB[] = "k-b";
162  static const char kValue[] = "true";
163  WriteKeyFile(base::StringPrintf("[%s]\n"
164                                  "%s=%s\n"
165                                  "[%s]\n"
166                                  "%s=%s\n"
167                                  "%s=%s\n"
168                                  "[%s]\n"
169                                  "%s=%s\n",
170                                  kGroupA, kKeyA, kValue,
171                                  kGroupB, kKeyA, kValue, kKeyB, kValue,
172                                  kGroupC, kKeyB, kValue));
173  EXPECT_TRUE(store_->IsNonEmpty());
174  ASSERT_TRUE(store_->Open());
175  set<string> groups_a = store_->GetGroupsWithKey(kKeyA);
176  EXPECT_EQ(2, groups_a.size());
177  EXPECT_TRUE(ContainsKey(groups_a, kGroupA));
178  EXPECT_TRUE(ContainsKey(groups_a, kGroupB));
179  set<string> groups_b = store_->GetGroupsWithKey(kKeyB);
180  EXPECT_EQ(2, groups_b.size());
181  EXPECT_TRUE(ContainsKey(groups_b, kGroupB));
182  EXPECT_TRUE(ContainsKey(groups_b, kGroupC));
183  ASSERT_TRUE(store_->Close());
184}
185
186TEST_F(KeyFileStoreTest, ContainsGroup) {
187  static const char kGroupA[] = "group-a";
188  static const char kGroupB[] = "group-b";
189  static const char kGroupC[] = "group-c";
190  WriteKeyFile(base::StringPrintf("[%s]\n"
191                                  "[%s]\n"
192                                  "[%s]\n",
193                                  kGroupA, kGroupB, kGroupC));
194  ASSERT_TRUE(store_->Open());
195  EXPECT_TRUE(store_->ContainsGroup(kGroupA));
196  EXPECT_TRUE(store_->ContainsGroup(kGroupB));
197  EXPECT_TRUE(store_->ContainsGroup(kGroupC));
198  EXPECT_FALSE(store_->ContainsGroup("group-d"));
199  ASSERT_TRUE(store_->Close());
200}
201
202TEST_F(KeyFileStoreTest, GetGroupsWithProperties) {
203  static const char kGroupA[] = "group-a";
204  static const char kGroupB[] = "group-b";
205  static const char kGroupC[] = "group-c";
206  static const char kAttributeA[] = "attr-a";
207  static const char kAttributeB[] = "attr-b";
208  static const char kAttributeC[] = "attr-c";
209  static const char kValueA_0[] = "val-a";
210  static const char kValueA_1[] = "val-b";
211  static const int kValueB_0 = 1;
212  static const int kValueB_1 = 2;
213  static const bool kValueC_0 = true;
214  static const char kValueC_0_string[] = "true";
215  static const bool kValueC_1 = false;
216  static const char kValueC_1_string[] = "false";
217  WriteKeyFile(base::StringPrintf("[%s]\n"
218                                  "%s=%s\n"
219                                  "%s=%d\n"
220                                  "%s=%s\n"
221                                  "[%s]\n"
222                                  "%s=%s\n"
223                                  "%s=%d\n"
224                                  "%s=%s\n"
225                                  "[%s]\n"
226                                  "%s=%s\n"
227                                  "%s=%d\n"
228                                  "%s=%s\n",
229                                  kGroupA,
230                                  kAttributeA, kValueA_0,
231                                  kAttributeB, kValueB_0,
232                                  kAttributeC, kValueC_0_string,
233                                  kGroupB,
234                                  kAttributeA, kValueA_0,
235                                  kAttributeB, kValueB_1,
236                                  kAttributeC, kValueC_0_string,
237                                  kGroupC,
238                                  kAttributeA, kValueA_0,
239                                  kAttributeB, kValueB_0,
240                                  kAttributeC, kValueC_1_string));
241  ASSERT_TRUE(store_->Open());
242  {
243    KeyValueStore args;
244    args.SetString(kAttributeA, kValueA_0);
245    args.SetInt(kAttributeB, kValueB_0);
246    set<string> results = store_->GetGroupsWithProperties(args);
247    EXPECT_EQ(2, results.size());
248    EXPECT_TRUE(results.find(kGroupA) != results.end());
249    EXPECT_TRUE(results.find(kGroupC) != results.end());
250  }
251  {
252    KeyValueStore args;
253    args.SetString(kAttributeA, kValueA_0);
254    args.SetBool(kAttributeC, kValueC_0);
255    set<string> results = store_->GetGroupsWithProperties(args);
256    EXPECT_EQ(2, results.size());
257    EXPECT_TRUE(results.find(kGroupA) != results.end());
258    EXPECT_TRUE(results.find(kGroupB) != results.end());
259  }
260  {
261    KeyValueStore args;
262    args.SetBool(kAttributeC, kValueC_1);
263    set<string> results = store_->GetGroupsWithProperties(args);
264    EXPECT_EQ(1, results.size());
265    EXPECT_TRUE(results.find(kGroupC) != results.end());
266  }
267  {
268    KeyValueStore args;
269    args.SetString(kAttributeA, kValueA_0);
270    set<string> results = store_->GetGroupsWithProperties(args);
271    EXPECT_EQ(3, results.size());
272    EXPECT_TRUE(results.find(kGroupA) != results.end());
273    EXPECT_TRUE(results.find(kGroupB) != results.end());
274    EXPECT_TRUE(results.find(kGroupC) != results.end());
275  }
276  {
277    KeyValueStore args;
278    args.SetString(kAttributeA, kValueA_1);
279    set<string> results = store_->GetGroupsWithProperties(args);
280    EXPECT_EQ(0, results.size());
281  }
282  ASSERT_TRUE(store_->Close());
283}
284
285TEST_F(KeyFileStoreTest, DeleteKey) {
286  static const char kGroup[] = "the-group";
287  static const char kKeyDead[] = "dead";
288  static const char kKeyAlive[] = "alive";
289  const int kValueAlive = 3;
290  WriteKeyFile(base::StringPrintf("[%s]\n"
291                                  "%s=5\n"
292                                  "%s=%d\n",
293                                  kGroup, kKeyDead, kKeyAlive, kValueAlive));
294  ASSERT_TRUE(store_->Open());
295  EXPECT_TRUE(store_->DeleteKey(kGroup, kKeyDead));
296  EXPECT_TRUE(store_->DeleteKey(kGroup, "random-key"));
297  EXPECT_FALSE(store_->DeleteKey("random-group", kKeyAlive));
298  ASSERT_TRUE(store_->Close());
299  EXPECT_EQ(base::StringPrintf("[%s]\n"
300                               "%s=%d\n",
301                               kGroup, kKeyAlive, kValueAlive),
302            ReadKeyFile());
303}
304
305TEST_F(KeyFileStoreTest, DeleteGroup) {
306  static const char kGroupA[] = "group-a";
307  static const char kGroupB[] = "group-b";
308  static const char kGroupC[] = "group-c";
309  WriteKeyFile(base::StringPrintf("[%s]\n"
310                                  "[%s]\n"
311                                  "key-to-be-deleted=true\n"
312                                  "[%s]\n",
313                                  kGroupA, kGroupB, kGroupC));
314  ASSERT_TRUE(store_->Open());
315  EXPECT_TRUE(store_->DeleteGroup(kGroupB));
316  EXPECT_TRUE(store_->DeleteGroup("group-d"));
317  ASSERT_TRUE(store_->Close());
318  EXPECT_EQ(base::StringPrintf("[%s]\n"
319                               "\n"
320                               "[%s]\n",
321                               kGroupA, kGroupC),
322            ReadKeyFile());
323}
324
325TEST_F(KeyFileStoreTest, GetString) {
326  static const char kGroup[] = "something";
327  static const char kKey[] = "foo";
328  static const char kValue[] = "bar";
329  WriteKeyFile(base::StringPrintf("[%s]\n"
330                                  "%s=%s\n",
331                                  kGroup, kKey, kValue));
332  ASSERT_TRUE(store_->Open());
333  string value;
334  EXPECT_TRUE(store_->GetString(kGroup, kKey, &value));
335  EXPECT_EQ(kValue, value);
336  EXPECT_FALSE(store_->GetString("something-else", kKey, &value));
337  EXPECT_FALSE(store_->GetString(kGroup, "bar", &value));
338  EXPECT_TRUE(store_->GetString(kGroup, kKey, nullptr));
339  ASSERT_TRUE(store_->Close());
340}
341
342TEST_F(KeyFileStoreTest, SetString) {
343  static const char kGroup[] = "string-group";
344  static const char kKey1[] = "test-string";
345  static const char kValue1[] = "foo";
346  static const char kKey2[] = "empty-string";
347  static const char kValue2[] = "";
348  ASSERT_TRUE(store_->Open());
349  ASSERT_TRUE(store_->SetString(kGroup, kKey1, kValue1));
350  ASSERT_TRUE(store_->SetString(kGroup, kKey2, kValue2));
351  ASSERT_TRUE(store_->Close());
352  EXPECT_EQ(base::StringPrintf("[%s]\n"
353                               "%s=%s\n"
354                               "%s=%s\n",
355                               kGroup, kKey1, kValue1, kKey2, kValue2),
356            ReadKeyFile());
357}
358
359TEST_F(KeyFileStoreTest, GetBool) {
360  static const char kGroup[] = "boo";
361  static const char kKeyTrue[] = "foo";
362  static const char kKeyFalse[] = "bar";
363  static const char kKeyBad[] = "zoo";
364  WriteKeyFile(base::StringPrintf("[%s]\n"
365                                  "%s=true\n"
366                                  "%s=false\n"
367                                  "%s=moo\n",
368                                  kGroup, kKeyTrue, kKeyFalse, kKeyBad));
369  ASSERT_TRUE(store_->Open());
370  {
371    bool value = true;
372    EXPECT_TRUE(store_->GetBool(kGroup, kKeyFalse, &value));
373    EXPECT_FALSE(value);
374  }
375  {
376    bool value = false;
377    EXPECT_TRUE(store_->GetBool(kGroup, kKeyTrue, &value));
378    EXPECT_TRUE(value);
379  }
380  {
381    bool value;
382    EXPECT_FALSE(store_->GetBool(kGroup, kKeyBad, &value));
383    EXPECT_FALSE(store_->GetBool(kGroup, "unknown", &value));
384    EXPECT_FALSE(store_->GetBool("unknown", kKeyTrue, &value));
385  }
386  EXPECT_TRUE(store_->GetBool(kGroup, kKeyFalse, nullptr));
387  ASSERT_TRUE(store_->Close());
388}
389
390TEST_F(KeyFileStoreTest, SetBool) {
391  static const char kGroup[] = "bool-group";
392  static const char kKeyTrue[] = "test-true-bool";
393  static const char kKeyFalse[] = "test-false-bool";
394  ASSERT_TRUE(store_->Open());
395  ASSERT_TRUE(store_->SetBool(kGroup, kKeyTrue, true));
396  ASSERT_TRUE(store_->SetBool(kGroup, kKeyFalse, false));
397  ASSERT_TRUE(store_->Close());
398  EXPECT_EQ(base::StringPrintf("[%s]\n"
399                               "%s=true\n"
400                               "%s=false\n",
401                               kGroup, kKeyTrue, kKeyFalse),
402            ReadKeyFile());
403}
404
405TEST_F(KeyFileStoreTest, GetInt) {
406  static const char kGroup[] = "numbers";
407  static const char kKeyPos[] = "pos";
408  static const char kKeyNeg[] = "neg";
409  static const char kKeyBad[] = "bad";
410  const int kValuePos = 50;
411  const int kValueNeg = -20;
412  static const char kValueBad[] = "nan";
413  WriteKeyFile(base::StringPrintf("[%s]\n"
414                                  "%s=%d\n"
415                                  "%s=%d\n"
416                                  "%s=%s\n",
417                                  kGroup,
418                                  kKeyPos, kValuePos,
419                                  kKeyNeg, kValueNeg,
420                                  kKeyBad, kValueBad));
421  ASSERT_TRUE(store_->Open());
422  {
423    int value = 0;
424    EXPECT_TRUE(store_->GetInt(kGroup, kKeyNeg, &value));
425    EXPECT_EQ(kValueNeg, value);
426  }
427  {
428    int value = 0;
429    EXPECT_TRUE(store_->GetInt(kGroup, kKeyPos, &value));
430    EXPECT_EQ(kValuePos, value);
431  }
432  {
433    int value;
434    EXPECT_FALSE(store_->GetInt(kGroup, kKeyBad, &value));
435    EXPECT_FALSE(store_->GetInt(kGroup, "invalid", &value));
436    EXPECT_FALSE(store_->GetInt("invalid", kKeyPos, &value));
437  }
438  EXPECT_TRUE(store_->GetInt(kGroup, kKeyPos, nullptr));
439  ASSERT_TRUE(store_->Close());
440}
441
442TEST_F(KeyFileStoreTest, SetInt) {
443  static const char kGroup[] = "int-group";
444  static const char kKey1[] = "test-int";
445  static const char kKey2[] = "test-negative";
446  const int kValue1 = 5;
447  const int kValue2 = -10;
448  ASSERT_TRUE(store_->Open());
449  ASSERT_TRUE(store_->SetInt(kGroup, kKey1, kValue1));
450  ASSERT_TRUE(store_->SetInt(kGroup, kKey2, kValue2));
451  ASSERT_TRUE(store_->Close());
452  EXPECT_EQ(base::StringPrintf("[%s]\n"
453                               "%s=%d\n"
454                               "%s=%d\n",
455                               kGroup, kKey1, kValue1, kKey2, kValue2),
456            ReadKeyFile());
457}
458
459TEST_F(KeyFileStoreTest, GetUint64) {
460  static const char kGroup[] = "numbers";
461  static const char kKeyGood[] = "good";
462  static const char kKeyBad[] = "bad";
463  const uint64_t kValueGood = 0xFEDCBA9876543210LL;
464  static const char kValueBad[] = "nan";
465  // Use base::Uint64ToString() instead of using something like "%llu"
466  // (not correct for native 64 bit architectures) or PRIu64 (does not
467  // work correctly using cros_workon_make due to include intricacies).
468  WriteKeyFile(base::StringPrintf("[%s]\n"
469                                  "%s=%s\n"
470                                  "%s=%s\n",
471                                  kGroup,
472                                  kKeyGood,
473                                  base::Uint64ToString(kValueGood).c_str(),
474                                  kKeyBad, kValueBad));
475  ASSERT_TRUE(store_->Open());
476  {
477    uint64_t value = 0;
478    EXPECT_TRUE(store_->GetUint64(kGroup, kKeyGood, &value));
479    EXPECT_EQ(kValueGood, value);
480  }
481  {
482    uint64_t value;
483    EXPECT_FALSE(store_->GetUint64(kGroup, kKeyBad, &value));
484    EXPECT_FALSE(store_->GetUint64(kGroup, "invalid", &value));
485    EXPECT_FALSE(store_->GetUint64("invalid", kKeyGood, &value));
486  }
487  EXPECT_TRUE(store_->GetUint64(kGroup, kKeyGood, nullptr));
488  ASSERT_TRUE(store_->Close());
489}
490
491TEST_F(KeyFileStoreTest, SetUint64) {
492  static const char kGroup[] = "int-group";
493  static const char kKey[] = "test-int";
494  const uint64_t kValue = 0xFEDCBA9876543210LL;
495  ASSERT_TRUE(store_->Open());
496  ASSERT_TRUE(store_->SetUint64(kGroup, kKey, kValue));
497  ASSERT_TRUE(store_->Close());
498  EXPECT_EQ(base::StringPrintf("[%s]\n"
499                               "%s=%s\n",
500                               kGroup, kKey,
501                               base::Uint64ToString(kValue).c_str()),
502            ReadKeyFile());
503}
504
505TEST_F(KeyFileStoreTest, GetStringList) {
506  static const char kGroup[] = "string-lists";
507  static const char kKeyEmpty[] = "empty";
508  static const char kKeyEmptyValue[] = "empty-value";
509  static const char kKeyValueEmpty[] = "value-empty";
510  static const char kKeyValueEmptyValue[] = "value-empty-value";
511  static const char kKeyValues[] = "values";
512  static const char kValue[] = "value";
513  static const char kValue2[] = "value2";
514  static const char kValue3[] = "value3";
515  WriteKeyFile(base::StringPrintf("[%s]\n"
516                                  "%s=\n"
517                                  "%s=;%s\n"
518                                  "%s=%s;;\n"
519                                  "%s=%s;;%s\n"
520                                  "%s=%s;%s;%s\n",
521                                  kGroup,
522                                  kKeyEmpty,
523                                  kKeyEmptyValue, kValue,
524                                  kKeyValueEmpty, kValue,
525                                  kKeyValueEmptyValue, kValue, kValue2,
526                                  kKeyValues, kValue, kValue2, kValue3));
527  ASSERT_TRUE(store_->Open());
528
529  vector<string> value;
530
531  EXPECT_TRUE(store_->GetStringList(kGroup, kKeyValues, &value));
532  ASSERT_EQ(3, value.size());
533  EXPECT_EQ(kValue, value[0]);
534  EXPECT_EQ(kValue2, value[1]);
535  EXPECT_EQ(kValue3, value[2]);
536
537  EXPECT_TRUE(store_->GetStringList(kGroup, kKeyEmptyValue, &value));
538  ASSERT_EQ(2, value.size());
539  EXPECT_EQ("", value[0]);
540  EXPECT_EQ(kValue, value[1]);
541
542  EXPECT_TRUE(store_->GetStringList(kGroup, kKeyValueEmpty, &value));
543  ASSERT_EQ(2, value.size());
544  EXPECT_EQ(kValue, value[0]);
545  EXPECT_EQ("", value[1]);
546
547  EXPECT_TRUE(store_->GetStringList(kGroup, kKeyEmpty, &value));
548  ASSERT_EQ(0, value.size());
549
550  EXPECT_TRUE(store_->GetStringList(kGroup, kKeyValueEmptyValue, &value));
551  ASSERT_EQ(3, value.size());
552  EXPECT_EQ(kValue, value[0]);
553  EXPECT_EQ("", value[1]);
554  EXPECT_EQ(kValue2, value[2]);
555
556  EXPECT_FALSE(store_->GetStringList("unknown-string-lists",
557                                     kKeyEmpty,
558                                     &value));
559  EXPECT_FALSE(store_->GetStringList(kGroup, "some-key", &value));
560  EXPECT_TRUE(store_->GetStringList(kGroup, kKeyValues, nullptr));
561  ASSERT_TRUE(store_->Close());
562}
563
564TEST_F(KeyFileStoreTest, SetStringList) {
565  static const char kGroup[] = "strings";
566  static const char kKeyEmpty[] = "e";
567  static const char kKeyEmptyValue[] = "ev";
568  static const char kKeyValueEmpty[] = "ve";
569  static const char kKeyValueEmptyValue[] = "vev";
570  static const char kKeyValues[] = "v";
571  static const char kValue[] = "abc";
572  static const char kValue2[] = "pqr";
573  static const char kValue3[] = "xyz";
574  ASSERT_TRUE(store_->Open());
575  {
576    vector<string> value;
577    ASSERT_TRUE(store_->SetStringList(kGroup, kKeyEmpty, value));
578  }
579  {
580    vector<string> value;
581    value.push_back("");
582    value.push_back(kValue);
583    ASSERT_TRUE(store_->SetStringList(kGroup, kKeyEmptyValue, value));
584  }
585  {
586    vector<string> value;
587    value.push_back(kValue);
588    value.push_back("");
589    ASSERT_TRUE(store_->SetStringList(kGroup, kKeyValueEmpty, value));
590  }
591  {
592    vector<string> value;
593    value.push_back(kValue);
594    value.push_back("");
595    value.push_back(kValue2);
596    ASSERT_TRUE(store_->SetStringList(kGroup, kKeyValueEmptyValue, value));
597  }
598  {
599    vector<string> value;
600    value.push_back(kValue);
601    value.push_back(kValue2);
602    value.push_back(kValue3);
603    ASSERT_TRUE(store_->SetStringList(kGroup, kKeyValues, value));
604  }
605  ASSERT_TRUE(store_->Close());
606  EXPECT_EQ(base::StringPrintf("[%s]\n"
607                               "%s=\n"
608                               "%s=;%s;\n"
609                               "%s=%s;;\n"
610                               "%s=%s;;%s;\n"
611                               "%s=%s;%s;%s;\n",
612                               kGroup,
613                               kKeyEmpty,
614                               kKeyEmptyValue, kValue,
615                               kKeyValueEmpty, kValue,
616                               kKeyValueEmptyValue, kValue, kValue2,
617                               kKeyValues, kValue, kValue2, kValue3),
618            ReadKeyFile());
619}
620
621TEST_F(KeyFileStoreTest, GetCryptedString) {
622  static const char kGroup[] = "crypto-group";
623  static const char kKey[] = "secret";
624  WriteKeyFile(base::StringPrintf("[%s]\n"
625                                  "%s=%s\n",
626                                  kGroup, kKey, kROT47Text));
627  ASSERT_TRUE(store_->Open());
628  string value;
629  EXPECT_TRUE(store_->GetCryptedString(kGroup, kKey, &value));
630  EXPECT_EQ(kPlainText, value);
631  EXPECT_FALSE(store_->GetCryptedString("something-else", kKey, &value));
632  EXPECT_FALSE(store_->GetCryptedString(kGroup, "non-secret", &value));
633  EXPECT_TRUE(store_->GetCryptedString(kGroup, kKey, nullptr));
634  ASSERT_TRUE(store_->Close());
635}
636
637TEST_F(KeyFileStoreTest, SetCryptedString) {
638  static const char kGroup[] = "crypted-string-group";
639  static const char kKey[] = "test-string";
640  ASSERT_TRUE(store_->Open());
641  ASSERT_TRUE(store_->SetCryptedString(kGroup, kKey, kPlainText));
642  ASSERT_TRUE(store_->Close());
643  EXPECT_EQ(base::StringPrintf("[%s]\n"
644                               "%s=%s\n",
645                               kGroup, kKey, kROT47Text),
646            ReadKeyFile());
647}
648
649TEST_F(KeyFileStoreTest, PersistAcrossClose) {
650  static const char kGroup[] = "string-group";
651  static const char kKey1[] = "test-string";
652  static const char kValue1[] = "foo";
653  static const char kKey2[] = "empty-string";
654  static const char kValue2[] = "";
655  ASSERT_TRUE(store_->Open());
656  ASSERT_TRUE(store_->SetString(kGroup, kKey1, kValue1));
657  ASSERT_TRUE(store_->Close());
658  ASSERT_TRUE(store_->Open());
659  ASSERT_TRUE(store_->SetString(kGroup, kKey2, kValue2));
660  string value;
661  ASSERT_TRUE(store_->GetString(kGroup, kKey1, &value));
662  ASSERT_EQ(kValue1, value);
663  ASSERT_TRUE(store_->GetString(kGroup, kKey2, &value));
664  ASSERT_EQ(kValue2, value);
665  ASSERT_TRUE(store_->Close());
666}
667
668namespace {
669class ReadOnlyKeyFileStore : public KeyFileStore {
670 public:
671  explicit ReadOnlyKeyFileStore(const base::FilePath& path)
672      : KeyFileStore(path) {}
673  bool Flush() override { return true; }
674};
675
676bool OpenCheckClose(const FilePath& path,
677                    const string& group,
678                    const string& key,
679                    const string& expected_value) {
680  ReadOnlyKeyFileStore store(path);  // Don't modify file owned by caller.
681  EXPECT_TRUE(store.Open());
682  string value;
683  bool could_get = store.GetString(group, key, &value);
684  store.Close();
685  return could_get && expected_value == value;
686}
687
688TEST_F(KeyFileStoreTest, Flush) {
689  static const char kGroup[] = "string-group";
690  static const char kKey1[] = "test-string";
691  static const char kValue1[] = "foo";
692  static const char kKey2[] = "empty-string";
693  static const char kValue2[] = "";
694  ASSERT_TRUE(store_->Open());
695  ASSERT_TRUE(store_->SetString(kGroup, kKey1, kValue1));
696  ASSERT_TRUE(store_->Flush());
697  ASSERT_TRUE(OpenCheckClose(test_file_, kGroup, kKey1, kValue1));
698
699  ASSERT_TRUE(store_->SetString(kGroup, kKey2, kValue2));
700  ASSERT_TRUE(store_->Flush());
701  ASSERT_TRUE(OpenCheckClose(test_file_, kGroup, kKey2, kValue2));
702
703  EXPECT_TRUE(store_->DeleteKey(kGroup, kKey1));
704  ASSERT_TRUE(store_->Flush());
705  ASSERT_FALSE(OpenCheckClose(test_file_, kGroup, kKey1, kValue1));
706}
707}  // namespace
708
709TEST_F(KeyFileStoreTest, EmptyFile) {
710  ASSERT_TRUE(store_->Open());
711  ASSERT_TRUE(store_->Close());
712  EXPECT_FALSE(store_->IsNonEmpty());
713}
714
715TEST_F(KeyFileStoreTest, SetHeader) {
716  ASSERT_TRUE(store_->Open());
717  ASSERT_TRUE(store_->SetHeader("this is a test"));
718  ASSERT_TRUE(store_->Close());
719  EXPECT_TRUE(store_->IsNonEmpty());
720  ASSERT_TRUE(store_->Open());
721}
722
723TEST_F(KeyFileStoreTest, Combo) {
724  static const char kGroupA[] = "square";
725  static const char kGroupB[] = "circle";
726  static const char kGroupC[] = "triangle";
727  static const char kGroupX[] = "pentagon";
728  static const char kKeyString[] = "color";
729  static const char kKeyStringList[] = "alternative-colors";
730  static const char kKeyInt[] = "area";
731  static const char kKeyBool[] = "visible";
732  static const char kValueStringA[] = "blue";
733  static const char kValueStringB[] = "red";
734  static const char kValueStringC[] = "yellow";
735  static const char kValueStringCNew[] = "purple";
736  const int kValueIntA = 5;
737  const int kValueIntB = 10;
738  const int kValueIntBNew = 333;
739  WriteKeyFile(base::StringPrintf("[%s]\n"
740                                  "%s=%s\n"
741                                  "%s=%s;%s\n"
742                                  "%s=%d\n"
743                                  "[%s]\n"
744                                  "%s=%s\n"
745                                  "%s=%s;%s\n"
746                                  "%s=%d\n"
747                                  "%s=true\n"
748                                  "[%s]\n"
749                                  "%s=%s\n"
750                                  "%s=false\n",
751                                  kGroupA,
752                                  kKeyString, kValueStringA,
753                                  kKeyStringList, kValueStringB, kValueStringC,
754                                  kKeyInt, kValueIntA,
755                                  kGroupB,
756                                  kKeyString, kValueStringB,
757                                  kKeyStringList, kValueStringA, kValueStringC,
758                                  kKeyInt, kValueIntB,
759                                  kKeyBool,
760                                  kGroupC,
761                                  kKeyString, kValueStringC,
762                                  kKeyBool));
763  ASSERT_TRUE(store_->Open());
764
765  EXPECT_TRUE(store_->ContainsGroup(kGroupA));
766  EXPECT_TRUE(store_->ContainsGroup(kGroupB));
767  EXPECT_TRUE(store_->ContainsGroup(kGroupC));
768  EXPECT_FALSE(store_->ContainsGroup(kGroupX));
769
770  set<string> groups = store_->GetGroups();
771  EXPECT_EQ(3, groups.size());
772  EXPECT_TRUE(ContainsKey(groups, kGroupA));
773  EXPECT_TRUE(ContainsKey(groups, kGroupB));
774  EXPECT_TRUE(ContainsKey(groups, kGroupC));
775  EXPECT_FALSE(ContainsKey(groups, kGroupX));
776
777  {
778    string value;
779    EXPECT_TRUE(store_->GetString(kGroupB, kKeyString, &value));
780    EXPECT_EQ(kValueStringB, value);
781    EXPECT_TRUE(store_->GetString(kGroupA, kKeyString, &value));
782    EXPECT_EQ(kValueStringA, value);
783    EXPECT_TRUE(store_->GetString(kGroupC, kKeyString, &value));
784    EXPECT_EQ(kValueStringC, value);
785  }
786  {
787    vector<string> value;
788    EXPECT_TRUE(store_->GetStringList(kGroupB, kKeyStringList, &value));
789    ASSERT_EQ(2, value.size());
790    EXPECT_EQ(kValueStringA, value[0]);
791    EXPECT_EQ(kValueStringC, value[1]);
792    EXPECT_TRUE(store_->GetStringList(kGroupA, kKeyStringList, &value));
793    ASSERT_EQ(2, value.size());
794    EXPECT_EQ(kValueStringB, value[0]);
795    EXPECT_EQ(kValueStringC, value[1]);
796    EXPECT_FALSE(store_->GetStringList(kGroupC, kKeyStringList, &value));
797  }
798  {
799    int value = 0;
800    EXPECT_TRUE(store_->GetInt(kGroupB, kKeyInt, &value));
801    EXPECT_EQ(kValueIntB, value);
802    EXPECT_TRUE(store_->GetInt(kGroupA, kKeyInt, &value));
803    EXPECT_EQ(kValueIntA, value);
804    EXPECT_FALSE(store_->GetInt(kGroupC, kKeyInt, &value));
805  }
806  {
807    bool value = false;
808    EXPECT_TRUE(store_->GetBool(kGroupB, kKeyBool, &value));
809    EXPECT_TRUE(value);
810    EXPECT_TRUE(store_->GetBool(kGroupC, kKeyBool, &value));
811    EXPECT_FALSE(value);
812    EXPECT_FALSE(store_->GetBool(kGroupA, kKeyBool, &value));
813  }
814
815  EXPECT_TRUE(store_->DeleteGroup(kGroupA));
816  EXPECT_TRUE(store_->DeleteGroup(kGroupA));
817
818  EXPECT_FALSE(store_->ContainsGroup(kGroupA));
819  EXPECT_TRUE(store_->ContainsGroup(kGroupB));
820  EXPECT_TRUE(store_->ContainsGroup(kGroupC));
821
822  groups = store_->GetGroups();
823  EXPECT_EQ(2, groups.size());
824  EXPECT_FALSE(ContainsKey(groups, kGroupA));
825  EXPECT_TRUE(ContainsKey(groups, kGroupB));
826  EXPECT_TRUE(ContainsKey(groups, kGroupC));
827
828  EXPECT_TRUE(store_->SetBool(kGroupB, kKeyBool, false));
829  EXPECT_TRUE(store_->SetInt(kGroupB, kKeyInt, kValueIntBNew));
830  EXPECT_TRUE(store_->SetString(kGroupC, kKeyString, kValueStringCNew));
831  store_->SetStringList(kGroupB,
832                       kKeyStringList,
833                       vector<string>(1, kValueStringB));
834
835  EXPECT_TRUE(store_->DeleteKey(kGroupB, kKeyString));
836  EXPECT_TRUE(store_->DeleteKey(kGroupB, kKeyString));
837
838  {
839    string value;
840    EXPECT_FALSE(store_->GetString(kGroupB, kKeyString, &value));
841    EXPECT_FALSE(store_->GetString(kGroupA, kKeyString, &value));
842    EXPECT_TRUE(store_->GetString(kGroupC, kKeyString, &value));
843    EXPECT_EQ(kValueStringCNew, value);
844  }
845  {
846    vector<string> value;
847    EXPECT_TRUE(store_->GetStringList(kGroupB, kKeyStringList, &value));
848    ASSERT_EQ(1, value.size());
849    EXPECT_EQ(kValueStringB, value[0]);
850    EXPECT_FALSE(store_->GetStringList(kGroupA, kKeyStringList, &value));
851    EXPECT_FALSE(store_->GetStringList(kGroupC, kKeyStringList, &value));
852  }
853  {
854    int value = 0;
855    EXPECT_TRUE(store_->GetInt(kGroupB, kKeyInt, &value));
856    EXPECT_EQ(kValueIntBNew, value);
857    EXPECT_FALSE(store_->GetInt(kGroupA, kKeyInt, &value));
858    EXPECT_FALSE(store_->GetInt(kGroupC, kKeyInt, &value));
859  }
860  {
861    bool value = false;
862    EXPECT_TRUE(store_->GetBool(kGroupB, kKeyBool, &value));
863    EXPECT_FALSE(value);
864    EXPECT_TRUE(store_->GetBool(kGroupC, kKeyBool, &value));
865    EXPECT_FALSE(value);
866    EXPECT_FALSE(store_->GetBool(kGroupA, kKeyBool, &value));
867  }
868
869  ASSERT_TRUE(store_->Close());
870  EXPECT_EQ(base::StringPrintf("[%s]\n"
871                               "%s=%s;\n"
872                               "%s=%d\n"
873                               "%s=false\n"
874                               "\n"
875                               "[%s]\n"
876                               "%s=%s\n"
877                               "%s=false\n",
878                               kGroupB,
879                               kKeyStringList, kValueStringB,
880                               kKeyInt, kValueIntBNew,
881                               kKeyBool,
882                               kGroupC,
883                               kKeyString, kValueStringCNew,
884                               kKeyBool),
885            ReadKeyFile());
886}
887
888}  // namespace shill
889