• 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