1 // Copyright (C) 2013 Google Inc.
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
7 // http://www.apache.org/licenses/LICENSE-2.0
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.
15 #include <libaddressinput/address_input_helper.h>
17 #include <libaddressinput/address_data.h>
18 #include <libaddressinput/callback.h>
19 #include <libaddressinput/null_storage.h>
20 #include <libaddressinput/preload_supplier.h>
21 #include <libaddressinput/util/basictypes.h>
22 #include <libaddressinput/util/scoped_ptr.h>
27 #include <gtest/gtest.h>
29 #include "mock_source.h"
30 #include "testdata_source.h"
34 using i18n::addressinput::AddressData;
35 using i18n::addressinput::AddressInputHelper;
36 using i18n::addressinput::BuildCallback;
37 using i18n::addressinput::Callback;
38 using i18n::addressinput::MockSource;
39 using i18n::addressinput::NullStorage;
40 using i18n::addressinput::PreloadSupplier;
41 using i18n::addressinput::scoped_ptr;
42 using i18n::addressinput::TestdataSource;
44 class AddressInputHelperTest : public testing::Test {
46 AddressInputHelperTest()
47 // Our PreloadSupplier loads all data for a country at a time.
48 : supplier_(new TestdataSource(true), new NullStorage),
49 address_input_helper_(&supplier_),
50 loaded_(BuildCallback(this, &AddressInputHelperTest::Loaded)) {}
52 ~AddressInputHelperTest() {}
54 // Helper method to test FillAddress that ensures the PreloadSupplier has the
55 // necessary data preloaded.
56 void FillAddress(AddressData* address) {
57 const std::string& region_code = address->region_code;
58 if (!region_code.empty()) {
59 supplier_.LoadRules(region_code, *loaded_);
61 address_input_helper_.FillAddress(address);
65 // Used to preload data that we need.
66 void Loaded(bool success, const std::string&, int) { ASSERT_TRUE(success); }
68 PreloadSupplier supplier_;
69 const AddressInputHelper address_input_helper_;
70 const scoped_ptr<const PreloadSupplier::Callback> loaded_;
71 DISALLOW_COPY_AND_ASSIGN(AddressInputHelperTest);
74 TEST_F(AddressInputHelperTest, AddressWithMissingPostalCode) {
76 address.region_code = "CX";
77 address.administrative_area = "WA";
79 // There is only one postal code for Christmas Island
80 AddressData expected = address;
81 expected.postal_code = "6798";
82 FillAddress(&address);
83 EXPECT_EQ(expected, address);
86 TEST_F(AddressInputHelperTest, AddressWithPostalCodeMatchingAdmin) {
88 address.region_code = "US";
89 address.postal_code = "58098";
90 // Other data should be left alone.
91 address.address_line.push_back("10 High St");
93 // North Dakota has post codes starting with 58.
94 AddressData expected = address;
95 expected.administrative_area = "ND";
96 FillAddress(&address);
97 EXPECT_EQ(expected, address);
99 address.administrative_area = "CA"; // Override the admin area.
100 // Now, since the admin area was already filled in, we don't fix it, even
101 // though it was correct.
102 expected.administrative_area = "CA";
103 FillAddress(&address);
104 EXPECT_EQ(expected, address);
107 TEST_F(AddressInputHelperTest, AddressWithPostalCodeMatchingLowerLevel) {
109 address.region_code = "TW";
110 address.postal_code = "53012";
112 /* This matches 二水鄉 - Ershuei Township. */
113 AddressData expected = address;
114 /* This locality is in 彰化縣 - Changhua County. */
115 expected.administrative_area = "\xE5\xBD\xB0\xE5\x8C\x96\xE7\xB8\xA3";
116 expected.locality = "\xE4\xBA\x8C\xE6\xB0\xB4\xE9\x84\x89";
117 FillAddress(&address);
118 EXPECT_EQ(expected, address);
120 // Override the admin area.
121 address.administrative_area = "Already filled in";
122 expected.administrative_area = "Already filled in";
123 address.locality = "";
124 // However, the locality will still be filled in.
125 FillAddress(&address);
126 EXPECT_EQ(expected, address);
129 TEST_F(AddressInputHelperTest, AddressWithPostalCodeMatchingLowerLevelLatin) {
131 address.region_code = "TW";
132 address.postal_code = "53012";
133 address.language_code = "zh-Latn";
135 /* This matches 二水鄉 - Ershuei Township. */
136 AddressData expected = address;
137 /* This locality is in 彰化縣 - Changhua County. */
138 expected.locality = "Ershuei Township";
139 expected.administrative_area = "Changhua County";
140 FillAddress(&address);
141 EXPECT_EQ(expected, address);
143 // Override the admin area.
144 address.administrative_area = "Already filled in";
145 expected.administrative_area = "Already filled in";
146 address.locality = "";
147 // However, the locality will still be filled in.
148 FillAddress(&address);
149 EXPECT_EQ(expected, address);
152 TEST_F(AddressInputHelperTest, AddressWithPostalCodeMatchingDependentLocality) {
154 address.region_code = "KR";
155 // This matches Danwon-gu district.
156 address.postal_code = "425-111";
158 AddressData expected = address;
159 /* The province is Gyeonggi - 경기도. */
160 expected.administrative_area = "\xEA\xB2\xBD\xEA\xB8\xB0\xEB\x8F\x84";
161 /* The city is Ansan-si - 안산시. */
162 expected.locality = "\xEC\x95\x88\xEC\x82\xB0\xEC\x8B\x9C";
163 /* The district is Danwon-gu - 단원구 */
164 expected.dependent_locality = "\xEB\x8B\xA8\xEC\x9B\x90\xEA\xB5\xAC";
166 FillAddress(&address);
167 EXPECT_EQ(expected, address);
169 AddressData address_ko_latn;
170 address_ko_latn.region_code = "KR";
171 address_ko_latn.postal_code = "425-111";
172 address_ko_latn.language_code = "ko-latn";
174 expected = address_ko_latn;
175 /* The province is Gyeonggi - 경기도. */
176 expected.administrative_area = "Gyeonggi";
177 /* The city is Ansan-si - 안산시. */
178 expected.locality = "Ansan-si";
179 /* The district is Danwon-gu - 단원구 */
180 expected.dependent_locality = "Danwon-gu";
182 FillAddress(&address_ko_latn);
183 EXPECT_EQ(expected, address_ko_latn);
186 TEST_F(AddressInputHelperTest, AddressWithPostalCodeMatchingMultipleValues) {
188 address.region_code = "KR";
189 // This matches Wando-gun and Ganjin-gun, both in Jeonnam province.
190 address.postal_code = "527-111";
192 AddressData expected = address;
193 /* The province, Jeonnam - 전라남도 - is known, but we have several locality
194 * matches so none of them are populated. */
195 expected.administrative_area =
196 "\xEC\xA0\x84\xEB\x9D\xBC\xEB\x82\xA8\xEB\x8F\x84";
197 FillAddress(&address);
198 EXPECT_EQ(expected, address);
201 TEST_F(AddressInputHelperTest, AddressWithInvalidPostalCode) {
203 address.postal_code = "970";
204 address.region_code = "US";
206 // We don't expect any changes, since the postal code couldn't be determined
208 AddressData expected = address;
209 FillAddress(&address);
210 EXPECT_EQ(expected, address);
213 TEST_F(AddressInputHelperTest, AddressWithNoPostalCodeValidation) {
215 address.postal_code = "123";
216 address.region_code = "GA";
218 // We don't expect any changes, since the postal code couldn't be determined
219 // as valid - we have no information about postal codes in Gabon (or even that
221 AddressData expected = address;
222 FillAddress(&address);
223 EXPECT_EQ(expected, address);
226 TEST_F(AddressInputHelperTest, AddressWithInvalidOrMissingRegionCode) {
228 address.postal_code = "XXX";
229 address.administrative_area = "YYY";
231 // We don't expect any changes, since there was no region code.
232 AddressData expected = address;
233 FillAddress(&address);
234 EXPECT_EQ(expected, address);
236 address.region_code = "XXXX";
237 expected.region_code = "XXXX";
238 // Again, nothing should change.
239 FillAddress(&address);
240 EXPECT_EQ(expected, address);
243 class AddressInputHelperMockDataTest : public testing::Test {
245 AddressInputHelperMockDataTest()
246 : source_(new MockSource),
247 // Our PreloadSupplier loads all data for a country at a time.
248 supplier_(source_, new NullStorage),
249 address_input_helper_(&supplier_),
250 loaded_(BuildCallback(this, &AddressInputHelperMockDataTest::Loaded)) {}
252 ~AddressInputHelperMockDataTest() {}
254 // Helper method to test FillAddress that ensures the PreloadSupplier has the
255 // necessary data preloaded.
256 void FillAddress(AddressData* address) {
257 const std::string& region_code = address->region_code;
258 if (!region_code.empty()) {
259 supplier_.LoadRules(region_code, *loaded_);
261 address_input_helper_.FillAddress(address);
264 MockSource* const source_;
267 // Our mock source we assume will always succeed.
268 void Loaded(bool success, const std::string&, int) { ASSERT_TRUE(success); }
270 PreloadSupplier supplier_;
271 const AddressInputHelper address_input_helper_;
272 const scoped_ptr<const PreloadSupplier::Callback> loaded_;
273 DISALLOW_COPY_AND_ASSIGN(AddressInputHelperMockDataTest);
276 TEST_F(AddressInputHelperMockDataTest,
277 PostalCodeSharedAcrossDifferentHierarchies) {
278 // Note that this data is in the format of data that would be returned from
279 // the aggregate server.
280 source_->data_.insert(std::make_pair(
281 // We use KR since we need a country where we format all fields down to
282 // dependent locality, or the hierarchy won't be loaded.
285 // The top-level ZIP expression must be present for sub-key matches to be
287 "{\"id\":\"data/KR\", \"sub_keys\":\"A~B\", \"zip\":\"\\\\d{5}\"}, "
289 "{\"id\":\"data/KR/A\", \"sub_keys\":\"A1\"}, "
291 "{\"id\":\"data/KR/A/A1\", \"zip\":\"1\"}, "
293 "{\"id\":\"data/KR/B\", \"sub_keys\":\"B1\"}, "
295 "{\"id\":\"data/KR/B/B1\", \"zip\":\"12\"}}"));
298 address.region_code = "KR";
299 address.postal_code = "12345";
300 address.administrative_area = "";
302 AddressData expected = address;
303 FillAddress(&address);
304 // Nothing should have changed, since the ZIP code matches both of the cities,
305 // and they aren't even in the same state.
306 EXPECT_EQ(expected, address);
309 TEST_F(AddressInputHelperMockDataTest,
310 PostalCodeSharedAcrossDifferentHierarchiesSameState) {
311 // Create data where one state matches the ZIP code, but the other doesn't:
312 // within the state which does, multiple cities and sub-cities match. The only
313 // thing we can be certain of is therefore the state.
314 source_->data_.insert(std::make_pair(
315 // We use KR since we need a country where we format all fields down to
316 // dependent locality, or the hierarchy won't be loaded.
319 // The top-level ZIP expression must be present for sub-key matches to be
321 "{\"id\":\"data/KR\", \"sub_keys\":\"A~B\", \"zip\":\"\\\\d{5}\"}, "
323 "{\"id\":\"data/KR/A\", \"sub_keys\":\"A1~A2\"}, "
325 "{\"id\":\"data/KR/A/A1\", \"sub_keys\":\"A1a\", \"zip\":\"1\"}, "
326 // This key matches the ZIP code.
327 "\"data/KR/A/A1/A1a\": "
328 "{\"id\":\"data/KR/A/A1/A1a\", \"zip\":\"12\"}, "
330 "{\"id\":\"data/KR/A/A2\", \"sub_keys\":\"A2a\", \"zip\":\"1\"}, "
331 // This key, also in state A, but in city A2, matches the ZIP code.
332 "\"data/KR/A/A2/A2a\": "
333 "{\"id\":\"data/KR/A/A2/A2a\", \"zip\":\"123\"}, "
334 // This key, in state B, does not match the ZIP code.
336 "{\"id\":\"data/KR/B\", \"zip\":\"2\"}}"));
339 address.region_code = "KR";
340 address.postal_code = "12345";
341 address.administrative_area = "";
343 AddressData expected = address;
344 expected.administrative_area = "A";
345 FillAddress(&address);
346 // The ZIP code matches multiple city districts and cities; but only one
347 // state, so we fill this in.
348 EXPECT_EQ(expected, address);