1 /* 2 * Copyright (C) 2009 The Guava Authors 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.google.common.net; 18 19 20 import com.google.common.annotations.GwtCompatible; 21 import com.google.common.annotations.GwtIncompatible; 22 import com.google.common.annotations.J2ktIncompatible; 23 import com.google.common.base.Ascii; 24 import com.google.common.base.Strings; 25 import com.google.common.collect.ImmutableSet; 26 import com.google.common.collect.Iterables; 27 import com.google.common.testing.EqualsTester; 28 import com.google.common.testing.NullPointerTester; 29 import junit.framework.TestCase; 30 31 /** 32 * {@link TestCase} for {@link InternetDomainName}. 33 * 34 * @author Craig Berry 35 */ 36 @GwtCompatible(emulated = true) 37 public final class InternetDomainNameTest extends TestCase { 38 private static final InternetDomainName UNICODE_EXAMPLE = 39 InternetDomainName.from("j\u00f8rpeland.no"); 40 private static final InternetDomainName PUNYCODE_EXAMPLE = 41 InternetDomainName.from("xn--jrpeland-54a.no"); 42 43 /** The Greek letter delta, used in unicode testing. */ 44 private static final String DELTA = "\u0394"; 45 46 /** A domain part which is valid under lenient validation, but invalid under strict validation. */ 47 static final String LOTS_OF_DELTAS = Strings.repeat(DELTA, 62); 48 49 private static final String ALMOST_TOO_MANY_LEVELS = Strings.repeat("a.", 127); 50 51 private static final String ALMOST_TOO_LONG = Strings.repeat("aaaaa.", 40) + "1234567890.c"; 52 53 private static final ImmutableSet<String> VALID_NAME = 54 ImmutableSet.of( 55 "foo.com", 56 "f-_-o.cOM", 57 "f--1.com", 58 "f11-1.com", 59 "www", 60 "abc.a23", 61 "biz.com.ua", 62 "x", 63 "fOo", 64 "f--o", 65 "f_a", 66 "foo.net.us\uFF61ocm", 67 "woo.com.", 68 "8server.shop", 69 "123.cn", 70 "a" + DELTA + "b.com", 71 ALMOST_TOO_MANY_LEVELS, 72 ALMOST_TOO_LONG); 73 74 private static final ImmutableSet<String> INVALID_NAME = 75 ImmutableSet.of( 76 "", 77 " ", 78 "127.0.0.1", 79 "::1", 80 "13", 81 "abc.12c", 82 "foo-.com", 83 "_bar.quux", 84 "foo+bar.com", 85 "foo!bar.com", 86 ".foo.com", 87 "..bar.com", 88 "baz..com", 89 "..quiffle.com", 90 "fleeb.com..", 91 ".", 92 "..", 93 "...", 94 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.com", 95 "a" + DELTA + " .com", 96 ALMOST_TOO_MANY_LEVELS + "com", 97 ALMOST_TOO_LONG + ".c"); 98 99 private static final ImmutableSet<String> RS = 100 ImmutableSet.of( 101 "com", 102 "co.uk", 103 "foo.bd", 104 "xxxxxx.bd", 105 "org.mK", 106 "us", 107 "co.uk.", // Trailing dot 108 "co\uFF61uk", // Alternate dot character 109 "\u7f51\u7edc.Cn", // "网络.Cn" 110 "j\u00f8rpeland.no", // "jorpeland.no" (first o slashed) 111 "xn--jrpeland-54a.no"); // IDNA (punycode) encoding of above 112 113 private static final ImmutableSet<String> PS_NOT_RS = 114 ImmutableSet.of("blogspot.com", "blogspot.co.uk", "uk.com"); 115 116 private static final ImmutableSet<String> PS = 117 ImmutableSet.<String>builder().addAll(RS).addAll(PS_NOT_RS).build(); 118 119 private static final ImmutableSet<String> NO_PS = 120 ImmutableSet.of("www", "foo.ihopethiswillneverbeapublicsuffix", "x.y.z"); 121 122 /** 123 * Having a public suffix is equivalent to having a registry suffix, because all registry suffixes 124 * are public suffixes, and all public suffixes have registry suffixes. 125 */ 126 private static final ImmutableSet<String> NO_RS = NO_PS; 127 128 private static final ImmutableSet<String> NON_PS = 129 ImmutableSet.of( 130 "foo.bar.com", 131 "foo.ca", 132 "foo.bar.ca", 133 "foo.blogspot.com", 134 "foo.blogspot.co.uk", 135 "foo.uk.com", 136 "foo.bar.co.il", 137 "state.CA.us", 138 "www.state.pa.us", 139 "pvt.k12.ca.us", 140 "www.google.com", 141 "www4.yahoo.co.uk", 142 "home.netscape.com", 143 "web.MIT.edu", 144 "foo.eDu.au", 145 "utenti.blah.IT", 146 "dominio.com.co"); 147 148 private static final ImmutableSet<String> NON_RS = 149 ImmutableSet.<String>builder().addAll(NON_PS).addAll(PS_NOT_RS).build(); 150 151 private static final ImmutableSet<String> TOP_UNDER_REGISTRY_SUFFIX = 152 ImmutableSet.of("google.com", "foo.Co.uk", "foo.ca.us."); 153 154 private static final ImmutableSet<String> TOP_PRIVATE_DOMAIN = 155 ImmutableSet.of("google.com", "foo.Co.uk", "foo.ca.us.", "foo.blogspot.com"); 156 157 private static final ImmutableSet<String> UNDER_TOP_UNDER_REGISTRY_SUFFIX = 158 ImmutableSet.of("foo.bar.google.com", "a.b.co.uk", "x.y.ca.us"); 159 160 private static final ImmutableSet<String> UNDER_PRIVATE_DOMAIN = 161 ImmutableSet.of("foo.bar.google.com", "a.b.co.uk", "x.y.ca.us", "a.b.blogspot.com"); 162 163 private static final ImmutableSet<String> VALID_IP_ADDRS = 164 ImmutableSet.of("1.2.3.4", "127.0.0.1", "::1", "2001:db8::1"); 165 166 private static final ImmutableSet<String> INVALID_IP_ADDRS = 167 ImmutableSet.of( 168 "", "1", "1.2.3", "...", "1.2.3.4.5", "400.500.600.700", ":", ":::1", "2001:db8:"); 169 170 private static final ImmutableSet<String> SOMEWHERE_UNDER_PS = 171 ImmutableSet.of( 172 "foo.bar.google.com", 173 "a.b.c.1.2.3.ca.us", 174 "site.jp", 175 "uomi-online.kir.jp", 176 "jprs.co.jp", 177 "site.quick.jp", 178 "site.tenki.jp", 179 "site.or.jp", 180 "site.gr.jp", 181 "site.ne.jp", 182 "site.ac.jp", 183 "site.ad.jp", 184 "site.ed.jp", 185 "site.geo.jp", 186 "site.go.jp", 187 "site.lg.jp", 188 "1.fm", 189 "site.cc", 190 "site.ee", 191 "site.fi", 192 "site.fm", 193 "site.gr", 194 "www.leguide.ma", 195 "site.ma", 196 "some.org.mk", 197 "site.mk", 198 "site.tv", 199 "site.us", 200 "www.odev.us", 201 "www.GOOGLE.com", 202 "www.com", 203 "google.com", 204 "www7.google.co.uk", 205 "google.Co.uK", 206 "jobs.kt.com.", 207 "home.netscape.com", 208 "web.stanford.edu", 209 "stanford.edu", 210 "state.ca.us", 211 "www.state.ca.us", 212 "state.ca.us", 213 "pvt.k12.ca.us", 214 "www.rave.ca.", 215 "cnn.ca", 216 "ledger-enquirer.com", 217 "it-trace.ch", 218 "cool.dk", 219 "cool.co.uk", 220 "cool.de", 221 "cool.es", 222 "cool\uFF61fr", // Alternate dot character 223 "cool.nl", 224 "members.blah.nl.", 225 "cool.se", 226 "utenti.blah.it", 227 "kt.co", 228 "a\u7f51\u7edcA.\u7f51\u7edc.Cn" // "a网络A.网络.Cn" 229 ); 230 231 private static final ImmutableSet<String> SOMEWHERE_UNDER_RS = 232 ImmutableSet.<String>builder().addAll(SOMEWHERE_UNDER_PS).addAll(PS_NOT_RS).build(); 233 testValid()234 public void testValid() { 235 for (String name : VALID_NAME) { 236 InternetDomainName unused = InternetDomainName.from(name); 237 } 238 } 239 testInvalid()240 public void testInvalid() { 241 for (String name : INVALID_NAME) { 242 try { 243 InternetDomainName.from(name); 244 fail("Should have been invalid: '" + name + "'"); 245 } catch (IllegalArgumentException expected) { 246 } 247 } 248 } 249 testPublicSuffix()250 public void testPublicSuffix() { 251 for (String name : PS) { 252 final InternetDomainName domain = InternetDomainName.from(name); 253 assertTrue(name, domain.isPublicSuffix()); 254 assertTrue(name, domain.hasPublicSuffix()); 255 assertFalse(name, domain.isUnderPublicSuffix()); 256 assertFalse(name, domain.isTopPrivateDomain()); 257 assertEquals(domain, domain.publicSuffix()); 258 } 259 260 for (String name : NO_PS) { 261 final InternetDomainName domain = InternetDomainName.from(name); 262 assertFalse(name, domain.isPublicSuffix()); 263 assertFalse(name, domain.hasPublicSuffix()); 264 assertFalse(name, domain.isUnderPublicSuffix()); 265 assertFalse(name, domain.isTopPrivateDomain()); 266 assertNull(domain.publicSuffix()); 267 } 268 269 for (String name : NON_PS) { 270 final InternetDomainName domain = InternetDomainName.from(name); 271 assertFalse(name, domain.isPublicSuffix()); 272 assertTrue(name, domain.hasPublicSuffix()); 273 assertTrue(name, domain.isUnderPublicSuffix()); 274 } 275 } 276 testUnderPublicSuffix()277 public void testUnderPublicSuffix() { 278 for (String name : SOMEWHERE_UNDER_PS) { 279 final InternetDomainName domain = InternetDomainName.from(name); 280 assertFalse(name, domain.isPublicSuffix()); 281 assertTrue(name, domain.hasPublicSuffix()); 282 assertTrue(name, domain.isUnderPublicSuffix()); 283 } 284 } 285 testTopPrivateDomain()286 public void testTopPrivateDomain() { 287 for (String name : TOP_PRIVATE_DOMAIN) { 288 final InternetDomainName domain = InternetDomainName.from(name); 289 assertFalse(name, domain.isPublicSuffix()); 290 assertTrue(name, domain.hasPublicSuffix()); 291 assertTrue(name, domain.isUnderPublicSuffix()); 292 assertTrue(name, domain.isTopPrivateDomain()); 293 assertEquals(domain.parent(), domain.publicSuffix()); 294 } 295 } 296 testUnderPrivateDomain()297 public void testUnderPrivateDomain() { 298 for (String name : UNDER_PRIVATE_DOMAIN) { 299 final InternetDomainName domain = InternetDomainName.from(name); 300 assertFalse(name, domain.isPublicSuffix()); 301 assertTrue(name, domain.hasPublicSuffix()); 302 assertTrue(name, domain.isUnderPublicSuffix()); 303 assertFalse(name, domain.isTopPrivateDomain()); 304 } 305 } 306 testRegistrySuffix()307 public void testRegistrySuffix() { 308 for (String name : RS) { 309 final InternetDomainName domain = InternetDomainName.from(name); 310 assertTrue(name, domain.isRegistrySuffix()); 311 assertTrue(name, domain.hasRegistrySuffix()); 312 assertFalse(name, domain.isUnderRegistrySuffix()); 313 assertFalse(name, domain.isTopDomainUnderRegistrySuffix()); 314 assertEquals(domain, domain.registrySuffix()); 315 } 316 317 for (String name : NO_RS) { 318 final InternetDomainName domain = InternetDomainName.from(name); 319 assertFalse(name, domain.isRegistrySuffix()); 320 assertFalse(name, domain.hasRegistrySuffix()); 321 assertFalse(name, domain.isUnderRegistrySuffix()); 322 assertFalse(name, domain.isTopDomainUnderRegistrySuffix()); 323 assertNull(domain.registrySuffix()); 324 } 325 326 for (String name : NON_RS) { 327 final InternetDomainName domain = InternetDomainName.from(name); 328 assertFalse(name, domain.isRegistrySuffix()); 329 assertTrue(name, domain.hasRegistrySuffix()); 330 assertTrue(name, domain.isUnderRegistrySuffix()); 331 } 332 } 333 testUnderRegistrySuffix()334 public void testUnderRegistrySuffix() { 335 for (String name : SOMEWHERE_UNDER_RS) { 336 final InternetDomainName domain = InternetDomainName.from(name); 337 assertFalse(name, domain.isRegistrySuffix()); 338 assertTrue(name, domain.hasRegistrySuffix()); 339 assertTrue(name, domain.isUnderRegistrySuffix()); 340 } 341 } 342 testTopDomainUnderRegistrySuffix()343 public void testTopDomainUnderRegistrySuffix() { 344 for (String name : TOP_UNDER_REGISTRY_SUFFIX) { 345 final InternetDomainName domain = InternetDomainName.from(name); 346 assertFalse(name, domain.isRegistrySuffix()); 347 assertTrue(name, domain.hasRegistrySuffix()); 348 assertTrue(name, domain.isUnderRegistrySuffix()); 349 assertTrue(name, domain.isTopDomainUnderRegistrySuffix()); 350 assertEquals(domain.parent(), domain.registrySuffix()); 351 } 352 } 353 testUnderTopDomainUnderRegistrySuffix()354 public void testUnderTopDomainUnderRegistrySuffix() { 355 for (String name : UNDER_TOP_UNDER_REGISTRY_SUFFIX) { 356 final InternetDomainName domain = InternetDomainName.from(name); 357 assertFalse(name, domain.isRegistrySuffix()); 358 assertTrue(name, domain.hasRegistrySuffix()); 359 assertTrue(name, domain.isUnderRegistrySuffix()); 360 assertFalse(name, domain.isTopDomainUnderRegistrySuffix()); 361 } 362 } 363 testParent()364 public void testParent() { 365 assertEquals("com", InternetDomainName.from("google.com").parent().toString()); 366 assertEquals("uk", InternetDomainName.from("co.uk").parent().toString()); 367 assertEquals("google.com", InternetDomainName.from("www.google.com").parent().toString()); 368 369 try { 370 InternetDomainName.from("com").parent(); 371 fail("'com' should throw ISE on .parent() call"); 372 } catch (IllegalStateException expected) { 373 } 374 } 375 testChild()376 public void testChild() { 377 InternetDomainName domain = InternetDomainName.from("foo.com"); 378 379 assertEquals("www.foo.com", domain.child("www").toString()); 380 381 try { 382 domain.child("www."); 383 fail("www..google.com should have been invalid"); 384 } catch (IllegalArgumentException expected) { 385 } 386 } 387 testParentChild()388 public void testParentChild() { 389 InternetDomainName origin = InternetDomainName.from("foo.com"); 390 InternetDomainName parent = origin.parent(); 391 assertEquals("com", parent.toString()); 392 393 // These would throw an exception if leniency were not preserved during parent() and child() 394 // calls. 395 InternetDomainName child = parent.child(LOTS_OF_DELTAS); 396 InternetDomainName unused = child.child(LOTS_OF_DELTAS); 397 } 398 testValidTopPrivateDomain()399 public void testValidTopPrivateDomain() { 400 InternetDomainName googleDomain = InternetDomainName.from("google.com"); 401 402 assertEquals(googleDomain, googleDomain.topPrivateDomain()); 403 assertEquals(googleDomain, googleDomain.child("mail").topPrivateDomain()); 404 assertEquals(googleDomain, googleDomain.child("foo.bar").topPrivateDomain()); 405 } 406 testInvalidTopPrivateDomain()407 public void testInvalidTopPrivateDomain() { 408 ImmutableSet<String> badCookieDomains = ImmutableSet.of("co.uk", "foo", "com"); 409 410 for (String domain : badCookieDomains) { 411 try { 412 InternetDomainName.from(domain).topPrivateDomain(); 413 fail(domain); 414 } catch (IllegalStateException expected) { 415 } 416 } 417 } 418 testIsValid()419 public void testIsValid() { 420 final Iterable<String> validCases = Iterables.concat(VALID_NAME, PS, NO_PS, NON_PS); 421 final Iterable<String> invalidCases = 422 Iterables.concat(INVALID_NAME, VALID_IP_ADDRS, INVALID_IP_ADDRS); 423 424 for (String valid : validCases) { 425 assertTrue(valid, InternetDomainName.isValid(valid)); 426 } 427 428 for (String invalid : invalidCases) { 429 assertFalse(invalid, InternetDomainName.isValid(invalid)); 430 } 431 } 432 testToString()433 public void testToString() { 434 for (String inputName : SOMEWHERE_UNDER_PS) { 435 InternetDomainName domain = InternetDomainName.from(inputName); 436 437 /* 438 * We would ordinarily use constants for the expected results, but 439 * doing it by derivation allows us to reuse the test case definitions 440 * used in other tests. 441 */ 442 443 String expectedName = Ascii.toLowerCase(inputName); 444 expectedName = expectedName.replaceAll("[\u3002\uFF0E\uFF61]", "."); 445 446 if (expectedName.endsWith(".")) { 447 expectedName = expectedName.substring(0, expectedName.length() - 1); 448 } 449 450 assertEquals(expectedName, domain.toString()); 451 } 452 } 453 testPublicSuffixExclusion()454 public void testPublicSuffixExclusion() { 455 InternetDomainName domain = InternetDomainName.from("foo.city.yokohama.jp"); 456 assertTrue(domain.hasPublicSuffix()); 457 assertEquals("yokohama.jp", domain.publicSuffix().toString()); 458 459 // Behold the weirdness! 460 assertFalse(domain.publicSuffix().isPublicSuffix()); 461 } 462 testPublicSuffixMultipleUnders()463 public void testPublicSuffixMultipleUnders() { 464 // PSL has both *.uk and *.sch.uk; the latter should win. 465 // See http://code.google.com/p/guava-libraries/issues/detail?id=1176 466 467 InternetDomainName domain = InternetDomainName.from("www.essex.sch.uk"); 468 assertTrue(domain.hasPublicSuffix()); 469 assertEquals("essex.sch.uk", domain.publicSuffix().toString()); 470 assertEquals("www.essex.sch.uk", domain.topPrivateDomain().toString()); 471 } 472 testRegistrySuffixExclusion()473 public void testRegistrySuffixExclusion() { 474 InternetDomainName domain = InternetDomainName.from("foo.city.yokohama.jp"); 475 assertTrue(domain.hasRegistrySuffix()); 476 assertEquals("yokohama.jp", domain.registrySuffix().toString()); 477 478 // Behold the weirdness! 479 assertFalse(domain.registrySuffix().isRegistrySuffix()); 480 } 481 testRegistrySuffixMultipleUnders()482 public void testRegistrySuffixMultipleUnders() { 483 // PSL has both *.uk and *.sch.uk; the latter should win. 484 // See http://code.google.com/p/guava-libraries/issues/detail?id=1176 485 486 InternetDomainName domain = InternetDomainName.from("www.essex.sch.uk"); 487 assertTrue(domain.hasRegistrySuffix()); 488 assertEquals("essex.sch.uk", domain.registrySuffix().toString()); 489 assertEquals("www.essex.sch.uk", domain.topDomainUnderRegistrySuffix().toString()); 490 } 491 testEquality()492 public void testEquality() { 493 new EqualsTester() 494 .addEqualityGroup(idn("google.com"), idn("google.com"), idn("GOOGLE.COM")) 495 .addEqualityGroup(idn("www.google.com")) 496 .addEqualityGroup(UNICODE_EXAMPLE) 497 .addEqualityGroup(PUNYCODE_EXAMPLE) 498 .testEquals(); 499 } 500 idn(String domain)501 private static InternetDomainName idn(String domain) { 502 return InternetDomainName.from(domain); 503 } 504 505 @J2ktIncompatible 506 @GwtIncompatible // NullPointerTester testNulls()507 public void testNulls() { 508 final NullPointerTester tester = new NullPointerTester(); 509 510 tester.testAllPublicStaticMethods(InternetDomainName.class); 511 tester.testAllPublicInstanceMethods(InternetDomainName.from("google.com")); 512 } 513 } 514