Convert libaddressinput validation error codes into error messages.
diff --git a/cpp/include/libaddressinput/address_data.h b/cpp/include/libaddressinput/address_data.h
index ea371fe..5718dd3 100644
--- a/cpp/include/libaddressinput/address_data.h
+++ b/cpp/include/libaddressinput/address_data.h
@@ -68,6 +68,11 @@
// which comprises multiple fields (will crash otherwise).
const std::vector<std::string>& GetRepeatedFieldValue(
AddressField field) const;
+
+ // Returns true if the parameter comprises multiple fields, false otherwise.
+ // Use it to determine whether to call |GetFieldValue| or
+ // |GetRepeatedFieldValue|.
+ static bool IsRepeatedFieldValue(AddressField field);
};
} // namespace addressinput
diff --git a/cpp/include/libaddressinput/localization.h b/cpp/include/libaddressinput/localization.h
index 77a1917..c25ad4a 100644
--- a/cpp/include/libaddressinput/localization.h
+++ b/cpp/include/libaddressinput/localization.h
@@ -15,11 +15,17 @@
#ifndef I18N_ADDRESSINPUT_LOCALIZATION_H_
#define I18N_ADDRESSINPUT_LOCALIZATION_H_
+#include <libaddressinput/address_field.h>
+#include <libaddressinput/address_problem.h>
+
#include <string>
+#include <vector>
namespace i18n {
namespace addressinput {
+struct AddressData;
+
// The object to retrieve localized strings based on message IDs. Sample usage:
// Localization localization;
// localization.SetLanguage("en");
@@ -41,6 +47,22 @@
// there's no message with this identifier.
std::string GetString(int message_id) const;
+ // Returns the error message. If |enable_examples| is false, then the error
+ // message will not contain examples of valid input. If |enable_links| is
+ // false, then the error message will not contain HTML links. (Some error
+ // messages contain postal code examples or link to post office websites to
+ // look up the postal code for an address). Vector field values (e.g. for
+ // street address) should not be empty if problem is UNKNOWN_VALUE. The
+ // POSTAL_CODE field should only be used with MISSING_REQUIRED_FIELD,
+ // INVALID_FORMAT, and MISMATCHING_VALUE problem codes. All other fields
+ // should only be used with MISSING_REQUIRED_FIELD, UNKNOWN_VALUE, and
+ // USES_P_O_BOX problem codes.
+ std::string GetErrorMessage(const AddressData& address,
+ AddressField field,
+ AddressProblem problem,
+ bool enable_examples,
+ bool enable_links);
+
// Sets the language for the strings. The only supported language is "en"
// until we have translations.
void SetLanguage(const std::string& language_tag);
@@ -54,6 +76,22 @@
const std::string& GetLanguage() const { return language_tag_; }
private:
+ // Returns the error message where the address field is a postal code. Helper
+ // to |GetErrorMessage|. If |postal_code_example| is empty, then the error
+ // message will not contain examples of valid postal codes. If
+ // |post_service_url| is empty, then the error message will not contain a post
+ // service URL. The problem should only be one of MISSING_REQUIRED_FIELD,
+ // INVALID_FORMAT, or MISMATCHING_VALUE.
+ std::string GetErrorMessageForPostalCode(const AddressData& address,
+ AddressProblem problem,
+ bool uses_postal_code_as_label,
+ std::string postal_code_example,
+ std::string post_service_url);
+
+ // Calls |parameters.push_back| with 2 strings: the opening and closing tags
+ // of the given URL's HTML link.
+ void PushBackUrl(std::vector<std::string>& parameters, const std::string url);
+
// The string getter.
std::string (*get_string_)(int);
diff --git a/cpp/src/address_data.cc b/cpp/src/address_data.cc
index 8e2fdc6..7c285b8 100644
--- a/cpp/src/address_data.cc
+++ b/cpp/src/address_data.cc
@@ -97,5 +97,10 @@
return this->*kVectorStringField[field];
}
+// static
+bool AddressData::IsRepeatedFieldValue(AddressField field) {
+ return field == STREET_ADDRESS;
+}
+
} // namespace addressinput
} // namespace i18n
diff --git a/cpp/src/address_ui.cc b/cpp/src/address_ui.cc
index 7933794..d515765 100644
--- a/cpp/src/address_ui.cc
+++ b/cpp/src/address_ui.cc
@@ -37,10 +37,10 @@
namespace {
-std::string GetString(const Localization& localization,
- AddressField field,
- int admin_area_name_message_id,
- int postal_code_name_message_id) {
+std::string GetLabelForField(const Localization& localization,
+ AddressField field,
+ int admin_area_name_message_id,
+ int postal_code_name_message_id) {
int messageId;
switch (field) {
case SORTING_CODE:
@@ -126,7 +126,7 @@
: AddressUiComponent::HINT_SHORT;
preceded_by_newline = false;
component.field = format_it->GetField();
- component.name = GetString(localization, format_it->GetField(),
+ component.name = GetLabelForField(localization, format_it->GetField(),
rule.GetAdminAreaNameMessageId(), rule.GetPostalCodeNameMessageId());
result.push_back(component);
}
diff --git a/cpp/src/localization.cc b/cpp/src/localization.cc
index 1558b23..6b16e35 100644
--- a/cpp/src/localization.cc
+++ b/cpp/src/localization.cc
@@ -14,10 +14,19 @@
#include <libaddressinput/localization.h>
+#include <libaddressinput/address_data.h>
+#include <libaddressinput/address_field.h>
+#include <libaddressinput/address_problem.h>
+
#include <cassert>
#include <cstddef>
#include <string>
+#include "grit.h"
+#include "region_data_constants.h"
+#include "rule.h"
+#include "util/string_util.h"
+
namespace i18n {
namespace addressinput {
@@ -52,6 +61,57 @@
return get_string_(message_id);
}
+std::string Localization::GetErrorMessage(const AddressData& address,
+ AddressField field,
+ AddressProblem problem,
+ bool enable_examples,
+ bool enable_links) {
+ if (field == POSTAL_CODE) {
+ Rule rule;
+ rule.CopyFrom(Rule::GetDefault());
+ std::string postal_code_example, post_service_url;
+ if (rule.ParseSerializedRule(
+ RegionDataConstants::GetRegionData(address.region_code))) {
+ if (enable_examples) {
+ postal_code_example = rule.GetPostalCodeExample();
+ }
+ if (enable_links) {
+ post_service_url = rule.GetPostServiceUrl();
+ }
+ }
+ // If we can't parse the serialized rule |uses_postal_code_as_label| will be
+ // determined from the default rule.
+ bool uses_postal_code_as_label =
+ rule.GetPostalCodeNameMessageId() ==
+ IDS_LIBADDRESSINPUT_POSTAL_CODE_LABEL;
+ return GetErrorMessageForPostalCode(address, problem,
+ uses_postal_code_as_label,
+ postal_code_example, post_service_url);
+ } else {
+ if (problem == MISSING_REQUIRED_FIELD) {
+ return get_string_(IDS_LIBADDRESSINPUT_MISSING_REQUIRED_FIELD);
+ } else if (problem == UNKNOWN_VALUE) {
+ std::vector<std::string> parameters;
+ if (AddressData::IsRepeatedFieldValue(field)) {
+ std::vector<std::string> values = address.GetRepeatedFieldValue(field);
+ assert(!values.empty());
+ parameters.push_back(values.front());
+ } else {
+ parameters.push_back(address.GetFieldValue(field));
+ }
+ return DoReplaceStringPlaceholders(
+ get_string_(IDS_LIBADDRESSINPUT_UNKNOWN_VALUE), parameters);
+ } else if (problem == USES_P_O_BOX) {
+ return get_string_(IDS_LIBADDRESSINPUT_PO_BOX_FORBIDDEN_VALUE);
+ } else {
+ // Keep the default under "else" so the compiler helps us check that all
+ // handled cases return and don't fall through.
+ assert(false);
+ return "";
+ }
+ }
+}
+
void Localization::SetLanguage(const std::string& language_tag) {
if (language_tag == kDefaultLanguage) {
get_string_ = &en::GetStdString;
@@ -68,5 +128,74 @@
language_tag_ = language_tag;
}
+std::string Localization::GetErrorMessageForPostalCode(
+ const AddressData& address,
+ AddressProblem problem,
+ bool uses_postal_code_as_label,
+ std::string postal_code_example,
+ std::string post_service_url) {
+ int message_id;
+ std::vector<std::string> parameters;
+ if (problem == MISSING_REQUIRED_FIELD) {
+ if (!postal_code_example.empty() && !post_service_url.empty()) {
+ message_id = uses_postal_code_as_label ?
+ IDS_LIBADDRESSINPUT_MISSING_REQUIRED_POSTAL_CODE_EXAMPLE_AND_URL :
+ IDS_LIBADDRESSINPUT_MISSING_REQUIRED_ZIP_CODE_EXAMPLE_AND_URL;
+ parameters.push_back(postal_code_example);
+ Localization::PushBackUrl(parameters, post_service_url);
+ } else if (!postal_code_example.empty()) {
+ message_id = uses_postal_code_as_label ?
+ IDS_LIBADDRESSINPUT_MISSING_REQUIRED_POSTAL_CODE_EXAMPLE :
+ IDS_LIBADDRESSINPUT_MISSING_REQUIRED_ZIP_CODE_EXAMPLE ;
+ parameters.push_back(postal_code_example);
+ } else {
+ message_id = IDS_LIBADDRESSINPUT_MISSING_REQUIRED_FIELD;
+ }
+ return DoReplaceStringPlaceholders(get_string_(message_id), parameters);
+ } else if (problem == INVALID_FORMAT) {
+ if (!postal_code_example.empty() && !post_service_url.empty()) {
+ message_id = uses_postal_code_as_label ?
+ IDS_LIBADDRESSINPUT_UNRECOGNIZED_FORMAT_POSTAL_CODE_EXAMPLE_AND_URL :
+ IDS_LIBADDRESSINPUT_UNRECOGNIZED_FORMAT_ZIP_CODE_EXAMPLE_AND_URL;
+ parameters.push_back(postal_code_example);
+ Localization::PushBackUrl(parameters, post_service_url);
+ } else if (!postal_code_example.empty()) {
+ message_id = uses_postal_code_as_label ?
+ IDS_LIBADDRESSINPUT_UNRECOGNIZED_FORMAT_POSTAL_CODE_EXAMPLE :
+ IDS_LIBADDRESSINPUT_UNRECOGNIZED_FORMAT_ZIP_CODE_EXAMPLE;
+ parameters.push_back(postal_code_example);
+ } else {
+ message_id = uses_postal_code_as_label ?
+ IDS_LIBADDRESSINPUT_UNRECOGNIZED_FORMAT_POSTAL_CODE :
+ IDS_LIBADDRESSINPUT_UNRECOGNIZED_FORMAT_ZIP;
+ }
+ return DoReplaceStringPlaceholders(get_string_(message_id), parameters);
+ } else if (problem == MISMATCHING_VALUE) {
+ if (!post_service_url.empty()) {
+ message_id = uses_postal_code_as_label ?
+ IDS_LIBADDRESSINPUT_MISMATCHING_VALUE_POSTAL_CODE_URL :
+ IDS_LIBADDRESSINPUT_MISMATCHING_VALUE_ZIP_URL;
+ Localization::PushBackUrl(parameters, post_service_url);
+ } else {
+ message_id = uses_postal_code_as_label ?
+ IDS_LIBADDRESSINPUT_MISMATCHING_VALUE_POSTAL_CODE :
+ IDS_LIBADDRESSINPUT_MISMATCHING_VALUE_ZIP;
+ }
+ return DoReplaceStringPlaceholders(get_string_(message_id), parameters);
+ } else {
+ // Keep the default under "else" so the compiler helps us check that all
+ // handled cases return and don't fall through.
+ assert(false);
+ return "";
+ }
+}
+
+void Localization::PushBackUrl(std::vector<std::string>& parameters,
+ const std::string url) {
+ // TODO: HTML-escape the "url".
+ parameters.push_back("<a href=\"" + url + "\">");
+ parameters.push_back("</a>");
+}
+
} // namespace addressinput
} // namespace i18n
diff --git a/cpp/src/rule.cc b/cpp/src/rule.cc
index 614f400..68d34a9 100644
--- a/cpp/src/rule.cc
+++ b/cpp/src/rule.cc
@@ -48,6 +48,8 @@
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".
@@ -119,7 +121,9 @@
admin_area_name_message_id_(INVALID_MESSAGE_ID),
postal_code_name_message_id_(INVALID_MESSAGE_ID),
name_(),
- latin_name_() {}
+ latin_name_(),
+ postal_code_example_(),
+ post_service_url_() {}
Rule::~Rule() {}
@@ -151,6 +155,8 @@
postal_code_name_message_id_ = rule.postal_code_name_message_id_;
name_ = rule.name_;
latin_name_ = rule.latin_name_;
+ postal_code_example_ = rule.postal_code_example_;
+ post_service_url_ = rule.post_service_url_;
}
bool Rule::ParseSerializedRule(const std::string& serialized_rule) {
@@ -233,6 +239,14 @@
if (json.HasStringValueForKey(kLatinNameKey)) {
latin_name_ = json.GetStringValueForKey(kLatinNameKey);
}
+
+ if (json.HasStringValueForKey(kPostalCodeExampleKey)) {
+ postal_code_example_ = json.GetStringValueForKey(kPostalCodeExampleKey);
+ }
+
+ if (json.HasStringValueForKey(kPostServiceUrlKey)) {
+ post_service_url_ = json.GetStringValueForKey(kPostServiceUrlKey);
+ }
}
} // namespace addressinput
diff --git a/cpp/src/rule.h b/cpp/src/rule.h
index 6e57d70..4954b98 100644
--- a/cpp/src/rule.h
+++ b/cpp/src/rule.h
@@ -116,6 +116,16 @@
// rule, if there is one.
const std::string& GetLatinName() const { return latin_name_; }
+ // Returns the postal code example string for this rule.
+ const std::string& GetPostalCodeExample() const {
+ return postal_code_example_;
+ }
+
+ // Returns the post service URL string for this rule.
+ const std::string& GetPostServiceUrl() const {
+ return post_service_url_;
+ }
+
private:
std::string id_;
std::vector<FormatElement> format_;
@@ -128,6 +138,8 @@
int postal_code_name_message_id_;
std::string name_;
std::string latin_name_;
+ std::string postal_code_example_;
+ std::string post_service_url_;
DISALLOW_COPY_AND_ASSIGN(Rule);
};
diff --git a/cpp/test/localization_test.cc b/cpp/test/localization_test.cc
index 6be9d2c..e4d866c 100644
--- a/cpp/test/localization_test.cc
+++ b/cpp/test/localization_test.cc
@@ -14,6 +14,10 @@
#include <libaddressinput/localization.h>
+#include <libaddressinput/address_data.h>
+#include <libaddressinput/address_field.h>
+#include <libaddressinput/address_problem.h>
+
#include <string>
#include <gtest/gtest.h>
@@ -23,8 +27,24 @@
namespace {
+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::SORTING_CODE;
+using i18n::addressinput::STREET_ADDRESS;
+using i18n::addressinput::UNKNOWN_VALUE;
+using i18n::addressinput::USES_P_O_BOX;
// Tests for Localization object.
class LocalizationTest : public testing::TestWithParam<int> {
@@ -57,23 +77,41 @@
// Tests all message identifiers.
INSTANTIATE_TEST_CASE_P(
AllMessages, LocalizationTest,
- testing::Values(IDS_LIBADDRESSINPUT_COUNTRY_OR_REGION_LABEL,
- IDS_LIBADDRESSINPUT_LOCALITY_LABEL,
- IDS_LIBADDRESSINPUT_DISTRICT,
- IDS_LIBADDRESSINPUT_RECIPIENT_LABEL,
- IDS_LIBADDRESSINPUT_ADDRESS_LINE_1_LABEL,
- IDS_LIBADDRESSINPUT_POSTAL_CODE_LABEL,
- IDS_LIBADDRESSINPUT_ZIP_CODE_LABEL,
- IDS_LIBADDRESSINPUT_AREA,
- IDS_LIBADDRESSINPUT_COUNTY,
- IDS_LIBADDRESSINPUT_DEPARTMENT,
- IDS_LIBADDRESSINPUT_DO_SI,
- IDS_LIBADDRESSINPUT_EMIRATE,
- IDS_LIBADDRESSINPUT_ISLAND,
- IDS_LIBADDRESSINPUT_PARISH,
- IDS_LIBADDRESSINPUT_PREFECTURE,
- IDS_LIBADDRESSINPUT_PROVINCE,
- IDS_LIBADDRESSINPUT_STATE));
+ testing::Values(
+ IDS_LIBADDRESSINPUT_COUNTRY_OR_REGION_LABEL,
+ IDS_LIBADDRESSINPUT_LOCALITY_LABEL,
+ IDS_LIBADDRESSINPUT_ADDRESS_LINE_1_LABEL,
+ IDS_LIBADDRESSINPUT_POSTAL_CODE_LABEL,
+ IDS_LIBADDRESSINPUT_ZIP_CODE_LABEL,
+ IDS_LIBADDRESSINPUT_AREA,
+ IDS_LIBADDRESSINPUT_COUNTY,
+ IDS_LIBADDRESSINPUT_DEPARTMENT,
+ IDS_LIBADDRESSINPUT_DISTRICT,
+ IDS_LIBADDRESSINPUT_DO_SI,
+ IDS_LIBADDRESSINPUT_EMIRATE,
+ IDS_LIBADDRESSINPUT_ISLAND,
+ IDS_LIBADDRESSINPUT_PARISH,
+ IDS_LIBADDRESSINPUT_PREFECTURE,
+ IDS_LIBADDRESSINPUT_PROVINCE,
+ IDS_LIBADDRESSINPUT_STATE,
+ IDS_LIBADDRESSINPUT_RECIPIENT_LABEL,
+ IDS_LIBADDRESSINPUT_MISSING_REQUIRED_FIELD,
+ IDS_LIBADDRESSINPUT_MISSING_REQUIRED_POSTAL_CODE_EXAMPLE_AND_URL,
+ IDS_LIBADDRESSINPUT_MISSING_REQUIRED_POSTAL_CODE_EXAMPLE,
+ IDS_LIBADDRESSINPUT_MISSING_REQUIRED_ZIP_CODE_EXAMPLE_AND_URL,
+ IDS_LIBADDRESSINPUT_MISSING_REQUIRED_ZIP_CODE_EXAMPLE,
+ IDS_LIBADDRESSINPUT_UNKNOWN_VALUE,
+ IDS_LIBADDRESSINPUT_UNRECOGNIZED_FORMAT_POSTAL_CODE_EXAMPLE_AND_URL,
+ IDS_LIBADDRESSINPUT_UNRECOGNIZED_FORMAT_POSTAL_CODE_EXAMPLE,
+ IDS_LIBADDRESSINPUT_UNRECOGNIZED_FORMAT_POSTAL_CODE,
+ IDS_LIBADDRESSINPUT_UNRECOGNIZED_FORMAT_ZIP_CODE_EXAMPLE_AND_URL,
+ IDS_LIBADDRESSINPUT_UNRECOGNIZED_FORMAT_ZIP_CODE_EXAMPLE,
+ IDS_LIBADDRESSINPUT_UNRECOGNIZED_FORMAT_ZIP,
+ IDS_LIBADDRESSINPUT_MISMATCHING_VALUE_POSTAL_CODE_URL,
+ IDS_LIBADDRESSINPUT_MISMATCHING_VALUE_POSTAL_CODE,
+ IDS_LIBADDRESSINPUT_MISMATCHING_VALUE_ZIP_URL,
+ IDS_LIBADDRESSINPUT_MISMATCHING_VALUE_ZIP,
+ IDS_LIBADDRESSINPUT_PO_BOX_FORBIDDEN_VALUE));
// Verifies that an invalid message identifier results in an empty string in the
// default configuration.
@@ -86,4 +124,349 @@
EXPECT_EQ("en", localization_.GetLanguage());
}
+TEST(LocalizationGetErrorMessageTest, MissingRequiredPostalCode) {
+ Localization localization;
+ AddressData address;
+ address.region_code = "CH";
+ EXPECT_EQ(std::string("You must provide a postal code, for example\n") +
+ " 2544,1211,1556,3030.\n" +
+ " Don't know your postal code? Find it out\n" +
+ " <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));
+ EXPECT_EQ(std::string("You must provide a postal code, for example\n") +
+ " 2544,1211,1556,3030.",
+ localization.GetErrorMessage(address, POSTAL_CODE,
+ MISSING_REQUIRED_FIELD, true, false));
+ EXPECT_EQ("You can't leave this empty.",
+ localization.GetErrorMessage(address, POSTAL_CODE,
+ MISSING_REQUIRED_FIELD, false, false));
+ EXPECT_EQ("You can't leave this empty.",
+ localization.GetErrorMessage(address, POSTAL_CODE,
+ MISSING_REQUIRED_FIELD, false, true));
+}
+
+TEST(LocalizationGetErrorMessageTest, MissingRequiredZipCode) {
+ Localization localization;
+ AddressData address;
+ address.region_code = "US";
+ EXPECT_EQ(std::string("You must provide a ZIP code, for example\n") +
+ " 95014,22162-1010.\n" +
+ " Don't know your ZIP code? Find it out\n" +
+ " <a href=\"https://tools.usps.com/go/ZipLookupAction!" +
+ "input.action\">here</a>.",
+ localization.GetErrorMessage(address, POSTAL_CODE,
+ MISSING_REQUIRED_FIELD, true, true));
+ EXPECT_EQ(std::string("You must provide a ZIP code, for example\n") +
+ " 95014,22162-1010.",
+ localization.GetErrorMessage(address, POSTAL_CODE,
+ MISSING_REQUIRED_FIELD, true, false));
+ EXPECT_EQ("You can't leave this empty.",
+ localization.GetErrorMessage(address, POSTAL_CODE,
+ MISSING_REQUIRED_FIELD, false, false));
+ EXPECT_EQ("You can't leave this empty.",
+ localization.GetErrorMessage(address, POSTAL_CODE,
+ MISSING_REQUIRED_FIELD, false, true));
+}
+
+TEST(LocalizationGetErrorMessageTest, MissingRequiredOtherFields) {
+ Localization localization;
+ AddressData address;
+ address.region_code = "US";
+ std::vector<AddressField> other_fields;
+ other_fields.push_back(COUNTRY);
+ other_fields.push_back(ADMIN_AREA);
+ other_fields.push_back(LOCALITY);
+ other_fields.push_back(DEPENDENT_LOCALITY);
+ other_fields.push_back(SORTING_CODE);
+ other_fields.push_back(STREET_ADDRESS);
+ other_fields.push_back(RECIPIENT);
+ for (std::vector<AddressField>::iterator it = other_fields.begin();
+ it != other_fields.end(); it++) {
+ EXPECT_EQ("You can't leave this empty.",
+ localization.GetErrorMessage(
+ address, *it, MISSING_REQUIRED_FIELD, true, true));
+ EXPECT_EQ("You can't leave this empty.",
+ localization.GetErrorMessage(
+ address, *it, MISSING_REQUIRED_FIELD, true, false));
+ EXPECT_EQ("You can't leave this empty.",
+ localization.GetErrorMessage(
+ address, *it, MISSING_REQUIRED_FIELD, false, false));
+ EXPECT_EQ("You can't leave this empty.",
+ localization.GetErrorMessage(
+ address, *it, MISSING_REQUIRED_FIELD, false, true));
+ }
+}
+
+TEST(LocalizationGetErrorMessageTest, UnknownValueOtherFields) {
+ Localization localization;
+ AddressData address;
+ address.region_code = "US";
+ address.administrative_area = "bad admin area";
+ address.locality = "bad locality";
+ address.dependent_locality = "bad dependent locality";
+ address.sorting_code = "bad sorting code";
+ std::vector<std::string> address_line;
+ address_line.push_back("bad address line 1");
+ address_line.push_back("bad address line 2");
+ address.address_line = address_line;
+ address.recipient = "bad recipient";
+ EXPECT_EQ(std::string("US\n ") +
+ "is not recognized as a known value for this field.",
+ localization.GetErrorMessage(
+ address, COUNTRY, UNKNOWN_VALUE, true, true));
+ EXPECT_EQ(std::string("US\n ") +
+ "is not recognized as a known value for this field.",
+ localization.GetErrorMessage(
+ address, COUNTRY, UNKNOWN_VALUE, true, false));
+ EXPECT_EQ(std::string("US\n ") +
+ "is not recognized as a known value for this field.",
+ localization.GetErrorMessage(
+ address, COUNTRY, UNKNOWN_VALUE, false, false));
+ EXPECT_EQ(std::string("US\n ") +
+ "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\n ") +
+ "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\n ") +
+ "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\n ") +
+ "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\n ") +
+ "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\n ") +
+ "is not recognized as a known value for this field.",
+ localization.GetErrorMessage(
+ address, LOCALITY, UNKNOWN_VALUE, true, true));
+ EXPECT_EQ(std::string("bad locality\n ") +
+ "is not recognized as a known value for this field.",
+ localization.GetErrorMessage(
+ address, LOCALITY, UNKNOWN_VALUE, true, false));
+ EXPECT_EQ(std::string("bad locality\n ") +
+ "is not recognized as a known value for this field.",
+ localization.GetErrorMessage(
+ address, LOCALITY, UNKNOWN_VALUE, false, false));
+ EXPECT_EQ(std::string("bad locality\n ") +
+ "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\n ") +
+ "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\n ") +
+ "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\n ") +
+ "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\n ") +
+ "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\n ") +
+ "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\n ") +
+ "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\n ") +
+ "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\n ") +
+ "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\n ") +
+ "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\n ") +
+ "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\n ") +
+ "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\n ") +
+ "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\n ") +
+ "is not recognized as a known value for this field.",
+ localization.GetErrorMessage(
+ address, RECIPIENT, UNKNOWN_VALUE, true, true));
+ EXPECT_EQ(std::string("bad recipient\n ") +
+ "is not recognized as a known value for this field.",
+ localization.GetErrorMessage(
+ address, RECIPIENT, UNKNOWN_VALUE, true, false));
+ EXPECT_EQ(std::string("bad recipient\n ") +
+ "is not recognized as a known value for this field.",
+ localization.GetErrorMessage(
+ address, RECIPIENT, UNKNOWN_VALUE, false, false));
+ EXPECT_EQ(std::string("bad recipient\n ") +
+ "is not recognized as a known value for this field.",
+ localization.GetErrorMessage(
+ address, RECIPIENT, UNKNOWN_VALUE, false, true));
+}
+
+TEST(LocalizationGetErrorMessageTest, InvalidFormatPostalCode) {
+ 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:\n" +
+ " 2544,1211,1556,3030.\n" +
+ " Don't know your postal code? Find it out\n" +
+ " <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 ") +
+ "of a valid postal code:\n" +
+ " 2544,1211,1556,3030.",
+ localization.GetErrorMessage(address, POSTAL_CODE,
+ INVALID_FORMAT, true, false));
+ EXPECT_EQ("This postal code format is not recognized.",
+ localization.GetErrorMessage(address, POSTAL_CODE,
+ INVALID_FORMAT, false, false));
+ EXPECT_EQ("This postal code format is not recognized.",
+ localization.GetErrorMessage(address, POSTAL_CODE,
+ INVALID_FORMAT, false, true));
+}
+
+TEST(LocalizationGetErrorMessageTest, InvalidFormatZipCode) {
+ 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:\n" +
+ " 95014,22162-1010.\n" +
+ " Don't know your ZIP code? Find it out\n" +
+ " <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 ") +
+ "a valid ZIP code:\n" +
+ " 95014,22162-1010.",
+ localization.GetErrorMessage(address, POSTAL_CODE,
+ INVALID_FORMAT, true, false));
+ EXPECT_EQ("This ZIP code format is not recognized.",
+ localization.GetErrorMessage(address, POSTAL_CODE,
+ INVALID_FORMAT, false, false));
+ EXPECT_EQ("This ZIP code format is not recognized.",
+ localization.GetErrorMessage(address, POSTAL_CODE,
+ INVALID_FORMAT, false, true));
+}
+
+TEST(LocalizationGetErrorMessageTest, MismatchingValuePostalCode) {
+ 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.\n" +
+ " Don't know your postal code? Find it out\n" +
+ " <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 ") +
+ "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 ") +
+ "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.\n" +
+ " Don't know your postal code? Find it out\n" +
+ " <a href=\"http://www.post.ch/db/owa/pv_plz_pack/pr_main\">" +
+ "here</a>.",
+ localization.GetErrorMessage(address, POSTAL_CODE,
+ MISMATCHING_VALUE, false, true));
+}
+
+TEST(LocalizationGetErrorMessageTest, MismatchingValueZipCode) {
+ 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.\n" +
+ " Don't know your ZIP code? Find it out\n" +
+ " <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 ") +
+ "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 ") +
+ "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.\n" +
+ " Don't know your ZIP code? Find it out\n" +
+ " <a href=\"https://tools.usps.com/go/ZipLookupAction!" +
+ "input.action\">here</a>.",
+ localization.GetErrorMessage(address, POSTAL_CODE,
+ MISMATCHING_VALUE, false, true));
+}
+
+TEST(LocalizationGetErrorMessageTest, UsesPOBoxOtherFields) {
+ Localization localization;
+ AddressData address;
+ address.region_code = "US";
+ std::vector<AddressField> other_fields;
+ other_fields.push_back(COUNTRY);
+ other_fields.push_back(ADMIN_AREA);
+ other_fields.push_back(LOCALITY);
+ other_fields.push_back(DEPENDENT_LOCALITY);
+ other_fields.push_back(SORTING_CODE);
+ other_fields.push_back(STREET_ADDRESS);
+ 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\n" +
+ " 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\n" +
+ " 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\n" +
+ " 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\n" +
+ " or building address.",
+ localization.GetErrorMessage(
+ address, *it, USES_P_O_BOX, false, true));
+ }
+}
+
} // namespace
diff --git a/cpp/test/rule_test.cc b/cpp/test/rule_test.cc
index 5fdab33..38ac77b 100644
--- a/cpp/test/rule_test.cc
+++ b/cpp/test/rule_test.cc
@@ -57,7 +57,9 @@
"\"languages\":\"en~fr\","
"\"zip\":\"\\\\d{3}\","
"\"state_name_type\":\"area\","
- "\"zip_name_type\":\"postal\""
+ "\"zip_name_type\":\"postal\","
+ "\"zipex\":\"1234\","
+ "\"posturl\":\"http://www.testpost.com\""
"}"));
Rule copy;
@@ -73,6 +75,8 @@
copy.GetPostalCodeNameMessageId());
EXPECT_NE(rule.GetName(), copy.GetName());
EXPECT_NE(rule.GetLatinName(), copy.GetLatinName());
+ EXPECT_NE(rule.GetPostalCodeExample(), copy.GetPostalCodeExample());
+ EXPECT_NE(rule.GetPostServiceUrl(), copy.GetPostServiceUrl());
EXPECT_TRUE(rule.GetPostalCodeMatcher() != NULL);
EXPECT_TRUE(copy.GetPostalCodeMatcher() == NULL);
@@ -90,6 +94,8 @@
copy.GetPostalCodeNameMessageId());
EXPECT_EQ(rule.GetName(), copy.GetName());
EXPECT_EQ(rule.GetLatinName(), copy.GetLatinName());
+ EXPECT_EQ(rule.GetPostalCodeExample(), copy.GetPostalCodeExample());
+ EXPECT_EQ(rule.GetPostServiceUrl(), copy.GetPostServiceUrl());
EXPECT_TRUE(copy.GetPostalCodeMatcher() != NULL);
}
@@ -99,24 +105,32 @@
ASSERT_TRUE(rule.ParseSerializedRule("{"
"\"fmt\":\"%S%Z\","
"\"state_name_type\":\"area\","
- "\"zip_name_type\":\"postal\""
+ "\"zip_name_type\":\"postal\","
+ "\"zipex\":\"1234\","
+ "\"posturl\":\"http://www.testpost.com\""
"}"));
EXPECT_FALSE(rule.GetFormat().empty());
EXPECT_EQ(IDS_LIBADDRESSINPUT_AREA,
rule.GetAdminAreaNameMessageId());
EXPECT_EQ(IDS_LIBADDRESSINPUT_POSTAL_CODE_LABEL,
rule.GetPostalCodeNameMessageId());
+ EXPECT_EQ("1234", rule.GetPostalCodeExample());
+ EXPECT_EQ("http://www.testpost.com", rule.GetPostServiceUrl());
ASSERT_TRUE(rule.ParseSerializedRule("{"
"\"fmt\":\"\","
"\"state_name_type\":\"do_si\","
- "\"zip_name_type\":\"zip\""
+ "\"zip_name_type\":\"zip\","
+ "\"zipex\":\"5678\","
+ "\"posturl\":\"http://www.fakepost.com\""
"}"));
EXPECT_TRUE(rule.GetFormat().empty());
EXPECT_EQ(IDS_LIBADDRESSINPUT_DO_SI,
rule.GetAdminAreaNameMessageId());
EXPECT_EQ(IDS_LIBADDRESSINPUT_ZIP_CODE_LABEL,
rule.GetPostalCodeNameMessageId());
+ EXPECT_EQ("5678", rule.GetPostalCodeExample());
+ EXPECT_EQ("http://www.fakepost.com", rule.GetPostServiceUrl());
}
TEST(RuleTest, ParsesFormatCorrectly) {
@@ -178,6 +192,19 @@
EXPECT_EQ(expected, rule.GetLanguages());
}
+TEST(RuleTest, ParsesPostalCodeExampleCorrectly) {
+ Rule rule;
+ ASSERT_TRUE(rule.ParseSerializedRule("{\"zipex\":\"1234,12345-6789\"}"));
+ EXPECT_EQ("1234,12345-6789", rule.GetPostalCodeExample());
+}
+
+TEST(RuleTest, ParsesPostServiceUrlCorrectly) {
+ Rule rule;
+ ASSERT_TRUE(
+ rule.ParseSerializedRule("{\"posturl\":\"http://www.testpost.com\"}"));
+ EXPECT_EQ("http://www.testpost.com", rule.GetPostServiceUrl());
+}
+
TEST(RuleTest, PostalCodeMatcher) {
Rule rule;
ASSERT_TRUE(rule.ParseSerializedRule("{\"zip\":\"\\\\d{3}\"}"));