• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.providers.contacts;
18 
19 import android.provider.ContactsContract.FullNameStyle;
20 import android.provider.ContactsContract.PhoneticNameStyle;
21 
22 import androidx.test.filters.SmallTest;
23 
24 import com.android.providers.contacts.NameSplitter.Name;
25 
26 import junit.framework.TestCase;
27 
28 import java.util.Locale;
29 
30 /**
31  * Tests for {@link NameSplitter}.
32  *
33  * Run the test like this:
34  * <code>
35  * adb shell am instrument -e class com.android.providers.contacts.NameSplitterTest -w \
36  *         com.android.providers.contacts.tests/android.test.InstrumentationTestRunner
37  * </code>
38  */
39 @SmallTest
40 public class NameSplitterTest extends TestCase {
41     private NameSplitter mNameSplitter;
42 
43     @Override
setUp()44     protected void setUp() throws Exception {
45         super.setUp();
46         createNameSplitter(Locale.US);
47     }
48 
createNameSplitter(Locale locale)49     private void createNameSplitter(Locale locale) {
50         mNameSplitter = new NameSplitter("Mr, Ms, Mrs", "d', st, st., von", "Jr., M.D., MD, D.D.S.",
51                 "&, AND", locale);
52     }
53 
testNull()54     public void testNull() {
55         assertSplitName(null, null, null, null, null, null);
56         assertJoinedName(null, null, null, null, null, null);
57     }
58 
testEmpty()59     public void testEmpty() {
60         assertSplitName("", null, null, null, null, null);
61         assertJoinedName(null, null, null, null, null, null);
62     }
63 
testSpaces()64     public void testSpaces() {
65         assertSplitName(" ", null, null, null, null, null);
66         assertJoinedName(null, null, null, null, null, null);
67     }
68 
testFamilyName()69     public void testFamilyName() {
70         assertSplitName("Smith", null, "Smith", null, null, null);
71         assertJoinedName("Smith", null, "Smith", null, null, null);
72     }
73 
testIgnoreSuffix()74     public void testIgnoreSuffix() {
75         assertSplitName("Ms MD", "Ms", null, null, "MD", null);
76         assertJoinedName("Ms MD", "Ms", null, null, "MD", null);
77     }
78 
testGivenFamilyName()79     public void testGivenFamilyName() {
80         assertSplitName("John Smith", null, "John", null, "Smith", null);
81         assertJoinedName("John Smith", null, "John", null, "Smith", null);
82     }
83 
testGivenMiddleFamilyName()84     public void testGivenMiddleFamilyName() {
85         assertSplitName("John Edward Smith", null, "John", "Edward", "Smith", null);
86         assertJoinedName("John Edward Smith", null, "John", "Edward", "Smith", null);
87     }
88 
testThreeNamesAndFamilyName()89     public void testThreeNamesAndFamilyName() {
90         assertSplitName("John Edward Kevin Smith", null, "John Edward", "Kevin", "Smith", null);
91         assertJoinedName("John Edward Kevin Smith", null, "John Edward", "Kevin", "Smith", null);
92     }
93 
testPrefixFivenFamilyName()94     public void testPrefixFivenFamilyName() {
95         assertSplitName("Mr. John Smith", "Mr.", "John", null, "Smith", null);
96         assertJoinedName("Mr John Smith", "Mr", "John", null, "Smith", null);
97         assertSplitName("Mr.John Smith", "Mr.", "John", null, "Smith", null);
98         assertJoinedName("Mr John Smith", "Mr", "John", null, "Smith", null);
99     }
100 
testFivenFamilyNameSuffix()101     public void testFivenFamilyNameSuffix() {
102         assertSplitName("John Smith Jr", null, "John", null, "Smith", "Jr");
103         assertJoinedName("John Smith, Jr.", null, "John", null, "Smith", "Jr");
104     }
105 
testGivenFamilyNameSuffixWithDot()106     public void testGivenFamilyNameSuffixWithDot() {
107         assertSplitName("John Smith M.D.", null, "John", null, "Smith", "M.D.");
108         assertJoinedName("John Smith, M.D.", null, "John", null, "Smith", "M.D.");
109         assertSplitName("John Smith D D S", null, "John", null, "Smith", "D D S");
110         assertJoinedName("John Smith, D D S", null, "John", null, "Smith", "D D S");
111     }
112 
testGivenSuffixFamilyName()113     public void testGivenSuffixFamilyName() {
114         assertSplitName("John von Smith", null, "John", null, "von Smith", null);
115         assertJoinedName("John von Smith", null, "John", null, "von Smith", null);
116     }
117 
testGivenSuffixFamilyNameWithDot()118     public void testGivenSuffixFamilyNameWithDot() {
119         assertSplitName("John St.Smith", null, "John", null, "St. Smith", null);
120         assertJoinedName("John St. Smith", null, "John", null, "St. Smith", null);
121     }
122 
testPrefixGivenMiddleFamily()123     public void testPrefixGivenMiddleFamily() {
124         assertSplitName("Mr. John Kevin Smith", "Mr.", "John", "Kevin", "Smith", null);
125         assertJoinedName("Mr John Kevin Smith", "Mr", "John", "Kevin", "Smith", null);
126         assertSplitName("Mr.John Kevin Smith", "Mr.", "John", "Kevin", "Smith", null);
127         assertJoinedName("Mr. John Kevin Smith", "Mr.", "John", "Kevin", "Smith", null);
128     }
129 
testPrefixGivenMiddleFamilySuffix()130     public void testPrefixGivenMiddleFamilySuffix() {
131         assertSplitName("Mr. John Kevin Smith Jr.", "Mr.", "John", "Kevin", "Smith", "Jr.");
132         assertJoinedName("Mr John Kevin Smith, Jr.", "Mr", "John", "Kevin", "Smith", "Jr");
133     }
134 
testPrefixGivenMiddlePrefixFamilySuffixWrongCapitalization()135     public void testPrefixGivenMiddlePrefixFamilySuffixWrongCapitalization() {
136         assertSplitName("MR. john keVin VON SmiTh JR.", "MR.", "john", "keVin", "VON SmiTh", "JR.");
137         assertJoinedName("MR john keVin VON SmiTh, JR.", "MR", "john", "keVin", "VON SmiTh", "JR");
138     }
139 
testPrefixFamilySuffix()140     public void testPrefixFamilySuffix() {
141         assertSplitName("von Smith Jr.", null, null, null, "von Smith", "Jr.");
142         assertJoinedName("von Smith, Jr.", null, null, null, "von Smith", "Jr");
143     }
144 
testFamilyNameGiven()145     public void testFamilyNameGiven() {
146         assertSplitName("Smith, John", null, "John", null, "Smith", null);
147         assertSplitName("Smith  , John", null, "John", null, "Smith", null);
148         assertSplitName("Smith, John Kimble", null, "John", "Kimble", "Smith", null);
149         assertSplitName("Smith, John K.", null, "John", "K.", "Smith", null);
150         assertSplitName("Smith, John, Jr.", null, "John", null, "Smith", "Jr.");
151         assertSplitName("Smith, John Kimble, Jr.", null, "John", "Kimble", "Smith", "Jr.");
152         assertSplitName("von Braun, John, Jr.", null, "John", null, "von Braun", "Jr.");
153         assertSplitName("von Braun, John Kimble, Jr.", null, "John", "Kimble", "von Braun", "Jr.");
154     }
155 
testTwoNamesAndFamilyNameWithAmpersand()156     public void testTwoNamesAndFamilyNameWithAmpersand() {
157         assertSplitName("John & Edward Smith", null, "John & Edward", null, "Smith", null);
158         assertJoinedName("John & Edward Smith", null, "John & Edward", null, "Smith", null);
159         assertSplitName("John and Edward Smith", null, "John and Edward", null, "Smith", null);
160         assertSplitName("Smith, John and Edward", null, "John and Edward", null, "Smith", null);
161         assertJoinedName("John and Edward Smith", null, "John and Edward", null, "Smith", null);
162     }
163 
testWithMiddleInitialAndNoDot()164     public void testWithMiddleInitialAndNoDot() {
165         assertSplitName("John E. Smith", null, "John", "E.", "Smith", null);
166         assertJoinedName("John E Smith", null, "John", "E", "Smith", null);
167     }
168 
testWithLongGivenNameAndDot()169     public void testWithLongGivenNameAndDot() {
170         assertSplitName("John Ed. K. Smith", null, "John Ed.", "K.", "Smith", null);
171         assertJoinedName("John Ed. K Smith", null, "John Ed.", "K", "Smith", null);
172     }
173 
testGuessFullNameStyleEmpty()174     public void testGuessFullNameStyleEmpty() {
175         assertFullNameStyle(FullNameStyle.UNDEFINED, null);
176         assertFullNameStyle(FullNameStyle.UNDEFINED, "");
177     }
178 
testGuessFullNameStyleWestern()179     public void testGuessFullNameStyleWestern() {
180 
181         // Latin letters
182         assertFullNameStyle(FullNameStyle.WESTERN, "John Doe");
183 
184         // Starts with a Latin letter, but contains Japanese letters
185         assertFullNameStyle(FullNameStyle.JAPANESE, "A\u3080\u308D\u306A\u307F\u3048");
186 
187         // Starts with an Extended Latin letter "Latin Capital Ligature OE"
188         assertFullNameStyle(FullNameStyle.WESTERN, "\u0152uvre");
189 
190         // Non-letters don't make a difference. This one starts with a vertical line
191         assertFullNameStyle(FullNameStyle.WESTERN, "\uFF5C.?+Smith");
192     }
193 
testGuessFullNameStyleJapanese()194     public void testGuessFullNameStyleJapanese() {
195         createNameSplitter(Locale.JAPAN);
196 
197         // Hiragana: always Japanese
198         assertFullNameStyle(FullNameStyle.JAPANESE, "\u3042\u3080\u308D\u306A\u307F\u3048");
199 
200         // Katakana: always Japanese
201         assertFullNameStyle(FullNameStyle.JAPANESE, "\u30A2\u30E0\u30ED \u30CA\u30DF\u30A8");
202 
203         // Half-width Katakana: always Japanese
204         assertFullNameStyle(FullNameStyle.JAPANESE, "\uFF71\uFF91\uFF9B \uFF85\uFF90\uFF74");
205 
206         // Kanji: we cannot tell if this is Japanese, Chinese or Korean, but we are
207         // in Locale.JAPAN, so assume Japanese
208         assertFullNameStyle(FullNameStyle.JAPANESE, "\u5B89\u5BA4\u5948\u7F8E\u6075");
209 
210         // TODO: mix
211 
212         // Accompanied by a phonetic name in Hiragana, we can safely assume that the
213         // name is Japanese
214         assertFullNameStyle(FullNameStyle.JAPANESE, "\u5B89\u5BA4\u5948\u7F8E\u6075",
215                 "\u3042\u3080\u308D", null, "\u306A\u307F\u3048");
216 
217         // Starts with a latin letter - not Western
218         assertFullNameStyle(FullNameStyle.JAPANESE, "A\u3080\u308D\u306A\u307F\u3048");
219     }
220 
testGuessFullNameStyleChinese()221     public void testGuessFullNameStyleChinese() {
222         createNameSplitter(Locale.CHINA);
223 
224         // Hanzi: we cannot tell if this is Chinese, Japanese or Korean,
225         // but we are in Locale.CHINA, so assume this is Chinese
226         assertFullNameStyle(FullNameStyle.CHINESE, "\u675C\u9D51");
227 
228         // Accompanied by a phonetic name in Pinyin, we can safely assume that the
229         // name is Chinese
230         assertFullNameStyle(FullNameStyle.CHINESE, "\u675C\u9D51",
231                 "du4", null, "juan1");
232 
233         // Non-letters don't make a difference. This one starts with a vertical line
234         assertFullNameStyle(FullNameStyle.CHINESE, "\uFF5C--(\u675C\u9D51)");
235     }
236 
testGuessFullNameStyleChineseMixed()237     public void testGuessFullNameStyleChineseMixed() {
238         createNameSplitter(Locale.CHINA);
239         // Both first and last names are Chinese.
240         assertFullNameStyle(FullNameStyle.CHINESE, "\u675C \u9D51");
241         // Last name is Chinese, first name is English.
242         assertFullNameStyle(FullNameStyle.CHINESE, "\u675C Juan");
243         // Last name is English, first name is Chinese.
244         assertFullNameStyle(FullNameStyle.CHINESE, "Du \u9D51");
245         // Both first and last names are English, prefix, middle, suffix are all Chinese.
246         Name name = new Name();
247         name.prefix = "\u524D";
248         name.givenNames = "Du";
249         name.middleName = "\u5C0F";
250         name.familyName = "Juan";
251         name.suffix = "\u540E";
252         mNameSplitter.guessNameStyle(name);
253         // guessFullNameStyle() only look at last and first name.
254         assertEquals(FullNameStyle.WESTERN, name.fullNameStyle);
255     }
256 
testGuessPhoneticNameStyle()257     public void testGuessPhoneticNameStyle() {
258 
259         // Hiragana
260         assertPhoneticNameStyle(PhoneticNameStyle.JAPANESE, "\u3042\u3080\u308D", null, null);
261         assertPhoneticNameStyle(PhoneticNameStyle.JAPANESE, null, "\u3042\u3080\u308D", null);
262         assertPhoneticNameStyle(PhoneticNameStyle.JAPANESE, null, null, "\u306A\u307F\u3048");
263         assertPhoneticNameStyle(PhoneticNameStyle.JAPANESE, "\u3042\u3080\u308D", null,
264                 "\u306A\u307F\u3048");
265 
266         // Katakana
267         assertPhoneticNameStyle(PhoneticNameStyle.JAPANESE, "\u30A2\u30E0\u30ED", null,
268                 "\u30CA\u30DF\u30A8");
269 
270         // Half-width Katakana
271         assertPhoneticNameStyle(PhoneticNameStyle.JAPANESE, "\u30A2\u30E0\u30ED", null,
272                 "\u30CA\u30DF\u30A8");
273 
274         // Chinese
275         assertPhoneticNameStyle(PhoneticNameStyle.PINYIN, "du4", null, "juan1");
276     }
277 
testSplitJapaneseName()278     public void testSplitJapaneseName() {
279         createNameSplitter(Locale.JAPAN);
280 
281         // One word is interpreted as given name only
282         assertSplitName("\u3042\u3080\u308D", null, "\u3042\u3080\u308D", null, null, null);
283 
284         // Two words are interpreted as family + give name
285         assertSplitName("\u3042\u3080\u308D \u306A\u307F\u3048", null, "\u306A\u307F\u3048", null,
286                 "\u3042\u3080\u308D", null);
287 
288         // Multiple words are interpreted as "family - given names"
289         assertSplitName("\u3042\u3080\u308D \u3068\u304A\u308B \u306A\u307F\u3048", null,
290                 "\u3068\u304A\u308B \u306A\u307F\u3048", null, "\u3042\u3080\u308D", null);
291 
292         // Hanzi characters without spaces: lump them all in the given name
293         assertSplitName("\u6BB5\u5C0F\u6D9B", null, "\u6BB5\u5C0F\u6D9B", null, null, null);
294     }
295 
testSplitChineseName()296     public void testSplitChineseName() {
297         createNameSplitter(Locale.CHINA);
298 
299         // Two Hanzi characters: familyName+givenName
300         assertSplitName("\u6BB5\u5C0F", null, "\u5C0F", null, "\u6BB5", null);
301 
302         // Two Hanzi characters: familyName+middleName+givenName
303         assertSplitName("\u6BB5\u5C0F\u6D9B", null, "\u6D9B", "\u5C0F", "\u6BB5", null);
304 
305         // Two Hanzi characters: familyName(2)+middleName+givenName
306         assertSplitName("\u6BB5\u5C0F\u6D9B\u6D9C", null, "\u6D9C", "\u6D9B", "\u6BB5\u5C0F", null);
307     }
308 
testJoinJapaneseName()309     public void testJoinJapaneseName() {
310         createNameSplitter(Locale.JAPAN);
311 
312         assertJoinedName("\u3042\u3080\u308D", FullNameStyle.JAPANESE, null, "\u3042\u3080\u308D",
313                 null, null, null, true);
314 
315         // Given-name-first flag is ignored for CJK locales
316         assertJoinedName("\u3084\u307E\u3056\u304D \u3068\u304A\u308B", FullNameStyle.JAPANESE,
317                 null, "\u3068\u304A\u308B", null, "\u3084\u307E\u3056\u304D", null, false);
318         assertJoinedName("\u3084\u307E\u3056\u304D \u3068\u304A\u308B \u3068\u304A\u308B",
319                 FullNameStyle.JAPANESE, null, "\u3068\u304A\u308B", "\u3068\u304A\u308B",
320                 "\u3084\u307E\u3056\u304D", null, false);
321     }
322 
testJoinChineseName()323     public void testJoinChineseName() {
324         createNameSplitter(Locale.CHINA);
325 
326         // Given-name-first flag is ignored for CJK locales
327         assertJoinedName("\u6BB5\u5C0F\u6D9B", FullNameStyle.CHINESE, null,
328                 "\u6D9B", "\u5C0F", "\u6BB5", null, true);
329         assertJoinedName("\u6BB5\u5C0F\u6D9B", FullNameStyle.CHINESE, null,
330                 "\u6D9B", "\u5C0F", "\u6BB5", null, false);
331     }
332 
assertSplitName(String fullName, String prefix, String givenNames, String middleName, String familyName, String suffix)333     private void assertSplitName(String fullName, String prefix, String givenNames,
334             String middleName, String familyName, String suffix) {
335         final Name name = new Name();
336         mNameSplitter.split(name, fullName);
337         assertEquals(prefix, name.getPrefix());
338         assertEquals(givenNames, name.getGivenNames());
339         assertEquals(middleName, name.getMiddleName());
340         assertEquals(familyName, name.getFamilyName());
341         assertEquals(suffix, name.getSuffix());
342     }
343 
assertJoinedName(String expected, String prefix, String givenNames, String middleName, String familyName, String suffix)344     private void assertJoinedName(String expected, String prefix, String givenNames,
345             String middleName, String familyName, String suffix) {
346         assertJoinedName(expected, FullNameStyle.WESTERN, prefix, givenNames, middleName,
347                 familyName, suffix, true);
348     }
349 
assertJoinedName(String expected, int nameStyle, String prefix, String givenNames, String middleName, String familyName, String suffix, boolean givenNameFirst)350     private void assertJoinedName(String expected, int nameStyle, String prefix, String givenNames,
351             String middleName, String familyName, String suffix, boolean givenNameFirst) {
352         Name name = new Name();
353         name.fullNameStyle = nameStyle;
354         name.prefix = prefix;
355         name.givenNames = givenNames;
356         name.middleName = middleName;
357         name.familyName = familyName;
358         name.suffix = suffix;
359         String actual = mNameSplitter.join(name, givenNameFirst, true);
360         assertEquals(expected, actual);
361     }
362 
assertFullNameStyle(int expectedFullNameStyle, String fullName)363     private void assertFullNameStyle(int expectedFullNameStyle, String fullName) {
364         Name name = new Name();
365         mNameSplitter.split(name, fullName);
366         mNameSplitter.guessNameStyle(name);
367 
368         assertEquals(expectedFullNameStyle, name.fullNameStyle);
369     }
370 
assertFullNameStyle(int expectedFullNameStyle, String fullName, String phoneticFamilyName, String phoneticMiddleName, String phoneticGivenName)371     private void assertFullNameStyle(int expectedFullNameStyle, String fullName,
372             String phoneticFamilyName, String phoneticMiddleName, String phoneticGivenName) {
373         Name name = new Name();
374         mNameSplitter.split(name, fullName);
375         name.phoneticFamilyName = phoneticFamilyName;
376         name.phoneticMiddleName = phoneticMiddleName;
377         name.phoneticGivenName = phoneticGivenName;
378 
379         mNameSplitter.guessNameStyle(name);
380 
381         assertEquals(expectedFullNameStyle, name.fullNameStyle);
382     }
383 
assertPhoneticNameStyle(int expectedPhoneticNameStyle, String phoneticFamilyName, String phoneticMiddleName, String phoneticGivenName)384     private void assertPhoneticNameStyle(int expectedPhoneticNameStyle, String phoneticFamilyName,
385             String phoneticMiddleName, String phoneticGivenName) {
386         Name name = new Name();
387         name.phoneticFamilyName = phoneticFamilyName;
388         name.phoneticMiddleName = phoneticMiddleName;
389         name.phoneticGivenName = phoneticGivenName;
390 
391         mNameSplitter.guessNameStyle(name);
392 
393         assertEquals(expectedPhoneticNameStyle, name.phoneticNameStyle);
394     }
395 
testSplitKoreanName()396     public void testSplitKoreanName() {
397         createNameSplitter(Locale.KOREA);
398 
399         // Lee - Sang Il
400         assertSplitName("\uC774\uC0C1\uC77C", null, "\uC0C1\uC77C", null, "\uC774", null);
401         // Dok Go - Young Jae
402         assertSplitName("\uB3C5\uACE0\uC601\uC7AC",
403                 null, "\uC601\uC7AC", null, "\uB3C5\uACE0", null);
404     }
405 }
406