View Javadoc
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.base.Ascii;
21  import com.google.common.base.Strings;
22  import com.google.common.collect.ImmutableSet;
23  import com.google.common.collect.Iterables;
24  import com.google.common.testing.EqualsTester;
25  
26  import junit.framework.TestCase;
27  
28  /**
29   * {@link TestCase} for {@link InternetDomainName}.
30   *
31   * @author Craig Berry
32   */
33  @GwtCompatible(emulated = true)
34  public 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 }