diff options
author | pkasting@chromium.org <pkasting@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-11-25 20:47:52 +0000 |
---|---|---|
committer | pkasting@chromium.org <pkasting@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-11-25 20:47:52 +0000 |
commit | 4dad9ad838f6671fbd67e1c5292525e739e31983 (patch) | |
tree | 4d79fc17f12752cc221e0e40d16951677da71f92 /base | |
parent | 2b3f0f59a6761a41e22007c2c3096e8e18517e08 (diff) | |
download | chromium_src-4dad9ad838f6671fbd67e1c5292525e739e31983.zip chromium_src-4dad9ad838f6671fbd67e1c5292525e739e31983.tar.gz chromium_src-4dad9ad838f6671fbd67e1c5292525e739e31983.tar.bz2 |
Many changes to DictionaryValues:
* Add support for keys with "." in them via new XXXWithoutPathExpansion() APIs.
* Use these APIs with all key iterator usage.
* SetXXX() calls cannot fail, so change them from bool to void.
* Change GetSize() to size() since it's cheap, and add empty().
Other:
* Use standard for loop format in more places (e.g. instead of while loops when they're really doing a for loop).
* Shorten a few bits of code.
BUG=567
TEST=none
Review URL: http://codereview.chromium.org/441008
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@33109 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base')
-rw-r--r-- | base/json/json_reader.cc | 3 | ||||
-rw-r--r-- | base/json/json_reader_unittest.cc | 59 | ||||
-rw-r--r-- | base/json/json_writer.cc | 2 | ||||
-rw-r--r-- | base/json/json_writer_unittest.cc | 19 | ||||
-rw-r--r-- | base/values.cc | 229 | ||||
-rw-r--r-- | base/values.h | 53 | ||||
-rw-r--r-- | base/values_unittest.cc | 26 |
7 files changed, 269 insertions, 122 deletions
diff --git a/base/json/json_reader.cc b/base/json/json_reader.cc index 06d790c..bdc682b 100644 --- a/base/json/json_reader.cc +++ b/base/json/json_reader.cc @@ -281,7 +281,8 @@ Value* JSONReader::BuildValue(bool is_root) { Value* dict_value = BuildValue(false); if (!dict_value) return NULL; - static_cast<DictionaryValue*>(node.get())->Set(dict_key, dict_value); + static_cast<DictionaryValue*>(node.get())->SetWithoutPathExpansion( + dict_key, dict_value); // After a key/value pair, we expect a comma or the end of the // object. diff --git a/base/json/json_reader_unittest.cc b/base/json/json_reader_unittest.cc index 8ae51c5..17dea56 100644 --- a/base/json/json_reader_unittest.cc +++ b/base/json/json_reader_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Copyright (c) 2009 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -297,8 +297,7 @@ TEST(JSONReaderTest, Reading) { ASSERT_TRUE(root->IsType(Value::TYPE_DICTIONARY)); root.reset(JSONReader::Read( - "{\"number\":9.87654321, \"null\":null , \"\\x53\" : \"str\" }", - false)); + "{\"number\":9.87654321, \"null\":null , \"\\x53\" : \"str\" }", false)); ASSERT_TRUE(root.get()); ASSERT_TRUE(root->IsType(Value::TYPE_DICTIONARY)); DictionaryValue* dict_val = static_cast<DictionaryValue*>(root.get()); @@ -313,32 +312,32 @@ TEST(JSONReaderTest, Reading) { ASSERT_EQ(L"str", str_val); root2.reset(JSONReader::Read( - "{\"number\":9.87654321, \"null\":null , \"\\x53\" : \"str\", }", true)); + "{\"number\":9.87654321, \"null\":null , \"\\x53\" : \"str\", }", true)); ASSERT_TRUE(root2.get()); EXPECT_TRUE(root->Equals(root2.get())); // Test newline equivalence. root2.reset(JSONReader::Read( - "{\n" - " \"number\":9.87654321,\n" - " \"null\":null,\n" - " \"\\x53\":\"str\",\n" - "}\n", true)); + "{\n" + " \"number\":9.87654321,\n" + " \"null\":null,\n" + " \"\\x53\":\"str\",\n" + "}\n", true)); ASSERT_TRUE(root2.get()); EXPECT_TRUE(root->Equals(root2.get())); root2.reset(JSONReader::Read( - "{\r\n" - " \"number\":9.87654321,\r\n" - " \"null\":null,\r\n" - " \"\\x53\":\"str\",\r\n" - "}\r\n", true)); + "{\r\n" + " \"number\":9.87654321,\r\n" + " \"null\":null,\r\n" + " \"\\x53\":\"str\",\r\n" + "}\r\n", true)); ASSERT_TRUE(root2.get()); EXPECT_TRUE(root->Equals(root2.get())); // Test nesting root.reset(JSONReader::Read( - "{\"inner\":{\"array\":[true]},\"false\":false,\"d\":{}}", false)); + "{\"inner\":{\"array\":[true]},\"false\":false,\"d\":{}}", false)); ASSERT_TRUE(root.get()); ASSERT_TRUE(root->IsType(Value::TYPE_DICTIONARY)); dict_val = static_cast<DictionaryValue*>(root.get()); @@ -354,9 +353,37 @@ TEST(JSONReaderTest, Reading) { ASSERT_TRUE(dict_val->GetDictionary(L"d", &inner_dict)); root2.reset(JSONReader::Read( - "{\"inner\": {\"array\":[true] , },\"false\":false,\"d\":{},}", true)); + "{\"inner\": {\"array\":[true] , },\"false\":false,\"d\":{},}", true)); EXPECT_TRUE(root->Equals(root2.get())); + // Test keys with periods + root.reset(JSONReader::Read( + "{\"a.b\":3,\"c\":2,\"d.e.f\":{\"g.h.i.j\":1}}", false)); + ASSERT_TRUE(root.get()); + ASSERT_TRUE(root->IsType(Value::TYPE_DICTIONARY)); + dict_val = static_cast<DictionaryValue*>(root.get()); + int integer_value = 0; + EXPECT_TRUE(dict_val->GetIntegerWithoutPathExpansion(L"a.b", &integer_value)); + EXPECT_EQ(3, integer_value); + EXPECT_TRUE(dict_val->GetIntegerWithoutPathExpansion(L"c", &integer_value)); + EXPECT_EQ(2, integer_value); + inner_dict = NULL; + ASSERT_TRUE(dict_val->GetDictionaryWithoutPathExpansion(L"d.e.f", + &inner_dict)); + ASSERT_EQ(1U, inner_dict->size()); + EXPECT_TRUE(inner_dict->GetIntegerWithoutPathExpansion(L"g.h.i.j", + &integer_value)); + EXPECT_EQ(1, integer_value); + + root.reset(JSONReader::Read("{\"a\":{\"b\":2},\"a.b\":1}", false)); + ASSERT_TRUE(root.get()); + ASSERT_TRUE(root->IsType(Value::TYPE_DICTIONARY)); + dict_val = static_cast<DictionaryValue*>(root.get()); + EXPECT_TRUE(dict_val->GetInteger(L"a.b", &integer_value)); + EXPECT_EQ(2, integer_value); + EXPECT_TRUE(dict_val->GetIntegerWithoutPathExpansion(L"a.b", &integer_value)); + EXPECT_EQ(1, integer_value); + // Invalid, no closing brace root.reset(JSONReader::Read("{\"a\": true", false)); ASSERT_FALSE(root.get()); diff --git a/base/json/json_writer.cc b/base/json/json_writer.cc index 133b625..ffdad76 100644 --- a/base/json/json_writer.cc +++ b/base/json/json_writer.cc @@ -157,7 +157,7 @@ void JSONWriter::BuildJSONString(const Value* const node, } Value* value = NULL; - bool result = dict->Get(*key_itr, &value); + bool result = dict->GetWithoutPathExpansion(*key_itr, &value); DCHECK(result); if (pretty_print_) diff --git a/base/json/json_writer_unittest.cc b/base/json/json_writer_unittest.cc index cd2a6fe..e7d0f05 100644 --- a/base/json/json_writer_unittest.cc +++ b/base/json/json_writer_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Copyright (c) 2009 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -76,6 +76,23 @@ TEST(JSONWriterTest, Writing) { "}" JSON_NEWLINE, output_js); #undef JSON_NEWLINE + + // Test keys with periods + DictionaryValue period_dict; + period_dict.SetWithoutPathExpansion(L"a.b", Value::CreateIntegerValue(3)); + period_dict.SetWithoutPathExpansion(L"c", Value::CreateIntegerValue(2)); + DictionaryValue* period_dict2 = new DictionaryValue; + period_dict2->SetWithoutPathExpansion(L"g.h.i.j", + Value::CreateIntegerValue(1)); + period_dict.SetWithoutPathExpansion(L"d.e.f", period_dict2); + JSONWriter::Write(&period_dict, false, &output_js); + ASSERT_EQ("{\"a.b\":3,\"c\":2,\"d.e.f\":{\"g.h.i.j\":1}}", output_js); + + DictionaryValue period_dict3; + period_dict3.Set(L"a.b", Value::CreateIntegerValue(2)); + period_dict3.SetWithoutPathExpansion(L"a.b", Value::CreateIntegerValue(1)); + JSONWriter::Write(&period_dict3, false, &output_js); + ASSERT_EQ("{\"a\":{\"b\":2},\"a.b\":1}", output_js); } } // namespace base diff --git a/base/values.cc b/base/values.cc index 305f1cb..f66b5968 100644 --- a/base/values.cc +++ b/base/values.cc @@ -253,92 +253,79 @@ bool DictionaryValue::HasKey(const std::wstring& key) const { return current_entry != dictionary_.end(); } -void DictionaryValue::SetInCurrentNode(const std::wstring& key, - Value* in_value) { - // If there's an existing value here, we need to delete it, because - // we own all our children. - if (HasKey(key)) { - DCHECK(dictionary_[key] != in_value); // This would be bogus - delete dictionary_[key]; - } - - dictionary_[key] = in_value; -} - -bool DictionaryValue::Set(const std::wstring& path, Value* in_value) { +void DictionaryValue::Set(const std::wstring& path, Value* in_value) { DCHECK(in_value); - std::wstring key = path; - - size_t delimiter_position = path.find_first_of(L".", 0); - // If there isn't a dictionary delimiter in the path, we're done. - if (delimiter_position == std::wstring::npos) { - SetInCurrentNode(key, in_value); - return true; - } else { - key = path.substr(0, delimiter_position); - } + std::wstring current_path(path); + DictionaryValue* current_dictionary = this; + for (size_t delimiter_position = current_path.find('.'); + delimiter_position != std::wstring::npos; + delimiter_position = current_path.find('.')) { + // Assume that we're indexing into a dictionary. + std::wstring key(current_path, 0, delimiter_position); + DictionaryValue* child_dictionary; + if (!current_dictionary->GetDictionary(key, &child_dictionary)) { + child_dictionary = new DictionaryValue; + current_dictionary->SetWithoutPathExpansion(key, child_dictionary); + } - // Assume that we're indexing into a dictionary. - DictionaryValue* entry = NULL; - if (!HasKey(key) || (dictionary_[key]->GetType() != TYPE_DICTIONARY)) { - entry = new DictionaryValue; - SetInCurrentNode(key, entry); - } else { - entry = static_cast<DictionaryValue*>(dictionary_[key]); + current_dictionary = child_dictionary; + current_path.erase(0, delimiter_position + 1); } - std::wstring remaining_path = path.substr(delimiter_position + 1); - return entry->Set(remaining_path, in_value); + current_dictionary->SetWithoutPathExpansion(current_path, in_value); } -bool DictionaryValue::SetBoolean(const std::wstring& path, bool in_value) { - return Set(path, CreateBooleanValue(in_value)); +void DictionaryValue::SetBoolean(const std::wstring& path, bool in_value) { + Set(path, CreateBooleanValue(in_value)); } -bool DictionaryValue::SetInteger(const std::wstring& path, int in_value) { - return Set(path, CreateIntegerValue(in_value)); +void DictionaryValue::SetInteger(const std::wstring& path, int in_value) { + Set(path, CreateIntegerValue(in_value)); } -bool DictionaryValue::SetReal(const std::wstring& path, double in_value) { - return Set(path, CreateRealValue(in_value)); +void DictionaryValue::SetReal(const std::wstring& path, double in_value) { + Set(path, CreateRealValue(in_value)); } -bool DictionaryValue::SetString(const std::wstring& path, +void DictionaryValue::SetString(const std::wstring& path, const std::string& in_value) { - return Set(path, CreateStringValue(in_value)); + Set(path, CreateStringValue(in_value)); } -bool DictionaryValue::SetString(const std::wstring& path, +void DictionaryValue::SetString(const std::wstring& path, const std::wstring& in_value) { - return Set(path, CreateStringValue(in_value)); + Set(path, CreateStringValue(in_value)); } -bool DictionaryValue::Get(const std::wstring& path, Value** out_value) const { - std::wstring key = path; - - size_t delimiter_position = path.find_first_of(L".", 0); - if (delimiter_position != std::wstring::npos) { - key = path.substr(0, delimiter_position); +void DictionaryValue::SetWithoutPathExpansion(const std::wstring& key, + Value* in_value) { + // If there's an existing value here, we need to delete it, because + // we own all our children. + if (HasKey(key)) { + DCHECK(dictionary_[key] != in_value); // This would be bogus + delete dictionary_[key]; } - ValueMap::const_iterator entry_iterator = dictionary_.find(key); - if (entry_iterator == dictionary_.end()) - return false; - Value* entry = entry_iterator->second; + dictionary_[key] = in_value; +} - if (delimiter_position == std::wstring::npos) { - if (out_value) - *out_value = entry; - return true; - } +bool DictionaryValue::Get(const std::wstring& path, Value** out_value) const { + std::wstring current_path(path); + const DictionaryValue* current_dictionary = this; + for (size_t delimiter_position = current_path.find('.'); + delimiter_position != std::wstring::npos; + delimiter_position = current_path.find('.')) { + DictionaryValue* child_dictionary; + if (!current_dictionary->GetDictionary( + current_path.substr(0, delimiter_position), &child_dictionary)) + return false; - if (entry->IsType(TYPE_DICTIONARY)) { - DictionaryValue* dictionary = static_cast<DictionaryValue*>(entry); - return dictionary->Get(path.substr(delimiter_position + 1), out_value); + current_dictionary = child_dictionary; + current_path.erase(0, delimiter_position + 1); } - return false; + return current_dictionary->GetWithoutPathExpansion(current_path, out_value); } bool DictionaryValue::GetBoolean(const std::wstring& path, @@ -425,44 +412,111 @@ bool DictionaryValue::GetList(const std::wstring& path, return true; } -bool DictionaryValue::Remove(const std::wstring& path, Value** out_value) { - std::wstring key = path; - - size_t delimiter_position = path.find_first_of(L".", 0); - if (delimiter_position != std::wstring::npos) { - key = path.substr(0, delimiter_position); - } - - ValueMap::iterator entry_iterator = dictionary_.find(key); +bool DictionaryValue::GetWithoutPathExpansion(const std::wstring& key, + Value** out_value) const { + ValueMap::const_iterator entry_iterator = dictionary_.find(key); if (entry_iterator == dictionary_.end()) return false; + Value* entry = entry_iterator->second; + if (out_value) + *out_value = entry; + return true; +} - if (delimiter_position == std::wstring::npos) { - if (out_value) - *out_value = entry; - else - delete entry; +bool DictionaryValue::GetIntegerWithoutPathExpansion(const std::wstring& path, + int* out_value) const { + Value* value; + if (!GetWithoutPathExpansion(path, &value)) + return false; - dictionary_.erase(entry_iterator); - return true; - } + return value->GetAsInteger(out_value); +} + +bool DictionaryValue::GetStringWithoutPathExpansion( + const std::wstring& path, + std::string* out_value) const { + Value* value; + if (!GetWithoutPathExpansion(path, &value)) + return false; + + return value->GetAsString(out_value); +} + +bool DictionaryValue::GetStringWithoutPathExpansion( + const std::wstring& path, + std::wstring* out_value) const { + Value* value; + if (!GetWithoutPathExpansion(path, &value)) + return false; + + return value->GetAsString(out_value); +} + +bool DictionaryValue::GetDictionaryWithoutPathExpansion( + const std::wstring& path, + DictionaryValue** out_value) const { + Value* value; + bool result = GetWithoutPathExpansion(path, &value); + if (!result || !value->IsType(TYPE_DICTIONARY)) + return false; + + if (out_value) + *out_value = static_cast<DictionaryValue*>(value); + + return true; +} - if (entry->IsType(TYPE_DICTIONARY)) { - DictionaryValue* dictionary = static_cast<DictionaryValue*>(entry); - return dictionary->Remove(path.substr(delimiter_position + 1), out_value); +bool DictionaryValue::GetListWithoutPathExpansion(const std::wstring& path, + ListValue** out_value) const { + Value* value; + bool result = GetWithoutPathExpansion(path, &value); + if (!result || !value->IsType(TYPE_LIST)) + return false; + + if (out_value) + *out_value = static_cast<ListValue*>(value); + + return true; +} + +bool DictionaryValue::Remove(const std::wstring& path, Value** out_value) { + std::wstring current_path(path); + DictionaryValue* current_dictionary = this; + size_t delimiter_position = current_path.rfind('.'); + if (delimiter_position != std::wstring::npos) { + if (!GetDictionary(current_path.substr(0, delimiter_position), + ¤t_dictionary)) + return false; + current_path.erase(0, delimiter_position + 1); } - return false; + return current_dictionary->RemoveWithoutPathExpansion(current_path, + out_value); +} + +bool DictionaryValue::RemoveWithoutPathExpansion(const std::wstring& key, + Value** out_value) { + ValueMap::iterator entry_iterator = dictionary_.find(key); + if (entry_iterator == dictionary_.end()) + return false; + + Value* entry = entry_iterator->second; + if (out_value) + *out_value = entry; + else + delete entry; + dictionary_.erase(entry_iterator); + return true; } Value* DictionaryValue::DeepCopy() const { DictionaryValue* result = new DictionaryValue; - ValueMap::const_iterator current_entry = dictionary_.begin(); - while (current_entry != dictionary_.end()) { - result->Set(current_entry->first, current_entry->second->DeepCopy()); - ++current_entry; + for (ValueMap::const_iterator current_entry(dictionary_.begin()); + current_entry != dictionary_.end(); ++current_entry) { + result->SetWithoutPathExpansion(current_entry->first, + current_entry->second->DeepCopy()); } return result; @@ -479,7 +533,8 @@ bool DictionaryValue::Equals(const Value* other) const { while (lhs_it != end_keys() && rhs_it != other_dict->end_keys()) { Value* lhs; Value* rhs; - if (!Get(*lhs_it, &lhs) || !other_dict->Get(*rhs_it, &rhs) || + if (!GetWithoutPathExpansion(*lhs_it, &lhs) || + !other_dict->GetWithoutPathExpansion(*rhs_it, &rhs) || !lhs->Equals(rhs)) { return false; } diff --git a/base/values.h b/base/values.h index b3c380c..49ce287 100644 --- a/base/values.h +++ b/base/values.h @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Copyright (c) 2009 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -207,7 +207,10 @@ class DictionaryValue : public Value { bool HasKey(const std::wstring& key) const; // Returns the number of Values in this dictionary. - size_t GetSize() const { return dictionary_.size(); } + size_t size() const { return dictionary_.size(); } + + // Returns whether the dictionary is empty. + bool empty() const { return dictionary_.empty(); } // Clears any current contents of this dictionary. void Clear(); @@ -220,16 +223,20 @@ class DictionaryValue : public Value { // a DictionaryValue, a new DictionaryValue will be created and attached // to the path in that location. // Note that the dictionary takes ownership of the value referenced by - // |in_value|. - bool Set(const std::wstring& path, Value* in_value); + // |in_value|, and therefore |in_value| must be non-NULL. + void Set(const std::wstring& path, Value* in_value); // Convenience forms of Set(). These methods will replace any existing // value at that path, even if it has a different type. - bool SetBoolean(const std::wstring& path, bool in_value); - bool SetInteger(const std::wstring& path, int in_value); - bool SetReal(const std::wstring& path, double in_value); - bool SetString(const std::wstring& path, const std::string& in_value); - bool SetString(const std::wstring& path, const std::wstring& in_value); + void SetBoolean(const std::wstring& path, bool in_value); + void SetInteger(const std::wstring& path, int in_value); + void SetReal(const std::wstring& path, double in_value); + void SetString(const std::wstring& path, const std::string& in_value); + void SetString(const std::wstring& path, const std::wstring& in_value); + + // Like Set(), but without special treatment of '.'. This allows e.g. URLs to + // be used as paths. + void SetWithoutPathExpansion(const std::wstring& key, Value* in_value); // Gets the Value associated with the given path starting from this object. // A path has the form "<key>" or "<key>.<key>.[...]", where "." indexes @@ -253,6 +260,21 @@ class DictionaryValue : public Value { DictionaryValue** out_value) const; bool GetList(const std::wstring& path, ListValue** out_value) const; + // Like Get(), but without special treatment of '.'. This allows e.g. URLs to + // be used as paths. + bool GetWithoutPathExpansion(const std::wstring& key, + Value** out_value) const; + bool GetIntegerWithoutPathExpansion(const std::wstring& path, + int* out_value) const; + bool GetStringWithoutPathExpansion(const std::wstring& path, + std::string* out_value) const; + bool GetStringWithoutPathExpansion(const std::wstring& path, + std::wstring* out_value) const; + bool GetDictionaryWithoutPathExpansion(const std::wstring& path, + DictionaryValue** out_value) const; + bool GetListWithoutPathExpansion(const std::wstring& path, + ListValue** out_value) const; + // Removes the Value with the specified path from this dictionary (or one // of its child dictionaries, if the path is more than just a local key). // If |out_value| is non-NULL, the removed Value AND ITS OWNERSHIP will be @@ -261,8 +283,16 @@ class DictionaryValue : public Value { // it will return false and the DictionaryValue object will be unchanged. bool Remove(const std::wstring& path, Value** out_value); + // Like Remove(), but without special treatment of '.'. This allows e.g. URLs + // to be used as paths. + bool RemoveWithoutPathExpansion(const std::wstring& key, Value** out_value); + // This class provides an iterator for the keys in the dictionary. // It can't be used to modify the dictionary. + // + // YOU SHOULD ALWAYS USE THE XXXWithoutPathExpansion() APIs WITH THESE, NOT + // THE NORMAL XXX() APIs. This makes sure things will work correctly if any + // keys have '.'s in them. class key_iterator : private std::iterator<std::input_iterator_tag, const std::wstring> { public: @@ -280,11 +310,6 @@ class DictionaryValue : public Value { key_iterator end_keys() const { return key_iterator(dictionary_.end()); } private: - // Associates the value |in_value| with the |key|. This method should be - // used instead of "dictionary_[key] = foo" so that any previous value can - // be properly deleted. - void SetInCurrentNode(const std::wstring& key, Value* in_value); - ValueMap dictionary_; DISALLOW_COPY_AND_ASSIGN(DictionaryValue); diff --git a/base/values_unittest.cc b/base/values_unittest.cc index 5253eca..0182d76 100644 --- a/base/values_unittest.cc +++ b/base/values_unittest.cc @@ -20,9 +20,9 @@ TEST(ValuesTest, Basic) { ASSERT_EQ(std::wstring(L"http://google.com"), homepage); ASSERT_FALSE(settings.Get(L"global", NULL)); - ASSERT_TRUE(settings.Set(L"global", Value::CreateBooleanValue(true))); + settings.Set(L"global", Value::CreateBooleanValue(true)); ASSERT_TRUE(settings.Get(L"global", NULL)); - ASSERT_TRUE(settings.SetString(L"global.homepage", L"http://scurvy.com")); + settings.SetString(L"global.homepage", L"http://scurvy.com"); ASSERT_TRUE(settings.Get(L"global", NULL)); homepage = L"http://google.com"; ASSERT_TRUE(settings.GetString(L"global.homepage", &homepage)); @@ -285,6 +285,28 @@ TEST(ValuesTest, DictionaryRemoval) { } } +TEST(ValuesTest, DictionaryWithoutPathExpansion) { + DictionaryValue dict; + dict.Set(L"this.is.expanded", Value::CreateNullValue()); + dict.SetWithoutPathExpansion(L"this.isnt.expanded", Value::CreateNullValue()); + + EXPECT_FALSE(dict.HasKey(L"this.is.expanded")); + EXPECT_TRUE(dict.HasKey(L"this")); + Value* value1; + EXPECT_TRUE(dict.Get(L"this", &value1)); + DictionaryValue* value2; + ASSERT_TRUE(dict.GetDictionaryWithoutPathExpansion(L"this", &value2)); + EXPECT_EQ(value1, value2); + EXPECT_EQ(1U, value2->size()); + + EXPECT_TRUE(dict.HasKey(L"this.isnt.expanded")); + Value* value3; + EXPECT_FALSE(dict.Get(L"this.isnt.expanded", &value3)); + Value* value4; + ASSERT_TRUE(dict.GetWithoutPathExpansion(L"this.isnt.expanded", &value4)); + EXPECT_EQ(Value::TYPE_NULL, value4->GetType()); +} + TEST(ValuesTest, DeepCopy) { DictionaryValue original_dict; Value* original_null = Value::CreateNullValue(); |