• 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 
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