Home | History | Annotate | Download | only in base
      1 // Copyright (c) 2009 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 
     13 class ValuesTest: public testing::Test {
     14 };
     15 
     16 TEST(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 
     61 TEST(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 
     96 TEST(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 
    129 TEST(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.
    170 class 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 
    190 TEST(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 
    217 TEST(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 
    258 TEST(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 
    286 TEST(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 
    317 TEST(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 
    339 TEST(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 
    484 TEST(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 
    521 TEST(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