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", ©_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", ©_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(©_bool_value));
367 ASSERT_TRUE(copy_bool_value);
368
369 Value* copy_int = NULL;
370 ASSERT_TRUE(copy_dict->Get("int", ©_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(©_int_value));
376 ASSERT_EQ(42, copy_int_value);
377
378 Value* copy_double = NULL;
379 ASSERT_TRUE(copy_dict->Get("double", ©_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(©_double_value));
385 ASSERT_EQ(3.14, copy_double_value);
386
387 Value* copy_string = NULL;
388 ASSERT_TRUE(copy_dict->Get("string", ©_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(©_string_value));
395 ASSERT_TRUE(copy_string->GetAsString(©_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", ©_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(©_string_value));
405 ASSERT_TRUE(copy_string16->GetAsString(©_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", ©_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", ©_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, ©_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(©_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, ©_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(©_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