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", ©_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", ©_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(©_bool_value)); 387 ASSERT_TRUE(copy_bool_value); 388 389 Value* copy_int = NULL; 390 ASSERT_TRUE(copy_dict->Get(L"int", ©_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(©_int_value)); 396 ASSERT_EQ(42, copy_int_value); 397 398 Value* copy_real = NULL; 399 ASSERT_TRUE(copy_dict->Get(L"real", ©_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(©_real_value)); 405 ASSERT_EQ(3.14, copy_real_value); 406 407 Value* copy_string = NULL; 408 ASSERT_TRUE(copy_dict->Get(L"string", ©_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(©_string_value)); 416 ASSERT_TRUE(copy_string->GetAsString(©_wstring_value)); 417 ASSERT_TRUE(copy_string->GetAsUTF16(©_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", ©_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(©_string_value)); 428 ASSERT_TRUE(copy_wstring->GetAsString(©_wstring_value)); 429 ASSERT_TRUE(copy_wstring->GetAsUTF16(©_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", ©_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(©_string_value)); 440 ASSERT_TRUE(copy_utf16->GetAsString(©_wstring_value)); 441 ASSERT_TRUE(copy_utf16->GetAsUTF16(©_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", ©_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", ©_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, ©_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(©_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, ©_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(©_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