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