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 43 protected void setUp() throws Exception { 44 super.setUp(); 45 createNameSplitter(Locale.US); 46 } 47 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 53 public void testNull() { 54 assertSplitName(null, null, null, null, null, null); 55 assertJoinedName(null, null, null, null, null, null); 56 } 57 58 public void testEmpty() { 59 assertSplitName("", null, null, null, null, null); 60 assertJoinedName(null, null, null, null, null, null); 61 } 62 63 public void testSpaces() { 64 assertSplitName(" ", null, null, null, null, null); 65 assertJoinedName(null, null, null, null, null, null); 66 } 67 68 public void testFamilyName() { 69 assertSplitName("Smith", null, "Smith", null, null, null); 70 assertJoinedName("Smith", null, "Smith", null, null, null); 71 } 72 73 public void testIgnoreSuffix() { 74 assertSplitName("Ms MD", "Ms", null, null, "MD", null); 75 assertJoinedName("Ms MD", "Ms", null, null, "MD", null); 76 } 77 78 public void testGivenFamilyName() { 79 assertSplitName("John Smith", null, "John", null, "Smith", null); 80 assertJoinedName("John Smith", null, "John", null, "Smith", null); 81 } 82 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 173 public void testGuessFullNameStyleEmpty() { 174 assertFullNameStyle(FullNameStyle.UNDEFINED, null); 175 assertFullNameStyle(FullNameStyle.UNDEFINED, ""); 176 } 177 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 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 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 236 237 public void testGuessPhoneticNameStyle() { 238 239 // Hiragana 240 assertPhoneticNameStyle(PhoneticNameStyle.JAPANESE, "\u3042\u3080\u308D", null, null); 241 assertPhoneticNameStyle(PhoneticNameStyle.JAPANESE, null, "\u3042\u3080\u308D", null); 242 assertPhoneticNameStyle(PhoneticNameStyle.JAPANESE, null, null, "\u306A\u307F\u3048"); 243 assertPhoneticNameStyle(PhoneticNameStyle.JAPANESE, "\u3042\u3080\u308D", null, 244 "\u306A\u307F\u3048"); 245 246 // Katakana 247 assertPhoneticNameStyle(PhoneticNameStyle.JAPANESE, "\u30A2\u30E0\u30ED", null, 248 "\u30CA\u30DF\u30A8"); 249 250 // Half-width Katakana 251 assertPhoneticNameStyle(PhoneticNameStyle.JAPANESE, "\u30A2\u30E0\u30ED", null, 252 "\u30CA\u30DF\u30A8"); 253 254 // Chinese 255 assertPhoneticNameStyle(PhoneticNameStyle.PINYIN, "du4", null, "juan1"); 256 } 257 258 public void testSplitJapaneseName() { 259 createNameSplitter(Locale.JAPAN); 260 261 // One word is interpreted as given name only 262 assertSplitName("\u3042\u3080\u308D", null, "\u3042\u3080\u308D", null, null, null); 263 264 // Two words are interpreted as family + give name 265 assertSplitName("\u3042\u3080\u308D \u306A\u307F\u3048", null, "\u306A\u307F\u3048", null, 266 "\u3042\u3080\u308D", null); 267 268 // Multiple words are interpreted as "family - given names" 269 assertSplitName("\u3042\u3080\u308D \u3068\u304A\u308B \u306A\u307F\u3048", null, 270 "\u3068\u304A\u308B \u306A\u307F\u3048", null, "\u3042\u3080\u308D", null); 271 272 // Hanzi characters without spaces: lump them all in the given name 273 assertSplitName("\u6BB5\u5C0F\u6D9B", null, "\u6BB5\u5C0F\u6D9B", null, null, null); 274 } 275 276 public void testSplitChineseName() { 277 createNameSplitter(Locale.CHINA); 278 279 // Two Hanzi characters: familyName+givenName 280 assertSplitName("\u6BB5\u5C0F", null, "\u5C0F", null, "\u6BB5", null); 281 282 // Two Hanzi characters: familyName+middleName+givenName 283 assertSplitName("\u6BB5\u5C0F\u6D9B", null, "\u6D9B", "\u5C0F", "\u6BB5", null); 284 285 // Two Hanzi characters: familyName(2)+middleName+givenName 286 assertSplitName("\u6BB5\u5C0F\u6D9B\u6D9C", null, "\u6D9C", "\u6D9B", "\u6BB5\u5C0F", null); 287 } 288 289 public void testJoinJapaneseName() { 290 createNameSplitter(Locale.JAPAN); 291 292 assertJoinedName("\u3042\u3080\u308D", FullNameStyle.JAPANESE, null, "\u3042\u3080\u308D", 293 null, null, null, true); 294 295 // Given-name-first flag is ignored for CJK locales 296 assertJoinedName("\u3084\u307E\u3056\u304D \u3068\u304A\u308B", FullNameStyle.JAPANESE, 297 null, "\u3068\u304A\u308B", null, "\u3084\u307E\u3056\u304D", null, false); 298 assertJoinedName("\u3084\u307E\u3056\u304D \u3068\u304A\u308B \u3068\u304A\u308B", 299 FullNameStyle.JAPANESE, null, "\u3068\u304A\u308B", "\u3068\u304A\u308B", 300 "\u3084\u307E\u3056\u304D", null, false); 301 } 302 303 public void testJoinChineseName() { 304 createNameSplitter(Locale.CHINA); 305 306 // Given-name-first flag is ignored for CJK locales 307 assertJoinedName("\u6BB5\u5C0F\u6D9B", FullNameStyle.CHINESE, null, 308 "\u6D9B", "\u5C0F", "\u6BB5", null, true); 309 assertJoinedName("\u6BB5\u5C0F\u6D9B", FullNameStyle.CHINESE, null, 310 "\u6D9B", "\u5C0F", "\u6BB5", null, false); 311 } 312 313 private void assertSplitName(String fullName, String prefix, String givenNames, 314 String middleName, String familyName, String suffix) { 315 final Name name = new Name(); 316 mNameSplitter.split(name, fullName); 317 assertEquals(prefix, name.getPrefix()); 318 assertEquals(givenNames, name.getGivenNames()); 319 assertEquals(middleName, name.getMiddleName()); 320 assertEquals(familyName, name.getFamilyName()); 321 assertEquals(suffix, name.getSuffix()); 322 } 323 324 private void assertJoinedName(String expected, String prefix, String givenNames, 325 String middleName, String familyName, String suffix) { 326 assertJoinedName(expected, FullNameStyle.WESTERN, prefix, givenNames, middleName, 327 familyName, suffix, true); 328 } 329 330 private void assertJoinedName(String expected, int nameStyle, String prefix, String givenNames, 331 String middleName, String familyName, String suffix, boolean givenNameFirst) { 332 Name name = new Name(); 333 name.fullNameStyle = nameStyle; 334 name.prefix = prefix; 335 name.givenNames = givenNames; 336 name.middleName = middleName; 337 name.familyName = familyName; 338 name.suffix = suffix; 339 String actual = mNameSplitter.join(name, givenNameFirst, true); 340 assertEquals(expected, actual); 341 } 342 343 private void assertFullNameStyle(int expectedFullNameStyle, String fullName) { 344 Name name = new Name(); 345 mNameSplitter.split(name, fullName); 346 mNameSplitter.guessNameStyle(name); 347 348 assertEquals(expectedFullNameStyle, name.fullNameStyle); 349 } 350 351 private void assertFullNameStyle(int expectedFullNameStyle, String fullName, 352 String phoneticFamilyName, String phoneticMiddleName, String phoneticGivenName) { 353 Name name = new Name(); 354 mNameSplitter.split(name, fullName); 355 name.phoneticFamilyName = phoneticFamilyName; 356 name.phoneticMiddleName = phoneticMiddleName; 357 name.phoneticGivenName = phoneticGivenName; 358 359 mNameSplitter.guessNameStyle(name); 360 361 assertEquals(expectedFullNameStyle, name.fullNameStyle); 362 } 363 364 private void assertPhoneticNameStyle(int expectedPhoneticNameStyle, String phoneticFamilyName, 365 String phoneticMiddleName, String phoneticGivenName) { 366 Name name = new Name(); 367 name.phoneticFamilyName = phoneticFamilyName; 368 name.phoneticMiddleName = phoneticMiddleName; 369 name.phoneticGivenName = phoneticGivenName; 370 371 mNameSplitter.guessNameStyle(name); 372 373 assertEquals(expectedPhoneticNameStyle, name.phoneticNameStyle); 374 } 375 376 public void testSplitKoreanName() { 377 createNameSplitter(Locale.KOREA); 378 379 // Lee - Sang Il 380 assertSplitName("\uC774\uC0C1\uC77C", null, "\uC0C1\uC77C", null, "\uC774", null); 381 // Dok Go - Young Jae 382 assertSplitName("\uB3C5\uACE0\uC601\uC7AC", 383 null, "\uC601\uC7AC", null, "\uB3C5\uACE0", null); 384 } 385 } 386