1// Copyright (C) 2013 Google Inc. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15#include <libaddressinput/address_ui.h> 16 17#include <libaddressinput/address_field.h> 18#include <libaddressinput/address_ui_component.h> 19#include <libaddressinput/localization.h> 20#include <libaddressinput/util/basictypes.h> 21 22#include <set> 23#include <string> 24#include <vector> 25 26#include <gtest/gtest.h> 27 28namespace { 29 30using i18n::addressinput::AddressField; 31using i18n::addressinput::AddressUiComponent; 32using i18n::addressinput::BuildComponents; 33using i18n::addressinput::GetRegionCodes; 34using i18n::addressinput::Localization; 35 36using i18n::addressinput::COUNTRY; 37using i18n::addressinput::ADMIN_AREA; 38using i18n::addressinput::POSTAL_CODE; 39using i18n::addressinput::STREET_ADDRESS; 40using i18n::addressinput::ORGANIZATION; 41using i18n::addressinput::RECIPIENT; 42 43static const char kUiLanguageTag[] = "en"; 44 45// Returns testing::AssertionSuccess if the |components| are valid. Uses 46// |region_code| in test failure messages. 47testing::AssertionResult ComponentsAreValid( 48 const std::vector<AddressUiComponent>& components) { 49 if (components.empty()) { 50 return testing::AssertionFailure() << "no components"; 51 } 52 53 for (std::vector<AddressUiComponent>::const_iterator 54 component_it = components.begin(); 55 component_it != components.end(); ++component_it) { 56 static const AddressField kMinAddressField = COUNTRY; 57 static const AddressField kMaxAddressField = RECIPIENT; 58 if (component_it->field < kMinAddressField || 59 component_it->field > kMaxAddressField) { 60 return testing::AssertionFailure() << "unexpected field " 61 << component_it->field; 62 } 63 64 if (component_it->name.empty()) { 65 return testing::AssertionFailure() << "empty field name for field " 66 << component_it->field; 67 } 68 } 69 70 return testing::AssertionSuccess(); 71} 72 73// Tests for address UI functions. 74class AddressUiTest : public testing::TestWithParam<std::string> { 75 protected: 76 AddressUiTest() {} 77 Localization localization_; 78 std::string best_address_language_tag_; 79 80 private: 81 DISALLOW_COPY_AND_ASSIGN(AddressUiTest); 82}; 83 84// Verifies that a region code consists of two characters, for example "TW". 85TEST_P(AddressUiTest, RegionCodeHasTwoCharacters) { 86 EXPECT_EQ(2, GetParam().size()); 87} 88 89// Verifies that BuildComponents() returns valid UI components for a region 90// code. 91TEST_P(AddressUiTest, ComponentsAreValid) { 92 EXPECT_TRUE(ComponentsAreValid(BuildComponents( 93 GetParam(), localization_, kUiLanguageTag, &best_address_language_tag_))); 94} 95 96// Verifies that BuildComponents() returns at most one input field of each type. 97TEST_P(AddressUiTest, UniqueFieldTypes) { 98 std::set<AddressField> fields; 99 const std::vector<AddressUiComponent>& components = 100 BuildComponents(GetParam(), localization_, kUiLanguageTag, 101 &best_address_language_tag_); 102 for (std::vector<AddressUiComponent>::const_iterator it = components.begin(); 103 it != components.end(); ++it) { 104 EXPECT_TRUE(fields.insert(it->field).second); 105 } 106} 107 108// Test all regions codes. 109INSTANTIATE_TEST_CASE_P( 110 AllRegions, AddressUiTest, 111 testing::ValuesIn(GetRegionCodes())); 112 113// Verifies that BuildComponents() returns an empty vector for an invalid region 114// code. 115TEST_F(AddressUiTest, InvalidRegionCodeReturnsEmptyVector) { 116 EXPECT_TRUE(BuildComponents( 117 "INVALID-REGION-CODE", localization_, kUiLanguageTag, 118 &best_address_language_tag_).empty()); 119} 120 121// Test data for determining the best language tag and whether the right format 122// pattern was used (fmt vs lfmt). 123struct LanguageTestCase { 124 LanguageTestCase(const std::string& region_code, 125 const std::string& ui_language_tag, 126 const std::string& expected_best_address_language_tag, 127 AddressField expected_first_field) 128 : region_code(region_code), 129 ui_language_tag(ui_language_tag), 130 expected_best_address_language_tag(expected_best_address_language_tag), 131 expected_first_field(expected_first_field) {} 132 133 ~LanguageTestCase() {} 134 135 // The CLDR region code to test. 136 const std::string region_code; 137 138 // The BCP 47 language tag to test. 139 const std::string ui_language_tag; 140 141 // The expected value for the best language tag returned by BuildComponents(). 142 const std::string expected_best_address_language_tag; 143 144 // The first field expected to be returned from BuildComponents(). Useful for 145 // determining whether the returned format is in Latin or default order. 146 const AddressField expected_first_field; 147}; 148 149class BestAddressLanguageTagTest 150 : public testing::TestWithParam<LanguageTestCase> { 151 protected: 152 BestAddressLanguageTagTest() {} 153 Localization localization_; 154 std::string best_address_language_tag_; 155 156 private: 157 DISALLOW_COPY_AND_ASSIGN(BestAddressLanguageTagTest); 158}; 159 160std::string GetterStub(int) { return std::string(); } 161 162TEST_P(BestAddressLanguageTagTest, CorrectBestAddressLanguageTag) { 163 localization_.SetGetter(&GetterStub); 164 const std::vector<AddressUiComponent>& components = BuildComponents( 165 GetParam().region_code, localization_, GetParam().ui_language_tag, 166 &best_address_language_tag_); 167 EXPECT_EQ(GetParam().expected_best_address_language_tag, 168 best_address_language_tag_); 169 ASSERT_FALSE(components.empty()); 170 EXPECT_EQ(GetParam().expected_first_field, components.front().field); 171} 172 173INSTANTIATE_TEST_CASE_P( 174 LanguageTestCases, BestAddressLanguageTagTest, 175 testing::Values( 176 // Armenia supports hy and has a Latin format. 177 LanguageTestCase("AM", "", "hy", RECIPIENT), 178 LanguageTestCase("AM", "hy", "hy", RECIPIENT), 179 LanguageTestCase("AM", "en", "hy-Latn", RECIPIENT), 180 181 // P.R. China supports zh-Hans and has a Latin format. 182 LanguageTestCase("CN", "zh-hans", "zh-Hans", POSTAL_CODE), 183 LanguageTestCase("CN", "zh-hant", "zh-Hans", POSTAL_CODE), 184 LanguageTestCase("CN", "zh-hans-CN", "zh-Hans", POSTAL_CODE), 185 LanguageTestCase("CN", "zh", "zh-Hans", POSTAL_CODE), 186 LanguageTestCase("CN", "ZH_HANS", "zh-Hans", POSTAL_CODE), 187 LanguageTestCase("CN", "zh-cmn-Hans-CN", "zh-Hans", POSTAL_CODE), 188 LanguageTestCase("CN", "zh-Latn", "zh-Latn", RECIPIENT), 189 LanguageTestCase("CN", "zh-latn-CN", "zh-Latn", RECIPIENT), 190 LanguageTestCase("CN", "en", "zh-Latn", RECIPIENT), 191 LanguageTestCase("CN", "ja", "zh-Latn", RECIPIENT), 192 LanguageTestCase("CN", "ko", "zh-Latn", RECIPIENT), 193 LanguageTestCase("CN", "ZH_LATN", "zh-Latn", RECIPIENT), 194 // Libaddressinput does not have information about extended language 195 // subtags, so it uses the zh-Latn language tag for all base languages 196 // that are not zh, even if it's effectively the same language. 197 // Mandarin Chinese, Simplified script, as used in China: 198 LanguageTestCase("CN", "cmn-Hans-CN", "zh-Latn", RECIPIENT), 199 200 // Hong Kong supports zh-Hant and en. It has a Latin format. 201 LanguageTestCase("HK", "zh", "zh-Hant", ADMIN_AREA), 202 LanguageTestCase("HK", "zh-hans", "zh-Hant", ADMIN_AREA), 203 LanguageTestCase("HK", "zh-hant", "zh-Hant", ADMIN_AREA), 204 LanguageTestCase("HK", "zh-yue-HK", "zh-Hant", ADMIN_AREA), 205 LanguageTestCase("HK", "en", "en", ADMIN_AREA), 206 LanguageTestCase("HK", "zh-latn", "zh-Latn", RECIPIENT), 207 LanguageTestCase("HK", "fr", "zh-Latn", RECIPIENT), 208 LanguageTestCase("HK", "ja", "zh-Latn", RECIPIENT), 209 LanguageTestCase("HK", "ko", "zh-Latn", RECIPIENT), 210 // Libaddressinput does not have information about extended language 211 // subtags, so it uses the zh-Latn language tag for all base languages 212 // that are not zh or en, even if it's effectively the same language. 213 // Cantonese Chinese, as used in Hong Kong: 214 LanguageTestCase("HK", "yue-HK", "zh-Latn", RECIPIENT), 215 216 // Macao supports zh-Hant and pt. It has a Latin format. 217 LanguageTestCase("MO", "zh", "zh-Hant", STREET_ADDRESS), 218 LanguageTestCase("MO", "zh-Hant", "zh-Hant", STREET_ADDRESS), 219 LanguageTestCase("MO", "pt", "pt", STREET_ADDRESS), 220 LanguageTestCase("MO", "zh-Latn", "zh-Latn", RECIPIENT), 221 LanguageTestCase("MO", "en", "zh-Latn", RECIPIENT), 222 223 // Switzerland supports de, fr, and it. 224 LanguageTestCase("CH", "de", "de", ORGANIZATION), 225 LanguageTestCase("CH", "de-DE", "de", ORGANIZATION), 226 LanguageTestCase("CH", "de-Latn-DE", "de", ORGANIZATION), 227 LanguageTestCase("CH", "fr", "fr", ORGANIZATION), 228 LanguageTestCase("CH", "it", "it", ORGANIZATION), 229 LanguageTestCase("CH", "en", "de", ORGANIZATION), 230 231 // Antarctica does not have language information. 232 LanguageTestCase("AQ", "en", "en", RECIPIENT), 233 LanguageTestCase("AQ", "fr", "fr", RECIPIENT), 234 LanguageTestCase("AQ", "es", "es", RECIPIENT), 235 LanguageTestCase("AQ", "zh-Hans", "zh-Hans", RECIPIENT), 236 237 // Egypt supports ar and has a Latin format. 238 LanguageTestCase("EG", "ar", "ar", RECIPIENT), 239 LanguageTestCase("EG", "ar-Arab", "ar", RECIPIENT), 240 LanguageTestCase("EG", "ar-Latn", "ar-Latn", RECIPIENT), 241 LanguageTestCase("EG", "fr", "ar-Latn", RECIPIENT), 242 LanguageTestCase("EG", "fa", "ar-Latn", RECIPIENT), 243 // Libaddressinput does not have language-to-script mapping, so it uses 244 // the ar-Latn language tag for all base languages that are not ar, even 245 // if the script is the same. 246 LanguageTestCase("EG", "fa-Arab", "ar-Latn", RECIPIENT))); 247 248} // namespace 249