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