1// Copyright (C) 2014 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 "address_validator_test.h"
16
17#include <libaddressinput/address_data.h>
18#include <libaddressinput/address_field.h>
19#include <libaddressinput/address_problem.h>
20#include <libaddressinput/address_validator.h>
21#include <libaddressinput/downloader.h>
22#include <libaddressinput/load_rules_delegate.h>
23#include <libaddressinput/storage.h>
24#include <libaddressinput/util/scoped_ptr.h>
25
26#include <cstddef>
27#include <set>
28#include <string>
29#include <vector>
30
31#include <gtest/gtest.h>
32
33#include "fake_downloader.h"
34#include "fake_storage.h"
35#include "region_data_constants.h"
36
37namespace i18n {
38namespace addressinput {
39
40class AddressValidatorTest : public testing::Test, public LoadRulesDelegate {
41 public:
42  AddressValidatorTest()
43      : validator_(BuildAddressValidatorForTesting(
44            FakeDownloader::kFakeDataUrl,
45            scoped_ptr<Downloader>(new FakeDownloader),
46            scoped_ptr<Storage>(new FakeStorage),
47            this)) {
48    validator_->LoadRules("US");
49  }
50
51  virtual ~AddressValidatorTest() {}
52
53 protected:
54  scoped_ptr<AddressValidator> validator_;
55
56 private:
57  // LoadRulesDelegate implementation.
58  virtual void OnAddressValidationRulesLoaded(const std::string& country_code,
59                                              bool success) {
60    AddressData address_data;
61    address_data.country_code = country_code;
62    AddressValidator::Status status =
63        validator_->ValidateAddress(address_data, AddressProblemFilter(), NULL);
64    EXPECT_EQ(success, status == AddressValidator::SUCCESS);
65  }
66};
67
68TEST_F(AddressValidatorTest, RegionHasRules) {
69  const std::vector<std::string>& region_codes =
70      RegionDataConstants::GetRegionCodes();
71  AddressData address;
72  for (size_t i = 0; i < region_codes.size(); ++i) {
73    SCOPED_TRACE("For region: " + region_codes[i]);
74    validator_->LoadRules(region_codes[i]);
75    address.country_code = region_codes[i];
76    EXPECT_EQ(
77        AddressValidator::SUCCESS,
78        validator_->ValidateAddress(address, AddressProblemFilter(), NULL));
79  }
80}
81
82TEST_F(AddressValidatorTest, EmptyAddressNoFatalFailure) {
83  AddressData address;
84  address.country_code = "US";
85
86  AddressProblems problems;
87  EXPECT_EQ(
88      AddressValidator::SUCCESS,
89      validator_->ValidateAddress(address, AddressProblemFilter(), &problems));
90}
91
92TEST_F(AddressValidatorTest, USZipCode) {
93  AddressData address;
94  address.address_lines.push_back("340 Main St.");
95  address.locality = "Venice";
96  address.administrative_area = "CA";
97  address.country_code = "US";
98
99  // Valid Californian zip code.
100  address.postal_code = "90291";
101  AddressProblems problems;
102  EXPECT_EQ(
103      AddressValidator::SUCCESS,
104      validator_->ValidateAddress(address, AddressProblemFilter(), &problems));
105  EXPECT_TRUE(problems.empty());
106
107  problems.clear();
108
109  // An extended, valid Californian zip code.
110  address.postal_code = "90210-1234";
111  EXPECT_EQ(
112      AddressValidator::SUCCESS,
113      validator_->ValidateAddress(address, AddressProblemFilter(), &problems));
114  EXPECT_TRUE(problems.empty());
115
116  problems.clear();
117
118  // New York zip code (which is invalid for California).
119  address.postal_code = "12345";
120  EXPECT_EQ(
121      AddressValidator::SUCCESS,
122      validator_->ValidateAddress(address, AddressProblemFilter(), &problems));
123  EXPECT_EQ(1U, problems.size());
124  EXPECT_EQ(problems[0].field, POSTAL_CODE);
125  EXPECT_EQ(problems[0].type, AddressProblem::MISMATCHING_VALUE);
126
127  problems.clear();
128
129  // A zip code with a "90" in the middle.
130  address.postal_code = "12903";
131  EXPECT_EQ(
132      AddressValidator::SUCCESS,
133      validator_->ValidateAddress(address, AddressProblemFilter(), &problems));
134  EXPECT_EQ(1U, problems.size());
135  EXPECT_EQ(problems[0].field, POSTAL_CODE);
136  EXPECT_EQ(problems[0].type, AddressProblem::MISMATCHING_VALUE);
137
138  problems.clear();
139
140  // Invalid zip code (too many digits).
141  address.postal_code = "902911";
142  EXPECT_EQ(
143      AddressValidator::SUCCESS,
144      validator_->ValidateAddress(address, AddressProblemFilter(), &problems));
145  EXPECT_EQ(1U, problems.size());
146  EXPECT_EQ(problems[0].field, POSTAL_CODE);
147  EXPECT_EQ(problems[0].type, AddressProblem::UNRECOGNIZED_FORMAT);
148
149  problems.clear();
150
151  // Invalid zip code (too few digits).
152  address.postal_code = "9029";
153  EXPECT_EQ(
154      AddressValidator::SUCCESS,
155      validator_->ValidateAddress(address, AddressProblemFilter(), &problems));
156  EXPECT_EQ(1U, problems.size());
157  EXPECT_EQ(problems[0].field, POSTAL_CODE);
158  EXPECT_EQ(problems[0].type, AddressProblem::UNRECOGNIZED_FORMAT);
159}
160
161TEST_F(AddressValidatorTest, BasicValidation) {
162  // US rules should always be available, even though this load call fails.
163  validator_->LoadRules("US");
164  AddressData address;
165  address.country_code = "US";
166  address.language_code = "en";
167  address.administrative_area = "TX";
168  address.locality = "Paris";
169  address.postal_code = "75461";
170  address.address_lines.push_back("123 Main St");
171  AddressProblems problems;
172  EXPECT_EQ(
173      AddressValidator::SUCCESS,
174      validator_->ValidateAddress(address, AddressProblemFilter(), &problems));
175  EXPECT_TRUE(problems.empty());
176
177  // The display name works as well as the key.
178  address.administrative_area = "Texas";
179  problems.clear();
180  EXPECT_EQ(
181      AddressValidator::SUCCESS,
182      validator_->ValidateAddress(address, AddressProblemFilter(), &problems));
183  EXPECT_TRUE(problems.empty());
184
185  // Ignore capitalization.
186  address.administrative_area = "tx";
187  problems.clear();
188  EXPECT_EQ(
189      AddressValidator::SUCCESS,
190      validator_->ValidateAddress(address, AddressProblemFilter(), &problems));
191  EXPECT_TRUE(problems.empty());
192
193  // Ignore capitalization.
194  address.administrative_area = "teXas";
195  problems.clear();
196  EXPECT_EQ(
197      AddressValidator::SUCCESS,
198      validator_->ValidateAddress(address, AddressProblemFilter(), &problems));
199  EXPECT_TRUE(problems.empty());
200
201  // Ignore diacriticals.
202  address.administrative_area = "T\u00E9xas";
203  problems.clear();
204  EXPECT_EQ(
205      AddressValidator::SUCCESS,
206      validator_->ValidateAddress(address, AddressProblemFilter(), &problems));
207  EXPECT_TRUE(problems.empty());
208}
209
210TEST_F(AddressValidatorTest, BasicValidationFailure) {
211  // US rules should always be available, even though this load call fails.
212  validator_->LoadRules("US");
213  AddressData address;
214  address.country_code = "US";
215  address.language_code = "en";
216  address.administrative_area = "XT";
217  address.locality = "Paris";
218  address.postal_code = "75461";
219  address.address_lines.push_back("123 Main St");
220  AddressProblems problems;
221  EXPECT_EQ(
222      AddressValidator::SUCCESS,
223      validator_->ValidateAddress(address, AddressProblemFilter(), &problems));
224
225  ASSERT_EQ(1U, problems.size());
226  EXPECT_EQ(AddressProblem::UNKNOWN_VALUE, problems[0].type);
227  EXPECT_EQ(ADMIN_AREA, problems[0].field);
228}
229
230TEST_F(AddressValidatorTest, NoNullSuggestionsCrash) {
231  AddressData address;
232  address.country_code = "US";
233  EXPECT_EQ(AddressValidator::SUCCESS,
234            validator_->GetSuggestions(address, COUNTRY, 1, NULL));
235}
236
237TEST_F(AddressValidatorTest, SuggestAdminAreaForPostalCode) {
238  AddressData address;
239  address.country_code = "US";
240  address.postal_code = "90291";
241
242  std::vector<AddressData> suggestions;
243  EXPECT_EQ(AddressValidator::SUCCESS,
244            validator_->GetSuggestions(address, POSTAL_CODE, 1, &suggestions));
245  ASSERT_EQ(1U, suggestions.size());
246  EXPECT_EQ("CA", suggestions[0].administrative_area);
247  EXPECT_EQ("90291", suggestions[0].postal_code);
248}
249
250TEST_F(AddressValidatorTest, SuggestLocalityForPostalCodeWithAdminArea) {
251  validator_->LoadRules("TW");
252  AddressData address;
253  address.country_code = "TW";
254  address.postal_code = "515";
255  address.administrative_area = "Changhua";
256
257  std::vector<AddressData> suggestions;
258  EXPECT_EQ(AddressValidator::SUCCESS,
259            validator_->GetSuggestions(address, POSTAL_CODE, 1, &suggestions));
260  ASSERT_EQ(1U, suggestions.size());
261  EXPECT_EQ("Dacun Township", suggestions[0].locality);
262  EXPECT_EQ("Changhua County", suggestions[0].administrative_area);
263  EXPECT_EQ("515", suggestions[0].postal_code);
264}
265
266TEST_F(AddressValidatorTest, SuggestAdminAreaForPostalCodeWithLocality) {
267  validator_->LoadRules("TW");
268  AddressData address;
269  address.country_code = "TW";
270  address.postal_code = "515";
271  address.locality = "Dacun";
272
273  std::vector<AddressData> suggestions;
274  EXPECT_EQ(AddressValidator::SUCCESS,
275            validator_->GetSuggestions(address, POSTAL_CODE, 1, &suggestions));
276  ASSERT_EQ(1U, suggestions.size());
277  EXPECT_EQ("Dacun Township", suggestions[0].locality);
278  EXPECT_EQ("Changhua County", suggestions[0].administrative_area);
279  EXPECT_EQ("515", suggestions[0].postal_code);
280}
281
282TEST_F(AddressValidatorTest, NoSuggestForPostalCodeWithWrongAdminArea) {
283  AddressData address;
284  address.country_code = "US";
285  address.postal_code = "90066";
286  address.postal_code = "TX";
287
288  std::vector<AddressData> suggestions;
289  EXPECT_EQ(AddressValidator::SUCCESS,
290            validator_->GetSuggestions(address, POSTAL_CODE, 1, &suggestions));
291  EXPECT_TRUE(suggestions.empty());
292}
293
294TEST_F(AddressValidatorTest, SuggestForLocality) {
295  validator_->LoadRules("CN");
296  AddressData address;
297  address.country_code = "CN";
298  address.locality = "Anqin";
299
300  std::vector<AddressData> suggestions;
301  EXPECT_EQ(AddressValidator::SUCCESS,
302            validator_->GetSuggestions(address, LOCALITY, 10, &suggestions));
303  ASSERT_EQ(1U, suggestions.size());
304  EXPECT_EQ("Anqing Shi", suggestions[0].locality);
305  EXPECT_EQ("ANHUI SHENG", suggestions[0].administrative_area);
306}
307
308TEST_F(AddressValidatorTest, SuggestForLocalityAndAdminArea) {
309  validator_->LoadRules("CN");
310  AddressData address;
311  address.country_code = "CN";
312  address.locality = "Anqing";
313  address.administrative_area = "Anhui";
314
315  std::vector<AddressData> suggestions;
316  EXPECT_EQ(AddressValidator::SUCCESS,
317            validator_->GetSuggestions(address, LOCALITY, 10, &suggestions));
318  ASSERT_EQ(1U, suggestions.size());
319  EXPECT_TRUE(suggestions[0].dependent_locality.empty());
320  EXPECT_EQ("Anqing Shi", suggestions[0].locality);
321  EXPECT_EQ("ANHUI SHENG", suggestions[0].administrative_area);
322}
323
324TEST_F(AddressValidatorTest, SuggestForAdminAreaAndLocality) {
325  validator_->LoadRules("CN");
326  AddressData address;
327  address.country_code = "CN";
328  address.locality = "Anqing";
329  address.administrative_area = "Anhui";
330
331  std::vector<AddressData> suggestions;
332  EXPECT_EQ(AddressValidator::SUCCESS,
333            validator_->GetSuggestions(address, ADMIN_AREA, 10, &suggestions));
334  ASSERT_EQ(1U, suggestions.size());
335  EXPECT_TRUE(suggestions[0].dependent_locality.empty());
336  EXPECT_TRUE(suggestions[0].locality.empty());
337  EXPECT_EQ("ANHUI SHENG", suggestions[0].administrative_area);
338}
339
340TEST_F(AddressValidatorTest, SuggestForDependentLocality) {
341  validator_->LoadRules("CN");
342  AddressData address;
343  address.country_code = "CN";
344  address.dependent_locality = "Zongyang";
345
346  std::vector<AddressData> suggestions;
347  EXPECT_EQ(AddressValidator::SUCCESS,
348            validator_->GetSuggestions(
349                address, DEPENDENT_LOCALITY, 10, &suggestions));
350  ASSERT_EQ(1U, suggestions.size());
351  EXPECT_EQ("Zongyang Xian", suggestions[0].dependent_locality);
352  EXPECT_EQ("Anqing Shi", suggestions[0].locality);
353  EXPECT_EQ("ANHUI SHENG", suggestions[0].administrative_area);
354}
355
356TEST_F(AddressValidatorTest,
357       NoSuggestForDependentLocalityWithWrongAdminArea) {
358  validator_->LoadRules("CN");
359  AddressData address;
360  address.country_code = "CN";
361  address.dependent_locality = "Zongyang";
362  address.administrative_area = "Sichuan Sheng";
363
364  std::vector<AddressData> suggestions;
365  EXPECT_EQ(AddressValidator::SUCCESS,
366            validator_->GetSuggestions(
367                address, DEPENDENT_LOCALITY, 10, &suggestions));
368  EXPECT_TRUE(suggestions.empty());
369}
370
371TEST_F(AddressValidatorTest, EmptySuggestionsOverLimit) {
372  AddressData address;
373  address.country_code = "US";
374  address.administrative_area = "A";
375
376  std::vector<AddressData> suggestions;
377  EXPECT_EQ(AddressValidator::SUCCESS,
378            validator_->GetSuggestions(address, ADMIN_AREA, 1, &suggestions));
379  EXPECT_TRUE(suggestions.empty());
380}
381
382TEST_F(AddressValidatorTest, PreferShortSuggestions) {
383  AddressData address;
384  address.country_code = "US";
385  address.administrative_area = "CA";
386
387  std::vector<AddressData> suggestions;
388  EXPECT_EQ(AddressValidator::SUCCESS,
389            validator_->GetSuggestions(address, ADMIN_AREA, 10, &suggestions));
390  ASSERT_EQ(1U, suggestions.size());
391  EXPECT_EQ("CA", suggestions[0].administrative_area);
392}
393
394TEST_F(AddressValidatorTest, SuggestTheSingleMatchForFullMatchName) {
395  AddressData address;
396  address.country_code = "US";
397  address.administrative_area = "Texas";
398
399  std::vector<AddressData> suggestions;
400  EXPECT_EQ(AddressValidator::SUCCESS,
401            validator_->GetSuggestions(address, ADMIN_AREA, 10, &suggestions));
402  ASSERT_EQ(1U, suggestions.size());
403  EXPECT_EQ("Texas", suggestions[0].administrative_area);
404}
405
406TEST_F(AddressValidatorTest, SuggestAdminArea) {
407  AddressData address;
408  address.country_code = "US";
409  address.administrative_area = "Cali";
410
411  std::vector<AddressData> suggestions;
412  EXPECT_EQ(AddressValidator::SUCCESS,
413            validator_->GetSuggestions(address, ADMIN_AREA, 10, &suggestions));
414  ASSERT_EQ(1U, suggestions.size());
415  EXPECT_EQ("California", suggestions[0].administrative_area);
416}
417
418TEST_F(AddressValidatorTest, MultipleSuggestions) {
419  AddressData address;
420  address.country_code = "US";
421  address.administrative_area = "MA";
422
423  std::vector<AddressData> suggestions;
424  EXPECT_EQ(AddressValidator::SUCCESS,
425            validator_->GetSuggestions(address, ADMIN_AREA, 10, &suggestions));
426  EXPECT_LT(1U, suggestions.size());
427
428  // Massachusetts should not be a suggestion, because it's already covered
429  // under MA.
430  std::set<std::string> expected_suggestions;
431  expected_suggestions.insert("MA");
432  expected_suggestions.insert("Maine");
433  expected_suggestions.insert("Marshall Islands");
434  expected_suggestions.insert("Maryland");
435  for (std::vector<AddressData>::const_iterator it = suggestions.begin();
436       it != suggestions.end(); ++it) {
437    expected_suggestions.erase(it->administrative_area);
438  }
439  EXPECT_TRUE(expected_suggestions.empty());
440}
441
442TEST_F(AddressValidatorTest, SuggestNonLatinKeyWhenLanguageMatches) {
443  validator_->LoadRules("KR");
444  AddressData address;
445  address.language_code = "ko";
446  address.country_code = "KR";
447  address.postal_code = "210-210";
448
449  std::vector<AddressData> suggestions;
450  EXPECT_EQ(AddressValidator::SUCCESS,
451            validator_->GetSuggestions(address, POSTAL_CODE, 1, &suggestions));
452  ASSERT_EQ(1U, suggestions.size());
453  EXPECT_EQ("강원도", suggestions[0].administrative_area);
454  EXPECT_EQ("210-210", suggestions[0].postal_code);
455}
456
457TEST_F(AddressValidatorTest, SuggestNonLatinKeyWhenUserInputIsNotLatin) {
458  validator_->LoadRules("KR");
459  AddressData address;
460  address.language_code = "en";
461  address.country_code = "KR";
462  address.administrative_area = "강원";
463
464  std::vector<AddressData> suggestions;
465  EXPECT_EQ(AddressValidator::SUCCESS,
466            validator_->GetSuggestions(address, ADMIN_AREA, 1, &suggestions));
467  ASSERT_EQ(1U, suggestions.size());
468  EXPECT_EQ("강원도", suggestions[0].administrative_area);
469}
470
471TEST_F(AddressValidatorTest,
472       SuggestLatinNameWhenLanguageDiffersAndLatinNameAvailable) {
473  validator_->LoadRules("KR");
474  AddressData address;
475  address.language_code = "en";
476  address.country_code = "KR";
477  address.postal_code = "210-210";
478
479  std::vector<AddressData> suggestions;
480  EXPECT_EQ(AddressValidator::SUCCESS,
481            validator_->GetSuggestions(address, POSTAL_CODE, 1, &suggestions));
482  ASSERT_EQ(1U, suggestions.size());
483  EXPECT_EQ("Gangwon", suggestions[0].administrative_area);
484  EXPECT_EQ("210-210", suggestions[0].postal_code);
485}
486
487TEST_F(AddressValidatorTest, SuggestLatinNameWhenUserInputIsLatin) {
488  validator_->LoadRules("KR");
489  AddressData address;
490  address.language_code = "ko";
491  address.country_code = "KR";
492  address.administrative_area = "Gang";
493
494  std::vector<AddressData> suggestions;
495  EXPECT_EQ(AddressValidator::SUCCESS,
496            validator_->GetSuggestions(address, ADMIN_AREA, 1, &suggestions));
497  ASSERT_EQ(1U, suggestions.size());
498  EXPECT_EQ("Gangwon", suggestions[0].administrative_area);
499}
500
501TEST_F(AddressValidatorTest, NoSuggestionsForEmptyAddress) {
502  AddressData address;
503  address.country_code = "US";
504
505  std::vector<AddressData> suggestions;
506  EXPECT_EQ(
507      AddressValidator::SUCCESS,
508      validator_->GetSuggestions(address, POSTAL_CODE, 999, &suggestions));
509  EXPECT_TRUE(suggestions.empty());
510}
511
512TEST_F(AddressValidatorTest, SuggestionIncludesCountry) {
513  AddressData address;
514  address.country_code = "US";
515  address.postal_code = "90291";
516
517  std::vector<AddressData> suggestions;
518  EXPECT_EQ(AddressValidator::SUCCESS,
519            validator_->GetSuggestions(address, POSTAL_CODE, 1, &suggestions));
520  ASSERT_EQ(1U, suggestions.size());
521  EXPECT_EQ("US", suggestions[0].country_code);
522}
523
524TEST_F(AddressValidatorTest, SuggestOnlyForAdministrativeAreasAndPostalCode) {
525  AddressData address;
526  address.country_code = "US";
527  address.administrative_area = "CA";
528  address.locality = "Los Angeles";
529  address.dependent_locality = "Venice";
530  address.postal_code = "90291";
531  address.sorting_code = "123";
532  address.address_lines.push_back("123 Main St");
533  address.organization = "Google";
534  address.recipient = "Jon Smith";
535
536  // Fields that should not have suggestions in US.
537  static const AddressField kNoSugestFields[] = {
538    COUNTRY,
539    LOCALITY,
540    DEPENDENT_LOCALITY,
541    SORTING_CODE,
542    STREET_ADDRESS,
543    ORGANIZATION,
544    RECIPIENT
545  };
546
547  static const size_t kNumNoSuggestFields =
548      sizeof kNoSugestFields / sizeof (AddressField);
549
550  for (size_t i = 0; i < kNumNoSuggestFields; ++i) {
551    std::vector<AddressData> suggestions;
552    EXPECT_EQ(AddressValidator::SUCCESS,
553              validator_->GetSuggestions(
554                  address, kNoSugestFields[i], 999, &suggestions));
555    EXPECT_TRUE(suggestions.empty());
556  }
557}
558
559TEST_F(AddressValidatorTest, CanonicalizeUsAdminAreaName) {
560  AddressData address;
561  address.country_code = "US";
562  address.administrative_area = "cALIFORNIa";
563  EXPECT_TRUE(validator_->CanonicalizeAdministrativeArea(&address));
564  EXPECT_EQ("CA", address.administrative_area);
565}
566
567TEST_F(AddressValidatorTest, CanonicalizeUsAdminAreaKey) {
568  AddressData address;
569  address.country_code = "US";
570  address.administrative_area = "CA";
571  EXPECT_TRUE(validator_->CanonicalizeAdministrativeArea(&address));
572  EXPECT_EQ("CA", address.administrative_area);
573}
574
575TEST_F(AddressValidatorTest, CanonicalizeJpAdminAreaKey) {
576  validator_->LoadRules("JP");
577  AddressData address;
578  address.country_code = "JP";
579  address.administrative_area = "東京都";
580  EXPECT_TRUE(validator_->CanonicalizeAdministrativeArea(&address));
581  EXPECT_EQ("東京都", address.administrative_area);
582}
583
584TEST_F(AddressValidatorTest, CanonicalizeJpAdminAreaLatinName) {
585  validator_->LoadRules("JP");
586  AddressData address;
587  address.country_code = "JP";
588  address.administrative_area = "tOKYo";
589  EXPECT_TRUE(validator_->CanonicalizeAdministrativeArea(&address));
590  EXPECT_EQ("TOKYO", address.administrative_area);
591}
592
593}  // namespace addressinput
594}  // namespace i18n
595