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