• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
13 class ValuesTest : public testing::Test {
14 };
15 
TEST_F(ValuesTest,Basic)16 TEST_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 
TEST_F(ValuesTest,List)59 TEST_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 
TEST_F(ValuesTest,BinaryValue)94 TEST_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 
TEST_F(ValuesTest,StringValue)127 TEST_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.
153 class DeletionTestValue : public Value {
154  public:
DeletionTestValue(bool * deletion_flag)155   explicit DeletionTestValue(bool* deletion_flag) : Value(TYPE_NULL) {
156     Init(deletion_flag);  // Separate function so that we can use ASSERT_*
157   }
158 
Init(bool * deletion_flag)159   void Init(bool* deletion_flag) {
160     ASSERT_TRUE(deletion_flag);
161     deletion_flag_ = deletion_flag;
162     *deletion_flag_ = false;
163   }
164 
~DeletionTestValue()165   ~DeletionTestValue() {
166     *deletion_flag_ = true;
167   }
168 
169  private:
170   bool* deletion_flag_;
171 };
172 
TEST_F(ValuesTest,ListDeletion)173 TEST_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 
TEST_F(ValuesTest,ListRemoval)200 TEST_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 
TEST_F(ValuesTest,DictionaryDeletion)241 TEST_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 
TEST_F(ValuesTest,DictionaryRemoval)269 TEST_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 
TEST_F(ValuesTest,DictionaryWithoutPathExpansion)300 TEST_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 
TEST_F(ValuesTest,DeepCopy)322 TEST_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 
TEST_F(ValuesTest,Equals)447 TEST_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 
TEST_F(ValuesTest,StaticEquals)491 TEST_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 
TEST_F(ValuesTest,DeepCopyCovariantReturnTypes)514 TEST_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 
TEST_F(ValuesTest,RemoveEmptyChildren)570 TEST_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 
TEST_F(ValuesTest,MergeDictionary)645 TEST_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