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