summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaisuke Miyakawa <dmiyakawa@google.com>2009-07-07 11:11:34 +0900
committerDaisuke Miyakawa <dmiyakawa@google.com>2009-07-07 11:11:34 +0900
commitf06f5fa351ded0b9e04e15efa7e34f0f085fc9df (patch)
tree3cbf04975166c494af3b17d271e09284064bea0f
parentab3ee7de06d0451d0a34cbd982006f62928e4b48 (diff)
"Rewrite" PhoneNumberUtil so that it compares two phone strings using as many characters as possible, unlike the previous implementation.
Unlike the change 5480, this considers the NDD-problem mentioned in the internal issue 1949010. This time, 1-650-555-1234 and 650-555-1234 match each other. Added tests for the cases. related internal issue: 1868702, 1949010
-rw-r--r--android/Android.mk24
-rw-r--r--android/PhoneNumberUtils.cpp518
-rw-r--r--android/PhoneNumberUtils.h2
-rw-r--r--android/PhoneNumberUtilsTest.cpp137
4 files changed, 466 insertions, 215 deletions
diff --git a/android/Android.mk b/android/Android.mk
index 2ec4701..a9f68da 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -30,3 +30,27 @@ LOCAL_SRC_FILES := \
LOCAL_MODULE_TAGS := optional
include $(BUILD_EXECUTABLE)
+
+# Test for PhoneNumberUtils
+#
+# You can also test this in Unix, like this:
+# > g++ -Wall external/sqlite/android/PhoneNumberUtils.cpp \
+# external/sqlite/android/PhoneNumberUtilsTest.cpp
+# > ./a.out
+#
+# Note: tests related to PHONE_NUMBERS_EQUAL also exists in AndroidTests in
+# java space. Add tests if you modify this.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE:= libsqlite3_phone_number_utils_test
+
+LOCAL_CFLAGS += -Wall -Werror
+
+LOCAL_SRC_FILES := \
+ PhoneNumberUtils.cpp \
+ PhoneNumberUtilsTest.cpp
+
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_EXECUTABLE)
diff --git a/android/PhoneNumberUtils.cpp b/android/PhoneNumberUtils.cpp
index 9e5e470..cb8552e 100644
--- a/android/PhoneNumberUtils.cpp
+++ b/android/PhoneNumberUtils.cpp
@@ -1,293 +1,383 @@
-/* //device/vmlibs-android/com.android.internal.telephony/PhoneNumberUtils.java
-**
-** Copyright 2006, The Android Open Source Project
-**
-** 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.
-*/
+/*
+ * Copyright 2009, The Android Open Source Project
+ *
+ * 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 <string.h>
namespace android {
-static int MIN_MATCH = 5;
+/* Generated by the following Python script. Values of country calling codes
+ are from http://en.wikipedia.org/wiki/List_of_country_calling_codes
+
+#!/usr/bin/python
+import sys
+ccc_set_2digits = set([0, 1, 7,
+ 20, 27, 28, 30, 31, 32, 33, 34, 36, 39, 40, 43, 44, 45,
+ 46, 47, 48, 49, 51, 52, 53, 54, 55, 56, 57, 58, 60, 61,
+ 62, 63, 64, 65, 66, 81, 82, 83, 84, 86, 89, 90, 91, 92,
+ 93, 94, 95, 98])
+
+ONE_LINE_NUM = 10
+
+for i in xrange(100):
+ if i % ONE_LINE_NUM == 0:
+ sys.stdout.write(' ')
+ if i in ccc_set_2digits:
+ included = 'true'
+ else:
+ included = 'false'
+ sys.stdout.write(included + ',')
+ if ((i + 1) % ONE_LINE_NUM) == 0:
+ sys.stdout.write('\n')
+ else:
+ sys.stdout.write(' ')
+*/
+static bool two_length_country_code_map[100] = {
+ true, true, false, false, false, false, false, true, false, false,
+ false, false, false, false, false, false, false, false, false, false,
+ true, false, false, false, false, false, false, true, true, false,
+ true, true, true, true, true, false, true, false, false, true,
+ true, false, false, true, true, true, true, true, true, true,
+ false, true, true, true, true, true, true, true, true, false,
+ true, true, true, true, true, true, true, false, false, false,
+ false, false, false, false, false, false, false, false, false, false,
+ false, true, true, true, true, false, true, false, false, true,
+ true, true, true, true, true, true, false, false, true, false,
+};
+
+#define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0]))
-/** True if c is ISO-LATIN characters 0-9 */
-static bool isISODigit (char c)
+/**
+ * Returns true if "ccc_candidate" expresses (part of ) some country calling
+ * code.
+ * Returns false otherwise.
+ */
+static bool isCountryCallingCode(int ccc_candidate) {
+ return ccc_candidate > 0 &&
+ ccc_candidate < (int)ARRAY_SIZE(two_length_country_code_map) &&
+ two_length_country_code_map[ccc_candidate];
+}
+
+/**
+ * Returns interger corresponding to the input if input "ch" is
+ * ISO-LATIN characters 0-9.
+ * Returns -1 otherwise
+ */
+static int tryGetISODigit (char ch)
{
- return c >= '0' && c <= '9';
+ if ('0' <= ch && ch <= '9') {
+ return ch - '0';
+ } else {
+ return -1;
+ }
}
/** True if c is ISO-LATIN characters 0-9, *, # , + */
-static bool isNonSeparator(char c)
+static bool isNonSeparator(char ch)
{
- return (c >= '0' && c <= '9') || c == '*' || c == '#' || c == '+';
+ return ('0' <= ch && ch <= '9') || ch == '*' || ch == '#' || ch == '+';
}
/**
- * Phone numbers are stored in "lookup" form in the database
- * as reversed strings to allow for caller ID lookup
+ * Try to store the pointer to "new_ptr" which does not have trunk prefix.
*
- * This method takes a phone number and makes a valid SQL "LIKE"
- * string that will match the lookup form
+ * Currently this function simply ignore the first digit assuming it is
+ * trunk prefix. Actually trunk prefix is different in each country.
+ *
+ * e.g.
+ * "+79161234567" equals "89161234567" (Russian trunk digit is 8)
+ * "+33123456789" equals "0123456789" (French trunk digit is 0)
*
*/
-/** all of a up to len must be an international prefix or
- * separators/non-dialing digits
- */
-static bool matchIntlPrefix(const char* a, int len)
+static bool tryGetTrunkPrefixOmittedStr(const char *str, size_t len,
+ const char **new_ptr, size_t *new_len)
{
- /* '([^0-9*#+]\+[^0-9*#+] | [^0-9*#+]0(0|11)[^0-9*#+] )$' */
- /* 0 1 2 3 45 */
-
- int state = 0;
- for (int i = 0 ; i < len ; i++) {
- char c = a[i];
-
- switch (state) {
- case 0:
- if (c == '+') state = 1;
- else if (c == '0') state = 2;
- else if (isNonSeparator(c)) return false;
- break;
-
- case 2:
- if (c == '0') state = 3;
- else if (c == '1') state = 4;
- else if (isNonSeparator(c)) return false;
- break;
-
- case 4:
- if (c == '1') state = 5;
- else if (isNonSeparator(c)) return false;
- break;
-
- default:
- if (isNonSeparator(c)) return false;
- break;
-
- }
- }
-
- return state == 1 || state == 3 || state == 5;
-}
-
-/** all of 'a' up to len must match non-US trunk prefix ('0') */
-static bool matchTrunkPrefix(const char* a, int len)
-{
- bool found;
-
- found = false;
-
- for (int i = 0 ; i < len ; i++) {
- char c = a[i];
-
- if (c == '0' && !found) {
- found = true;
- } else if (isNonSeparator(c)) {
+ for (size_t i = 0 ; i < len ; i++) {
+ char ch = str[i];
+ if (tryGetISODigit(ch) >= 0) {
+ if (new_ptr != NULL) {
+ *new_ptr = str + i + 1;
+ }
+ if (new_len != NULL) {
+ *new_len = len - (i + 1);
+ }
+ return true;
+ } else if (isNonSeparator(ch)) {
return false;
}
}
-
- return found;
+
+ return false;
}
-/** all of 'a' up to len must be a (+|00|011)country code)
- * We're fast and loose with the country code. Any \d{1,3} matches */
-static bool matchIntlPrefixAndCC(const char* a, int len)
+/*
+ * Note that this function does not strictly care the country calling code with
+ * 3 length (like Morocco: +212), assuming it is enough to use the first two
+ * digit to compare two phone numbers.
+ */
+static int tryGetCountryCallingCode(const char *str, size_t len,
+ const char **new_ptr, size_t *new_len)
{
- /* [^0-9*#+]*(\+|0(0|11)\d\d?\d? [^0-9*#+] $ */
- /* 0 1 2 3 45 6 7 8 */
+ // Rough regexp:
+ // ^[^0-9*#+]*((\+|0(0|11)\d\d?|166) [^0-9*#+] $
+ // 0 1 2 3 45 6 7 89
+ //
+ // In all the states, this function ignores separator characters.
+ // "166" is the special case for the call from Thailand to the US. Ugu!
int state = 0;
- for (int i = 0 ; i < len ; i++ ) {
- char c = a[i];
-
+ int ccc = 0;
+ for (size_t i = 0 ; i < len ; i++ ) {
+ char ch = str[i];
switch (state) {
case 0:
- if (c == '+') state = 1;
- else if (c == '0') state = 2;
- else if (isNonSeparator(c)) return false;
+ if (ch == '+') state = 1;
+ else if (ch == '0') state = 2;
+ else if (ch == '1') state = 8;
+ else if (isNonSeparator(ch)) return -1;
break;
case 2:
- if (c == '0') state = 3;
- else if (c == '1') state = 4;
- else if (isNonSeparator(c)) return false;
+ if (ch == '0') state = 3;
+ else if (ch == '1') state = 4;
+ else if (isNonSeparator(ch)) return -1;
break;
case 4:
- if (c == '1') state = 5;
- else if (isNonSeparator(c)) return false;
+ if (ch == '1') state = 5;
+ else if (isNonSeparator(ch)) return -1;
break;
case 1:
case 3:
case 5:
- if (isISODigit(c)) state = 6;
- else if (isNonSeparator(c)) return false;
- break;
-
case 6:
case 7:
- if (isISODigit(c)) state++;
- else if (isNonSeparator(c)) return false;
- break;
-
+ {
+ int ret = tryGetISODigit(ch);
+ if (ret > 0) {
+ ccc = ccc * 10 + ret;
+ if (ccc >= 100 || isCountryCallingCode(ccc)) {
+ if (new_ptr != NULL) {
+ *new_ptr = str + i + 1;
+ }
+ if (new_len != NULL) {
+ *new_len = len - (i + 1);
+ }
+ return ccc;
+ }
+ if (state == 1 || state == 3 || state == 5) {
+ state = 6;
+ } else {
+ state++;
+ }
+ } else if (isNonSeparator(ch)) {
+ return -1;
+ }
+ }
+ break;
+ case 8:
+ if (ch == '6') state = 9;
+ else if (isNonSeparator(ch)) return -1;
+ break;
+ case 9:
+ if (ch == '6') {
+ if (new_ptr != NULL) {
+ *new_ptr = str + i + 1;
+ }
+ if (new_len != NULL) {
+ *new_len = len - (i + 1);
+ }
+ return 66;
+ }
+ break;
default:
- if (isNonSeparator(c)) return false;
+ return -1;
}
}
- return state == 6 || state == 7 || state == 8;
-}
-
-/** or -1 if both are negative */
-static int minPositive(int a, int b)
-{
- if (a >= 0 && b >= 0) {
- return (a < b) ? a : b;
- } else if (a >= 0) { /* && b < 0 */
- return a;
- } else if (b >= 0) { /* && a < 0 */
- return b;
- } else { /* a < 0 && b < 0 */
- return -1;
- }
+ return -1;
}
/**
- * Return the offset into a of the first appearance of b, or -1 if there
- * is no such character in a.
+ * Return true if the prefix of "ch" is "ignorable". Here, "ignorable" means
+ * that "ch" has only one digit and separater characters. The one digit is
+ * assumed to be trunk prefix.
*/
-static int indexOf(const char *a, char b) {
- char *ix = strchr(a, b);
+static bool checkPrefixIsIgnorable(const char* ch, int i) {
+ bool trunk_prefix_was_read = false;
+ while (i >= 0) {
+ if (tryGetISODigit(ch[i]) >= 0) {
+ if (trunk_prefix_was_read) {
+ // More than one digit appeared, meaning that "a" and "b"
+ // is different.
+ return false;
+ } else {
+ // Ignore just one digit, assuming it is trunk prefix.
+ trunk_prefix_was_read = true;
+ }
+ } else if (isNonSeparator(ch[i])) {
+ // Trunk prefix is a digit, not "*", "#"...
+ return false;
+ }
+ i--;
+ }
- if (ix == NULL)
- return -1;
- else
- return ix - a;
+ return true;
}
/**
* Compare phone numbers a and b, return true if they're identical
* enough for caller ID purposes.
*
- * - Compares from right to left
- * - requires MIN_MATCH (5) characters to match
- * - handles common trunk prefixes and international prefixes
- * (basically, everything except the Russian trunk prefix)
+ * Assume NULL as 0-length string.
*
- * Tolerates nulls
+ * Detailed information:
+ * Currently (as of 2009-06-12), we cannot depend on the locale given from the
+ * OS. For example, current Android does not accept "en_JP", meaning
+ * "the display language is English but the phone should be in Japan", but
+ * en_US, es_US, etc. So we cannot identify which digit is valid trunk prefix
+ * in the country where the phone is used. More specifically, "880-1234-1234"
+ * is not valid phone number in Japan since the trunk prefix in Japan is not 8
+ * but 0 (correct number should be "080-1234-1234"), while Russian trunk prefix
+ * is 8. Also, we cannot know whether the country where users live has trunk
+ * prefix itself. So, we cannot determine whether "+81-80-1234-1234" is NOT
+ * same as "880-1234-1234" (while "+81-80-1234-1234" is same as "080-1234-1234"
+ * and we can determine "880-1234-1234" is different from "080-1234-1234").
+ *
+ * In the future, we should handle trunk prefix more correctly, but as of now,
+ * we just ignore it...
*/
bool phone_number_compare(const char* a, const char* b)
{
- int ia, ib;
- int matched;
-
- if (a == NULL || b == NULL) {
- return false;
+ size_t len_a = 0;
+ size_t len_b = 0;
+ if (a == NULL) {
+ a = "";
+ } else {
+ len_a = strlen(a);
}
-
- ia = strlen(a);
- ib = strlen(b);
- if (ia == 0 || ib == 0) {
- return false;
+ if (b == NULL) {
+ b = "";
+ } else {
+ len_b = strlen(b);
}
- // Compare from right to left
- ia--;
- ib--;
-
- matched = 0;
-
- while (ia >= 0 && ib >=0) {
- char ca, cb;
- bool skipCmp = false;
-
- ca = a[ia];
-
- if (!isNonSeparator(ca)) {
- ia--;
- skipCmp = true;
- }
-
- cb = b[ib];
-
- if (!isNonSeparator(cb)) {
- ib--;
- skipCmp = true;
+ const char* tmp_a = NULL;
+ const char* tmp_b = NULL;
+ size_t tmp_len_a = len_a;
+ size_t tmp_len_b = len_b;
+
+ int ccc_a = tryGetCountryCallingCode(a, len_a, &tmp_a, &tmp_len_a);
+ int ccc_b = tryGetCountryCallingCode(b, len_b, &tmp_b, &tmp_len_b);
+ bool ok_to_ignore_prefix = true;
+ if (ccc_a >= 0 && ccc_b >= 0) {
+ if (ccc_a != ccc_b) {
+ // Different Country Calling Code. Must be different phone number.
+ return false;
}
-
- if (!skipCmp) {
- if (cb != ca) {
- break;
- }
- ia--; ib--; matched++;
+ // When both have ccc, do not ignore trunk prefix. Without this,
+ // "+81123123" becomes same as "+810123123" (+81 == Japan)
+ ok_to_ignore_prefix = false;
+ } else if (ccc_a < 0 && ccc_b < 0) {
+ // When both do not have ccc, do not ignore trunk prefix. Without this,
+ // "123123" becomes same as "0123123"
+ ok_to_ignore_prefix = false;
+ } else {
+ if (ccc_a < 0) {
+ tryGetTrunkPrefixOmittedStr(a, len_a, &tmp_a, &tmp_len_a);
}
- }
-
- if (matched < MIN_MATCH) {
- int aLen = strlen(a);
-
- // if the input strings match, but their lengths < MIN_MATCH,
- // treat them as equal.
- if (aLen == (int)strlen(b) && aLen == matched) {
- return true;
+ if (ccc_b < 0) {
+ tryGetTrunkPrefixOmittedStr(b, len_b, &tmp_b, &tmp_len_b);
}
- return false;
}
- // At least one string has matched completely;
- if (matched >= MIN_MATCH && (ia < 0 || ib < 0)) {
- return true;
+ if (tmp_a != NULL) {
+ a = tmp_a;
+ len_a = tmp_len_a;
}
-
- /*
- * Now, what remains must be one of the following for a
- * match:
- *
- * - a '+' on one and a '00' or a '011' on the other
- * - a '0' on one and a (+,00)<country code> on the other
- * (for this, a '0' and a '00' prefix would have succeeded above)
- */
-
- if (matchIntlPrefix(a, ia + 1) && matchIntlPrefix(b, ib +1)) {
- return true;
+ if (tmp_b != NULL) {
+ b = tmp_b;
+ len_b = tmp_len_b;
}
- if (matchTrunkPrefix(a, ia + 1) && matchIntlPrefixAndCC(b, ib +1)) {
- return true;
- }
+ int i_a = len_a - 1;
+ int i_b = len_b - 1;
+ while (i_a >= 0 && i_b >= 0) {
+ bool skip_compare = false;
+ char ch_a = a[i_a];
+ char ch_b = b[i_b];
+ if (!isNonSeparator(ch_a)) {
+ i_a--;
+ skip_compare = true;
+ }
+ if (!isNonSeparator(ch_b)) {
+ i_b--;
+ skip_compare = true;
+ }
- if (matchTrunkPrefix(b, ib + 1) && matchIntlPrefixAndCC(a, ia +1)) {
- return true;
+ if (!skip_compare) {
+ if (ch_a != ch_b) {
+ return false;
+ }
+ i_a--;
+ i_b--;
+ }
}
- /*
- * Last resort: if the number of unmatched characters on both sides is less than or equal
- * to the length of the longest country code and only one number starts with a + accept
- * the match. This is because some countries like France and Russia have an extra prefix
- * digit that is used when dialing locally in country that does not show up when you dial
- * the number using the country code. In France this prefix digit is used to determine
- * which land line carrier to route the call over.
- */
- bool aPlusFirst = (*a == '+');
- bool bPlusFirst = (*b == '+');
- if (ia < 4 && ib < 4 && (aPlusFirst || bPlusFirst) && !(aPlusFirst && bPlusFirst)) {
- return true;
+ if (ok_to_ignore_prefix) {
+ if (!checkPrefixIsIgnorable(a, i_a)) {
+ return false;
+ }
+ if (!checkPrefixIsIgnorable(b, i_b)) {
+ return false;
+ }
+ } else {
+ // In the US, 1-650-555-1234 must be equal to 650-555-1234,
+ // while 090-1234-1234 must not be equalt to 90-1234-1234 in Japan.
+ // This request exists just in US (with 1 trunk (NDD) prefix).
+ //
+ // At least, in this "rough" comparison, we should ignore the prefix
+ // '1', so if the remaining non-separator number is 0, we ignore it
+ // just once.
+ bool may_be_namp = true;
+ while (i_a >= 0) {
+ const char ch_a = a[i_a];
+ if (isNonSeparator(ch_a)) {
+ if (may_be_namp && tryGetISODigit(ch_a) == 1) {
+ may_be_namp = false;
+ } else {
+ return false;
+ }
+ }
+ i_a--;
+ }
+ while (i_b >= 0) {
+ const char ch_b = b[i_b];
+ if (isNonSeparator(ch_b)) {
+ if (may_be_namp && tryGetISODigit(ch_b) == 1) {
+ may_be_namp = false;
+ } else {
+ return false;
+ }
+ }
+ i_b--;
+ }
}
- return false;
+ return true;
}
} // namespace android
diff --git a/android/PhoneNumberUtils.h b/android/PhoneNumberUtils.h
index 1a5720f..8f350a7 100644
--- a/android/PhoneNumberUtils.h
+++ b/android/PhoneNumberUtils.h
@@ -19,7 +19,7 @@
#define _ANDROID_PHONE_NUMBER_UTILS_H
namespace android {
-
+
bool phone_number_compare(const char* a, const char* b);
}
diff --git a/android/PhoneNumberUtilsTest.cpp b/android/PhoneNumberUtilsTest.cpp
new file mode 100644
index 0000000..6772fe5
--- /dev/null
+++ b/android/PhoneNumberUtilsTest.cpp
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * 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.
+ */
+/*
+ * Note that similar (or almost same) tests exist in Java side (See
+ * DatabaseGeneralTest.java in AndroidTests). The differences are:
+ * - this test is quite easy to do (You can do it in your Unix PC)
+ * - this test is not automatically executed by build servers
+ *
+ * You should also execute the test before submitting this.
+ */
+
+#include "PhoneNumberUtils.h"
+
+#include <stdio.h>
+#include <string.h>
+
+using namespace android;
+
+#define EXPECT(function, input1, input2, expected, total, error) \
+ ({ \
+ const char *i1_cache = input1; \
+ const char *i2_cache = input2; \
+ (total)++; \
+ if ((expected) != (function)((i1_cache), (i2_cache))) { \
+ if (expected) { \
+ printf("%s != %s while we expect %s == %s\n", \
+ (i1_cache), (i2_cache), (i1_cache), (i2_cache)); \
+ } else { \
+ printf("%s == %s while we expect %s != %s\n", \
+ (i1_cache), (i2_cache), (i1_cache), (i2_cache)); \
+ } \
+ (error)++; \
+ } \
+ })
+
+#define EXPECT_EQ(input1, input2) \
+ EXPECT(phone_number_compare, (input1), (input2), true, \
+ (total), (error))
+
+
+#define EXPECT_NE(input1, input2) \
+ EXPECT(phone_number_compare, (input1), (input2), false, \
+ (total), (error))
+
+int main() {
+ int total = 0;
+ int error = 0;
+
+ EXPECT_EQ(NULL, NULL);
+ EXPECT_EQ("", NULL);
+ EXPECT_EQ(NULL, "");
+ EXPECT_EQ("", "");
+
+ EXPECT_EQ("999", "999");
+ EXPECT_EQ("119", "119");
+
+ EXPECT_NE("123456789", "923456789");
+ EXPECT_NE("123456789", "123456781");
+ EXPECT_NE("123456789", "1234567890");
+ EXPECT_NE("123456789", "0123456789");
+
+ // Google, Inc.
+ EXPECT_EQ("650-253-0000", "6502530000");
+ EXPECT_EQ("650-253-0000", "650 253 0000");
+ EXPECT_EQ("650 253 0000", "6502530000");
+
+ // trunk (NDD) prefix must be properly handled in US
+ EXPECT_EQ("650-253-0000", "1-650-253-0000");
+ EXPECT_EQ("650-253-0000", " 1-650-253-0000");
+ EXPECT_NE("650-253-0000", "11-650-253-0000");
+ EXPECT_NE("650-253-0000", "0-650-253-0000");
+
+ EXPECT_EQ("+1 650-253-0000", "6502530000");
+ EXPECT_EQ("001 650-253-0000", "6502530000");
+ EXPECT_EQ("0111 650-253-0000", "6502530000");
+
+ // Country code is different.
+ EXPECT_NE("+19012345678", "+819012345678");
+
+ // Russian trunk digit
+ EXPECT_EQ("+79161234567", "89161234567");
+
+ // French trunk digit
+ EXPECT_EQ("+33123456789", "0123456789");
+
+ // Trunk digit for city codes in the Netherlands
+ EXPECT_EQ("+31771234567", "0771234567");
+
+ // Japanese dial
+ EXPECT_EQ("090-1234-5678", "+819012345678");
+ EXPECT_EQ("090(1234)5678", "+819012345678");
+ EXPECT_EQ("090-1234-5678", "+81-90-1234-5678");
+
+ // Trunk prefix must not be ignored in Japan
+ EXPECT_NE("090-1234-5678", "90-1234-5678");
+
+ EXPECT_NE("090-1234-5678", "080-1234-5678");
+ EXPECT_NE("090-1234-5678", "190-1234-5678");
+ EXPECT_NE("090-1234-5678", "890-1234-5678");
+ EXPECT_NE("+81-90-1234-5678", "+81-090-1234-5678");
+
+ EXPECT_EQ("+593(800)123-1234", "8001231234");
+
+ // Two continuous 0 at the beginieng of the phone string should not be
+ // treated as trunk prefix.
+ EXPECT_NE("008001231234", "8001231234");
+
+ // Test broken caller ID seen on call from Thailand to the US
+ EXPECT_EQ("+66811234567", "166811234567");
+
+ // Confirm that the bug found before does not re-appear.
+ EXPECT_NE("080-1234-5678", "+819012345678");
+
+ // Currently we cannot get this test through (Japanese trunk prefix is 0,
+ // but there is no sensible way to know it now (as of 2009-6-12)...
+ // EXPECT_NE("290-1234-5678", "+819012345678");
+
+ printf("total: %d, error: %d\n\n", total, error);
+ if (error == 0) {
+ printf("Success!\n");
+ } else {
+ printf("Failure... :(\n");
+ }
+}