diff options
author | rouslan@chromium.org <rouslan@chromium.org@38ededc0-08b8-5190-f2ac-b31f878777ad> | 2014-05-28 17:07:07 +0000 |
---|---|---|
committer | rouslan@chromium.org <rouslan@chromium.org@38ededc0-08b8-5190-f2ac-b31f878777ad> | 2014-05-28 17:07:07 +0000 |
commit | 018e8c28bb50ae78b83921f7211667407512b706 (patch) | |
tree | 10757bab69c15562271723dea11af5781ffa8edb | |
parent | ea5e77397b59d94af3591644c3dc23dc6f9ba22e (diff) | |
download | src-018e8c28bb50ae78b83921f7211667407512b706.tar.gz |
Separate region data builder from preload supplier.
R=roubert@google.com
Review URL: https://codereview.appspot.com/101830044
git-svn-id: http://libaddressinput.googlecode.com/svn/trunk@256 38ededc0-08b8-5190-f2ac-b31f878777ad
-rw-r--r-- | cpp/include/libaddressinput/preload_supplier.h | 38 | ||||
-rw-r--r-- | cpp/include/libaddressinput/region_data_builder.h | 80 | ||||
-rw-r--r-- | cpp/libaddressinput.gypi | 2 | ||||
-rw-r--r-- | cpp/src/preload_supplier.cc | 113 | ||||
-rw-r--r-- | cpp/src/region_data_builder.cc | 147 | ||||
-rw-r--r-- | cpp/test/preload_supplier_test.cc | 46 | ||||
-rw-r--r-- | cpp/test/region_data_builder_test.cc | 98 |
7 files changed, 337 insertions, 187 deletions
diff --git a/cpp/include/libaddressinput/preload_supplier.h b/cpp/include/libaddressinput/preload_supplier.h index 7226126..447911f 100644 --- a/cpp/include/libaddressinput/preload_supplier.h +++ b/cpp/include/libaddressinput/preload_supplier.h @@ -29,7 +29,6 @@ namespace addressinput { class Downloader; class LookupKey; -class RegionData; class Retriever; class Rule; class Storage; @@ -83,52 +82,15 @@ class PreloadSupplier : public Supplier { bool IsLoaded(const std::string& region_code) const; bool IsPending(const std::string& region_code) const; - // Returns a tree of administrative subdivisions for the |region_code|. - // Examples: - // US with en-US UI language. - // |______________________ - // | | | - // v v v - // AL:Alabama AK:Alaska AS:American Samoa ... - // - // KR with ko-Latn UI language. - // |______________________________________ - // | | | - // v v v - // 강원도:Gangwon 경기도:Gyeonggi 경상남도:Gyeongnam ... - // - // KR with ko-KR UI language. - // |_______________________________ - // | | | - // v v v - // 강원도:강원 경기도:경기 경상남도:경남 ... - // - // The BCP 47 |ui_language_tag| is used to choose the best supported language - // tag for this region (assigned to |best_region_tree_language_tag|). For - // example, Canada has both English and French names for its administrative - // subdivisions. If the UI language is French, then the French names are used. - // The |best_region_tree_language_tag| value may be an empty string. - // - // Should be called only if IsLoaded(region_code) returns true. The - // |best_region_tree_language_tag| parameter should not be NULL. - const RegionData& BuildRegionTree(const std::string& region_code, - const std::string& ui_language_tag, - std::string* best_region_tree_language_tag); - private: - typedef std::map<std::string, const RegionData*> LanguageRegionMap; - typedef std::map<std::string, LanguageRegionMap*> RegionCodeDataMap; - bool GetRuleHierarchy(const LookupKey& lookup_key, RuleHierarchy* hierarchy) const; bool IsLoadedKey(const std::string& key) const; bool IsPendingKey(const std::string& key) const; - static std::string KeyFromRegionCode(const std::string& region_code); const scoped_ptr<const Retriever> retriever_; std::set<std::string> pending_; std::map<std::string, const Rule*> rule_cache_; - RegionCodeDataMap region_data_cache_; DISALLOW_COPY_AND_ASSIGN(PreloadSupplier); }; diff --git a/cpp/include/libaddressinput/region_data_builder.h b/cpp/include/libaddressinput/region_data_builder.h new file mode 100644 index 0000000..906ca36 --- /dev/null +++ b/cpp/include/libaddressinput/region_data_builder.h @@ -0,0 +1,80 @@ +// Copyright (C) 2014 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef I18N_ADDRESSINPUT_REGION_DATA_BUILDER_H_ +#define I18N_ADDRESSINPUT_REGION_DATA_BUILDER_H_ + +#include <libaddressinput/util/basictypes.h> + +#include <map> +#include <string> + +namespace i18n { +namespace addressinput { + +class PreloadSupplier; +class RegionData; + +class RegionDataBuilder { + public: + // Does not take ownership of |supplier|, which should not be NULL. + explicit RegionDataBuilder(PreloadSupplier* supplier); + ~RegionDataBuilder(); + + // Returns a tree of administrative subdivisions for the |region_code|. + // Examples: + // US with en-US UI language. + // |______________________ + // | | | + // v v v + // AL:Alabama AK:Alaska AS:American Samoa ... + // + // KR with ko-Latn UI language. + // |______________________________________ + // | | | + // v v v + // 강원도:Gangwon 경기도:Gyeonggi 경상남도:Gyeongnam ... + // + // KR with ko-KR UI language. + // |_______________________________ + // | | | + // v v v + // 강원도:강원 경기도:경기 경상남도:경남 ... + // + // The BCP 47 |ui_language_tag| is used to choose the best supported language + // tag for this region (assigned to |best_region_tree_language_tag|). For + // example, Canada has both English and French names for its administrative + // subdivisions. If the UI language is French, then the French names are used. + // The |best_region_tree_language_tag| value may be an empty string. + // + // Should be called only if supplier->IsLoaded(region_code) returns true. The + // |best_region_tree_language_tag| parameter should not be NULL. + const RegionData& Build(const std::string& region_code, + const std::string& ui_language_tag, + std::string* best_region_tree_language_tag); + + private: + typedef std::map<std::string, const RegionData*> LanguageRegionMap; + typedef std::map<std::string, LanguageRegionMap*> RegionCodeDataMap; + + PreloadSupplier* const supplier_; // Not owned. + RegionCodeDataMap cache_; + + DISALLOW_COPY_AND_ASSIGN(RegionDataBuilder); +}; + +} // namespace addressinput +} // namespace i18n + +#endif // I18N_ADDRESSINPUT_REGION_DATA_BUILDER_H_ diff --git a/cpp/libaddressinput.gypi b/cpp/libaddressinput.gypi index 62ebe88..f5e668c 100644 --- a/cpp/libaddressinput.gypi +++ b/cpp/libaddressinput.gypi @@ -32,6 +32,7 @@ 'src/post_box_matchers.cc', 'src/preload_supplier.cc', 'src/region_data.cc', + 'src/region_data_builder.cc', 'src/region_data_constants.cc', 'src/retriever.cc', 'src/rule.cc', @@ -68,6 +69,7 @@ 'test/ondemand_supplier_test.cc', 'test/post_box_matchers_test.cc', 'test/preload_supplier_test.cc', + 'test/region_data_builder_test.cc', 'test/region_data_constants_test.cc', 'test/region_data_test.cc', 'test/retriever_test.cc', diff --git a/cpp/src/preload_supplier.cc b/cpp/src/preload_supplier.cc index 9504cc6..be438a2 100644 --- a/cpp/src/preload_supplier.cc +++ b/cpp/src/preload_supplier.cc @@ -17,7 +17,6 @@ #include <libaddressinput/address_data.h> #include <libaddressinput/address_field.h> #include <libaddressinput/callback.h> -#include <libaddressinput/region_data.h> #include <libaddressinput/supplier.h> #include <libaddressinput/util/basictypes.h> #include <libaddressinput/util/scoped_ptr.h> @@ -134,58 +133,12 @@ class Helper { DISALLOW_COPY_AND_ASSIGN(Helper); }; -// Does not take ownership of |supplier| or |parent_region|, neither of which is -// allowed to be NULL. -void BuildRegionTreeRecursively(PreloadSupplier* supplier, - const LookupKey& parent_key, - RegionData* parent_region, - const std::vector<std::string>& keys, - bool prefer_latin_name) { - assert(supplier != NULL); - assert(parent_region != NULL); - - LookupKey lookup_key; - for (std::vector<std::string>::const_iterator key_it = keys.begin(); - key_it != keys.end(); ++key_it) { - lookup_key.FromLookupKey(parent_key, *key_it); - const Rule* rule = supplier->GetRule(lookup_key); - if (rule == NULL) { - return; - } - const std::string& local_name = rule->GetName().empty() - ? *key_it : rule->GetName(); - const std::string& name = - prefer_latin_name && !rule->GetLatinName().empty() - ? rule->GetLatinName() : local_name; - RegionData* region = parent_region->AddSubRegion(*key_it, name); - if (!rule->GetSubKeys().empty()) { - BuildRegionTreeRecursively(supplier, lookup_key, region, - rule->GetSubKeys(), prefer_latin_name); - } - } -} - -// Does not take ownership of |supplier|, which cannot be NULL. The caller owns -// the result. -RegionData* BuildRegion(PreloadSupplier* supplier, - const std::string& region_code, - const Language& language) { - assert(supplier != NULL); - +std::string KeyFromRegionCode(const std::string& region_code) { AddressData address; address.region_code = region_code; - LookupKey lookup_key; lookup_key.FromAddress(address); - - const Rule* const rule = supplier->GetRule(lookup_key); - assert(rule != NULL); - - RegionData* region = new RegionData(region_code); - BuildRegionTreeRecursively(supplier, lookup_key, region, - rule->GetSubKeys(), language.has_latin_script); - - return region; + return lookup_key.ToKeyString(0); // Zero depth = COUNTRY level. } } // namespace @@ -195,23 +148,12 @@ PreloadSupplier::PreloadSupplier(const std::string& validation_data_url, Storage* storage) : retriever_(new Retriever(validation_data_url, downloader, storage)), pending_(), - rule_cache_(), - region_data_cache_() {} + rule_cache_() {} PreloadSupplier::~PreloadSupplier() { for (std::map<std::string, const Rule*>::const_iterator - rule_it = rule_cache_.begin(); rule_it != rule_cache_.end(); ++rule_it) { - delete rule_it->second; - } - - for (RegionCodeDataMap::const_iterator region_it = region_data_cache_.begin(); - region_it != region_data_cache_.end(); ++region_it) { - for (LanguageRegionMap::const_iterator - language_it = region_it->second->begin(); - language_it != region_it->second->end(); ++language_it) { - delete language_it->second; - } - delete region_it->second; + it = rule_cache_.begin(); it != rule_cache_.end(); ++it) { + delete it->second; } } @@ -261,42 +203,6 @@ bool PreloadSupplier::IsPending(const std::string& region_code) const { return IsPendingKey(KeyFromRegionCode(region_code)); } -const RegionData& PreloadSupplier::BuildRegionTree( - const std::string& region_code, - const std::string& ui_language_tag, - std::string* best_region_tree_language_tag) { - assert(IsLoaded(region_code)); - assert(best_region_tree_language_tag != NULL); - - // Look up the region tree in cache first before building it. - RegionCodeDataMap::const_iterator region_it = - region_data_cache_.find(region_code); - if (region_it == region_data_cache_.end()) { - region_it = region_data_cache_.insert( - std::make_pair(region_code, new LanguageRegionMap)).first; - } - - // No need to copy from default rule first, because only languages and Latin - // format are going to be used, which do not exist in the default rule. - Rule rule; - rule.ParseSerializedRule(RegionDataConstants::GetRegionData(region_code)); - static const Language kUndefinedLanguage("und"); - const Language& best_language = rule.GetLanguages().empty() - ? kUndefinedLanguage - : ChooseBestAddressLanguage(rule, Language(ui_language_tag)); - *best_region_tree_language_tag = best_language.tag; - - LanguageRegionMap::const_iterator language_it = - region_it->second->find(best_language.tag); - if (language_it == region_it->second->end()) { - language_it = region_it->second->insert( - std::make_pair(best_language.tag, - BuildRegion(this, region_code, best_language))).first; - } - - return *language_it->second; -} - bool PreloadSupplier::GetRuleHierarchy(const LookupKey& lookup_key, RuleHierarchy* hierarchy) const { assert(hierarchy != NULL); @@ -328,14 +234,5 @@ bool PreloadSupplier::IsPendingKey(const std::string& key) const { return pending_.find(key) != pending_.end(); } -// static -std::string PreloadSupplier::KeyFromRegionCode(const std::string& region_code) { - AddressData address; - address.region_code = region_code; - LookupKey lookup_key; - lookup_key.FromAddress(address); - return lookup_key.ToKeyString(0); // Zero depth = COUNTRY level. -} - } // namespace addressinput } // namespace i18n diff --git a/cpp/src/region_data_builder.cc b/cpp/src/region_data_builder.cc new file mode 100644 index 0000000..82d223c --- /dev/null +++ b/cpp/src/region_data_builder.cc @@ -0,0 +1,147 @@ +// Copyright (C) 2014 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include <libaddressinput/region_data_builder.h> + +#include <libaddressinput/address_data.h> +#include <libaddressinput/preload_supplier.h> +#include <libaddressinput/region_data.h> + +#include <cassert> +#include <cstddef> +#include <string> +#include <utility> +#include <vector> + +#include "language.h" +#include "lookup_key.h" +#include "region_data_constants.h" +#include "rule.h" + +namespace i18n { +namespace addressinput { + +namespace { + +// Does not take ownership of |supplier| or |parent_region|, neither of which is +// allowed to be NULL. +void BuildRegionTreeRecursively(PreloadSupplier* supplier, + const LookupKey& parent_key, + RegionData* parent_region, + const std::vector<std::string>& keys, + bool prefer_latin_name) { + assert(supplier != NULL); + assert(parent_region != NULL); + + LookupKey lookup_key; + for (std::vector<std::string>::const_iterator key_it = keys.begin(); + key_it != keys.end(); ++key_it) { + lookup_key.FromLookupKey(parent_key, *key_it); + const Rule* rule = supplier->GetRule(lookup_key); + if (rule == NULL) { + return; + } + const std::string& local_name = rule->GetName().empty() + ? *key_it : rule->GetName(); + const std::string& name = + prefer_latin_name && !rule->GetLatinName().empty() + ? rule->GetLatinName() : local_name; + RegionData* region = parent_region->AddSubRegion(*key_it, name); + if (!rule->GetSubKeys().empty()) { + BuildRegionTreeRecursively(supplier, lookup_key, region, + rule->GetSubKeys(), prefer_latin_name); + } + } +} + +// Does not take ownership of |supplier|, which cannot be NULL. The caller owns +// the result. +RegionData* BuildRegion(PreloadSupplier* supplier, + const std::string& region_code, + const Language& language) { + assert(supplier != NULL); + + AddressData address; + address.region_code = region_code; + + LookupKey lookup_key; + lookup_key.FromAddress(address); + + const Rule* const rule = supplier->GetRule(lookup_key); + assert(rule != NULL); + + RegionData* region = new RegionData(region_code); + BuildRegionTreeRecursively(supplier, lookup_key, region, + rule->GetSubKeys(), language.has_latin_script); + + return region; +} + +} // namespace + +RegionDataBuilder::RegionDataBuilder(PreloadSupplier* supplier) + : supplier_(supplier), + cache_() { + assert(supplier_ != NULL); +} + +RegionDataBuilder::~RegionDataBuilder() { + for (RegionCodeDataMap::const_iterator region_it = cache_.begin(); + region_it != cache_.end(); ++region_it) { + for (LanguageRegionMap::const_iterator + language_it = region_it->second->begin(); + language_it != region_it->second->end(); ++language_it) { + delete language_it->second; + } + delete region_it->second; + } +} + +const RegionData& RegionDataBuilder::Build( + const std::string& region_code, + const std::string& ui_language_tag, + std::string* best_region_tree_language_tag) { + assert(supplier_->IsLoaded(region_code)); + assert(best_region_tree_language_tag != NULL); + + // Look up the region tree in cache first before building it. + RegionCodeDataMap::const_iterator region_it = cache_.find(region_code); + if (region_it == cache_.end()) { + region_it = + cache_.insert(std::make_pair(region_code, new LanguageRegionMap)).first; + } + + // No need to copy from default rule first, because only languages and Latin + // format are going to be used, which do not exist in the default rule. + Rule rule; + rule.ParseSerializedRule(RegionDataConstants::GetRegionData(region_code)); + static const Language kUndefinedLanguage("und"); + const Language& best_language = rule.GetLanguages().empty() + ? kUndefinedLanguage + : ChooseBestAddressLanguage(rule, Language(ui_language_tag)); + *best_region_tree_language_tag = best_language.tag; + + LanguageRegionMap::const_iterator language_it = + region_it->second->find(best_language.tag); + if (language_it == region_it->second->end()) { + language_it = region_it->second->insert(std::make_pair( + best_language.tag, + BuildRegion(supplier_, region_code, best_language))).first; + } + + return *language_it->second; +} + +} // namespace addressinput +} // namespace i18n diff --git a/cpp/test/preload_supplier_test.cc b/cpp/test/preload_supplier_test.cc index 3ddbc34..b812ef1 100644 --- a/cpp/test/preload_supplier_test.cc +++ b/cpp/test/preload_supplier_test.cc @@ -17,7 +17,6 @@ #include <libaddressinput/address_data.h> #include <libaddressinput/callback.h> #include <libaddressinput/null_storage.h> -#include <libaddressinput/region_data.h> #include <libaddressinput/util/basictypes.h> #include <libaddressinput/util/scoped_ptr.h> @@ -38,7 +37,6 @@ using i18n::addressinput::FakeDownloader; using i18n::addressinput::LookupKey; using i18n::addressinput::NullStorage; using i18n::addressinput::PreloadSupplier; -using i18n::addressinput::RegionData; using i18n::addressinput::Rule; using i18n::addressinput::scoped_ptr; @@ -48,22 +46,20 @@ class PreloadSupplierTest : public testing::Test { : supplier_(FakeDownloader::kFakeAggregateDataUrl, new FakeDownloader, new NullStorage), - loaded_callback_(BuildCallback(this, &PreloadSupplierTest::OnLoaded)), - best_language_() {} + loaded_callback_(BuildCallback(this, &PreloadSupplierTest::OnLoaded)) {} - ~PreloadSupplierTest() {} + virtual ~PreloadSupplierTest() {} PreloadSupplier supplier_; scoped_ptr<PreloadSupplier::Callback> loaded_callback_; - std::string best_language_; private: void OnLoaded(bool success, const std::string& region_code, const int& num_rules) { - EXPECT_TRUE(success); - EXPECT_FALSE(region_code.empty()); - EXPECT_LT(0, num_rules); + ASSERT_TRUE(success); + ASSERT_FALSE(region_code.empty()); + ASSERT_LT(0, num_rules); ASSERT_TRUE(supplier_.IsLoaded(region_code)); } @@ -127,36 +123,4 @@ TEST_F(PreloadSupplierTest, GetTooPreciseRule) { EXPECT_TRUE(rule == NULL); } -TEST_F(PreloadSupplierTest, BuildUsRegionTree) { - supplier_.LoadRules("US", *loaded_callback_); - const RegionData& tree = - supplier_.BuildRegionTree("US", "en-US", &best_language_); - EXPECT_FALSE(tree.sub_regions().empty()); -} - -TEST_F(PreloadSupplierTest, BuildCnRegionTree) { - supplier_.LoadRules("CN", *loaded_callback_); - const RegionData& tree = - supplier_.BuildRegionTree("CN", "zh-Hans", &best_language_); - ASSERT_FALSE(tree.sub_regions().empty()); - EXPECT_FALSE(tree.sub_regions().front()->sub_regions().empty()); -} - -TEST_F(PreloadSupplierTest, BuildChRegionTree) { - supplier_.LoadRules("CH", *loaded_callback_); - const RegionData& tree = - supplier_.BuildRegionTree("CH", "de-CH", &best_language_); - // Although "CH" has information for its administrative divisions, the - // administrative area field is not used, which results in an empty tree of - // sub-regions. - EXPECT_TRUE(tree.sub_regions().empty()); -} - -TEST_F(PreloadSupplierTest, BuildZwRegionTree) { - supplier_.LoadRules("ZW", *loaded_callback_); - const RegionData& tree = - supplier_.BuildRegionTree("ZW", "en-ZW", &best_language_); - EXPECT_TRUE(tree.sub_regions().empty()); -} - } // namespace diff --git a/cpp/test/region_data_builder_test.cc b/cpp/test/region_data_builder_test.cc new file mode 100644 index 0000000..088a73e --- /dev/null +++ b/cpp/test/region_data_builder_test.cc @@ -0,0 +1,98 @@ +// Copyright (C) 2014 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include <libaddressinput/region_data_builder.h> + +#include <libaddressinput/callback.h> +#include <libaddressinput/null_storage.h> +#include <libaddressinput/preload_supplier.h> +#include <libaddressinput/region_data.h> +#include <libaddressinput/util/basictypes.h> +#include <libaddressinput/util/scoped_ptr.h> + +#include "fake_downloader.h" + +#include <string> + +#include <gtest/gtest.h> + +namespace { + +using i18n::addressinput::BuildCallback; +using i18n::addressinput::FakeDownloader; +using i18n::addressinput::NullStorage; +using i18n::addressinput::PreloadSupplier; +using i18n::addressinput::RegionData; +using i18n::addressinput::RegionDataBuilder; +using i18n::addressinput::scoped_ptr; + +class RegionDataBuilderTest : public testing::Test { + protected: + RegionDataBuilderTest() + : supplier_(FakeDownloader::kFakeAggregateDataUrl, + new FakeDownloader, + new NullStorage), + builder_(&supplier_), + loaded_callback_(BuildCallback(this, &RegionDataBuilderTest::OnLoaded)), + best_language_() {} + + virtual ~RegionDataBuilderTest() {} + + PreloadSupplier supplier_; + RegionDataBuilder builder_; + scoped_ptr<PreloadSupplier::Callback> loaded_callback_; + std::string best_language_; + + private: + void OnLoaded(bool success, + const std::string& region_code, + const int& num_rules) { + ASSERT_TRUE(success); + ASSERT_FALSE(region_code.empty()); + ASSERT_LT(0, num_rules); + ASSERT_TRUE(supplier_.IsLoaded(region_code)); + } + + DISALLOW_COPY_AND_ASSIGN(RegionDataBuilderTest); +}; + +TEST_F(RegionDataBuilderTest, BuildUsRegionTree) { + supplier_.LoadRules("US", *loaded_callback_); + const RegionData& tree = builder_.Build("US", "en-US", &best_language_); + EXPECT_FALSE(tree.sub_regions().empty()); +} + +TEST_F(RegionDataBuilderTest, BuildCnRegionTree) { + supplier_.LoadRules("CN", *loaded_callback_); + const RegionData& tree = builder_.Build("CN", "zh-Hans", &best_language_); + ASSERT_FALSE(tree.sub_regions().empty()); + EXPECT_FALSE(tree.sub_regions().front()->sub_regions().empty()); +} + +TEST_F(RegionDataBuilderTest, BuildChRegionTree) { + supplier_.LoadRules("CH", *loaded_callback_); + const RegionData& tree = builder_.Build("CH", "de-CH", &best_language_); + // Although "CH" has information for its administrative divisions, the + // administrative area field is not used, which results in an empty tree of + // sub-regions. + EXPECT_TRUE(tree.sub_regions().empty()); +} + +TEST_F(RegionDataBuilderTest, BuildZwRegionTree) { + supplier_.LoadRules("ZW", *loaded_callback_); + const RegionData& tree = builder_.Build("ZW", "en-ZW", &best_language_); + EXPECT_TRUE(tree.sub_regions().empty()); +} + +} // namespace |