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