• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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