Merge tag android-5.1.0_r1 into AOSP_5.1_MERGE
Change-Id: I1bfeb0d9aa9e441e0962baf17b8f9b28dfc206b3
diff --git a/cpp/include/libaddressinput/address_data.h b/cpp/include/libaddressinput/address_data.h
index e2d057a..89d3273 100644
--- a/cpp/include/libaddressinput/address_data.h
+++ b/cpp/include/libaddressinput/address_data.h
@@ -55,6 +55,10 @@
// Language code of the address. Should be in BCP-47 format.
std::string language_code;
+ // The organization, firm, company, or institution at this address. This
+ // corresponds to the FirmName sub-element of the xAL FirmType element.
+ std::string organization;
+
// Name of recipient or contact person. Not present in xAL.
std::string recipient;
diff --git a/cpp/include/libaddressinput/address_field.h b/cpp/include/libaddressinput/address_field.h
index 1adc97b..8f2ee05 100644
--- a/cpp/include/libaddressinput/address_field.h
+++ b/cpp/include/libaddressinput/address_field.h
@@ -31,6 +31,7 @@
SORTING_CODE, // Sorting code.
POSTAL_CODE, // Zip or postal code.
STREET_ADDRESS, // Street address lines.
+ ORGANIZATION, // Organization, company, firm, institution, etc.
RECIPIENT // Name.
};
diff --git a/cpp/include/libaddressinput/address_input_helper.h b/cpp/include/libaddressinput/address_input_helper.h
index ce52cf9..feb04d7 100644
--- a/cpp/include/libaddressinput/address_input_helper.h
+++ b/cpp/include/libaddressinput/address_input_helper.h
@@ -15,17 +15,17 @@
#ifndef I18N_ADDRESSINPUT_ADDRESS_INPUT_HELPER_H_
#define I18N_ADDRESSINPUT_ADDRESS_INPUT_HELPER_H_
-#include <vector>
-
#include <libaddressinput/util/basictypes.h>
+#include <vector>
+
namespace i18n {
namespace addressinput {
class LookupKey;
-class Node;
class PreloadSupplier;
struct AddressData;
+struct Node;
class AddressInputHelper {
public:
diff --git a/cpp/include/libaddressinput/address_metadata.h b/cpp/include/libaddressinput/address_metadata.h
index 269f982..cbe72db 100644
--- a/cpp/include/libaddressinput/address_metadata.h
+++ b/cpp/include/libaddressinput/address_metadata.h
@@ -17,6 +17,8 @@
#include <libaddressinput/address_field.h>
+#include <string>
+
namespace i18n {
namespace addressinput {
diff --git a/cpp/include/libaddressinput/address_normalizer.h b/cpp/include/libaddressinput/address_normalizer.h
index 6bd3366..06b7eb2 100644
--- a/cpp/include/libaddressinput/address_normalizer.h
+++ b/cpp/include/libaddressinput/address_normalizer.h
@@ -21,9 +21,9 @@
namespace i18n {
namespace addressinput {
-class AddressData;
class PreloadSupplier;
class StringCompare;
+struct AddressData;
class AddressNormalizer {
public:
diff --git a/cpp/include/libaddressinput/address_validator.h b/cpp/include/libaddressinput/address_validator.h
index d3a09f3..cdb1edf 100644
--- a/cpp/include/libaddressinput/address_validator.h
+++ b/cpp/include/libaddressinput/address_validator.h
@@ -38,7 +38,8 @@
// class MyClass {
// public:
// MyClass()
-// : validator_(kMyServerUrl, new MyDownloader, new MyStorage),
+// : supplier_(new MySupplier),
+// validator_(new AddressValidator(supplier_.get())),
// validated_(BuildCallback(this, &MyClass::Validated)) {}
//
// virtual ~MyClass() {}
@@ -61,7 +62,8 @@
// AddressData address_;
// FieldProblemMap filter_;
// FieldProblemMap problems_;
-// const AddressValidator validator_;
+// const scoped_ptr<Supplier> supplier_;
+// const scoped_ptr<AddressValidator> validator_;
// const scoped_ptr<const AddressValidator::Callback> validated_;
// };
class AddressValidator {
diff --git a/cpp/include/libaddressinput/downloader.h b/cpp/include/libaddressinput/downloader.h
deleted file mode 100644
index 0da4e1f..0000000
--- a/cpp/include/libaddressinput/downloader.h
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright (C) 2013 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.
-//
-// The interface to be implemented by the user of the library to enable
-// downloading validation rules from a server.
-
-#ifndef I18N_ADDRESSINPUT_DOWNLOADER_H_
-#define I18N_ADDRESSINPUT_DOWNLOADER_H_
-
-#include <libaddressinput/callback.h>
-
-#include <string>
-
-namespace i18n {
-namespace addressinput {
-
-// Downloads validation rules from the server. The downloaded data must be
-// allocated on the heap, passing ownership to the callback. Sample usage:
-//
-// class MyDownloader : public Downloader {
-// public:
-// virtual void Download(const std::string& url,
-// const Callback& downloaded) const {
-// bool success = ...
-// std::string* data = new ...
-// downloaded(success, url, data);
-// }
-// };
-class Downloader {
- public:
- typedef i18n::addressinput::Callback<const std::string&,
- std::string*> Callback;
-
- virtual ~Downloader() {}
-
- // Downloads |url| and invokes the |downloaded| callback.
- virtual void Download(const std::string& url,
- const Callback& downloaded) const = 0;
-};
-
-} // namespace addressinput
-} // namespace i18n
-
-#endif // I18N_ADDRESSINPUT_DOWNLOADER_H_
diff --git a/cpp/include/libaddressinput/localization.h b/cpp/include/libaddressinput/localization.h
index acfdf7e..5e7896d 100644
--- a/cpp/include/libaddressinput/localization.h
+++ b/cpp/include/libaddressinput/localization.h
@@ -17,9 +17,9 @@
#include <libaddressinput/address_field.h>
#include <libaddressinput/address_problem.h>
+#include <libaddressinput/util/basictypes.h>
#include <string>
-#include <vector>
namespace i18n {
namespace addressinput {
@@ -84,6 +84,8 @@
// The string getter.
std::string (*get_string_)(int);
+
+ DISALLOW_COPY_AND_ASSIGN(Localization);
};
} // namespace addressinput
diff --git a/cpp/include/libaddressinput/ondemand_supplier.h b/cpp/include/libaddressinput/ondemand_supplier.h
index 0fe33f8..6212d34 100644
--- a/cpp/include/libaddressinput/ondemand_supplier.h
+++ b/cpp/include/libaddressinput/ondemand_supplier.h
@@ -26,10 +26,10 @@
namespace i18n {
namespace addressinput {
-class Downloader;
class LookupKey;
class Retriever;
class Rule;
+class Source;
class Storage;
// An implementation of the Supplier interface that owns a Retriever object,
@@ -46,14 +46,8 @@
// in total less than 2 MB of JSON data.)
class OndemandSupplier : public Supplier {
public:
- // Takes ownership of |downloader| and |storage|. The |validation_data_url|
- // should be a URL to an address data server that |downloader| can access.
- //
- // (See the documentation for the Downloader implementation used for
- // information about what URLs are useable with that Downloader.)
- OndemandSupplier(const std::string& validation_data_url,
- const Downloader* downloader,
- Storage* storage);
+ // Takes ownership of |source| and |storage|.
+ OndemandSupplier(const Source* source, Storage* storage);
virtual ~OndemandSupplier();
// Loads the metadata needed for |lookup_key|, then calls |supplied|.
diff --git a/cpp/include/libaddressinput/preload_supplier.h b/cpp/include/libaddressinput/preload_supplier.h
index 740b4d0..5987c79 100644
--- a/cpp/include/libaddressinput/preload_supplier.h
+++ b/cpp/include/libaddressinput/preload_supplier.h
@@ -20,6 +20,7 @@
#include <libaddressinput/util/basictypes.h>
#include <libaddressinput/util/scoped_ptr.h>
+#include <map>
#include <set>
#include <string>
#include <vector>
@@ -27,11 +28,11 @@
namespace i18n {
namespace addressinput {
-class Downloader;
class IndexMap;
class LookupKey;
class Retriever;
class Rule;
+class Source;
class Storage;
// An implementation of the Supplier interface that owns a Retriever object,
@@ -41,8 +42,8 @@
// or in progress of being loaded.
//
// When using a PreloadSupplier, it becomes possible to do synchronous address
-// validation using an asynchronous Downloader, and to have full control over
-// when network access is being done.
+// validation using an asynchronous Source, and to have full control over when
+// network access is being done.
//
// The maximum size of this cache is naturally limited to the amount of data
// available from the data server. (Currently this is less than 12,000 items of
@@ -51,15 +52,8 @@
public:
typedef i18n::addressinput::Callback<const std::string&, int> Callback;
- // Takes ownership of |downloader| and |storage|. The |validation_data_url|
- // should be a URL to a service that returns address metadata aggregated per
- // region, and which |downloader| can access.
- //
- // (See the documentation for the Downloader implementation used for
- // information about what URLs are useable with that Downloader.)
- PreloadSupplier(const std::string& validation_data_url,
- const Downloader* downloader,
- Storage* storage);
+ // Takes ownership of |source| and |storage|.
+ PreloadSupplier(const Source* source, Storage* storage);
virtual ~PreloadSupplier();
// Collects the metadata needed for |lookup_key| from the cache, then calls
@@ -80,6 +74,11 @@
// Calls |loaded| when the loading has finished.
void LoadRules(const std::string& region_code, const Callback& loaded);
+ // Returns a mapping of lookup keys to rules. Should be called only when
+ // IsLoaded() returns true for the |region_code|.
+ const std::map<std::string, const Rule*>& GetRulesForRegion(
+ const std::string& region_code) const;
+
bool IsLoaded(const std::string& region_code) const;
bool IsPending(const std::string& region_code) const;
@@ -93,6 +92,7 @@
std::set<std::string> pending_;
const scoped_ptr<IndexMap> rule_index_;
std::vector<const Rule*> rule_storage_;
+ std::map<std::string, std::map<std::string, const Rule*> > region_rules_;
DISALLOW_COPY_AND_ASSIGN(PreloadSupplier);
};
diff --git a/cpp/include/libaddressinput/source.h b/cpp/include/libaddressinput/source.h
new file mode 100644
index 0000000..4d91b68
--- /dev/null
+++ b/cpp/include/libaddressinput/source.h
@@ -0,0 +1,56 @@
+// Copyright (C) 2013 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.
+//
+// The interface to be implemented by the user of the library to access address
+// metadata, typically by downloading this from the address metadata server or
+// by linking the metadata into the binary.
+
+#ifndef I18N_ADDRESSINPUT_SOURCE_H_
+#define I18N_ADDRESSINPUT_SOURCE_H_
+
+#include <libaddressinput/callback.h>
+
+#include <string>
+
+namespace i18n {
+namespace addressinput {
+
+// Gets address metadata. The callback data must be allocated on the heap,
+// passing ownership to the callback. Sample usage:
+//
+// class MySource : public Source {
+// public:
+// virtual void Get(const std::string& key,
+// const Callback& data_ready) const {
+// bool success = ...
+// std::string* data = new ...
+// data_ready(success, key, data);
+// }
+// };
+class Source {
+ public:
+ typedef i18n::addressinput::Callback<const std::string&,
+ std::string*> Callback;
+
+ virtual ~Source() {}
+
+ // Gets metadata for |key| and invokes the |data_ready| callback.
+ virtual void Get(const std::string& key,
+ const Callback& data_ready) const = 0;
+};
+
+} // namespace addressinput
+} // namespace i18n
+
+#endif // I18N_ADDRESSINPUT_SOURCE_H_
diff --git a/cpp/include/libaddressinput/storage.h b/cpp/include/libaddressinput/storage.h
index 38fb887..94ad13b 100644
--- a/cpp/include/libaddressinput/storage.h
+++ b/cpp/include/libaddressinput/storage.h
@@ -13,7 +13,7 @@
// limitations under the License.
//
// The interface to be implemented by the user of the library to enable storing
-// the downloaded validation rules (e.g. on disk).
+// address metadata (e.g. on disk).
#ifndef I18N_ADDRESSINPUT_STORAGE_H_
#define I18N_ADDRESSINPUT_STORAGE_H_
@@ -25,8 +25,8 @@
namespace i18n {
namespace addressinput {
-// Stores downloaded validation rules. The data must be allocated on the heap,
-// passing ownership to the called function. Sample usage:
+// Stores address metadata. The data must be allocated on the heap, passing
+// ownership to the called function. Sample usage:
//
// class MyStorage : public Storage {
// public:
diff --git a/cpp/include/libaddressinput/supplier.h b/cpp/include/libaddressinput/supplier.h
index fcd64ad..7d079cf 100644
--- a/cpp/include/libaddressinput/supplier.h
+++ b/cpp/include/libaddressinput/supplier.h
@@ -16,7 +16,6 @@
#define I18N_ADDRESSINPUT_SUPPLIER_H_
#include <libaddressinput/callback.h>
-#include <libaddressinput/util/basictypes.h>
namespace i18n {
namespace addressinput {
diff --git a/cpp/include/libaddressinput/util/basictypes.h b/cpp/include/libaddressinput/util/basictypes.h
index 763b179..663133f 100644
--- a/cpp/include/libaddressinput/util/basictypes.h
+++ b/cpp/include/libaddressinput/util/basictypes.h
@@ -20,9 +20,8 @@
#ifndef I18N_ADDRESSINPUT_UTIL_BASICTYPES_H_
#define I18N_ADDRESSINPUT_UTIL_BASICTYPES_H_
-#include <limits.h> // So we can set the bounds of our types
-#include <stddef.h> // For size_t
-#include <string.h> // for memcpy
+#include <climits> // So we can set the bounds of our types
+#include <cstddef> // For size_t
#if !defined(_WIN32)
// stdint.h is part of C99 but MSVC doesn't have it.
diff --git a/cpp/include/libaddressinput/util/scoped_ptr.h b/cpp/include/libaddressinput/util/scoped_ptr.h
index fe15fca..a88c2a9 100644
--- a/cpp/include/libaddressinput/util/scoped_ptr.h
+++ b/cpp/include/libaddressinput/util/scoped_ptr.h
@@ -11,15 +11,14 @@
// This is an implementation designed to match the anticipated future TR2
// implementation of the scoped_ptr class and scoped_ptr_malloc (deprecated).
-#include <assert.h>
-#include <stddef.h>
-#include <stdlib.h>
-
-#include <algorithm> // For std::swap().
-
#include <libaddressinput/util/basictypes.h>
#include <libaddressinput/util/template_util.h>
+#include <algorithm> // For std::swap().
+#include <cassert>
+#include <cstddef>
+#include <cstdlib>
+
namespace i18n {
namespace addressinput {
diff --git a/cpp/libaddressinput.gypi b/cpp/libaddressinput.gypi
index 8d9030f..e36ee95 100644
--- a/cpp/libaddressinput.gypi
+++ b/cpp/libaddressinput.gypi
@@ -28,7 +28,6 @@
'src/language.cc',
'src/localization.cc',
'src/lookup_key.cc',
- 'src/lookup_key_util.cc',
'src/null_storage.cc',
'src/ondemand_supplier.cc',
'src/ondemand_supply_task.cc',
@@ -40,6 +39,7 @@
'src/retriever.cc',
'src/rule.cc',
'src/rule_retriever.cc',
+ 'src/util/cctype_tolower_equal.cc',
'src/util/json.cc',
'src/util/md5.cc',
'src/util/string_compare.cc',
@@ -60,16 +60,13 @@
'test/address_problem_test.cc',
'test/address_ui_test.cc',
'test/address_validator_test.cc',
- 'test/fake_downloader.cc',
- 'test/fake_downloader_test.cc',
'test/fake_storage.cc',
'test/fake_storage_test.cc',
'test/format_element_test.cc',
'test/language_test.cc',
'test/localization_test.cc',
'test/lookup_key_test.cc',
- 'test/lookup_key_util_test.cc',
- 'test/mock_downloader.cc',
+ 'test/mock_source.cc',
'test/null_storage_test.cc',
'test/ondemand_supply_task_test.cc',
'test/post_box_matchers_test.cc',
@@ -81,6 +78,8 @@
'test/rule_retriever_test.cc',
'test/rule_test.cc',
'test/supplier_test.cc',
+ 'test/testdata_source.cc',
+ 'test/testdata_source_test.cc',
'test/util/json_test.cc',
'test/util/md5_unittest.cc',
'test/util/scoped_ptr_unittest.cc',
diff --git a/cpp/res/messages.grdp b/cpp/res/messages.grdp
index 1e1bcf2..7ca2000 100644
--- a/cpp/res/messages.grdp
+++ b/cpp/res/messages.grdp
@@ -85,6 +85,12 @@
Island
</message>
<message
+ name="IDS_LIBADDRESSINPUT_OBLAST"
+ desc="Administrative Area for certain countries (e.g., Russia's
+ Leningrad).">
+ Oblast
+ </message>
+ <message
name="IDS_LIBADDRESSINPUT_PARISH"
desc="Administrative Area for certain countries (e.g., Andorra's
Canillo).">
@@ -107,6 +113,13 @@
State
</message>
<message
+ name="IDS_LIBADDRESSINPUT_ORGANIZATION_LABEL"
+ desc="Label for the field of organization, firm, company, or institution
+ in an address. Examples of values in this field: Google,
+ Department of Transportation, University of Cambridge.">
+ Organization
+ </message>
+ <message
name="IDS_LIBADDRESSINPUT_RECIPIENT_LABEL"
desc="Label for the field for a person's name in an address.">
Name
diff --git a/cpp/src/address_data.cc b/cpp/src/address_data.cc
index a3549ed..40d3ee7 100644
--- a/cpp/src/address_data.cc
+++ b/cpp/src/address_data.cc
@@ -41,6 +41,7 @@
&AddressData::sorting_code,
&AddressData::postal_code,
NULL,
+ &AddressData::organization,
&AddressData::recipient
};
@@ -53,6 +54,7 @@
NULL,
NULL,
&AddressData::address_line,
+ NULL,
NULL
};
@@ -76,9 +78,9 @@
return IsStringEmpty(value);
} else {
const std::vector<std::string>& value = GetRepeatedFieldValue(field);
- return std::find_if(value.begin(), value.end(),
- std::not1(std::ptr_fun(&IsStringEmpty))) ==
- value.end();
+ return std::find_if(value.begin(),
+ value.end(),
+ std::not1(std::ptr_fun(&IsStringEmpty))) == value.end();
}
}
@@ -104,16 +106,16 @@
}
bool AddressData::operator==(const AddressData& other) const {
- return
- region_code == other.region_code &&
- address_line == other.address_line &&
- administrative_area == other.administrative_area &&
- locality == other.locality &&
- dependent_locality == other.dependent_locality &&
- postal_code == other.postal_code &&
- sorting_code == other.sorting_code &&
- language_code == other.language_code &&
- recipient == other.recipient;
+ return region_code == other.region_code &&
+ address_line == other.address_line &&
+ administrative_area == other.administrative_area &&
+ locality == other.locality &&
+ dependent_locality == other.dependent_locality &&
+ postal_code == other.postal_code &&
+ sorting_code == other.sorting_code &&
+ language_code == other.language_code &&
+ organization == other.organization &&
+ recipient == other.recipient;
}
// static
@@ -144,6 +146,7 @@
}
o << "language_code: \"" << address.language_code << "\"\n"
+ "organization: \"" << address.organization << "\"\n"
"recipient: \"" << address.recipient << "\"\n";
return o;
diff --git a/cpp/src/address_field.cc b/cpp/src/address_field.cc
index 9831479..c5c96d8 100644
--- a/cpp/src/address_field.cc
+++ b/cpp/src/address_field.cc
@@ -14,11 +14,11 @@
#include <libaddressinput/address_field.h>
+#include <libaddressinput/util/basictypes.h>
+
#include <cstddef>
#include <ostream>
-#include <libaddressinput/util/basictypes.h>
-
using i18n::addressinput::AddressField;
using i18n::addressinput::COUNTRY;
using i18n::addressinput::RECIPIENT;
@@ -32,6 +32,7 @@
"SORTING_CODE",
"POSTAL_CODE",
"STREET_ADDRESS",
+ "ORGANIZATION",
"RECIPIENT"
};
COMPILE_ASSERT(COUNTRY == 0, bad_base);
diff --git a/cpp/src/address_field_util.cc b/cpp/src/address_field_util.cc
index 1cac289..26de3c0 100644
--- a/cpp/src/address_field_util.cc
+++ b/cpp/src/address_field_util.cc
@@ -40,6 +40,7 @@
fields.insert(std::make_pair('X', SORTING_CODE));
fields.insert(std::make_pair('Z', POSTAL_CODE));
fields.insert(std::make_pair('A', STREET_ADDRESS));
+ fields.insert(std::make_pair('O', ORGANIZATION));
fields.insert(std::make_pair('N', RECIPIENT));
return fields;
}
diff --git a/cpp/src/address_field_util.h b/cpp/src/address_field_util.h
index 62a6b7e..123672b 100644
--- a/cpp/src/address_field_util.h
+++ b/cpp/src/address_field_util.h
@@ -20,11 +20,11 @@
#include <string>
#include <vector>
-#include "format_element.h"
-
namespace i18n {
namespace addressinput {
+class FormatElement;
+
// Clears |fields|, parses |format|, and adds the format address fields to
// |fields|. The |fields| may also contain NEWLINE elements. For example, parses
// "%S%C%n%D%X" into {ADMIN_AREA, LOCALITY, NEWLINE, DEPENDENT_LOCALITY,
diff --git a/cpp/src/address_formatter.cc b/cpp/src/address_formatter.cc
index 29f3486..b54cbac 100644
--- a/cpp/src/address_formatter.cc
+++ b/cpp/src/address_formatter.cc
@@ -14,20 +14,22 @@
#include <libaddressinput/address_formatter.h>
-#include <strings.h>
-
-#include <algorithm>
-#include <cstddef>
-#include <string>
-#include <vector>
-
#include <libaddressinput/address_data.h>
#include <libaddressinput/address_field.h>
+#include <libaddressinput/util/basictypes.h>
+
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <functional>
+#include <string>
+#include <vector>
#include "format_element.h"
#include "language.h"
#include "region_data_constants.h"
#include "rule.h"
+#include "util/cctype_tolower_equal.h"
namespace i18n {
namespace addressinput {
@@ -66,15 +68,6 @@
"uz"
};
-// Case insensitive matcher for language tags.
-struct LanguageMatcher {
- LanguageMatcher(const std::string& tag) : tag(tag) {}
- std::string tag;
- bool operator() (const std::string& s) {
- return strcasecmp(tag.c_str(), s.c_str()) == 0;
- }
-};
-
std::string GetLineSeparatorForLanguage(const std::string& language_tag) {
Language address_language(language_tag);
@@ -87,42 +80,45 @@
const std::string& base_language = address_language.base;
if (std::find_if(kLanguagesThatUseSpace,
kLanguagesThatUseSpace + arraysize(kLanguagesThatUseSpace),
- LanguageMatcher(base_language)) !=
+ std::bind2nd(EqualToTolowerString(), base_language)) !=
kLanguagesThatUseSpace + arraysize(kLanguagesThatUseSpace)) {
return kSpaceSeparator;
- } else if (std::find_if(kLanguagesThatHaveNoSeparator,
- kLanguagesThatHaveNoSeparator +
- arraysize(kLanguagesThatHaveNoSeparator),
- LanguageMatcher(base_language)) !=
+ } else if (std::find_if(
+ kLanguagesThatHaveNoSeparator,
+ kLanguagesThatHaveNoSeparator +
+ arraysize(kLanguagesThatHaveNoSeparator),
+ std::bind2nd(EqualToTolowerString(), base_language)) !=
kLanguagesThatHaveNoSeparator +
arraysize(kLanguagesThatHaveNoSeparator)) {
return "";
- } else if (std::find_if(kLanguagesThatUseAnArabicComma,
- kLanguagesThatUseAnArabicComma +
- arraysize(kLanguagesThatUseAnArabicComma),
- LanguageMatcher(base_language)) !=
+ } else if (std::find_if(
+ kLanguagesThatUseAnArabicComma,
+ kLanguagesThatUseAnArabicComma +
+ arraysize(kLanguagesThatUseAnArabicComma),
+ std::bind2nd(EqualToTolowerString(), base_language)) !=
kLanguagesThatUseAnArabicComma +
arraysize(kLanguagesThatUseAnArabicComma)) {
return kArabicCommaSeparator;
}
- // Either the language is a latin-script language, or no language was
+ // Either the language is a Latin-script language, or no language was
// specified. In the latter case we still return ", " as the most common
// separator in use. In countries that don't use this, e.g. Thailand,
- // addresses are often written in latin script where this would still be
+ // addresses are often written in Latin script where this would still be
// appropriate, so this is a reasonable default in the absence of information.
return kCommaSeparator;
}
-void CombineLinesForLanguage(
- const std::vector<std::string>& lines, const std::string& language_tag,
- std::string *line) {
- if (lines.size() > 0) {
- line->assign(lines[0]);
- }
+void CombineLinesForLanguage(const std::vector<std::string>& lines,
+ const std::string& language_tag,
+ std::string* line) {
+ line->clear();
std::string separator = GetLineSeparatorForLanguage(language_tag);
- for (std::vector<std::string>::const_iterator it = lines.begin() + 1;
- it < lines.end(); ++it) {
- line->append(separator);
+ for (std::vector<std::string>::const_iterator it = lines.begin();
+ it != lines.end();
+ ++it) {
+ if (it != lines.begin()) {
+ line->append(separator);
+ }
line->append(*it);
}
}
@@ -143,36 +139,73 @@
Language language(address_data.language_code);
- // If latinized rules are available and the |language_code| of this address is
- // explicitly tagged as being Latin, then use the latinized formatting rules.
+ // If Latin-script rules are available and the |language_code| of this address
+ // is explicitly tagged as being Latin, then use the Latin-script formatting
+ // rules.
const std::vector<FormatElement>& format =
language.has_latin_script && !rule.GetLatinFormat().empty()
- ? rule.GetLatinFormat() : rule.GetFormat();
+ ? rule.GetLatinFormat()
+ : rule.GetFormat();
+
+ // Address format without the unnecessary elements (based on which address
+ // fields are empty). We assume all literal strings that are not at the start
+ // or end of a line are separators, and therefore only relevant if the
+ // surrounding fields are filled in. This works with the data we have
+ // currently.
+ std::vector<FormatElement> pruned_format;
+ for (std::vector<FormatElement>::const_iterator
+ element_it = format.begin();
+ element_it != format.end();
+ ++element_it) {
+ // Always keep the newlines.
+ if (element_it->IsNewline() ||
+ // Always keep the non-empty address fields.
+ (element_it->IsField() &&
+ !address_data.IsFieldEmpty(element_it->GetField())) ||
+ // Only keep literals that satisfy these 2 conditions:
+ (!element_it->IsField() &&
+ // (1) Not preceding an empty field.
+ (element_it + 1 == format.end() ||
+ !(element_it + 1)->IsField() ||
+ !address_data.IsFieldEmpty((element_it + 1)->GetField())) &&
+ // (2) Not following a removed field.
+ (element_it == format.begin() ||
+ !(element_it - 1)->IsField() ||
+ (!pruned_format.empty() && pruned_format.back().IsField())))) {
+ pruned_format.push_back(*element_it);
+ }
+ }
std::string line;
- for (size_t i = 0; i < format.size(); ++i) {
- FormatElement element = format[i];
- if (element.IsNewline()) {
+ for (std::vector<FormatElement>::const_iterator
+ element_it = pruned_format.begin();
+ element_it != pruned_format.end();
+ ++element_it) {
+ if (element_it->IsNewline()) {
if (!line.empty()) {
lines->push_back(line);
line.clear();
}
- } else if (element.IsField()) {
- AddressField field = element.GetField();
+ } else if (element_it->IsField()) {
+ AddressField field = element_it->GetField();
if (field == STREET_ADDRESS) {
// The field "street address" represents the street address lines of an
// address, so there can be multiple values.
- if (!line.empty()) {
- lines->push_back(line);
- line.clear();
+ if (!address_data.IsFieldEmpty(field)) {
+ line.append(address_data.address_line.front());
+ if (address_data.address_line.size() > 1U) {
+ lines->push_back(line);
+ line.clear();
+ lines->insert(lines->end(),
+ address_data.address_line.begin() + 1,
+ address_data.address_line.end());
+ }
}
- lines->insert(lines->end(), address_data.address_line.begin(),
- address_data.address_line.end());
} else {
line.append(address_data.GetFieldValue(field));
}
} else {
- line.append(element.GetLiteral());
+ line.append(element_it->GetLiteral());
}
}
if (!line.empty()) {
diff --git a/cpp/src/address_input_helper.cc b/cpp/src/address_input_helper.cc
index a8ce92f..c492760 100644
--- a/cpp/src/address_input_helper.cc
+++ b/cpp/src/address_input_helper.cc
@@ -14,15 +14,17 @@
#include <libaddressinput/address_input_helper.h>
+#include <libaddressinput/address_data.h>
+#include <libaddressinput/address_field.h>
+#include <libaddressinput/preload_supplier.h>
+#include <libaddressinput/util/basictypes.h>
+
#include <cassert>
#include <cstddef>
#include <string>
#include <vector>
-#include <libaddressinput/address_data.h>
-#include <libaddressinput/address_field.h>
-#include <libaddressinput/preload_supplier.h>
-#include <libaddressinput/util/basictypes.h>
+#include <re2/re2.h>
#include "language.h"
#include "lookup_key.h"
@@ -97,7 +99,7 @@
AddressInputHelper::AddressInputHelper(PreloadSupplier* supplier)
: supplier_(supplier) {
- assert(supplier_ != NULL);
+ assert(supplier_ != NULL);
}
AddressInputHelper::~AddressInputHelper() {
diff --git a/cpp/src/address_metadata.cc b/cpp/src/address_metadata.cc
index 59030ef..c088e0d 100644
--- a/cpp/src/address_metadata.cc
+++ b/cpp/src/address_metadata.cc
@@ -17,7 +17,9 @@
#include <libaddressinput/address_field.h>
#include <algorithm>
+#include <string>
+#include "format_element.h"
#include "region_data_constants.h"
#include "rule.h"
diff --git a/cpp/src/address_normalizer.cc b/cpp/src/address_normalizer.cc
index e80489d..562203e 100644
--- a/cpp/src/address_normalizer.cc
+++ b/cpp/src/address_normalizer.cc
@@ -20,9 +20,10 @@
#include <cassert>
#include <cstddef>
+#include <string>
+#include <vector>
#include "lookup_key.h"
-#include "region_data_constants.h"
#include "rule.h"
#include "util/string_compare.h"
diff --git a/cpp/src/address_problem.cc b/cpp/src/address_problem.cc
index e6cf446..0fade17 100644
--- a/cpp/src/address_problem.cc
+++ b/cpp/src/address_problem.cc
@@ -14,11 +14,11 @@
#include <libaddressinput/address_problem.h>
+#include <libaddressinput/util/basictypes.h>
+
#include <cstddef>
#include <ostream>
-#include <libaddressinput/util/basictypes.h>
-
using i18n::addressinput::AddressProblem;
using i18n::addressinput::UNEXPECTED_FIELD;
using i18n::addressinput::USES_P_O_BOX;
diff --git a/cpp/src/address_ui.cc b/cpp/src/address_ui.cc
index a099335..33f0797 100644
--- a/cpp/src/address_ui.cc
+++ b/cpp/src/address_ui.cc
@@ -24,7 +24,6 @@
#include <string>
#include <vector>
-#include "address_field_util.h"
#include "format_element.h"
#include "grit.h"
#include "language.h"
@@ -64,6 +63,9 @@
case STREET_ADDRESS:
messageId = IDS_LIBADDRESSINPUT_ADDRESS_LINE_1_LABEL;
break;
+ case ORGANIZATION:
+ messageId = IDS_LIBADDRESSINPUT_ORGANIZATION_LABEL;
+ break;
case RECIPIENT:
messageId = IDS_LIBADDRESSINPUT_RECIPIENT_LABEL;
break;
@@ -99,9 +101,9 @@
*best_address_language_tag = best_address_language.tag;
const std::vector<FormatElement>& format =
- !rule.GetLatinFormat().empty() &&
- best_address_language.has_latin_script
- ? rule.GetLatinFormat() : rule.GetFormat();
+ !rule.GetLatinFormat().empty() && best_address_language.has_latin_script
+ ? rule.GetLatinFormat()
+ : rule.GetFormat();
// For avoiding showing an input field twice, when the field is displayed
// twice on an envelope.
@@ -127,8 +129,10 @@
: AddressUiComponent::HINT_SHORT;
preceded_by_newline = false;
component.field = format_it->GetField();
- component.name = GetLabelForField(localization, format_it->GetField(),
- rule.GetAdminAreaNameMessageId(), rule.GetPostalCodeNameMessageId());
+ component.name = GetLabelForField(localization,
+ format_it->GetField(),
+ rule.GetAdminAreaNameMessageId(),
+ rule.GetPostalCodeNameMessageId());
result.push_back(component);
}
diff --git a/cpp/src/address_validator.cc b/cpp/src/address_validator.cc
index b3e4aae..8f0c33c 100644
--- a/cpp/src/address_validator.cc
+++ b/cpp/src/address_validator.cc
@@ -14,6 +14,9 @@
#include <libaddressinput/address_validator.h>
+#include <cassert>
+#include <cstddef>
+
#include "validation_task.h"
namespace i18n {
diff --git a/cpp/src/language.cc b/cpp/src/language.cc
index 9e456f0..28817dc 100644
--- a/cpp/src/language.cc
+++ b/cpp/src/language.cc
@@ -32,13 +32,13 @@
// legacy code generates tags with '_' instead of '-'.
static const char kSubtagsSeparator = '-';
static const char kAlternativeSubtagsSeparator = '_';
- std::replace(tag.begin(), tag.end(), kAlternativeSubtagsSeparator,
- kSubtagsSeparator);
+ std::replace(
+ tag.begin(), tag.end(), kAlternativeSubtagsSeparator, kSubtagsSeparator);
// OK to use 'tolower' because BCP 47 tags are always in ASCII.
std::string lowercase = tag;
- std::transform(lowercase.begin(), lowercase.end(), lowercase.begin(),
- tolower);
+ std::transform(
+ lowercase.begin(), lowercase.end(), lowercase.begin(), tolower);
base = lowercase.substr(0, lowercase.find(kSubtagsSeparator));
diff --git a/cpp/src/localization.cc b/cpp/src/localization.cc
index 9bb32a5..b544cd9 100644
--- a/cpp/src/localization.cc
+++ b/cpp/src/localization.cc
@@ -21,8 +21,9 @@
#include <cassert>
#include <cstddef>
#include <string>
+#include <vector>
-#include "grit.h"
+#include "messages.h"
#include "region_data_constants.h"
#include "rule.h"
#include "util/string_split.h"
@@ -30,10 +31,11 @@
namespace {
-void PushBackUrl(std::vector<std::string>& parameters, const std::string url) {
+void PushBackUrl(const std::string& url, std::vector<std::string>* parameters) {
+ assert(parameters != NULL);
// TODO: HTML-escape the "url".
- parameters.push_back("<a href=\"" + url + "\">");
- parameters.push_back("</a>");
+ parameters->push_back("<a href=\"" + url + "\">");
+ parameters->push_back("</a>");
}
} // namespace
@@ -136,7 +138,7 @@
IDS_LIBADDRESSINPUT_MISSING_REQUIRED_POSTAL_CODE_EXAMPLE_AND_URL :
IDS_LIBADDRESSINPUT_MISSING_REQUIRED_ZIP_CODE_EXAMPLE_AND_URL;
parameters.push_back(postal_code_example);
- PushBackUrl(parameters, post_service_url);
+ PushBackUrl(post_service_url, ¶meters);
} else if (!postal_code_example.empty()) {
message_id = uses_postal_code_as_label ?
IDS_LIBADDRESSINPUT_MISSING_REQUIRED_POSTAL_CODE_EXAMPLE :
@@ -152,7 +154,7 @@
IDS_LIBADDRESSINPUT_UNRECOGNIZED_FORMAT_POSTAL_CODE_EXAMPLE_AND_URL :
IDS_LIBADDRESSINPUT_UNRECOGNIZED_FORMAT_ZIP_CODE_EXAMPLE_AND_URL;
parameters.push_back(postal_code_example);
- PushBackUrl(parameters, post_service_url);
+ PushBackUrl(post_service_url, ¶meters);
} else if (!postal_code_example.empty()) {
message_id = uses_postal_code_as_label ?
IDS_LIBADDRESSINPUT_UNRECOGNIZED_FORMAT_POSTAL_CODE_EXAMPLE :
@@ -169,7 +171,7 @@
message_id = uses_postal_code_as_label ?
IDS_LIBADDRESSINPUT_MISMATCHING_VALUE_POSTAL_CODE_URL :
IDS_LIBADDRESSINPUT_MISMATCHING_VALUE_ZIP_URL;
- PushBackUrl(parameters, post_service_url);
+ PushBackUrl(post_service_url, ¶meters);
} else {
message_id = uses_postal_code_as_label ?
IDS_LIBADDRESSINPUT_MISMATCHING_VALUE_POSTAL_CODE :
diff --git a/cpp/src/lookup_key.cc b/cpp/src/lookup_key.cc
index b6f73fc..d793a2b 100644
--- a/cpp/src/lookup_key.cc
+++ b/cpp/src/lookup_key.cc
@@ -14,20 +14,23 @@
#include "lookup_key.h"
+#include <libaddressinput/address_data.h>
+#include <libaddressinput/address_field.h>
+#include <libaddressinput/util/basictypes.h>
+
+#include <algorithm>
#include <cassert>
#include <cstddef>
+#include <functional>
#include <map>
#include <string>
#include <utility>
#include <vector>
-#include <libaddressinput/address_data.h>
-#include <libaddressinput/address_field.h>
-#include <libaddressinput/util/basictypes.h>
-
#include "language.h"
#include "region_data_constants.h"
#include "rule.h"
+#include "util/cctype_tolower_equal.h"
namespace i18n {
namespace addressinput {
@@ -39,15 +42,6 @@
const char kData[] = "data";
const char kUnknown[] = "ZZ";
-// Case insensitive matcher for language tags.
-struct LanguageMatcher {
- LanguageMatcher(const std::string& tag) : tag(tag) { }
- std::string tag;
- bool operator() (const std::string& s) {
- return strcasecmp(tag.c_str(), s.c_str()) == 0;
- }
-};
-
// Assume the language_tag has had "Latn" script removed when this is called.
bool ShouldSetLanguageForKey(const std::string& language_tag,
const std::string& region_code) {
@@ -69,10 +63,9 @@
return false;
}
// Finally, only return true if the language is one of the remaining ones.
- return std::find_if(languages.begin() + 1,
- languages.end(),
- LanguageMatcher(language_tag))
- != languages.end();
+ return std::find_if(languages.begin() + 1, languages.end(),
+ std::bind2nd(EqualToTolowerString(), language_tag)) !=
+ languages.end();
}
} // namespace
@@ -105,8 +98,9 @@
}
}
Language address_language(address.language_code);
- std::string language_tag_no_latn = address_language.has_latin_script ?
- address_language.base : address_language.tag;
+ std::string language_tag_no_latn = address_language.has_latin_script
+ ? address_language.base
+ : address_language.tag;
if (ShouldSetLanguageForKey(language_tag_no_latn, address.region_code)) {
language_ = language_tag_no_latn;
}
@@ -117,7 +111,8 @@
assert(parent.nodes_.size() < arraysize(kHierarchy));
assert(!child_node.empty());
- nodes_ = parent.nodes_;
+ // Copy its nodes if this isn't the parent object.
+ if (this != &parent) nodes_ = parent.nodes_;
AddressField child_field = kHierarchy[nodes_.size()];
nodes_.insert(std::make_pair(child_field, child_node));
}
diff --git a/cpp/src/lookup_key_util.cc b/cpp/src/lookup_key_util.cc
deleted file mode 100644
index e63e9a5..0000000
--- a/cpp/src/lookup_key_util.cc
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright (C) 2013 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 "lookup_key_util.h"
-
-#include <cassert>
-#include <string>
-
-namespace i18n {
-namespace addressinput {
-
-LookupKeyUtil::LookupKeyUtil(const std::string& validation_data_url)
- : validation_data_url_(validation_data_url) {
- assert(validation_data_url_.length() > 0);
- assert(validation_data_url_[validation_data_url_.length() - 1] == '/');
-}
-
-LookupKeyUtil::~LookupKeyUtil() {}
-
-std::string LookupKeyUtil::GetUrlForKey(const std::string& key) const {
- return validation_data_url_ + key;
-}
-
-std::string LookupKeyUtil::GetKeyForUrl(const std::string& url) const {
- return IsValidationDataUrl(url) ? url.substr(validation_data_url_.length())
- : std::string();
-}
-
-bool LookupKeyUtil::IsValidationDataUrl(const std::string& url) const {
- return
- url.compare(0, validation_data_url_.length(), validation_data_url_) == 0;
-}
-
-} // namespace addressinput
-} // namespace i18n
diff --git a/cpp/src/lookup_key_util.h b/cpp/src/lookup_key_util.h
deleted file mode 100644
index 4996c1c..0000000
--- a/cpp/src/lookup_key_util.h
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright (C) 2013 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.
-//
-// Functions for working with lookup keys. The lookup keys are strings that
-// identify serialized validation rules.
-
-#ifndef I18N_ADDRESSINPUT_LOOKUP_KEY_UTIL_H_
-#define I18N_ADDRESSINPUT_LOOKUP_KEY_UTIL_H_
-
-#include <string>
-
-namespace i18n {
-namespace addressinput {
-
-// Utility functions for lookup keys. Sample usage:
-// LookupKeyUtil lookup_keys("https://i18napis.appspot.com/ssl-address/");
-// Download(lookup_keys.GetUrlForKey("data/US"));
-class LookupKeyUtil {
- public:
- // Builds a lookup key utility for the |validation_data_url| parameter. The
- // parameter must end with a '/'.
- explicit LookupKeyUtil(const std::string& validation_data_url);
- ~LookupKeyUtil();
-
- // Returns the URL where the |key| can be retrieved. For example, returns
- // "https://i18napis.appspot.com/ssl-address/data/US" for input "data/US".
- // Assumes that the input string is a valid URL segment.
- std::string GetUrlForKey(const std::string& key) const;
-
- // Returns the key for the |url|. For example, returns "data/US" for
- // "https://i18napis.appspot.com/ssl-address/data/US". If the |url| does not
- // start with |validation_data_url| that was passed to the constructor, then
- // returns an empty string. (This can happen if the user of the library
- // returns a bad URL in their Downloader implementation.)
- std::string GetKeyForUrl(const std::string& url) const;
-
- // Returns true if the |url| starts with |validation_data_url| that was passed
- // to the constructor.
- bool IsValidationDataUrl(const std::string& url) const;
-
- private:
- const std::string validation_data_url_;
-};
-
-} // namespace addressinput
-} // namespace i18n
-
-#endif // I18N_ADDRESSINPUT_LOOKUP_KEY_UTIL_H_
diff --git a/cpp/src/ondemand_supplier.cc b/cpp/src/ondemand_supplier.cc
index 9228570..fa3f88e 100644
--- a/cpp/src/ondemand_supplier.cc
+++ b/cpp/src/ondemand_supplier.cc
@@ -19,8 +19,6 @@
#include <map>
#include <string>
-#include <libaddressinput/util/scoped_ptr.h>
-
#include "lookup_key.h"
#include "ondemand_supply_task.h"
#include "region_data_constants.h"
@@ -30,10 +28,8 @@
namespace i18n {
namespace addressinput {
-OndemandSupplier::OndemandSupplier(const std::string& validation_data_url,
- const Downloader* downloader,
- Storage* storage)
- : retriever_(new Retriever(validation_data_url, downloader, storage)) {
+OndemandSupplier::OndemandSupplier(const Source* source, Storage* storage)
+ : retriever_(new Retriever(source, storage)) {
}
OndemandSupplier::~OndemandSupplier() {
diff --git a/cpp/src/ondemand_supply_task.cc b/cpp/src/ondemand_supply_task.cc
index ab92746..a4f6a12 100644
--- a/cpp/src/ondemand_supply_task.cc
+++ b/cpp/src/ondemand_supply_task.cc
@@ -14,6 +14,11 @@
#include "ondemand_supply_task.h"
+#include <libaddressinput/address_field.h>
+#include <libaddressinput/callback.h>
+#include <libaddressinput/supplier.h>
+#include <libaddressinput/util/basictypes.h>
+
#include <algorithm>
#include <cassert>
#include <cstddef>
@@ -22,12 +27,6 @@
#include <string>
#include <utility>
-#include <libaddressinput/address_field.h>
-#include <libaddressinput/callback.h>
-#include <libaddressinput/supplier.h>
-#include <libaddressinput/util/basictypes.h>
-#include <libaddressinput/util/scoped_ptr.h>
-
#include "lookup_key.h"
#include "retriever.h"
#include "rule.h"
@@ -64,7 +63,7 @@
} else {
// When the final pending rule has been retrieved, the retrieved_ callback,
// implemented by Load(), will finish by calling Loaded(), which will finish
- // by delete'ing this RuleHierarchy object. So after the final call to
+ // by delete'ing this OndemandSupplyTask object. So after the final call to
// retriever.Retrieve() no attributes of this object can be accessed (as the
// object then no longer will exist, if the final callback has finished by
// then), and the condition statement of the loop must therefore not use the
@@ -82,21 +81,20 @@
void OndemandSupplyTask::Load(bool success,
const std::string& key,
const std::string& data) {
+ size_t depth = std::count(key.begin(), key.end(), '/') - 1;
+ assert(depth < arraysize(LookupKey::kHierarchy));
+
// Sanity check: This key should be present in the set of pending requests.
size_t status = pending_.erase(key);
assert(status == 1); // There will always be one item erased from the set.
(void)status; // Prevent unused variable if assert() is optimized away.
- size_t depth = std::count(key.begin(), key.end(), '/') - 1;
- assert(depth < arraysize(LookupKey::kHierarchy));
- AddressField field = LookupKey::kHierarchy[depth];
-
if (success) {
// The address metadata server will return the empty JSON "{}" when it
// successfully performed a lookup, but didn't find any data for that key.
if (data != "{}") {
Rule* rule = new Rule;
- if (field == COUNTRY) {
+ if (LookupKey::kHierarchy[depth] == COUNTRY) {
// All rules on the COUNTRY level inherit from the default rule.
rule->CopyFrom(Rule::GetDefault());
}
diff --git a/cpp/src/ondemand_supply_task.h b/cpp/src/ondemand_supply_task.h
index 61e3567..45b33c9 100644
--- a/cpp/src/ondemand_supply_task.h
+++ b/cpp/src/ondemand_supply_task.h
@@ -29,7 +29,6 @@
namespace addressinput {
class LookupKey;
-class Retriever;
class Rule;
// An OndemandSupplyTask object encapsulates the information necessary to
diff --git a/cpp/src/post_box_matchers.cc b/cpp/src/post_box_matchers.cc
index 1edd8b3..f1ad6dd 100644
--- a/cpp/src/post_box_matchers.cc
+++ b/cpp/src/post_box_matchers.cc
@@ -20,12 +20,12 @@
#include <utility>
#include <vector>
+#include <re2/re2.h>
+
#include "language.h"
#include "rule.h"
#include "util/re2ptr.h"
-#include <re2/re2.h>
-
namespace i18n {
namespace addressinput {
@@ -97,7 +97,7 @@
return matchers;
}
-} // namespace
+} // namespace
// static
std::vector<const RE2ptr*> PostBoxMatchers::GetMatchers(
diff --git a/cpp/src/post_box_matchers.h b/cpp/src/post_box_matchers.h
index 8f9f44b..9924a2c 100644
--- a/cpp/src/post_box_matchers.h
+++ b/cpp/src/post_box_matchers.h
@@ -17,19 +17,24 @@
#ifndef I18N_ADDRESSINPUT_POST_BOX_MATCHERS_H_
#define I18N_ADDRESSINPUT_POST_BOX_MATCHERS_H_
+#include <libaddressinput/util/basictypes.h>
+
#include <vector>
namespace i18n {
namespace addressinput {
-class RE2ptr;
class Rule;
+struct RE2ptr;
class PostBoxMatchers {
public:
// Returns pointers to RE2 regular expression objects to test address lines
// for those languages that are relevant for |country_rule|.
static std::vector<const RE2ptr*> GetMatchers(const Rule& country_rule);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(PostBoxMatchers);
};
} // namespace addressinput
diff --git a/cpp/src/preload_supplier.cc b/cpp/src/preload_supplier.cc
index 31325bd..79119bd 100644
--- a/cpp/src/preload_supplier.cc
+++ b/cpp/src/preload_supplier.cc
@@ -32,7 +32,6 @@
#include <utility>
#include <vector>
-#include "language.h"
#include "lookup_key.h"
#include "region_data_constants.h"
#include "retriever.h"
@@ -53,15 +52,11 @@
public:
result_type operator()(const first_argument_type& a,
const second_argument_type& b) const {
+ static const StringCompare kStringCompare;
return kStringCompare.NaturalLess(a, b);
}
-
- private:
- static const StringCompare kStringCompare;
};
-const StringCompare IndexLess::kStringCompare;
-
} // namespace
class IndexMap : public std::map<std::string, const Rule*, IndexLess> {};
@@ -77,16 +72,19 @@
const Retriever& retriever,
std::set<std::string>* pending,
IndexMap* rule_index,
- std::vector<const Rule*>* rule_storage)
+ std::vector<const Rule*>* rule_storage,
+ std::map<std::string, const Rule*>* region_rules)
: region_code_(region_code),
loaded_(loaded),
pending_(pending),
rule_index_(rule_index),
rule_storage_(rule_storage),
+ region_rules_(region_rules),
retrieved_(BuildCallback(this, &Helper::OnRetrieved)) {
assert(pending_ != NULL);
assert(rule_index_ != NULL);
assert(rule_storage_ != NULL);
+ assert(region_rules_ != NULL);
assert(retrieved_ != NULL);
pending_->insert(key);
retriever.Retrieve(key, *retrieved_);
@@ -105,8 +103,17 @@
(void)status; // Prevent unused variable if assert() is optimized away.
Json json;
+ std::string id;
std::vector<const Rule*> sub_rules;
+ IndexMap::iterator last_index_it = rule_index_->end();
+ IndexMap::iterator last_latin_it = rule_index_->end();
+ std::map<std::string, const Rule*>::iterator last_region_it =
+ region_rules_->end();
+
+ IndexMap::const_iterator hints[arraysize(LookupKey::kHierarchy) - 1];
+ std::fill(hints, hints + arraysize(hints), rule_index_->end());
+
if (!success) {
goto callback;
}
@@ -116,20 +123,17 @@
goto callback;
}
- for (std::vector<std::string>::const_iterator
- it = json.GetKeys().begin(); it != json.GetKeys().end(); ++it) {
- if (!json.HasDictionaryValueForKey(*it)) {
+ for (std::vector<const Json*>::const_iterator
+ it = json.GetSubDictionaries().begin();
+ it != json.GetSubDictionaries().end();
+ ++it) {
+ const Json* value = *it;
+ assert(value != NULL);
+ if (!value->GetStringValueForKey("id", &id)) {
success = false;
goto callback;
}
- const Json& value = json.GetDictionaryValueForKey(*it);
-
- if (!value.HasStringValueForKey("id")) {
- success = false;
- goto callback;
- }
- const std::string& id = value.GetStringValueForKey("id");
- assert(*it == id); // Sanity check.
+ assert(!id.empty());
size_t depth = std::count(id.begin(), id.end(), '/') - 1;
assert(depth < arraysize(LookupKey::kHierarchy));
@@ -140,7 +144,7 @@
// All rules on the COUNTRY level inherit from the default rule.
rule->CopyFrom(Rule::GetDefault());
}
- rule->ParseJsonRule(value);
+ rule->ParseJsonRule(*value);
assert(id == rule->GetId()); // Sanity check.
rule_storage_->push_back(rule);
@@ -148,11 +152,15 @@
sub_rules.push_back(rule);
}
- // Add the ID of this Rule object to the rule index.
- std::pair<IndexMap::iterator, bool> result =
- rule_index_->insert(std::make_pair(id, rule));
- assert(result.second);
- (void)result; // Prevent unused variable if assert() is optimized away.
+ // Add the ID of this Rule object to the rule index with natural string
+ // comparison for keys.
+ last_index_it =
+ rule_index_->insert(last_index_it, std::make_pair(id, rule));
+
+ // Add the ID of this Rule object to the region-specific rule index with
+ // exact string comparison for keys.
+ last_region_it =
+ region_rules_->insert(last_region_it, std::make_pair(id, rule));
++rule_count;
}
@@ -184,9 +192,12 @@
}
parent_id.resize(pos);
- IndexMap::const_iterator jt = rule_index_->find(parent_id);
- assert(jt != rule_index_->end());
- hierarchy.push(jt->second);
+ IndexMap::const_iterator* const hint = &hints[hierarchy.size() - 1];
+ if (*hint == rule_index_->end() || (*hint)->first != parent_id) {
+ *hint = rule_index_->find(parent_id);
+ }
+ assert(*hint != rule_index_->end());
+ hierarchy.push((*hint)->second);
}
std::string human_id((*it)->GetId().substr(0, sizeof "data/ZZ" - 1));
@@ -222,13 +233,15 @@
}
}
- rule_index_->insert(std::make_pair(human_id, *it));
+ last_index_it =
+ rule_index_->insert(last_index_it, std::make_pair(human_id, *it));
// Add the Latin script ID, if a Latin script name could be found for
// every part of the ID.
if (std::count(human_id.begin(), human_id.end(), '/') ==
std::count(latin_id.begin(), latin_id.end(), '/')) {
- rule_index_->insert(std::make_pair(latin_id, *it));
+ last_latin_it =
+ rule_index_->insert(last_latin_it, std::make_pair(latin_id, *it));
}
}
@@ -242,6 +255,7 @@
std::set<std::string>* const pending_;
IndexMap* const rule_index_;
std::vector<const Rule*>* const rule_storage_;
+ std::map<std::string, const Rule*>* const region_rules_;
const scoped_ptr<const Retriever::Callback> retrieved_;
DISALLOW_COPY_AND_ASSIGN(Helper);
@@ -257,13 +271,12 @@
} // namespace
-PreloadSupplier::PreloadSupplier(const std::string& validation_data_url,
- const Downloader* downloader,
- Storage* storage)
- : retriever_(new Retriever(validation_data_url, downloader, storage)),
+PreloadSupplier::PreloadSupplier(const Source* source, Storage* storage)
+ : retriever_(new Retriever(source, storage)),
pending_(),
rule_index_(new IndexMap),
- rule_storage_() {}
+ rule_storage_(),
+ region_rules_() {}
PreloadSupplier::~PreloadSupplier() {
for (std::vector<const Rule*>::const_iterator
@@ -308,7 +321,14 @@
*retriever_,
&pending_,
rule_index_.get(),
- &rule_storage_);
+ &rule_storage_,
+ ®ion_rules_[region_code]);
+}
+
+const std::map<std::string, const Rule*>& PreloadSupplier::GetRulesForRegion(
+ const std::string& region_code) const {
+ assert(IsLoaded(region_code));
+ return region_rules_.find(region_code)->second;
}
bool PreloadSupplier::IsLoaded(const std::string& region_code) const {
diff --git a/cpp/src/region_data.cc b/cpp/src/region_data.cc
index f5f0275..798501e 100644
--- a/cpp/src/region_data.cc
+++ b/cpp/src/region_data.cc
@@ -14,7 +14,6 @@
#include <libaddressinput/region_data.h>
-#include <cassert>
#include <cstddef>
#include <string>
#include <vector>
diff --git a/cpp/src/region_data_builder.cc b/cpp/src/region_data_builder.cc
index 82d223c..b600d09 100644
--- a/cpp/src/region_data_builder.cc
+++ b/cpp/src/region_data_builder.cc
@@ -17,6 +17,7 @@
#include <libaddressinput/address_data.h>
#include <libaddressinput/preload_supplier.h>
#include <libaddressinput/region_data.h>
+#include <libaddressinput/util/basictypes.h>
#include <cassert>
#include <cstddef>
@@ -34,56 +35,91 @@
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);
+// The maximum depth of lookup keys.
+static const size_t kLookupKeysMaxDepth = arraysize(LookupKey::kHierarchy) - 1;
+
+// Does not take ownership of |parent_region|, which is not allowed to be NULL.
+void BuildRegionTreeRecursively(
+ const std::map<std::string, const Rule*>& rules,
+ std::map<std::string, const Rule*>::const_iterator hint,
+ const LookupKey& parent_key,
+ RegionData* parent_region,
+ const std::vector<std::string>& keys,
+ bool prefer_latin_name,
+ size_t region_max_depth) {
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& lookup_key_string =
+ lookup_key.ToKeyString(kLookupKeysMaxDepth);
+
+ ++hint;
+ if (hint == rules.end() || hint->first != lookup_key_string) {
+ hint = rules.find(lookup_key_string);
+ if (hint == rules.end()) {
+ return;
+ }
}
+
+ const Rule* rule = hint->second;
+ assert(rule != NULL);
+
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);
+
+ if (!rule->GetSubKeys().empty() &&
+ region_max_depth > parent_key.GetDepth()) {
+ BuildRegionTreeRecursively(rules,
+ hint,
+ lookup_key,
+ region,
+ rule->GetSubKeys(),
+ prefer_latin_name,
+ region_max_depth);
}
}
}
-// Does not take ownership of |supplier|, which cannot be NULL. The caller owns
-// the result.
-RegionData* BuildRegion(PreloadSupplier* supplier,
+// The caller owns the result.
+RegionData* BuildRegion(const std::map<std::string, const Rule*>& rules,
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);
+ std::map<std::string, const Rule*>::const_iterator hint =
+ rules.find(lookup_key.ToKeyString(kLookupKeysMaxDepth));
+ assert(hint != rules.end());
+
+ const Rule* rule = hint->second;
assert(rule != NULL);
RegionData* region = new RegionData(region_code);
- BuildRegionTreeRecursively(supplier, lookup_key, region,
- rule->GetSubKeys(), language.has_latin_script);
+
+ // If there're sub-keys for field X, but field X is not used in this region
+ // code, then these sub-keys are skipped over. For example, CH has sub-keys
+ // for field ADMIN_AREA, but CH does not use ADMIN_AREA field.
+ size_t region_max_depth =
+ RegionDataConstants::GetMaxLookupKeyDepth(region_code);
+ if (region_max_depth > 0) {
+ BuildRegionTreeRecursively(rules,
+ hint,
+ lookup_key,
+ region,
+ rule->GetSubKeys(),
+ language.has_latin_script,
+ region_max_depth);
+ }
return region;
}
@@ -127,17 +163,23 @@
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));
+ 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;
+ const std::map<std::string, const Rule*>& rules =
+ supplier_->GetRulesForRegion(region_code);
+ language_it =
+ region_it->second->insert(std::make_pair(best_language.tag,
+ BuildRegion(rules,
+ region_code,
+ best_language)))
+ .first;
}
return *language_it->second;
diff --git a/cpp/src/region_data_constants.cc b/cpp/src/region_data_constants.cc
index cabee28..e21d4b8 100644
--- a/cpp/src/region_data_constants.cc
+++ b/cpp/src/region_data_constants.cc
@@ -16,6 +16,9 @@
#include "region_data_constants.h"
+#include <libaddressinput/address_field.h>
+#include <libaddressinput/util/basictypes.h>
+
#include <algorithm>
#include <cstddef>
#include <map>
@@ -24,10 +27,8 @@
#include <utility>
#include <vector>
-#include <libaddressinput/address_field.h>
-#include <libaddressinput/util/basictypes.h>
-
#include "address_field_util.h"
+#include "format_element.h"
#include "lookup_key.h"
namespace i18n {
@@ -43,9 +44,8 @@
"\"languages\":\"en\""
"}"));
region_data.insert(std::make_pair("AD", "{"
- "\"fmt\":\"%N%n%O%n%A%n%Z %S\","
- "\"require\":\"AS\","
- "\"state_name_type\":\"parish\","
+ "\"fmt\":\"%N%n%O%n%A%n%Z %C\","
+ "\"require\":\"A\","
"\"zipex\":\"AD100,AD501,AD700\","
"\"posturl\":\"http://www.correos.es/comun/CodigosPostales/1010_s-CodPostal.asp\?Provincia=\","
"\"languages\":\"ca\""
@@ -119,7 +119,7 @@
"\"languages\":\"nl~pap\""
"}"));
region_data.insert(std::make_pair("AX", "{"
- "\"fmt\":\"%O%n%N%n%A%nAX-%Z %C%n\u00c5LAND\","
+ "\"fmt\":\"%O%n%N%n%A%nAX-%Z %C%n\\u00c5LAND\","
"\"require\":\"ACZ\","
"\"zipex\":\"22150,22550,22240,22710,22270,22730,22430\","
"\"posturl\":\"http://www.posten.ax/department.con\?iPage=123\","
@@ -329,7 +329,7 @@
"\"languages\":\"ar~fr\""
"}"));
region_data.insert(std::make_pair("DK", "{"
- "\"fmt\":\"%O%n%N%n%A%n%Z %C\","
+ "\"fmt\":\"%N%n%O%n%A%n%Z %C\","
"\"require\":\"ACZ\","
"\"zipex\":\"8660,1566\","
"\"posturl\":\"http://www.postdanmark.dk/da/Privat/Kundeservice/postnummerkort/Sider/Find-postnummer.aspx\","
@@ -634,7 +634,7 @@
"\"languages\":\"ar\""
"}"));
region_data.insert(std::make_pair("JP", "{"
- "\"fmt\":\"\u3012%Z%n%S%C%n%A%n%O%n%N\","
+ "\"fmt\":\"\\u3012%Z%n%S%C%n%A%n%O%n%N\","
"\"lfmt\":\"%N%n%O%n%A%n%C, %S%n%Z\","
"\"require\":\"ACSZ\","
"\"state_name_type\":\"prefecture\","
@@ -1062,8 +1062,9 @@
"\"languages\":\"sr-Cyrl~sr-Latn\""
"}"));
region_data.insert(std::make_pair("RU", "{"
- "\"fmt\":\"%Z %C %n%A%n%O%n%N\","
+ "\"fmt\":\"%N%n%O%n%A%n%C%n%S%n%Z\","
"\"require\":\"ACZ\","
+ "\"state_name_type\":\"oblast\","
"\"zipex\":\"125075,247112,103375\","
"\"posturl\":\"http://info.russianpost.ru/servlet/department\","
"\"languages\":\"ru\""
@@ -1242,7 +1243,9 @@
"\"languages\":\"sw~en\""
"}"));
region_data.insert(std::make_pair("UA", "{"
- "\"fmt\":\"%Z %C%n%A%n%O%n%N\","
+ "\"fmt\":\"%N%n%O%n%A%n%C%n%S%n%Z\","
+ "\"require\":\"ACZ\","
+ "\"state_name_type\":\"oblast\","
"\"zipex\":\"15432,01055,01001\","
"\"posturl\":\"http://services.ukrposhta.com/postindex_new/\","
"\"languages\":\"uk~ru\""
@@ -1396,8 +1399,10 @@
std::vector<std::string> InitRegionCodes() {
std::vector<std::string> region_codes(GetAllRegionData().size());
- std::transform(GetAllRegionData().begin(), GetAllRegionData().end(),
- region_codes.begin(), SelectFirst());
+ std::transform(GetAllRegionData().begin(),
+ GetAllRegionData().end(),
+ region_codes.begin(),
+ SelectFirst());
return region_codes;
}
diff --git a/cpp/src/region_data_constants.h b/cpp/src/region_data_constants.h
index 7a2c133..4159e72 100644
--- a/cpp/src/region_data_constants.h
+++ b/cpp/src/region_data_constants.h
@@ -15,6 +15,8 @@
#ifndef I18N_ADDRESSINPUT_REGION_DATA_CONSTANTS_H_
#define I18N_ADDRESSINPUT_REGION_DATA_CONSTANTS_H_
+#include <libaddressinput/util/basictypes.h>
+
#include <cstddef>
#include <string>
#include <vector>
@@ -29,6 +31,9 @@
static const std::string& GetRegionData(const std::string& region_code);
static const std::string& GetDefaultRegionData();
static size_t GetMaxLookupKeyDepth(const std::string& region_code);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(RegionDataConstants);
};
} // namespace addressinput
diff --git a/cpp/src/retriever.cc b/cpp/src/retriever.cc
index 8fa76b7..151b74d 100644
--- a/cpp/src/retriever.cc
+++ b/cpp/src/retriever.cc
@@ -15,7 +15,7 @@
#include "retriever.h"
#include <libaddressinput/callback.h>
-#include <libaddressinput/downloader.h>
+#include <libaddressinput/source.h>
#include <libaddressinput/storage.h>
#include <libaddressinput/util/basictypes.h>
#include <libaddressinput/util/scoped_ptr.h>
@@ -24,7 +24,6 @@
#include <cstddef>
#include <string>
-#include "lookup_key_util.h"
#include "validating_storage.h"
namespace i18n {
@@ -37,14 +36,12 @@
// Does not take ownership of its parameters.
Helper(const std::string& key,
const Retriever::Callback& retrieved,
- const LookupKeyUtil& lookup_key_util,
- const Downloader& downloader,
+ const Source& source,
ValidatingStorage* storage)
: retrieved_(retrieved),
- lookup_key_util_(lookup_key_util),
- downloader_(downloader),
+ source_(source),
storage_(storage),
- downloaded_(BuildCallback(this, &Helper::OnDownloaded)),
+ fresh_data_ready_(BuildCallback(this, &Helper::OnFreshDataReady)),
validated_data_ready_(
BuildCallback(this, &Helper::OnValidatedDataReady)),
stale_data_() {
@@ -68,13 +65,14 @@
if (data != NULL && !data->empty()) {
stale_data_ = *data;
}
- downloader_.Download(lookup_key_util_.GetUrlForKey(key), *downloaded_);
+ source_.Get(key, *fresh_data_ready_);
}
delete data;
}
- void OnDownloaded(bool success, const std::string& url, std::string* data) {
- const std::string& key = lookup_key_util_.GetKeyForUrl(url);
+ void OnFreshDataReady(bool success,
+ const std::string& key,
+ std::string* data) {
if (success) {
assert(data != NULL);
retrieved_(true, key, *data);
@@ -92,11 +90,10 @@
}
const Retriever::Callback& retrieved_;
- const LookupKeyUtil& lookup_key_util_;
- const Downloader& downloader_;
+ const Source& source_;
ValidatingStorage* storage_;
- scoped_ptr<Downloader::Callback> downloaded_;
- scoped_ptr<Storage::Callback> validated_data_ready_;
+ const scoped_ptr<const Source::Callback> fresh_data_ready_;
+ const scoped_ptr<const Storage::Callback> validated_data_ready_;
std::string stale_data_;
DISALLOW_COPY_AND_ASSIGN(Helper);
@@ -104,21 +101,17 @@
} // namespace
-Retriever::Retriever(const std::string& validation_data_url,
- const Downloader* downloader,
- Storage* storage)
- : lookup_key_util_(validation_data_url),
- downloader_(downloader),
- storage_(new ValidatingStorage(storage)) {
+Retriever::Retriever(const Source* source, Storage* storage)
+ : source_(source), storage_(new ValidatingStorage(storage)) {
+ assert(source_ != NULL);
assert(storage_ != NULL);
- assert(downloader_ != NULL);
}
Retriever::~Retriever() {}
void Retriever::Retrieve(const std::string& key,
const Callback& retrieved) const {
- new Helper(key, retrieved, lookup_key_util_, *downloader_, storage_.get());
+ new Helper(key, retrieved, *source_, storage_.get());
}
} // namespace addressinput
diff --git a/cpp/src/retriever.h b/cpp/src/retriever.h
index 17d17ec..4bf27a5 100644
--- a/cpp/src/retriever.h
+++ b/cpp/src/retriever.h
@@ -23,46 +23,40 @@
#include <string>
-#include "lookup_key_util.h"
-
namespace i18n {
namespace addressinput {
-class Downloader;
+class Source;
class Storage;
class ValidatingStorage;
// Retrieves data. Sample usage:
+// Source* source = ...;
// Storage* storage = ...;
-// Downloader* downloader = ...;
-// Retriever retriever("https://i18napis.appspot.com/ssl-address/",
-// downloader, storage);
-// scoped_ptr<Retriever::Callback> retrieved(BuildCallback(
-// this, &MyClass::OnDataRetrieved));
+// Retriever retriever(source, storage);
+// const scoped_ptr<const Retriever::Callback> retrieved(
+// BuildCallback(this, &MyClass::OnDataRetrieved));
// retriever.Retrieve("data/CA/AB--fr", *retrieved);
class Retriever {
public:
typedef i18n::addressinput::Callback<const std::string&,
const std::string&> Callback;
- // Takes ownership of |downloader| and |storage|.
- Retriever(const std::string& validation_data_url,
- const Downloader* downloader,
- Storage* storage);
+ // Takes ownership of |source| and |storage|.
+ Retriever(const Source* source, Storage* storage);
~Retriever();
// Retrieves the data for |key| and invokes the |retrieved| callback. Checks
- // for the data in storage first. If storage does not have the data for |key|,
- // then downloads the data and places it in storage. If the data in storage is
- // corrupted, then it's discarded and redownloaded. If the data is stale, then
- // it's redownloaded. If the download fails, then stale data will be returned
- // this one time. The next call to Retrieve() will attempt to download fresh
- // data again.
+ // for the data in |storage_| first. If storage does not have the data for
+ // |key|, then gets the data from |source_| and places it in storage. If the
+ // data in storage is corrupted, then it's discarded and requested anew. If
+ // the data is stale, then it's requested anew. If the request fails, then
+ // stale data will be returned this one time. Any subsequent call to
+ // Retrieve() will attempt to get fresh data again.
void Retrieve(const std::string& key, const Callback& retrieved) const;
private:
- const LookupKeyUtil lookup_key_util_;
- scoped_ptr<const Downloader> downloader_;
+ scoped_ptr<const Source> source_;
scoped_ptr<ValidatingStorage> storage_;
DISALLOW_COPY_AND_ASSIGN(Retriever);
diff --git a/cpp/src/rule.cc b/cpp/src/rule.cc
index e25142f..7ab84e5 100644
--- a/cpp/src/rule.cc
+++ b/cpp/src/rule.cc
@@ -14,14 +14,16 @@
#include "rule.h"
-#include <libaddressinput/address_field.h>
-
+#include <cassert>
#include <cstddef>
#include <map>
#include <string>
#include <utility>
+#include <re2/re2.h>
+
#include "address_field_util.h"
+#include "format_element.h"
#include "grit.h"
#include "messages.h"
#include "region_data_constants.h"
@@ -29,8 +31,6 @@
#include "util/re2ptr.h"
#include "util/string_split.h"
-#include <re2/re2.h>
-
namespace i18n {
namespace addressinput {
@@ -38,20 +38,6 @@
typedef std::map<std::string, int> NameMessageIdMap;
-const char kAdminAreaNameTypeKey[] = "state_name_type";
-const char kFormatKey[] = "fmt";
-const char kIdKey[] = "id";
-const char kLanguagesKey[] = "languages";
-const char kLatinFormatKey[] = "lfmt";
-const char kLatinNameKey[] = "lname";
-const char kNameKey[] = "name";
-const char kPostalCodeNameTypeKey[] = "zip_name_type";
-const char kRequireKey[] = "require";
-const char kSubKeysKey[] = "sub_keys";
-const char kZipKey[] = "zip";
-const char kPostalCodeExampleKey[] = "zipex";
-const char kPostServiceUrlKey[] = "posturl";
-
// Used as a separator in a list of items. For example, the list of supported
// languages can be "de~fr~it".
const char kSeparator = '~';
@@ -73,6 +59,8 @@
message_ids.insert(std::make_pair(
"island", IDS_LIBADDRESSINPUT_ISLAND));
message_ids.insert(std::make_pair(
+ "oblast", IDS_LIBADDRESSINPUT_OBLAST));
+ message_ids.insert(std::make_pair(
"parish", IDS_LIBADDRESSINPUT_PARISH));
message_ids.insert(std::make_pair(
"prefecture", IDS_LIBADDRESSINPUT_PREFECTURE));
@@ -150,6 +138,7 @@
}
void Rule::CopyFrom(const Rule& rule) {
+ assert(this != &rule);
id_ = rule.id_;
format_ = rule.format_;
latin_format_ = rule.latin_format_;
@@ -180,36 +169,33 @@
}
void Rule::ParseJsonRule(const Json& json) {
- if (json.HasStringValueForKey(kIdKey)) {
- id_ = json.GetStringValueForKey(kIdKey);
+ std::string value;
+ if (json.GetStringValueForKey("id", &value)) {
+ id_.swap(value);
}
- if (json.HasStringValueForKey(kFormatKey)) {
- ParseFormatRule(json.GetStringValueForKey(kFormatKey), &format_);
+ if (json.GetStringValueForKey("fmt", &value)) {
+ ParseFormatRule(value, &format_);
}
- if (json.HasStringValueForKey(kLatinFormatKey)) {
- ParseFormatRule(json.GetStringValueForKey(kLatinFormatKey), &latin_format_);
+ if (json.GetStringValueForKey("lfmt", &value)) {
+ ParseFormatRule(value, &latin_format_);
}
- if (json.HasStringValueForKey(kRequireKey)) {
- ParseAddressFieldsRequired(
- json.GetStringValueForKey(kRequireKey), &required_);
+ if (json.GetStringValueForKey("require", &value)) {
+ ParseAddressFieldsRequired(value, &required_);
}
- if (json.HasStringValueForKey(kSubKeysKey)) {
- SplitString(
- json.GetStringValueForKey(kSubKeysKey), kSeparator, &sub_keys_);
+ if (json.GetStringValueForKey("sub_keys", &value)) {
+ SplitString(value, kSeparator, &sub_keys_);
}
- if (json.HasStringValueForKey(kLanguagesKey)) {
- SplitString(
- json.GetStringValueForKey(kLanguagesKey), kSeparator, &languages_);
+ if (json.GetStringValueForKey("languages", &value)) {
+ SplitString(value, kSeparator, &languages_);
}
sole_postal_code_.clear();
- if (json.HasStringValueForKey(kZipKey)) {
- const std::string& zip = json.GetStringValueForKey(kZipKey);
+ if (json.GetStringValueForKey("zip", &value)) {
// The "zip" field in the JSON data is used in two different ways to
// validate the postal code. At the country level, the "zip" field indicates
// a Java compatible regular expression corresponding to all postal codes in
@@ -223,7 +209,7 @@
// RE2::FullMatch() to perform matching against the entire string.
RE2::Options options;
options.set_never_capture(true);
- RE2* matcher = new RE2("^(" + zip + ")", options);
+ RE2* matcher = new RE2("^(" + value + ")", options);
if (matcher->ok()) {
postal_code_matcher_.reset(new RE2ptr(matcher));
} else {
@@ -232,37 +218,35 @@
}
// If the "zip" field is not a regular expression, then it is the sole
// postal code for this rule.
- if (!ContainsRegExSpecialCharacters(zip)) {
- sole_postal_code_ = zip;
+ if (!ContainsRegExSpecialCharacters(value)) {
+ sole_postal_code_.swap(value);
}
}
- if (json.HasStringValueForKey(kAdminAreaNameTypeKey)) {
+ if (json.GetStringValueForKey("state_name_type", &value)) {
admin_area_name_message_id_ =
- GetMessageIdFromName(json.GetStringValueForKey(kAdminAreaNameTypeKey),
- GetAdminAreaMessageIds());
+ GetMessageIdFromName(value, GetAdminAreaMessageIds());
}
- if (json.HasStringValueForKey(kPostalCodeNameTypeKey)) {
+ if (json.GetStringValueForKey("zip_name_type", &value)) {
postal_code_name_message_id_ =
- GetMessageIdFromName(json.GetStringValueForKey(kPostalCodeNameTypeKey),
- GetPostalCodeMessageIds());
+ GetMessageIdFromName(value, GetPostalCodeMessageIds());
}
- if (json.HasStringValueForKey(kNameKey)) {
- name_ = json.GetStringValueForKey(kNameKey);
+ if (json.GetStringValueForKey("name", &value)) {
+ name_.swap(value);
}
- if (json.HasStringValueForKey(kLatinNameKey)) {
- latin_name_ = json.GetStringValueForKey(kLatinNameKey);
+ if (json.GetStringValueForKey("lname", &value)) {
+ latin_name_.swap(value);
}
- if (json.HasStringValueForKey(kPostalCodeExampleKey)) {
- postal_code_example_ = json.GetStringValueForKey(kPostalCodeExampleKey);
+ if (json.GetStringValueForKey("zipex", &value)) {
+ postal_code_example_.swap(value);
}
- if (json.HasStringValueForKey(kPostServiceUrlKey)) {
- post_service_url_ = json.GetStringValueForKey(kPostServiceUrlKey);
+ if (json.GetStringValueForKey("posturl", &value)) {
+ post_service_url_.swap(value);
}
}
diff --git a/cpp/src/rule.h b/cpp/src/rule.h
index c722932..1286bcb 100644
--- a/cpp/src/rule.h
+++ b/cpp/src/rule.h
@@ -27,13 +27,12 @@
#include <string>
#include <vector>
-#include "format_element.h"
-
namespace i18n {
namespace addressinput {
+class FormatElement;
class Json;
-class RE2ptr;
+struct RE2ptr;
// Stores address metadata addressing rules, to be used for determining the
// layout of an address input widget or for address validation. Sample usage:
@@ -99,9 +98,7 @@
}
// Returns the sole postal code for this rule, if there is one.
- const std::string& GetSolePostalCode() const {
- return sole_postal_code_;
- }
+ const std::string& GetSolePostalCode() const { return sole_postal_code_; }
// The message string identifier for admin area name. If not set, then
// INVALID_MESSAGE_ID.
@@ -127,9 +124,7 @@
}
// Returns the post service URL string for this rule.
- const std::string& GetPostServiceUrl() const {
- return post_service_url_;
- }
+ const std::string& GetPostServiceUrl() const { return post_service_url_; }
private:
std::string id_;
diff --git a/cpp/src/rule_retriever.cc b/cpp/src/rule_retriever.cc
index a77c93a..f0ed848 100644
--- a/cpp/src/rule_retriever.cc
+++ b/cpp/src/rule_retriever.cc
@@ -57,7 +57,7 @@
}
const RuleRetriever::Callback& rule_ready_;
- scoped_ptr<Retriever::Callback> data_retrieved_;
+ const scoped_ptr<const Retriever::Callback> data_retrieved_;
DISALLOW_COPY_AND_ASSIGN(Helper);
};
diff --git a/cpp/src/rule_retriever.h b/cpp/src/rule_retriever.h
index ba3b4c7..ae4b5ee 100644
--- a/cpp/src/rule_retriever.h
+++ b/cpp/src/rule_retriever.h
@@ -32,8 +32,8 @@
// Retrieves validation rules. Sample usage:
// const Retriever* retriever = ...
// RuleRetriever rules(retriever);
-// scoped_ptr<RuleRetriever::Callback> rule_ready(BuildCallback(
-// this, &MyClass::OnRuleReady));
+// const scoped_ptr<const RuleRetriever::Callback> rule_ready(
+// BuildCallback(this, &MyClass::OnRuleReady));
// rules.RetrieveRule("data/CA/AB--fr", *rule_ready);
class RuleRetriever {
public:
diff --git a/cpp/src/util/cctype_tolower_equal.cc b/cpp/src/util/cctype_tolower_equal.cc
new file mode 100644
index 0000000..819138f
--- /dev/null
+++ b/cpp/src/util/cctype_tolower_equal.cc
@@ -0,0 +1,44 @@
+// 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 "cctype_tolower_equal.h"
+
+#include <algorithm>
+#include <cctype>
+#include <functional>
+#include <string>
+
+namespace i18n {
+namespace addressinput {
+
+namespace {
+
+struct EqualToTolowerChar
+ : public std::binary_function<std::string::value_type,
+ std::string::value_type, bool> {
+ result_type operator()(first_argument_type a, second_argument_type b) const {
+ return std::tolower(a) == std::tolower(b);
+ }
+};
+
+} // namespace
+
+EqualToTolowerString::result_type EqualToTolowerString::operator()(
+ const first_argument_type& a, const second_argument_type& b) const {
+ return a.size() == b.size() &&
+ std::equal(a.begin(), a.end(), b.begin(), EqualToTolowerChar());
+}
+
+} // addressinput
+} // i18n
diff --git a/cpp/src/util/cctype_tolower_equal.h b/cpp/src/util/cctype_tolower_equal.h
new file mode 100644
index 0000000..106087e
--- /dev/null
+++ b/cpp/src/util/cctype_tolower_equal.h
@@ -0,0 +1,35 @@
+// 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_UTIL_CCTYPE_TOLOWER_EQUAL_H_
+#define I18N_ADDRESSINPUT_UTIL_CCTYPE_TOLOWER_EQUAL_H_
+
+#include <functional>
+#include <string>
+
+namespace i18n {
+namespace addressinput {
+
+// Performs case insensitive comparison of |a| and |b| by calling std::tolower()
+// from <cctype>.
+struct EqualToTolowerString
+ : public std::binary_function<std::string, std::string, bool> {
+ result_type operator()(const first_argument_type& a,
+ const second_argument_type& b) const;
+};
+
+} // addressinput
+} // i18n
+
+#endif // I18N_ADDRESSINPUT_UTIL_CCTYPE_TOLOWER_EQUAL_H_
diff --git a/cpp/src/util/json.cc b/cpp/src/util/json.cc
index d819bb2..730479c 100644
--- a/cpp/src/util/json.cc
+++ b/cpp/src/util/json.cc
@@ -19,9 +19,7 @@
#include <cassert>
#include <cstddef>
-#include <map>
#include <string>
-#include <utility>
#include <vector>
#include <rapidjson/document.h>
@@ -36,161 +34,100 @@
class Json::JsonImpl {
public:
- // Takes ownership of |document|.
- explicit JsonImpl(const Document* document)
- : document_(document), value_(document), dictionaries_() {
- assert(value_ != NULL);
- assert(value_->IsObject());
- BuildKeyList();
- }
-
- // Does not take ownership of |value|.
- explicit JsonImpl(const Value* value)
- : document_(), value_(value), dictionaries_() {
- assert(value_ != NULL);
- assert(value_->IsObject());
- BuildKeyList();
+ explicit JsonImpl(const std::string& json)
+ : document_(new Document),
+ value_(document_.get()),
+ dictionaries_(),
+ valid_(false) {
+ document_->Parse<kParseValidateEncodingFlag>(json.c_str());
+ valid_ = !document_->HasParseError() && document_->IsObject();
}
~JsonImpl() {
- for (std::map<std::string, const Json*>::const_iterator
- it = dictionaries_.begin();
+ for (std::vector<const Json*>::const_iterator it = dictionaries_.begin();
it != dictionaries_.end(); ++it) {
- delete it->second;
+ delete *it;
}
}
- // The caller does not own the result.
- const Value::Member* FindMember(const std::string& key) {
- return value_->FindMember(key.c_str());
+ bool valid() const { return valid_; }
+
+ const std::vector<const Json*>& GetSubDictionaries() {
+ if (dictionaries_.empty()) {
+ for (Value::ConstMemberIterator member = value_->MemberBegin();
+ member != value_->MemberEnd(); ++member) {
+ if (member->value.IsObject()) {
+ dictionaries_.push_back(new Json(new JsonImpl(&member->value)));
+ }
+ }
+ }
+ return dictionaries_;
}
- // The caller does not own the result. The result can be NULL if there's no
- // dictionary for |key|.
- const Json* FindDictionary(const std::string& key) const {
- std::map<std::string, const Json*>::const_iterator it =
- dictionaries_.find(key);
- return it != dictionaries_.end() ? it->second : NULL;
- }
+ bool GetStringValueForKey(const std::string& key, std::string* value) const {
+ assert(value != NULL);
- // Takes ownership of |dictionary|. Should be called only once per |key| and
- // per |dictionary|.
- void AddDictionary(const std::string& key, const Json* dictionary) {
- bool inserted =
- dictionaries_.insert(std::make_pair(key, dictionary)).second;
- // Cannot do work inside of assert(), because the compiler can optimize it
- // away.
- assert(inserted);
- // Avoid unused variable warning when assert() is optimized away.
- (void)inserted;
- }
+ Value::ConstMemberIterator member = value_->FindMember(key.c_str());
+ if (member == NULL || !member->value.IsString()) {
+ return false;
+ }
- const std::vector<std::string>& GetKeys() const {
- return keys_;
+ value->assign(member->value.GetString(),
+ member->value.GetStringLength());
+ return true;
}
private:
- void BuildKeyList() {
- assert(keys_.empty());
- for (Value::ConstMemberIterator it = value_->MemberBegin();
- it != value_->MemberEnd(); ++it) {
- keys_.push_back(it->name.GetString());
- }
+ // Does not take ownership of |value|.
+ explicit JsonImpl(const Value* value)
+ : document_(),
+ value_(value),
+ dictionaries_(),
+ valid_(true) {
+ assert(value_ != NULL);
+ assert(value_->IsObject());
}
// An owned JSON document. Can be NULL if the JSON document is not owned.
- //
- // When a JsonImpl object is constructed using a Document object, then
- // JsonImpl is supposed to take ownership of that object, making sure to
- // delete it in its own destructor. But when a JsonImpl object is constructed
- // using a Value object, then that object is owned by a Member object which is
- // owned by a Document object, and should therefore not be deleted by
- // JsonImpl.
- const scoped_ptr<const Document> document_;
+ const scoped_ptr<Document> document_;
// A JSON document that is not owned. Cannot be NULL. Can point to document_.
const Value* const value_;
- // Owned JSON objects.
- std::map<std::string, const Json*> dictionaries_;
+ // Owned JSON objects of sub-dictionaries.
+ std::vector<const Json*> dictionaries_;
- std::vector<std::string> keys_;
+ // True if the JSON object was parsed successfully.
+ bool valid_;
DISALLOW_COPY_AND_ASSIGN(JsonImpl);
};
-Json::Json() {}
+Json::Json() : impl_() {}
Json::~Json() {}
bool Json::ParseObject(const std::string& json) {
assert(impl_ == NULL);
- scoped_ptr<Document> document(new Document);
- document->Parse<kParseValidateEncodingFlag>(json.c_str());
- bool valid = !document->HasParseError() && document->IsObject();
- if (valid) {
- impl_.reset(new JsonImpl(document.release()));
+ impl_.reset(new JsonImpl(json));
+ if (!impl_->valid()) {
+ impl_.reset();
}
- return valid;
+ return impl_ != NULL;
}
-const std::vector<std::string>& Json::GetKeys() const {
+const std::vector<const Json*>& Json::GetSubDictionaries() const {
assert(impl_ != NULL);
- return impl_->GetKeys();
+ return impl_->GetSubDictionaries();
}
-bool Json::HasStringValueForKey(const std::string& key) const {
+bool Json::GetStringValueForKey(const std::string& key,
+ std::string* value) const {
assert(impl_ != NULL);
-
- // Member is owned by impl_.
- const Value::Member* member = impl_->FindMember(key);
- return member != NULL && member->value.IsString();
+ return impl_->GetStringValueForKey(key, value);
}
-std::string Json::GetStringValueForKey(const std::string& key) const {
- assert(impl_ != NULL);
-
- // Member is owned by impl_.
- const Value::Member* member = impl_->FindMember(key.c_str());
- assert(member != NULL);
- assert(member->value.IsString());
- return std::string(member->value.GetString(),
- member->value.GetStringLength());
-}
-
-bool Json::HasDictionaryValueForKey(const std::string& key) const {
- assert(impl_ != NULL);
-
- // The value returned by FindDictionary() is owned by impl_.
- if (impl_->FindDictionary(key) != NULL) {
- return true;
- }
-
- // Member is owned by impl_.
- const Value::Member* member = impl_->FindMember(key);
- return member != NULL && member->value.IsObject();
-}
-
-const Json& Json::GetDictionaryValueForKey(const std::string& key) const {
- assert(impl_ != NULL);
-
- // Existing_dictionary is owned by impl_.
- const Json* existing_dictionary = impl_->FindDictionary(key);
- if (existing_dictionary != NULL) {
- return *existing_dictionary;
- }
-
- // Member is owned by impl_.
- const Value::Member* member = impl_->FindMember(key);
- assert(member != NULL);
- assert(member->value.IsObject());
-
- // Dictionary is owned by impl_.
- Json* dictionary = new Json;
- dictionary->impl_.reset(new JsonImpl(&member->value));
- impl_->AddDictionary(key, dictionary);
- return *dictionary;
-}
+Json::Json(JsonImpl* impl) : impl_(impl) {}
} // namespace addressinput
} // namespace i18n
diff --git a/cpp/src/util/json.h b/cpp/src/util/json.h
index 1fbf500..1aac803 100644
--- a/cpp/src/util/json.h
+++ b/cpp/src/util/json.h
@@ -39,32 +39,24 @@
// object.
bool ParseObject(const std::string& json);
- // Returns the list of keys in the parsed JSON. The JSON object must be parsed
- // successfully in ParseObject() before invoking this method.
- const std::vector<std::string>& GetKeys() const;
+ // Returns the list of sub dictionaries. The JSON object must be parsed
+ // successfully in ParseObject() before invoking this method. The caller does
+ // not own the result.
+ const std::vector<const Json*>& GetSubDictionaries() const;
- // Returns true if the parsed JSON contains a string value for |key|. The JSON
- // object must be parsed successfully in ParseObject() before invoking this
- // method.
- bool HasStringValueForKey(const std::string& key) const;
-
- // Returns the string value for the |key|. The |key| must be present and its
- // value must be of string type, i.e., HasStringValueForKey(key) must return
- // true before invoking this method.
- std::string GetStringValueForKey(const std::string& key) const;
-
- // Returns true if the parsed JSON contains a dictionary value for |key|. The
- // JSON object must be parsed successfully in ParseObject() before invoking
- // this method.
- bool HasDictionaryValueForKey(const std::string& key) const;
-
- // Returns the dictionary value for the |key|. The |key| must be present and
- // its value must be of the dictionary type, i.e., HasDictionaryValueForKey()
- // must return true before invoking this method.
- const Json& GetDictionaryValueForKey(const std::string& key) const;
+ // Returns true if the parsed JSON contains a string value for |key|. Sets
+ // |value| to the string value of the |key|. The JSON object must be parsed
+ // successfully in ParseObject() before invoking this method. The |value|
+ // parameter should not be NULL.
+ bool GetStringValueForKey(const std::string& key, std::string* value) const;
private:
class JsonImpl;
+ friend class JsonImpl;
+
+ // Constructor to be called by JsonImpl.
+ explicit Json(JsonImpl* impl);
+
scoped_ptr<JsonImpl> impl_;
DISALLOW_COPY_AND_ASSIGN(Json);
diff --git a/cpp/src/util/lru_cache_using_std.h b/cpp/src/util/lru_cache_using_std.h
index 25aced7..6062d28 100644
--- a/cpp/src/util/lru_cache_using_std.h
+++ b/cpp/src/util/lru_cache_using_std.h
@@ -21,8 +21,10 @@
#define I18N_ADDRESSINPUT_UTIL_LRU_CACHE_USING_STD_H_
#include <cassert>
+#include <cstddef>
#include <list>
#include <map>
+#include <utility>
// Class providing fixed-size (by number of records)
// LRU-replacement cache of a function with signature
diff --git a/cpp/src/util/md5.cc b/cpp/src/util/md5.cc
index 4a629d0..ea7561b 100644
--- a/cpp/src/util/md5.cc
+++ b/cpp/src/util/md5.cc
@@ -28,7 +28,9 @@
#include <libaddressinput/util/basictypes.h>
+#include <cstddef>
#include <string>
+#include <string.h>
namespace {
diff --git a/cpp/src/util/md5.h b/cpp/src/util/md5.h
index 8d05301..98bc325 100644
--- a/cpp/src/util/md5.h
+++ b/cpp/src/util/md5.h
@@ -8,6 +8,7 @@
#ifndef I18N_ADDRESSINPUT_UTIL_MD5_H_
#define I18N_ADDRESSINPUT_UTIL_MD5_H_
+#include <cstddef>
#include <string>
namespace i18n {
diff --git a/cpp/src/util/string_util.cc b/cpp/src/util/string_util.cc
index 18d0a87..8396d51 100644
--- a/cpp/src/util/string_util.cc
+++ b/cpp/src/util/string_util.cc
@@ -10,10 +10,9 @@
#include "string_util.h"
-#include <libaddressinput/util/basictypes.h>
-
-#include <algorithm>
#include <cassert>
+#include <cstddef>
+#include <stdint.h>
#include <string>
#include <vector>
diff --git a/cpp/src/validating_storage.cc b/cpp/src/validating_storage.cc
index 7dc231c..a504db4 100644
--- a/cpp/src/validating_storage.cc
+++ b/cpp/src/validating_storage.cc
@@ -52,7 +52,7 @@
std::string* data) {
if (success) {
assert(data != NULL);
- bool is_stale = !ValidatingUtil::UnwrapTimestamp(data, time(NULL));
+ bool is_stale = !ValidatingUtil::UnwrapTimestamp(data, std::time(NULL));
bool is_corrupted = !ValidatingUtil::UnwrapChecksum(data);
success = !is_corrupted && !is_stale;
if (is_corrupted) {
@@ -68,7 +68,7 @@
}
const Storage::Callback& data_ready_;
- scoped_ptr<Storage::Callback> wrapped_data_ready_;
+ const scoped_ptr<const Storage::Callback> wrapped_data_ready_;
DISALLOW_COPY_AND_ASSIGN(Helper);
};
@@ -84,7 +84,7 @@
void ValidatingStorage::Put(const std::string& key, std::string* data) {
assert(data != NULL);
- ValidatingUtil::Wrap(time(NULL), data);
+ ValidatingUtil::Wrap(std::time(NULL), data);
wrapped_storage_->Put(key, data);
}
diff --git a/cpp/src/validating_storage.h b/cpp/src/validating_storage.h
index 11e74cd..1cf3f95 100644
--- a/cpp/src/validating_storage.h
+++ b/cpp/src/validating_storage.h
@@ -32,8 +32,8 @@
// scoped_ptr<Storage> file_storage = ...;
// ValidatingStorage storage(file_storage));
// storage.Put("key", new std::string("data"));
-// scoped_ptr<ValidatingStorage::Callback> data_ready(BuildCallback(
-// this, &MyClass::OnDataReady));
+// const scoped_ptr<const ValidatingStorage::Callback> data_ready(
+// BuildCallback(this, &MyClass::OnDataReady));
// storage.Get("key", *data_ready);
class ValidatingStorage : public Storage {
public:
diff --git a/cpp/src/validating_util.cc b/cpp/src/validating_util.cc
index 6b52e8b..9356689 100644
--- a/cpp/src/validating_util.cc
+++ b/cpp/src/validating_util.cc
@@ -84,7 +84,11 @@
void ValidatingUtil::Wrap(time_t timestamp, std::string* data) {
assert(data != NULL);
char timestamp_string[2 + 3 * sizeof timestamp];
- snprintf(timestamp_string, sizeof timestamp_string, "%ld", timestamp);
+ int size =
+ std::sprintf(timestamp_string, "%ld", static_cast<long>(timestamp));
+ assert(size > 0);
+ assert(size < sizeof timestamp_string);
+ (void)size;
std::string header;
header.append(kTimestampPrefix, kTimestampPrefixLength);
@@ -108,7 +112,7 @@
std::string timestamp_string;
if (!UnwrapHeader(
- kTimestampPrefix, kTimestampPrefixLength, data, ×tamp_string)) {
+ kTimestampPrefix, kTimestampPrefixLength, data, ×tamp_string)) {
return false;
}
diff --git a/cpp/src/validating_util.h b/cpp/src/validating_util.h
index 1357651..20d541b 100644
--- a/cpp/src/validating_util.h
+++ b/cpp/src/validating_util.h
@@ -19,6 +19,8 @@
#ifndef I18N_ADDRESSINPUT_VALIDATING_UTIL_H_
#define I18N_ADDRESSINPUT_VALIDATING_UTIL_H_
+#include <libaddressinput/util/basictypes.h>
+
#include <ctime>
#include <string>
@@ -47,6 +49,9 @@
// Strips out the checksum from |data|. Returns |true| if the checksum is
// present, formatted correctly, and valid for this data.
static bool UnwrapChecksum(std::string* data);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ValidatingUtil);
};
} // namespace addressinput
diff --git a/cpp/src/validation_task.cc b/cpp/src/validation_task.cc
index e5beb1a..1e7911a 100644
--- a/cpp/src/validation_task.cc
+++ b/cpp/src/validation_task.cc
@@ -19,6 +19,7 @@
#include <libaddressinput/address_metadata.h>
#include <libaddressinput/address_problem.h>
#include <libaddressinput/address_validator.h>
+#include <libaddressinput/callback.h>
#include <libaddressinput/supplier.h>
#include <libaddressinput/util/basictypes.h>
@@ -29,13 +30,13 @@
#include <utility>
#include <vector>
+#include <re2/re2.h>
+
#include "lookup_key.h"
#include "post_box_matchers.h"
#include "rule.h"
#include "util/re2ptr.h"
-#include <re2/re2.h>
-
namespace i18n {
namespace addressinput {
@@ -109,6 +110,7 @@
SORTING_CODE,
POSTAL_CODE,
STREET_ADDRESS,
+ ORGANIZATION,
RECIPIENT
};
@@ -131,7 +133,8 @@
DEPENDENT_LOCALITY,
SORTING_CODE,
POSTAL_CODE,
- STREET_ADDRESS,
+ STREET_ADDRESS
+ // ORGANIZATION is never required.
// RECIPIENT is handled separately.
};
@@ -255,9 +258,10 @@
bool ValidationTask::ShouldReport(AddressField field,
AddressProblem problem) const {
return filter_ == NULL || filter_->empty() ||
- std::find(filter_->begin(), filter_->end(),
+ std::find(filter_->begin(),
+ filter_->end(),
FieldProblemMap::value_type(field, problem)) !=
- filter_->end();
+ filter_->end();
}
} // namespace addressinput
diff --git a/cpp/src/validation_task.h b/cpp/src/validation_task.h
index f0895f3..1658678 100644
--- a/cpp/src/validation_task.h
+++ b/cpp/src/validation_task.h
@@ -22,11 +22,12 @@
#include <libaddressinput/util/basictypes.h>
#include <libaddressinput/util/scoped_ptr.h>
+#include <string>
+
namespace i18n {
namespace addressinput {
class LookupKey;
-class Rule;
struct AddressData;
// A ValidationTask object encapsulates the information necessary to perform
@@ -64,16 +65,14 @@
void CheckMissingRequiredField(const std::string& region_code) const;
// Checks the hierarchical fields for UNKNOWN_VALUE problems.
- void CheckUnknownValue(
- const Supplier::RuleHierarchy& hierarchy) const;
+ void CheckUnknownValue(const Supplier::RuleHierarchy& hierarchy) const;
// Checks the POSTAL_CODE field for problems.
void CheckPostalCodeFormatAndValue(
const Supplier::RuleHierarchy& hierarchy) const;
// Checks the STREET_ADDRESS field for USES_P_O_BOX problems.
- void CheckUsesPoBox(
- const Supplier::RuleHierarchy& hierarchy) const;
+ void CheckUsesPoBox(const Supplier::RuleHierarchy& hierarchy) const;
// Writes (|field|,|problem|) to |problems_|.
void ReportProblem(AddressField field, AddressProblem problem) const;
diff --git a/cpp/test/address_data_test.cc b/cpp/test/address_data_test.cc
index 8ba0f4b..46491c9 100644
--- a/cpp/test/address_data_test.cc
+++ b/cpp/test/address_data_test.cc
@@ -32,6 +32,7 @@
using i18n::addressinput::SORTING_CODE;
using i18n::addressinput::POSTAL_CODE;
using i18n::addressinput::STREET_ADDRESS;
+using i18n::addressinput::ORGANIZATION;
using i18n::addressinput::RECIPIENT;
TEST(AddressDataTest, GetFieldValue) {
@@ -42,6 +43,7 @@
address.dependent_locality = "ddd";
address.sorting_code = "xxx";
address.postal_code = "zzz";
+ address.organization = "ooo";
address.recipient = "nnn";
EXPECT_EQ(address.region_code,
@@ -56,6 +58,8 @@
address.GetFieldValue(SORTING_CODE));
EXPECT_EQ(address.postal_code,
address.GetFieldValue(POSTAL_CODE));
+ EXPECT_EQ(address.organization,
+ address.GetFieldValue(ORGANIZATION));
EXPECT_EQ(address.recipient,
address.GetFieldValue(RECIPIENT));
}
@@ -78,6 +82,7 @@
EXPECT_TRUE(address.IsFieldEmpty(SORTING_CODE));
EXPECT_TRUE(address.IsFieldEmpty(POSTAL_CODE));
EXPECT_TRUE(address.IsFieldEmpty(STREET_ADDRESS));
+ EXPECT_TRUE(address.IsFieldEmpty(ORGANIZATION));
EXPECT_TRUE(address.IsFieldEmpty(RECIPIENT));
address.region_code = "rrr";
@@ -87,6 +92,7 @@
address.sorting_code = "xxx";
address.postal_code = "zzz";
address.address_line.push_back("aaa");
+ address.organization = "ooo";
address.recipient = "nnn";
EXPECT_FALSE(address.IsFieldEmpty(COUNTRY));
@@ -96,6 +102,7 @@
EXPECT_FALSE(address.IsFieldEmpty(SORTING_CODE));
EXPECT_FALSE(address.IsFieldEmpty(POSTAL_CODE));
EXPECT_FALSE(address.IsFieldEmpty(STREET_ADDRESS));
+ EXPECT_FALSE(address.IsFieldEmpty(ORGANIZATION));
EXPECT_FALSE(address.IsFieldEmpty(RECIPIENT));
}
@@ -149,6 +156,7 @@
address.dependent_locality = "D";
address.sorting_code = "X";
address.language_code = "zh-Hant";
+ address.organization = "O";
oss << address;
EXPECT_EQ("region_code: \"R\"\n"
"administrative_area: \"S\"\n"
@@ -159,6 +167,7 @@
"address_line: \"Line 1\"\n"
"address_line: \"Line 2\"\n"
"language_code: \"zh-Hant\"\n"
+ "organization: \"O\"\n"
"recipient: \"N\"\n", oss.str());
}
@@ -173,6 +182,7 @@
address.locality = "C";
address.dependent_locality = "D";
address.sorting_code = "X";
+ address.organization = "O";
address.language_code = "zh-Hant";
AddressData clone = address;
diff --git a/cpp/test/address_field_util_test.cc b/cpp/test/address_field_util_test.cc
index 4a1d7a2..0cde367 100644
--- a/cpp/test/address_field_util_test.cc
+++ b/cpp/test/address_field_util_test.cc
@@ -26,20 +26,22 @@
namespace {
using i18n::addressinput::AddressField;
-using i18n::addressinput::COUNTRY;
-using i18n::addressinput::LOCALITY;
using i18n::addressinput::FormatElement;
using i18n::addressinput::ParseFormatRule;
+
+using i18n::addressinput::COUNTRY;
+using i18n::addressinput::LOCALITY;
using i18n::addressinput::POSTAL_CODE;
-using i18n::addressinput::RECIPIENT;
using i18n::addressinput::STREET_ADDRESS;
+using i18n::addressinput::ORGANIZATION;
+using i18n::addressinput::RECIPIENT;
TEST(AddressFieldUtilTest, FormatParseNewline) {
std::vector<FormatElement> actual;
- ParseFormatRule("%O%n%N%n%A%nAX-%Z %C%nÅLAND", &actual);
+ ParseFormatRule("%O%n%N%n%A%nAX-%Z %C%n\xC3\x85LAND", &actual); /* "ÅLAND" */
std::vector<FormatElement> expected;
- // Organization is skipped.
+ expected.push_back(FormatElement(ORGANIZATION));
expected.push_back(FormatElement());
expected.push_back(FormatElement(RECIPIENT));
expected.push_back(FormatElement());
@@ -50,7 +52,7 @@
expected.push_back(FormatElement(" "));
expected.push_back(FormatElement(LOCALITY));
expected.push_back(FormatElement());
- expected.push_back(FormatElement("ÅLAND"));
+ expected.push_back(FormatElement("\xC3\x85LAND")); /* "ÅLAND" */
EXPECT_EQ(expected, actual);
}
diff --git a/cpp/test/address_formatter_test.cc b/cpp/test/address_formatter_test.cc
index ca94a32..c656ec8 100644
--- a/cpp/test/address_formatter_test.cc
+++ b/cpp/test/address_formatter_test.cc
@@ -28,6 +28,13 @@
using i18n::addressinput::GetFormattedNationalAddressLine;
using i18n::addressinput::GetStreetAddressLinesAsSingleLine;
+TEST(AddressFormatterTest, GetStreetAddressLinesAsSingleLine_EmptyAddress) {
+ AddressData address;
+ std::string result;
+ GetStreetAddressLinesAsSingleLine(address, &result);
+ EXPECT_TRUE(result.empty());
+}
+
TEST(AddressFormatterTest, GetStreetAddressLinesAsSingleLine_1Line) {
AddressData address;
address.region_code = "US"; // Not used.
@@ -198,4 +205,163 @@
EXPECT_EQ(expected, lines);
}
+TEST(AddressFormatterTest, GetFormattedNationalAddress_InlineStreetAddress) {
+ AddressData address;
+ address.region_code = "CI";
+ address.address_line.push_back("32 Boulevard Carde");
+ address.locality = "Abidjan";
+ address.sorting_code = "64";
+
+ std::vector<std::string> expected;
+ expected.push_back("64 32 Boulevard Carde Abidjan 64");
+
+ std::vector<std::string> lines;
+ GetFormattedNationalAddress(address, &lines);
+ EXPECT_EQ(expected, lines);
+}
+
+TEST(AddressFormatterTest,
+ GetFormattedNationalAddressMissingFields_LiteralsAroundField) {
+ AddressData address;
+ address.region_code = "CH";
+ std::vector<std::string> expected;
+ std::vector<std::string> lines;
+ GetFormattedNationalAddress(address, &lines);
+ EXPECT_EQ(expected, lines);
+
+ address.locality = "Zurich";
+ expected.push_back("Zurich");
+ GetFormattedNationalAddress(address, &lines);
+ EXPECT_EQ(expected, lines);
+
+ address.postal_code = "8001";
+ expected.back().assign("CH-8001 Zurich");
+ GetFormattedNationalAddress(address, &lines);
+ EXPECT_EQ(expected, lines);
+
+ address.locality.clear();
+ expected.back().assign("CH-8001");
+ GetFormattedNationalAddress(address, &lines);
+ EXPECT_EQ(expected, lines);
+}
+
+TEST(AddressFormatterTest,
+ GetFormattedNationalAddressMissingFields_LiteralsBetweenFields) {
+ AddressData address;
+ address.region_code = "US";
+ std::vector<std::string> expected;
+ std::vector<std::string> lines;
+ GetFormattedNationalAddress(address, &lines);
+ EXPECT_EQ(expected, lines);
+
+ address.administrative_area = "CA";
+ expected.push_back("CA");
+ GetFormattedNationalAddress(address, &lines);
+ EXPECT_EQ(expected, lines);
+
+ address.locality = "Los Angeles";
+ expected.back().assign("Los Angeles, CA");
+ GetFormattedNationalAddress(address, &lines);
+ EXPECT_EQ(expected, lines);
+
+ address.postal_code = "90291";
+ expected.back().assign("Los Angeles, CA 90291");
+ GetFormattedNationalAddress(address, &lines);
+ EXPECT_EQ(expected, lines);
+
+ address.administrative_area.clear();
+ expected.back().assign("Los Angeles 90291");
+ GetFormattedNationalAddress(address, &lines);
+ EXPECT_EQ(expected, lines);
+
+ address.locality.clear();
+ address.administrative_area = "CA";
+ expected.back().assign("CA 90291");
+ GetFormattedNationalAddress(address, &lines);
+ EXPECT_EQ(expected, lines);
+}
+
+TEST(AddressFormatterTest,
+ GetFormattedNationalAddressMissingFields_LiteralOnSeparateLine) {
+ AddressData address;
+ address.region_code = "AX";
+ std::vector<std::string> expected;
+ expected.push_back("\xC3\x85LAND"); /* ÅLAND */
+ std::vector<std::string> lines;
+ GetFormattedNationalAddress(address, &lines);
+ EXPECT_EQ(expected, lines);
+
+ address.locality = "City";
+ expected.insert(expected.begin(), "City");
+ GetFormattedNationalAddress(address, &lines);
+ EXPECT_EQ(expected, lines);
+
+ address.postal_code = "123";
+ expected.front().assign("AX-123 City");
+ GetFormattedNationalAddress(address, &lines);
+ EXPECT_EQ(expected, lines);
+}
+
+TEST(AddressFormatterTest,
+ GetFormattedNationalAddressMissingFields_LiteralBeforeField) {
+ AddressData address;
+ address.region_code = "JP";
+ address.language_code = "ja";
+ std::vector<std::string> expected;
+ std::vector<std::string> lines;
+ GetFormattedNationalAddress(address, &lines);
+ EXPECT_EQ(expected, lines);
+
+ address.postal_code = "123";
+ expected.push_back("\xE3\x80\x92" "123"); /* 〒123 */
+ GetFormattedNationalAddress(address, &lines);
+ EXPECT_EQ(expected, lines);
+
+ address.administrative_area = "Prefecture";
+ expected.push_back("Prefecture");
+ GetFormattedNationalAddress(address, &lines);
+ EXPECT_EQ(expected, lines);
+
+ address.postal_code.clear();
+ expected.erase(expected.begin());
+ GetFormattedNationalAddress(address, &lines);
+ EXPECT_EQ(expected, lines);
+}
+
+TEST(AddressFormatterTest,
+ GetFormattedNationalAddressMissingFields_DuplicateField) {
+ AddressData address;
+ address.region_code = "CI";
+ std::vector<std::string> expected;
+ std::vector<std::string> lines;
+ GetFormattedNationalAddress(address, &lines);
+ EXPECT_EQ(expected, lines);
+
+ address.sorting_code = "123";
+ expected.push_back("123 123");
+ GetFormattedNationalAddress(address, &lines);
+ EXPECT_EQ(expected, lines);
+
+ address.address_line.push_back("456 Main St");
+ expected.back().assign("123 456 Main St 123");
+ GetFormattedNationalAddress(address, &lines);
+ EXPECT_EQ(expected, lines);
+
+ address.locality = "Yamoussoukro";
+ expected.back().assign("123 456 Main St Yamoussoukro 123");
+ GetFormattedNationalAddress(address, &lines);
+ EXPECT_EQ(expected, lines);
+
+ address.sorting_code.erase();
+ expected.back().assign("456 Main St Yamoussoukro");
+ GetFormattedNationalAddress(address, &lines);
+ EXPECT_EQ(expected, lines);
+
+ address.address_line.clear();
+ expected.back().assign("Yamoussoukro");
+ GetFormattedNationalAddress(address, &lines);
+ EXPECT_EQ(expected, lines);
+}
+
+
} // namespace
diff --git a/cpp/test/address_input_helper_test.cc b/cpp/test/address_input_helper_test.cc
index 84a2286..4014c91 100644
--- a/cpp/test/address_input_helper_test.cc
+++ b/cpp/test/address_input_helper_test.cc
@@ -26,8 +26,8 @@
#include <gtest/gtest.h>
-#include "fake_downloader.h"
-#include "mock_downloader.h"
+#include "mock_source.h"
+#include "testdata_source.h"
namespace {
@@ -35,24 +35,20 @@
using i18n::addressinput::AddressInputHelper;
using i18n::addressinput::BuildCallback;
using i18n::addressinput::Callback;
-using i18n::addressinput::FakeDownloader;
-using i18n::addressinput::MockDownloader;
+using i18n::addressinput::MockSource;
using i18n::addressinput::NullStorage;
using i18n::addressinput::PreloadSupplier;
using i18n::addressinput::scoped_ptr;
+using i18n::addressinput::TestdataSource;
class AddressInputHelperTest : public testing::Test {
protected:
AddressInputHelperTest()
// Our PreloadSupplier loads all data for a country at a time.
- : supplier_(FakeDownloader::kFakeAggregateDataUrl,
- new FakeDownloader,
- new NullStorage),
+ : supplier_(new TestdataSource(true), new NullStorage),
address_input_helper_(&supplier_),
loaded_(BuildCallback(this, &AddressInputHelperTest::Loaded)) {}
- ~AddressInputHelperTest() {}
-
// Helper method to test FillAddress that ensures the PreloadSupplier has the
// necessary data preloaded.
void FillAddress(AddressData* address) {
@@ -65,9 +61,7 @@
private:
// Used to preload data that we need.
- void Loaded(bool success, const std::string&, int) {
- ASSERT_TRUE(success);
- }
+ void Loaded(bool success, const std::string&, int) { ASSERT_TRUE(success); }
PreloadSupplier supplier_;
const AddressInputHelper address_input_helper_;
@@ -194,8 +188,8 @@
address.postal_code = "527-111";
AddressData expected = address;
- /* The province, Jeonnam - 전라남도 - is known, but we have several locality
- * matches so none of them are populated. */
+ /* The province, Jeonnam - 전라남도 - is known, but we have several locality
+ * matches so none of them are populated. */
expected.administrative_area =
"\xEC\xA0\x84\xEB\x9D\xBC\xEB\x82\xA8\xEB\x8F\x84";
FillAddress(&address);
@@ -247,16 +241,12 @@
class AddressInputHelperMockDataTest : public testing::Test {
protected:
AddressInputHelperMockDataTest()
- : downloader_(new MockDownloader),
+ : source_(new MockSource),
// Our PreloadSupplier loads all data for a country at a time.
- supplier_(MockDownloader::kMockDataUrl,
- downloader_,
- new NullStorage),
+ supplier_(source_, new NullStorage),
address_input_helper_(&supplier_),
loaded_(BuildCallback(this, &AddressInputHelperMockDataTest::Loaded)) {}
- ~AddressInputHelperMockDataTest() {}
-
// Helper method to test FillAddress that ensures the PreloadSupplier has the
// necessary data preloaded.
void FillAddress(AddressData* address) {
@@ -267,13 +257,11 @@
address_input_helper_.FillAddress(address);
}
- MockDownloader* const downloader_;
+ MockSource* const source_;
private:
- // Our mock downloader we assume will always succeed.
- void Loaded(bool success, const std::string&, int) {
- ASSERT_TRUE(success);
- }
+ // Our mock source we assume will always succeed.
+ void Loaded(bool success, const std::string&, int) { ASSERT_TRUE(success); }
PreloadSupplier supplier_;
const AddressInputHelper address_input_helper_;
@@ -285,7 +273,7 @@
PostalCodeSharedAcrossDifferentHierarchies) {
// Note that this data is in the format of data that would be returned from
// the aggregate server.
- downloader_->data_.insert(std::make_pair(
+ source_->data_.insert(std::make_pair(
// We use KR since we need a country where we format all fields down to
// dependent locality, or the hierarchy won't be loaded.
"data/KR",
@@ -319,14 +307,14 @@
// Create data where one state matches the ZIP code, but the other doesn't:
// within the state which does, multiple cities and sub-cities match. The only
// thing we can be certain of is therefore the state.
- downloader_->data_.insert(std::make_pair(
+ source_->data_.insert(std::make_pair(
// We use KR since we need a country where we format all fields down to
// dependent locality, or the hierarchy won't be loaded.
"data/KR",
"{\"data/KR\": "
// The top-level ZIP expression must be present for sub-key matches to be
// evaluated.
- "{\"id\":\"data/KR\", \"sub_keys\":\"A~B\", \"zip\":\"\\\\d\{5}\"}, "
+ "{\"id\":\"data/KR\", \"sub_keys\":\"A~B\", \"zip\":\"\\\\d{5}\"}, "
"\"data/KR/A\": "
"{\"id\":\"data/KR/A\", \"sub_keys\":\"A1~A2\"}, "
"\"data/KR/A/A1\": "
diff --git a/cpp/test/address_metadata_test.cc b/cpp/test/address_metadata_test.cc
index e1959cd..b60619b 100644
--- a/cpp/test/address_metadata_test.cc
+++ b/cpp/test/address_metadata_test.cc
@@ -20,13 +20,13 @@
namespace {
+using i18n::addressinput::IsFieldRequired;
+using i18n::addressinput::IsFieldUsed;
+
using i18n::addressinput::COUNTRY;
using i18n::addressinput::ADMIN_AREA;
using i18n::addressinput::DEPENDENT_LOCALITY;
-using i18n::addressinput::IsFieldRequired;
-using i18n::addressinput::IsFieldUsed;
-
TEST(AddressMetadataTest, IsFieldRequiredCountry) {
EXPECT_TRUE(IsFieldRequired(COUNTRY, "US"));
EXPECT_TRUE(IsFieldRequired(COUNTRY, "CH"));
diff --git a/cpp/test/address_normalizer_test.cc b/cpp/test/address_normalizer_test.cc
index 6f2d9f4..3a7acf2 100644
--- a/cpp/test/address_normalizer_test.cc
+++ b/cpp/test/address_normalizer_test.cc
@@ -21,31 +21,29 @@
#include <libaddressinput/util/basictypes.h>
#include <libaddressinput/util/scoped_ptr.h>
-#include "fake_downloader.h"
+#include <string>
#include <gtest/gtest.h>
+#include "testdata_source.h"
+
namespace {
using i18n::addressinput::AddressData;
using i18n::addressinput::AddressNormalizer;
using i18n::addressinput::BuildCallback;
-using i18n::addressinput::FakeDownloader;
using i18n::addressinput::NullStorage;
using i18n::addressinput::PreloadSupplier;
using i18n::addressinput::scoped_ptr;
+using i18n::addressinput::TestdataSource;
class AddressNormalizerTest : public testing::Test {
protected:
AddressNormalizerTest()
- : supplier_(FakeDownloader::kFakeAggregateDataUrl,
- new FakeDownloader,
- new NullStorage),
+ : supplier_(new TestdataSource(true), new NullStorage),
loaded_(BuildCallback(this, &AddressNormalizerTest::OnLoaded)),
normalizer_(&supplier_) {}
- virtual ~AddressNormalizerTest() {}
-
PreloadSupplier supplier_;
const scoped_ptr<const PreloadSupplier::Callback> loaded_;
const AddressNormalizer normalizer_;
@@ -86,12 +84,13 @@
AddressData address;
address.language_code = "ko-KR";
address.region_code = "KR";
- address.administrative_area = "강원";
+ address.administrative_area = "\xEA\xB0\x95\xEC\x9B\x90"; /* "강원" */
normalizer_.Normalize(&address);
- EXPECT_EQ("강원도", address.administrative_area);
+ EXPECT_EQ(
+ "\xEA\xB0\x95\xEC\x9B\x90\xEB\x8F\x84", /* "강원도" */
+ address.administrative_area);
}
-
TEST_F(AddressNormalizerTest, DontSwitchLatinScriptForUnknownLanguage) {
supplier_.LoadRules("KR", *loaded_);
AddressData address;
@@ -105,9 +104,11 @@
supplier_.LoadRules("KR", *loaded_);
AddressData address;
address.region_code = "KR";
- address.administrative_area = "강원";
+ address.administrative_area = "\xEA\xB0\x95\xEC\x9B\x90"; /* "강원" */
normalizer_.Normalize(&address);
- EXPECT_EQ("강원도", address.administrative_area);
+ EXPECT_EQ(
+ "\xEA\xB0\x95\xEC\x9B\x90\xEB\x8F\x84", /* "강원도" */
+ address.administrative_area);
}
} // namespace
diff --git a/cpp/test/address_ui_test.cc b/cpp/test/address_ui_test.cc
index c23d205..d2e512f 100644
--- a/cpp/test/address_ui_test.cc
+++ b/cpp/test/address_ui_test.cc
@@ -17,6 +17,7 @@
#include <libaddressinput/address_field.h>
#include <libaddressinput/address_ui_component.h>
#include <libaddressinput/localization.h>
+#include <libaddressinput/util/basictypes.h>
#include <set>
#include <string>
@@ -26,16 +27,18 @@
namespace {
-using i18n::addressinput::ADMIN_AREA;
using i18n::addressinput::AddressField;
using i18n::addressinput::AddressUiComponent;
using i18n::addressinput::BuildComponents;
-using i18n::addressinput::COUNTRY;
using i18n::addressinput::GetRegionCodes;
using i18n::addressinput::Localization;
+
+using i18n::addressinput::COUNTRY;
+using i18n::addressinput::ADMIN_AREA;
using i18n::addressinput::POSTAL_CODE;
-using i18n::addressinput::RECIPIENT;
using i18n::addressinput::STREET_ADDRESS;
+using i18n::addressinput::ORGANIZATION;
+using i18n::addressinput::RECIPIENT;
static const char kUiLanguageTag[] = "en";
@@ -70,8 +73,12 @@
// Tests for address UI functions.
class AddressUiTest : public testing::TestWithParam<std::string> {
protected:
+ AddressUiTest() {}
Localization localization_;
std::string best_address_language_tag_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(AddressUiTest);
};
// Verifies that a region code consists of two characters, for example "TW".
@@ -142,8 +149,12 @@
class BestAddressLanguageTagTest
: public testing::TestWithParam<LanguageTestCase> {
protected:
+ BestAddressLanguageTagTest() {}
Localization localization_;
std::string best_address_language_tag_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BestAddressLanguageTagTest);
};
std::string GetterStub(int) { return std::string(); }
@@ -210,12 +221,12 @@
LanguageTestCase("MO", "en", "zh-Latn", RECIPIENT),
// Switzerland supports de, fr, and it.
- LanguageTestCase("CH", "de", "de", RECIPIENT),
- LanguageTestCase("CH", "de-DE", "de", RECIPIENT),
- LanguageTestCase("CH", "de-Latn-DE", "de", RECIPIENT),
- LanguageTestCase("CH", "fr", "fr", RECIPIENT),
- LanguageTestCase("CH", "it", "it", RECIPIENT),
- LanguageTestCase("CH", "en", "de", RECIPIENT),
+ LanguageTestCase("CH", "de", "de", ORGANIZATION),
+ LanguageTestCase("CH", "de-DE", "de", ORGANIZATION),
+ LanguageTestCase("CH", "de-Latn-DE", "de", ORGANIZATION),
+ LanguageTestCase("CH", "fr", "fr", ORGANIZATION),
+ LanguageTestCase("CH", "it", "it", ORGANIZATION),
+ LanguageTestCase("CH", "en", "de", ORGANIZATION),
// Antarctica does not have language information.
LanguageTestCase("AQ", "en", "en", RECIPIENT),
diff --git a/cpp/test/address_validator_test.cc b/cpp/test/address_validator_test.cc
index 79195e3..3177b01 100644
--- a/cpp/test/address_validator_test.cc
+++ b/cpp/test/address_validator_test.cc
@@ -15,6 +15,7 @@
#include <libaddressinput/address_validator.h>
#include <libaddressinput/address_data.h>
+#include <libaddressinput/address_field.h>
#include <libaddressinput/address_problem.h>
#include <libaddressinput/callback.h>
#include <libaddressinput/null_storage.h>
@@ -23,28 +24,28 @@
#include <libaddressinput/util/basictypes.h>
#include <libaddressinput/util/scoped_ptr.h>
+#include <string>
#include <utility>
#include <gtest/gtest.h>
-#include "fake_downloader.h"
+#include "testdata_source.h"
namespace {
using i18n::addressinput::AddressData;
using i18n::addressinput::AddressValidator;
using i18n::addressinput::BuildCallback;
-using i18n::addressinput::FakeDownloader;
using i18n::addressinput::FieldProblemMap;
using i18n::addressinput::NullStorage;
using i18n::addressinput::OndemandSupplier;
using i18n::addressinput::PreloadSupplier;
using i18n::addressinput::scoped_ptr;
+using i18n::addressinput::TestdataSource;
using i18n::addressinput::COUNTRY;
using i18n::addressinput::ADMIN_AREA;
using i18n::addressinput::LOCALITY;
-using i18n::addressinput::DEPENDENT_LOCALITY;
using i18n::addressinput::POSTAL_CODE;
using i18n::addressinput::STREET_ADDRESS;
@@ -69,8 +70,6 @@
public:
static ValidatorWrapper* Build() { return new OndemandValidatorWrapper; }
- virtual ~OndemandValidatorWrapper() {}
-
virtual void Validate(const AddressData& address,
bool allow_postal,
bool require_name,
@@ -88,9 +87,7 @@
private:
OndemandValidatorWrapper()
- : supplier_(FakeDownloader::kFakeDataUrl,
- new FakeDownloader,
- new NullStorage),
+ : supplier_(new TestdataSource(false), new NullStorage),
validator_(&supplier_) {}
OndemandSupplier supplier_;
@@ -102,8 +99,6 @@
public:
static ValidatorWrapper* Build() { return new PreloadValidatorWrapper; }
- virtual ~PreloadValidatorWrapper() {}
-
virtual void Validate(const AddressData& address,
bool allow_postal,
bool require_name,
@@ -125,15 +120,11 @@
private:
PreloadValidatorWrapper()
- : supplier_(FakeDownloader::kFakeAggregateDataUrl,
- new FakeDownloader,
- new NullStorage),
+ : supplier_(new TestdataSource(true), new NullStorage),
validator_(&supplier_),
loaded_(BuildCallback(this, &PreloadValidatorWrapper::Loaded)) {}
- void Loaded(bool success, const std::string&, int) {
- ASSERT_TRUE(success);
- }
+ void Loaded(bool success, const std::string&, int) { ASSERT_TRUE(success); }
PreloadSupplier supplier_;
const AddressValidator validator_;
@@ -155,8 +146,6 @@
validator_wrapper_((*GetParam())()),
validated_(BuildCallback(this, &AddressValidatorTest::Validated)) {}
- virtual ~AddressValidatorTest() {}
-
void Validate() {
validator_wrapper_->Validate(
address_,
diff --git a/cpp/test/fake_downloader.cc b/cpp/test/fake_downloader.cc
deleted file mode 100644
index 0f3f8f1..0000000
--- a/cpp/test/fake_downloader.cc
+++ /dev/null
@@ -1,178 +0,0 @@
-// Copyright (C) 2013 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 "fake_downloader.h"
-
-#include <cassert>
-#include <fstream>
-#include <map>
-#include <string>
-#include <utility>
-
-#include "lookup_key_util.h"
-
-namespace i18n {
-namespace addressinput {
-
-// static
-const char FakeDownloader::kFakeDataUrl[] = "test:///plain/";
-
-// static
-const char FakeDownloader::kFakeAggregateDataUrl[] = "test:///aggregate/";
-
-namespace {
-
-// The name of the test data file.
-const char kDataFileName[] = TEST_DATA_DIR "/countryinfo.txt";
-
-// The number of characters in the fake data URL prefix.
-const size_t kFakeDataUrlLength = sizeof FakeDownloader::kFakeDataUrl - 1;
-
-// The number of characters in the fake aggregate data URL prefix.
-const size_t kFakeAggregateDataUrlLength =
- sizeof FakeDownloader::kFakeAggregateDataUrl - 1;
-
-// Each data key begins with this string. Example of a data key:
-// data/CH/AG
-const char kDataKeyPrefix[] = "data/";
-
-// The number of characters in the data key prefix.
-const size_t kDataKeyPrefixLength = sizeof kDataKeyPrefix - 1;
-
-// The number of characters in a CLDR region code, e.g. 'CH'.
-const size_t kCldrRegionCodeLength = 2;
-
-// The number of characters in an aggregate data key, e.g. 'data/CH'.
-const size_t kAggregateDataKeyLength =
- kDataKeyPrefixLength + kCldrRegionCodeLength;
-
-const LookupKeyUtil& GetLookupKeyUtil() {
- static const LookupKeyUtil kLookupKeyUtil(FakeDownloader::kFakeDataUrl);
- return kLookupKeyUtil;
-}
-
-const LookupKeyUtil& GetAggregateLookupKeyUtil() {
- static const LookupKeyUtil kLookupKeyUtil(
- FakeDownloader::kFakeAggregateDataUrl);
- return kLookupKeyUtil;
-}
-
-std::map<std::string, std::string> InitData() {
- std::map<std::string, std::string> data;
- std::ifstream file(kDataFileName);
- assert(file.is_open());
-
- std::string line;
- while (file.good()) {
- // Example line from countryinfo.txt:
- // data/CH/AG={"name": "Aargau"}
- std::getline(file, line);
-
- std::string::size_type divider = line.find('=');
- if (divider != std::string::npos) {
- // Example key:
- // data/CH/AG
- const std::string& key = line.substr(0, divider);
-
- // Example value:
- // {"name": "Aargau"}
- const std::string& value = line.substr(divider + 1);
-
- // For example, map 'test:///plain/data/CH/AG' to '{"name": "Aargau"}'.
- data.insert(std::make_pair(GetLookupKeyUtil().GetUrlForKey(key), value));
-
- // Aggregate keys that begin with 'data/'. We don't aggregate keys that
- // begin with 'example/' because example data is not used anywhere.
- if (key.compare(0,
- kDataKeyPrefixLength,
- kDataKeyPrefix,
- kDataKeyPrefixLength) == 0) {
- // Example aggregate URL:
- // test:///aggregate/data/CH
- const std::string& aggregate_url = GetAggregateLookupKeyUtil()
- .GetUrlForKey(key.substr(0, kAggregateDataKeyLength));
-
- std::map<std::string, std::string>::iterator aggregate_data_it =
- data.find(aggregate_url);
- if (aggregate_data_it != data.end()) {
- // Append more data to the aggregate string, for example:
- // , "data/CH/AG": {"name": "Aargau"}
- aggregate_data_it->second.append(", \"" + key + "\": " + value);
- } else {
- // Begin a new aggregate string, for example:
- // {"data/CH/AG": {"name": "Aargau"}
- data.insert(
- std::make_pair(aggregate_url, "{\"" + key + "\": " + value));
- }
- }
- }
- }
- file.close();
-
- // Make the aggregate data strings valid. For example, this incomplete JSON
- // data:
- // {"data/CH/AG": {"name": "Aargau"},
- // "data/CH": {"name": "SWITZERLAND"}
- //
- // becomes valid JSON data like so:
- //
- // {"data/CH/AG": {"name": "Aargau"},
- // "data/CH": {"name": "SWITZERLAND"}}
- for (std::map<std::string, std::string>::iterator data_it = data.begin();
- data_it != data.end(); ++data_it) {
- if (data_it->first.compare(0,
- kFakeAggregateDataUrlLength,
- FakeDownloader::kFakeAggregateDataUrl,
- kFakeAggregateDataUrlLength) == 0) {
- data_it->second.append("}");
- }
- }
-
- return data;
-}
-
-const std::map<std::string, std::string>& GetData() {
- static const std::map<std::string, std::string> kData(InitData());
- return kData;
-}
-
-} // namespace
-
-FakeDownloader::FakeDownloader() {}
-
-FakeDownloader::~FakeDownloader() {}
-
-void FakeDownloader::Download(const std::string& url,
- const Callback& downloaded) const {
- std::map<std::string, std::string>::const_iterator data_it =
- GetData().find(url);
- bool success = data_it != GetData().end();
- std::string* data = NULL;
- if (success) {
- data = new std::string(data_it->second);
- } else if (GetLookupKeyUtil().IsValidationDataUrl(url) ||
- GetAggregateLookupKeyUtil().IsValidationDataUrl(url)) {
- // URLs that start with "https://i18napis.appspot.com/ssl-address/" or
- // "https://i18napis.appspot.com/ssl-aggregate-address/" prefix, but do not
- // have associated data will always return "{}" with status code 200.
- // FakeDownloader imitates this behavior for URLs that start with
- // "test://address/" and "test://aggregate-address/" prefixes.
- success = true;
- data = new std::string("{}");
- }
- downloaded(success, url, data);
-}
-
-} // namespace addressinput
-} // namespace i18n
diff --git a/cpp/test/fake_downloader.h b/cpp/test/fake_downloader.h
deleted file mode 100644
index 111ce7a..0000000
--- a/cpp/test/fake_downloader.h
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright (C) 2013 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.
-//
-// A fake downloader object to use in tests. Reads data from a file instead of
-// downloading it from a server.
-
-#ifndef I18N_ADDRESSINPUT_TEST_FAKE_DOWNLOADER_H_
-#define I18N_ADDRESSINPUT_TEST_FAKE_DOWNLOADER_H_
-
-#include <libaddressinput/downloader.h>
-
-#include <string>
-
-namespace i18n {
-namespace addressinput {
-
-// "Downloads" serialized validation rules from a test data file. Sample usage:
-// class MyClass {
-// public:
-// MyClass() : downloader_(),
-// callback_(BuildCallback(this, &MyClass::OnDownloaded)) {}
-//
-// ~MyClass() {}
-//
-// void GetData(const std::string& key) {
-// downloader_.Download(std::string(FakeDownloader::kFakeDataUrl) + key,
-// *callback_);
-// }
-//
-// private:
-// void OnDownloaded(bool success,
-// const std::string& url,
-// std::string* data) {
-// ...
-// delete data;
-// }
-//
-// FakeDownloader downloader_;
-// scoped_ptr<Downloader::Callback> callback_;
-//
-// DISALLOW_COPY_AND_ASSIGN(MyClass);
-// };
-class FakeDownloader : public Downloader {
- public:
- // The fake data URL to be used in tests for retrieving one key at a time.
- static const char kFakeDataUrl[];
-
- // The fake data URL to be used in tests for retrieving aggregate data, which
- // is a JSON dictionary that maps from keys to dictionaries of what you would
- // normally get from kFakeDataUrl.
- static const char kFakeAggregateDataUrl[];
-
- FakeDownloader();
- virtual ~FakeDownloader();
-
- // Downloader implementation.
- virtual void Download(const std::string& url,
- const Callback& downloaded) const;
-};
-
-} // namespace addressinput
-} // namespace i18n
-
-#endif // I18N_ADDRESSINPUT_TEST_FAKE_DOWNLOADER_H_
diff --git a/cpp/test/fake_downloader_test.cc b/cpp/test/fake_downloader_test.cc
deleted file mode 100644
index 2d88acc..0000000
--- a/cpp/test/fake_downloader_test.cc
+++ /dev/null
@@ -1,208 +0,0 @@
-// Copyright (C) 2013 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 "fake_downloader.h"
-
-#include <libaddressinput/callback.h>
-#include <libaddressinput/downloader.h>
-#include <libaddressinput/util/scoped_ptr.h>
-
-#include <cstddef>
-#include <string>
-
-#include <gtest/gtest.h>
-
-#include "region_data_constants.h"
-
-namespace {
-
-using i18n::addressinput::BuildCallback;
-using i18n::addressinput::Downloader;
-using i18n::addressinput::FakeDownloader;
-using i18n::addressinput::RegionDataConstants;
-using i18n::addressinput::scoped_ptr;
-
-// Tests for FakeDownloader object.
-class FakeDownloaderTest : public testing::TestWithParam<std::string> {
- protected:
- FakeDownloaderTest() : downloader_(), success_(false), url_(), data_() {}
- virtual ~FakeDownloaderTest() {}
-
- Downloader::Callback* BuildCallback() {
- return ::BuildCallback(this, &FakeDownloaderTest::OnDownloaded);
- }
-
- FakeDownloader downloader_;
- bool success_;
- std::string url_;
- std::string data_;
-
- private:
- void OnDownloaded(bool success, const std::string& url, std::string* data) {
- ASSERT_FALSE(success && data == NULL);
- success_ = success;
- url_ = url;
- if (data != NULL) {
- data_ = *data;
- delete data;
- }
- }
-};
-
-// Returns testing::AssertionSuccess if |data| is valid downloaded data for
-// |key|.
-testing::AssertionResult DataIsValid(const std::string& data,
- const std::string& key) {
- if (data.empty()) {
- return testing::AssertionFailure() << "empty data";
- }
-
- std::string expected_data_begin = "{\"id\":\"" + key + "\"";
- if (data.compare(0, expected_data_begin.length(), expected_data_begin) != 0) {
- return testing::AssertionFailure() << data << " does not begin with "
- << expected_data_begin;
- }
-
- // Verify that the data ends on "}.
- static const char kDataEnd[] = "\"}";
- static const size_t kDataEndLength = sizeof kDataEnd - 1;
- if (data.compare(data.length() - kDataEndLength,
- kDataEndLength,
- kDataEnd,
- kDataEndLength) != 0) {
- return testing::AssertionFailure() << data << " does not end with "
- << kDataEnd;
- }
-
- return testing::AssertionSuccess();
-}
-
-// Verifies that FakeDownloader downloads valid data for a region code.
-TEST_P(FakeDownloaderTest, FakeDownloaderHasValidDataForRegion) {
- std::string key = "data/" + GetParam();
- std::string url = std::string(FakeDownloader::kFakeDataUrl) + key;
- scoped_ptr<Downloader::Callback> callback(BuildCallback());
- downloader_.Download(url, *callback);
-
- EXPECT_TRUE(success_);
- EXPECT_EQ(url, url_);
- EXPECT_TRUE(DataIsValid(data_, key));
-};
-
-// Returns testing::AssertionSuccess if |data| is valid aggregated downloaded
-// data for |key|.
-testing::AssertionResult AggregateDataIsValid(const std::string& data,
- const std::string& key) {
- if (data.empty()) {
- return testing::AssertionFailure() << "empty data";
- }
-
- std::string expected_data_begin = "{\"" + key;
- if (data.compare(0, expected_data_begin.length(), expected_data_begin) != 0) {
- return testing::AssertionFailure() << data << " does not begin with "
- << expected_data_begin;
- }
-
- // Verify that the data ends on "}}.
- static const char kDataEnd[] = "\"}}";
- static const size_t kDataEndLength = sizeof kDataEnd - 1;
- if (data.compare(data.length() - kDataEndLength,
- kDataEndLength,
- kDataEnd,
- kDataEndLength) != 0) {
- return testing::AssertionFailure() << data << " does not end with "
- << kDataEnd;
- }
-
- return testing::AssertionSuccess();
-}
-
-// Verifies that FakeDownloader downloads valid aggregated data for a region
-// code.
-TEST_P(FakeDownloaderTest, FakeDownloaderHasValidAggregatedDataForRegion) {
- std::string key = "data/" + GetParam();
- std::string url = std::string(FakeDownloader::kFakeAggregateDataUrl) + key;
- scoped_ptr<Downloader::Callback> callback(BuildCallback());
- downloader_.Download(url, *callback);
-
- EXPECT_TRUE(success_);
- EXPECT_EQ(url, url_);
- EXPECT_TRUE(AggregateDataIsValid(data_, key));
-};
-
-// Test all region codes.
-INSTANTIATE_TEST_CASE_P(
- AllRegions, FakeDownloaderTest,
- testing::ValuesIn(RegionDataConstants::GetRegionCodes()));
-
-// Verifies that the key "data" also contains valid data.
-TEST_F(FakeDownloaderTest, DownloadExistingData) {
- static const std::string kKey = "data";
- static const std::string kUrl =
- std::string(FakeDownloader::kFakeDataUrl) + kKey;
- scoped_ptr<Downloader::Callback> callback(BuildCallback());
- downloader_.Download(kUrl, *callback);
-
- EXPECT_TRUE(success_);
- EXPECT_EQ(kUrl, url_);
- EXPECT_TRUE(DataIsValid(data_, kKey));
-}
-
-// Verifies that downloading a missing key will return "{}".
-TEST_F(FakeDownloaderTest, DownloadMissingKeyReturnsEmptyDictionary) {
- static const std::string kJunkUrl =
- std::string(FakeDownloader::kFakeDataUrl) + "junk";
- scoped_ptr<Downloader::Callback> callback(BuildCallback());
- downloader_.Download(kJunkUrl, *callback);
-
- EXPECT_TRUE(success_);
- EXPECT_EQ(kJunkUrl, url_);
- EXPECT_EQ("{}", data_);
-}
-
-// Verifies that aggregate downloading of a missing key will also return "{}".
-TEST_F(FakeDownloaderTest, AggregateDownloadMissingKeyReturnsEmptyDictionary) {
- static const std::string kJunkUrl =
- std::string(FakeDownloader::kFakeAggregateDataUrl) + "junk";
- scoped_ptr<Downloader::Callback> callback(BuildCallback());
- downloader_.Download(kJunkUrl, *callback);
-
- EXPECT_TRUE(success_);
- EXPECT_EQ(kJunkUrl, url_);
- EXPECT_EQ("{}", data_);
-}
-
-// Verifies that downloading an empty key will return "{}".
-TEST_F(FakeDownloaderTest, DownloadEmptyKeyReturnsEmptyDictionary) {
- static const std::string kPrefixOnlyUrl = FakeDownloader::kFakeDataUrl;
- scoped_ptr<Downloader::Callback> callback(BuildCallback());
- downloader_.Download(kPrefixOnlyUrl, *callback);
-
- EXPECT_TRUE(success_);
- EXPECT_EQ(kPrefixOnlyUrl, url_);
- EXPECT_EQ("{}", data_);
-}
-
-// Verifies that downloading a real URL fails.
-TEST_F(FakeDownloaderTest, DownloadRealUrlFals) {
- static const std::string kRealUrl = "http://www.google.com/";
- scoped_ptr<Downloader::Callback> callback(BuildCallback());
- downloader_.Download(kRealUrl, *callback);
-
- EXPECT_FALSE(success_);
- EXPECT_EQ(kRealUrl, url_);
- EXPECT_TRUE(data_.empty());
-}
-
-} // namespace
diff --git a/cpp/test/fake_storage.h b/cpp/test/fake_storage.h
index 5e07cb0..3a164c4 100644
--- a/cpp/test/fake_storage.h
+++ b/cpp/test/fake_storage.h
@@ -19,6 +19,7 @@
#define I18N_ADDRESSINPUT_FAKE_STORAGE_H_
#include <libaddressinput/storage.h>
+#include <libaddressinput/util/basictypes.h>
#include <map>
#include <string>
@@ -30,7 +31,7 @@
// class MyClass {
// public:
// MyClass() : storage_(),
-// callback(BuildCallback(this, &MyClass::OnDataReady)) {}
+// data_ready_(BuildCallback(this, &MyClass::OnDataReady)) {}
//
// ~MyClass() {}
//
@@ -39,7 +40,7 @@
// }
//
// void Read() {
-// storage_.Get("key", *callback_);
+// storage_.Get("key", *data_ready_);
// }
//
// private:
@@ -51,7 +52,7 @@
// }
//
// FakeStorage storage_;
-// scoped_ptr<Storage::Callback> callback_;
+// const scoped_ptr<const Storage::Callback> data_ready_;
//
// DISALLOW_COPY_AND_ASSIGN(MyClass);
// };
@@ -66,6 +67,7 @@
private:
std::map<std::string, std::string*> data_;
+ DISALLOW_COPY_AND_ASSIGN(FakeStorage);
};
} // namespace addressinput
diff --git a/cpp/test/fake_storage_test.cc b/cpp/test/fake_storage_test.cc
index 49663ca..5905f02 100644
--- a/cpp/test/fake_storage_test.cc
+++ b/cpp/test/fake_storage_test.cc
@@ -16,6 +16,7 @@
#include <libaddressinput/callback.h>
#include <libaddressinput/storage.h>
+#include <libaddressinput/util/basictypes.h>
#include <libaddressinput/util/scoped_ptr.h>
#include <cstddef>
@@ -33,22 +34,21 @@
// Tests for FakeStorage object.
class FakeStorageTest : public testing::Test {
protected:
- FakeStorageTest() : storage_(), success_(false), key_(), data_() {}
- virtual ~FakeStorageTest() {}
-
- Storage::Callback* BuildCallback() {
- return ::BuildCallback(this, &FakeStorageTest::OnDataReady);
- }
+ FakeStorageTest()
+ : storage_(),
+ success_(false),
+ key_(),
+ data_(),
+ data_ready_(BuildCallback(this, &FakeStorageTest::OnDataReady)) {}
FakeStorage storage_;
bool success_;
std::string key_;
std::string data_;
+ const scoped_ptr<const Storage::Callback> data_ready_;
private:
- void OnDataReady(bool success,
- const std::string& key,
- std::string* data) {
+ void OnDataReady(bool success, const std::string& key, std::string* data) {
ASSERT_FALSE(success && data == NULL);
success_ = success;
key_ = key;
@@ -57,11 +57,12 @@
delete data;
}
}
+
+ DISALLOW_COPY_AND_ASSIGN(FakeStorageTest);
};
TEST_F(FakeStorageTest, GetWithoutPutReturnsEmptyData) {
- scoped_ptr<Storage::Callback> callback(BuildCallback());
- storage_.Get("key", *callback);
+ storage_.Get("key", *data_ready_);
EXPECT_FALSE(success_);
EXPECT_EQ("key", key_);
@@ -70,9 +71,7 @@
TEST_F(FakeStorageTest, GetReturnsWhatWasPut) {
storage_.Put("key", new std::string("value"));
-
- scoped_ptr<Storage::Callback> callback(BuildCallback());
- storage_.Get("key", *callback);
+ storage_.Get("key", *data_ready_);
EXPECT_TRUE(success_);
EXPECT_EQ("key", key_);
@@ -82,9 +81,7 @@
TEST_F(FakeStorageTest, SecondPutOverwritesData) {
storage_.Put("key", new std::string("bad-value"));
storage_.Put("key", new std::string("good-value"));
-
- scoped_ptr<Storage::Callback> callback(BuildCallback());
- storage_.Get("key", *callback);
+ storage_.Get("key", *data_ready_);
EXPECT_TRUE(success_);
EXPECT_EQ("key", key_);
diff --git a/cpp/test/format_element_test.cc b/cpp/test/format_element_test.cc
index f4b8ae5..d23203f 100644
--- a/cpp/test/format_element_test.cc
+++ b/cpp/test/format_element_test.cc
@@ -14,6 +14,8 @@
#include "format_element.h"
+#include <libaddressinput/address_field.h>
+
#include <sstream>
#include <gtest/gtest.h>
diff --git a/cpp/test/language_test.cc b/cpp/test/language_test.cc
index 197459e..502031b 100644
--- a/cpp/test/language_test.cc
+++ b/cpp/test/language_test.cc
@@ -14,6 +14,8 @@
#include "language.h"
+#include <libaddressinput/util/basictypes.h>
+
#include <string>
#include <gtest/gtest.h>
@@ -40,7 +42,13 @@
const bool expected_has_latin_script;
};
-class LanguageTest : public testing::TestWithParam<LanguageTestCase> {};
+class LanguageTest : public testing::TestWithParam<LanguageTestCase> {
+ protected:
+ LanguageTest() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(LanguageTest);
+};
TEST_P(LanguageTest, ExtractedDataIsCorrect) {
Language language(GetParam().input_language_tag);
diff --git a/cpp/test/localization_test.cc b/cpp/test/localization_test.cc
index 2ed4b07..1eba5b8 100644
--- a/cpp/test/localization_test.cc
+++ b/cpp/test/localization_test.cc
@@ -17,8 +17,10 @@
#include <libaddressinput/address_data.h>
#include <libaddressinput/address_field.h>
#include <libaddressinput/address_problem.h>
+#include <libaddressinput/util/basictypes.h>
#include <string>
+#include <vector>
#include <gtest/gtest.h>
@@ -29,27 +31,33 @@
using i18n::addressinput::AddressData;
using i18n::addressinput::AddressField;
-using i18n::addressinput::AddressProblem;
-using i18n::addressinput::ADMIN_AREA;
-using i18n::addressinput::COUNTRY;
-using i18n::addressinput::DEPENDENT_LOCALITY;
-using i18n::addressinput::INVALID_FORMAT;
using i18n::addressinput::INVALID_MESSAGE_ID;
-using i18n::addressinput::LOCALITY;
using i18n::addressinput::Localization;
-using i18n::addressinput::MISMATCHING_VALUE;
-using i18n::addressinput::MISSING_REQUIRED_FIELD;
-using i18n::addressinput::POSTAL_CODE;
-using i18n::addressinput::RECIPIENT;
+
+using i18n::addressinput::COUNTRY;
+using i18n::addressinput::ADMIN_AREA;
+using i18n::addressinput::LOCALITY;
+using i18n::addressinput::DEPENDENT_LOCALITY;
using i18n::addressinput::SORTING_CODE;
+using i18n::addressinput::POSTAL_CODE;
using i18n::addressinput::STREET_ADDRESS;
+using i18n::addressinput::ORGANIZATION;
+using i18n::addressinput::RECIPIENT;
+
+using i18n::addressinput::MISSING_REQUIRED_FIELD;
using i18n::addressinput::UNKNOWN_VALUE;
+using i18n::addressinput::INVALID_FORMAT;
+using i18n::addressinput::MISMATCHING_VALUE;
using i18n::addressinput::USES_P_O_BOX;
// Tests for Localization object.
class LocalizationTest : public testing::TestWithParam<int> {
protected:
+ LocalizationTest() {}
Localization localization_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(LocalizationTest);
};
// Verifies that a custom message getter can be used.
@@ -96,6 +104,7 @@
IDS_LIBADDRESSINPUT_PREFECTURE,
IDS_LIBADDRESSINPUT_PROVINCE,
IDS_LIBADDRESSINPUT_STATE,
+ IDS_LIBADDRESSINPUT_ORGANIZATION_LABEL,
IDS_LIBADDRESSINPUT_RECIPIENT_LABEL,
IDS_LIBADDRESSINPUT_MISSING_REQUIRED_FIELD,
IDS_LIBADDRESSINPUT_MISSING_REQUIRED_POSTAL_CODE_EXAMPLE_AND_URL,
@@ -125,9 +134,9 @@
Localization localization;
AddressData address;
address.region_code = "CH";
- EXPECT_EQ(std::string("You must provide a postal code, for example 2544.") +
- " Don't know your postal code? Find it out" +
- " <a href=\"http://www.post.ch/db/owa/pv_plz_pack/pr_main\">" +
+ EXPECT_EQ("You must provide a postal code, for example 2544."
+ " Don't know your postal code? Find it out"
+ " <a href=\"http://www.post.ch/db/owa/pv_plz_pack/pr_main\">"
"here</a>.",
localization.GetErrorMessage(address, POSTAL_CODE,
MISSING_REQUIRED_FIELD, true, true));
@@ -146,9 +155,9 @@
Localization localization;
AddressData address;
address.region_code = "US";
- EXPECT_EQ(std::string("You must provide a ZIP code, for example 95014.") +
- " Don't know your ZIP code? Find it out" +
- " <a href=\"https://tools.usps.com/go/ZipLookupAction!" +
+ EXPECT_EQ("You must provide a ZIP code, for example 95014."
+ " Don't know your ZIP code? Find it out"
+ " <a href=\"https://tools.usps.com/go/ZipLookupAction!"
"input.action\">here</a>.",
localization.GetErrorMessage(address, POSTAL_CODE,
MISSING_REQUIRED_FIELD, true, true));
@@ -174,6 +183,7 @@
other_fields.push_back(DEPENDENT_LOCALITY);
other_fields.push_back(SORTING_CODE);
other_fields.push_back(STREET_ADDRESS);
+ other_fields.push_back(ORGANIZATION);
other_fields.push_back(RECIPIENT);
for (std::vector<AddressField>::iterator it = other_fields.begin();
it != other_fields.end(); it++) {
@@ -204,116 +214,133 @@
address_line.push_back("bad address line 1");
address_line.push_back("bad address line 2");
address.address_line = address_line;
+ address.organization = "bad organization";
address.recipient = "bad recipient";
- EXPECT_EQ(std::string("US ") +
+ EXPECT_EQ("US "
"is not recognized as a known value for this field.",
localization.GetErrorMessage(
address, COUNTRY, UNKNOWN_VALUE, true, true));
- EXPECT_EQ(std::string("US ") +
+ EXPECT_EQ("US "
"is not recognized as a known value for this field.",
localization.GetErrorMessage(
address, COUNTRY, UNKNOWN_VALUE, true, false));
- EXPECT_EQ(std::string("US ") +
+ EXPECT_EQ("US "
"is not recognized as a known value for this field.",
localization.GetErrorMessage(
address, COUNTRY, UNKNOWN_VALUE, false, false));
- EXPECT_EQ(std::string("US ") +
+ EXPECT_EQ("US "
"is not recognized as a known value for this field.",
localization.GetErrorMessage(
address, COUNTRY, UNKNOWN_VALUE, false, true));
- EXPECT_EQ(std::string("bad admin area ") +
+ EXPECT_EQ("bad admin area "
"is not recognized as a known value for this field.",
localization.GetErrorMessage(
address, ADMIN_AREA, UNKNOWN_VALUE, true, true));
- EXPECT_EQ(std::string("bad admin area ") +
+ EXPECT_EQ("bad admin area "
"is not recognized as a known value for this field.",
localization.GetErrorMessage(
address, ADMIN_AREA, UNKNOWN_VALUE, true, false));
- EXPECT_EQ(std::string("bad admin area ") +
+ EXPECT_EQ("bad admin area "
"is not recognized as a known value for this field.",
localization.GetErrorMessage(
address, ADMIN_AREA, UNKNOWN_VALUE, false, false));
- EXPECT_EQ(std::string("bad admin area ") +
+ EXPECT_EQ("bad admin area "
"is not recognized as a known value for this field.",
localization.GetErrorMessage(
address, ADMIN_AREA, UNKNOWN_VALUE, false, true));
- EXPECT_EQ(std::string("bad locality ") +
+ EXPECT_EQ("bad locality "
"is not recognized as a known value for this field.",
localization.GetErrorMessage(
address, LOCALITY, UNKNOWN_VALUE, true, true));
- EXPECT_EQ(std::string("bad locality ") +
+ EXPECT_EQ("bad locality "
"is not recognized as a known value for this field.",
localization.GetErrorMessage(
address, LOCALITY, UNKNOWN_VALUE, true, false));
- EXPECT_EQ(std::string("bad locality ") +
+ EXPECT_EQ("bad locality "
"is not recognized as a known value for this field.",
localization.GetErrorMessage(
address, LOCALITY, UNKNOWN_VALUE, false, false));
- EXPECT_EQ(std::string("bad locality ") +
+ EXPECT_EQ("bad locality "
"is not recognized as a known value for this field.",
localization.GetErrorMessage(
address, LOCALITY, UNKNOWN_VALUE, false, true));
- EXPECT_EQ(std::string("bad dependent locality ") +
+ EXPECT_EQ("bad dependent locality "
"is not recognized as a known value for this field.",
localization.GetErrorMessage(
address, DEPENDENT_LOCALITY, UNKNOWN_VALUE, true, true));
- EXPECT_EQ(std::string("bad dependent locality ") +
+ EXPECT_EQ("bad dependent locality "
"is not recognized as a known value for this field.",
localization.GetErrorMessage(
address, DEPENDENT_LOCALITY, UNKNOWN_VALUE, true, false));
- EXPECT_EQ(std::string("bad dependent locality ") +
+ EXPECT_EQ("bad dependent locality "
"is not recognized as a known value for this field.",
localization.GetErrorMessage(
address, DEPENDENT_LOCALITY, UNKNOWN_VALUE, false, false));
- EXPECT_EQ(std::string("bad dependent locality ") +
+ EXPECT_EQ("bad dependent locality "
"is not recognized as a known value for this field.",
localization.GetErrorMessage(
address, DEPENDENT_LOCALITY, UNKNOWN_VALUE, false, true));
- EXPECT_EQ(std::string("bad sorting code ") +
+ EXPECT_EQ("bad sorting code "
"is not recognized as a known value for this field.",
localization.GetErrorMessage(
address, SORTING_CODE, UNKNOWN_VALUE, true, true));
- EXPECT_EQ(std::string("bad sorting code ") +
+ EXPECT_EQ("bad sorting code "
"is not recognized as a known value for this field.",
localization.GetErrorMessage(
address, SORTING_CODE, UNKNOWN_VALUE, true, false));
- EXPECT_EQ(std::string("bad sorting code ") +
+ EXPECT_EQ("bad sorting code "
"is not recognized as a known value for this field.",
localization.GetErrorMessage(
address, SORTING_CODE, UNKNOWN_VALUE, false, false));
- EXPECT_EQ(std::string("bad sorting code ") +
+ EXPECT_EQ("bad sorting code "
"is not recognized as a known value for this field.",
localization.GetErrorMessage(
address, SORTING_CODE, UNKNOWN_VALUE, false, true));
- EXPECT_EQ(std::string("bad address line 1 ") +
+ EXPECT_EQ("bad address line 1 "
"is not recognized as a known value for this field.",
localization.GetErrorMessage(
address, STREET_ADDRESS, UNKNOWN_VALUE, true, true));
- EXPECT_EQ(std::string("bad address line 1 ") +
+ EXPECT_EQ("bad address line 1 "
"is not recognized as a known value for this field.",
localization.GetErrorMessage(
address, STREET_ADDRESS, UNKNOWN_VALUE, true, false));
- EXPECT_EQ(std::string("bad address line 1 ") +
+ EXPECT_EQ("bad address line 1 "
"is not recognized as a known value for this field.",
localization.GetErrorMessage(
address, STREET_ADDRESS, UNKNOWN_VALUE, false, false));
- EXPECT_EQ(std::string("bad address line 1 ") +
+ EXPECT_EQ("bad address line 1 "
"is not recognized as a known value for this field.",
localization.GetErrorMessage(
address, STREET_ADDRESS, UNKNOWN_VALUE, false, true));
- EXPECT_EQ(std::string("bad recipient ") +
+ EXPECT_EQ("bad organization "
+ "is not recognized as a known value for this field.",
+ localization.GetErrorMessage(
+ address, ORGANIZATION, UNKNOWN_VALUE, true, true));
+ EXPECT_EQ("bad organization "
+ "is not recognized as a known value for this field.",
+ localization.GetErrorMessage(
+ address, ORGANIZATION, UNKNOWN_VALUE, true, false));
+ EXPECT_EQ("bad organization "
+ "is not recognized as a known value for this field.",
+ localization.GetErrorMessage(
+ address, ORGANIZATION, UNKNOWN_VALUE, false, false));
+ EXPECT_EQ("bad organization "
+ "is not recognized as a known value for this field.",
+ localization.GetErrorMessage(
+ address, ORGANIZATION, UNKNOWN_VALUE, false, true));
+ EXPECT_EQ("bad recipient "
"is not recognized as a known value for this field.",
localization.GetErrorMessage(
address, RECIPIENT, UNKNOWN_VALUE, true, true));
- EXPECT_EQ(std::string("bad recipient ") +
+ EXPECT_EQ("bad recipient "
"is not recognized as a known value for this field.",
localization.GetErrorMessage(
address, RECIPIENT, UNKNOWN_VALUE, true, false));
- EXPECT_EQ(std::string("bad recipient ") +
+ EXPECT_EQ("bad recipient "
"is not recognized as a known value for this field.",
localization.GetErrorMessage(
address, RECIPIENT, UNKNOWN_VALUE, false, false));
- EXPECT_EQ(std::string("bad recipient ") +
+ EXPECT_EQ("bad recipient "
"is not recognized as a known value for this field.",
localization.GetErrorMessage(
address, RECIPIENT, UNKNOWN_VALUE, false, true));
@@ -323,14 +350,14 @@
Localization localization;
AddressData address;
address.region_code = "CH";
- EXPECT_EQ(std::string("This postal code format is not recognized. Example ") +
- "of a valid postal code: 2544." +
- " Don't know your postal code? Find it out" +
- " <a href=\"http://www.post.ch/db/owa/pv_plz_pack/pr_main\">" +
+ EXPECT_EQ("This postal code format is not recognized. Example "
+ "of a valid postal code: 2544."
+ " Don't know your postal code? Find it out"
+ " <a href=\"http://www.post.ch/db/owa/pv_plz_pack/pr_main\">"
"here</a>.",
localization.GetErrorMessage(address, POSTAL_CODE,
INVALID_FORMAT, true, true));
- EXPECT_EQ(std::string("This postal code format is not recognized. Example ") +
+ EXPECT_EQ("This postal code format is not recognized. Example "
"of a valid postal code: 2544.",
localization.GetErrorMessage(address, POSTAL_CODE,
INVALID_FORMAT, true, false));
@@ -346,14 +373,14 @@
Localization localization;
AddressData address;
address.region_code = "US";
- EXPECT_EQ(std::string("This ZIP code format is not recognized. Example of ") +
- "a valid ZIP code: 95014." +
- " Don't know your ZIP code? Find it out" +
- " <a href=\"https://tools.usps.com/go/ZipLookupAction!" +
+ EXPECT_EQ("This ZIP code format is not recognized. Example of "
+ "a valid ZIP code: 95014."
+ " Don't know your ZIP code? Find it out"
+ " <a href=\"https://tools.usps.com/go/ZipLookupAction!"
"input.action\">here</a>.",
localization.GetErrorMessage(address, POSTAL_CODE,
INVALID_FORMAT, true, true));
- EXPECT_EQ(std::string("This ZIP code format is not recognized. Example of ") +
+ EXPECT_EQ("This ZIP code format is not recognized. Example of "
"a valid ZIP code: 95014.",
localization.GetErrorMessage(address, POSTAL_CODE,
INVALID_FORMAT, true, false));
@@ -369,25 +396,25 @@
Localization localization;
AddressData address;
address.region_code = "CH";
- EXPECT_EQ(std::string("This postal code does not appear to match the rest ") +
- "of this address." +
- " Don't know your postal code? Find it out" +
- " <a href=\"http://www.post.ch/db/owa/pv_plz_pack/pr_main\">" +
+ EXPECT_EQ("This postal code does not appear to match the rest "
+ "of this address."
+ " Don't know your postal code? Find it out"
+ " <a href=\"http://www.post.ch/db/owa/pv_plz_pack/pr_main\">"
"here</a>.",
localization.GetErrorMessage(address, POSTAL_CODE,
MISMATCHING_VALUE, true, true));
- EXPECT_EQ(std::string("This postal code does not appear to match the rest ") +
+ EXPECT_EQ("This postal code does not appear to match the rest "
"of this address.",
localization.GetErrorMessage(address, POSTAL_CODE,
MISMATCHING_VALUE, true, false));
- EXPECT_EQ(std::string("This postal code does not appear to match the rest ") +
+ EXPECT_EQ("This postal code does not appear to match the rest "
"of this address.",
localization.GetErrorMessage(address, POSTAL_CODE,
MISMATCHING_VALUE, false, false));
- EXPECT_EQ(std::string("This postal code does not appear to match the rest ") +
- "of this address." +
- " Don't know your postal code? Find it out" +
- " <a href=\"http://www.post.ch/db/owa/pv_plz_pack/pr_main\">" +
+ EXPECT_EQ("This postal code does not appear to match the rest "
+ "of this address."
+ " Don't know your postal code? Find it out"
+ " <a href=\"http://www.post.ch/db/owa/pv_plz_pack/pr_main\">"
"here</a>.",
localization.GetErrorMessage(address, POSTAL_CODE,
MISMATCHING_VALUE, false, true));
@@ -397,25 +424,25 @@
Localization localization;
AddressData address;
address.region_code = "US";
- EXPECT_EQ(std::string("This ZIP code does not appear to match the rest of ") +
- "this address." +
- " Don't know your ZIP code? Find it out" +
- " <a href=\"https://tools.usps.com/go/ZipLookupAction!" +
+ EXPECT_EQ("This ZIP code does not appear to match the rest of "
+ "this address."
+ " Don't know your ZIP code? Find it out"
+ " <a href=\"https://tools.usps.com/go/ZipLookupAction!"
"input.action\">here</a>.",
localization.GetErrorMessage(address, POSTAL_CODE,
MISMATCHING_VALUE, true, true));
- EXPECT_EQ(std::string("This ZIP code does not appear to match the rest of ") +
+ EXPECT_EQ("This ZIP code does not appear to match the rest of "
"this address.",
localization.GetErrorMessage(address, POSTAL_CODE,
MISMATCHING_VALUE, true, false));
- EXPECT_EQ(std::string("This ZIP code does not appear to match the rest of ") +
+ EXPECT_EQ("This ZIP code does not appear to match the rest of "
"this address.",
localization.GetErrorMessage(address, POSTAL_CODE,
MISMATCHING_VALUE, false, false));
- EXPECT_EQ(std::string("This ZIP code does not appear to match the rest of ") +
- "this address." +
- " Don't know your ZIP code? Find it out" +
- " <a href=\"https://tools.usps.com/go/ZipLookupAction!" +
+ EXPECT_EQ("This ZIP code does not appear to match the rest of "
+ "this address."
+ " Don't know your ZIP code? Find it out"
+ " <a href=\"https://tools.usps.com/go/ZipLookupAction!"
"input.action\">here</a>.",
localization.GetErrorMessage(address, POSTAL_CODE,
MISMATCHING_VALUE, false, true));
@@ -432,26 +459,27 @@
other_fields.push_back(DEPENDENT_LOCALITY);
other_fields.push_back(SORTING_CODE);
other_fields.push_back(STREET_ADDRESS);
+ other_fields.push_back(ORGANIZATION);
other_fields.push_back(RECIPIENT);
for (std::vector<AddressField>::iterator it = other_fields.begin();
it != other_fields.end(); it++) {
- EXPECT_EQ(std::string("This address line appears to contain a post ") +
- "office box. Please use a street" +
+ EXPECT_EQ("This address line appears to contain a post "
+ "office box. Please use a street"
" or building address.",
localization.GetErrorMessage(
address, *it, USES_P_O_BOX, true, true));
- EXPECT_EQ(std::string("This address line appears to contain a post ") +
- "office box. Please use a street" +
+ EXPECT_EQ("This address line appears to contain a post "
+ "office box. Please use a street"
" or building address.",
localization.GetErrorMessage(
address, *it, USES_P_O_BOX, true, false));
- EXPECT_EQ(std::string("This address line appears to contain a post ") +
- "office box. Please use a street" +
+ EXPECT_EQ("This address line appears to contain a post "
+ "office box. Please use a street"
" or building address.",
localization.GetErrorMessage(
address, *it, USES_P_O_BOX, false, false));
- EXPECT_EQ(std::string("This address line appears to contain a post ") +
- "office box. Please use a street" +
+ EXPECT_EQ("This address line appears to contain a post "
+ "office box. Please use a street"
" or building address.",
localization.GetErrorMessage(
address, *it, USES_P_O_BOX, false, true));
diff --git a/cpp/test/lookup_key_test.cc b/cpp/test/lookup_key_test.cc
index 18668f8..3f1fab6 100644
--- a/cpp/test/lookup_key_test.cc
+++ b/cpp/test/lookup_key_test.cc
@@ -17,6 +17,8 @@
#include <libaddressinput/address_data.h>
#include <libaddressinput/util/basictypes.h>
+#include <cstddef>
+
#include <gtest/gtest.h>
namespace {
diff --git a/cpp/test/lookup_key_util_test.cc b/cpp/test/lookup_key_util_test.cc
deleted file mode 100644
index a210bd5..0000000
--- a/cpp/test/lookup_key_util_test.cc
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright (C) 2013 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 "lookup_key_util.h"
-
-#include <gtest/gtest.h>
-
-namespace {
-
-using i18n::addressinput::LookupKeyUtil;
-
-TEST(LookupKeyUtilTest, GetUrlForKey) {
- const LookupKeyUtil util("test:///");
- EXPECT_EQ("test:///", util.GetUrlForKey(""));
- EXPECT_EQ("test:///data", util.GetUrlForKey("data"));
- EXPECT_EQ("test:///data/US", util.GetUrlForKey("data/US"));
- EXPECT_EQ("test:///data/CA--fr", util.GetUrlForKey("data/CA--fr"));
-}
-
-TEST(LookupKeyUtilTest, GetKeyForUrl) {
- const LookupKeyUtil util("test:///");
- EXPECT_EQ("", util.GetKeyForUrl("test://"));
- EXPECT_EQ("", util.GetKeyForUrl("http://www.google.com/"));
- EXPECT_EQ("", util.GetKeyForUrl(""));
- EXPECT_EQ("", util.GetKeyForUrl("test:///"));
- EXPECT_EQ("data", util.GetKeyForUrl("test:///data"));
- EXPECT_EQ("data/US", util.GetKeyForUrl("test:///data/US"));
- EXPECT_EQ("data/CA--fr", util.GetKeyForUrl("test:///data/CA--fr"));
-}
-
-TEST(LookupKeyUtilTest, IsValidationDataUrl) {
- const LookupKeyUtil util("test:///");
- EXPECT_FALSE(util.IsValidationDataUrl("test://"));
- EXPECT_FALSE(util.IsValidationDataUrl("http://www.google.com/"));
- EXPECT_FALSE(util.IsValidationDataUrl(""));
- EXPECT_TRUE(util.IsValidationDataUrl("test:///"));
- EXPECT_TRUE(util.IsValidationDataUrl("test:///data"));
- EXPECT_TRUE(util.IsValidationDataUrl("test:///data/US"));
- EXPECT_TRUE(util.IsValidationDataUrl("test:///data/CA--fr"));
-}
-
-} // namespace
diff --git a/cpp/test/mock_downloader.cc b/cpp/test/mock_downloader.cc
deleted file mode 100644
index 71256aa..0000000
--- a/cpp/test/mock_downloader.cc
+++ /dev/null
@@ -1,49 +0,0 @@
-// 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 "mock_downloader.h"
-
-#include <cassert>
-#include <cstddef>
-#include <map>
-#include <string>
-
-namespace i18n {
-namespace addressinput {
-
-// static
-const char MockDownloader::kMockDataUrl[] = "mock:///";
-
-namespace {
-
-// The number of characters in the mock data URL prefix.
-const size_t kMockDataUrlLength = sizeof MockDownloader::kMockDataUrl - 1;
-
-} // namespace
-
-MockDownloader::MockDownloader() {}
-
-MockDownloader::~MockDownloader() {}
-
-void MockDownloader::Download(const std::string& url,
- const Callback& downloaded) const {
- assert(url.compare(0, kMockDataUrlLength, kMockDataUrl) == 0);
- std::string key(url, kMockDataUrlLength);
- std::map<std::string, std::string>::const_iterator it = data_.find(key);
- bool success = it != data_.end();
- downloaded(success, url, success ? new std::string(it->second) : NULL);
-}
-
-} // namespace addressinput
-} // namespace i18n
diff --git a/cpp/test/mock_downloader.h b/cpp/test/mock_downloader.h
deleted file mode 100644
index b423660..0000000
--- a/cpp/test/mock_downloader.h
+++ /dev/null
@@ -1,80 +0,0 @@
-// 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.
-//
-// A mock downloader object to use in tests.
-
-#ifndef I18N_ADDRESSINPUT_TEST_MOCK_DOWNLOADER_H_
-#define I18N_ADDRESSINPUT_TEST_MOCK_DOWNLOADER_H_
-
-#include <libaddressinput/downloader.h>
-
-#include <map>
-#include <string>
-
-#include <libaddressinput/util/basictypes.h>
-
-namespace i18n {
-namespace addressinput {
-
-// "Downloads" serialized validation rules from a key-value map. Sample usage:
-// class MyClass {
-// public:
-// MyClass() : downloader_(),
-// callback_(BuildCallback(this, &MyClass::OnDownloaded)) {
-// downloader_.data_.insert(
-// std::make_pair("data/XA", "{\"id\":\"data/XA\"}"));
-// }
-//
-// ~MyClass() {}
-//
-// void GetData(const std::string& key) {
-// downloader_.Download(std::string(MockDownloader::kMockDataUrl) + key,
-// *callback_);
-// }
-//
-// private:
-// void OnDownloaded(bool success,
-// const std::string& url,
-// std::string* data) {
-// ...
-// delete data;
-// }
-//
-// MockDownloader downloader_;
-// const scoped_ptr<const Downloader::Callback> callback_;
-//
-// DISALLOW_COPY_AND_ASSIGN(MyClass);
-// };
-class MockDownloader : public Downloader {
- public:
- // The mock data URL to be used in tests.
- static const char kMockDataUrl[];
-
- MockDownloader();
- virtual ~MockDownloader();
-
- // Downloader implementation.
- virtual void Download(const std::string& url,
- const Callback& downloaded) const;
-
- std::map<std::string, std::string> data_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(MockDownloader);
-};
-
-} // namespace addressinput
-} // namespace i18n
-
-#endif // I18N_ADDRESSINPUT_TEST_MOCK_DOWNLOADER_H_
diff --git a/cpp/test/mock_source.cc b/cpp/test/mock_source.cc
new file mode 100644
index 0000000..d04598b
--- /dev/null
+++ b/cpp/test/mock_source.cc
@@ -0,0 +1,35 @@
+// 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 "mock_source.h"
+
+#include <cstddef>
+#include <map>
+#include <string>
+
+namespace i18n {
+namespace addressinput {
+
+MockSource::MockSource() {}
+
+MockSource::~MockSource() {}
+
+void MockSource::Get(const std::string& key, const Callback& data_ready) const {
+ std::map<std::string, std::string>::const_iterator it = data_.find(key);
+ bool success = it != data_.end();
+ data_ready(success, key, success ? new std::string(it->second) : NULL);
+}
+
+} // namespace addressinput
+} // namespace i18n
diff --git a/cpp/test/mock_source.h b/cpp/test/mock_source.h
new file mode 100644
index 0000000..27f75c4
--- /dev/null
+++ b/cpp/test/mock_source.h
@@ -0,0 +1,74 @@
+// 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.
+//
+// A mock implementation of the Source interface to be used in tests.
+
+#ifndef I18N_ADDRESSINPUT_TEST_MOCK_SOURCE_H_
+#define I18N_ADDRESSINPUT_TEST_MOCK_SOURCE_H_
+
+#include <libaddressinput/source.h>
+#include <libaddressinput/util/basictypes.h>
+
+#include <map>
+#include <string>
+
+namespace i18n {
+namespace addressinput {
+
+// Gets address metadata from a key-value map. Sample usage:
+// class MyClass {
+// public:
+// MyClass() : source_(),
+// data_ready_(BuildCallback(this, &MyClass::OnDataReady)) {
+// source_.data_.insert(
+// std::make_pair("data/XA", "{\"id\":\"data/XA\"}"));
+// }
+//
+// ~MyClass() {}
+//
+// void GetData(const std::string& key) {
+// source_.Get(key, *data_ready_);
+// }
+//
+// private:
+// void OnDataReady(bool success,
+// const std::string& key,
+// std::string* data) {
+// ...
+// delete data;
+// }
+//
+// MockSource source_;
+// const scoped_ptr<const Source::Callback> data_ready_;
+//
+// DISALLOW_COPY_AND_ASSIGN(MyClass);
+// };
+class MockSource : public Source {
+ public:
+ MockSource();
+ virtual ~MockSource();
+
+ // Source implementation.
+ virtual void Get(const std::string& key, const Callback& data_ready) const;
+
+ std::map<std::string, std::string> data_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockSource);
+};
+
+} // namespace addressinput
+} // namespace i18n
+
+#endif // I18N_ADDRESSINPUT_TEST_MOCK_SOURCE_H_
diff --git a/cpp/test/null_storage_test.cc b/cpp/test/null_storage_test.cc
index dca0803..3669ea9 100644
--- a/cpp/test/null_storage_test.cc
+++ b/cpp/test/null_storage_test.cc
@@ -12,8 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include <libaddressinput/callback.h>
#include <libaddressinput/null_storage.h>
+
+#include <libaddressinput/callback.h>
#include <libaddressinput/storage.h>
#include <libaddressinput/util/basictypes.h>
#include <libaddressinput/util/scoped_ptr.h>
@@ -32,16 +33,14 @@
class NullStorageTest : public testing::Test {
protected:
- NullStorageTest() {}
-
- Storage::Callback* BuildCallback() {
- return ::BuildCallback(this, &NullStorageTest::OnDataReady);
- }
+ NullStorageTest()
+ : data_ready_(BuildCallback(this, &NullStorageTest::OnDataReady)) {}
NullStorage storage_;
bool success_;
std::string key_;
std::string data_;
+ const scoped_ptr<const Storage::Callback> data_ready_;
static const char kKey[];
@@ -68,8 +67,7 @@
}
TEST_F(NullStorageTest, Get) {
- const scoped_ptr<const Storage::Callback> callback(BuildCallback());
- storage_.Get(kKey, *callback);
+ storage_.Get(kKey, *data_ready_);
EXPECT_FALSE(success_);
EXPECT_EQ(kKey, key_);
EXPECT_TRUE(data_.empty());
diff --git a/cpp/test/ondemand_supply_task_test.cc b/cpp/test/ondemand_supply_task_test.cc
index 84b2f65..e15e997 100644
--- a/cpp/test/ondemand_supply_task_test.cc
+++ b/cpp/test/ondemand_supply_task_test.cc
@@ -29,7 +29,7 @@
#include <gtest/gtest.h>
#include "lookup_key.h"
-#include "mock_downloader.h"
+#include "mock_source.h"
#include "retriever.h"
#include "rule.h"
@@ -37,7 +37,7 @@
using i18n::addressinput::BuildCallback;
using i18n::addressinput::LookupKey;
-using i18n::addressinput::MockDownloader;
+using i18n::addressinput::MockSource;
using i18n::addressinput::NullStorage;
using i18n::addressinput::OndemandSupplyTask;
using i18n::addressinput::Retriever;
@@ -52,11 +52,9 @@
lookup_key_(),
rule_(),
called_(false),
- downloader_(new MockDownloader),
+ source_(new MockSource),
rule_cache_(),
- retriever_(
- new Retriever(
- MockDownloader::kMockDataUrl, downloader_, new NullStorage)),
+ retriever_(new Retriever(source_, new NullStorage)),
supplied_(BuildCallback(this, &OndemandSupplyTaskTest::Supplied)),
task_(new OndemandSupplyTask(lookup_key_, &rule_cache_, *supplied_)) {}
@@ -67,19 +65,15 @@
}
}
- void Queue(const std::string& key) {
- task_->Queue(key);
- }
+ void Queue(const std::string& key) { task_->Queue(key); }
- void Retrieve() {
- task_->Retrieve(*retriever_);
- }
+ void Retrieve() { task_->Retrieve(*retriever_); }
- bool success_; // Expected status from MockDownloader.
+ bool success_; // Expected status from MockSource.
LookupKey lookup_key_; // Stub.
const Rule* rule_[arraysize(LookupKey::kHierarchy)];
bool called_;
- MockDownloader* const downloader_;
+ MockSource* const source_;
private:
void Supplied(bool success,
@@ -119,7 +113,7 @@
}
TEST_F(OndemandSupplyTaskTest, Valid) {
- downloader_->data_.insert(std::make_pair("data/XA", "{\"id\":\"data/XA\"}"));
+ source_->data_.insert(std::make_pair("data/XA", "{\"id\":\"data/XA\"}"));
Queue("data/XA");
@@ -139,13 +133,13 @@
}
TEST_F(OndemandSupplyTaskTest, ValidHierarchy) {
- downloader_->data_.insert(
+ source_->data_.insert(
std::make_pair("data/XA", "{\"id\":\"data/XA\"}"));
- downloader_->data_.insert(
+ source_->data_.insert(
std::make_pair("data/XA/aa", "{\"id\":\"data/XA/aa\"}"));
- downloader_->data_.insert(
+ source_->data_.insert(
std::make_pair("data/XA/aa/bb", "{\"id\":\"data/XA/aa/bb\"}"));
- downloader_->data_.insert(
+ source_->data_.insert(
std::make_pair("data/XA/aa/bb/cc", "{\"id\":\"data/XA/aa/bb/cc\"}"));
Queue("data/XA");
@@ -179,7 +173,7 @@
}
TEST_F(OndemandSupplyTaskTest, InvalidJson1) {
- downloader_->data_.insert(std::make_pair("data/XA", ":"));
+ source_->data_.insert(std::make_pair("data/XA", ":"));
success_ = false;
@@ -190,8 +184,8 @@
}
TEST_F(OndemandSupplyTaskTest, InvalidJson2) {
- downloader_->data_.insert(std::make_pair("data/XA", "{\"id\":\"data/XA\"}"));
- downloader_->data_.insert(std::make_pair("data/XA/aa", ":"));
+ source_->data_.insert(std::make_pair("data/XA", "{\"id\":\"data/XA\"}"));
+ source_->data_.insert(std::make_pair("data/XA/aa", ":"));
success_ = false;
@@ -203,8 +197,8 @@
}
TEST_F(OndemandSupplyTaskTest, EmptyJsonJustMeansServerKnowsNothingAboutKey) {
- downloader_->data_.insert(std::make_pair("data/XA", "{\"id\":\"data/XA\"}"));
- downloader_->data_.insert(std::make_pair("data/XA/aa", "{}"));
+ source_->data_.insert(std::make_pair("data/XA", "{\"id\":\"data/XA\"}"));
+ source_->data_.insert(std::make_pair("data/XA/aa", "{}"));
Queue("data/XA");
Queue("data/XA/aa");
@@ -220,7 +214,7 @@
}
TEST_F(OndemandSupplyTaskTest, IfCountryFailsAllFails) {
- downloader_->data_.insert(
+ source_->data_.insert(
std::make_pair("data/XA/aa", "{\"id\":\"data/XA/aa\"}"));
success_ = false;
diff --git a/cpp/test/post_box_matchers_test.cc b/cpp/test/post_box_matchers_test.cc
index d89ee0b..8abd974 100644
--- a/cpp/test/post_box_matchers_test.cc
+++ b/cpp/test/post_box_matchers_test.cc
@@ -17,13 +17,13 @@
#include <cstddef>
#include <vector>
-#include "rule.h"
-
#include <gtest/gtest.h>
+#include "rule.h"
+
namespace i18n {
namespace addressinput {
-class RE2ptr;
+struct RE2ptr;
} // namespace addressinput
} // namespace i18n
diff --git a/cpp/test/preload_supplier_test.cc b/cpp/test/preload_supplier_test.cc
index ab787d8..8612e98 100644
--- a/cpp/test/preload_supplier_test.cc
+++ b/cpp/test/preload_supplier_test.cc
@@ -20,38 +20,34 @@
#include <libaddressinput/util/basictypes.h>
#include <libaddressinput/util/scoped_ptr.h>
-#include "fake_downloader.h"
-#include "lookup_key.h"
-#include "rule.h"
-
#include <cstddef>
#include <string>
#include <gtest/gtest.h>
+#include "lookup_key.h"
+#include "rule.h"
+#include "testdata_source.h"
+
namespace {
using i18n::addressinput::AddressData;
using i18n::addressinput::BuildCallback;
-using i18n::addressinput::FakeDownloader;
using i18n::addressinput::LookupKey;
using i18n::addressinput::NullStorage;
using i18n::addressinput::PreloadSupplier;
using i18n::addressinput::Rule;
using i18n::addressinput::scoped_ptr;
+using i18n::addressinput::TestdataSource;
class PreloadSupplierTest : public testing::Test {
protected:
PreloadSupplierTest()
- : supplier_(FakeDownloader::kFakeAggregateDataUrl,
- new FakeDownloader,
- new NullStorage),
+ : supplier_(new TestdataSource(true), new NullStorage),
loaded_callback_(BuildCallback(this, &PreloadSupplierTest::OnLoaded)) {}
- virtual ~PreloadSupplierTest() {}
-
PreloadSupplier supplier_;
- scoped_ptr<PreloadSupplier::Callback> loaded_callback_;
+ const scoped_ptr<const PreloadSupplier::Callback> loaded_callback_;
private:
void OnLoaded(bool success, const std::string& region_code, int num_rules) {
@@ -121,4 +117,12 @@
EXPECT_TRUE(rule == NULL);
}
+TEST_F(PreloadSupplierTest, GetRulesForRegion) {
+ supplier_.LoadRules("CN", *loaded_callback_);
+ const std::map<std::string, const Rule*>& rules =
+ supplier_.GetRulesForRegion("CN");
+ EXPECT_TRUE(rules.find("data/CN") != rules.end());
+ EXPECT_LT(1U, rules.size());
+}
+
} // namespace
diff --git a/cpp/test/region_data_builder_test.cc b/cpp/test/region_data_builder_test.cc
index 03b0981..fe2f2e1 100644
--- a/cpp/test/region_data_builder_test.cc
+++ b/cpp/test/region_data_builder_test.cc
@@ -21,37 +21,34 @@
#include <libaddressinput/util/basictypes.h>
#include <libaddressinput/util/scoped_ptr.h>
-#include "fake_downloader.h"
-
#include <string>
#include <gtest/gtest.h>
+#include "testdata_source.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;
+using i18n::addressinput::TestdataSource;
class RegionDataBuilderTest : public testing::Test {
protected:
RegionDataBuilderTest()
- : supplier_(FakeDownloader::kFakeAggregateDataUrl,
- new FakeDownloader,
+ : supplier_(new TestdataSource(true),
new NullStorage),
builder_(&supplier_),
loaded_callback_(BuildCallback(this, &RegionDataBuilderTest::OnLoaded)),
best_language_() {}
- virtual ~RegionDataBuilderTest() {}
-
PreloadSupplier supplier_;
RegionDataBuilder builder_;
- scoped_ptr<PreloadSupplier::Callback> loaded_callback_;
+ const scoped_ptr<const PreloadSupplier::Callback> loaded_callback_;
std::string best_language_;
private:
@@ -108,7 +105,9 @@
const RegionData& tree = builder_.Build("KR", "ko-Latn", &best_language_);
EXPECT_EQ("ko-Latn", best_language_);
ASSERT_FALSE(tree.sub_regions().empty());
- EXPECT_EQ("강원도", tree.sub_regions().front()->key());
+ EXPECT_EQ(
+ "\xEA\xB0\x95\xEC\x9B\x90\xEB\x8F\x84", /* "강원도" */
+ tree.sub_regions().front()->key());
EXPECT_EQ("Gangwon", tree.sub_regions().front()->name());
}
@@ -117,8 +116,12 @@
const RegionData& tree = builder_.Build("KR", "ko-KR", &best_language_);
EXPECT_EQ("ko", best_language_);
ASSERT_FALSE(tree.sub_regions().empty());
- EXPECT_EQ("강원도", tree.sub_regions().front()->key());
- EXPECT_EQ("강원", tree.sub_regions().front()->name());
+ EXPECT_EQ(
+ "\xEA\xB0\x95\xEC\x9B\x90\xEB\x8F\x84", /* "강원도" */
+ tree.sub_regions().front()->key());
+ EXPECT_EQ(
+ "\xEA\xB0\x95\xEC\x9B\x90", /* "강원" */
+ tree.sub_regions().front()->name());
}
} // namespace
diff --git a/cpp/test/region_data_constants_test.cc b/cpp/test/region_data_constants_test.cc
index b407374..63e6ae2 100644
--- a/cpp/test/region_data_constants_test.cc
+++ b/cpp/test/region_data_constants_test.cc
@@ -14,8 +14,9 @@
#include "region_data_constants.h"
+#include <libaddressinput/util/basictypes.h>
+
#include <string>
-#include <vector>
#include <gtest/gtest.h>
@@ -24,7 +25,13 @@
using i18n::addressinput::RegionDataConstants;
// Tests for region codes, for example "ZA".
-class RegionCodeTest : public testing::TestWithParam<std::string> {};
+class RegionCodeTest : public testing::TestWithParam<std::string> {
+ protected:
+ RegionCodeTest() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(RegionCodeTest);
+};
// Verifies that a region code consists of two characters, for example "ZA".
TEST_P(RegionCodeTest, RegionCodeHasTwoCharacters) {
@@ -58,9 +65,14 @@
// Tests for region data, for example "{\"fmt\":\"%C%S\"}".
class RegionDataTest : public testing::TestWithParam<std::string> {
protected:
+ RegionDataTest() {}
+
const std::string& GetData() const {
return RegionDataConstants::GetRegionData(GetParam());
}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(RegionDataTest);
};
// Verifies that a region data value begins with '{' and end with '}', for
diff --git a/cpp/test/region_data_test.cc b/cpp/test/region_data_test.cc
index 66d06c6..074d3a6 100644
--- a/cpp/test/region_data_test.cc
+++ b/cpp/test/region_data_test.cc
@@ -14,6 +14,7 @@
#include <libaddressinput/region_data.h>
+#include <cstddef>
#include <string>
#include <gtest/gtest.h>
diff --git a/cpp/test/retriever_test.cc b/cpp/test/retriever_test.cc
index aff418c..00c2ea4 100644
--- a/cpp/test/retriever_test.cc
+++ b/cpp/test/retriever_test.cc
@@ -17,6 +17,7 @@
#include <libaddressinput/callback.h>
#include <libaddressinput/null_storage.h>
#include <libaddressinput/storage.h>
+#include <libaddressinput/util/basictypes.h>
#include <libaddressinput/util/scoped_ptr.h>
#include <cstddef>
@@ -24,8 +25,8 @@
#include <gtest/gtest.h>
-#include "fake_downloader.h"
-#include "mock_downloader.h"
+#include "mock_source.h"
+#include "testdata_source.h"
#define CHECKSUM "dd63dafcbd4d5b28badfcaf86fb6fcdb"
#define DATA "{'foo': 'bar'}"
@@ -34,16 +35,16 @@
namespace {
using i18n::addressinput::BuildCallback;
-using i18n::addressinput::FakeDownloader;
-using i18n::addressinput::MockDownloader;
+using i18n::addressinput::MockSource;
using i18n::addressinput::NullStorage;
using i18n::addressinput::Retriever;
-using i18n::addressinput::Storage;
using i18n::addressinput::scoped_ptr;
+using i18n::addressinput::Storage;
+using i18n::addressinput::TestdataSource;
const char kKey[] = "data/CA/AB--fr";
-// Empty data that the downloader can return.
+// Empty data that the source can return.
const char kEmptyData[] = "{}";
// The value of the data that the stale storage returns.
@@ -58,23 +59,17 @@
class RetrieverTest : public testing::Test {
protected:
RetrieverTest()
- : retriever_(FakeDownloader::kFakeDataUrl,
- new FakeDownloader,
- new NullStorage),
+ : retriever_(new TestdataSource(false), new NullStorage),
success_(false),
key_(),
- data_() {}
-
- virtual ~RetrieverTest() {}
-
- Retriever::Callback* BuildCallback() {
- return ::BuildCallback(this, &RetrieverTest::OnDataReady);
- }
+ data_(),
+ data_ready_(BuildCallback(this, &RetrieverTest::OnDataReady)) {}
Retriever retriever_;
bool success_;
std::string key_;
std::string data_;
+ const scoped_ptr<const Retriever::Callback> data_ready_;
private:
void OnDataReady(bool success,
@@ -84,11 +79,12 @@
key_ = key;
data_ = data;
}
+
+ DISALLOW_COPY_AND_ASSIGN(RetrieverTest);
};
TEST_F(RetrieverTest, RetrieveData) {
- scoped_ptr<Retriever::Callback> callback(BuildCallback());
- retriever_.Retrieve(kKey, *callback);
+ retriever_.Retrieve(kKey, *data_ready_);
EXPECT_TRUE(success_);
EXPECT_EQ(kKey, key_);
@@ -97,11 +93,8 @@
}
TEST_F(RetrieverTest, ReadDataFromStorage) {
- scoped_ptr<Retriever::Callback> callback1(BuildCallback());
- retriever_.Retrieve(kKey, *callback1);
-
- scoped_ptr<Retriever::Callback> callback2(BuildCallback());
- retriever_.Retrieve(kKey, *callback2);
+ retriever_.Retrieve(kKey, *data_ready_);
+ retriever_.Retrieve(kKey, *data_ready_);
EXPECT_TRUE(success_);
EXPECT_EQ(kKey, key_);
@@ -112,22 +105,18 @@
TEST_F(RetrieverTest, MissingKeyReturnsEmptyData) {
static const char kMissingKey[] = "junk";
- scoped_ptr<Retriever::Callback> callback(BuildCallback());
- retriever_.Retrieve(kMissingKey, *callback);
+ retriever_.Retrieve(kMissingKey, *data_ready_);
EXPECT_TRUE(success_);
EXPECT_EQ(kMissingKey, key_);
EXPECT_EQ(kEmptyData, data_);
}
-TEST_F(RetrieverTest, FaultyDownloader) {
- // An empty MockDownloader will fail for any request.
- Retriever bad_retriever(MockDownloader::kMockDataUrl,
- new MockDownloader,
- new NullStorage);
+TEST_F(RetrieverTest, FaultySource) {
+ // An empty MockSource will fail for any request.
+ Retriever bad_retriever(new MockSource, new NullStorage);
- scoped_ptr<Retriever::Callback> callback(BuildCallback());
- bad_retriever.Retrieve(kKey, *callback);
+ bad_retriever.Retrieve(kKey, *data_ready_);
EXPECT_FALSE(success_);
EXPECT_EQ(kKey, key_);
@@ -157,15 +146,13 @@
DISALLOW_COPY_AND_ASSIGN(StaleStorage);
};
-TEST_F(RetrieverTest, UseStaleDataWhenDownloaderFails) {
+TEST_F(RetrieverTest, UseStaleDataWhenSourceFails) {
// Owned by |resilient_retriver|.
StaleStorage* stale_storage = new StaleStorage;
- // An empty MockDownloader will fail for any request.
- Retriever resilient_retriever(
- MockDownloader::kMockDataUrl, new MockDownloader, stale_storage);
+ // An empty MockSource will fail for any request.
+ Retriever resilient_retriever(new MockSource, stale_storage);
- scoped_ptr<Retriever::Callback> callback(BuildCallback());
- resilient_retriever.Retrieve(kKey, *callback);
+ resilient_retriever.Retrieve(kKey, *data_ready_);
EXPECT_TRUE(success_);
EXPECT_EQ(kKey, key_);
@@ -173,14 +160,12 @@
EXPECT_FALSE(stale_storage->data_updated_);
}
-TEST_F(RetrieverTest, DoNotUseStaleDataWhenDownloaderSucceeds) {
+TEST_F(RetrieverTest, DoNotUseStaleDataWhenSourceSucceeds) {
// Owned by |resilient_retriver|.
StaleStorage* stale_storage = new StaleStorage;
- Retriever resilient_retriever(
- FakeDownloader::kFakeDataUrl, new FakeDownloader, stale_storage);
+ Retriever resilient_retriever(new TestdataSource(false), stale_storage);
- scoped_ptr<Retriever::Callback> callback(BuildCallback());
- resilient_retriever.Retrieve(kKey, *callback);
+ resilient_retriever.Retrieve(kKey, *data_ready_);
EXPECT_TRUE(success_);
EXPECT_EQ(kKey, key_);
diff --git a/cpp/test/rule_retriever_test.cc b/cpp/test/rule_retriever_test.cc
index ecfb0c8..ecf3af7 100644
--- a/cpp/test/rule_retriever_test.cc
+++ b/cpp/test/rule_retriever_test.cc
@@ -16,47 +16,43 @@
#include <libaddressinput/callback.h>
#include <libaddressinput/null_storage.h>
+#include <libaddressinput/util/basictypes.h>
#include <libaddressinput/util/scoped_ptr.h>
#include <string>
#include <gtest/gtest.h>
-#include "fake_downloader.h"
#include "retriever.h"
#include "rule.h"
+#include "testdata_source.h"
namespace {
using i18n::addressinput::BuildCallback;
-using i18n::addressinput::FakeDownloader;
using i18n::addressinput::NullStorage;
using i18n::addressinput::Retriever;
using i18n::addressinput::Rule;
using i18n::addressinput::RuleRetriever;
using i18n::addressinput::scoped_ptr;
+using i18n::addressinput::TestdataSource;
// Tests for RuleRetriever object.
class RuleRetrieverTest : public testing::Test {
protected:
RuleRetrieverTest()
- : rule_retriever_(new Retriever(FakeDownloader::kFakeDataUrl,
- new FakeDownloader,
- new NullStorage)),
+ : rule_retriever_(
+ new Retriever(new TestdataSource(false), new NullStorage)),
success_(false),
key_(),
- rule_() {}
-
- virtual ~RuleRetrieverTest() {}
-
- RuleRetriever::Callback* BuildCallback() {
- return ::BuildCallback(this, &RuleRetrieverTest::OnRuleReady);
- }
+ rule_(),
+ rule_ready_(BuildCallback(this, &RuleRetrieverTest::OnRuleReady)) {}
RuleRetriever rule_retriever_;
bool success_;
std::string key_;
Rule rule_;
+ const scoped_ptr<const RuleRetriever::Callback> rule_ready_;
private:
void OnRuleReady(bool success,
@@ -66,13 +62,14 @@
key_ = key;
rule_.CopyFrom(rule);
}
+
+ DISALLOW_COPY_AND_ASSIGN(RuleRetrieverTest);
};
TEST_F(RuleRetrieverTest, ExistingRule) {
static const char kExistingKey[] = "data/CA";
- scoped_ptr<RuleRetriever::Callback> callback(BuildCallback());
- rule_retriever_.RetrieveRule(kExistingKey, *callback);
+ rule_retriever_.RetrieveRule(kExistingKey, *rule_ready_);
EXPECT_TRUE(success_);
EXPECT_EQ(kExistingKey, key_);
@@ -82,8 +79,7 @@
TEST_F(RuleRetrieverTest, MissingRule) {
static const char kMissingKey[] = "junk";
- scoped_ptr<RuleRetriever::Callback> callback(BuildCallback());
- rule_retriever_.RetrieveRule(kMissingKey, *callback);
+ rule_retriever_.RetrieveRule(kMissingKey, *rule_ready_);
EXPECT_TRUE(success_); // The server returns "{}" for bad keys.
EXPECT_EQ(kMissingKey, key_);
diff --git a/cpp/test/rule_test.cc b/cpp/test/rule_test.cc
index 25426a2..7c5a0c5 100644
--- a/cpp/test/rule_test.cc
+++ b/cpp/test/rule_test.cc
@@ -16,6 +16,7 @@
#include <libaddressinput/address_field.h>
#include <libaddressinput/localization.h>
+#include <libaddressinput/util/basictypes.h>
#include <cstddef>
#include <string>
@@ -24,7 +25,6 @@
#include <gtest/gtest.h>
-#include "address_field_util.h"
#include "format_element.h"
#include "grit.h"
#include "messages.h"
@@ -242,7 +242,11 @@
class PostalCodeNameParseTest
: public testing::TestWithParam<std::pair<std::string, int> > {
protected:
+ PostalCodeNameParseTest() {}
Rule rule_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(PostalCodeNameParseTest);
};
// Verifies that a postal code name is parsed correctly.
@@ -264,7 +268,11 @@
class AdminAreaNameParseTest
: public testing::TestWithParam<std::pair<std::string, int> > {
protected:
+ AdminAreaNameParseTest() {}
Rule rule_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(AdminAreaNameParseTest);
};
// Verifies that an administrative area name is parsed correctly.
@@ -303,6 +311,8 @@
// Tests for rule parsing.
class RuleParseTest : public testing::TestWithParam<std::string> {
protected:
+ RuleParseTest() {}
+
const std::string& GetRegionData() const {
// GetParam() is either a region code or the region data itself.
// RegionDataContants::GetRegionData() returns an empty string for anything
@@ -313,6 +323,9 @@
Rule rule_;
Localization localization_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(RuleParseTest);
};
// Verifies that a region data can be parsed successfully.
diff --git a/cpp/test/supplier_test.cc b/cpp/test/supplier_test.cc
index 13913c3..e55c0c1 100644
--- a/cpp/test/supplier_test.cc
+++ b/cpp/test/supplier_test.cc
@@ -16,11 +16,9 @@
#include <libaddressinput/address_data.h>
#include <libaddressinput/callback.h>
-#include <libaddressinput/downloader.h>
#include <libaddressinput/null_storage.h>
#include <libaddressinput/ondemand_supplier.h>
#include <libaddressinput/preload_supplier.h>
-#include <libaddressinput/storage.h>
#include <libaddressinput/util/basictypes.h>
#include <libaddressinput/util/scoped_ptr.h>
@@ -30,9 +28,9 @@
#include <gtest/gtest.h>
-#include "fake_downloader.h"
#include "lookup_key.h"
#include "rule.h"
+#include "testdata_source.h"
namespace {
@@ -55,16 +53,14 @@
using i18n::addressinput::AddressData;
using i18n::addressinput::BuildCallback;
-using i18n::addressinput::Downloader;
-using i18n::addressinput::FakeDownloader;
using i18n::addressinput::LookupKey;
using i18n::addressinput::NullStorage;
using i18n::addressinput::OndemandSupplier;
using i18n::addressinput::PreloadSupplier;
using i18n::addressinput::Rule;
using i18n::addressinput::scoped_ptr;
-using i18n::addressinput::Storage;
using i18n::addressinput::Supplier;
+using i18n::addressinput::TestdataSource;
class SupplierWrapper {
public:
@@ -77,8 +73,6 @@
public:
static SupplierWrapper* Build() { return new OndemandSupplierWrapper; }
- virtual ~OndemandSupplierWrapper() {}
-
virtual void Supply(const LookupKey& lookup_key,
const Supplier::Callback& supplied) {
ondemand_supplier_.Supply(lookup_key, supplied);
@@ -86,9 +80,7 @@
private:
OndemandSupplierWrapper()
- : ondemand_supplier_(FakeDownloader::kFakeDataUrl,
- new FakeDownloader,
- new NullStorage) {}
+ : ondemand_supplier_(new TestdataSource(false), new NullStorage) {}
OndemandSupplier ondemand_supplier_;
DISALLOW_COPY_AND_ASSIGN(OndemandSupplierWrapper);
@@ -98,8 +90,6 @@
public:
static SupplierWrapper* Build() { return new PreloadSupplierWrapper; }
- virtual ~PreloadSupplierWrapper() {}
-
virtual void Supply(const LookupKey& lookup_key,
const Supplier::Callback& supplied) {
const std::string& region_code = lookup_key.GetRegionCode();
@@ -111,14 +101,10 @@
private:
PreloadSupplierWrapper()
- : preload_supplier_(FakeDownloader::kFakeAggregateDataUrl,
- new FakeDownloader,
- new NullStorage),
+ : preload_supplier_(new TestdataSource(true), new NullStorage),
loaded_(BuildCallback(this, &PreloadSupplierWrapper::Loaded)) {}
- void Loaded(bool success, const std::string&, int) {
- ASSERT_TRUE(success);
- }
+ void Loaded(bool success, const std::string&, int) { ASSERT_TRUE(success); }
PreloadSupplier preload_supplier_;
const scoped_ptr<const PreloadSupplier::Callback> loaded_;
@@ -135,8 +121,6 @@
supplier_wrapper_((*GetParam())()),
supplied_(BuildCallback(this, &SupplierTest::Supplied)) {}
- virtual ~SupplierTest() {}
-
void Supply() {
lookup_key_.FromAddress(address_);
supplier_wrapper_->Supply(lookup_key_, *supplied_);
diff --git a/cpp/test/testdata_source.cc b/cpp/test/testdata_source.cc
new file mode 100644
index 0000000..d333cb0
--- /dev/null
+++ b/cpp/test/testdata_source.cc
@@ -0,0 +1,174 @@
+// Copyright (C) 2013 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 "testdata_source.h"
+
+#include <cassert>
+#include <cstddef>
+#include <cstdlib>
+#include <fstream>
+#include <iostream>
+#include <map>
+#include <string>
+#include <utility>
+
+namespace i18n {
+namespace addressinput {
+
+namespace {
+
+// For historical reasons, normal and aggregated data is here stored in the
+// same data structure, differentiated by giving each key a prefix. It does
+// seem like a good idea to refactor this.
+const char kNormalPrefix = '-';
+const char kAggregatePrefix = '+';
+
+// The name of the test data file.
+const char kDataFileName[] = TEST_DATA_DIR "/countryinfo.txt";
+
+// Each data key begins with this string. Example of a data key:
+// data/CH/AG
+const char kDataKeyPrefix[] = "data/";
+
+// The number of characters in the data key prefix.
+const size_t kDataKeyPrefixLength = sizeof kDataKeyPrefix - 1;
+
+// The number of characters in a CLDR region code, e.g. 'CH'.
+const size_t kCldrRegionCodeLength = 2;
+
+// The number of characters in an aggregate data key, e.g. 'data/CH'.
+const size_t kAggregateDataKeyLength =
+ kDataKeyPrefixLength + kCldrRegionCodeLength;
+
+std::map<std::string, std::string> InitData() {
+ std::map<std::string, std::string> data;
+ std::ifstream file(kDataFileName);
+ if (!file.is_open()) {
+ std::cerr << "Error opening \"" << kDataFileName << "\"." << std::endl;
+ std::exit(EXIT_FAILURE);
+ }
+
+ const std::string normal_prefix(1, kNormalPrefix);
+ const std::string aggregate_prefix(1, kAggregatePrefix);
+
+ std::string key;
+ std::string value;
+
+ std::map<std::string, std::string>::iterator last_data_it = data.end();
+ std::map<std::string, std::string>::iterator aggregate_data_it = data.end();
+
+ while (file.good()) {
+ // Example line from countryinfo.txt:
+ // data/CH/AG={"name": "Aargau"}
+ // Example key:
+ // data/CH/AG
+ std::getline(file, key, '=');
+
+ if (!key.empty()) {
+ // Example value:
+ // {"name": "Aargau"}
+ std::getline(file, value, '\n');
+
+ // For example, map '-data/CH/AG' to '{"name": "Aargau"}'.
+ last_data_it = data.insert(
+ last_data_it,
+ std::make_pair(normal_prefix + key, value));
+
+ // Aggregate keys that begin with 'data/'. We don't aggregate keys that
+ // begin with 'example/' because example data is not used anywhere.
+ if (key.compare(0,
+ kDataKeyPrefixLength,
+ kDataKeyPrefix,
+ kDataKeyPrefixLength) == 0) {
+ // If aggregate_data_it and key have the same prefix, e.g. "data/ZZ".
+ if (aggregate_data_it != data.end() &&
+ key.compare(0,
+ kAggregateDataKeyLength,
+ aggregate_data_it->first,
+ sizeof kAggregatePrefix,
+ kAggregateDataKeyLength) == 0) {
+ // Append more data to the aggregate string, for example:
+ // , "data/CH/AG": {"name": "Aargau"}
+ aggregate_data_it->second.append(", \"" + key + "\": " + value);
+ } else {
+ // The countryinfo.txt file must be sorted so that subkey data
+ // follows directly after its parent key data.
+ assert(key.size() == kAggregateDataKeyLength);
+
+ // Make the aggregate data strings valid. For example, this incomplete
+ // JSON data:
+ // {"data/CH/AG": {"name": "Aargau"},
+ // "data/CH": {"name": "SWITZERLAND"}
+ //
+ // becomes valid JSON data like so:
+ //
+ // {"data/CH/AG": {"name": "Aargau"},
+ // "data/CH": {"name": "SWITZERLAND"}}
+ if (aggregate_data_it != data.end()) {
+ aggregate_data_it->second.push_back('}');
+ }
+
+ // Example aggregate prefixed key:
+ // +data/CH
+ const std::string& aggregate_key =
+ aggregate_prefix + key.substr(0, kAggregateDataKeyLength);
+
+ // Begin a new aggregate string, for example:
+ // {"data/CH/AG": {"name": "Aargau"}
+ aggregate_data_it = data.insert(
+ aggregate_data_it,
+ std::make_pair(aggregate_key, "{\"" + key + "\": " + value));
+ }
+ }
+ }
+ }
+
+ file.close();
+ return data;
+}
+
+const std::map<std::string, std::string>& GetData() {
+ static const std::map<std::string, std::string> kData(InitData());
+ return kData;
+}
+
+} // namespace
+
+TestdataSource::TestdataSource(bool aggregate) : aggregate_(aggregate) {}
+
+TestdataSource::~TestdataSource() {}
+
+void TestdataSource::Get(const std::string& key,
+ const Callback& data_ready) const {
+ std::string prefixed_key(1, aggregate_ ? kAggregatePrefix : kNormalPrefix);
+ prefixed_key += key;
+ std::map<std::string, std::string>::const_iterator data_it =
+ GetData().find(prefixed_key);
+ bool success = data_it != GetData().end();
+ std::string* data = NULL;
+ if (success) {
+ data = new std::string(data_it->second);
+ } else {
+ // URLs that start with "https://i18napis.appspot.com/ssl-address/" or
+ // "https://i18napis.appspot.com/ssl-aggregate-address/" prefix, but do not
+ // have associated data will always return "{}" with status code 200.
+ // TestdataSource imitates this behavior.
+ success = true;
+ data = new std::string("{}");
+ }
+ data_ready(success, key, data);
+}
+
+} // namespace addressinput
+} // namespace i18n
diff --git a/cpp/test/testdata_source.h b/cpp/test/testdata_source.h
new file mode 100644
index 0000000..626483e
--- /dev/null
+++ b/cpp/test/testdata_source.h
@@ -0,0 +1,71 @@
+// Copyright (C) 2013 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.
+//
+// An implementation of the Source interface, that reads address metadata from a
+// text file, to be used in tests.
+
+#ifndef I18N_ADDRESSINPUT_TEST_TESTDATA_SOURCE_H_
+#define I18N_ADDRESSINPUT_TEST_TESTDATA_SOURCE_H_
+
+#include <libaddressinput/source.h>
+#include <libaddressinput/util/basictypes.h>
+
+#include <string>
+
+namespace i18n {
+namespace addressinput {
+
+// Gets address metadata from a text file. Sample usage:
+// class MyClass {
+// public:
+// MyClass() : source_(),
+// data_ready_(BuildCallback(this, &MyClass::OnDataReady)) {}
+//
+// ~MyClass() {}
+//
+// void GetData(const std::string& key) {
+// source_.Get(key, *data_ready_);
+// }
+//
+// private:
+// void OnDataReady(bool success,
+// const std::string& key,
+// std::string* data) {
+// ...
+// delete data;
+// }
+//
+// TestdataSource source_;
+// const scoped_ptr<const Source::Callback> data_ready_;
+//
+// DISALLOW_COPY_AND_ASSIGN(MyClass);
+// };
+class TestdataSource : public Source {
+ public:
+ // Will return aggregate data if |aggregate| is set to true.
+ explicit TestdataSource(bool aggregate);
+ virtual ~TestdataSource();
+
+ // Source implementation.
+ virtual void Get(const std::string& key, const Callback& data_ready) const;
+
+ private:
+ const bool aggregate_;
+ DISALLOW_COPY_AND_ASSIGN(TestdataSource);
+};
+
+} // namespace addressinput
+} // namespace i18n
+
+#endif // I18N_ADDRESSINPUT_TEST_TESTDATA_SOURCE_H_
diff --git a/cpp/test/testdata_source_test.cc b/cpp/test/testdata_source_test.cc
new file mode 100644
index 0000000..58468a9
--- /dev/null
+++ b/cpp/test/testdata_source_test.cc
@@ -0,0 +1,190 @@
+// Copyright (C) 2013 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 "testdata_source.h"
+
+#include <libaddressinput/callback.h>
+#include <libaddressinput/source.h>
+#include <libaddressinput/util/basictypes.h>
+#include <libaddressinput/util/scoped_ptr.h>
+
+#include <cstddef>
+#include <string>
+
+#include <gtest/gtest.h>
+
+#include "region_data_constants.h"
+
+namespace {
+
+using i18n::addressinput::BuildCallback;
+using i18n::addressinput::RegionDataConstants;
+using i18n::addressinput::scoped_ptr;
+using i18n::addressinput::Source;
+using i18n::addressinput::TestdataSource;
+
+// Tests for TestdataSource object.
+class TestdataSourceTest : public testing::TestWithParam<std::string> {
+ protected:
+ TestdataSourceTest()
+ : source_(false),
+ aggregate_source_(true),
+ success_(false),
+ key_(),
+ data_(),
+ data_ready_(BuildCallback(this, &TestdataSourceTest::OnDataReady)) {}
+
+ TestdataSource source_;
+ TestdataSource aggregate_source_;
+ bool success_;
+ std::string key_;
+ std::string data_;
+ const scoped_ptr<const Source::Callback> data_ready_;
+
+ private:
+ void OnDataReady(bool success, const std::string& key, std::string* data) {
+ ASSERT_FALSE(success && data == NULL);
+ success_ = success;
+ key_ = key;
+ if (data != NULL) {
+ data_ = *data;
+ delete data;
+ }
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(TestdataSourceTest);
+};
+
+// Returns testing::AssertionSuccess if |data| is valid callback data for
+// |key|.
+testing::AssertionResult DataIsValid(const std::string& data,
+ const std::string& key) {
+ if (data.empty()) {
+ return testing::AssertionFailure() << "empty data";
+ }
+
+ std::string expected_data_begin = "{\"id\":\"" + key + "\"";
+ if (data.compare(0, expected_data_begin.length(), expected_data_begin) != 0) {
+ return testing::AssertionFailure() << data << " does not begin with "
+ << expected_data_begin;
+ }
+
+ // Verify that the data ends on "}.
+ static const char kDataEnd[] = "\"}";
+ static const size_t kDataEndLength = sizeof kDataEnd - 1;
+ if (data.compare(data.length() - kDataEndLength,
+ kDataEndLength,
+ kDataEnd,
+ kDataEndLength) != 0) {
+ return testing::AssertionFailure() << data << " does not end with "
+ << kDataEnd;
+ }
+
+ return testing::AssertionSuccess();
+}
+
+// Verifies that TestdataSource gets valid data for a region code.
+TEST_P(TestdataSourceTest, TestdataSourceHasValidDataForRegion) {
+ std::string key = "data/" + GetParam();
+ source_.Get(key, *data_ready_);
+
+ EXPECT_TRUE(success_);
+ EXPECT_EQ(key, key_);
+ EXPECT_TRUE(DataIsValid(data_, key));
+};
+
+// Returns testing::AssertionSuccess if |data| is valid aggregated callback
+// data for |key|.
+testing::AssertionResult AggregateDataIsValid(const std::string& data,
+ const std::string& key) {
+ if (data.empty()) {
+ return testing::AssertionFailure() << "empty data";
+ }
+
+ std::string expected_data_begin = "{\"" + key;
+ if (data.compare(0, expected_data_begin.length(), expected_data_begin) != 0) {
+ return testing::AssertionFailure() << data << " does not begin with "
+ << expected_data_begin;
+ }
+
+ // Verify that the data ends on "}}.
+ static const char kDataEnd[] = "\"}}";
+ static const size_t kDataEndLength = sizeof kDataEnd - 1;
+ if (data.compare(data.length() - kDataEndLength,
+ kDataEndLength,
+ kDataEnd,
+ kDataEndLength) != 0) {
+ return testing::AssertionFailure() << data << " does not end with "
+ << kDataEnd;
+ }
+
+ return testing::AssertionSuccess();
+}
+
+// Verifies that TestdataSource gets valid aggregated data for a region code.
+TEST_P(TestdataSourceTest, TestdataSourceHasValidAggregatedDataForRegion) {
+ std::string key = "data/" + GetParam();
+ aggregate_source_.Get(key, *data_ready_);
+
+ EXPECT_TRUE(success_);
+ EXPECT_EQ(key, key_);
+ EXPECT_TRUE(AggregateDataIsValid(data_, key));
+};
+
+// Test all region codes.
+INSTANTIATE_TEST_CASE_P(
+ AllRegions, TestdataSourceTest,
+ testing::ValuesIn(RegionDataConstants::GetRegionCodes()));
+
+// Verifies that the key "data" also contains valid data.
+TEST_F(TestdataSourceTest, GetExistingData) {
+ static const std::string kKey = "data";
+ source_.Get(kKey, *data_ready_);
+
+ EXPECT_TRUE(success_);
+ EXPECT_EQ(kKey, key_);
+ EXPECT_TRUE(DataIsValid(data_, kKey));
+}
+
+// Verifies that requesting a missing key will return "{}".
+TEST_F(TestdataSourceTest, GetMissingKeyReturnsEmptyDictionary) {
+ static const std::string kJunkKey = "junk";
+ source_.Get(kJunkKey, *data_ready_);
+
+ EXPECT_TRUE(success_);
+ EXPECT_EQ(kJunkKey, key_);
+ EXPECT_EQ("{}", data_);
+}
+
+// Verifies that aggregate requesting of a missing key will also return "{}".
+TEST_F(TestdataSourceTest, AggregateGetMissingKeyReturnsEmptyDictionary) {
+ static const std::string kJunkKey = "junk";
+ aggregate_source_.Get(kJunkKey, *data_ready_);
+
+ EXPECT_TRUE(success_);
+ EXPECT_EQ(kJunkKey, key_);
+ EXPECT_EQ("{}", data_);
+}
+
+// Verifies that requesting an empty key will return "{}".
+TEST_F(TestdataSourceTest, GetEmptyKeyReturnsEmptyDictionary) {
+ static const std::string kEmptyKey;
+ source_.Get(kEmptyKey, *data_ready_);
+
+ EXPECT_TRUE(success_);
+ EXPECT_EQ(kEmptyKey, key_);
+ EXPECT_EQ("{}", data_);
+}
+
+} // namespace
diff --git a/cpp/test/util/json_test.cc b/cpp/test/util/json_test.cc
index f6eb389..594c341 100644
--- a/cpp/test/util/json_test.cc
+++ b/cpp/test/util/json_test.cc
@@ -22,7 +22,6 @@
namespace {
using i18n::addressinput::Json;
-using i18n::addressinput::scoped_ptr;
TEST(JsonTest, EmptyStringIsNotValid) {
Json json;
@@ -32,8 +31,9 @@
TEST(JsonTest, EmptyDictionaryContainsNoKeys) {
Json json;
ASSERT_TRUE(json.ParseObject("{}"));
- EXPECT_FALSE(json.HasStringValueForKey("key"));
- EXPECT_FALSE(json.HasStringValueForKey(std::string()));
+ std::string not_checked;
+ EXPECT_FALSE(json.GetStringValueForKey("key", ¬_checked));
+ EXPECT_FALSE(json.GetStringValueForKey(std::string(), ¬_checked));
}
TEST(JsonTest, InvalidJsonIsNotValid) {
@@ -44,35 +44,40 @@
TEST(JsonTest, OneKeyIsValid) {
Json json;
ASSERT_TRUE(json.ParseObject("{\"key\": \"value\"}"));
- ASSERT_TRUE(json.HasStringValueForKey("key"));
- EXPECT_EQ("value", json.GetStringValueForKey("key"));
+ std::string value;
+ EXPECT_TRUE(json.GetStringValueForKey("key", &value));
+ EXPECT_EQ("value", value);
}
TEST(JsonTest, EmptyStringKeyIsNotInObject) {
Json json;
ASSERT_TRUE(json.ParseObject("{\"key\": \"value\"}"));
- EXPECT_FALSE(json.HasStringValueForKey(std::string()));
+ std::string not_checked;
+ EXPECT_FALSE(json.GetStringValueForKey(std::string(), ¬_checked));
}
TEST(JsonTest, EmptyKeyIsValid) {
Json json;
ASSERT_TRUE(json.ParseObject("{\"\": \"value\"}"));
- ASSERT_TRUE(json.HasStringValueForKey(std::string()));
- EXPECT_EQ("value", json.GetStringValueForKey(std::string()));
+ std::string value;
+ EXPECT_TRUE(json.GetStringValueForKey(std::string(), &value));
+ EXPECT_EQ("value", value);
}
TEST(JsonTest, EmptyValueIsValid) {
Json json;
ASSERT_TRUE(json.ParseObject("{\"key\": \"\"}"));
- ASSERT_TRUE(json.HasStringValueForKey("key"));
- EXPECT_TRUE(json.GetStringValueForKey("key").empty());
+ std::string value;
+ EXPECT_TRUE(json.GetStringValueForKey("key", &value));
+ EXPECT_TRUE(value.empty());
}
TEST(JsonTest, Utf8EncodingIsValid) {
Json json;
- ASSERT_TRUE(json.ParseObject("{\"key\": \"Ü\"}"));
- ASSERT_TRUE(json.HasStringValueForKey("key"));
- EXPECT_EQ("Ü", json.GetStringValueForKey("key"));
+ ASSERT_TRUE(json.ParseObject("{\"key\": \"\xC3\x9C\"}")); /* "Ü" */
+ std::string value;
+ EXPECT_TRUE(json.GetStringValueForKey("key", &value));
+ EXPECT_EQ("\xC3\x9C", value); /* "Ü" */
}
TEST(JsonTest, InvalidUtf8IsNotValid) {
@@ -89,11 +94,12 @@
TEST(JsonTest, TwoKeysAreValid) {
Json json;
ASSERT_TRUE(json.ParseObject("{\"key1\": \"value1\", \"key2\": \"value2\"}"));
- ASSERT_TRUE(json.HasStringValueForKey("key1"));
- EXPECT_EQ("value1", json.GetStringValueForKey("key1"));
+ std::string value;
+ EXPECT_TRUE(json.GetStringValueForKey("key1", &value));
+ EXPECT_EQ("value1", value);
- ASSERT_TRUE(json.HasStringValueForKey("key2"));
- EXPECT_EQ("value2", json.GetStringValueForKey("key2"));
+ EXPECT_TRUE(json.GetStringValueForKey("key2", &value));
+ EXPECT_EQ("value2", value);
}
TEST(JsonTest, ListIsNotValid) {
@@ -114,28 +120,35 @@
TEST(JsonTest, NoDictionaryFound) {
Json json;
ASSERT_TRUE(json.ParseObject("{\"key\":\"value\"}"));
- EXPECT_FALSE(json.HasDictionaryValueForKey("key"));
+ EXPECT_TRUE(json.GetSubDictionaries().empty());
}
TEST(JsonTest, DictionaryFound) {
Json json;
ASSERT_TRUE(json.ParseObject("{\"key\":{\"inner_key\":\"value\"}}"));
- ASSERT_TRUE(json.HasDictionaryValueForKey("key"));
- const Json& sub_json = json.GetDictionaryValueForKey("key");
- ASSERT_TRUE(sub_json.HasStringValueForKey("inner_key"));
- EXPECT_EQ("value", sub_json.GetStringValueForKey("inner_key"));
+ const std::vector<const Json*>& sub_dicts = json.GetSubDictionaries();
+ ASSERT_EQ(1U, sub_dicts.size());
+
+ std::string value;
+ EXPECT_TRUE(sub_dicts.front()->GetStringValueForKey("inner_key", &value));
+ EXPECT_EQ("value", value);
}
-TEST(JsonTest, DictionariesHaveKeys) {
+TEST(JsonTest, DictionariesHaveSubDictionaries) {
Json json;
- ASSERT_TRUE(json.ParseObject("{\"key\":{\"inner_key\":\"value\"}}"));
- std::vector<std::string> expected_keys(1, "key");
- EXPECT_EQ(expected_keys, json.GetKeys());
+ ASSERT_TRUE(json.ParseObject(
+ "{\"key\":{\"inner_key\":{\"inner_inner_key\":\"value\"}}}"));
+ const std::vector<const Json*>& sub_dicts = json.GetSubDictionaries();
+ ASSERT_EQ(1U, sub_dicts.size());
- ASSERT_TRUE(json.HasDictionaryValueForKey("key"));
- const Json& sub_json = json.GetDictionaryValueForKey("key");
- std::vector<std::string> expected_sub_keys(1, "inner_key");
- EXPECT_EQ(expected_sub_keys, sub_json.GetKeys());
+ const std::vector<const Json*>& sub_sub_dicts =
+ sub_dicts.front()->GetSubDictionaries();
+ ASSERT_EQ(1U, sub_sub_dicts.size());
+
+ std::string value;
+ EXPECT_TRUE(
+ sub_sub_dicts.front()->GetStringValueForKey("inner_inner_key", &value));
+ EXPECT_EQ("value", value);
}
} // namespace
diff --git a/cpp/test/util/scoped_ptr_unittest.cc b/cpp/test/util/scoped_ptr_unittest.cc
index 250ffca..633625c 100644
--- a/cpp/test/util/scoped_ptr_unittest.cc
+++ b/cpp/test/util/scoped_ptr_unittest.cc
@@ -9,6 +9,8 @@
#include <libaddressinput/util/basictypes.h>
+#include <cstddef>
+
#include <gtest/gtest.h>
namespace {
diff --git a/cpp/test/util/string_compare_test.cc b/cpp/test/util/string_compare_test.cc
index 8f8d4d5..b35b7df 100644
--- a/cpp/test/util/string_compare_test.cc
+++ b/cpp/test/util/string_compare_test.cc
@@ -14,6 +14,8 @@
#include "util/string_compare.h"
+#include <libaddressinput/util/basictypes.h>
+
#include <string>
#include <gtest/gtest.h>
@@ -42,7 +44,11 @@
class StringCompareTest : public testing::TestWithParam<TestCase> {
protected:
+ StringCompareTest() {}
StringCompare compare_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(StringCompareTest);
};
TEST_P(StringCompareTest, CorrectComparison) {
@@ -63,15 +69,39 @@
INSTANTIATE_TEST_CASE_P(
Comparisons, StringCompareTest,
- testing::Values(TestCase("foo", "foo", true, false),
- TestCase("foo", "FOO", true, false),
- TestCase("bar", "foo", false, true),
- TestCase("강원도", "강원도", true, false),
- TestCase("강원도", "대구광역시", false, true),
- TestCase("ZÜRICH", "zürich", true, false),
- TestCase("абв", "где", false, true),
- TestCase("абв", "ГДЕ", false, true),
- TestCase("где", "абв", false, false),
- TestCase("где", "АБВ", false, false)));
+ testing::Values(
+ TestCase("foo", "foo", true, false),
+ TestCase("foo", "FOO", true, false),
+ TestCase("bar", "foo", false, true),
+ TestCase(
+ "\xEA\xB0\x95\xEC\x9B\x90\xEB\x8F\x84", /* "강원도" */
+ "\xEA\xB0\x95\xEC\x9B\x90\xEB\x8F\x84", /* "강원도" */
+ true, false),
+ TestCase(
+ /* "강원도" */
+ "\xEA\xB0\x95\xEC\x9B\x90\xEB\x8F\x84",
+ /* "대구광역시" */
+ "\xEB\x8C\x80\xEA\xB5\xAC\xEA\xB4\x91\xEC\x97\xAD\xEC\x8B\x9C",
+ false, true),
+ TestCase(
+ "Z\xC3\x9CRICH", /* "ZÜRICH" */
+ "z\xC3\xBCrich", /* "zürich" */
+ true, false),
+ TestCase(
+ "\xD0\xB0\xD0\xB1\xD0\xB2", /* "абв" */
+ "\xD0\xB3\xD0\xB4\xD0\xB5", /* "где" */
+ false, true),
+ TestCase(
+ "\xD0\xB0\xD0\xB1\xD0\xB2", /* "абв" */
+ "\xD0\x93\xD0\x94\xD0\x95", /* "ГДЕ" */
+ false, true),
+ TestCase(
+ "\xD0\xB3\xD0\xB4\xD0\xB5", /* "где" */
+ "\xD0\xB0\xD0\xB1\xD0\xB2", /* "абв" */
+ false, false),
+ TestCase(
+ "\xD0\xB3\xD0\xB4\xD0\xB5", /* "где" */
+ "\xD0\x90\xD0\x91\xD0\x92", /* "АБВ" */
+ false, false)));
} // namespace
diff --git a/cpp/test/util/string_util_test.cc b/cpp/test/util/string_util_test.cc
index 9933b31..e7de1fc 100644
--- a/cpp/test/util/string_util_test.cc
+++ b/cpp/test/util/string_util_test.cc
@@ -15,6 +15,7 @@
#include "util/string_util.h"
#include <string>
+#include <vector>
#include <gtest/gtest.h>
diff --git a/cpp/test/validating_storage_test.cc b/cpp/test/validating_storage_test.cc
index ced22dc..3c8aa53 100644
--- a/cpp/test/validating_storage_test.cc
+++ b/cpp/test/validating_storage_test.cc
@@ -16,6 +16,7 @@
#include <libaddressinput/callback.h>
#include <libaddressinput/storage.h>
+#include <libaddressinput/util/basictypes.h>
#include <libaddressinput/util/scoped_ptr.h>
#include <cstddef>
@@ -45,26 +46,22 @@
const char kEmptyData[] = "";
// Tests for ValidatingStorage object.
-class ValidatingStorageTest : public testing::Test {
+class ValidatingStorageTest : public testing::Test {
protected:
ValidatingStorageTest()
: wrapped_storage_(new FakeStorage),
storage_(wrapped_storage_),
success_(false),
key_(),
- data_() {}
-
- virtual ~ValidatingStorageTest() {}
-
- ValidatingStorage::Callback* BuildCallback() {
- return ::BuildCallback(this, &ValidatingStorageTest::OnDataReady);
- }
+ data_(),
+ data_ready_(BuildCallback(this, &ValidatingStorageTest::OnDataReady)) {}
Storage* const wrapped_storage_; // Owned by |storage_|.
ValidatingStorage storage_;
bool success_;
std::string key_;
std::string data_;
+ const scoped_ptr<const ValidatingStorage::Callback> data_ready_;
private:
void OnDataReady(bool success, const std::string& key, std::string* data) {
@@ -76,13 +73,13 @@
delete data;
}
}
+
+ DISALLOW_COPY_AND_ASSIGN(ValidatingStorageTest);
};
TEST_F(ValidatingStorageTest, GoodData) {
storage_.Put(kKey, new std::string(kValidatedData));
-
- scoped_ptr<ValidatingStorage::Callback> callback(BuildCallback());
- storage_.Get(kKey, *callback);
+ storage_.Get(kKey, *data_ready_);
EXPECT_TRUE(success_);
EXPECT_EQ(kKey, key_);
@@ -91,9 +88,7 @@
TEST_F(ValidatingStorageTest, EmptyData) {
storage_.Put(kKey, new std::string(kEmptyData));
-
- scoped_ptr<ValidatingStorage::Callback> callback(BuildCallback());
- storage_.Get(kKey, *callback);
+ storage_.Get(kKey, *data_ready_);
EXPECT_TRUE(success_);
EXPECT_EQ(kKey, key_);
@@ -101,8 +96,7 @@
}
TEST_F(ValidatingStorageTest, MissingKey) {
- scoped_ptr<ValidatingStorage::Callback> callback(BuildCallback());
- storage_.Get(kKey, *callback);
+ storage_.Get(kKey, *data_ready_);
EXPECT_FALSE(success_);
EXPECT_EQ(kKey, key_);
@@ -112,9 +106,7 @@
TEST_F(ValidatingStorageTest, GarbageData) {
storage_.Put(kKey, new std::string(kValidatedData));
wrapped_storage_->Put(kKey, new std::string("garbage"));
-
- scoped_ptr<ValidatingStorage::Callback> callback(BuildCallback());
- storage_.Get(kKey, *callback);
+ storage_.Get(kKey, *data_ready_);
EXPECT_FALSE(success_);
EXPECT_EQ(kKey, key_);
@@ -124,9 +116,7 @@
TEST_F(ValidatingStorageTest, StaleData) {
storage_.Put(kKey, new std::string(kValidatedData));
wrapped_storage_->Put(kKey, new std::string(kStaleWrappedData));
-
- scoped_ptr<ValidatingStorage::Callback> callback(BuildCallback());
- storage_.Get(kKey, *callback);
+ storage_.Get(kKey, *data_ready_);
EXPECT_FALSE(success_);
EXPECT_EQ(kKey, key_);
diff --git a/cpp/test/validation_task_test.cc b/cpp/test/validation_task_test.cc
index 011a978..9caf996 100644
--- a/cpp/test/validation_task_test.cc
+++ b/cpp/test/validation_task_test.cc
@@ -34,8 +34,6 @@
namespace i18n {
namespace addressinput {
-class LookupKey;
-
class ValidationTaskTest : public testing::Test {
protected:
ValidationTaskTest()
@@ -59,6 +57,7 @@
SORTING_CODE,
POSTAL_CODE,
STREET_ADDRESS,
+ ORGANIZATION,
RECIPIENT
};
@@ -85,8 +84,6 @@
filter_.insert(std::make_pair(RECIPIENT, MISSING_REQUIRED_FIELD));
}
- virtual ~ValidationTaskTest() {}
-
void Validate() {
Rule rule[arraysize(json_)];
@@ -217,12 +214,14 @@
address_.locality = "ccc";
address_.postal_code = "zzz";
address_.address_line.push_back("aaa");
+ address_.organization = "ooo";
address_.recipient = "nnn";
filter_.insert(std::make_pair(ADMIN_AREA, MISSING_REQUIRED_FIELD));
filter_.insert(std::make_pair(LOCALITY, MISSING_REQUIRED_FIELD));
filter_.insert(std::make_pair(POSTAL_CODE, MISSING_REQUIRED_FIELD));
filter_.insert(std::make_pair(STREET_ADDRESS, MISSING_REQUIRED_FIELD));
+ filter_.insert(std::make_pair(ORGANIZATION, MISSING_REQUIRED_FIELD));
ASSERT_NO_FATAL_FAILURE(Validate());
ASSERT_TRUE(called_);
diff --git a/java/res/values/address_strings.xml b/java/res/values/address_strings.xml
index 57b34c4..f12247a 100644
--- a/java/res/values/address_strings.xml
+++ b/java/res/values/address_strings.xml
@@ -80,6 +80,9 @@
<!-- Administrative Area for certain countries (e.g., Bahama's Cat Island) [CHAR LIMIT=30] -->
<string name="i18n_island">Island</string>
+ <!-- Administrative Area for certain countries (e.g., Russia's Leningrad) [CHAR LIMIT=30] -->
+ <string name="i18n_oblast">Oblast</string>
+
<!-- Administrative Area for certain countries (e.g., Andorra's Canillo) [CHAR LIMIT=30] -->
<string name="i18n_parish">Parish</string>
@@ -140,6 +143,10 @@
(e.g., Bahama) is entered incorrectly by the user [CHAR LIMIT=30] -->
<string name="invalid_island">Invalid island</string>
+ <!-- Message to be shown when the administrative area (oblast) for certain countries
+ (e.g., Russia) is entered incorrectly by the user [CHAR LIMIT=30] -->
+ <string name="invalid_oblast">Invalid oblast</string>
+
<!-- Message to be shown when the administrative area (parish) for certain countries
(e.g., Andorra) is entered incorrectly by the user [CHAR LIMIT=30] -->
<string name="invalid_parish">Invalid parish</string>
diff --git a/java/src/com/android/i18n/addressinput/AddressDataKey.java b/java/src/com/android/i18n/addressinput/AddressDataKey.java
index 33ffd74..a4766af 100644
--- a/java/src/com/android/i18n/addressinput/AddressDataKey.java
+++ b/java/src/com/android/i18n/addressinput/AddressDataKey.java
@@ -56,11 +56,15 @@
*/
LFMT,
/**
+ * Indicates the type of the name used for the locality (city) field.
+ */
+ LOCALITY_NAME_TYPE,
+ /**
* Indicates which fields must be present in a valid address.
*/
REQUIRE,
/**
- * Indicates the name used for the admin areas for a particular region.
+ * Indicates the type of the name used for the state (administrative area) field.
*/
STATE_NAME_TYPE,
/**
@@ -90,7 +94,7 @@
*/
ZIP,
/**
- * Indicates the name used for the postal code for a particular region.
+ * Indicates the type of the name used for the ZIP (postal code) field.
*/
ZIP_NAME_TYPE;
diff --git a/java/src/com/android/i18n/addressinput/AddressField.java b/java/src/com/android/i18n/addressinput/AddressField.java
index b951021..17b1817 100644
--- a/java/src/com/android/i18n/addressinput/AddressField.java
+++ b/java/src/com/android/i18n/addressinput/AddressField.java
@@ -24,14 +24,14 @@
* formatting. Note that the metadata also has a character for newlines, which is not defined here.
*/
public enum AddressField {
- ADMIN_AREA('S', "state"),
- LOCALITY('C', "city"),
- RECIPIENT('N', "name"),
- ORGANIZATION('O', "organization"),
+ ADMIN_AREA('S'),
+ LOCALITY('C'),
+ RECIPIENT('N'),
+ ORGANIZATION('O'),
// Deprecated - use A instead.
- ADDRESS_LINE_1('1', "street1"),
+ ADDRESS_LINE_1('1'),
// Deprecated - use A instead.
- ADDRESS_LINE_2('2', "street2"),
+ ADDRESS_LINE_2('2'),
DEPENDENT_LOCALITY('D'),
POSTAL_CODE('Z'),
SORTING_CODE('X'),
@@ -58,15 +58,8 @@
private final char mField;
- private final String mAttributeName;
-
- private AddressField(char field, String attributeName) {
- mField = field;
- mAttributeName = attributeName;
- }
-
private AddressField(char field) {
- this(field, null);
+ mField = field;
}
/**
@@ -78,17 +71,6 @@
}
/**
- * Gets attribute name. Attribute names are used as keys to JSON address data returned from the
- * server. Returns null if the field does not have a corresponding attribute name.
- *
- * Note: Not all address fields have attribute names. Fields like postal code, country, sorting
- * code, or street address do not have attribute names.
- */
- String getAttributeName() {
- return mAttributeName;
- }
-
- /**
* Gets the field's identification character, as used in the metadata.
*
* @return identification char.
diff --git a/java/src/com/android/i18n/addressinput/AddressWidget.java b/java/src/com/android/i18n/addressinput/AddressWidget.java
index 2ebfeef..c377e2c 100644
--- a/java/src/com/android/i18n/addressinput/AddressWidget.java
+++ b/java/src/com/android/i18n/addressinput/AddressWidget.java
@@ -81,11 +81,16 @@
private ScriptType mScript;
+ // The appropriate label that should be applied to the locality (city) field of the current
+ // country. Examples include "city" or "district".
+ private String mLocalityLabel;
+
// The appropriate label that should be applied to the admin area field of the current country.
// Examples include "state", "province", "emirate", etc.
private String mAdminLabel;
private static final Map<String, Integer> ADMIN_LABELS;
+ private static final Map<String, Integer> LOCALITY_LABELS;
private static final Map<String, Integer> ADMIN_ERROR_MESSAGES;
private static final FormOptions SHOW_ALL_FIELDS = new FormOptions.Builder().build();
@@ -107,12 +112,18 @@
adminLabelMap.put("do_si", R.string.i18n_do_si);
adminLabelMap.put("emirate", R.string.i18n_emirate);
adminLabelMap.put("island", R.string.i18n_island);
+ adminLabelMap.put("oblast", R.string.i18n_oblast);
adminLabelMap.put("parish", R.string.i18n_parish);
adminLabelMap.put("prefecture", R.string.i18n_prefecture);
adminLabelMap.put("province", R.string.i18n_province);
adminLabelMap.put("state", R.string.i18n_state_label);
ADMIN_LABELS = Collections.unmodifiableMap(adminLabelMap);
+ Map<String, Integer> localityLabelMap = new HashMap<String, Integer>(2);
+ localityLabelMap.put("city", R.string.i18n_locality_label);
+ localityLabelMap.put("district", R.string.i18n_dependent_locality_label);
+ LOCALITY_LABELS = Collections.unmodifiableMap(localityLabelMap);
+
Map<String, Integer> adminErrorMap = new HashMap<String, Integer>(15);
adminErrorMap.put("area", R.string.invalid_area);
adminErrorMap.put("county", R.string.invalid_county_label);
@@ -121,6 +132,7 @@
adminErrorMap.put("do_si", R.string.invalid_do_si);
adminErrorMap.put("emirate", R.string.invalid_emirate);
adminErrorMap.put("island", R.string.invalid_island);
+ adminErrorMap.put("oblast", R.string.invalid_oblast);
adminErrorMap.put("parish", R.string.invalid_parish);
adminErrorMap.put("prefecture", R.string.invalid_prefecture);
adminErrorMap.put("province", R.string.invalid_province);
@@ -266,7 +278,7 @@
// Set up AddressField.LOCALITY
AddressUiComponent localityUi = new AddressUiComponent(AddressField.LOCALITY);
- localityUi.setFieldName(mContext.getString(R.string.i18n_locality_label));
+ localityUi.setFieldName(getLocalityFieldName(countryNode));
mInputWidgets.put(AddressField.LOCALITY, localityUi);
// Set up AddressField.DEPENDENT_LOCALITY
@@ -330,6 +342,17 @@
return zipName;
}
+ private String getLocalityFieldName(AddressVerificationNodeData countryNode) {
+ String localityLabelType = countryNode.get(AddressDataKey.LOCALITY_NAME_TYPE);
+ mLocalityLabel = localityLabelType;
+ Integer result = LOCALITY_LABELS.get(localityLabelType);
+ if (result == null) {
+ // Fallback to city.
+ result = R.string.i18n_locality_label;
+ }
+ return mContext.getString(result);
+ }
+
private String getAdminAreaFieldName(AddressVerificationNodeData countryNode) {
String adminLabelType = countryNode.get(AddressDataKey.STATE_NAME_TYPE);
mAdminLabel = adminLabelType;
diff --git a/java/src/com/android/i18n/addressinput/FormatInterpreter.java b/java/src/com/android/i18n/addressinput/FormatInterpreter.java
index ffd19b1..ed7b2ac 100644
--- a/java/src/com/android/i18n/addressinput/FormatInterpreter.java
+++ b/java/src/com/android/i18n/addressinput/FormatInterpreter.java
@@ -155,15 +155,16 @@
List<String> lines = new ArrayList<String>();
StringBuilder currentLine = new StringBuilder();
- for (String substr : getFormatSubStrings(scriptType, regionCode)) {
- if (substr.equals(NEW_LINE)) {
- String normalizedStr = removeAllRedundantSpaces(currentLine.toString());
+ for (String formatSymbol : getFormatSubStrings(scriptType, regionCode)) {
+ if (formatSymbol.equals(NEW_LINE)) {
+ String normalizedStr =
+ removeRedundantSpacesAndLeadingPunctuation(currentLine.toString());
if (normalizedStr.length() > 0) {
lines.add(normalizedStr);
currentLine.setLength(0);
}
- } else if (substr.startsWith("%")) {
- char c = substr.charAt(1);
+ } else if (formatSymbol.startsWith("%")) {
+ char c = formatSymbol.charAt(1);
AddressField field = AddressField.of(c);
Util.checkNotNull(field, "null address field for character " + c);
@@ -203,10 +204,10 @@
currentLine.append(value);
}
} else {
- currentLine.append(substr);
+ currentLine.append(formatSymbol);
}
}
- String normalizedStr = removeAllRedundantSpaces(currentLine.toString());
+ String normalizedStr = removeRedundantSpacesAndLeadingPunctuation(currentLine.toString());
if (normalizedStr.length() > 0) {
lines.add(normalizedStr);
}
@@ -242,13 +243,16 @@
return parts;
}
- private String removeAllRedundantSpaces(String str) {
+ private static String removeRedundantSpacesAndLeadingPunctuation(String str) {
+ // Remove leading commas and other punctuation that might have been added by the formatter
+ // in the case of missing data.
+ str = str.replaceFirst("^[-,\\s]+", "");
str = str.trim();
str = str.replaceAll(" +", " ");
return str;
}
- private String getFormatString(ScriptType scriptType, String regionCode) {
+ private static String getFormatString(ScriptType scriptType, String regionCode) {
String format = (scriptType == ScriptType.LOCAL)
? getJsonValue(regionCode, AddressDataKey.FMT)
: getJsonValue(regionCode, AddressDataKey.LFMT);
@@ -258,7 +262,7 @@
return format;
}
- private String getJsonValue(String regionCode, AddressDataKey key) {
+ private static String getJsonValue(String regionCode, AddressDataKey key) {
Util.checkNotNull(regionCode);
String jsonString = RegionDataConstants.getCountryFormatMap().get(regionCode);
Util.checkNotNull(jsonString, "no json data for region code " + regionCode);
diff --git a/java/src/com/android/i18n/addressinput/RegionDataConstants.java b/java/src/com/android/i18n/addressinput/RegionDataConstants.java
index 48affab..4f4c5b7 100644
--- a/java/src/com/android/i18n/addressinput/RegionDataConstants.java
+++ b/java/src/com/android/i18n/addressinput/RegionDataConstants.java
@@ -41,10 +41,8 @@
"name", "ANDORRA",
"lang", "ca",
"languages", "ca",
- "fmt", "%N%n%O%n%A%n%Z %S",
- "require", "AS",
- "upper", "S",
- "state_name_type", "parish",
+ "fmt", "%N%n%O%n%A%n%Z %C",
+ "require", "A",
}),
AE(new String[]{
"name", "UNITED ARAB EMIRATES",
@@ -311,7 +309,7 @@
}),
DK(new String[]{
"name", "DENMARK",
- "fmt", "%O%n%N%n%A%n%Z %C",
+ "fmt", "%N%n%O%n%A%n%Z %C",
"require", "ACZ",
}),
DM(new String[]{
@@ -977,8 +975,9 @@
}),
RU(new String[]{
"name", "RUSSIAN FEDERATION",
- "fmt", "%Z %C %n%A%n%O%n%N",
+ "fmt", "%N%n%O%n%A%n%C%n%S%n%Z",
"require", "ACZ",
+ "state_name_type", "oblast",
"upper", "AC",
}),
RW(new String[]{
@@ -1124,6 +1123,7 @@
"name", "TURKEY",
"fmt", "%N%n%O%n%A%n%Z %C/%S",
"require", "ACZ",
+ "locality_name_type", "district",
}),
TT(new String[]{
"name", "TRINIDAD AND TOBAGO",
@@ -1167,7 +1167,7 @@
"name", "UNITED STATES",
"lang", "en",
"languages", "en",
- "fmt", "%N%n%O%n%A%n%C %S %Z",
+ "fmt", "%N%n%O%n%A%n%C, %S %Z",
"require", "ACSZ",
"upper", "CS",
"zip_name_type", "zip",
@@ -1269,6 +1269,7 @@
"upper", "C",
"zip_name_type", "postal",
"state_name_type", "province",
+ "locality_name_type", "city",
});
private String jsonString;
diff --git a/java/test/com/android/i18n/addressinput/AddressFieldTest.java b/java/test/com/android/i18n/addressinput/AddressFieldTest.java
index 3419097..aa0a741 100644
--- a/java/test/com/android/i18n/addressinput/AddressFieldTest.java
+++ b/java/test/com/android/i18n/addressinput/AddressFieldTest.java
@@ -30,8 +30,4 @@
public void testGetChar() throws Exception {
assertEquals('R', AddressField.COUNTRY.getChar());
}
-
- public void testGetAttributeName() throws Exception {
- assertEquals("name", AddressField.RECIPIENT.getAttributeName());
- }
}
diff --git a/java/test/com/android/i18n/addressinput/ClientDataTest.java b/java/test/com/android/i18n/addressinput/ClientDataTest.java
index 570434e..b18d726 100644
--- a/java/test/com/android/i18n/addressinput/ClientDataTest.java
+++ b/java/test/com/android/i18n/addressinput/ClientDataTest.java
@@ -78,6 +78,6 @@
// data from there.
assertNotNull(data);
String unitedStatesFormatInfo = data.get(AddressDataKey.FMT);
- assertEquals("%N%n%O%n%A%n%C %S %Z", unitedStatesFormatInfo);
+ assertEquals("%N%n%O%n%A%n%C, %S %Z", unitedStatesFormatInfo);
}
}
diff --git a/java/test/com/android/i18n/addressinput/FormatInterpreterTest.java b/java/test/com/android/i18n/addressinput/FormatInterpreterTest.java
index 50372ed..f5bac79 100644
--- a/java/test/com/android/i18n/addressinput/FormatInterpreterTest.java
+++ b/java/test/com/android/i18n/addressinput/FormatInterpreterTest.java
@@ -147,7 +147,7 @@
public void testUsEnvelopeAddress() {
List<String> expected = new ArrayList<String>();
expected.add("1098 Alta Ave");
- expected.add("Mt View CA 94043");
+ expected.add("Mt View, CA 94043");
List<String> real = formatInterpreter.getEnvelopeAddress(US_CA_ADDRESS);
@@ -189,4 +189,44 @@
List<String> real = formatInterpreter.getEnvelopeAddress(address);
assertEquals(expected, real);
}
+
+ public void testEnvelopeAddressLeadingPostPrefix() {
+ List<String> expected = new ArrayList<String>();
+ expected.add("CH-8047 Herrliberg");
+ AddressData address = new AddressData.Builder().setCountry("CH")
+ .setPostalCode("8047")
+ .setLocality("Herrliberg")
+ .build();
+
+ List<String> real = formatInterpreter.getEnvelopeAddress(address);
+ assertEquals(expected, real);
+ }
+
+ public void testSvAddress() {
+ final AddressData svAddress = new AddressData.Builder().setCountry("SV")
+ .setAdminArea("Ahuachapán")
+ .setLocality("Ahuachapán")
+ .setAddressLine1("Some Street 12")
+ .build();
+
+ List<String> expected = new ArrayList<String>();
+ expected.add("Some Street 12");
+ expected.add("Ahuachapán");
+ expected.add("Ahuachapán");
+
+ List<String> real = formatInterpreter.getEnvelopeAddress(svAddress);
+ assertEquals(expected, real);
+
+ final AddressData svAddressWithPostCode = new AddressData.Builder(svAddress)
+ .setPostalCode("CP 2101")
+ .build();
+
+ expected = new ArrayList<String>();
+ expected.add("Some Street 12");
+ expected.add("CP 2101-Ahuachapán");
+ expected.add("Ahuachapán");
+
+ real = formatInterpreter.getEnvelopeAddress(svAddressWithPostCode);
+ assertEquals(expected, real);
+ }
}