1 /* 2 * Copyright (C) 2008 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.emailcommon.mail; 18 19 import android.test.AndroidTestCase; 20 import android.test.suitebuilder.annotation.SmallTest; 21 import org.apache.james.mime4j.decoder.DecoderUtil; 22 23 import java.io.UnsupportedEncodingException; 24 import java.net.URLEncoder; 25 26 /** 27 * This is a series of unit tests for the Address class. These tests must be locally 28 * complete - no server(s) required. 29 */ 30 @SmallTest 31 public class AddressUnitTests extends AndroidTestCase { 32 33 private static final String MULTI_ADDRESSES_LIST = 34 "noname1 (at) dom1.com, " 35 + "<noname2 (at) dom2.com>, " 36 + "simple name <address3 (at) dom3.org>, " 37 + "\"name,4\" <address4 (at) dom4.org>," 38 + "\"big \\\"G\\\"\" <bigG (at) dom5.net>," 39 + "\u65E5\u672C\u8A9E <address6 (at) co.jp>," 40 + "\"\u65E5\u672C\u8A9E\" <address7 (at) co.jp>," 41 + "\uD834\uDF01\uD834\uDF46 <address8 (at) ne.jp>," 42 + "\"\uD834\uDF01\uD834\uDF46\" <address9 (at) ne.jp>," 43 + "noname (at) dom.com <noname (at) dom.com>" // personal == address 44 ; 45 private static final int MULTI_ADDRESSES_COUNT = 10; 46 47 private static final Address PACK_ADDR_1 = new Address("john (at) gmail.com", "John Doe"); 48 private static final Address PACK_ADDR_2 = new Address("foo (at) bar.com", null); 49 private static final Address PACK_ADDR_3 = new Address( 50 "mar.y+test (at) gmail.com", "Mar-y, B; B*arr"); 51 private static final Address[][] PACK_CASES = { 52 {PACK_ADDR_2}, {PACK_ADDR_1}, 53 {PACK_ADDR_1, PACK_ADDR_2}, {PACK_ADDR_2, PACK_ADDR_1}, 54 {PACK_ADDR_1, PACK_ADDR_3}, {PACK_ADDR_2, PACK_ADDR_2}, 55 {PACK_ADDR_1, PACK_ADDR_2, PACK_ADDR_3}, {PACK_ADDR_3, PACK_ADDR_1, PACK_ADDR_2} 56 }; 57 58 Address mAddress1; 59 Address mAddress2; 60 Address mAddress3; 61 62 /** 63 * Setup code. We generate a handful of Address objects 64 */ 65 @Override 66 protected void setUp() throws Exception { 67 super.setUp(); 68 69 mAddress1 = new Address("address1", "personal1"); 70 mAddress2 = new Address("address2", ""); 71 mAddress3 = new Address("address3", null); 72 } 73 74 // see documentation of DecoderUtil.decodeEncodedWords() for details 75 private String padEncoded(String s) { 76 return "=?UTF-8?B?" + s + "?="; 77 } 78 79 /** 80 * Generate strings of incresing lenght by taking prefix substrings. 81 * For each of them, compare with the decoding of the precomputed base-64 encoding. 82 */ 83 public void testBase64Decode() { 84 String testString = "xyza\0\""; 85 String base64Encoded[] = {"", "eA==", "eHk=", "eHl6", "eHl6YQ==", "eHl6YQA=", "eHl6YQAi"}; 86 int len = testString.length(); 87 for (int i = 1; i <= len; ++i) { 88 String encoded = padEncoded(base64Encoded[i]); 89 String decoded = DecoderUtil.decodeEncodedWords(encoded); 90 String prefix = testString.substring(0, i); 91 assertEquals(""+i, prefix, decoded); 92 } 93 } 94 95 /** 96 * Test for setAddress(). 97 */ 98 public void testSetAddress() { 99 String bareAddress = "user1 (at) dom1.com"; 100 String bracketAddress = "<user2 (at) dom2.com>"; 101 102 Address address = new Address(bareAddress); 103 assertEquals("bare address", "user1 (at) dom1.com", address.getAddress()); 104 105 address.setAddress(bracketAddress); 106 assertEquals("bracket address", "user2 (at) dom2.com", address.getAddress()); 107 } 108 109 /** 110 * Test for empty setPersonal(). 111 */ 112 public void testNullPersonal() { 113 Address address = new Address("user1 (at) dom1.org"); 114 assertNull("no name", address.getPersonal()); 115 116 address.setPersonal(null); 117 assertNull("null name", address.getPersonal()); 118 119 address.setPersonal(""); 120 assertNull("empty name", address.getPersonal()); 121 122 address.setPersonal("\"\""); 123 assertNull("quoted empty address", address.getPersonal()); 124 } 125 126 /** 127 * Test for setPersonal(). 128 */ 129 public void testSetPersonal() { 130 Address address = new Address("user1 (at) dom1.net", "simple name"); 131 assertEquals("simple name", "simple name", address.getPersonal()); 132 133 address.setPersonal("big \\\"G\\\""); 134 assertEquals("quoted name", "big \"G\"", address.getPersonal()); 135 136 address.setPersonal("=?UTF-8?Q?big \"G\"?="); 137 assertEquals("quoted printable name", "big \"G\"", address.getPersonal()); 138 139 address.setPersonal("=?UTF-8?B?YmlnICJHIg==?="); 140 assertEquals("base64 encoded name", "big \"G\"", address.getPersonal()); 141 } 142 143 /** 144 * Test for setPersonal() with utf-16 and utf-32. 145 */ 146 public void testSetPersonalMultipleEncodings() { 147 Address address = new Address("user1 (at) dom1.co.jp", "=?UTF-8?B?5bK45pys?="); 148 assertEquals("base64 utf-16 name", "\u5CB8\u672C", address.getPersonal()); 149 150 address.setPersonal("\"=?UTF-8?Q?=E5=B2=B8=E6=9C=AC?=\""); 151 assertEquals("quoted printable utf-16 name", "\u5CB8\u672C", address.getPersonal()); 152 153 address.setPersonal("=?ISO-2022-JP?B?GyRCNF9LXBsoQg==?="); 154 assertEquals("base64 jis encoded name", "\u5CB8\u672C", address.getPersonal()); 155 156 address.setPersonal("\"=?UTF-8?B?8J2MgfCdjYY=?=\""); 157 assertEquals("base64 utf-32 name", "\uD834\uDF01\uD834\uDF46", address.getPersonal()); 158 159 address.setPersonal("=?UTF-8?Q?=F0=9D=8C=81=F0=9D=8D=86?="); 160 assertEquals("quoted printable utf-32 name", 161 "\uD834\uDF01\uD834\uDF46", address.getPersonal()); 162 } 163 164 /** 165 * TODO: more in-depth tests for parse() 166 */ 167 168 /** 169 * Simple quick checks of empty-input edge conditions for parse() 170 * 171 * NOTE: This is not a claim that these edge cases are "correct", only to maintain consistent 172 * behavior while I am changing some of the code in the function under test. 173 */ 174 public void testEmptyParse() { 175 Address[] result; 176 177 // null input => empty array 178 result = Address.parse(null); 179 assertTrue("parsing null address", result != null && result.length == 0); 180 181 // empty string input => empty array 182 result = Address.parse(""); 183 assertTrue("parsing zero-length", result != null && result.length == 0); 184 185 // spaces 186 result = Address.parse(" "); 187 assertTrue("parsing spaces", result != null && result.length == 0); 188 189 // spaces with comma 190 result = Address.parse(" , "); 191 assertTrue("parsing spaces with comma", result != null && result.length == 0); 192 } 193 194 /** 195 * Test parsing for single address. 196 */ 197 public void testSingleParse() { 198 Address[] address1 = Address.parse("address1 (at) dom1.com"); 199 assertEquals("bare address count", 1, address1.length); 200 assertEquals("bare address", "address1 (at) dom1.com", address1[0].getAddress()); 201 assertNull("name of bare address", address1[0].getPersonal()); 202 203 Address[] address2 = Address.parse("<address2 (at) dom2.com>"); 204 assertEquals("bracket address count", 1, address2.length); 205 assertEquals("bracket address", "address2 (at) dom2.com", address2[0].getAddress()); 206 assertNull("name of bracket address", address2[0].getPersonal()); 207 208 Address[] address3 = Address.parse("first last <address3 (at) dom3.org>"); 209 assertEquals("address with name count", 1, address3.length); 210 assertEquals("address with name", "address3 (at) dom3.org", address3[0].getAddress()); 211 assertEquals("name of address with name", "first last", address3[0].getPersonal()); 212 213 Address[] address4 = Address.parse("\"first,last\" <address4 (at) dom4.org>"); 214 assertEquals("address with quoted name count", 1, address4.length); 215 assertEquals("address with quoted name", "address4 (at) dom4.org", address4[0].getAddress()); 216 assertEquals("name of address with quoted name", "first,last", address4[0].getPersonal()); 217 } 218 219 /** 220 * Test parsing for illegal address. 221 */ 222 public void testIllegalParse() { 223 Address[] address1 = Address.parse("address1"); 224 assertEquals("no atmark", 0, address1.length); 225 226 Address[] address2 = Address.parse("address2@"); 227 assertEquals("no domain", 0, address2.length); 228 229 Address[] address3 = Address.parse("@dom3.com"); 230 assertEquals("no local part", 0, address3.length); 231 232 Address[] address4 = Address.parse("address4@sub (at) dom4.org"); 233 assertEquals("more than one atmark", 0, address4.length); 234 235 Address[] address5 = Address.parse("address5@dom5"); 236 assertEquals("not dot in domain part", 0, address5.length); 237 238 Address[] address6 = Address.parse("address6 (at) dom6.com."); 239 assertEquals("domain ends with dot", 0, address6.length); 240 241 Address[] address7 = Address.parse("address7 (at) .dom7.org"); 242 assertEquals("domain starts with dot", 0, address7.length); 243 } 244 245 /** 246 * Test parsing for address part. 247 */ 248 public void testParsingAddress() { 249 Address[] addresses = Address.parse("address1 (at) dom1.net, <address2 (at) dom2.com>"); 250 assertEquals("address count", 2, addresses.length); 251 252 assertEquals("bare address", "address1 (at) dom1.net", addresses[0].getAddress()); 253 assertNull("bare address name", addresses[0].getPersonal()); 254 255 assertEquals("bracket address", "address2 (at) dom2.com", addresses[1].getAddress()); 256 assertNull("bracket address name", addresses[1].getPersonal()); 257 } 258 259 /** 260 * Test parsing for simple name part. 261 */ 262 public void testParsingSimpleName() { 263 Address[] addresses = Address.parse( 264 "name 1 <address1 (at) dom1.net>, " + 265 "\"name,2\" <address2 (at) dom2.org>"); 266 assertEquals("address count", 2, addresses.length); 267 268 assertEquals("bare name address", "address1 (at) dom1.net", addresses[0].getAddress()); 269 assertEquals("bare name", "name 1", addresses[0].getPersonal()); 270 271 assertEquals("double quoted name address", "address2 (at) dom2.org", addresses[1].getAddress()); 272 assertEquals("double quoted name", "name,2", addresses[1].getPersonal()); 273 } 274 275 /** 276 * Test parsing for utf-16 name part. 277 */ 278 public void testParsingUtf16Name() { 279 Address[] addresses = Address.parse( 280 "\u3042\u3044\u3046 \u3048\u304A <address1 (at) dom1.jp>, " + 281 "\"\u3042\u3044\u3046,\u3048\u304A\" <address2 (at) dom2.jp>"); 282 assertEquals("address count", 2, addresses.length); 283 284 assertEquals("bare utf-16 name address", "address1 (at) dom1.jp", addresses[0].getAddress()); 285 assertEquals("bare utf-16 name", 286 "\u3042\u3044\u3046 \u3048\u304A", addresses[0].getPersonal()); 287 288 assertEquals("double quoted utf-16 name address", 289 "address2 (at) dom2.jp", addresses[1].getAddress()); 290 assertEquals("double quoted utf-16 name", 291 "\u3042\u3044\u3046,\u3048\u304A", addresses[1].getPersonal()); 292 } 293 294 /** 295 * Test parsing for utf-32 name part. 296 */ 297 public void testParsingUtf32Name() { 298 Address[] addresses = Address.parse( 299 "\uD834\uDF01\uD834\uDF46 \uD834\uDF22 <address1 (at) dom1.net>, " + 300 "\"\uD834\uDF01\uD834\uDF46,\uD834\uDF22\" <address2 (at) dom2.com>"); 301 assertEquals("address count", 2, addresses.length); 302 303 assertEquals("bare utf-32 name address", "address1 (at) dom1.net", addresses[0].getAddress()); 304 assertEquals("bare utf-32 name", 305 "\uD834\uDF01\uD834\uDF46 \uD834\uDF22", addresses[0].getPersonal()); 306 307 assertEquals("double quoted utf-32 name address", 308 "address2 (at) dom2.com", addresses[1].getAddress()); 309 assertEquals("double quoted utf-32 name", 310 "\uD834\uDF01\uD834\uDF46,\uD834\uDF22", addresses[1].getPersonal()); 311 } 312 313 /** 314 * Test parsing for multi addresses. 315 */ 316 public void testParseMulti() { 317 Address[] addresses = Address.parse(MULTI_ADDRESSES_LIST); 318 319 assertEquals("multi addrsses count", MULTI_ADDRESSES_COUNT, addresses.length); 320 321 assertEquals("no name 1 address", "noname1 (at) dom1.com", addresses[0].getAddress()); 322 assertNull("no name 1 name", addresses[0].getPersonal()); 323 assertEquals("no name 2 address", "noname2 (at) dom2.com", addresses[1].getAddress()); 324 assertNull("no name 2 name", addresses[1].getPersonal()); 325 assertEquals("simple name address", "address3 (at) dom3.org", addresses[2].getAddress()); 326 assertEquals("simple name name", "simple name", addresses[2].getPersonal()); 327 assertEquals("double quoted name address", "address4 (at) dom4.org", addresses[3].getAddress()); 328 assertEquals("double quoted name name", "name,4", addresses[3].getPersonal()); 329 assertEquals("quoted name address", "bigG (at) dom5.net", addresses[4].getAddress()); 330 assertEquals("quoted name name", "big \"G\"", addresses[4].getPersonal()); 331 assertEquals("utf-16 name address", "address6 (at) co.jp", addresses[5].getAddress()); 332 assertEquals("utf-16 name name", "\u65E5\u672C\u8A9E", addresses[5].getPersonal()); 333 assertEquals("utf-16 quoted name address", "address7 (at) co.jp", addresses[6].getAddress()); 334 assertEquals("utf-16 quoted name name", "\u65E5\u672C\u8A9E", 335 addresses[6].getPersonal()); 336 assertEquals("utf-32 name address", "address8 (at) ne.jp", addresses[7].getAddress()); 337 assertEquals("utf-32 name name", "\uD834\uDF01\uD834\uDF46", addresses[7].getPersonal()); 338 assertEquals("utf-32 quoted name address", "address9 (at) ne.jp", addresses[8].getAddress()); 339 assertEquals("utf-32 quoted name name", "\uD834\uDF01\uD834\uDF46", 340 addresses[8].getPersonal()); 341 } 342 343 /** 344 * Test various combinations of the toString (single) method 345 */ 346 public void testToStringSingle() { 347 Address[] addresses = Address.parse(MULTI_ADDRESSES_LIST); 348 349 assertEquals("multi addrsses count", MULTI_ADDRESSES_COUNT, addresses.length); 350 351 // test for toString() results. 352 assertEquals("no name 1", "noname1 (at) dom1.com", addresses[0].toString()); 353 assertEquals("no name 2", "noname2 (at) dom2.com", addresses[1].toString()); 354 assertEquals("simple name", "simple name <address3 (at) dom3.org>", addresses[2].toString()); 355 assertEquals("double quoted name", 356 "\"name,4\" <address4 (at) dom4.org>", addresses[3].toString()); 357 assertEquals("quoted name", "\"big \"G\"\" <bigG (at) dom5.net>", addresses[4].toString()); 358 assertEquals("utf-16 name", "\u65E5\u672C\u8A9E <address6 (at) co.jp>", 359 addresses[5].toString()); 360 assertEquals("utf-16 quoted name", "\u65E5\u672C\u8A9E <address7 (at) co.jp>", 361 addresses[6].toString()); 362 assertEquals("utf-32 name", "\uD834\uDF01\uD834\uDF46 <address8 (at) ne.jp>", 363 addresses[7].toString()); 364 assertEquals("utf-32 quoted name", "\uD834\uDF01\uD834\uDF46 <address9 (at) ne.jp>", 365 addresses[8].toString()); 366 assertEquals("name==address", "noname (at) dom.com", addresses[9].toString()); 367 } 368 369 /** 370 * Test various combinations of the toString (multi) method 371 */ 372 public void testToStringMulti() { 373 final Address[] address = Address.parse("noname1 (at) dom1.com"); 374 final Address[] addresses = Address.parse(MULTI_ADDRESSES_LIST); 375 376 assertEquals("multi addrsses count", MULTI_ADDRESSES_COUNT, addresses.length); 377 378 { 379 String line = Address.toString(address); 380 assertEquals("toString multi-1", 381 "noname1 (at) dom1.com", 382 line); 383 } 384 { 385 String line = Address.toString(addresses); 386 assertEquals("toString multi-n", 387 "noname1 (at) dom1.com," 388 + "noname2 (at) dom2.com," 389 + "simple name <address3 (at) dom3.org>," 390 + "\"name,4\" <address4 (at) dom4.org>," 391 + "\"big \"G\"\" <bigG (at) dom5.net>," 392 + "\u65E5\u672C\u8A9E <address6 (at) co.jp>," 393 + "\u65E5\u672C\u8A9E <address7 (at) co.jp>," 394 + "\uD834\uDF01\uD834\uDF46 <address8 (at) ne.jp>," 395 + "\uD834\uDF01\uD834\uDF46 <address9 (at) ne.jp>," 396 + "noname (at) dom.com", 397 line); 398 } 399 400 // With custom separator 401 { 402 String line = Address.toString(address, "$"); 403 assertEquals("toString multi-1", 404 "noname1 (at) dom1.com", 405 line); 406 } 407 408 { 409 String line = Address.toString(addresses, "$"); 410 assertEquals("toString multi-n", 411 "noname1 (at) dom1.com$" 412 + "noname2 (at) dom2.com$" 413 + "simple name <address3 (at) dom3.org>$" 414 + "\"name,4\" <address4 (at) dom4.org>$" 415 + "\"big \"G\"\" <bigG (at) dom5.net>$" 416 + "\u65E5\u672C\u8A9E <address6 (at) co.jp>$" 417 + "\u65E5\u672C\u8A9E <address7 (at) co.jp>$" 418 + "\uD834\uDF01\uD834\uDF46 <address8 (at) ne.jp>$" 419 + "\uD834\uDF01\uD834\uDF46 <address9 (at) ne.jp>$" 420 + "noname (at) dom.com", 421 line); 422 } 423 } 424 425 /** 426 * Test parsing for quoted and encoded name part. 427 */ 428 public void testParsingQuotedEncodedName() { 429 Address[] addresses = Address.parse( 430 "\"big \\\"G\\\"\" <bigG (at) dom1.com>, =?UTF-8?B?5pel5pys6Kqe?= <address2 (at) co.jp>"); 431 432 assertEquals("address count", 2, addresses.length); 433 434 assertEquals("quoted name address", "bigG (at) dom1.com", addresses[0].getAddress()); 435 assertEquals("quoted name", "big \"G\"", addresses[0].getPersonal()); 436 437 assertEquals("encoded name address", "address2 (at) co.jp", addresses[1].getAddress()); 438 assertEquals("encoded name", "\u65E5\u672C\u8A9E", addresses[1].getPersonal()); 439 } 440 441 /** 442 * Test various combinations of the toHeader (single) method 443 */ 444 public void testToHeaderSingle() { 445 Address noName1 = new Address("noname1 (at) dom1.com"); 446 Address noName2 = new Address("<noname2 (at) dom2.com>", ""); 447 Address simpleName = new Address("address3 (at) dom3.org", "simple name"); 448 Address dquoteName = new Address("address4 (at) dom4.org", "name,4"); 449 Address quotedName = new Address("bigG (at) dom5.net", "big \"G\""); 450 Address utf16Name = new Address("<address6 (at) co.jp>", "\"\u65E5\u672C\u8A9E\""); 451 Address utf32Name = new Address("<address8 (at) ne.jp>", "\uD834\uDF01\uD834\uDF46"); 452 Address sameName = new Address("address (at) dom.org", "address (at) dom.org"); 453 454 // test for internal states. 455 assertEquals("no name 1 address", "noname1 (at) dom1.com", noName1.getAddress()); 456 assertNull("no name 1 name", noName1.getPersonal()); 457 assertEquals("no name 2 address", "noname2 (at) dom2.com", noName2.getAddress()); 458 assertNull("no name 2 name", noName2.getPersonal()); 459 assertEquals("simple name address", "address3 (at) dom3.org", simpleName.getAddress()); 460 assertEquals("simple name name", "simple name", simpleName.getPersonal()); 461 assertEquals("double quoted name address", "address4 (at) dom4.org", dquoteName.getAddress()); 462 assertEquals("double quoted name name", "name,4", dquoteName.getPersonal()); 463 assertEquals("quoted name address", "bigG (at) dom5.net", quotedName.getAddress()); 464 assertEquals("quoted name name", "big \"G\"", quotedName.getPersonal()); 465 assertEquals("utf-16 name address", "address6 (at) co.jp", utf16Name.getAddress()); 466 assertEquals("utf-16 name name", "\u65E5\u672C\u8A9E", utf16Name.getPersonal()); 467 assertEquals("utf-32 name address", "address8 (at) ne.jp", utf32Name.getAddress()); 468 assertEquals("utf-32 name name", "\uD834\uDF01\uD834\uDF46", utf32Name.getPersonal()); 469 assertEquals("name == address address", "address (at) dom.org", sameName.getAddress()); 470 assertEquals("name == address name", "address (at) dom.org", sameName.getPersonal()); 471 472 // Test for toHeader() results. 473 assertEquals("no name 1", "noname1 (at) dom1.com", noName1.toHeader()); 474 assertEquals("no name 2", "noname2 (at) dom2.com", noName2.toHeader()); 475 assertEquals("simple name", "simple name <address3 (at) dom3.org>", simpleName.toHeader()); 476 assertEquals("double quoted name", "\"name,4\" <address4 (at) dom4.org>", dquoteName.toHeader()); 477 assertEquals("quoted name", "\"big \\\"G\\\"\" <bigG (at) dom5.net>", quotedName.toHeader()); 478 assertEquals("utf-16 name", "=?UTF-8?B?5pel5pys6Kqe?= <address6 (at) co.jp>", 479 utf16Name.toHeader()); 480 assertEquals("utf-32 name", "=?UTF-8?B?8J2MgfCdjYY=?= <address8 (at) ne.jp>", 481 utf32Name.toHeader()); 482 assertEquals("name == address", "\"address (at) dom.org\" <address (at) dom.org>", 483 sameName.toHeader()); 484 } 485 486 /** 487 * Test various combinations of the toHeader (multi) method 488 */ 489 public void testToHeaderMulti() { 490 Address noName1 = new Address("noname1 (at) dom1.com"); 491 Address noName2 = new Address("<noname2 (at) dom2.com>", ""); 492 Address simpleName = new Address("address3 (at) dom3.org", "simple name"); 493 Address dquoteName = new Address("address4 (at) dom4.org", "name,4"); 494 Address quotedName = new Address("bigG (at) dom5.net", "big \"G\""); 495 Address utf16Name = new Address("<address6 (at) co.jp>", "\"\u65E5\u672C\u8A9E\""); 496 Address utf32Name = new Address("<address8 (at) ne.jp>", "\uD834\uDF01\uD834\uDF46"); 497 498 // test for internal states. 499 assertEquals("no name 1 address", "noname1 (at) dom1.com", noName1.getAddress()); 500 assertNull("no name 1 name", noName1.getPersonal()); 501 assertEquals("no name 2 address", "noname2 (at) dom2.com", noName2.getAddress()); 502 assertNull("no name 2 name", noName2.getPersonal()); 503 assertEquals("simple name address", "address3 (at) dom3.org", simpleName.getAddress()); 504 assertEquals("simple name name", "simple name", simpleName.getPersonal()); 505 assertEquals("double quoted name address", "address4 (at) dom4.org", dquoteName.getAddress()); 506 assertEquals("double quoted name name", "name,4", dquoteName.getPersonal()); 507 assertEquals("quoted name address", "bigG (at) dom5.net", quotedName.getAddress()); 508 assertEquals("quoted name name", "big \"G\"", quotedName.getPersonal()); 509 assertEquals("utf-16 name address", "address6 (at) co.jp", utf16Name.getAddress()); 510 assertEquals("utf-16 name name", "\u65E5\u672C\u8A9E", utf16Name.getPersonal()); 511 assertEquals("utf-32 name address", "address8 (at) ne.jp", utf32Name.getAddress()); 512 assertEquals("utf-32 name name", "\uD834\uDF01\uD834\uDF46", utf32Name.getPersonal()); 513 514 Address[] addresses = new Address[] { 515 noName1, noName2, simpleName, dquoteName, quotedName, utf16Name, utf32Name, 516 }; 517 String line = Address.toHeader(addresses); 518 519 assertEquals("toHeader() multi", 520 "noname1 (at) dom1.com, " 521 + "noname2 (at) dom2.com, " 522 + "simple name <address3 (at) dom3.org>, " 523 + "\"name,4\" <address4 (at) dom4.org>, " 524 + "\"big \\\"G\\\"\" <bigG (at) dom5.net>, " 525 + "=?UTF-8?B?5pel5pys6Kqe?= <address6 (at) co.jp>, " 526 + "=?UTF-8?B?8J2MgfCdjYY=?= <address8 (at) ne.jp>", 527 line); 528 } 529 530 /** 531 * Test various combinations of the toFriendly (single) method 532 */ 533 public void testToFriendlySingle() { 534 assertEquals("personal1", mAddress1.toFriendly()); 535 assertEquals("address2", mAddress2.toFriendly()); 536 assertEquals("address3", mAddress3.toFriendly()); 537 } 538 539 /** 540 * Test various combinations of the toFriendly (array) method 541 */ 542 public void testToFriendlyArray() { 543 Address[] list1 = null; 544 Address[] list2 = new Address[0]; 545 Address[] list3 = new Address[] { mAddress1 }; 546 Address[] list4 = new Address[] { mAddress1, mAddress2, mAddress3 }; 547 548 assertEquals(null, Address.toFriendly(list1)); 549 assertEquals(null, Address.toFriendly(list2)); 550 assertEquals("personal1", Address.toFriendly(list3)); 551 assertEquals("personal1, address2, address3", Address.toFriendly(list4)); 552 } 553 554 /** 555 * Simple quick checks of empty-input edge conditions for pack() 556 * 557 * NOTE: This is not a claim that these edge cases are "correct", only to maintain consistent 558 * behavior while I am changing some of the code in the function under test. 559 */ 560 public void testEmptyPack() { 561 String result; 562 563 // null input => null string 564 result = Address.pack(null); 565 assertNull("packing null", result); 566 567 // zero-length input => empty string 568 result = Address.pack(new Address[] { }); 569 assertEquals("packing empty array", "", result); 570 } 571 572 /** 573 * Simple quick checks of empty-input edge conditions for unpack() 574 * 575 * NOTE: This is not a claim that these edge cases are "correct", only to maintain consistent 576 * behavior while I am changing some of the code in the function under test. 577 */ 578 public void testEmptyUnpack() { 579 Address[] result; 580 581 // null input => empty array 582 result = Address.unpack(null); 583 assertTrue("unpacking null address", result != null && result.length == 0); 584 585 // empty string input => empty array 586 result = Address.unpack(""); 587 assertTrue("unpacking zero-length", result != null && result.length == 0); 588 } 589 590 private static boolean addressEquals(Address a1, Address a2) { 591 if (!a1.equals(a2)) { 592 return false; 593 } 594 final String displayName1 = a1.getPersonal(); 595 final String displayName2 = a2.getPersonal(); 596 if (displayName1 == null) { 597 return displayName2 == null; 598 } else { 599 return displayName1.equals(displayName2); 600 } 601 } 602 603 private static boolean addressArrayEquals(Address[] array1, Address[] array2) { 604 if (array1.length != array2.length) { 605 return false; 606 } 607 for (int i = array1.length - 1; i >= 0; --i) { 608 if (!addressEquals(array1[i], array2[i])) { 609 return false; 610 } 611 } 612 return true; 613 } 614 615 public void testPackUnpack() { 616 for (Address[] list : PACK_CASES) { 617 String packed = Address.pack(list); 618 assertTrue(packed, addressArrayEquals(list, Address.unpack(packed))); 619 } 620 } 621 622 /** 623 * Tests that unpackToString() returns the same result as toString(unpack()). 624 */ 625 public void testUnpackToString() { 626 assertNull(Address.unpackToString(null)); 627 assertNull(Address.unpackToString("")); 628 629 for (Address[] list : PACK_CASES) { 630 String packed = Address.pack(list); 631 String s1 = Address.unpackToString(packed); 632 String s2 = Address.toString(Address.unpack(packed)); 633 assertEquals(s2, s2, s1); 634 } 635 } 636 637 /** 638 * Tests that parseAndPack() returns the same result as pack(parse()). 639 */ 640 public void testParseAndPack() { 641 String s1 = Address.parseAndPack(MULTI_ADDRESSES_LIST); 642 String s2 = Address.pack(Address.parse(MULTI_ADDRESSES_LIST)); 643 assertEquals(s2, s1); 644 } 645 646 public void testSinglePack() { 647 Address[] addrArray = new Address[1]; 648 for (Address address : new Address[]{PACK_ADDR_1, PACK_ADDR_2, PACK_ADDR_3}) { 649 String packed1 = address.pack(); 650 addrArray[0] = address; 651 String packed2 = Address.pack(addrArray); 652 assertEquals(packed1, packed2); 653 } 654 } 655 656 /** 657 * Tests that: 658 * 1. unpackFirst() with empty list returns null. 659 * 2. unpackFirst() with non-empty returns the same as unpack()[0] 660 */ 661 public void testUnpackFirst() { 662 assertNull(Address.unpackFirst(null)); 663 assertNull(Address.unpackFirst("")); 664 665 for (Address[] list : PACK_CASES) { 666 String packed = Address.pack(list); 667 Address[] array = Address.unpack(packed); 668 Address first = Address.unpackFirst(packed); 669 assertTrue(packed, addressEquals(array[0], first)); 670 } 671 } 672 673 public void testIsValidAddress() { 674 String notValid[] = {"", "foo", "john@", "x@y", "x@y.", "foo.com"}; 675 String valid[] = {"x (at) y.z", "john (at) gmail.com", "a (at) b.c.d"}; 676 for (String address : notValid) { 677 assertTrue(address, !Address.isValidAddress(address)); 678 } 679 for (String address : valid) { 680 assertTrue(address, Address.isValidAddress(address)); 681 } 682 683 // isAllValid() must accept empty address list as valid 684 assertTrue("Empty address list is valid", Address.isAllValid("")); 685 } 686 687 /** 688 * Legacy pack() used for testing legacyUnpack(). 689 * The packed list is a comma separated list of: 690 * URLENCODE(address)[;URLENCODE(personal)] 691 * @See pack() 692 */ 693 private static String legacyPack(Address[] addresses) { 694 if (addresses == null) { 695 return null; 696 } else if (addresses.length == 0) { 697 return ""; 698 } 699 StringBuffer sb = new StringBuffer(); 700 for (int i = 0, count = addresses.length; i < count; i++) { 701 Address address = addresses[i]; 702 try { 703 sb.append(URLEncoder.encode(address.getAddress(), "UTF-8")); 704 if (address.getPersonal() != null) { 705 sb.append(';'); 706 sb.append(URLEncoder.encode(address.getPersonal(), "UTF-8")); 707 } 708 if (i < count - 1) { 709 sb.append(','); 710 } 711 } 712 catch (UnsupportedEncodingException uee) { 713 return null; 714 } 715 } 716 return sb.toString(); 717 } 718 } 719