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