values_unittest.cc revision c407dc5cd9bdc5668497f21b26b09d988ab439de
1// Copyright (c) 2010 The Chromium 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 <limits>
6
7#include "base/scoped_ptr.h"
8#include "base/string_util.h"
9#include "base/string16.h"
10#include "base/values.h"
11#include "testing/gtest/include/gtest/gtest.h"
12
13class ValuesTest: public testing::Test {
14};
15
16TEST(ValuesTest, Basic) {
17  // Test basic dictionary getting/setting
18  DictionaryValue settings;
19  std::wstring homepage = L"http://google.com";
20  ASSERT_FALSE(
21    settings.GetString(L"global.homepage", &homepage));
22  ASSERT_EQ(std::wstring(L"http://google.com"), homepage);
23
24  ASSERT_FALSE(settings.Get(L"global", NULL));
25  settings.Set(L"global", Value::CreateBooleanValue(true));
26  ASSERT_TRUE(settings.Get(L"global", NULL));
27  settings.SetString(L"global.homepage", L"http://scurvy.com");
28  ASSERT_TRUE(settings.Get(L"global", NULL));
29  homepage = L"http://google.com";
30  ASSERT_TRUE(settings.GetString(L"global.homepage", &homepage));
31  ASSERT_EQ(std::wstring(L"http://scurvy.com"), homepage);
32
33  // Test storing a dictionary in a list.
34  ListValue* toolbar_bookmarks;
35  ASSERT_FALSE(
36    settings.GetList(L"global.toolbar.bookmarks", &toolbar_bookmarks));
37
38  toolbar_bookmarks = new ListValue;
39  settings.Set(L"global.toolbar.bookmarks", toolbar_bookmarks);
40  ASSERT_TRUE(
41    settings.GetList(L"global.toolbar.bookmarks", &toolbar_bookmarks));
42
43  DictionaryValue* new_bookmark = new DictionaryValue;
44  new_bookmark->SetString(L"name", L"Froogle");
45  new_bookmark->SetString(L"url", L"http://froogle.com");
46  toolbar_bookmarks->Append(new_bookmark);
47
48  ListValue* bookmark_list;
49  ASSERT_TRUE(settings.GetList(L"global.toolbar.bookmarks", &bookmark_list));
50  DictionaryValue* bookmark;
51  ASSERT_EQ(1U, bookmark_list->GetSize());
52  ASSERT_TRUE(bookmark_list->GetDictionary(0, &bookmark));
53  std::wstring bookmark_name = L"Unnamed";
54  ASSERT_TRUE(bookmark->GetString(L"name", &bookmark_name));
55  ASSERT_EQ(std::wstring(L"Froogle"), bookmark_name);
56  std::wstring bookmark_url;
57  ASSERT_TRUE(bookmark->GetString(L"url", &bookmark_url));
58  ASSERT_EQ(std::wstring(L"http://froogle.com"), bookmark_url);
59}
60
61TEST(ValuesTest, List) {
62  scoped_ptr<ListValue> mixed_list(new ListValue());
63  mixed_list->Set(0, Value::CreateBooleanValue(true));
64  mixed_list->Set(1, Value::CreateIntegerValue(42));
65  mixed_list->Set(2, Value::CreateRealValue(88.8));
66  mixed_list->Set(3, Value::CreateStringValue("foo"));
67  ASSERT_EQ(4u, mixed_list->GetSize());
68
69  Value *value = NULL;
70  bool bool_value = false;
71  int int_value = 0;
72  double double_value = 0.0;
73  std::string string_value;
74
75  ASSERT_FALSE(mixed_list->Get(4, &value));
76
77  ASSERT_FALSE(mixed_list->GetInteger(0, &int_value));
78  ASSERT_EQ(0, int_value);
79  ASSERT_FALSE(mixed_list->GetReal(1, &double_value));
80  ASSERT_EQ(0.0, double_value);
81  ASSERT_FALSE(mixed_list->GetString(2, &string_value));
82  ASSERT_EQ("", string_value);
83  ASSERT_FALSE(mixed_list->GetBoolean(3, &bool_value));
84  ASSERT_EQ(false, bool_value);
85
86  ASSERT_TRUE(mixed_list->GetBoolean(0, &bool_value));
87  ASSERT_EQ(true, bool_value);
88  ASSERT_TRUE(mixed_list->GetInteger(1, &int_value));
89  ASSERT_EQ(42, int_value);
90  ASSERT_TRUE(mixed_list->GetReal(2, &double_value));
91  ASSERT_EQ(88.8, double_value);
92  ASSERT_TRUE(mixed_list->GetString(3, &string_value));
93  ASSERT_EQ("foo", string_value);
94}
95
96TEST(ValuesTest, BinaryValue) {
97  char* buffer = NULL;
98  // Passing a null buffer pointer doesn't yield a BinaryValue
99  scoped_ptr<BinaryValue> binary(BinaryValue::Create(buffer, 0));
100  ASSERT_FALSE(binary.get());
101
102  // If you want to represent an empty binary value, use a zero-length buffer.
103  buffer = new char[1];
104  ASSERT_TRUE(buffer);
105  binary.reset(BinaryValue::Create(buffer, 0));
106  ASSERT_TRUE(binary.get());
107  ASSERT_TRUE(binary->GetBuffer());
108  ASSERT_EQ(buffer, binary->GetBuffer());
109  ASSERT_EQ(0U, binary->GetSize());
110
111  // Test the common case of a non-empty buffer
112  buffer = new char[15];
113  binary.reset(BinaryValue::Create(buffer, 15));
114  ASSERT_TRUE(binary.get());
115  ASSERT_TRUE(binary->GetBuffer());
116  ASSERT_EQ(buffer, binary->GetBuffer());
117  ASSERT_EQ(15U, binary->GetSize());
118
119  char stack_buffer[42];
120  memset(stack_buffer, '!', 42);
121  binary.reset(BinaryValue::CreateWithCopiedBuffer(stack_buffer, 42));
122  ASSERT_TRUE(binary.get());
123  ASSERT_TRUE(binary->GetBuffer());
124  ASSERT_NE(stack_buffer, binary->GetBuffer());
125  ASSERT_EQ(42U, binary->GetSize());
126  ASSERT_EQ(0, memcmp(stack_buffer, binary->GetBuffer(), binary->GetSize()));
127}
128
129TEST(ValuesTest, StringValue) {
130  // Test overloaded CreateStringValue.
131  scoped_ptr<Value> narrow_value(Value::CreateStringValue("narrow"));
132  ASSERT_TRUE(narrow_value.get());
133  ASSERT_TRUE(narrow_value->IsType(Value::TYPE_STRING));
134  scoped_ptr<Value> wide_value(Value::CreateStringValue(L"wide"));
135  ASSERT_TRUE(wide_value.get());
136  ASSERT_TRUE(wide_value->IsType(Value::TYPE_STRING));
137  scoped_ptr<Value> utf16_value(
138      Value::CreateStringValueFromUTF16(ASCIIToUTF16("utf16")));
139  ASSERT_TRUE(utf16_value.get());
140  ASSERT_TRUE(utf16_value->IsType(Value::TYPE_STRING));
141
142  // Test overloaded GetString.
143  std::string narrow = "http://google.com";
144  std::wstring wide = L"http://google.com";
145  string16 utf16 = ASCIIToUTF16("http://google.com");
146  ASSERT_TRUE(narrow_value->GetAsString(&narrow));
147  ASSERT_TRUE(narrow_value->GetAsString(&wide));
148  ASSERT_TRUE(narrow_value->GetAsUTF16(&utf16));
149  ASSERT_EQ(std::string("narrow"), narrow);
150  ASSERT_EQ(std::wstring(L"narrow"), wide);
151  ASSERT_EQ(ASCIIToUTF16("narrow"), utf16);
152
153  ASSERT_TRUE(wide_value->GetAsString(&narrow));
154  ASSERT_TRUE(wide_value->GetAsString(&wide));
155  ASSERT_TRUE(wide_value->GetAsUTF16(&utf16));
156  ASSERT_EQ(std::string("wide"), narrow);
157  ASSERT_EQ(std::wstring(L"wide"), wide);
158  ASSERT_EQ(ASCIIToUTF16("wide"), utf16);
159
160  ASSERT_TRUE(utf16_value->GetAsString(&narrow));
161  ASSERT_TRUE(utf16_value->GetAsString(&wide));
162  ASSERT_TRUE(utf16_value->GetAsUTF16(&utf16));
163  ASSERT_EQ(std::string("utf16"), narrow);
164  ASSERT_EQ(std::wstring(L"utf16"), wide);
165  ASSERT_EQ(ASCIIToUTF16("utf16"), utf16);
166}
167
168// This is a Value object that allows us to tell if it's been
169// properly deleted by modifying the value of external flag on destruction.
170class DeletionTestValue : public Value {
171 public:
172  explicit DeletionTestValue(bool* deletion_flag) : Value(TYPE_NULL) {
173    Init(deletion_flag);  // Separate function so that we can use ASSERT_*
174  }
175
176  void Init(bool* deletion_flag) {
177    ASSERT_TRUE(deletion_flag);
178    deletion_flag_ = deletion_flag;
179    *deletion_flag_ = false;
180  }
181
182  ~DeletionTestValue() {
183    *deletion_flag_ = true;
184  }
185
186 private:
187  bool* deletion_flag_;
188};
189
190TEST(ValuesTest, ListDeletion) {
191  bool deletion_flag = true;
192
193  {
194    ListValue list;
195    list.Append(new DeletionTestValue(&deletion_flag));
196    EXPECT_FALSE(deletion_flag);
197  }
198  EXPECT_TRUE(deletion_flag);
199
200  {
201    ListValue list;
202    list.Append(new DeletionTestValue(&deletion_flag));
203    EXPECT_FALSE(deletion_flag);
204    list.Clear();
205    EXPECT_TRUE(deletion_flag);
206  }
207
208  {
209    ListValue list;
210    list.Append(new DeletionTestValue(&deletion_flag));
211    EXPECT_FALSE(deletion_flag);
212    EXPECT_TRUE(list.Set(0, Value::CreateNullValue()));
213    EXPECT_TRUE(deletion_flag);
214  }
215}
216
217TEST(ValuesTest, ListRemoval) {
218  bool deletion_flag = true;
219  Value* removed_item = NULL;
220
221  {
222    ListValue list;
223    list.Append(new DeletionTestValue(&deletion_flag));
224    EXPECT_FALSE(deletion_flag);
225    EXPECT_EQ(1U, list.GetSize());
226    EXPECT_FALSE(list.Remove(std::numeric_limits<size_t>::max(),
227                             &removed_item));
228    EXPECT_FALSE(list.Remove(1, &removed_item));
229    EXPECT_TRUE(list.Remove(0, &removed_item));
230    ASSERT_TRUE(removed_item);
231    EXPECT_EQ(0U, list.GetSize());
232  }
233  EXPECT_FALSE(deletion_flag);
234  delete removed_item;
235  removed_item = NULL;
236  EXPECT_TRUE(deletion_flag);
237
238  {
239    ListValue list;
240    list.Append(new DeletionTestValue(&deletion_flag));
241    EXPECT_FALSE(deletion_flag);
242    EXPECT_TRUE(list.Remove(0, NULL));
243    EXPECT_TRUE(deletion_flag);
244    EXPECT_EQ(0U, list.GetSize());
245  }
246
247  {
248    ListValue list;
249    DeletionTestValue* value = new DeletionTestValue(&deletion_flag);
250    list.Append(value);
251    EXPECT_FALSE(deletion_flag);
252    EXPECT_EQ(0, list.Remove(*value));
253    EXPECT_TRUE(deletion_flag);
254    EXPECT_EQ(0U, list.GetSize());
255  }
256}
257
258TEST(ValuesTest, DictionaryDeletion) {
259  std::wstring key = L"test";
260  bool deletion_flag = true;
261
262  {
263    DictionaryValue dict;
264    dict.Set(key, new DeletionTestValue(&deletion_flag));
265    EXPECT_FALSE(deletion_flag);
266  }
267  EXPECT_TRUE(deletion_flag);
268
269  {
270    DictionaryValue dict;
271    dict.Set(key, new DeletionTestValue(&deletion_flag));
272    EXPECT_FALSE(deletion_flag);
273    dict.Clear();
274    EXPECT_TRUE(deletion_flag);
275  }
276
277  {
278    DictionaryValue dict;
279    dict.Set(key, new DeletionTestValue(&deletion_flag));
280    EXPECT_FALSE(deletion_flag);
281    dict.Set(key, Value::CreateNullValue());
282    EXPECT_TRUE(deletion_flag);
283  }
284}
285
286TEST(ValuesTest, DictionaryRemoval) {
287  std::wstring key = L"test";
288  bool deletion_flag = true;
289  Value* removed_item = NULL;
290
291  {
292    DictionaryValue dict;
293    dict.Set(key, new DeletionTestValue(&deletion_flag));
294    EXPECT_FALSE(deletion_flag);
295    EXPECT_TRUE(dict.HasKey(key));
296    EXPECT_FALSE(dict.Remove(L"absent key", &removed_item));
297    EXPECT_TRUE(dict.Remove(key, &removed_item));
298    EXPECT_FALSE(dict.HasKey(key));
299    ASSERT_TRUE(removed_item);
300  }
301  EXPECT_FALSE(deletion_flag);
302  delete removed_item;
303  removed_item = NULL;
304  EXPECT_TRUE(deletion_flag);
305
306  {
307    DictionaryValue dict;
308    dict.Set(key, new DeletionTestValue(&deletion_flag));
309    EXPECT_FALSE(deletion_flag);
310    EXPECT_TRUE(dict.HasKey(key));
311    EXPECT_TRUE(dict.Remove(key, NULL));
312    EXPECT_TRUE(deletion_flag);
313    EXPECT_FALSE(dict.HasKey(key));
314  }
315}
316
317TEST(ValuesTest, DictionaryWithoutPathExpansion) {
318  DictionaryValue dict;
319  dict.Set(L"this.is.expanded", Value::CreateNullValue());
320  dict.SetWithoutPathExpansion(L"this.isnt.expanded", Value::CreateNullValue());
321
322  EXPECT_FALSE(dict.HasKey(L"this.is.expanded"));
323  EXPECT_TRUE(dict.HasKey(L"this"));
324  Value* value1;
325  EXPECT_TRUE(dict.Get(L"this", &value1));
326  DictionaryValue* value2;
327  ASSERT_TRUE(dict.GetDictionaryWithoutPathExpansion(L"this", &value2));
328  EXPECT_EQ(value1, value2);
329  EXPECT_EQ(1U, value2->size());
330
331  EXPECT_TRUE(dict.HasKey(L"this.isnt.expanded"));
332  Value* value3;
333  EXPECT_FALSE(dict.Get(L"this.isnt.expanded", &value3));
334  Value* value4;
335  ASSERT_TRUE(dict.GetWithoutPathExpansion(L"this.isnt.expanded", &value4));
336  EXPECT_EQ(Value::TYPE_NULL, value4->GetType());
337}
338
339TEST(ValuesTest, DeepCopy) {
340  DictionaryValue original_dict;
341  Value* original_null = Value::CreateNullValue();
342  original_dict.Set(L"null", original_null);
343  Value* original_bool = Value::CreateBooleanValue(true);
344  original_dict.Set(L"bool", original_bool);
345  Value* original_int = Value::CreateIntegerValue(42);
346  original_dict.Set(L"int", original_int);
347  Value* original_real = Value::CreateRealValue(3.14);
348  original_dict.Set(L"real", original_real);
349  Value* original_string = Value::CreateStringValue("hello");
350  original_dict.Set(L"string", original_string);
351  Value* original_wstring = Value::CreateStringValue(L"peek-a-boo");
352  original_dict.Set(L"wstring", original_wstring);
353  Value* original_utf16 =
354      Value::CreateStringValueFromUTF16(ASCIIToUTF16("hello16"));
355  original_dict.Set(L"utf16", original_utf16);
356
357  char* original_buffer = new char[42];
358  memset(original_buffer, '!', 42);
359  BinaryValue* original_binary = Value::CreateBinaryValue(original_buffer, 42);
360  original_dict.Set(L"binary", original_binary);
361
362  ListValue* original_list = new ListValue();
363  Value* original_list_element_0 = Value::CreateIntegerValue(0);
364  original_list->Append(original_list_element_0);
365  Value* original_list_element_1 = Value::CreateIntegerValue(1);
366  original_list->Append(original_list_element_1);
367  original_dict.Set(L"list", original_list);
368
369  scoped_ptr<DictionaryValue> copy_dict(
370      static_cast<DictionaryValue*>(original_dict.DeepCopy()));
371  ASSERT_TRUE(copy_dict.get());
372  ASSERT_NE(copy_dict.get(), &original_dict);
373
374  Value* copy_null = NULL;
375  ASSERT_TRUE(copy_dict->Get(L"null", &copy_null));
376  ASSERT_TRUE(copy_null);
377  ASSERT_NE(copy_null, original_null);
378  ASSERT_TRUE(copy_null->IsType(Value::TYPE_NULL));
379
380  Value* copy_bool = NULL;
381  ASSERT_TRUE(copy_dict->Get(L"bool", &copy_bool));
382  ASSERT_TRUE(copy_bool);
383  ASSERT_NE(copy_bool, original_bool);
384  ASSERT_TRUE(copy_bool->IsType(Value::TYPE_BOOLEAN));
385  bool copy_bool_value = false;
386  ASSERT_TRUE(copy_bool->GetAsBoolean(&copy_bool_value));
387  ASSERT_TRUE(copy_bool_value);
388
389  Value* copy_int = NULL;
390  ASSERT_TRUE(copy_dict->Get(L"int", &copy_int));
391  ASSERT_TRUE(copy_int);
392  ASSERT_NE(copy_int, original_int);
393  ASSERT_TRUE(copy_int->IsType(Value::TYPE_INTEGER));
394  int copy_int_value = 0;
395  ASSERT_TRUE(copy_int->GetAsInteger(&copy_int_value));
396  ASSERT_EQ(42, copy_int_value);
397
398  Value* copy_real = NULL;
399  ASSERT_TRUE(copy_dict->Get(L"real", &copy_real));
400  ASSERT_TRUE(copy_real);
401  ASSERT_NE(copy_real, original_real);
402  ASSERT_TRUE(copy_real->IsType(Value::TYPE_REAL));
403  double copy_real_value = 0;
404  ASSERT_TRUE(copy_real->GetAsReal(&copy_real_value));
405  ASSERT_EQ(3.14, copy_real_value);
406
407  Value* copy_string = NULL;
408  ASSERT_TRUE(copy_dict->Get(L"string", &copy_string));
409  ASSERT_TRUE(copy_string);
410  ASSERT_NE(copy_string, original_string);
411  ASSERT_TRUE(copy_string->IsType(Value::TYPE_STRING));
412  std::string copy_string_value;
413  std::wstring copy_wstring_value;
414  string16 copy_utf16_value;
415  ASSERT_TRUE(copy_string->GetAsString(&copy_string_value));
416  ASSERT_TRUE(copy_string->GetAsString(&copy_wstring_value));
417  ASSERT_TRUE(copy_string->GetAsUTF16(&copy_utf16_value));
418  ASSERT_EQ(std::string("hello"), copy_string_value);
419  ASSERT_EQ(std::wstring(L"hello"), copy_wstring_value);
420  ASSERT_EQ(ASCIIToUTF16("hello"), copy_utf16_value);
421
422  Value* copy_wstring = NULL;
423  ASSERT_TRUE(copy_dict->Get(L"wstring", &copy_wstring));
424  ASSERT_TRUE(copy_wstring);
425  ASSERT_NE(copy_wstring, original_wstring);
426  ASSERT_TRUE(copy_wstring->IsType(Value::TYPE_STRING));
427  ASSERT_TRUE(copy_wstring->GetAsString(&copy_string_value));
428  ASSERT_TRUE(copy_wstring->GetAsString(&copy_wstring_value));
429  ASSERT_TRUE(copy_wstring->GetAsUTF16(&copy_utf16_value));
430  ASSERT_EQ(std::string("peek-a-boo"), copy_string_value);
431  ASSERT_EQ(std::wstring(L"peek-a-boo"), copy_wstring_value);
432  ASSERT_EQ(ASCIIToUTF16("peek-a-boo"), copy_utf16_value);
433
434  Value* copy_utf16 = NULL;
435  ASSERT_TRUE(copy_dict->Get(L"utf16", &copy_utf16));
436  ASSERT_TRUE(copy_utf16);
437  ASSERT_NE(copy_utf16, original_utf16);
438  ASSERT_TRUE(copy_utf16->IsType(Value::TYPE_STRING));
439  ASSERT_TRUE(copy_utf16->GetAsString(&copy_string_value));
440  ASSERT_TRUE(copy_utf16->GetAsString(&copy_wstring_value));
441  ASSERT_TRUE(copy_utf16->GetAsUTF16(&copy_utf16_value));
442  ASSERT_EQ(std::string("hello16"), copy_string_value);
443  ASSERT_EQ(std::wstring(L"hello16"), copy_wstring_value);
444  ASSERT_EQ(ASCIIToUTF16("hello16"), copy_utf16_value);
445
446  Value* copy_binary = NULL;
447  ASSERT_TRUE(copy_dict->Get(L"binary", &copy_binary));
448  ASSERT_TRUE(copy_binary);
449  ASSERT_NE(copy_binary, original_binary);
450  ASSERT_TRUE(copy_binary->IsType(Value::TYPE_BINARY));
451  ASSERT_NE(original_binary->GetBuffer(),
452    static_cast<BinaryValue*>(copy_binary)->GetBuffer());
453  ASSERT_EQ(original_binary->GetSize(),
454    static_cast<BinaryValue*>(copy_binary)->GetSize());
455  ASSERT_EQ(0, memcmp(original_binary->GetBuffer(),
456               static_cast<BinaryValue*>(copy_binary)->GetBuffer(),
457               original_binary->GetSize()));
458
459  Value* copy_value = NULL;
460  ASSERT_TRUE(copy_dict->Get(L"list", &copy_value));
461  ASSERT_TRUE(copy_value);
462  ASSERT_NE(copy_value, original_list);
463  ASSERT_TRUE(copy_value->IsType(Value::TYPE_LIST));
464  ListValue* copy_list = static_cast<ListValue*>(copy_value);
465  ASSERT_EQ(2U, copy_list->GetSize());
466
467  Value* copy_list_element_0;
468  ASSERT_TRUE(copy_list->Get(0, &copy_list_element_0));
469  ASSERT_TRUE(copy_list_element_0);
470  ASSERT_NE(copy_list_element_0, original_list_element_0);
471  int copy_list_element_0_value;
472  ASSERT_TRUE(copy_list_element_0->GetAsInteger(&copy_list_element_0_value));
473  ASSERT_EQ(0, copy_list_element_0_value);
474
475  Value* copy_list_element_1;
476  ASSERT_TRUE(copy_list->Get(1, &copy_list_element_1));
477  ASSERT_TRUE(copy_list_element_1);
478  ASSERT_NE(copy_list_element_1, original_list_element_1);
479  int copy_list_element_1_value;
480  ASSERT_TRUE(copy_list_element_1->GetAsInteger(&copy_list_element_1_value));
481  ASSERT_EQ(1, copy_list_element_1_value);
482}
483
484TEST(ValuesTest, Equals) {
485  Value* null1 = Value::CreateNullValue();
486  Value* null2 = Value::CreateNullValue();
487  EXPECT_NE(null1, null2);
488  EXPECT_TRUE(null1->Equals(null2));
489
490  Value* boolean = Value::CreateBooleanValue(false);
491  EXPECT_FALSE(null1->Equals(boolean));
492  delete null1;
493  delete null2;
494  delete boolean;
495
496  DictionaryValue dv;
497  dv.SetBoolean(L"a", false);
498  dv.SetInteger(L"b", 2);
499  dv.SetReal(L"c", 2.5);
500  dv.SetString(L"d1", "string");
501  dv.SetString(L"d2", L"string");
502  dv.Set(L"e", Value::CreateNullValue());
503
504  DictionaryValue* copy = static_cast<DictionaryValue*>(dv.DeepCopy());
505  EXPECT_TRUE(dv.Equals(copy));
506
507  ListValue* list = new ListValue;
508  list->Append(Value::CreateNullValue());
509  list->Append(new DictionaryValue);
510  dv.Set(L"f", list);
511
512  EXPECT_FALSE(dv.Equals(copy));
513  copy->Set(L"f", list->DeepCopy());
514  EXPECT_TRUE(dv.Equals(copy));
515
516  list->Append(Value::CreateBooleanValue(true));
517  EXPECT_FALSE(dv.Equals(copy));
518  delete copy;
519}
520
521TEST(ValuesTest, RemoveEmptyChildren) {
522  scoped_ptr<DictionaryValue> root(new DictionaryValue);
523  // Remove empty lists and dictionaries.
524  root->Set(L"empty_dict", new DictionaryValue);
525  root->Set(L"empty_list", new ListValue);
526  root->SetWithoutPathExpansion(L"a.b.c.d.e", new DictionaryValue);
527  root.reset(root->DeepCopyWithoutEmptyChildren());
528  EXPECT_TRUE(root->empty());
529
530  // Make sure we don't prune too much.
531  root->SetBoolean(L"bool", true);
532  root->Set(L"empty_dict", new DictionaryValue);
533  root->SetString(L"empty_string", "");
534  root.reset(root->DeepCopyWithoutEmptyChildren());
535  EXPECT_EQ(2U, root->size());
536
537  // Should do nothing.
538  root.reset(root->DeepCopyWithoutEmptyChildren());
539  EXPECT_EQ(2U, root->size());
540
541  // Nested test cases.  These should all reduce back to the bool and string
542  // set above.
543  {
544    root->Set(L"a.b.c.d.e", new DictionaryValue);
545    root.reset(root->DeepCopyWithoutEmptyChildren());
546    EXPECT_EQ(2U, root->size());
547  }
548  {
549    DictionaryValue* inner = new DictionaryValue;
550    root->Set(L"dict_with_emtpy_children", inner);
551    inner->Set(L"empty_dict", new DictionaryValue);
552    inner->Set(L"empty_list", new ListValue);
553    root.reset(root->DeepCopyWithoutEmptyChildren());
554    EXPECT_EQ(2U, root->size());
555  }
556  {
557    ListValue* inner = new ListValue;
558    root->Set(L"list_with_empty_children", inner);
559    inner->Append(new DictionaryValue);
560    inner->Append(new ListValue);
561    root.reset(root->DeepCopyWithoutEmptyChildren());
562    EXPECT_EQ(2U, root->size());
563  }
564
565  // Nested with siblings.
566  {
567    ListValue* inner = new ListValue;
568    root->Set(L"list_with_empty_children", inner);
569    inner->Append(new DictionaryValue);
570    inner->Append(new ListValue);
571    DictionaryValue* inner2 = new DictionaryValue;
572    root->Set(L"dict_with_empty_children", inner2);
573    inner2->Set(L"empty_dict", new DictionaryValue);
574    inner2->Set(L"empty_list", new ListValue);
575    root.reset(root->DeepCopyWithoutEmptyChildren());
576    EXPECT_EQ(2U, root->size());
577  }
578
579  // Make sure nested values don't get pruned.
580  {
581    ListValue* inner = new ListValue;
582    root->Set(L"list_with_empty_children", inner);
583    ListValue* inner2 = new ListValue;
584    inner->Append(new DictionaryValue);
585    inner->Append(inner2);
586    inner2->Append(Value::CreateStringValue("hello"));
587    root.reset(root->DeepCopyWithoutEmptyChildren());
588    EXPECT_EQ(3U, root->size());
589    EXPECT_TRUE(root->GetList(L"list_with_empty_children", &inner));
590    EXPECT_EQ(1U, inner->GetSize());  // Dictionary was pruned.
591    EXPECT_TRUE(inner->GetList(0, &inner2));
592    EXPECT_EQ(1U, inner2->GetSize());
593  }
594}
595
596TEST(ValuesTest, MergeDictionary) {
597  scoped_ptr<DictionaryValue> base(new DictionaryValue);
598  base->SetString(L"base_key", "base_key_value_base");
599  base->SetString(L"collide_key", "collide_key_value_base");
600  DictionaryValue* base_sub_dict = new DictionaryValue;
601  base_sub_dict->SetString(L"sub_base_key", "sub_base_key_value_base");
602  base_sub_dict->SetString(L"sub_collide_key", "sub_collide_key_value_base");
603  base->Set(L"sub_dict_key", base_sub_dict);
604
605  scoped_ptr<DictionaryValue> merge(new DictionaryValue);
606  merge->SetString(L"merge_key", "merge_key_value_merge");
607  merge->SetString(L"collide_key", "collide_key_value_merge");
608  DictionaryValue* merge_sub_dict = new DictionaryValue;
609  merge_sub_dict->SetString(L"sub_merge_key", "sub_merge_key_value_merge");
610  merge_sub_dict->SetString(L"sub_collide_key", "sub_collide_key_value_merge");
611  merge->Set(L"sub_dict_key", merge_sub_dict);
612
613  base->MergeDictionary(merge.get());
614
615  EXPECT_EQ(4U, base->size());
616  std::string base_key_value;
617  EXPECT_TRUE(base->GetString(L"base_key", &base_key_value));
618  EXPECT_EQ("base_key_value_base", base_key_value); // Base value preserved.
619  std::string collide_key_value;
620  EXPECT_TRUE(base->GetString(L"collide_key", &collide_key_value));
621  EXPECT_EQ("collide_key_value_merge", collide_key_value); // Replaced.
622  std::string merge_key_value;
623  EXPECT_TRUE(base->GetString(L"merge_key", &merge_key_value));
624  EXPECT_EQ("merge_key_value_merge", merge_key_value); // Merged in.
625
626  DictionaryValue* res_sub_dict;
627  EXPECT_TRUE(base->GetDictionary(L"sub_dict_key", &res_sub_dict));
628  EXPECT_EQ(3U, res_sub_dict->size());
629  std::string sub_base_key_value;
630  EXPECT_TRUE(res_sub_dict->GetString(L"sub_base_key", &sub_base_key_value));
631  EXPECT_EQ("sub_base_key_value_base", sub_base_key_value); // Preserved.
632  std::string sub_collide_key_value;
633  EXPECT_TRUE(res_sub_dict->GetString(L"sub_collide_key",
634                                      &sub_collide_key_value));
635  EXPECT_EQ("sub_collide_key_value_merge", sub_collide_key_value); // Replaced.
636  std::string sub_merge_key_value;
637  EXPECT_TRUE(res_sub_dict->GetString(L"sub_merge_key", &sub_merge_key_value));
638  EXPECT_EQ("sub_merge_key_value_merge", sub_merge_key_value); // Merged in.
639}
640