CPP: Add AsYouTypeFormatter (port from Java).
authorphilip.liard@gmail.com <philip.liard@gmail.com@ee073f10-1060-11df-b6a4-87a95322a99c>
Wed, 14 Sep 2011 10:42:59 +0000 (10:42 +0000)
committerphilip.liard@gmail.com <philip.liard@gmail.com@ee073f10-1060-11df-b6a4-87a95322a99c>
Wed, 14 Sep 2011 10:42:59 +0000 (10:42 +0000)
git-svn-id: http://libphonenumber.googlecode.com/svn/trunk@352 ee073f10-1060-11df-b6a4-87a95322a99c

cpp/CMakeLists.txt
cpp/src/base/logging.h
cpp/src/phonenumbers/asyoutypeformatter.cc [new file with mode: 0644]
cpp/src/phonenumbers/asyoutypeformatter.h [new file with mode: 0644]
cpp/src/phonenumbers/phonenumberutil.cc
cpp/src/phonenumbers/phonenumberutil.h
cpp/src/phonenumbers/unicodestring.cc [new file with mode: 0644]
cpp/src/phonenumbers/unicodestring.h [new file with mode: 0644]
cpp/test/phonenumbers/asyoutypeformatter_test.cc [new file with mode: 0644]
cpp/test/phonenumbers/unicodestring_test.cc [new file with mode: 0644]
tools/script/continuous-integration.sh

index 0be3d68..f152613 100644 (file)
@@ -153,6 +153,7 @@ add_custom_target (
 set (
   SOURCES
   "src/base/string_piece.cc"
+  "src/phonenumbers/asyoutypeformatter.cc"
   "src/phonenumbers/default_logger.cc"
   "src/phonenumbers/logger.cc"
   "src/phonenumbers/metadata.h"          # Generated by build tools.
@@ -162,6 +163,7 @@ set (
   "src/phonenumbers/phonenumberutil.cc"
   "src/phonenumbers/regexp_cache.cc"
   "src/phonenumbers/stringutil.cc"
+  "src/phonenumbers/unicodestring.cc"
   "src/phonenumbers/utf/rune.c"
   "src/phonenumbers/utf/unicodetext.cc"
   "src/phonenumbers/utf/unilib.cc"
@@ -291,12 +293,14 @@ target_link_libraries (phonenumber_testing ${LIBRARY_DEPS})
 add_dependencies (phonenumber_testing generate-sources ${TEST_METADATA_TARGET})
 
 set (TEST_SOURCES
+  "test/phonenumbers/asyoutypeformatter_test.cc"
   "test/phonenumbers/logger_test.cc"
   "test/phonenumbers/phonenumberutil_test.cc"
   "test/phonenumbers/regexp_adapter_test.cc"
   "test/phonenumbers/regexp_cache_test.cc"
   "test/phonenumbers/run_tests.cc"
   "test/phonenumbers/stringutil_test.cc"
+  "test/phonenumbers/unicodestring_test.cc"
   "test/phonenumbers/utf/unicodetext_test.cc"
 )
 
@@ -311,12 +315,20 @@ add_custom_target(test COMMAND libphonenumber_test DEPENDS libphonenumber_test)
 
 # Install rules.
 install (FILES
+  "src/phonenumbers/asyoutypeformatter.h"
   "src/phonenumbers/logger.h"
   "src/phonenumbers/phonenumber.pb.h"
+  "src/phonenumbers/phonemetadata.pb.h"
   "src/phonenumbers/phonenumberutil.h"
+  "src/phonenumbers/regexp_adapter.h"
+  "src/phonenumbers/regexp_cache.h"
+  "src/phonenumbers/unicodestring.h"
   DESTINATION include/phonenumbers/
 )
 
+install (FILES "src/phonenumbers/utf/unicodetext.h"
+         DESTINATION include/phonenumbers/utf/)
+
 install (FILES src/base/basictypes.h
          DESTINATION include/base/)
 
index aeb9f14..ce31e34 100644 (file)
 
 // Author: Philippe Liard
 
-// This file does not come from Chromium.
-// It provides a minimalist implementation of common macros.
+// This file provides a minimalist implementation of common macros.
 
 #ifndef BASE_LOGGING_H_
-# define BASE_LOGGING_H_
+#define BASE_LOGGING_H_
 
-# include <cassert>
-# include <iostream>
+#include <cassert>
 
-# define CHECK_EQ(X, Y) assert((X) == (Y))
+#define CHECK_EQ(X, Y) assert((X) == (Y))
 
-# define DCHECK(X) assert(X)
-# define DCHECK_EQ(X, Y) CHECK_EQ((X), (Y))
+#define DCHECK(X) assert(X)
+#define DCHECK_EQ(X, Y) CHECK_EQ((X), (Y))
 
-# define NOTREACHED() std::cerr
+template <typename T> T* CHECK_NOTNULL(T* ptr) {
+  assert(ptr);
+  return ptr;
+}
 
-#endif
+#endif  // BASE_LOGGING_H_
diff --git a/cpp/src/phonenumbers/asyoutypeformatter.cc b/cpp/src/phonenumbers/asyoutypeformatter.cc
new file mode 100644 (file)
index 0000000..057fc7e
--- /dev/null
@@ -0,0 +1,629 @@
+// Copyright (C) 2011 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.
+
+#include "phonenumbers/asyoutypeformatter.h"
+
+#include <cctype>
+#include <list>
+#include <string>
+
+#include <google/protobuf/message_lite.h>
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "phonenumbers/phonemetadata.pb.h"
+#include "phonenumbers/phonenumberutil.h"
+#include "phonenumbers/regexp_cache.h"
+#include "phonenumbers/regexp_factory.h"
+#include "phonenumbers/stringutil.h"
+#include "phonenumbers/unicodestring.h"
+
+namespace i18n {
+namespace phonenumbers {
+
+using google::protobuf::RepeatedPtrField;
+
+namespace {
+
+const char kPlusSign = '+';
+
+// A pattern that is used to match character classes in regular expressions.
+// An example of a character class is [1-4].
+const char kCharacterClassPattern[] = "\\[([^\\[\\]])*\\]";
+
+// This is the minimum length of national number accrued that is required to
+// trigger the formatter. The first element of the leading_digits_pattern of
+// each number_format contains a regular expression that matches up to this
+// number of digits.
+const size_t kMinLeadingDigitsLength = 3;
+
+// The digits that have not been entered yet will be represented by a \u2008,
+// the punctuation space.
+const char kDigitPlaceholder[] = "\xE2\x80\x88"; /* " " */
+
+// Replaces any standalone digit in the pattern (not any inside a {} grouping)
+// with \d. This function replaces the standalone digit regex used in the Java
+// version which is currently not supported by RE2 because it uses a special
+// construct (?=).
+void ReplacePatternDigits(string* pattern) {
+  DCHECK(pattern);
+  string new_pattern;
+
+  for (string::const_iterator it = pattern->begin(); it != pattern->end();
+       ++it) {
+    const char current_char = *it;
+
+    if (isdigit(current_char)) {
+      if (it + 1 != pattern->end()) {
+        const char next_char = it[1];
+
+        if (next_char != ',' && next_char != '}') {
+          new_pattern += "\\d";
+        } else {
+          new_pattern += current_char;
+        }
+      } else {
+        new_pattern += "\\d";
+      }
+    } else {
+      new_pattern += current_char;
+    }
+  }
+  pattern->assign(new_pattern);
+}
+
+// Matches all the groups contained in 'input' against 'pattern'.
+void MatchAllGroups(const string& pattern,
+                    const string& input,
+                    const AbstractRegExpFactory& regexp_factory,
+                    RegExpCache* cache,
+                    string* group) {
+  DCHECK(cache);
+  DCHECK(group);
+  string new_pattern(pattern);
+
+  // Transforms pattern "(...)(...)(...)" to "(.........)".
+  strrmm(&new_pattern, "()");
+  new_pattern = StrCat("(", new_pattern, ")");
+
+  const scoped_ptr<RegExpInput> consume_input(
+      regexp_factory.CreateInput(input));
+  bool status =
+      cache->GetRegExp(new_pattern).Consume(consume_input.get(), group);
+  DCHECK(status);
+}
+
+PhoneMetadata CreateEmptyMetadata() {
+  PhoneMetadata metadata;
+  metadata.set_international_prefix("NA");
+  return metadata;
+}
+
+}  // namespace
+
+AsYouTypeFormatter::AsYouTypeFormatter(const string& region_code)
+    : regexp_factory_(new RegExpFactory()),
+      regexp_cache_(*regexp_factory_.get(), 64),
+      current_output_(),
+      formatting_template_(),
+      current_formatting_pattern_(),
+      accrued_input_(),
+      accrued_input_without_formatting_(),
+      able_to_format_(true),
+      is_international_formatting_(false),
+      is_expecting_country_code_(false),
+      phone_util_(*PhoneNumberUtil::GetInstance()),
+      default_country_(region_code),
+      empty_metadata_(CreateEmptyMetadata()),
+      default_metadata_(GetMetadataForRegion(region_code)),
+      current_metadata_(default_metadata_),
+      last_match_position_(0),
+      original_position_(0),
+      position_to_remember_(0),
+      prefix_before_national_number_(),
+      national_number_(),
+      possible_formats_() {
+}
+
+// The metadata needed by this class is the same for all regions sharing the
+// same country calling code. Therefore, we return the metadata for "main"
+// region for this country calling code.
+const PhoneMetadata* AsYouTypeFormatter::GetMetadataForRegion(
+    const string& region_code) const {
+  int country_calling_code = phone_util_.GetCountryCodeForRegion(region_code);
+  string main_country;
+  phone_util_.GetRegionCodeForCountryCode(country_calling_code, &main_country);
+  const PhoneMetadata* const metadata =
+      phone_util_.GetMetadataForRegion(main_country);
+  if (metadata) {
+    return metadata;
+  }
+  // Set to a default instance of the metadata. This allows us to function with
+  // an incorrect region code, even if formatting only works for numbers
+  // specified with "+".
+  return &empty_metadata_;
+}
+
+bool AsYouTypeFormatter::MaybeCreateNewTemplate() {
+  // When there are multiple available formats, the formatter uses the first
+  // format where a formatting template could be created.
+  for (list<const NumberFormat*>::const_iterator it = possible_formats_.begin();
+       it != possible_formats_.end(); ++it) {
+    DCHECK(*it);
+    const NumberFormat& number_format = **it;
+    const string& pattern = number_format.pattern();
+    if (current_formatting_pattern_ == pattern) {
+      return false;
+    }
+    if (CreateFormattingTemplate(number_format)) {
+      current_formatting_pattern_ = pattern;
+      return true;
+    }
+  }
+  able_to_format_ = false;
+  return false;
+}
+
+void AsYouTypeFormatter::GetAvailableFormats(
+    const string& leading_three_digits) {
+  const RepeatedPtrField<NumberFormat>& format_list =
+      (is_international_formatting_ &&
+       current_metadata_->intl_number_format().size() > 0)
+          ? current_metadata_->intl_number_format()
+          : current_metadata_->number_format();
+
+  for (RepeatedPtrField<NumberFormat>::const_iterator it = format_list.begin();
+       it != format_list.end(); ++it) {
+    if (phone_util_.IsFormatEligibleForAsYouTypeFormatter(it->format())) {
+      possible_formats_.push_back(&*it);
+    }
+  }
+  NarrowDownPossibleFormats(leading_three_digits);
+}
+
+void AsYouTypeFormatter::NarrowDownPossibleFormats(
+    const string& leading_digits) {
+  const int index_of_leading_digits_pattern =
+      leading_digits.length() - kMinLeadingDigitsLength;
+
+  for (list<const NumberFormat*>::iterator it = possible_formats_.begin();
+       it != possible_formats_.end(); ) {
+    DCHECK(*it);
+    const NumberFormat& format = **it;
+
+    if (format.leading_digits_pattern_size() >
+        index_of_leading_digits_pattern) {
+      const scoped_ptr<RegExpInput> input(
+          regexp_factory_->CreateInput(leading_digits));
+      if (!regexp_cache_.GetRegExp(format.leading_digits_pattern().Get(
+              index_of_leading_digits_pattern)).Consume(input.get())) {
+        it = possible_formats_.erase(it);
+        continue;
+      }
+    }  // else the particular format has no more specific leadingDigitsPattern,
+       // and it should be retained.
+    ++it;
+  }
+}
+
+bool AsYouTypeFormatter::CreateFormattingTemplate(const NumberFormat& format) {
+  string number_pattern = format.pattern();
+
+  // The formatter doesn't format numbers when numberPattern contains "|", e.g.
+  // (20|3)\d{4}. In those cases we quickly return.
+  if (number_pattern.find('|') != string::npos) {
+    return false;
+  }
+  // Replace anything in the form of [..] with \d.
+  static const scoped_ptr<const RegExp> character_class_pattern(
+      regexp_factory_->CreateRegExp(kCharacterClassPattern));
+  character_class_pattern->GlobalReplace(&number_pattern, "\\\\d");
+
+  // Replace any standalone digit (not the one in d{}) with \d.
+  ReplacePatternDigits(&number_pattern);
+
+  string number_format = format.format();
+  formatting_template_.remove();
+  UnicodeString temp_template;
+  GetFormattingTemplate(number_pattern, number_format, &temp_template);
+
+  if (temp_template.length() > 0) {
+    formatting_template_.append(temp_template);
+    return true;
+  }
+  return false;
+}
+
+void AsYouTypeFormatter::GetFormattingTemplate(
+    const string& number_pattern,
+    const string& number_format,
+    UnicodeString* formatting_template) {
+  DCHECK(formatting_template);
+
+  // Creates a phone number consisting only of the digit 9 that matches the
+  // number_pattern by applying the pattern to the longest_phone_number string.
+  static const char longest_phone_number[] = "999999999999999";
+  string a_phone_number;
+
+  MatchAllGroups(number_pattern, longest_phone_number, *regexp_factory_,
+                 &regexp_cache_, &a_phone_number);
+  // No formatting template can be created if the number of digits entered so
+  // far is longer than the maximum the current formatting rule can accommodate.
+  if (a_phone_number.length() < national_number_.length()) {
+    formatting_template->remove();
+    return;
+  }
+  // Formats the number according to number_format.
+  regexp_cache_.GetRegExp(number_pattern).GlobalReplace(
+      &a_phone_number, number_format);
+  // Replaces each digit with character kDigitPlaceholder.
+  GlobalReplaceSubstring("9", kDigitPlaceholder, &a_phone_number);
+  formatting_template->setTo(a_phone_number.c_str(), a_phone_number.size());
+}
+
+void AsYouTypeFormatter::Clear() {
+  current_output_.clear();
+  accrued_input_.remove();
+  accrued_input_without_formatting_.remove();
+  formatting_template_.remove();
+  last_match_position_ = 0;
+  current_formatting_pattern_.clear();
+  prefix_before_national_number_.clear();
+  national_number_.clear();
+  able_to_format_ = true;
+  position_to_remember_ = 0;
+  original_position_ = 0;
+  is_international_formatting_ = false;
+  is_expecting_country_code_ = false;
+  possible_formats_.clear();
+
+  if (current_metadata_ != default_metadata_) {
+    current_metadata_ = GetMetadataForRegion(default_country_);
+  }
+}
+
+const string& AsYouTypeFormatter::InputDigit(char32 next_char, string* result) {
+  DCHECK(result);
+
+  InputDigitWithOptionToRememberPosition(next_char, false, &current_output_);
+  result->assign(current_output_);
+  return *result;
+}
+
+const string& AsYouTypeFormatter::InputDigitAndRememberPosition(
+    char32 next_char,
+    string* result) {
+  DCHECK(result);
+
+  InputDigitWithOptionToRememberPosition(next_char, true, &current_output_);
+  result->assign(current_output_);
+  return *result;
+}
+
+void AsYouTypeFormatter::InputDigitWithOptionToRememberPosition(
+    char32 next_char,
+    bool remember_position,
+    string* phone_number) {
+  DCHECK(phone_number);
+
+  accrued_input_.append(next_char);
+  if (remember_position) {
+    original_position_ = accrued_input_.length();
+  }
+  // We do formatting on-the-fly only when each character entered is either a
+  // plus sign or a digit.
+  string next_char_string;
+  UnicodeString(next_char).toUTF8String(next_char_string);
+
+  if (next_char != kPlusSign &&
+      !phone_util_.ContainsOnlyValidDigits(next_char_string)) {
+    able_to_format_ = false;
+  }
+  if (!able_to_format_) {
+    phone_number->clear();
+    accrued_input_.toUTF8String(*phone_number);
+    return;
+  }
+  char normalized_next_char =
+      NormalizeAndAccrueDigitsAndPlusSign(next_char, remember_position);
+  // We start to attempt to format only when at least kMinLeadingDigitsLength
+  // digits (the plus sign is counted as a digit as well for this purpose) have
+  // been entered.
+  switch (accrued_input_without_formatting_.length()) {
+    case 0:
+    case 1:
+    case 2:
+      phone_number->clear();
+      accrued_input_.toUTF8String(*phone_number);
+      return;
+    case 3:
+      if (AttemptToExtractIdd()) {
+        is_expecting_country_code_ = true;
+      } else {
+        // No IDD or plus sign is found, must be entering in national format.
+        RemoveNationalPrefixFromNationalNumber();
+        AttemptToChooseFormattingPattern(phone_number);
+        return;
+      }
+    case 4:
+    case 5:
+      if (is_expecting_country_code_) {
+        if (AttemptToExtractCountryCode()) {
+          is_expecting_country_code_ = false;
+        }
+        phone_number->assign(prefix_before_national_number_);
+        phone_number->append(national_number_);
+        return;
+      }
+    // We make a last attempt to extract a country code at the 6th digit because
+    // the maximum length of IDD and country code are both 3.
+    case 6:
+      if (is_expecting_country_code_ && !AttemptToExtractCountryCode()) {
+        able_to_format_ = false;
+        phone_number->clear();
+        accrued_input_.toUTF8String(*phone_number);
+        return;
+      }
+    default:
+      if (possible_formats_.size() > 0) {
+        // The formatting pattern is already chosen.
+        string temp_national_number;
+        InputDigitHelper(normalized_next_char, &temp_national_number);
+        // See if accrued digits can be formatted properly already. If not, use
+        // the results from InputDigitHelper, which does formatting based on the
+        // formatting pattern chosen.
+        string formatted_number;
+        AttemptToFormatAccruedDigits(&formatted_number);
+        if (formatted_number.length() > 0) {
+          phone_number->assign(formatted_number);
+          return;
+        }
+        NarrowDownPossibleFormats(national_number_);
+        if (MaybeCreateNewTemplate()) {
+          InputAccruedNationalNumber(phone_number);
+          return;
+        }
+        phone_number->assign(able_to_format_
+            ? prefix_before_national_number_ + temp_national_number
+            : temp_national_number);
+      } else {
+        AttemptToChooseFormattingPattern(phone_number);
+      }
+  }
+}
+
+void AsYouTypeFormatter::AttemptToFormatAccruedDigits(
+    string* formatted_number) {
+  DCHECK(formatted_number);
+
+  for (list<const NumberFormat*>::const_iterator it = possible_formats_.begin();
+       it != possible_formats_.end(); ++it) {
+    DCHECK(*it);
+    const NumberFormat& num_format = **it;
+    string pattern = num_format.pattern();
+
+    if (regexp_cache_.GetRegExp(pattern).FullMatch(national_number_)) {
+      formatted_number->assign(national_number_);
+      string new_formatted_number(*formatted_number);
+      string format = num_format.format();
+
+      bool status = regexp_cache_.GetRegExp(pattern).GlobalReplace(
+          &new_formatted_number, format);
+      DCHECK(status);
+
+      formatted_number->assign(prefix_before_national_number_);
+      formatted_number->append(new_formatted_number);
+      return;
+    }
+  }
+  formatted_number->clear();
+}
+
+int AsYouTypeFormatter::GetRememberedPosition() const {
+  UnicodeString current_output(current_output_.c_str());
+  if (!able_to_format_) {
+    return ConvertUnicodeStringPosition(current_output, original_position_);
+  }
+  int accrued_input_index = 0;
+  int current_output_index = 0;
+
+  while (accrued_input_index < position_to_remember_ &&
+         current_output_index < current_output.length()) {
+    if (accrued_input_without_formatting_[accrued_input_index] ==
+        current_output[current_output_index]) {
+      ++accrued_input_index;
+    }
+    ++current_output_index;
+  }
+  return ConvertUnicodeStringPosition(current_output, current_output_index);
+}
+
+void AsYouTypeFormatter::AttemptToChooseFormattingPattern(
+    string* formatted_number) {
+  DCHECK(formatted_number);
+
+  if (national_number_.length() >= kMinLeadingDigitsLength) {
+    const string leading_digits =
+        national_number_.substr(0, kMinLeadingDigitsLength);
+
+    GetAvailableFormats(leading_digits);
+    MaybeCreateNewTemplate();
+    InputAccruedNationalNumber(formatted_number);
+  } else {
+    formatted_number->assign(prefix_before_national_number_ + national_number_);
+  }
+}
+
+void AsYouTypeFormatter::InputAccruedNationalNumber(string* number) {
+  DCHECK(number);
+  int length_of_national_number = national_number_.length();
+
+  if (length_of_national_number > 0) {
+    string temp_national_number;
+
+    for (int i = 0; i < length_of_national_number; ++i) {
+      temp_national_number.clear();
+      InputDigitHelper(national_number_[i], &temp_national_number);
+    }
+    number->assign(able_to_format_
+        ? prefix_before_national_number_ + temp_national_number
+        : temp_national_number);
+  } else {
+    number->assign(prefix_before_national_number_);
+  }
+}
+
+void AsYouTypeFormatter::RemoveNationalPrefixFromNationalNumber() {
+  int start_of_national_number = 0;
+
+  if (current_metadata_->country_code() == 1 && national_number_[0] == '1') {
+    start_of_national_number = 1;
+    prefix_before_national_number_.append("1 ");
+    is_international_formatting_ = true;
+  } else if (current_metadata_->has_national_prefix()) {
+    const scoped_ptr<RegExpInput> consumed_input(
+        regexp_factory_->CreateInput(national_number_));
+    const RegExp& pattern = regexp_cache_.GetRegExp(
+        current_metadata_->national_prefix_for_parsing());
+
+    if (pattern.Consume(consumed_input.get())) {
+      // When the national prefix is detected, we use international formatting
+      // rules instead of national ones, because national formatting rules could
+      // countain local formatting rules for numbers entered without area code.
+      is_international_formatting_ = true;
+      start_of_national_number =
+          national_number_.length() - consumed_input->ToString().length();
+      prefix_before_national_number_.append(
+          national_number_.substr(0, start_of_national_number));
+    }
+  }
+  national_number_.erase(0, start_of_national_number);
+}
+
+bool AsYouTypeFormatter::AttemptToExtractIdd() {
+  string accrued_input_without_formatting_stdstring;
+  accrued_input_without_formatting_
+      .toUTF8String(accrued_input_without_formatting_stdstring);
+  const scoped_ptr<RegExpInput> consumed_input(
+      regexp_factory_->CreateInput(accrued_input_without_formatting_stdstring));
+  const RegExp& international_prefix = regexp_cache_.GetRegExp(
+      StrCat("\\", string(&kPlusSign, 1), "|",
+             current_metadata_->international_prefix()));
+
+  if (international_prefix.Consume(consumed_input.get())) {
+    is_international_formatting_ = true;
+    const int start_of_country_code =
+        accrued_input_without_formatting_.length() -
+        consumed_input->ToString().length();
+
+    national_number_.clear();
+    accrued_input_without_formatting_.tempSubString(start_of_country_code)
+        .toUTF8String(national_number_);
+
+    string before_country_code;
+    accrued_input_without_formatting_.tempSubString(0, start_of_country_code)
+        .toUTF8String(before_country_code);
+    prefix_before_national_number_.append(before_country_code);
+
+    if (accrued_input_without_formatting_[0] != kPlusSign) {
+      prefix_before_national_number_.append(" ");
+    }
+    return true;
+  }
+  return false;
+}
+
+bool AsYouTypeFormatter::AttemptToExtractCountryCode() {
+  if (national_number_.length() == 0) {
+    return false;
+  }
+  string number_without_country_code(national_number_);
+  int country_code =
+    phone_util_.ExtractCountryCode(&number_without_country_code);
+  if (country_code == 0) {
+    return false;
+  }
+  national_number_.assign(number_without_country_code);
+  string new_region_code;
+  phone_util_.GetRegionCodeForCountryCode(country_code, &new_region_code);
+
+  if (new_region_code != default_country_) {
+    current_metadata_ = GetMetadataForRegion(new_region_code);
+  }
+  StrAppend(&prefix_before_national_number_, country_code, " ");
+
+  return true;
+}
+
+char AsYouTypeFormatter::NormalizeAndAccrueDigitsAndPlusSign(
+    char32 next_char,
+    bool remember_position) {
+  char normalized_char = next_char;
+
+  if (next_char == kPlusSign) {
+    accrued_input_without_formatting_.append(next_char);
+  } else {
+    string number;
+    UnicodeString(next_char).toUTF8String(number);
+    phone_util_.NormalizeDigitsOnly(&number);
+    accrued_input_without_formatting_.append(next_char);
+    national_number_.append(number);
+    normalized_char = number[0];
+  }
+  if (remember_position) {
+    position_to_remember_ = accrued_input_without_formatting_.length();
+  }
+  return normalized_char;
+}
+
+void AsYouTypeFormatter::InputDigitHelper(char next_char, string* number) {
+  DCHECK(number);
+  number->clear();
+  const char32 placeholder_codepoint = UnicodeString(kDigitPlaceholder)[0];
+  int placeholder_pos = formatting_template_
+      .tempSubString(last_match_position_).indexOf(placeholder_codepoint);
+  if (placeholder_pos != -1) {
+    UnicodeString temp_template = formatting_template_;
+    placeholder_pos = temp_template.indexOf(placeholder_codepoint);
+    temp_template.setCharAt(placeholder_pos, UnicodeString(next_char)[0]);
+    last_match_position_ = placeholder_pos;
+    formatting_template_.replace(0, temp_template.length(), temp_template);
+    formatting_template_.tempSubString(0, last_match_position_ + 1)
+        .toUTF8String(*number);
+  } else {
+    if (possible_formats_.size() == 1) {
+      // More digits are entered than we could handle, and there are no other
+      // valid patterns to try.
+      able_to_format_ = false;
+    }  // else, we just reset the formatting pattern.
+    current_formatting_pattern_.clear();
+    accrued_input_.toUTF8String(*number);
+  }
+}
+
+// Returns the number of bytes contained in the given UnicodeString up to the
+// specified position.
+// static
+int AsYouTypeFormatter::ConvertUnicodeStringPosition(const UnicodeString& s,
+                                                     int pos) {
+  if (pos > s.length()) {
+    return -1;
+  }
+  string substring;
+  s.tempSubString(0, pos).toUTF8String(substring);
+  return substring.length();
+}
+
+}  // namespace phonenumbers
+}  // namespace i18n
diff --git a/cpp/src/phonenumbers/asyoutypeformatter.h b/cpp/src/phonenumbers/asyoutypeformatter.h
new file mode 100644 (file)
index 0000000..2ae3aa3
--- /dev/null
@@ -0,0 +1,197 @@
+// Copyright (C) 2011 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.
+
+// A formatter which formats phone numbers as they are entered.
+//
+// An AsYouTypeFormatter can be created by invoking the GetAsYouTypeFormatter
+// method of the PhoneNumberUtil. After that digits can be added by invoking the
+// InputDigit method on the formatter instance, and the partially formatted
+// phone number will be returned each time a digit is added. The Clear method
+// can be invoked before a new number needs to be formatted.
+//
+// See AYTF_US, AYTF_GBFixedLine and AYTF_DE test functions in
+// asyoutypeformatter_test.cc for more details on how the formatter is to be
+// used.
+//
+// This is a direct port from AsYouTypeFormatter.java.  Changes to this class
+// should also happen to the Java version, whenever it makes sense.
+//
+// This class is NOT THREAD SAFE.
+
+#ifndef I18N_PHONENUMBERS_ASYOUTYPEFORMATTER_H_
+#define I18N_PHONENUMBERS_ASYOUTYPEFORMATTER_H_
+
+#include <list>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "phonenumbers/regexp_adapter.h"
+#include "phonenumbers/regexp_cache.h"
+#include "phonenumbers/phonemetadata.pb.h"
+#include "phonenumbers/unicodestring.h"
+
+namespace i18n {
+namespace phonenumbers {
+
+using std::list;
+using std::string;
+
+class PhoneNumberUtil;
+
+class AsYouTypeFormatter {
+ public:
+  ~AsYouTypeFormatter() {}
+
+  // Formats a phone number on-the-fly as each digit is entered.
+  // next_char is the most recently entered digit of a phone number. Formatting
+  // characters are allowed, but as soon as they are encountered this method
+  // formats the number as entered and not "as you type" anymore. Full width
+  // digits and Arabic-indic digits are allowed, and will be shown as they are.
+  // Returns the partially formatted phone number (which is a reference to the
+  // given string parameter for convenience).
+  const string& InputDigit(char32 next_char, string* result);
+
+  // Same as InputDigit, but remembers the position where next_char is inserted,
+  // so that it could be retrieved later by using GetRememberedPosition(). The
+  // remembered position will be automatically adjusted if additional formatting
+  // characters are later inserted/removed in front of next_char.
+  // Returns the partially formatted phone number (which is a reference to the
+  // given string parameter for convenience).
+  const string& InputDigitAndRememberPosition(char32 next_char, string* result);
+
+  // Returns the current position in the partially formatted phone number of the
+  // character which was previously passed in as the parameter of
+  // InputDigitAndRememberPosition().
+  int GetRememberedPosition() const;
+
+  // Clears the internal state of the formatter, so it could be reused.
+  void Clear();
+
+ private:
+  // Constructs an as-you-type formatter. Should be obtained from
+  // PhoneNumberUtil::GetAsYouTypeFormatter().
+  explicit AsYouTypeFormatter(const string& region_code);
+
+  // Returns the metadata corresponding to the given region code or empty
+  // metadata if it is unsupported.
+  const PhoneMetadata* GetMetadataForRegion(const string& region_code) const;
+
+  // Returns true if a new template is created as opposed to reusing the
+  // existing template.
+  bool MaybeCreateNewTemplate();
+
+  void GetAvailableFormats(const string& leading_three_digits);
+
+  void NarrowDownPossibleFormats(const string& leading_digits);
+
+  bool CreateFormattingTemplate(const NumberFormat& format);
+
+  // Gets a formatting template which could be used to efficiently format a
+  // partial number where digits are added one by one.
+  void GetFormattingTemplate(const string& number_pattern,
+                             const string& number_format,
+                             UnicodeString* formatting_template);
+
+  void InputDigitWithOptionToRememberPosition(char32 next_char,
+                                              bool remember_position,
+                                              string* phone_number);
+
+  void AttemptToFormatAccruedDigits(string* formatted_number);
+
+  // Attempts to set the formatting template and assigns the passed-in string
+  // parameter to the formatted version of the digits entered so far.
+  void AttemptToChooseFormattingPattern(string* formatted_number);
+
+  // Invokes InputDigitHelper on each digit of the national number accrued, and
+  // assigns the passed-in string parameter to a formatted string in the end.
+  void InputAccruedNationalNumber(string* number);
+
+  void RemoveNationalPrefixFromNationalNumber();
+
+  // Extracts IDD and plus sign to prefix_before_national_number_ when they are
+  // available, and places the remaining input into national_number_.
+  bool AttemptToExtractIdd();
+
+  // Extracts country code from the begining of national_number_ to
+  // prefix_before_national_number_ when they are available, and places the
+  // remaining input into national_number_.
+  // Returns true when a valid country code can be found.
+  bool AttemptToExtractCountryCode();
+
+  // Accrues digits and the plus sign to accrued_input_without_formatting for
+  // later use. If next_char contains a digit in non-ASCII format (e.g the
+  // full-width version of digits), it is first normalized to the ASCII
+  // version. The return value is next_char itself, or its normalized version,
+  // if next_char is a digit in non-ASCII format.
+  char NormalizeAndAccrueDigitsAndPlusSign(char32 next_char,
+                                           bool remember_position);
+
+  void InputDigitHelper(char next_char, string* number);
+
+  // Converts UnicodeString position to std::string position.
+  static int ConvertUnicodeStringPosition(const UnicodeString& s, int pos);
+
+  // Class attributes.
+  const scoped_ptr<const AbstractRegExpFactory> regexp_factory_;
+  RegExpCache regexp_cache_;
+
+  string current_output_;
+
+  UnicodeString formatting_template_;
+  string current_formatting_pattern_;
+
+  UnicodeString accrued_input_;
+  UnicodeString accrued_input_without_formatting_;
+
+  bool able_to_format_;
+  bool is_international_formatting_;
+  bool is_expecting_country_code_;
+
+  const PhoneNumberUtil& phone_util_;
+
+  const string default_country_;
+
+  const PhoneMetadata empty_metadata_;
+  const PhoneMetadata* const default_metadata_;
+  const PhoneMetadata* current_metadata_;
+
+  int last_match_position_;
+
+  // The position of a digit upon which InputDigitAndRememberPosition is most
+  // recently invoked, as found in the original sequence of characters the user
+  // entered.
+  int original_position_;
+
+  // The position of a digit upon which InputDigitAndRememberPosition is most
+  // recently invoked, as found in AccruedInputWithoutFormatting.
+  int position_to_remember_;
+
+  string prefix_before_national_number_;
+  string national_number_;
+
+  list<const NumberFormat*> possible_formats_;
+
+  friend class PhoneNumberUtil;
+  friend class AsYouTypeFormatterTest;
+
+  // Disallow copy and assign since this class uses RegExpCache which can't be
+  // copied.
+  DISALLOW_COPY_AND_ASSIGN(AsYouTypeFormatter);
+};
+
+}  // namespace phonenumbers
+}  // namespace i18n
+
+#endif  // I18N_PHONENUMBERS_ASYOUTYPEFORMATTER_H_
index d81a80c..3c24fdc 100644 (file)
@@ -34,6 +34,7 @@
 
 #include "base/logging.h"
 #include "base/memory/singleton.h"
+#include "phonenumbers/asyoutypeformatter.h"
 #include "phonenumbers/default_logger.h"
 #include "phonenumbers/encoding_utils.h"
 #include "phonenumbers/metadata.h"
@@ -748,6 +749,10 @@ const string& PhoneNumberUtil::GetExtnPatternsForMatching() const {
   return *(extn_patterns_for_matching.get());
 }
 
+bool PhoneNumberUtil::ContainsOnlyValidDigits(const string& s) const {
+  return digits_pattern->FullMatch(s);
+}
+
 void PhoneNumberUtil::TrimUnwantedEndChars(string* number) const {
   DCHECK(number);
   UnicodeText number_as_unicode;
@@ -767,6 +772,20 @@ void PhoneNumberUtil::TrimUnwantedEndChars(string* number) const {
                                             reverse_it.base()));
 }
 
+bool PhoneNumberUtil::IsFormatEligibleForAsYouTypeFormatter(
+    const string& format) const {
+  // A pattern that is used to determine if a numberFormat under
+  // availableFormats is eligible to be used by the AYTF. It is eligible when
+  // the format element under numberFormat contains groups of the dollar sign
+  // followed by a single digit, separated by valid phone number punctuation.
+  // This prevents invalid punctuation (such as the star sign in Israeli star
+  // numbers) getting into the output of the AYTF.
+  const RegExp& eligible_format_pattern = regexp_cache->GetRegExp(
+      StrCat("[", kValidPunctuation, "]*", "(\\$\\d", "[",
+             kValidPunctuation, "]*)+"));
+  return eligible_format_pattern.FullMatch(format);
+}
+
 void PhoneNumberUtil::GetSupportedRegions(set<string>* regions) const {
   DCHECK(regions);
   for (map<string, PhoneMetadata>::const_iterator it =
@@ -2207,5 +2226,10 @@ PhoneNumberUtil::MatchType PhoneNumberUtil::IsNumberMatchWithOneString(
   return INVALID_NUMBER;
 }
 
+AsYouTypeFormatter* PhoneNumberUtil::GetAsYouTypeFormatter(
+    const string& region_code) const {
+  return new AsYouTypeFormatter(region_code);
+}
+
 }  // namespace phonenumbers
 }  // namespace i18n
index 8115fbb..c35de85 100644 (file)
@@ -46,6 +46,7 @@ using std::vector;
 
 using google::protobuf::RepeatedPtrField;
 
+class AsYouTypeFormatter;
 class Logger;
 class NumberFormat;
 class PhoneMetadata;
@@ -65,6 +66,7 @@ class PhoneNumberUtil {
 class PhoneNumberUtil : public Singleton<PhoneNumberUtil> {
   friend class Singleton<PhoneNumberUtil>;
 #endif
+  friend class AsYouTypeFormatter;
   friend class PhoneNumberUtilTest;
  public:
   ~PhoneNumberUtil();
@@ -499,6 +501,13 @@ class PhoneNumberUtil : public Singleton<PhoneNumberUtil> {
   // handled by this class (i.e don't delete it).
   static void SetLogger(Logger* logger);
 
+  // Gets an AsYouTypeFormatter for the specific region.
+  // Returns an AsYouTypeFormatter object, which could be used to format phone
+  // numbers in the specific region "as you type".
+  // The deletion of the returned instance is under the responsibility of the
+  // caller.
+  AsYouTypeFormatter* GetAsYouTypeFormatter(const string& region_code) const;
+
   friend bool ConvertFromTelephoneNumberProto(
       const TelephoneNumber& proto_to_convert,
       PhoneNumber* new_proto);
@@ -560,6 +569,12 @@ class PhoneNumberUtil : public Singleton<PhoneNumberUtil> {
   // in a number, for use when matching.
   const string& GetExtnPatternsForMatching() const;
 
+  // Checks whether a string contains only valid digits.
+  bool ContainsOnlyValidDigits(const string& s) const;
+
+  // Checks if a format is eligible to be used by the AsYouTypeFormatter.
+  bool IsFormatEligibleForAsYouTypeFormatter(const string& format) const;
+
   // Trims unwanted end characters from a phone number string.
   void TrimUnwantedEndChars(string* number) const;
 
diff --git a/cpp/src/phonenumbers/unicodestring.cc b/cpp/src/phonenumbers/unicodestring.cc
new file mode 100644 (file)
index 0000000..627f683
--- /dev/null
@@ -0,0 +1,114 @@
+// Copyright (C) 2011 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: Philippe Liard
+
+#include "phonenumbers/unicodestring.h"
+
+#include <algorithm>
+#include <cassert>
+#include <iterator>
+
+using std::advance;
+using std::equal;
+
+namespace i18n {
+namespace phonenumbers {
+
+UnicodeString& UnicodeString::operator=(const UnicodeString& src) {
+  if (&src != this) {
+    invalidateCachedIndex();
+    text_ = src.text_;
+  }
+  return *this;
+}
+
+bool UnicodeString::operator==(const UnicodeString& rhs) const {
+  return equal(text_.begin(), text_.end(), rhs.text_.begin());
+}
+
+void UnicodeString::append(const UnicodeString& unicode_string) {
+  invalidateCachedIndex();
+  for (UnicodeString::const_iterator it = unicode_string.begin();
+       it != unicode_string.end(); ++it) {
+    append(*it);
+  }
+}
+
+int UnicodeString::indexOf(char32 codepoint) const {
+  int pos = 0;
+  for (UnicodeText::const_iterator it = text_.begin(); it != text_.end();
+       ++it, ++pos) {
+    if (*it == codepoint) {
+      return pos;
+    }
+  }
+  return -1;
+}
+
+void UnicodeString::replace(int start, int length, const UnicodeString& src) {
+  assert(length >= 0 && length <= this->length());
+  invalidateCachedIndex();
+  UnicodeText::const_iterator start_it = text_.begin();
+  advance(start_it, start);
+  UnicodeText unicode_text;
+  unicode_text.append(text_.begin(), start_it);
+  unicode_text.append(src.text_);
+  advance(start_it, length);
+  unicode_text.append(start_it, text_.end());
+  text_ = unicode_text;
+}
+
+void UnicodeString::setCharAt(int pos, char32 c) {
+  assert(pos < length());
+  invalidateCachedIndex();
+  UnicodeText::const_iterator pos_it = text_.begin();
+  advance(pos_it, pos);
+  UnicodeText unicode_text;
+  unicode_text.append(text_.begin(), pos_it);
+  unicode_text.push_back(c);
+  ++pos_it;
+  unicode_text.append(pos_it, text_.end());
+  text_ = unicode_text;
+}
+
+UnicodeString UnicodeString::tempSubString(int start, int length) const {
+  const int unicodestring_length = this->length();
+  if (length == std::numeric_limits<int>::max()) {
+    length = unicodestring_length - start;
+  }
+  if (start > unicodestring_length || length > unicodestring_length) {
+    return UnicodeString("");
+  }
+  UnicodeText::const_iterator start_it = text_.begin();
+  advance(start_it, start);
+  UnicodeText::const_iterator end_it = start_it;
+  advance(end_it, length);
+  UnicodeString substring;
+  substring.text_.PointTo(start_it, end_it);
+  return substring;
+}
+
+char32 UnicodeString::operator[](int index) const {
+  assert(index < length());
+  if (cached_index_ == -1 || cached_index_ > index) {
+    cached_it_ = text_.begin();
+    cached_index_ = 0;
+  }
+  for (; cached_index_ < index; ++cached_index_, ++cached_it_) {}
+  return *cached_it_;
+}
+
+}  // namespace phonenumbers
+}  // namespace i18n
diff --git a/cpp/src/phonenumbers/unicodestring.h b/cpp/src/phonenumbers/unicodestring.h
new file mode 100644 (file)
index 0000000..47a151f
--- /dev/null
@@ -0,0 +1,133 @@
+// Copyright (C) 2011 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: Philippe Liard
+
+#ifndef I18N_PHONENUMBERS_UNICODESTRING_H_
+#define I18N_PHONENUMBERS_UNICODESTRING_H_
+
+#include "phonenumbers/utf/unicodetext.h"
+
+#include <cstring>
+#include <limits>
+
+namespace i18n {
+namespace phonenumbers {
+
+// This class supports the minimal subset of icu::UnicodeString needed by
+// AsYouTypeFormatter in order to let the libphonenumber not depend on ICU
+// which is not available by default on some systems, such as iOS.
+class UnicodeString {
+ public:
+  UnicodeString() : cached_index_(-1) {}
+
+  // Constructs a new unicode string copying the provided C string.
+  explicit UnicodeString(const char* utf8)
+      : text_(UTF8ToUnicodeText(utf8, std::strlen(utf8))),
+        cached_index_(-1) {}
+
+  // Constructs a new unicode string containing the provided codepoint.
+  explicit UnicodeString(char32 codepoint) : cached_index_(-1) {
+    append(codepoint);
+  }
+
+  UnicodeString(const UnicodeString& src)
+      : text_(src.text_), cached_index_(-1) {}
+
+  UnicodeString& operator=(const UnicodeString& src);
+
+  bool operator==(const UnicodeString& rhs) const;
+
+  void append(const UnicodeString& unicode_string);
+
+  inline void append(char32 codepoint) {
+    invalidateCachedIndex();
+    text_.push_back(codepoint);
+  }
+
+  typedef UnicodeText::const_iterator const_iterator;
+
+  inline const_iterator begin() const {
+    return text_.begin();
+  }
+
+  inline const_iterator end() const {
+    return text_.end();
+  }
+
+  // Returns the index of the provided codepoint or -1 if not found.
+  int indexOf(char32 codepoint) const;
+
+  // Returns the number of codepoints contained in the unicode string.
+  inline int length() const {
+    return text_.size();
+  }
+
+  // Clears the unicode string.
+  inline void remove() {
+    invalidateCachedIndex();
+    text_.clear();
+  }
+
+  // Replaces the substring located at [ start, start + length - 1 ] with the
+  // provided unicode string.
+  void replace(int start, int length, const UnicodeString& src);
+
+  void setCharAt(int pos, char32 c);
+
+  // Copies the provided C string.
+  inline void setTo(const char* s, size_t len) {
+    invalidateCachedIndex();
+    text_.CopyUTF8(s, len);
+  }
+
+  // Returns the substring located at [ start, start + length - 1 ] without
+  // copying the underlying C string. If one of the provided parameters is out
+  // of range, the function returns an empty unicode string.
+  UnicodeString tempSubString(
+      int start,
+      int length = std::numeric_limits<int>::max()) const;
+
+  inline void toUTF8String(string& out) const {
+    out = UnicodeTextToUTF8(text_);
+  }
+
+  char32 operator[](int index) const;
+
+ private:
+  UnicodeText text_;
+
+  // As UnicodeText doesn't provide random access, an operator[] implementation
+  // would naively iterate from the beginning of the string to the supplied
+  // index which would be inefficient.
+  // As operator[] is very likely to be called in a loop with consecutive
+  // indexes, we save the corresponding iterator so we can reuse it the next
+  // time it is called.
+
+  // The following function which invalidates the cached index corresponding to
+  // the iterator position must be called every time the unicode string is
+  // modified (i.e. in all the non-const methods).
+  inline void invalidateCachedIndex() {
+    cached_index_ = -1;
+  }
+
+  // Iterator corresponding to the cached index below, used by operator[].
+  mutable UnicodeText::const_iterator cached_it_;
+  mutable int cached_index_;
+};
+
+}  // namespace phonenumbers
+}  // namespace i18n
+
+#endif  // I18N_PHONENUMBERS_UNICODESTRING_H_
diff --git a/cpp/test/phonenumbers/asyoutypeformatter_test.cc b/cpp/test/phonenumbers/asyoutypeformatter_test.cc
new file mode 100644 (file)
index 0000000..782193d
--- /dev/null
@@ -0,0 +1,759 @@
+// Copyright (C) 2011 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.
+
+// Unit tests for asyoutypeformatter.cc, ported from AsYouTypeFormatterTest.java
+
+#include "phonenumbers/asyoutypeformatter.h"
+
+#include <gtest/gtest.h>
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "phonenumbers/phonenumberutil.h"
+#include "phonenumbers/region_code.h"
+
+namespace i18n {
+namespace phonenumbers {
+
+class PhoneMetadata;
+
+class AsYouTypeFormatterTest : public testing::Test {
+ protected:
+  AsYouTypeFormatterTest() : phone_util_(*PhoneNumberUtil::GetInstance()) {
+  }
+
+  const PhoneMetadata* GetCurrentMetadata() const {
+    return CHECK_NOTNULL(formatter_.get())->current_metadata_;
+  }
+
+  int ConvertUnicodeStringPosition(const UnicodeString& s, int pos) const {
+    return AsYouTypeFormatter::ConvertUnicodeStringPosition(s, pos);
+  }
+
+  const PhoneNumberUtil& phone_util_;
+  scoped_ptr<AsYouTypeFormatter> formatter_;
+  string result_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(AsYouTypeFormatterTest);
+};
+
+TEST_F(AsYouTypeFormatterTest, ConvertUnicodeStringPosition) {
+  EXPECT_EQ(-1, ConvertUnicodeStringPosition(UnicodeString("12345"), 10));
+  EXPECT_EQ(3, ConvertUnicodeStringPosition(UnicodeString("12345"), 3));
+  EXPECT_EQ(0, ConvertUnicodeStringPosition(
+      UnicodeString("\xEF\xBC\x95" /* "5" */), 0));
+  EXPECT_EQ(4, ConvertUnicodeStringPosition(
+      UnicodeString("0\xEF\xBC\x95""3" /* "053" */), 2));
+  EXPECT_EQ(5, ConvertUnicodeStringPosition(
+      UnicodeString("0\xEF\xBC\x95""3" /* "053" */), 3));
+}
+
+TEST_F(AsYouTypeFormatterTest, Constructor) {
+  formatter_.reset(phone_util_.GetAsYouTypeFormatter("US"));
+
+  EXPECT_TRUE(GetCurrentMetadata() != NULL);
+}
+
+TEST_F(AsYouTypeFormatterTest, TooLongNumberMatchingMultipleLeadingDigits) {
+  // See http://code.google.com/p/libphonenumber/issues/detail?id=36
+  // The bug occurred last time for countries which have two formatting rules
+  // with exactly the same leading digits pattern but differ in length.
+  formatter_.reset(phone_util_.GetAsYouTypeFormatter(RegionCode::GetUnknown()));
+
+  EXPECT_EQ("+", formatter_->InputDigit('+', &result_));
+  EXPECT_EQ("+8", formatter_->InputDigit('8', &result_));
+  EXPECT_EQ("+81 ", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("+81 9", formatter_->InputDigit('9', &result_));
+  EXPECT_EQ("+81 90", formatter_->InputDigit('0', &result_));
+  EXPECT_EQ("+81 90 1", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("+81 90 12", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("+81 90 123", formatter_->InputDigit('3', &result_));
+  EXPECT_EQ("+81 90 1234", formatter_->InputDigit('4', &result_));
+  EXPECT_EQ("+81 90 1234 5", formatter_->InputDigit('5', &result_));
+  EXPECT_EQ("+81 90 1234 56", formatter_->InputDigit('6', &result_));
+  EXPECT_EQ("+81 90 1234 567", formatter_->InputDigit('7', &result_));
+  EXPECT_EQ("+81 90 1234 5678", formatter_->InputDigit('8', &result_));
+  EXPECT_EQ("+81 90 12 345 6789", formatter_->InputDigit('9', &result_));
+  EXPECT_EQ("+81901234567890", formatter_->InputDigit('0', &result_));
+}
+
+TEST_F(AsYouTypeFormatterTest, AYTF_US) {
+  formatter_.reset(phone_util_.GetAsYouTypeFormatter("US"));
+
+  EXPECT_EQ("6", formatter_->InputDigit('6', &result_));
+  EXPECT_EQ("65", formatter_->InputDigit('5', &result_));
+  EXPECT_EQ("650", formatter_->InputDigit('0', &result_));
+  EXPECT_EQ("650 2", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("650 25", formatter_->InputDigit('5', &result_));
+  EXPECT_EQ("650 253", formatter_->InputDigit('3', &result_));
+
+  // Note this is how a US local number (without area code) should be formatted.
+  EXPECT_EQ("650 2532", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("650 253 22", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("650 253 222", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("650 253 2222", formatter_->InputDigit('2', &result_));
+
+  formatter_->Clear();
+  EXPECT_EQ("1", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("16", formatter_->InputDigit('6', &result_));
+  EXPECT_EQ("1 65", formatter_->InputDigit('5', &result_));
+  EXPECT_EQ("1 650", formatter_->InputDigit('0', &result_));
+  EXPECT_EQ("1 650 2", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("1 650 25", formatter_->InputDigit('5', &result_));
+  EXPECT_EQ("1 650 253", formatter_->InputDigit('3', &result_));
+  EXPECT_EQ("1 650 253 2", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("1 650 253 22", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("1 650 253 222", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("1 650 253 2222", formatter_->InputDigit('2', &result_));
+
+  formatter_->Clear();
+  EXPECT_EQ("0", formatter_->InputDigit('0', &result_));
+  EXPECT_EQ("01", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("011 ", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("011 4", formatter_->InputDigit('4', &result_));
+  EXPECT_EQ("011 44 ", formatter_->InputDigit('4', &result_));
+  EXPECT_EQ("011 44 6", formatter_->InputDigit('6', &result_));
+  EXPECT_EQ("011 44 61", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("011 44 6 12", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("011 44 6 123", formatter_->InputDigit('3', &result_));
+  EXPECT_EQ("011 44 6 123 1", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("011 44 6 123 12", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("011 44 6 123 123", formatter_->InputDigit('3', &result_));
+  EXPECT_EQ("011 44 6 123 123 1", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("011 44 6 123 123 12", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("011 44 6 123 123 123", formatter_->InputDigit('3', &result_));
+
+  formatter_->Clear();
+  EXPECT_EQ("0", formatter_->InputDigit('0', &result_));
+  EXPECT_EQ("01", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("011 ", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("011 5", formatter_->InputDigit('5', &result_));
+  EXPECT_EQ("011 54 ", formatter_->InputDigit('4', &result_));
+  EXPECT_EQ("011 54 9", formatter_->InputDigit('9', &result_));
+  EXPECT_EQ("011 54 91", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("011 54 9 11", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("011 54 9 11 2", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("011 54 9 11 23", formatter_->InputDigit('3', &result_));
+  EXPECT_EQ("011 54 9 11 231", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("011 54 9 11 2312", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("011 54 9 11 2312 1", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("011 54 9 11 2312 12", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("011 54 9 11 2312 123", formatter_->InputDigit('3', &result_));
+  EXPECT_EQ("011 54 9 11 2312 1234", formatter_->InputDigit('4', &result_));
+
+  formatter_->Clear();
+  EXPECT_EQ("0", formatter_->InputDigit('0', &result_));
+  EXPECT_EQ("01", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("011 ", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("011 2", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("011 24", formatter_->InputDigit('4', &result_));
+  EXPECT_EQ("011 244 ", formatter_->InputDigit('4', &result_));
+  EXPECT_EQ("011 244 2", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("011 244 28", formatter_->InputDigit('8', &result_));
+  EXPECT_EQ("011 244 280", formatter_->InputDigit('0', &result_));
+  EXPECT_EQ("011 244 280 0", formatter_->InputDigit('0', &result_));
+  EXPECT_EQ("011 244 280 00", formatter_->InputDigit('0', &result_));
+  EXPECT_EQ("011 244 280 000", formatter_->InputDigit('0', &result_));
+  EXPECT_EQ("011 244 280 000 0", formatter_->InputDigit('0', &result_));
+  EXPECT_EQ("011 244 280 000 00", formatter_->InputDigit('0', &result_));
+  EXPECT_EQ("011 244 280 000 000", formatter_->InputDigit('0', &result_));
+
+  formatter_->Clear();
+  EXPECT_EQ("+", formatter_->InputDigit('+', &result_));
+  EXPECT_EQ("+4", formatter_->InputDigit('4', &result_));
+  EXPECT_EQ("+48 ", formatter_->InputDigit('8', &result_));
+  EXPECT_EQ("+48 8", formatter_->InputDigit('8', &result_));
+  EXPECT_EQ("+48 88", formatter_->InputDigit('8', &result_));
+  EXPECT_EQ("+48 88 1", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("+48 88 12", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("+48 88 123", formatter_->InputDigit('3', &result_));
+  EXPECT_EQ("+48 88 123 1", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("+48 88 123 12", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("+48 88 123 12 1", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("+48 88 123 12 12", formatter_->InputDigit('2', &result_));
+}
+
+TEST_F(AsYouTypeFormatterTest, AYTF_USFullWidthCharacters) {
+  formatter_.reset(phone_util_.GetAsYouTypeFormatter("US"));
+
+  EXPECT_EQ("\xEF\xBC\x96" /* "6" */,
+            formatter_->InputDigit(UnicodeString("\xEF\xBC\x96" /* "6" */)[0],
+                                   &result_));
+  EXPECT_EQ("\xEF\xBC\x96\xEF\xBC\x95" /* "65" */,
+            formatter_->InputDigit(UnicodeString("\xEF\xBC\x95" /* "5" */)[0],
+                                   &result_));
+  EXPECT_EQ("650",
+            formatter_->InputDigit(UnicodeString("\xEF\xBC\x90" /* "0" */)[0],
+                                   &result_));
+  EXPECT_EQ("650 2",
+            formatter_->InputDigit(UnicodeString("\xEF\xBC\x92" /* "2" */)[0],
+                                   &result_));
+  EXPECT_EQ("650 25",
+            formatter_->InputDigit(UnicodeString("\xEF\xBC\x95" /* "5" */)[0],
+                                   &result_));
+  EXPECT_EQ("650 253",
+            formatter_->InputDigit(UnicodeString("\xEF\xBC\x93" /* "3" */)[0],
+                                   &result_));
+  EXPECT_EQ("650 2532",
+            formatter_->InputDigit(UnicodeString("\xEF\xBC\x92" /* "2" */)[0],
+                                   &result_));
+  EXPECT_EQ("650 253 22",
+            formatter_->InputDigit(UnicodeString("\xEF\xBC\x92" /* "2" */)[0],
+                                   &result_));
+  EXPECT_EQ("650 253 222",
+            formatter_->InputDigit(UnicodeString("\xEF\xBC\x92" /* "2" */)[0],
+                                   &result_));
+  EXPECT_EQ("650 253 2222",
+            formatter_->InputDigit(UnicodeString("\xEF\xBC\x92" /* "2" */)[0],
+                                   &result_));
+}
+
+TEST_F(AsYouTypeFormatterTest, AYTF_USMobileShortCode) {
+  formatter_.reset(phone_util_.GetAsYouTypeFormatter("US"));
+
+  EXPECT_EQ("*", formatter_->InputDigit('*', &result_));
+  EXPECT_EQ("*1", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("*12", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("*121", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("*121#", formatter_->InputDigit('#', &result_));
+}
+
+TEST_F(AsYouTypeFormatterTest, AYTF_USVanityNumber) {
+  formatter_.reset(phone_util_.GetAsYouTypeFormatter("US"));
+
+  EXPECT_EQ("8", formatter_->InputDigit('8', &result_));
+  EXPECT_EQ("80", formatter_->InputDigit('0', &result_));
+  EXPECT_EQ("800", formatter_->InputDigit('0', &result_));
+  EXPECT_EQ("800 ", formatter_->InputDigit(' ', &result_));
+  EXPECT_EQ("800 M", formatter_->InputDigit('M', &result_));
+  EXPECT_EQ("800 MY", formatter_->InputDigit('Y', &result_));
+  EXPECT_EQ("800 MY ", formatter_->InputDigit(' ', &result_));
+  EXPECT_EQ("800 MY A", formatter_->InputDigit('A', &result_));
+  EXPECT_EQ("800 MY AP", formatter_->InputDigit('P', &result_));
+  EXPECT_EQ("800 MY APP", formatter_->InputDigit('P', &result_));
+  EXPECT_EQ("800 MY APPL", formatter_->InputDigit('L', &result_));
+  EXPECT_EQ("800 MY APPLE", formatter_->InputDigit('E', &result_));
+}
+
+TEST_F(AsYouTypeFormatterTest, AYTFAndRememberPositionUS) {
+  formatter_.reset(phone_util_.GetAsYouTypeFormatter("US"));
+
+  EXPECT_EQ("1", formatter_->InputDigitAndRememberPosition('1', &result_));
+  EXPECT_EQ(1, formatter_->GetRememberedPosition());
+
+  EXPECT_EQ("16", formatter_->InputDigit('6', &result_));
+  EXPECT_EQ("1 65", formatter_->InputDigit('5', &result_));
+  EXPECT_EQ(1, formatter_->GetRememberedPosition());
+  EXPECT_EQ("1 650", formatter_->InputDigitAndRememberPosition('0', &result_));
+  EXPECT_EQ(5, formatter_->GetRememberedPosition());
+  EXPECT_EQ("1 650 2", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("1 650 25", formatter_->InputDigit('5', &result_));
+
+  // Note the remembered position for digit "0" changes from 4 to 5, because a
+  // space is now inserted in the front.
+  EXPECT_EQ(5, formatter_->GetRememberedPosition());
+  EXPECT_EQ("1 650 253", formatter_->InputDigit('3', &result_));
+  EXPECT_EQ("1 650 253 2", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("1 650 253 22", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ(5, formatter_->GetRememberedPosition());
+  EXPECT_EQ("1 650 253 222", formatter_->InputDigitAndRememberPosition('2',
+        &result_));
+  EXPECT_EQ(13, formatter_->GetRememberedPosition());
+  EXPECT_EQ("1 650 253 2222", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ(13, formatter_->GetRememberedPosition());
+  EXPECT_EQ("165025322222", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ(10, formatter_->GetRememberedPosition());
+  EXPECT_EQ("1650253222222", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ(10, formatter_->GetRememberedPosition());
+
+  formatter_->Clear();
+  EXPECT_EQ("1", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("16", formatter_->InputDigitAndRememberPosition('6', &result_));
+  EXPECT_EQ(2, formatter_->GetRememberedPosition());
+  EXPECT_EQ("1 65", formatter_->InputDigit('5', &result_));
+  EXPECT_EQ("1 650", formatter_->InputDigit('0', &result_));
+  EXPECT_EQ(3, formatter_->GetRememberedPosition());
+  EXPECT_EQ("1 650 2", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("1 650 25", formatter_->InputDigit('5', &result_));
+  EXPECT_EQ(3, formatter_->GetRememberedPosition());
+  EXPECT_EQ("1 650 253", formatter_->InputDigit('3', &result_));
+  EXPECT_EQ("1 650 253 2", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("1 650 253 22", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ(3, formatter_->GetRememberedPosition());
+  EXPECT_EQ("1 650 253 222", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("1 650 253 2222", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("165025322222", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ(2, formatter_->GetRememberedPosition());
+  EXPECT_EQ("1650253222222", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ(2, formatter_->GetRememberedPosition());
+
+  formatter_->Clear();
+  EXPECT_EQ("6", formatter_->InputDigit('6', &result_));
+  EXPECT_EQ("65", formatter_->InputDigit('5', &result_));
+  EXPECT_EQ("650", formatter_->InputDigit('0', &result_));
+  EXPECT_EQ("650 2", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("650 25", formatter_->InputDigit('5', &result_));
+  EXPECT_EQ("650 253", formatter_->InputDigit('3', &result_));
+  EXPECT_EQ("650 2532",
+            formatter_->InputDigitAndRememberPosition('2', &result_));
+  EXPECT_EQ(8, formatter_->GetRememberedPosition());
+  EXPECT_EQ("650 253 22", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ(9, formatter_->GetRememberedPosition());
+  EXPECT_EQ("650 253 222", formatter_->InputDigit('2', &result_));
+  // No more formatting when semicolon is entered.
+  EXPECT_EQ("650253222;", formatter_->InputDigit(';', &result_));
+  EXPECT_EQ(7, formatter_->GetRememberedPosition());
+  EXPECT_EQ("650253222;2", formatter_->InputDigit('2', &result_));
+
+  formatter_->Clear();
+  EXPECT_EQ("6", formatter_->InputDigit('6', &result_));
+  EXPECT_EQ("65", formatter_->InputDigit('5', &result_));
+  EXPECT_EQ("650", formatter_->InputDigit('0', &result_));
+  // No more formatting when users choose to do their own formatting.
+  EXPECT_EQ("650-", formatter_->InputDigit('-', &result_));
+  EXPECT_EQ("650-2", formatter_->InputDigitAndRememberPosition('2', &result_));
+  EXPECT_EQ(5, formatter_->GetRememberedPosition());
+  EXPECT_EQ("650-25", formatter_->InputDigit('5', &result_));
+  EXPECT_EQ(5, formatter_->GetRememberedPosition());
+  EXPECT_EQ("650-253", formatter_->InputDigit('3', &result_));
+  EXPECT_EQ(5, formatter_->GetRememberedPosition());
+  EXPECT_EQ("650-253-", formatter_->InputDigit('-', &result_));
+  EXPECT_EQ("650-253-2", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("650-253-22", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("650-253-222", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("650-253-2222", formatter_->InputDigit('2', &result_));
+
+  formatter_->Clear();
+  EXPECT_EQ("0", formatter_->InputDigit('0', &result_));
+  EXPECT_EQ("01", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("011 ", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("011 4", formatter_->InputDigitAndRememberPosition('4', &result_));
+  EXPECT_EQ("011 48 ", formatter_->InputDigit('8', &result_));
+  EXPECT_EQ(5, formatter_->GetRememberedPosition());
+  EXPECT_EQ("011 48 8", formatter_->InputDigit('8', &result_));
+  EXPECT_EQ(5, formatter_->GetRememberedPosition());
+  EXPECT_EQ("011 48 88", formatter_->InputDigit('8', &result_));
+  EXPECT_EQ("011 48 88 1", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("011 48 88 12", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ(5, formatter_->GetRememberedPosition());
+  EXPECT_EQ("011 48 88 123", formatter_->InputDigit('3', &result_));
+  EXPECT_EQ("011 48 88 123 1", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("011 48 88 123 12", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("011 48 88 123 12 1", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("011 48 88 123 12 12", formatter_->InputDigit('2', &result_));
+
+  formatter_->Clear();
+  EXPECT_EQ("+", formatter_->InputDigit('+', &result_));
+  EXPECT_EQ("+1", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("+1 6", formatter_->InputDigitAndRememberPosition('6', &result_));
+  EXPECT_EQ("+1 65", formatter_->InputDigit('5', &result_));
+  EXPECT_EQ("+1 650", formatter_->InputDigit('0', &result_));
+  EXPECT_EQ(4, formatter_->GetRememberedPosition());
+  EXPECT_EQ("+1 650 2", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ(4, formatter_->GetRememberedPosition());
+  EXPECT_EQ("+1 650 25", formatter_->InputDigit('5', &result_));
+  EXPECT_EQ("+1 650 253",
+            formatter_->InputDigitAndRememberPosition('3', &result_));
+  EXPECT_EQ("+1 650 253 2", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("+1 650 253 22", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("+1 650 253 222", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ(10, formatter_->GetRememberedPosition());
+
+  formatter_->Clear();
+  EXPECT_EQ("+", formatter_->InputDigit('+', &result_));
+  EXPECT_EQ("+1", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("+1 6", formatter_->InputDigitAndRememberPosition('6', &result_));
+  EXPECT_EQ("+1 65", formatter_->InputDigit('5', &result_));
+  EXPECT_EQ("+1 650", formatter_->InputDigit('0', &result_));
+  EXPECT_EQ(4, formatter_->GetRememberedPosition());
+  EXPECT_EQ("+1 650 2", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ(4, formatter_->GetRememberedPosition());
+  EXPECT_EQ("+1 650 25", formatter_->InputDigit('5', &result_));
+  EXPECT_EQ("+1 650 253", formatter_->InputDigit('3', &result_));
+  EXPECT_EQ("+1 650 253 2", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("+1 650 253 22", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("+1 650 253 222", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("+1650253222;", formatter_->InputDigit(';', &result_));
+  EXPECT_EQ(3, formatter_->GetRememberedPosition());
+}
+
+TEST_F(AsYouTypeFormatterTest, AYTF_GBFixedLine) {
+  formatter_.reset(phone_util_.GetAsYouTypeFormatter("GB"));
+
+  EXPECT_EQ("0", formatter_->InputDigit('0', &result_));
+  EXPECT_EQ("02", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("020", formatter_->InputDigit('0', &result_));
+  EXPECT_EQ("020 7", formatter_->InputDigitAndRememberPosition('7', &result_));
+  EXPECT_EQ(5, formatter_->GetRememberedPosition());
+  EXPECT_EQ("020 70", formatter_->InputDigit('0', &result_));
+  EXPECT_EQ("020 703", formatter_->InputDigit('3', &result_));
+  EXPECT_EQ(5, formatter_->GetRememberedPosition());
+  EXPECT_EQ("020 7031", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("020 7031 3", formatter_->InputDigit('3', &result_));
+  EXPECT_EQ("020 7031 30", formatter_->InputDigit('0', &result_));
+  EXPECT_EQ("020 7031 300", formatter_->InputDigit('0', &result_));
+  EXPECT_EQ("020 7031 3000", formatter_->InputDigit('0', &result_));
+}
+
+TEST_F(AsYouTypeFormatterTest, AYTF_GBTollFree) {
+  formatter_.reset(phone_util_.GetAsYouTypeFormatter("GB"));
+
+  EXPECT_EQ("0", formatter_->InputDigit('0', &result_));
+  EXPECT_EQ("08", formatter_->InputDigit('8', &result_));
+  EXPECT_EQ("080", formatter_->InputDigit('0', &result_));
+  EXPECT_EQ("080 7", formatter_->InputDigit('7', &result_));
+  EXPECT_EQ("080 70", formatter_->InputDigit('0', &result_));
+  EXPECT_EQ("080 703", formatter_->InputDigit('3', &result_));
+  EXPECT_EQ("080 7031", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("080 7031 3", formatter_->InputDigit('3', &result_));
+  EXPECT_EQ("080 7031 30", formatter_->InputDigit('0', &result_));
+  EXPECT_EQ("080 7031 300", formatter_->InputDigit('0', &result_));
+  EXPECT_EQ("080 7031 3000", formatter_->InputDigit('0', &result_));
+}
+
+TEST_F(AsYouTypeFormatterTest, AYTF_GBPremiumRate) {
+  formatter_.reset(phone_util_.GetAsYouTypeFormatter("GB"));
+
+  EXPECT_EQ("0", formatter_->InputDigit('0', &result_));
+  EXPECT_EQ("09", formatter_->InputDigit('9', &result_));
+  EXPECT_EQ("090", formatter_->InputDigit('0', &result_));
+  EXPECT_EQ("090 7", formatter_->InputDigit('7', &result_));
+  EXPECT_EQ("090 70", formatter_->InputDigit('0', &result_));
+  EXPECT_EQ("090 703", formatter_->InputDigit('3', &result_));
+  EXPECT_EQ("090 7031", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("090 7031 3", formatter_->InputDigit('3', &result_));
+  EXPECT_EQ("090 7031 30", formatter_->InputDigit('0', &result_));
+  EXPECT_EQ("090 7031 300", formatter_->InputDigit('0', &result_));
+  EXPECT_EQ("090 7031 3000", formatter_->InputDigit('0', &result_));
+}
+
+TEST_F(AsYouTypeFormatterTest, AYTF_NZMobile) {
+  formatter_.reset(phone_util_.GetAsYouTypeFormatter("NZ"));
+
+  EXPECT_EQ("0", formatter_->InputDigit('0', &result_));
+  EXPECT_EQ("02", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("021", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("02-11", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("02-112", formatter_->InputDigit('2', &result_));
+  // Note the unittest is using fake metadata which might produce non-ideal
+  // results.
+  EXPECT_EQ("02-112 3", formatter_->InputDigit('3', &result_));
+  EXPECT_EQ("02-112 34", formatter_->InputDigit('4', &result_));
+  EXPECT_EQ("02-112 345", formatter_->InputDigit('5', &result_));
+  EXPECT_EQ("02-112 3456", formatter_->InputDigit('6', &result_));
+}
+
+TEST_F(AsYouTypeFormatterTest, AYTF_DE) {
+  formatter_.reset(phone_util_.GetAsYouTypeFormatter("DE"));
+
+  EXPECT_EQ("0", formatter_->InputDigit('0', &result_));
+  EXPECT_EQ("03", formatter_->InputDigit('3', &result_));
+  EXPECT_EQ("030", formatter_->InputDigit('0', &result_));
+  EXPECT_EQ("030/1", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("030/12", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("030/123", formatter_->InputDigit('3', &result_));
+  EXPECT_EQ("030/1234", formatter_->InputDigit('4', &result_));
+
+  // 08021 2345
+  formatter_->Clear();
+  EXPECT_EQ("0", formatter_->InputDigit('0', &result_));
+  EXPECT_EQ("08", formatter_->InputDigit('8', &result_));
+  EXPECT_EQ("080", formatter_->InputDigit('0', &result_));
+  EXPECT_EQ("080 2", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("080 21", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("08021 2", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("08021 23", formatter_->InputDigit('3', &result_));
+  EXPECT_EQ("08021 234", formatter_->InputDigit('4', &result_));
+  EXPECT_EQ("08021 2345", formatter_->InputDigit('5', &result_));
+
+  // 00 1 650 253 2250
+  formatter_->Clear();
+  EXPECT_EQ("0", formatter_->InputDigit('0', &result_));
+  EXPECT_EQ("00", formatter_->InputDigit('0', &result_));
+  EXPECT_EQ("00 1 ", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("00 1 6", formatter_->InputDigit('6', &result_));
+  EXPECT_EQ("00 1 65", formatter_->InputDigit('5', &result_));
+  EXPECT_EQ("00 1 650", formatter_->InputDigit('0', &result_));
+  EXPECT_EQ("00 1 650 2", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("00 1 650 25", formatter_->InputDigit('5', &result_));
+  EXPECT_EQ("00 1 650 253", formatter_->InputDigit('3', &result_));
+  EXPECT_EQ("00 1 650 253 2", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("00 1 650 253 22", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("00 1 650 253 222", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("00 1 650 253 2222", formatter_->InputDigit('2', &result_));
+}
+
+TEST_F(AsYouTypeFormatterTest, AYTF_AR) {
+  formatter_.reset(phone_util_.GetAsYouTypeFormatter("AR"));
+
+  EXPECT_EQ("0", formatter_->InputDigit('0', &result_));
+  EXPECT_EQ("01", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("011", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("011 7", formatter_->InputDigit('7', &result_));
+  EXPECT_EQ("011 70", formatter_->InputDigit('0', &result_));
+  EXPECT_EQ("011 703", formatter_->InputDigit('3', &result_));
+  EXPECT_EQ("011 7031", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("011 7031-3", formatter_->InputDigit('3', &result_));
+  EXPECT_EQ("011 7031-30", formatter_->InputDigit('0', &result_));
+  EXPECT_EQ("011 7031-300", formatter_->InputDigit('0', &result_));
+  EXPECT_EQ("011 7031-3000", formatter_->InputDigit('0', &result_));
+}
+
+TEST_F(AsYouTypeFormatterTest, AYTF_ARMobile) {
+  formatter_.reset(phone_util_.GetAsYouTypeFormatter("AR"));
+
+  EXPECT_EQ("+", formatter_->InputDigit('+', &result_));
+  EXPECT_EQ("+5", formatter_->InputDigit('5', &result_));
+  EXPECT_EQ("+54 ", formatter_->InputDigit('4', &result_));
+  EXPECT_EQ("+54 9", formatter_->InputDigit('9', &result_));
+  EXPECT_EQ("+54 91", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("+54 9 11", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("+54 9 11 2", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("+54 9 11 23", formatter_->InputDigit('3', &result_));
+  EXPECT_EQ("+54 9 11 231", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("+54 9 11 2312", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("+54 9 11 2312 1", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("+54 9 11 2312 12", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("+54 9 11 2312 123", formatter_->InputDigit('3', &result_));
+  EXPECT_EQ("+54 9 11 2312 1234", formatter_->InputDigit('4', &result_));
+}
+
+TEST_F(AsYouTypeFormatterTest, AYTF_KR) {
+  formatter_.reset(phone_util_.GetAsYouTypeFormatter("KR"));
+
+  // +82 51 234 5678
+  EXPECT_EQ("+", formatter_->InputDigit('+', &result_));
+  EXPECT_EQ("+8", formatter_->InputDigit('8', &result_));
+  EXPECT_EQ("+82 ", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("+82 5", formatter_->InputDigit('5', &result_));
+  EXPECT_EQ("+82 51", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("+82 51-2", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("+82 51-23", formatter_->InputDigit('3', &result_));
+  EXPECT_EQ("+82 51-234", formatter_->InputDigit('4', &result_));
+  EXPECT_EQ("+82 51-234-5", formatter_->InputDigit('5', &result_));
+  EXPECT_EQ("+82 51-234-56", formatter_->InputDigit('6', &result_));
+  EXPECT_EQ("+82 51-234-567", formatter_->InputDigit('7', &result_));
+  EXPECT_EQ("+82 51-234-5678", formatter_->InputDigit('8', &result_));
+
+  // +82 2 531 5678
+  formatter_->Clear();
+  EXPECT_EQ("+", formatter_->InputDigit('+', &result_));
+  EXPECT_EQ("+8", formatter_->InputDigit('8', &result_));
+  EXPECT_EQ("+82 ", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("+82 2", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("+82 25", formatter_->InputDigit('5', &result_));
+  EXPECT_EQ("+82 2-53", formatter_->InputDigit('3', &result_));
+  EXPECT_EQ("+82 2-531", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("+82 2-531-5", formatter_->InputDigit('5', &result_));
+  EXPECT_EQ("+82 2-531-56", formatter_->InputDigit('6', &result_));
+  EXPECT_EQ("+82 2-531-567", formatter_->InputDigit('7', &result_));
+  EXPECT_EQ("+82 2-531-5678", formatter_->InputDigit('8', &result_));
+
+  // +82 2 3665 5678
+  formatter_->Clear();
+  EXPECT_EQ("+", formatter_->InputDigit('+', &result_));
+  EXPECT_EQ("+8", formatter_->InputDigit('8', &result_));
+  EXPECT_EQ("+82 ", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("+82 2", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("+82 23", formatter_->InputDigit('3', &result_));
+  EXPECT_EQ("+82 2-36", formatter_->InputDigit('6', &result_));
+  EXPECT_EQ("+82 2-366", formatter_->InputDigit('6', &result_));
+  EXPECT_EQ("+82 2-3665", formatter_->InputDigit('5', &result_));
+  EXPECT_EQ("+82 2-3665-5", formatter_->InputDigit('5', &result_));
+  EXPECT_EQ("+82 2-3665-56", formatter_->InputDigit('6', &result_));
+  EXPECT_EQ("+82 2-3665-567", formatter_->InputDigit('7', &result_));
+  EXPECT_EQ("+82 2-3665-5678", formatter_->InputDigit('8', &result_));
+
+  // 02-114
+  formatter_->Clear();
+  EXPECT_EQ("0", formatter_->InputDigit('0', &result_));
+  EXPECT_EQ("02", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("021", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("02-11", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("02-114", formatter_->InputDigit('4', &result_));
+
+  // 02-1300
+  formatter_->Clear();
+  EXPECT_EQ("0", formatter_->InputDigit('0', &result_));
+  EXPECT_EQ("02", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("021", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("02-13", formatter_->InputDigit('3', &result_));
+  EXPECT_EQ("02-130", formatter_->InputDigit('0', &result_));
+  EXPECT_EQ("02-1300", formatter_->InputDigit('0', &result_));
+
+  // 011-456-7890
+  formatter_->Clear();
+  EXPECT_EQ("0", formatter_->InputDigit('0', &result_));
+  EXPECT_EQ("01", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("011", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("011-4", formatter_->InputDigit('4', &result_));
+  EXPECT_EQ("011-45", formatter_->InputDigit('5', &result_));
+  EXPECT_EQ("011-456", formatter_->InputDigit('6', &result_));
+  EXPECT_EQ("011-456-7", formatter_->InputDigit('7', &result_));
+  EXPECT_EQ("011-456-78", formatter_->InputDigit('8', &result_));
+  EXPECT_EQ("011-456-789", formatter_->InputDigit('9', &result_));
+  EXPECT_EQ("011-456-7890", formatter_->InputDigit('0', &result_));
+
+  // 011-9876-7890
+  formatter_->Clear();
+  EXPECT_EQ("0", formatter_->InputDigit('0', &result_));
+  EXPECT_EQ("01", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("011", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("011-9", formatter_->InputDigit('9', &result_));
+  EXPECT_EQ("011-98", formatter_->InputDigit('8', &result_));
+  EXPECT_EQ("011-987", formatter_->InputDigit('7', &result_));
+  EXPECT_EQ("011-9876", formatter_->InputDigit('6', &result_));
+  EXPECT_EQ("011-9876-7", formatter_->InputDigit('7', &result_));
+  EXPECT_EQ("011-9876-78", formatter_->InputDigit('8', &result_));
+  EXPECT_EQ("011-9876-789", formatter_->InputDigit('9', &result_));
+  EXPECT_EQ("011-9876-7890", formatter_->InputDigit('0', &result_));
+}
+
+TEST_F(AsYouTypeFormatterTest, AYTF_MX) {
+  formatter_.reset(phone_util_.GetAsYouTypeFormatter("MX"));
+
+  // +52 800 123 4567
+  EXPECT_EQ("+", formatter_->InputDigit('+', &result_));
+  EXPECT_EQ("+5", formatter_->InputDigit('5', &result_));
+  EXPECT_EQ("+52 ", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("+52 8", formatter_->InputDigit('8', &result_));
+  EXPECT_EQ("+52 80", formatter_->InputDigit('0', &result_));
+  EXPECT_EQ("+52 800", formatter_->InputDigit('0', &result_));
+  EXPECT_EQ("+52 800 1", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("+52 800 12", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("+52 800 123", formatter_->InputDigit('3', &result_));
+  EXPECT_EQ("+52 800 123 4", formatter_->InputDigit('4', &result_));
+  EXPECT_EQ("+52 800 123 45", formatter_->InputDigit('5', &result_));
+  EXPECT_EQ("+52 800 123 456", formatter_->InputDigit('6', &result_));
+  EXPECT_EQ("+52 800 123 4567", formatter_->InputDigit('7', &result_));
+
+  // +52 55 1234 5678
+  formatter_->Clear();
+  EXPECT_EQ("+", formatter_->InputDigit('+', &result_));
+  EXPECT_EQ("+5", formatter_->InputDigit('5', &result_));
+  EXPECT_EQ("+52 ", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("+52 5", formatter_->InputDigit('5', &result_));
+  EXPECT_EQ("+52 55", formatter_->InputDigit('5', &result_));
+  EXPECT_EQ("+52 55 1", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("+52 55 12", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("+52 55 123", formatter_->InputDigit('3', &result_));
+  EXPECT_EQ("+52 55 1234", formatter_->InputDigit('4', &result_));
+  EXPECT_EQ("+52 55 1234 5", formatter_->InputDigit('5', &result_));
+  EXPECT_EQ("+52 55 1234 56", formatter_->InputDigit('6', &result_));
+  EXPECT_EQ("+52 55 1234 567", formatter_->InputDigit('7', &result_));
+  EXPECT_EQ("+52 55 1234 5678", formatter_->InputDigit('8', &result_));
+
+  // +52 212 345 6789
+  formatter_->Clear();
+  EXPECT_EQ("+", formatter_->InputDigit('+', &result_));
+  EXPECT_EQ("+5", formatter_->InputDigit('5', &result_));
+  EXPECT_EQ("+52 ", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("+52 2", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("+52 21", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("+52 212", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("+52 212 3", formatter_->InputDigit('3', &result_));
+  EXPECT_EQ("+52 212 34", formatter_->InputDigit('4', &result_));
+  EXPECT_EQ("+52 212 345", formatter_->InputDigit('5', &result_));
+  EXPECT_EQ("+52 212 345 6", formatter_->InputDigit('6', &result_));
+  EXPECT_EQ("+52 212 345 67", formatter_->InputDigit('7', &result_));
+  EXPECT_EQ("+52 212 345 678", formatter_->InputDigit('8', &result_));
+  EXPECT_EQ("+52 212 345 6789", formatter_->InputDigit('9', &result_));
+
+  // +52 1 55 1234 5678
+  formatter_->Clear();
+  EXPECT_EQ("+", formatter_->InputDigit('+', &result_));
+  EXPECT_EQ("+5", formatter_->InputDigit('5', &result_));
+  EXPECT_EQ("+52 ", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("+52 1", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("+52 15", formatter_->InputDigit('5', &result_));
+  EXPECT_EQ("+52 1 55", formatter_->InputDigit('5', &result_));
+  EXPECT_EQ("+52 1 55 1", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("+52 1 55 12", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("+52 1 55 123", formatter_->InputDigit('3', &result_));
+  EXPECT_EQ("+52 1 55 1234", formatter_->InputDigit('4', &result_));
+  EXPECT_EQ("+52 1 55 1234 5", formatter_->InputDigit('5', &result_));
+  EXPECT_EQ("+52 1 55 1234 56", formatter_->InputDigit('6', &result_));
+  EXPECT_EQ("+52 1 55 1234 567", formatter_->InputDigit('7', &result_));
+  EXPECT_EQ("+52 1 55 1234 5678", formatter_->InputDigit('8', &result_));
+
+  // +52 1 541 234 5678
+  formatter_->Clear();
+  EXPECT_EQ("+", formatter_->InputDigit('+', &result_));
+  EXPECT_EQ("+5", formatter_->InputDigit('5', &result_));
+  EXPECT_EQ("+52 ", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("+52 1", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("+52 15", formatter_->InputDigit('5', &result_));
+  EXPECT_EQ("+52 1 54", formatter_->InputDigit('4', &result_));
+  EXPECT_EQ("+52 1 541", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("+52 1 541 2", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("+52 1 541 23", formatter_->InputDigit('3', &result_));
+  EXPECT_EQ("+52 1 541 234", formatter_->InputDigit('4', &result_));
+  EXPECT_EQ("+52 1 541 234 5", formatter_->InputDigit('5', &result_));
+  EXPECT_EQ("+52 1 541 234 56", formatter_->InputDigit('6', &result_));
+  EXPECT_EQ("+52 1 541 234 567", formatter_->InputDigit('7', &result_));
+  EXPECT_EQ("+52 1 541 234 5678", formatter_->InputDigit('8', &result_));
+}
+
+TEST_F(AsYouTypeFormatterTest, AYTF_MultipleLeadingDigitPatterns) {
+  formatter_.reset(phone_util_.GetAsYouTypeFormatter("JP"));
+
+  // +81 50 2345 6789
+  EXPECT_EQ("+", formatter_->InputDigit('+', &result_));
+  EXPECT_EQ("+8", formatter_->InputDigit('8', &result_));
+  EXPECT_EQ("+81 ", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("+81 5", formatter_->InputDigit('5', &result_));
+  EXPECT_EQ("+81 50", formatter_->InputDigit('0', &result_));
+  EXPECT_EQ("+81 50 2", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("+81 50 23", formatter_->InputDigit('3', &result_));
+  EXPECT_EQ("+81 50 234", formatter_->InputDigit('4', &result_));
+  EXPECT_EQ("+81 50 2345", formatter_->InputDigit('5', &result_));
+  EXPECT_EQ("+81 50 2345 6", formatter_->InputDigit('6', &result_));
+  EXPECT_EQ("+81 50 2345 67", formatter_->InputDigit('7', &result_));
+  EXPECT_EQ("+81 50 2345 678", formatter_->InputDigit('8', &result_));
+  EXPECT_EQ("+81 50 2345 6789", formatter_->InputDigit('9', &result_));
+
+  // +81 222 12 5678
+  formatter_->Clear();
+  EXPECT_EQ("+", formatter_->InputDigit('+', &result_));
+  EXPECT_EQ("+8", formatter_->InputDigit('8', &result_));
+  EXPECT_EQ("+81 ", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("+81 2", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("+81 22", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("+81 22 2", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("+81 22 21", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("+81 2221 2", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("+81 222 12 5", formatter_->InputDigit('5', &result_));
+  EXPECT_EQ("+81 222 12 56", formatter_->InputDigit('6', &result_));
+  EXPECT_EQ("+81 222 12 567", formatter_->InputDigit('7', &result_));
+  EXPECT_EQ("+81 222 12 5678", formatter_->InputDigit('8', &result_));
+
+  // +81 3332 2 5678
+  formatter_->Clear();
+  EXPECT_EQ("+", formatter_->InputDigit('+', &result_));
+  EXPECT_EQ("+8", formatter_->InputDigit('8', &result_));
+  EXPECT_EQ("+81 ", formatter_->InputDigit('1', &result_));
+  EXPECT_EQ("+81 3", formatter_->InputDigit('3', &result_));
+  EXPECT_EQ("+81 33", formatter_->InputDigit('3', &result_));
+  EXPECT_EQ("+81 33 3", formatter_->InputDigit('3', &result_));
+  EXPECT_EQ("+81 3332", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("+81 3332 2", formatter_->InputDigit('2', &result_));
+  EXPECT_EQ("+81 3332 2 5", formatter_->InputDigit('5', &result_));
+  EXPECT_EQ("+81 3332 2 56", formatter_->InputDigit('6', &result_));
+  EXPECT_EQ("+81 3332 2 567", formatter_->InputDigit('7', &result_));
+  EXPECT_EQ("+81 3332 2 5678", formatter_->InputDigit('8', &result_));
+}
+
+}  // namespace phonenumbers
+}  // namespace i18n
diff --git a/cpp/test/phonenumbers/unicodestring_test.cc b/cpp/test/phonenumbers/unicodestring_test.cc
new file mode 100644 (file)
index 0000000..12b3d4c
--- /dev/null
@@ -0,0 +1,236 @@
+// Copyright (C) 2011 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: Philippe Liard
+
+#include <iostream>
+
+#include <gtest/gtest.h>
+
+#include "phonenumbers/unicodestring.h"
+
+using std::ostream;
+
+// Used by GTest to print the expected and actual results in case of failure.
+ostream& operator<<(ostream& out, const i18n::phonenumbers::UnicodeString& s) {
+  string utf8;
+  s.toUTF8String(utf8);
+  out << utf8;
+  return out;
+}
+
+namespace i18n {
+namespace phonenumbers {
+
+TEST(UnicodeString, ToUTF8StringWithEmptyString) {
+  UnicodeString s;
+  string utf8;
+  s.toUTF8String(utf8);
+  EXPECT_EQ("", utf8);
+}
+
+TEST(UnicodeString, ToUTF8String) {
+  UnicodeString s("hello");
+  string utf8;
+  s.toUTF8String(utf8);
+  EXPECT_EQ("hello", utf8);
+}
+
+TEST(UnicodeString, ToUTF8StringWithNonAscii) {
+  UnicodeString s("\xEF\xBC\x95\xEF\xBC\x93" /* "53" */);
+  string utf8;
+  s.toUTF8String(utf8);
+  EXPECT_EQ("\xEF\xBC\x95\xEF\xBC\x93", utf8);
+}
+
+TEST(UnicodeString, AppendCodepoint) {
+  UnicodeString s;
+  s.append('h');
+  ASSERT_EQ(UnicodeString("h"), s);
+  s.append('e');
+  EXPECT_EQ(UnicodeString("he"), s);
+}
+
+TEST(UnicodeString, AppendCodepointWithNonAscii) {
+  UnicodeString s;
+  s.append(0xFF15 /* 5 */);
+  ASSERT_EQ(UnicodeString("\xEF\xBC\x95" /* 5 */), s);
+  s.append(0xFF13 /* 3 */);
+  EXPECT_EQ(UnicodeString("\xEF\xBC\x95\xEF\xBC\x93" /* 53 */), s);
+}
+
+TEST(UnicodeString, AppendUnicodeString) {
+  UnicodeString s;
+  s.append(UnicodeString("he"));
+  ASSERT_EQ(UnicodeString("he"), s);
+  s.append(UnicodeString("llo"));
+  EXPECT_EQ(UnicodeString("hello"), s);
+}
+
+TEST(UnicodeString, AppendUnicodeStringWithNonAscii) {
+  UnicodeString s;
+  s.append(UnicodeString("\xEF\xBC\x95" /* 5 */));
+  ASSERT_EQ(UnicodeString("\xEF\xBC\x95"), s);
+  s.append(UnicodeString("\xEF\xBC\x93" /* 3 */));
+  EXPECT_EQ(UnicodeString("\xEF\xBC\x95\xEF\xBC\x93" /* 53 */), s);
+}
+
+TEST(UnicodeString, IndexOf) {
+  UnicodeString s("hello");
+  EXPECT_EQ(0, s.indexOf('h'));
+  EXPECT_EQ(2, s.indexOf('l'));
+  EXPECT_EQ(4, s.indexOf('o'));
+}
+
+TEST(UnicodeString, IndexOfWithNonAscii) {
+  UnicodeString s("\xEF\xBC\x95\xEF\xBC\x93" /* 53 */);
+  EXPECT_EQ(1, s.indexOf(0xFF13 /* 3 */));
+}
+
+TEST(UnicodeString, ReplaceWithEmptyInputs) {
+  UnicodeString s;
+  s.replace(0, 0, UnicodeString(""));
+  EXPECT_EQ(UnicodeString(""), s);
+}
+
+TEST(UnicodeString, ReplaceWithEmptyReplacement) {
+  UnicodeString s("hello");
+  s.replace(0, 5, UnicodeString(""));
+  EXPECT_EQ(UnicodeString(""), s);
+}
+
+TEST(UnicodeString, ReplaceBegining) {
+  UnicodeString s("hello world");
+  s.replace(0, 5, UnicodeString("HELLO"));
+  EXPECT_EQ(UnicodeString("HELLO world"), s);
+}
+
+TEST(UnicodeString, ReplaceMiddle) {
+  UnicodeString s("hello world");
+  s.replace(5, 1, UnicodeString("AB"));
+  EXPECT_EQ(UnicodeString("helloABworld"), s);
+}
+
+TEST(UnicodeString, ReplaceEnd) {
+  UnicodeString s("hello world");
+  s.replace(10, 1, UnicodeString("AB"));
+  EXPECT_EQ(UnicodeString("hello worlAB"), s);
+}
+
+TEST(UnicodeString, ReplaceWithNonAscii) {
+  UnicodeString s("hello world");
+  s.replace(3, 2, UnicodeString("\xEF\xBC\x91\xEF\xBC\x90" /* 10 */));
+  EXPECT_EQ(UnicodeString("hel\xEF\xBC\x91\xEF\xBC\x90 world"), s);
+}
+
+TEST(UnicodeString, SetCharBegining) {
+  UnicodeString s("hello");
+  s.setCharAt(0, 'H');
+  EXPECT_EQ(UnicodeString("Hello"), s);
+}
+
+TEST(UnicodeString, SetCharMiddle) {
+  UnicodeString s("hello");
+  s.setCharAt(2, 'L');
+  EXPECT_EQ(UnicodeString("heLlo"), s);
+}
+
+TEST(UnicodeString, SetCharEnd) {
+  UnicodeString s("hello");
+  s.setCharAt(4, 'O');
+  EXPECT_EQ(UnicodeString("hellO"), s);
+}
+
+TEST(UnicodeString, SetCharWithNonAscii) {
+  UnicodeString s("hello");
+  s.setCharAt(4, 0xFF10 /* 0 */);
+  EXPECT_EQ(UnicodeString("hell\xEF\xBC\x90" /* 0 */), s);
+}
+
+TEST(UnicodeString, TempSubStringWithEmptyString) {
+  EXPECT_EQ(UnicodeString(""), UnicodeString().tempSubString(0, 0));
+}
+
+TEST(UnicodeString, TempSubStringWithInvalidInputs) {
+  UnicodeString s("hello");
+  // tempSubString() returns an empty unicode string if one of the provided
+  // paramaters is out of range.
+  EXPECT_EQ(UnicodeString(""), s.tempSubString(6));
+  EXPECT_EQ(UnicodeString(""), s.tempSubString(2, 6));
+}
+
+TEST(UnicodeString, TempSubString) {
+  UnicodeString s("hello");
+  EXPECT_EQ(UnicodeString(""), s.tempSubString(0, 0));
+  EXPECT_EQ(UnicodeString("h"), s.tempSubString(0, 1));
+  EXPECT_EQ(UnicodeString("hello"), s.tempSubString(0, 5));
+  EXPECT_EQ(UnicodeString("llo"), s.tempSubString(2, 3));
+}
+
+TEST(UnicodeString, TempSubStringWithNoLength) {
+  UnicodeString s("hello");
+  EXPECT_EQ(UnicodeString("hello"), s.tempSubString(0));
+  EXPECT_EQ(UnicodeString("llo"), s.tempSubString(2));
+}
+
+TEST(UnicodeString, TempSubStringWithNonAscii) {
+  UnicodeString s("hel\xEF\xBC\x91\xEF\xBC\x90" /* 10 */);
+  EXPECT_EQ(UnicodeString("\xEF\xBC\x91" /* 1 */), s.tempSubString(3, 1));
+}
+
+TEST(UnicodeString, OperatorEqual) {
+  UnicodeString s("hello");
+  s = UnicodeString("Hello");
+  EXPECT_EQ(UnicodeString("Hello"), s);
+}
+
+TEST(UnicodeString, OperatorEqualWithNonAscii) {
+  UnicodeString s("hello");
+  s = UnicodeString("hel\xEF\xBC\x91\xEF\xBC\x90" /* 10 */);
+  EXPECT_EQ(UnicodeString("hel\xEF\xBC\x91\xEF\xBC\x90"), s);
+}
+
+TEST(UnicodeString, OperatorBracket) {
+  UnicodeString s("hello");
+  EXPECT_EQ('h', s[0]);
+  EXPECT_EQ('e', s[1]);
+  EXPECT_EQ('l', s[2]);
+  EXPECT_EQ('l', s[3]);
+  EXPECT_EQ('o', s[4]);
+}
+
+TEST(UnicodeString, OperatorBracketWithNonAscii) {
+  UnicodeString s("hel\xEF\xBC\x91\xEF\xBC\x90" /* 10 */);
+  EXPECT_EQ('h', s[0]);
+  EXPECT_EQ('e', s[1]);
+  EXPECT_EQ('l', s[2]);
+  EXPECT_EQ(0xFF11 /* 1 */, s[3]);
+  EXPECT_EQ(0xFF10 /* 0 */, s[4]);
+}
+
+TEST(UnicodeString, OperatorBracketWithIteratorCacheInvalidation) {
+  UnicodeString s("hello");
+  EXPECT_EQ('h', s[0]);
+  EXPECT_EQ('e', s[1]);
+  // Modify the string which should invalidate the iterator cache.
+  s.setCharAt(1, 'E');
+  EXPECT_EQ(UnicodeString("hEllo"), s);
+  EXPECT_EQ('E', s[1]);
+  // Get the previous character which should invalidate the iterator cache.
+  EXPECT_EQ('h', s[0]);
+  EXPECT_EQ('o', s[4]);
+}
+
+}  // namespace phonenumbers
+}  // namespace i18n
index 535e26d..6b2d04c 100755 (executable)
@@ -33,12 +33,18 @@ test_cpp_version() {
   # Write the program that tests the installation of the library to a temporary
   # source file.
   > $CC_TEST_FILE echo '
-    #include <cassert>
+    #include <base/memory/scoped_ptr.h>
+    #include <phonenumbers/asyoutypeformatter.h>
     #include <phonenumbers/phonenumberutil.h>
+
+    using i18n::phonenumbers::AsYouTypeFormatter;
     using i18n::phonenumbers::PhoneNumberUtil;
+
     int main() {
       PhoneNumberUtil* const phone_util = PhoneNumberUtil::GetInstance();
-      return phone_util == NULL;
+      const scoped_ptr<AsYouTypeFormatter> asytf(
+          phone_util->GetAsYouTypeFormatter("US"));
+      return !(phone_util != NULL && asytf != NULL);
     }'
   # Run the build and tests.
   (