CPP: port Java changes libphonenumber 4.9
authordavinci@google.com <davinci@google.com@ee073f10-1060-11df-b6a4-87a95322a99c>
Wed, 4 Jul 2012 13:52:11 +0000 (13:52 +0000)
committerdavinci@google.com <davinci@google.com@ee073f10-1060-11df-b6a4-87a95322a99c>
Wed, 4 Jul 2012 13:52:11 +0000 (13:52 +0000)
git-svn-id: http://libphonenumber.googlecode.com/svn/trunk@487 ee073f10-1060-11df-b6a4-87a95322a99c

cpp/CMakeLists.txt
cpp/src/phonenumbers/lite_metadata.cc
cpp/src/phonenumbers/metadata.cc
cpp/src/phonenumbers/phonenumbermatcher.h
cpp/src/phonenumbers/phonenumberutil.cc
cpp/src/phonenumbers/phonenumberutil.h
cpp/src/phonenumbers/shortnumberutil.cc [new file with mode: 0644]
cpp/src/phonenumbers/shortnumberutil.h [new file with mode: 0644]
cpp/test/phonenumbers/phonenumberutil_test.cc
cpp/test/phonenumbers/shortnumberutil_test.cc [new file with mode: 0644]
cpp/test/phonenumbers/test_util.h

index 6f4a50c..feec96b 100644 (file)
@@ -189,6 +189,7 @@ set (
   "src/phonenumbers/phonenumber.pb.cc"   # Generated by Protocol Buffers.
   "src/phonenumbers/phonenumberutil.cc"
   "src/phonenumbers/regexp_cache.cc"
+  "src/phonenumbers/shortnumberutil.cc"
   "src/phonenumbers/string_byte_sink.cc"
   "src/phonenumbers/stringutil.cc"
   "src/phonenumbers/unicodestring.cc"
@@ -357,6 +358,7 @@ set (TEST_SOURCES
   "test/phonenumbers/regexp_adapter_test.cc"
   "test/phonenumbers/regexp_cache_test.cc"
   "test/phonenumbers/run_tests.cc"
+  "test/phonenumbers/shortnumberutil_test.cc"
   "test/phonenumbers/stringutil_test.cc"
   "test/phonenumbers/test_util.cc"
   "test/phonenumbers/unicodestring_test.cc"
@@ -395,6 +397,7 @@ install (FILES
   "src/phonenumbers/phonenumberutil.h"
   "src/phonenumbers/regexp_adapter.h"
   "src/phonenumbers/regexp_cache.h"
+  "src/phonenumbers/shortnumberutil.h"
   "src/phonenumbers/unicodestring.h"
   DESTINATION include/phonenumbers/
 )
index 8b59dbf..fa95f4c 100644 (file)
@@ -3189,7 +3189,7 @@ static const unsigned char data[] = {
   0x7B, 0x37, 0x7D, 0x7C, 0x31, 0x28, 0x3F, 0x3A, 0x28, 0x3F, 0x3A, 0x31, 0x28,
   0x3F, 0x3A, 0x33, 0x5B, 0x30, 0x2D, 0x34, 0x38, 0x5D, 0x7C, 0x5B, 0x34, 0x36,
   0x5D, 0x5B, 0x30, 0x2D, 0x34, 0x5D, 0x7C, 0x35, 0x5B, 0x30, 0x31, 0x32, 0x37,
-  0x38, 0x39, 0x5D, 0x7C, 0x37, 0x5B, 0x30, 0x2D, 0x33, 0x39, 0x5D, 0x7C, 0x38,
+  0x38, 0x39, 0x5D, 0x7C, 0x37, 0x5B, 0x30, 0x2D, 0x34, 0x39, 0x5D, 0x7C, 0x38,
   0x5B, 0x30, 0x31, 0x33, 0x34, 0x39, 0x5D, 0x29, 0x7C, 0x32, 0x31, 0x5B, 0x30,
   0x2D, 0x37, 0x5D, 0x7C, 0x33, 0x31, 0x5B, 0x30, 0x2D, 0x38, 0x5D, 0x7C, 0x5B,
   0x34, 0x35, 0x39, 0x5D, 0x31, 0x5C, 0x64, 0x7C, 0x36, 0x31, 0x5B, 0x30, 0x2D,
index 0bde65c..1ee00d3 100644 (file)
@@ -3483,7 +3483,7 @@ static const unsigned char data[] = {
   0x28, 0x3F, 0x3A, 0x31, 0x28, 0x3F, 0x3A, 0x33, 0x5B, 0x30, 0x2D, 0x34, 0x38,
   0x5D, 0x7C, 0x5B, 0x34, 0x36, 0x5D, 0x5B, 0x30, 0x2D, 0x34, 0x5D, 0x7C, 0x35,
   0x5B, 0x30, 0x31, 0x32, 0x37, 0x38, 0x39, 0x5D, 0x7C, 0x37, 0x5B, 0x30, 0x2D,
-  0x33, 0x39, 0x5D, 0x7C, 0x38, 0x5B, 0x30, 0x31, 0x33, 0x34, 0x39, 0x5D, 0x29,
+  0x34, 0x39, 0x5D, 0x7C, 0x38, 0x5B, 0x30, 0x31, 0x33, 0x34, 0x39, 0x5D, 0x29,
   0x7C, 0x32, 0x31, 0x5B, 0x30, 0x2D, 0x37, 0x5D, 0x7C, 0x33, 0x31, 0x5B, 0x30,
   0x2D, 0x38, 0x5D, 0x7C, 0x5B, 0x34, 0x35, 0x39, 0x5D, 0x31, 0x5C, 0x64, 0x7C,
   0x36, 0x31, 0x5B, 0x30, 0x2D, 0x34, 0x36, 0x2D, 0x39, 0x5D, 0x29, 0x29, 0x5C,
index 3917f55..efa5673 100644 (file)
@@ -33,6 +33,9 @@
 namespace i18n {
 namespace phonenumbers {
 
+template <class R, class A1, class A2, class A3, class A4>
+    class ResultCallback4;
+
 using std::string;
 using std::vector;
 
index 7946b04..2497f2d 100644 (file)
@@ -17,9 +17,9 @@
 
 #include "phonenumbers/phonenumberutil.h"
 
+#include <string.h>
 #include <algorithm>
 #include <cctype>
-#include <cstddef>
 #include <fstream>
 #include <iostream>
 #include <iterator>
@@ -73,10 +73,10 @@ const char PhoneNumberUtil::kPlusChars[] = "+\xEF\xBC\x8B";  /* "++" */
 // unicode character.
 // static
 const char PhoneNumberUtil::kValidPunctuation[] =
-    /* "-x‐-―−ー--/  <U+200B><U+2060> ()()[].\\[\\]/~⁓∼" */
+    /* "-x‐-―−ー--/  ­<U+200B><U+2060> ()()[].\\[\\]/~⁓∼" */
     "-x\xE2\x80\x90-\xE2\x80\x95\xE2\x88\x92\xE3\x83\xBC\xEF\xBC\x8D-\xEF\xBC"
-    "\x8F \xC2\xA0\xE2\x80\x8B\xE2\x81\xA0\xE3\x80\x80()\xEF\xBC\x88\xEF\xBC"
-    "\x89\xEF\xBC\xBB\xEF\xBC\xBD.\\[\\]/~\xE2\x81\x93\xE2\x88\xBC";
+    "\x8F \xC2\xA0\xC2\xAD\xE2\x80\x8B\xE2\x81\xA0\xE3\x80\x80()\xEF\xBC\x88"
+    "\xEF\xBC\x89\xEF\xBC\xBB\xEF\xBC\xBD.\\[\\]/~\xE2\x81\x93\xE2\x88\xBC";
 
 // static
 const char PhoneNumberUtil::kCaptureUpToSecondNumberStart[] = "(.*)[\\\\/] *x";
@@ -97,9 +97,8 @@ const char kStarSign[] = "*";
 
 const char kRfc3966ExtnPrefix[] = ";ext=";
 const char kRfc3966Prefix[] = "tel:";
-// We include the "+" here since RFC3966 format specifies that the context must
-// be specified in international format.
-const char kRfc3966PhoneContext[] = ";phone-context=+";
+const char kRfc3966PhoneContext[] = ";phone-context=";
+const char kRfc3966IsdnSubaddress[] = ";isub=";
 
 const char kDigits[] = "\\p{Nd}";
 // We accept alpha characters in phone numbers, ASCII only. We store lower-case
@@ -588,8 +587,8 @@ class PhoneNumberRegExpsAndMappings {
                                           kStarSign)),
         valid_phone_number_(
             StrCat("[", PhoneNumberUtil::kPlusChars, "]*(?:[",
-                   punctuation_and_star_sign_, "]*[",
-                   kDigits, "]){3,}[", kValidAlpha,
+                   punctuation_and_star_sign_, "]*",
+                   kDigits, "){3,}[", kValidAlpha,
                    punctuation_and_star_sign_, kDigits,
                    "]*")),
         extn_patterns_for_parsing_(
@@ -740,6 +739,13 @@ const string& PhoneNumberUtil::GetExtnPatternsForMatching() const {
   return reg_exps_->extn_patterns_for_matching_;
 }
 
+bool PhoneNumberUtil::StartsWithPlusCharsPattern(const string& number)
+    const {
+  const scoped_ptr<RegExpInput> number_string_piece(
+      reg_exps_->regexp_factory_->CreateInput(number));
+  return reg_exps_->plus_chars_pattern_->Consume(number_string_piece.get());
+}
+
 bool PhoneNumberUtil::ContainsOnlyValidDigits(const string& s) const {
   return reg_exps_->digits_pattern_->FullMatch(s);
 }
@@ -1202,9 +1208,11 @@ void PhoneNumberUtil::FormatInOriginalFormat(const PhoneNumber& number,
   // user entered.
   if (!formatted_number->empty()) {
     string formatted_number_copy(*formatted_number);
-    NormalizeDigitsOnly(&formatted_number_copy);
+    NormalizeHelper(reg_exps_->diallable_char_mappings_,
+                    true /* remove non matches */, &formatted_number_copy);
     string raw_input_copy(number.raw_input());
-    NormalizeDigitsOnly(&raw_input_copy);
+    NormalizeHelper(reg_exps_->diallable_char_mappings_,
+                    true /* remove non matches */, &raw_input_copy);
     if (formatted_number_copy != raw_input_copy) {
       formatted_number->assign(number.raw_input());
     }
@@ -1698,38 +1706,70 @@ bool PhoneNumberUtil::CheckRegionForParsing(
   return true;
 }
 
-PhoneNumberUtil::ErrorType PhoneNumberUtil::ParseHelper(
-    const string& number_to_parse,
-    const string& default_region,
-    bool keep_raw_input,
-    bool check_region,
-    PhoneNumber* phone_number) const {
-  DCHECK(phone_number);
-
+// Converts number_to_parse to a form that we can parse and write it to
+// national_number if it is written in RFC3966; otherwise extract a possible
+// number out of it and write to national_number.
+void PhoneNumberUtil::BuildNationalNumberForParsing(
+    const string& number_to_parse, string* national_number) const {
   size_t index_of_phone_context = number_to_parse.find(kRfc3966PhoneContext);
-  string national_number;
   if (index_of_phone_context != string::npos) {
-    // Prefix the number with the phone context. The offset here is because the
-    // context we are expecting to match should start with a "+" sign, and we
-    // want to include this at the start of the number.
-    StrAppend(
-        &national_number,
-        number_to_parse.substr(
-            index_of_phone_context + strlen(kRfc3966PhoneContext) - 1));
+    int phone_context_start =
+        index_of_phone_context + strlen(kRfc3966PhoneContext);
+    // If the phone context contains a phone number prefix, we need to capture
+    // it, whereas domains will be ignored.
+    if (number_to_parse.at(phone_context_start) == kPlusSign[0]) {
+      // Additional parameters might follow the phone context. If so, we will
+      // remove them here because the parameters after phone context are not
+      // important for parsing the phone number.
+      size_t phone_context_end = number_to_parse.find(';', phone_context_start);
+      if (phone_context_end != string::npos) {
+        StrAppend(
+            national_number, number_to_parse.substr(
+                phone_context_start, phone_context_end - phone_context_start));
+      } else {
+        StrAppend(national_number, number_to_parse.substr(phone_context_start));
+      }
+    }
+
     // Now append everything between the "tel:" prefix and the phone-context.
+    // This should include the national number, an optional extension or
+    // isdn-subaddress component.
     int end_of_rfc_prefix =
         number_to_parse.find(kRfc3966Prefix) + strlen(kRfc3966Prefix);
     StrAppend(
-        &national_number,
+        national_number,
         number_to_parse.substr(end_of_rfc_prefix,
                                index_of_phone_context - end_of_rfc_prefix));
-    // Note that phone-contexts that are URLs will not be parsed -
-    // IsViablePhoneNumber will throw an exception below.
   } else {
     // Extract a possible number from the string passed in (this strips leading
     // characters that could not be the start of a phone number.)
-    ExtractPossibleNumber(number_to_parse, &national_number);
+    ExtractPossibleNumber(number_to_parse, national_number);
+  }
+
+  // Delete the isdn-subaddress and everything after it if it is present. Note
+  // extension won't appear at the same time with isdn-subaddress according to
+  // paragraph 5.3 of the RFC3966 spec.
+  size_t index_of_isdn = national_number->find(kRfc3966IsdnSubaddress);
+  if (index_of_isdn != string::npos) {
+    national_number->erase(index_of_isdn);
   }
+  // If both phone context and isdn-subaddress are absent but other parameters
+  // are present, the parameters are left in nationalNumber. This is because
+  // we are concerned about deleting content from a potential number string
+  // when there is no strong evidence that the number is actually written in
+  // RFC3966.
+}
+
+PhoneNumberUtil::ErrorType PhoneNumberUtil::ParseHelper(
+    const string& number_to_parse,
+    const string& default_region,
+    bool keep_raw_input,
+    bool check_region,
+    PhoneNumber* phone_number) const {
+  DCHECK(phone_number);
+
+  string national_number;
+  BuildNationalNumberForParsing(number_to_parse, &national_number);
 
   if (!IsViablePhoneNumber(national_number)) {
     VLOG(2) << "The string supplied did not seem to be a phone number.";
@@ -2390,7 +2430,7 @@ PhoneNumberUtil::ErrorType PhoneNumberUtil::MaybeExtractCountryCode(
     phone_number->set_country_code_source(country_code_source);
   }
   if (country_code_source != PhoneNumber::FROM_DEFAULT_COUNTRY) {
-    if (national_number->length() < kMinLengthForNsn) {
+    if (national_number->length() <= kMinLengthForNsn) {
       VLOG(2) << "Phone number had an IDD, but after this was not "
               << "long enough to be a viable phone number.";
       return TOO_SHORT_AFTER_IDD;
index 3aeb1fb..3013b3f 100644 (file)
@@ -73,6 +73,8 @@ class PhoneNumberUtil : public Singleton<PhoneNumberUtil> {
   friend class PhoneNumberMatcherTest;
   friend class PhoneNumberRegExpsAndMappings;
   friend class PhoneNumberUtilTest;
+  friend class ShortNumberUtil;
+  friend class ShortNumberUtilTest;
  public:
   ~PhoneNumberUtil();
   static const char kRegionCodeForNonGeoEntity[];
@@ -487,6 +489,8 @@ class PhoneNumberUtil : public Singleton<PhoneNumberUtil> {
   // particular region is not performed. This can be done separately with
   // IsValidNumber().
   //
+  // number_to_parse can also be provided in RFC3966 format.
+  //
   // default_region represents the country that we are expecting the number to
   // be from. This is only used if the number being parsed is not written in
   // international format. The country_code for the number in this case would be
@@ -565,7 +569,7 @@ class PhoneNumberUtil : public Singleton<PhoneNumberUtil> {
   typedef pair<int, list<string>*> IntRegionsPair;
 
   // The minimum and maximum length of the national significant number.
-  static const size_t kMinLengthForNsn = 3;
+  static const size_t kMinLengthForNsn = 2;
   // The ITU says the maximum length should be 15, but we have found longer
   // numbers in Germany.
   static const size_t kMaxLengthForNsn = 16;
@@ -622,6 +626,9 @@ class PhoneNumberUtil : public Singleton<PhoneNumberUtil> {
   // in a number, for use when matching.
   const string& GetExtnPatternsForMatching() const;
 
+  // Checks if a number matches the plus chars pattern.
+  bool StartsWithPlusCharsPattern(const string& number) const;
+
   // Checks whether a string contains only valid digits.
   bool ContainsOnlyValidDigits(const string& s) const;
 
@@ -748,6 +755,9 @@ class PhoneNumberUtil : public Singleton<PhoneNumberUtil> {
                         bool check_region,
                         PhoneNumber* phone_number) const;
 
+  void BuildNationalNumberForParsing(const string& number_to_parse,
+                                     string* national_number) const;
+
   // Returns true if the number can be dialled from outside the region, or
   // unknown. If the number can only be dialled from within the region, returns
   // false. Does not check the number is a valid number.
diff --git a/cpp/src/phonenumbers/shortnumberutil.cc b/cpp/src/phonenumbers/shortnumberutil.cc
new file mode 100644 (file)
index 0000000..9485d5a
--- /dev/null
@@ -0,0 +1,78 @@
+// Copyright (C) 2012 The Libphonenumber Authors
+//
+// 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.
+
+// Author: David Yonge-Mallo
+
+#include "phonenumbers/shortnumberutil.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "phonenumbers/phonemetadata.pb.h"
+#include "phonenumbers/phonenumberutil.h"
+#include "phonenumbers/regexp_adapter.h"
+#include "phonenumbers/regexp_factory.h"
+
+namespace i18n {
+namespace phonenumbers {
+
+using std::string;
+
+ShortNumberUtil::ShortNumberUtil()
+    : phone_util_(*PhoneNumberUtil::GetInstance()) {
+}
+
+bool ShortNumberUtil::ConnectsToEmergencyNumber(const string& number,
+    const string& region_code) const {
+  return MatchesEmergencyNumberHelper(number, region_code,
+      true /* allows prefix match */);
+}
+
+bool ShortNumberUtil::IsEmergencyNumber(const string& number,
+    const string& region_code) const {
+  return MatchesEmergencyNumberHelper(number, region_code,
+      false /* doesn't allow prefix match */);
+}
+
+bool ShortNumberUtil::MatchesEmergencyNumberHelper(const string& number,
+    const string& region_code, bool allow_prefix_match) const {
+  string extracted_number;
+  phone_util_.ExtractPossibleNumber(number, &extracted_number);
+  if (phone_util_.StartsWithPlusCharsPattern(extracted_number)) {
+    // Returns false if the number starts with a plus sign. We don't believe
+    // dialing the country code before emergency numbers (e.g. +1911) works,
+    // but later, if that proves to work, we can add additional logic here to
+    // handle it.
+    return false;
+  }
+  const PhoneMetadata* metadata = phone_util_.GetMetadataForRegion(region_code);
+  if (!metadata || !metadata->has_emergency()) {
+    return false;
+  }
+  const scoped_ptr<const AbstractRegExpFactory> regexp_factory(
+      new RegExpFactory());
+  const scoped_ptr<const RegExp> emergency_number_pattern(
+      regexp_factory->CreateRegExp(
+          metadata->emergency().national_number_pattern()));
+  phone_util_.NormalizeDigitsOnly(&extracted_number);
+  const scoped_ptr<RegExpInput> normalized_number_input(
+      regexp_factory->CreateInput(extracted_number));
+
+  // In Brazil, it is impossible to append additional digits to an emergency
+  // number to dial the number.
+  return (!allow_prefix_match || region_code == "BR")
+      ? emergency_number_pattern->FullMatch(extracted_number)
+      : emergency_number_pattern->Consume(normalized_number_input.get());
+}
+
+}  // namespace phonenumbers
+}  // namespace i18n
diff --git a/cpp/src/phonenumbers/shortnumberutil.h b/cpp/src/phonenumbers/shortnumberutil.h
new file mode 100644 (file)
index 0000000..53758a1
--- /dev/null
@@ -0,0 +1,73 @@
+// Copyright (C) 2012 The Libphonenumber Authors
+//
+// 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.
+
+// Utility for international short phone numbers, such as short codes and
+// emergency numbers. Note most commercial short numbers are not handled here,
+// but by the phonenumberutil.
+//
+// Author: David Yonge-Mallo
+//
+// This is a direct port from ShortNumberUtil.java.
+// Changes to this class should also happen to the Java version, whenever it
+// makes sense.
+
+#ifndef I18N_PHONENUMBERS_SHORTNUMBERUTIL_H_
+#define I18N_PHONENUMBERS_SHORTNUMBERUTIL_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+
+namespace i18n {
+namespace phonenumbers {
+
+using std::string;
+
+class PhoneNumberUtil;
+
+class ShortNumberUtil {
+ public:
+  ShortNumberUtil();
+
+  // Returns true if the number might be used to connect to an emergency service
+  // in the given region.
+  //
+  // This method takes into account cases where the number might contain
+  // formatting, or might have additional digits appended (when it is okay to do
+  // that in the region specified).
+  bool ConnectsToEmergencyNumber(const string& number,
+                                 const string& region_code) const;
+
+  // Returns true if the number exactly matches an emergency service number in
+  // the given region.
+  //
+  // This method takes into account cases where the number might contain
+  // formatting, but doesn't allow additional digits to be appended.
+  bool IsEmergencyNumber(const string& number,
+                         const string& region_code) const;
+
+ private:
+  const PhoneNumberUtil& phone_util_;
+
+  bool MatchesEmergencyNumberHelper(const string& number,
+                                    const string& region_code,
+                                    bool allow_prefix_match) const;
+
+  DISALLOW_COPY_AND_ASSIGN(ShortNumberUtil);
+};
+
+}  // namespace phonenumbers
+}  // namespace i18n
+
+#endif  // I18N_PHONENUMBERS_SHORTNUMBERUTIL_H_
index 4266d26..939fa89 100644 (file)
@@ -310,6 +310,13 @@ TEST_F(PhoneNumberUtilTest, GetExampleNumberForNonGeoEntity) {
       phone_util_.GetExampleNumberForNonGeoEntity(800 , &test_number);
   EXPECT_TRUE(success);
   EXPECT_EQ(toll_free_number, test_number);
+
+  PhoneNumber universal_premium_rate;
+  universal_premium_rate.set_country_code(979);
+  universal_premium_rate.set_national_number(123456789ULL);
+  success = phone_util_.GetExampleNumberForNonGeoEntity(979 , &test_number);
+  EXPECT_TRUE(success);
+  EXPECT_EQ(universal_premium_rate, test_number);
 }
 
 TEST_F(PhoneNumberUtilTest, FormatUSNumber) {
@@ -1264,6 +1271,11 @@ TEST_F(PhoneNumberUtilTest, IsValidNumber) {
   intl_toll_free_number.set_country_code(800);
   intl_toll_free_number.set_national_number(12345678ULL);
   EXPECT_TRUE(phone_util_.IsValidNumber(intl_toll_free_number));
+
+  PhoneNumber universal_premium_rate;
+  universal_premium_rate.set_country_code(979);
+  universal_premium_rate.set_national_number(123456789ULL);
+  EXPECT_TRUE(phone_util_.IsValidNumber(universal_premium_rate));
 }
 
 TEST_F(PhoneNumberUtilTest, IsValidForRegion) {
@@ -1373,6 +1385,53 @@ TEST_F(PhoneNumberUtilTest, IsNotValidNumber) {
   EXPECT_FALSE(phone_util_.IsValidNumber(intl_toll_free_number_too_long));
 }
 
+TEST_F(PhoneNumberUtilTest, GetRegionCodeForCountryCode) {
+  string region_code;
+  phone_util_.GetRegionCodeForCountryCode(1, &region_code);
+  EXPECT_EQ(RegionCode::US(), region_code);
+  phone_util_.GetRegionCodeForCountryCode(44, &region_code);
+  EXPECT_EQ(RegionCode::GB(), region_code);
+  phone_util_.GetRegionCodeForCountryCode(49, &region_code);
+  EXPECT_EQ(RegionCode::DE(), region_code);
+  phone_util_.GetRegionCodeForCountryCode(800, &region_code);
+  EXPECT_EQ(RegionCode::UN001(), region_code);
+  phone_util_.GetRegionCodeForCountryCode(979, &region_code);
+  EXPECT_EQ(RegionCode::UN001(), region_code);
+}
+
+TEST_F(PhoneNumberUtilTest, GetRegionCodeForNumber) {
+  string region_code;
+  PhoneNumber bs_number;
+  bs_number.set_country_code(1);
+  bs_number.set_national_number(2423232345ULL);
+  phone_util_.GetRegionCodeForNumber(bs_number, &region_code);
+  EXPECT_EQ(RegionCode::BS(), region_code);
+
+  PhoneNumber us_number;
+  us_number.set_country_code(1);
+  us_number.set_national_number(4241231234ULL);
+  phone_util_.GetRegionCodeForNumber(us_number, &region_code);
+  EXPECT_EQ(RegionCode::US(), region_code);
+
+  PhoneNumber gb_mobile;
+  gb_mobile.set_country_code(44);
+  gb_mobile.set_national_number(7912345678ULL);
+  phone_util_.GetRegionCodeForNumber(gb_mobile, &region_code);
+  EXPECT_EQ(RegionCode::GB(), region_code);
+
+  PhoneNumber intl_toll_free_number;
+  intl_toll_free_number.set_country_code(800);
+  intl_toll_free_number.set_national_number(12345678ULL);
+  phone_util_.GetRegionCodeForNumber(intl_toll_free_number, &region_code);
+  EXPECT_EQ(RegionCode::UN001(), region_code);
+
+  PhoneNumber universal_premium_rate;
+  universal_premium_rate.set_country_code(979);
+  universal_premium_rate.set_national_number(123456789ULL);
+  phone_util_.GetRegionCodeForNumber(universal_premium_rate, &region_code);
+  EXPECT_EQ(RegionCode::UN001(), region_code);
+}
+
 TEST_F(PhoneNumberUtilTest, IsPossibleNumber) {
   PhoneNumber number;
   number.set_country_code(1);
@@ -1469,7 +1528,7 @@ TEST_F(PhoneNumberUtilTest, IsPossibleNumberWithReason) {
   EXPECT_EQ(PhoneNumberUtil::IS_POSSIBLE,
             phone_util_.IsPossibleNumberWithReason(ad_number));
   ad_number.set_country_code(376);
-  ad_number.set_national_number(13ULL);
+  ad_number.set_national_number(1ULL);
   EXPECT_EQ(PhoneNumberUtil::TOO_SHORT,
             phone_util_.IsPossibleNumberWithReason(ad_number));
   ad_number.set_country_code(376);
@@ -1827,6 +1886,27 @@ TEST_F(PhoneNumberUtilTest, FormatInOriginalFormat) {
   phone_util_.FormatInOriginalFormat(phone_number, RegionCode::AU(),
                                      &formatted_number);
   EXPECT_EQ("0011 1 650 253 0000", formatted_number);
+
+  // Test the star sign is not removed from or added to the original input by
+  // this method.
+  phone_number.Clear();
+  formatted_number.clear();
+  EXPECT_EQ(PhoneNumberUtil::NO_PARSING_ERROR,
+            phone_util_.ParseAndKeepRawInput("*1234",
+                                             RegionCode::JP(),
+                                             &phone_number));
+  phone_util_.FormatInOriginalFormat(phone_number, RegionCode::JP(),
+                                     &formatted_number);
+  EXPECT_EQ("*1234", formatted_number);
+  phone_number.Clear();
+  formatted_number.clear();
+  EXPECT_EQ(PhoneNumberUtil::NO_PARSING_ERROR,
+            phone_util_.ParseAndKeepRawInput("1234",
+                                             RegionCode::JP(),
+                                             &phone_number));
+  phone_util_.FormatInOriginalFormat(phone_number, RegionCode::JP(),
+                                     &formatted_number);
+  EXPECT_EQ("1234", formatted_number);
 }
 
 TEST_F(PhoneNumberUtilTest, IsPremiumRate) {
@@ -1850,6 +1930,10 @@ TEST_F(PhoneNumberUtilTest, IsPremiumRate) {
   number.set_country_code(49);
   number.set_national_number(90091234567ULL);
   EXPECT_EQ(PhoneNumberUtil::PREMIUM_RATE, phone_util_.GetNumberType(number));
+
+  number.set_country_code(979);
+  number.set_national_number(123456789ULL);
+  EXPECT_EQ(PhoneNumberUtil::PREMIUM_RATE, phone_util_.GetNumberType(number));
 }
 
 TEST_F(PhoneNumberUtilTest, IsTollFree) {
@@ -2047,7 +2131,7 @@ TEST_F(PhoneNumberUtilTest, ConvertAlphaCharactersInNumber) {
 }
 
 TEST_F(PhoneNumberUtilTest, NormaliseRemovePunctuation) {
-  string input_number("034-56&+#234");
+  string input_number("034-56&+#2" "\xC2\xAD" "34");
   Normalize(&input_number);
   static const string kExpectedOutput("03456234");
   EXPECT_EQ(kExpectedOutput, input_number)
@@ -2389,6 +2473,9 @@ TEST_F(PhoneNumberUtilTest, IsNumberMatchMatches) {
   EXPECT_EQ(PhoneNumberUtil::EXACT_MATCH,
             phone_util_.IsNumberMatchWithTwoStrings("+64 3 331-6005",
                                                     "+6433316005"));
+  EXPECT_EQ(PhoneNumberUtil::EXACT_MATCH,
+            phone_util_.IsNumberMatchWithTwoStrings(
+                "+64 3 331-6005", "tel:+64-3-331-6005;isub=123"));
   // Test alpha numbers.
   EXPECT_EQ(PhoneNumberUtil::EXACT_MATCH,
             phone_util_.IsNumberMatchWithTwoStrings("+1800 siX-Flags",
@@ -2439,7 +2526,7 @@ TEST_F(PhoneNumberUtilTest, IsNumberMatchMatches) {
             phone_util_.IsNumberMatch(br_number_1, br_number_2));
 }
 
-TEST_F(PhoneNumberUtilTest, IsNumberMatchNonMetches) {
+TEST_F(PhoneNumberUtilTest, IsNumberMatchNonMatches) {
   // NSN matches.
   EXPECT_EQ(PhoneNumberUtil::NO_MATCH,
             phone_util_.IsNumberMatchWithTwoStrings("03 331 6005",
@@ -2459,6 +2546,9 @@ TEST_F(PhoneNumberUtilTest, IsNumberMatchNonMetches) {
   EXPECT_EQ(PhoneNumberUtil::NO_MATCH,
             phone_util_.IsNumberMatchWithTwoStrings("+64 3 331-6005 extn 1234",
                                                     "+0116433316005#1235"));
+  EXPECT_EQ(PhoneNumberUtil::NO_MATCH,
+            phone_util_.IsNumberMatchWithTwoStrings(
+                "+64 3 331-6005 extn 1234", "tel:+64-3-331-6005;ext=1235"));
   // NSN matches, but extension is different - not the same number.
   EXPECT_EQ(PhoneNumberUtil::NO_MATCH,
             phone_util_.IsNumberMatchWithTwoStrings("+64 3 331-6005 ext.1235",
@@ -2480,6 +2570,10 @@ TEST_F(PhoneNumberUtilTest, IsNumberMatchNsnMatches) {
   EXPECT_EQ(PhoneNumberUtil::NSN_MATCH,
             phone_util_.IsNumberMatchWithTwoStrings("+64 3 331-6005",
                                                     "03 331 6005"));
+  EXPECT_EQ(PhoneNumberUtil::NSN_MATCH,
+            phone_util_.IsNumberMatchWithTwoStrings(
+                "+64 3 331-6005",
+                "tel:03-331-6005;isub=1234;phone-context=abc.nz"));
 
   PhoneNumber nz_number;
   nz_number.set_country_code(64);
@@ -2529,6 +2623,17 @@ TEST_F(PhoneNumberUtilTest, IsNumberMatchShortNsnMatches) {
   EXPECT_EQ(PhoneNumberUtil::SHORT_NSN_MATCH,
             phone_util_.IsNumberMatchWithTwoStrings("+64 3 331-6005",
                                                     "331 6005"));
+  EXPECT_EQ(PhoneNumberUtil::SHORT_NSN_MATCH,
+            phone_util_.IsNumberMatchWithTwoStrings(
+                "+64 3 331-6005", "tel:331-6005;phone-context=abc.nz"));
+  EXPECT_EQ(PhoneNumberUtil::SHORT_NSN_MATCH,
+              phone_util_.IsNumberMatchWithTwoStrings(
+                  "+64 3 331-6005",
+                  "tel:331-6005;isub=1234;phone-context=abc.nz"));
+  EXPECT_EQ(PhoneNumberUtil::SHORT_NSN_MATCH,
+              phone_util_.IsNumberMatchWithTwoStrings(
+                  "+64 3 331-6005",
+                  "tel:331-6005;isub=1234;phone-context=abc.nz;a=%A1"));
 
   // We did not know that the "0" was a national prefix since neither number has
   // a country code, so this is considered a SHORT_NSN_MATCH.
@@ -2541,6 +2646,9 @@ TEST_F(PhoneNumberUtilTest, IsNumberMatchShortNsnMatches) {
                                                       "331 6005"));
 
   EXPECT_EQ(PhoneNumberUtil::SHORT_NSN_MATCH,
+              phone_util_.IsNumberMatchWithTwoStrings(
+                  "3 331-6005", "tel:331-6005;phone-context=abc.nz"));
+  EXPECT_EQ(PhoneNumberUtil::SHORT_NSN_MATCH,
             phone_util_.IsNumberMatchWithTwoStrings("3 331-6005",
                                                     "+64 331 6005"));
 
@@ -2614,7 +2722,21 @@ TEST_F(PhoneNumberUtilTest, ParseNationalNumber) {
             phone_util_.Parse("tel:331-6005;phone-context=+64-3",
                               RegionCode::US(), &test_number));
   EXPECT_EQ(nz_number, test_number);
-
+  // Test parsing RFC3966 format with optional user-defined parameters. The
+  // parameters will appear after the context if present.
+  EXPECT_EQ(PhoneNumberUtil::NO_PARSING_ERROR,
+            phone_util_.Parse("tel:03-331-6005;phone-context=+64;a=%A1",
+                              RegionCode::NZ(), &test_number));
+  EXPECT_EQ(nz_number, test_number);
+  // Test parsing RFC3966 with an ISDN subaddress.
+  EXPECT_EQ(PhoneNumberUtil::NO_PARSING_ERROR,
+            phone_util_.Parse("tel:03-331-6005;isub=12345;phone-context=+64",
+                              RegionCode::NZ(), &test_number));
+  EXPECT_EQ(nz_number, test_number);
+  EXPECT_EQ(PhoneNumberUtil::NO_PARSING_ERROR,
+            phone_util_.Parse("tel:+64-3-331-6005;isub=12345",
+                              RegionCode::US(), &test_number));
+  EXPECT_EQ(nz_number, test_number);
   // Testing international prefixes.
   // Should strip country code.
   test_number.Clear();
@@ -2652,6 +2774,34 @@ TEST_F(PhoneNumberUtilTest, ParseNationalNumber) {
                               RegionCode::NZ(), &test_number));
   EXPECT_EQ(nz_number, test_number);
 
+  PhoneNumber us_local_number;
+  us_local_number.set_country_code(1);
+  us_local_number.set_national_number(2530000ULL);
+  test_number.Clear();
+  EXPECT_EQ(PhoneNumberUtil::NO_PARSING_ERROR,
+            phone_util_.Parse("tel:253-0000;phone-context=www.google.com",
+                              RegionCode::US(), &test_number));
+  EXPECT_EQ(us_local_number, test_number);
+  test_number.Clear();
+  EXPECT_EQ(PhoneNumberUtil::NO_PARSING_ERROR,
+            phone_util_.Parse(
+                "tel:253-0000;isub=12345;phone-context=www.google.com",
+                RegionCode::US(), &test_number));
+  EXPECT_EQ(us_local_number, test_number);
+  // This is invalid because no "+" sign is present as part of phone-context.
+  // The phone context is simply ignored in this case just as if it contains a
+  // domain.
+  test_number.Clear();
+  EXPECT_EQ(PhoneNumberUtil::NO_PARSING_ERROR,
+            phone_util_.Parse("tel:2530000;isub=12345;phone-context=1-650",
+                              RegionCode::US(), &test_number));
+  EXPECT_EQ(us_local_number, test_number);
+  test_number.Clear();
+  EXPECT_EQ(PhoneNumberUtil::NO_PARSING_ERROR,
+            phone_util_.Parse("tel:2530000;isub=12345;phone-context=1234.com",
+                              RegionCode::US(), &test_number));
+  EXPECT_EQ(us_local_number, test_number);
+
   // Test for http://b/issue?id=2247493
   nz_number.Clear();
   nz_number.set_country_code(64);
@@ -2789,6 +2939,12 @@ TEST_F(PhoneNumberUtilTest, ParseWithInternationalPrefixes) {
             phone_util_.Parse("\xEF\xBC\x8B" "1 (650) 333-6000",
                               /* "+1 (650) 333-6000" */
                               RegionCode::SG(), &test_number));
+  // Using a soft hyphen U+00AD.
+  test_number.Clear();
+  EXPECT_EQ(PhoneNumberUtil::NO_PARSING_ERROR,
+            phone_util_.Parse("1 (650) 333" "\xC2\xAD" "-6000",
+                              /* "1 (650) 333­-6000­" */
+                              RegionCode::US(), &test_number));
   EXPECT_EQ(us_number, test_number);
   // The whole number, including punctuation, is here represented in full-width
   // form.
@@ -3066,15 +3222,15 @@ TEST_F(PhoneNumberUtilTest, FailedParseOnInvalidNumbers) {
   EXPECT_EQ(PhoneNumber::default_instance(), test_number);
 
   // RFC3966 phone-context is a website.
-  EXPECT_EQ(PhoneNumberUtil::NOT_A_NUMBER,
-            phone_util_.Parse("tel:555-1234;phone-context:www.google.com",
-                              RegionCode::US(), &test_number));
+  EXPECT_EQ(PhoneNumberUtil::INVALID_COUNTRY_CODE_ERROR,
+            phone_util_.Parse("tel:555-1234;phone-context=www.google.com",
+                              RegionCode::ZZ(), &test_number));
   EXPECT_EQ(PhoneNumber::default_instance(), test_number);
   // This is invalid because no "+" sign is present as part of phone-context.
   // This should not succeed in being parsed.
-  EXPECT_EQ(PhoneNumberUtil::NOT_A_NUMBER,
-            phone_util_.Parse("tel:555-1234;phone-context:1-331",
-                              RegionCode::US(), &test_number));
+  EXPECT_EQ(PhoneNumberUtil::INVALID_COUNTRY_CODE_ERROR,
+            phone_util_.Parse("tel:555-1234;phone-context=1-331",
+                              RegionCode::ZZ(), &test_number));
   EXPECT_EQ(PhoneNumber::default_instance(), test_number);
 }
 
@@ -3112,6 +3268,15 @@ TEST_F(PhoneNumberUtilTest, ParseNumbersWithPlusWithNoRegion) {
                               RegionCode::GetUnknown(), &result_proto));
   EXPECT_EQ(toll_free_number, result_proto);
 
+  PhoneNumber universal_premium_rate;
+  universal_premium_rate.set_country_code(979);
+  universal_premium_rate.set_national_number(123456789ULL);
+  result_proto.Clear();
+  EXPECT_EQ(PhoneNumberUtil::NO_PARSING_ERROR,
+            phone_util_.Parse("+979 123 456 789",
+                              RegionCode::GetUnknown(), &result_proto));
+  EXPECT_EQ(universal_premium_rate, result_proto);
+
   result_proto.Clear();
   // Test parsing RFC3966 format with a phone context.
   EXPECT_EQ(PhoneNumberUtil::NO_PARSING_ERROR,
@@ -3123,6 +3288,11 @@ TEST_F(PhoneNumberUtilTest, ParseNumbersWithPlusWithNoRegion) {
             phone_util_.Parse("  tel:03-331-6005;phone-context=+64",
                               RegionCode::GetUnknown(), &result_proto));
   EXPECT_EQ(nz_number, result_proto);
+  result_proto.Clear();
+  EXPECT_EQ(PhoneNumberUtil::NO_PARSING_ERROR,
+            phone_util_.Parse("tel:03-331-6005;isub=12345;phone-context=+64",
+                              RegionCode::GetUnknown(), &result_proto));
+  EXPECT_EQ(nz_number, result_proto);
 
   nz_number.set_raw_input("+64 3 331 6005");
   nz_number.set_country_code_source(PhoneNumber::FROM_NUMBER_WITH_PLUS_SIGN);
@@ -3451,15 +3621,15 @@ TEST_F(PhoneNumberUtilTest, IsAlphaNumber) {
   EXPECT_TRUE(phone_util_.IsAlphaNumber(kAlphaNumber));
   static const string kAlphaNumberWithExtension = "1800 six-flags ext. 1234";
   EXPECT_TRUE(phone_util_.IsAlphaNumber(kAlphaNumberWithExtension));
-  static const string kI18NAlphaNumber("+800 six-flags");
-  EXPECT_TRUE(phone_util_.IsAlphaNumber(kI18NAlphaNumber));
+  static const string kI18nAlphaNumber("+800 six-flags");
+  EXPECT_TRUE(phone_util_.IsAlphaNumber(kI18nAlphaNumber));
   static const string kNonAlphaNumber("1800 123-1234");
   EXPECT_FALSE(phone_util_.IsAlphaNumber(kNonAlphaNumber));
   static const string kNonAlphaNumberWithExtension(
       "1800 123-1234 extension: 1234");
   EXPECT_FALSE(phone_util_.IsAlphaNumber(kNonAlphaNumberWithExtension));
-  static const string kI18NNonAlphaNumber("+800 1234-1234");
-  EXPECT_FALSE(phone_util_.IsAlphaNumber(kI18NNonAlphaNumber));
+  static const string kI18nNonAlphaNumber("+800 1234-1234");
+  EXPECT_FALSE(phone_util_.IsAlphaNumber(kI18nNonAlphaNumber));
 }
 
 }  // namespace phonenumbers
diff --git a/cpp/test/phonenumbers/shortnumberutil_test.cc b/cpp/test/phonenumbers/shortnumberutil_test.cc
new file mode 100644 (file)
index 0000000..663517b
--- /dev/null
@@ -0,0 +1,161 @@
+// Copyright (C) 2009 The Libphonenumber Authors
+//
+// 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.
+
+// Author: David Yonge-Mallo
+
+#include <gtest/gtest.h>
+
+#include "phonenumbers/phonenumberutil.h"
+#include "phonenumbers/shortnumberutil.h"
+#include "phonenumbers/test_util.h"
+
+namespace i18n {
+namespace phonenumbers {
+
+class ShortNumberUtilTest : public testing::Test {
+ protected:
+  ShortNumberUtilTest() : short_util_() {
+  }
+
+  const ShortNumberUtil short_util_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ShortNumberUtilTest);
+};
+
+TEST_F(ShortNumberUtilTest, ConnectsToEmergencyNumber_US) {
+  EXPECT_TRUE(short_util_.ConnectsToEmergencyNumber("911", RegionCode::US()));
+  EXPECT_TRUE(short_util_.ConnectsToEmergencyNumber("119", RegionCode::US()));
+  EXPECT_FALSE(short_util_.ConnectsToEmergencyNumber("999", RegionCode::US()));
+}
+
+TEST_F(ShortNumberUtilTest, ConnectsToEmergencyNumberLongNumber_US) {
+  EXPECT_TRUE(short_util_.ConnectsToEmergencyNumber("9116666666",
+      RegionCode::US()));
+  EXPECT_TRUE(short_util_.ConnectsToEmergencyNumber("1196666666",
+      RegionCode::US()));
+  EXPECT_FALSE(short_util_.ConnectsToEmergencyNumber("9996666666",
+      RegionCode::US()));
+}
+
+TEST_F(ShortNumberUtilTest, ConnectsToEmergencyNumberWithFormatting_US) {
+  EXPECT_TRUE(short_util_.ConnectsToEmergencyNumber("9-1-1", RegionCode::US()));
+  EXPECT_TRUE(short_util_.ConnectsToEmergencyNumber("1-1-9", RegionCode::US()));
+  EXPECT_FALSE(short_util_.ConnectsToEmergencyNumber("9-9-9",
+      RegionCode::US()));
+}
+
+TEST_F(ShortNumberUtilTest, ConnectsToEmergencyNumberWithPlusSign_US) {
+  EXPECT_FALSE(short_util_.ConnectsToEmergencyNumber("+911", RegionCode::US()));
+  // This hex sequence is the full-width plus sign U+FF0B.
+  EXPECT_FALSE(short_util_.ConnectsToEmergencyNumber("\xEF\xBC\x8B" "911",
+      RegionCode::US()));
+  EXPECT_FALSE(short_util_.ConnectsToEmergencyNumber(" +911",
+      RegionCode::US()));
+  EXPECT_FALSE(short_util_.ConnectsToEmergencyNumber("+119", RegionCode::US()));
+  EXPECT_FALSE(short_util_.ConnectsToEmergencyNumber("+999", RegionCode::US()));
+}
+
+TEST_F(ShortNumberUtilTest, ConnectsToEmergencyNumber_BR) {
+  EXPECT_TRUE(short_util_.ConnectsToEmergencyNumber("911", RegionCode::BR()));
+  EXPECT_TRUE(short_util_.ConnectsToEmergencyNumber("190", RegionCode::BR()));
+  EXPECT_FALSE(short_util_.ConnectsToEmergencyNumber("999", RegionCode::BR()));
+}
+
+TEST_F(ShortNumberUtilTest, ConnectsToEmergencyNumberLongNumber_BR) {
+  // Brazilian emergency numbers don't work when additional digits are appended.
+  EXPECT_FALSE(short_util_.ConnectsToEmergencyNumber("9111", RegionCode::BR()));
+  EXPECT_FALSE(short_util_.ConnectsToEmergencyNumber("1900", RegionCode::BR()));
+  EXPECT_FALSE(short_util_.ConnectsToEmergencyNumber("9996", RegionCode::BR()));
+}
+
+TEST_F(ShortNumberUtilTest, ConnectsToEmergencyNumber_AO) {
+  // Angola doesn't have any metadata for emergency numbers in the test
+  // metadata.
+  EXPECT_FALSE(short_util_.ConnectsToEmergencyNumber("911", RegionCode::AO()));
+  EXPECT_FALSE(short_util_.ConnectsToEmergencyNumber("222123456",
+      RegionCode::AO()));
+  EXPECT_FALSE(short_util_.ConnectsToEmergencyNumber("923123456",
+      RegionCode::AO()));
+}
+
+TEST_F(ShortNumberUtilTest, ConnectsToEmergencyNumber_ZW) {
+  // Zimbabwe doesn't have any metadata in the test metadata.
+  EXPECT_FALSE(short_util_.ConnectsToEmergencyNumber("911", RegionCode::ZW()));
+  EXPECT_FALSE(short_util_.ConnectsToEmergencyNumber("01312345",
+      RegionCode::ZW()));
+  EXPECT_FALSE(short_util_.ConnectsToEmergencyNumber("0711234567",
+      RegionCode::ZW()));
+}
+
+TEST_F(ShortNumberUtilTest, IsEmergencyNumber_US) {
+  EXPECT_TRUE(short_util_.IsEmergencyNumber("911", RegionCode::US()));
+  EXPECT_TRUE(short_util_.IsEmergencyNumber("119", RegionCode::US()));
+  EXPECT_FALSE(short_util_.IsEmergencyNumber("999", RegionCode::US()));
+}
+
+TEST_F(ShortNumberUtilTest, IsEmergencyNumberLongNumber_US) {
+  EXPECT_FALSE(short_util_.IsEmergencyNumber("9116666666", RegionCode::US()));
+  EXPECT_FALSE(short_util_.IsEmergencyNumber("1196666666", RegionCode::US()));
+  EXPECT_FALSE(short_util_.IsEmergencyNumber("9996666666", RegionCode::US()));
+}
+
+TEST_F(ShortNumberUtilTest, IsEmergencyNumberWithFormatting_US) {
+  EXPECT_TRUE(short_util_.IsEmergencyNumber("9-1-1", RegionCode::US()));
+  EXPECT_TRUE(short_util_.IsEmergencyNumber("*911", RegionCode::US()));
+  EXPECT_TRUE(short_util_.IsEmergencyNumber("1-1-9", RegionCode::US()));
+  EXPECT_TRUE(short_util_.IsEmergencyNumber("*119", RegionCode::US()));
+  EXPECT_FALSE(short_util_.IsEmergencyNumber("9-9-9", RegionCode::US()));
+  EXPECT_FALSE(short_util_.IsEmergencyNumber("*999", RegionCode::US()));
+}
+
+TEST_F(ShortNumberUtilTest, IsEmergencyNumberWithPlusSign_US) {
+  EXPECT_FALSE(short_util_.IsEmergencyNumber("+911", RegionCode::US()));
+  // This hex sequence is the full-width plus sign U+FF0B.
+  EXPECT_FALSE(short_util_.IsEmergencyNumber("\xEF\xBC\x8B" "911",
+      RegionCode::US()));
+  EXPECT_FALSE(short_util_.IsEmergencyNumber(" +911", RegionCode::US()));
+  EXPECT_FALSE(short_util_.IsEmergencyNumber("+119", RegionCode::US()));
+  EXPECT_FALSE(short_util_.IsEmergencyNumber("+999", RegionCode::US()));
+}
+
+TEST_F(ShortNumberUtilTest, IsEmergencyNumber_BR) {
+  EXPECT_TRUE(short_util_.IsEmergencyNumber("911", RegionCode::BR()));
+  EXPECT_TRUE(short_util_.IsEmergencyNumber("190", RegionCode::BR()));
+  EXPECT_FALSE(short_util_.IsEmergencyNumber("999", RegionCode::BR()));
+}
+
+TEST_F(ShortNumberUtilTest, EmergencyNumberLongNumber_BR) {
+  EXPECT_FALSE(short_util_.IsEmergencyNumber("9111", RegionCode::BR()));
+  EXPECT_FALSE(short_util_.IsEmergencyNumber("1900", RegionCode::BR()));
+  EXPECT_FALSE(short_util_.IsEmergencyNumber("9996", RegionCode::BR()));
+}
+
+TEST_F(ShortNumberUtilTest, IsEmergencyNumber_AO) {
+  // Angola doesn't have any metadata for emergency numbers in the test
+  // metadata.
+  EXPECT_FALSE(short_util_.IsEmergencyNumber("911", RegionCode::AO()));
+  EXPECT_FALSE(short_util_.IsEmergencyNumber("222123456", RegionCode::AO()));
+  EXPECT_FALSE(short_util_.IsEmergencyNumber("923123456", RegionCode::AO()));
+}
+
+TEST_F(ShortNumberUtilTest, IsEmergencyNumber_ZW) {
+  // Zimbabwe doesn't have any metadata in the test metadata.
+  EXPECT_FALSE(short_util_.IsEmergencyNumber("911", RegionCode::ZW()));
+  EXPECT_FALSE(short_util_.IsEmergencyNumber("01312345", RegionCode::ZW()));
+  EXPECT_FALSE(short_util_.IsEmergencyNumber("0711234567", RegionCode::ZW()));
+}
+
+}  // namespace phonenumbers
+}  // namespace i18n
index 5e65aec..0a3957d 100644 (file)
@@ -141,6 +141,10 @@ class RegionCode {
     return "YT";
   }
 
+  static const char* ZW() {
+    return "ZW";
+  }
+
   // Returns a region code string representing the "unknown" region.
   static const char* GetUnknown() {
     return "ZZ";