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 17package com.google.common.net; 18 19import com.google.common.annotations.GwtCompatible; 20import com.google.common.base.Ascii; 21import com.google.common.base.Strings; 22import com.google.common.collect.ImmutableSet; 23import com.google.common.collect.Iterables; 24import com.google.common.testing.EqualsTester; 25 26import junit.framework.TestCase; 27 28/** 29 * {@link TestCase} for {@link InternetDomainName}. 30 * 31 * @author Craig Berry 32 */ 33@GwtCompatible(emulated = true) 34public final class InternetDomainNameTest extends TestCase { 35 private static final InternetDomainName UNICODE_EXAMPLE = 36 InternetDomainName.from("j\u00f8rpeland.no"); 37 private static final InternetDomainName PUNYCODE_EXAMPLE = 38 InternetDomainName.from("xn--jrpeland-54a.no"); 39 40 /** 41 * The Greek letter delta, used in unicode testing. 42 */ 43 private static final String DELTA = "\u0394"; 44 45 /** 46 * A domain part which is valid under lenient validation, but invalid under 47 * strict validation. 48 */ 49 static final String LOTS_OF_DELTAS = Strings.repeat(DELTA, 62); 50 51 private static final String ALMOST_TOO_MANY_LEVELS = 52 Strings.repeat("a.", 127); 53 54 private static final String ALMOST_TOO_LONG = 55 Strings.repeat("aaaaa.", 40) + "1234567890.c"; 56 57 private static final ImmutableSet<String> VALID_NAME = ImmutableSet.of( 58 "foo.com", 59 "f-_-o.cOM", 60 "f--1.com", 61 "f11-1.com", 62 "www", 63 "abc.a23", 64 "biz.com.ua", 65 "x", 66 "fOo", 67 "f--o", 68 "f_a", 69 "foo.net.us\uFF61ocm", 70 "woo.com.", 71 "a" + DELTA + "b.com", 72 ALMOST_TOO_MANY_LEVELS, 73 ALMOST_TOO_LONG); 74 75 private static final ImmutableSet<String> INVALID_NAME = ImmutableSet.of( 76 "", 77 " ", 78 "127.0.0.1", 79 "::1", "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> PS = ImmutableSet.of( 99 "com", 100 "co.uk", 101 "foo.bd", 102 "xxxxxx.bd", 103 "org.mK", 104 "us", 105 "uk\uFF61com.", // Alternate dot character 106 "\u7f51\u7edc.Cn", // "网络.Cn" 107 "j\u00f8rpeland.no", // "jorpeland.no" (first o slashed) 108 "xn--jrpeland-54a.no" // IDNA (punycode) encoding of above 109 ); 110 111 private static final ImmutableSet<String> NO_PS = ImmutableSet.of( 112 "www", "foo.google", "x.y.z"); 113 114 private static final ImmutableSet<String> NON_PS = ImmutableSet.of( 115 "foo.bar.com", "foo.ca", "foo.bar.ca", 116 "foo.bar.co.il", "state.CA.us", "www.state.pa.us", "pvt.k12.ca.us", 117 "www.google.com", "www4.yahoo.co.uk", "home.netscape.com", 118 "web.MIT.edu", "foo.eDu.au", "utenti.blah.IT", "dominio.com.co"); 119 120 private static final ImmutableSet<String> TOP_PRIVATE_DOMAIN = 121 ImmutableSet.of("google.com", "foo.Co.uk", "foo.ca.us."); 122 123 private static final ImmutableSet<String> UNDER_PRIVATE_DOMAIN = 124 ImmutableSet.of("foo.bar.google.com", "a.b.co.uk", "x.y.ca.us"); 125 126 private static final ImmutableSet<String> VALID_IP_ADDRS = ImmutableSet.of( 127 "1.2.3.4", "127.0.0.1", "::1", "2001:db8::1"); 128 129 private static final ImmutableSet<String> INVALID_IP_ADDRS = ImmutableSet.of( 130 "", "1", "1.2.3", "...", "1.2.3.4.5", "400.500.600.700", 131 ":", ":::1", "2001:db8:"); 132 133 private static final ImmutableSet<String> SOMEWHERE_UNDER_PS = 134 ImmutableSet.of( 135 "foo.bar.google.com", 136 "a.b.c.1.2.3.ca.us", 137 "site.jp", 138 "uomi-online.kir.jp", 139 "jprs.co.jp", 140 "site.quick.jp", 141 "site.tenki.jp", 142 "site.or.jp", 143 "site.gr.jp", 144 "site.ne.jp", 145 "site.ac.jp", 146 "site.ad.jp", 147 "site.ed.jp", 148 "site.geo.jp", 149 "site.go.jp", 150 "site.lg.jp", 151 "1.fm", 152 "site.cc", 153 "site.ee", 154 "site.fi", 155 "site.fm", 156 "site.gr", 157 "www.leguide.ma", 158 "site.ma", 159 "some.org.mk", 160 "site.mk", 161 "site.tv", 162 "site.us", 163 "www.odev.us", 164 "www.GOOGLE.com", 165 "www.com", 166 "google.com", 167 "www7.google.co.uk", 168 "google.Co.uK", 169 "jobs.kt.com.", 170 "home.netscape.com", 171 "web.stanford.edu", 172 "stanford.edu", 173 "state.ca.us", 174 "www.state.ca.us", 175 "state.ca.us", 176 "pvt.k12.ca.us", 177 "www.rave.ca.", 178 "cnn.ca", 179 "ledger-enquirer.com", 180 "it-trace.ch", 181 "cool.dk", 182 "cool.co.uk", 183 "cool.de", 184 "cool.es", 185 "cool\uFF61fr", // Alternate dot character 186 "cool.nl", 187 "members.blah.nl.", 188 "cool.se", 189 "utenti.blah.it", 190 "kt.co", 191 "a\u7f51\u7edcA.\u7f51\u7edc.Cn" // "a网络A.网络.Cn" 192 ); 193 194 public void testValid() { 195 for (String name : VALID_NAME) { 196 InternetDomainName.from(name); 197 } 198 } 199 200 public void testInvalid() { 201 for (String name : INVALID_NAME) { 202 try { 203 InternetDomainName.from(name); 204 fail("Should have been invalid: '" + name + "'"); 205 } catch (IllegalArgumentException expected) { 206 // Expected case 207 } 208 } 209 } 210 211 public void testPublicSuffix() { 212 for (String name : PS) { 213 final InternetDomainName domain = InternetDomainName.from(name); 214 assertTrue(name, domain.isPublicSuffix()); 215 assertTrue(name, domain.hasPublicSuffix()); 216 assertFalse(name, domain.isUnderPublicSuffix()); 217 assertFalse(name, domain.isTopPrivateDomain()); 218 assertEquals(domain, domain.publicSuffix()); 219 } 220 221 for (String name : NO_PS) { 222 final InternetDomainName domain = InternetDomainName.from(name); 223 assertFalse(name, domain.isPublicSuffix()); 224 assertFalse(name, domain.hasPublicSuffix()); 225 assertFalse(name, domain.isUnderPublicSuffix()); 226 assertFalse(name, domain.isTopPrivateDomain()); 227 assertNull(domain.publicSuffix()); 228 } 229 230 for (String name : NON_PS) { 231 final InternetDomainName domain = InternetDomainName.from(name); 232 assertFalse(name, domain.isPublicSuffix()); 233 assertTrue(name, domain.hasPublicSuffix()); 234 assertTrue(name, domain.isUnderPublicSuffix()); 235 } 236 } 237 238 public void testUnderPublicSuffix() { 239 for (String name : SOMEWHERE_UNDER_PS) { 240 final InternetDomainName domain = InternetDomainName.from(name); 241 assertFalse(name, domain.isPublicSuffix()); 242 assertTrue(name, domain.hasPublicSuffix()); 243 assertTrue(name, domain.isUnderPublicSuffix()); 244 } 245 } 246 247 public void testTopPrivateDomain() { 248 for (String name : TOP_PRIVATE_DOMAIN) { 249 final InternetDomainName domain = InternetDomainName.from(name); 250 assertFalse(name, domain.isPublicSuffix()); 251 assertTrue(name, domain.hasPublicSuffix()); 252 assertTrue(name, domain.isUnderPublicSuffix()); 253 assertTrue(name, domain.isTopPrivateDomain()); 254 assertEquals(domain.parent(), domain.publicSuffix()); 255 } 256 } 257 258 public void testUnderPrivateDomain() { 259 for (String name : UNDER_PRIVATE_DOMAIN) { 260 final InternetDomainName domain = InternetDomainName.from(name); 261 assertFalse(name, domain.isPublicSuffix()); 262 assertTrue(name, domain.hasPublicSuffix()); 263 assertTrue(name, domain.isUnderPublicSuffix()); 264 assertFalse(name, domain.isTopPrivateDomain()); 265 } 266 } 267 268 public void testParent() { 269 assertEquals( 270 "com", 271 InternetDomainName.from("google.com").parent().toString()); 272 assertEquals( 273 "uk", 274 InternetDomainName.from("co.uk").parent().toString()); 275 assertEquals( 276 "google.com", 277 InternetDomainName.from("www.google.com").parent().toString()); 278 279 try { 280 InternetDomainName.from("com").parent(); 281 fail("'com' should throw ISE on .parent() call"); 282 } catch (IllegalStateException expected) { 283 } 284 } 285 286 public void testChild() { 287 InternetDomainName domain = InternetDomainName.from("foo.com"); 288 289 assertEquals("www.foo.com", domain.child("www").toString()); 290 291 try { 292 domain.child("www."); 293 fail("www..google.com should have been invalid"); 294 } catch (IllegalArgumentException expected) { 295 // Expected outcome 296 } 297 } 298 299 public void testParentChild() { 300 InternetDomainName origin = InternetDomainName.from("foo.com"); 301 InternetDomainName parent = origin.parent(); 302 assertEquals("com", parent.toString()); 303 304 // These would throw an exception if leniency were not preserved during parent() and child() 305 // calls. 306 InternetDomainName child = parent.child(LOTS_OF_DELTAS); 307 child.child(LOTS_OF_DELTAS); 308 } 309 310 public void testValidTopPrivateDomain() { 311 InternetDomainName googleDomain = InternetDomainName.from("google.com"); 312 313 assertEquals(googleDomain, googleDomain.topPrivateDomain()); 314 assertEquals(googleDomain, googleDomain.child("mail").topPrivateDomain()); 315 assertEquals(googleDomain, googleDomain.child("foo.bar").topPrivateDomain()); 316 } 317 318 public void testInvalidTopPrivateDomain() { 319 ImmutableSet<String> badCookieDomains = 320 ImmutableSet.of("co.uk", "foo", "com"); 321 322 for (String domain : badCookieDomains) { 323 try { 324 InternetDomainName.from(domain).topPrivateDomain(); 325 fail(domain); 326 } catch (IllegalStateException expected) { 327 } 328 } 329 } 330 331 public void testIsValid() { 332 final Iterable<String> validCases = Iterables.concat( 333 VALID_NAME, PS, NO_PS, NON_PS); 334 final Iterable<String> invalidCases = Iterables.concat( 335 INVALID_NAME, VALID_IP_ADDRS, INVALID_IP_ADDRS); 336 337 for (String valid : validCases) { 338 assertTrue(valid, InternetDomainName.isValid(valid)); 339 } 340 341 for (String invalid : invalidCases) { 342 assertFalse(invalid, InternetDomainName.isValid(invalid)); 343 } 344 } 345 346 public void testToString() { 347 for (String inputName : SOMEWHERE_UNDER_PS) { 348 InternetDomainName domain = InternetDomainName.from(inputName); 349 350 /* 351 * We would ordinarily use constants for the expected results, but 352 * doing it by derivation allows us to reuse the test case definitions 353 * used in other tests. 354 */ 355 356 String expectedName = Ascii.toLowerCase(inputName); 357 expectedName = expectedName.replaceAll("[\u3002\uFF0E\uFF61]", "."); 358 359 if (expectedName.endsWith(".")) { 360 expectedName = expectedName.substring(0, expectedName.length() - 1); 361 } 362 363 assertEquals(expectedName, domain.toString()); 364 } 365 } 366 367 public void testExclusion() { 368 InternetDomainName domain = InternetDomainName.from("foo.teledata.mz"); 369 assertTrue(domain.hasPublicSuffix()); 370 assertEquals("mz", domain.publicSuffix().toString()); 371 372 // Behold the weirdness! 373 assertFalse(domain.publicSuffix().isPublicSuffix()); 374 } 375 376 public void testMultipleUnders() { 377 // PSL has both *.uk and *.sch.uk; the latter should win. 378 // See http://code.google.com/p/guava-libraries/issues/detail?id=1176 379 380 InternetDomainName domain = InternetDomainName.from("www.essex.sch.uk"); 381 assertTrue(domain.hasPublicSuffix()); 382 assertEquals("essex.sch.uk", domain.publicSuffix().toString()); 383 assertEquals("www.essex.sch.uk", domain.topPrivateDomain().toString()); 384 } 385 386 public void testEquality() { 387 new EqualsTester() 388 .addEqualityGroup( 389 idn("google.com"), idn("google.com"), idn("GOOGLE.COM")) 390 .addEqualityGroup(idn("www.google.com")) 391 .addEqualityGroup(UNICODE_EXAMPLE) 392 .addEqualityGroup(PUNYCODE_EXAMPLE) 393 .testEquals(); 394 } 395 396 private static InternetDomainName idn(String domain) { 397 return InternetDomainName.from(domain); 398 } 399} 400