/**
   * Returns a {@code HostSpecifier} built from the provided {@code specifier}, which is already
   * known to be valid. If the {@code specifier} might be invalid, use {@link #from(String)}
   * instead.
   *
   * <p>The specifier must be in one of these formats:
   *
   * <ul>
   *   <li>A domain name, like {@code google.com}
   *   <li>A IPv4 address string, like {@code 127.0.0.1}
   *   <li>An IPv6 address string with or without brackets, like {@code [2001:db8::1]} or {@code
   *       2001:db8::1}
   * </ul>
   *
   * @throws IllegalArgumentException if the specifier is not valid.
   */
  public static HostSpecifier fromValid(String specifier) {
    // Verify that no port was specified, and strip optional brackets from
    // IPv6 literals.
    final HostAndPort parsedHost = HostAndPort.fromString(specifier);
    Preconditions.checkArgument(!parsedHost.hasPort());
    final String host = parsedHost.getHostText();

    // Try to interpret the specifier as an IP address.  Note we build
    // the address rather than using the .is* methods because we want to
    // use InetAddresses.toUriString to convert the result to a string in
    // canonical form.
    InetAddress addr = null;
    try {
      addr = InetAddresses.forString(host);
    } catch (IllegalArgumentException e) {
      // It is not an IPv4 or IPv6 literal
    }

    if (addr != null) {
      return new HostSpecifier(InetAddresses.toUriString(addr));
    }

    // It is not any kind of IP address; must be a domain name or invalid.

    // TODO(user): different versions of this for different factories?
    final InternetDomainName domain = InternetDomainName.from(host);

    if (domain.hasPublicSuffix()) {
      return new HostSpecifier(domain.name());
    }

    throw new IllegalArgumentException(
        "Domain name does not have a recognized public suffix: " + host);
  }
  public void testValidTopPrivateDomain() {
    InternetDomainName googleDomain = InternetDomainName.from("google.com");

    assertEquals(googleDomain, googleDomain.topPrivateDomain());
    assertEquals(googleDomain, googleDomain.child("mail").topPrivateDomain());
    assertEquals(googleDomain, googleDomain.child("foo.bar").topPrivateDomain());
  }
 public void testUnderPublicSuffix() {
   for (String name : SOMEWHERE_UNDER_PS) {
     final InternetDomainName domain = InternetDomainName.from(name);
     assertFalse(name, domain.isPublicSuffix());
     assertTrue(name, domain.hasPublicSuffix());
     assertTrue(name, domain.isUnderPublicSuffix());
   }
 }
  public void testExclusion() {
    InternetDomainName domain = InternetDomainName.from("foo.nic.uk");
    assertTrue(domain.hasPublicSuffix());
    assertEquals("uk", domain.publicSuffix().toString());

    // Behold the weirdness!
    assertFalse(domain.publicSuffix().isPublicSuffix());
  }
  public void testMultipleUnders() {
    // PSL has both *.uk and *.sch.uk; the latter should win.
    // See http://code.google.com/p/guava-libraries/issues/detail?id=1176

    InternetDomainName domain = InternetDomainName.from("www.essex.sch.uk");
    assertTrue(domain.hasPublicSuffix());
    assertEquals("essex.sch.uk", domain.publicSuffix().toString());
    assertEquals("www.essex.sch.uk", domain.topPrivateDomain().toString());
  }
  public void testParent() {
    assertEquals("com", InternetDomainName.from("google.com").parent().toString());
    assertEquals("uk", InternetDomainName.from("co.uk").parent().toString());
    assertEquals("google.com", InternetDomainName.from("www.google.com").parent().toString());

    try {
      InternetDomainName.from("com").parent();
      fail("'com' should throw ISE on .parent() call");
    } catch (IllegalStateException expected) {
    }
  }
  public void testChild() {
    InternetDomainName domain = InternetDomainName.from("foo.com");

    assertEquals("www.foo.com", domain.child("www").toString());

    try {
      domain.child("www.");
      fail("www..google.com should have been invalid");
    } catch (IllegalArgumentException expected) {
      // Expected outcome
    }
  }
  public void testIsValid() {
    final Iterable<String> validCases = Iterables.concat(VALID_NAME, PS, NO_PS, NON_PS);
    final Iterable<String> invalidCases =
        Iterables.concat(INVALID_NAME, VALID_IP_ADDRS, INVALID_IP_ADDRS);

    for (String valid : validCases) {
      assertTrue(valid, InternetDomainName.isValid(valid));
    }

    for (String invalid : invalidCases) {
      assertFalse(invalid, InternetDomainName.isValid(invalid));
    }
  }
  @GwtIncompatible("NullPointerTester")
  public void testNulls() {
    final NullPointerTester tester = new NullPointerTester();

    tester.testAllPublicStaticMethods(InternetDomainName.class);
    tester.testAllPublicInstanceMethods(InternetDomainName.from("google.com"));
  }
  public void testParentChild() {
    InternetDomainName origin = InternetDomainName.from("foo.com");
    InternetDomainName parent = origin.parent();
    assertEquals("com", parent.toString());

    // These would throw an exception if leniency were not preserved during parent() and child()
    // calls.
    InternetDomainName child = parent.child(LOTS_OF_DELTAS);
    child.child(LOTS_OF_DELTAS);
  }
 public void testTopPrivateDomain() {
   for (String name : TOP_PRIVATE_DOMAIN) {
     final InternetDomainName domain = InternetDomainName.from(name);
     assertFalse(name, domain.isPublicSuffix());
     assertTrue(name, domain.hasPublicSuffix());
     assertTrue(name, domain.isUnderPublicSuffix());
     assertTrue(name, domain.isTopPrivateDomain());
     assertEquals(domain.parent(), domain.publicSuffix());
   }
 }
 public void testInvalid() {
   for (String name : INVALID_NAME) {
     try {
       InternetDomainName.from(name);
       fail("Should have been invalid: '" + name + "'");
     } catch (IllegalArgumentException expected) {
       // Expected case
     }
   }
 }
  public void testToString() {
    for (String inputName : SOMEWHERE_UNDER_PS) {
      InternetDomainName domain = InternetDomainName.from(inputName);

      /*
       * We would ordinarily use constants for the expected results, but
       * doing it by derivation allows us to reuse the test case definitions
       * used in other tests.
       */

      String expectedName = Ascii.toLowerCase(inputName);
      expectedName = expectedName.replaceAll("[\u3002\uFF0E\uFF61]", ".");

      if (expectedName.endsWith(".")) {
        expectedName = expectedName.substring(0, expectedName.length() - 1);
      }

      assertEquals(expectedName, domain.toString());
    }
  }
  public void testInvalidTopPrivateDomain() {
    ImmutableSet<String> badCookieDomains = ImmutableSet.of("co.uk", "foo", "com");

    for (String domain : badCookieDomains) {
      try {
        InternetDomainName.from(domain).topPrivateDomain();
        fail(domain);
      } catch (IllegalStateException expected) {
      }
    }
  }
 public void testValid() {
   for (String name : VALID_NAME) {
     InternetDomainName.from(name);
   }
 }
 private static InternetDomainName idn(String domain) {
   return InternetDomainName.from(domain);
 }
  public void testPublicSuffix() {
    for (String name : PS) {
      final InternetDomainName domain = InternetDomainName.from(name);
      assertTrue(name, domain.isPublicSuffix());
      assertTrue(name, domain.hasPublicSuffix());
      assertFalse(name, domain.isUnderPublicSuffix());
      assertFalse(name, domain.isTopPrivateDomain());
      assertEquals(domain, domain.publicSuffix());
    }

    for (String name : NO_PS) {
      final InternetDomainName domain = InternetDomainName.from(name);
      assertFalse(name, domain.isPublicSuffix());
      assertFalse(name, domain.hasPublicSuffix());
      assertFalse(name, domain.isUnderPublicSuffix());
      assertFalse(name, domain.isTopPrivateDomain());
      assertNull(domain.publicSuffix());
    }

    for (String name : NON_PS) {
      final InternetDomainName domain = InternetDomainName.from(name);
      assertFalse(name, domain.isPublicSuffix());
      assertTrue(name, domain.hasPublicSuffix());
      assertTrue(name, domain.isUnderPublicSuffix());
    }
  }
/**
 * {@link TestCase} for {@link InternetDomainName}.
 *
 * @author Craig Berry
 */
@GwtCompatible(emulated = true)
public final class InternetDomainNameTest extends TestCase {
  private static final InternetDomainName UNICODE_EXAMPLE =
      InternetDomainName.from("j\u00f8rpeland.no");
  private static final InternetDomainName PUNYCODE_EXAMPLE =
      InternetDomainName.from("xn--jrpeland-54a.no");

  /** The Greek letter delta, used in unicode testing. */
  private static final String DELTA = "\u0394";

  /** A domain part which is valid under lenient validation, but invalid under strict validation. */
  static final String LOTS_OF_DELTAS = Strings.repeat(DELTA, 62);

  private static final String ALMOST_TOO_MANY_LEVELS = Strings.repeat("a.", 127);

  private static final String ALMOST_TOO_LONG = Strings.repeat("aaaaa.", 40) + "1234567890.c";

  private static final ImmutableSet<String> VALID_NAME =
      ImmutableSet.of(
          "foo.com",
          "f-_-o.cOM",
          "f--1.com",
          "f11-1.com",
          "www",
          "abc.a23",
          "biz.com.ua",
          "x",
          "fOo",
          "f--o",
          "f_a",
          "foo.net.us\uFF61ocm",
          "woo.com.",
          "a" + DELTA + "b.com",
          ALMOST_TOO_MANY_LEVELS,
          ALMOST_TOO_LONG);

  private static final ImmutableSet<String> INVALID_NAME =
      ImmutableSet.of(
          "",
          " ",
          "127.0.0.1",
          "::1",
          "13",
          "abc.12c",
          "foo-.com",
          "_bar.quux",
          "foo+bar.com",
          "foo!bar.com",
          ".foo.com",
          "..bar.com",
          "baz..com",
          "..quiffle.com",
          "fleeb.com..",
          ".",
          "..",
          "...",
          "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.com",
          "a" + DELTA + " .com",
          ALMOST_TOO_MANY_LEVELS + "com",
          ALMOST_TOO_LONG + ".c");

  private static final ImmutableSet<String> PS =
      ImmutableSet.of(
          "com",
          "co.uk",
          "foo.bd",
          "xxxxxx.bd",
          "org.mK",
          "us",
          "uk\uFF61com.", // Alternate dot character
          "\u7f51\u7edc.Cn", // "网络.Cn"
          "j\u00f8rpeland.no", // "jorpeland.no" (first o slashed)
          "xn--jrpeland-54a.no" // IDNA (punycode) encoding of above
          );

  private static final ImmutableSet<String> NO_PS = ImmutableSet.of("www", "foo.google", "x.y.z");

  private static final ImmutableSet<String> NON_PS =
      ImmutableSet.of(
          "foo.bar.com",
          "foo.ca",
          "foo.bar.ca",
          "foo.bar.co.il",
          "state.CA.us",
          "www.state.pa.us",
          "pvt.k12.ca.us",
          "www.google.com",
          "www4.yahoo.co.uk",
          "home.netscape.com",
          "web.MIT.edu",
          "foo.eDu.au",
          "utenti.blah.IT",
          "dominio.com.co");

  private static final ImmutableSet<String> TOP_PRIVATE_DOMAIN =
      ImmutableSet.of("google.com", "foo.Co.uk", "foo.ca.us.");

  private static final ImmutableSet<String> UNDER_PRIVATE_DOMAIN =
      ImmutableSet.of("foo.bar.google.com", "a.b.co.uk", "x.y.ca.us");

  private static final ImmutableSet<String> VALID_IP_ADDRS =
      ImmutableSet.of("1.2.3.4", "127.0.0.1", "::1", "2001:db8::1");

  private static final ImmutableSet<String> INVALID_IP_ADDRS =
      ImmutableSet.of(
          "", "1", "1.2.3", "...", "1.2.3.4.5", "400.500.600.700", ":", ":::1", "2001:db8:");

  private static final ImmutableSet<String> SOMEWHERE_UNDER_PS =
      ImmutableSet.of(
          "foo.bar.google.com",
          "a.b.c.1.2.3.ca.us",
          "site.jp",
          "uomi-online.kir.jp",
          "jprs.co.jp",
          "site.quick.jp",
          "site.tenki.jp",
          "site.or.jp",
          "site.gr.jp",
          "site.ne.jp",
          "site.ac.jp",
          "site.ad.jp",
          "site.ed.jp",
          "site.geo.jp",
          "site.go.jp",
          "site.lg.jp",
          "1.fm",
          "site.cc",
          "site.ee",
          "site.fi",
          "site.fm",
          "site.gr",
          "www.leguide.ma",
          "site.ma",
          "some.org.mk",
          "site.mk",
          "site.tv",
          "site.us",
          "www.odev.us",
          "www.GOOGLE.com",
          "www.com",
          "google.com",
          "www7.google.co.uk",
          "google.Co.uK",
          "jobs.kt.com.",
          "home.netscape.com",
          "web.stanford.edu",
          "stanford.edu",
          "state.ca.us",
          "www.state.ca.us",
          "state.ca.us",
          "pvt.k12.ca.us",
          "www.rave.ca.",
          "cnn.ca",
          "ledger-enquirer.com",
          "it-trace.ch",
          "cool.dk",
          "cool.co.uk",
          "cool.de",
          "cool.es",
          "cool\uFF61fr", // Alternate dot character
          "cool.nl",
          "members.blah.nl.",
          "cool.se",
          "utenti.blah.it",
          "kt.co",
          "a\u7f51\u7edcA.\u7f51\u7edc.Cn" // "a网络A.网络.Cn"
          );

  public void testValid() {
    for (String name : VALID_NAME) {
      InternetDomainName.from(name);
    }
  }

  public void testInvalid() {
    for (String name : INVALID_NAME) {
      try {
        InternetDomainName.from(name);
        fail("Should have been invalid: '" + name + "'");
      } catch (IllegalArgumentException expected) {
        // Expected case
      }
    }
  }

  public void testPublicSuffix() {
    for (String name : PS) {
      final InternetDomainName domain = InternetDomainName.from(name);
      assertTrue(name, domain.isPublicSuffix());
      assertTrue(name, domain.hasPublicSuffix());
      assertFalse(name, domain.isUnderPublicSuffix());
      assertFalse(name, domain.isTopPrivateDomain());
      assertEquals(domain, domain.publicSuffix());
    }

    for (String name : NO_PS) {
      final InternetDomainName domain = InternetDomainName.from(name);
      assertFalse(name, domain.isPublicSuffix());
      assertFalse(name, domain.hasPublicSuffix());
      assertFalse(name, domain.isUnderPublicSuffix());
      assertFalse(name, domain.isTopPrivateDomain());
      assertNull(domain.publicSuffix());
    }

    for (String name : NON_PS) {
      final InternetDomainName domain = InternetDomainName.from(name);
      assertFalse(name, domain.isPublicSuffix());
      assertTrue(name, domain.hasPublicSuffix());
      assertTrue(name, domain.isUnderPublicSuffix());
    }
  }

  public void testUnderPublicSuffix() {
    for (String name : SOMEWHERE_UNDER_PS) {
      final InternetDomainName domain = InternetDomainName.from(name);
      assertFalse(name, domain.isPublicSuffix());
      assertTrue(name, domain.hasPublicSuffix());
      assertTrue(name, domain.isUnderPublicSuffix());
    }
  }

  public void testTopPrivateDomain() {
    for (String name : TOP_PRIVATE_DOMAIN) {
      final InternetDomainName domain = InternetDomainName.from(name);
      assertFalse(name, domain.isPublicSuffix());
      assertTrue(name, domain.hasPublicSuffix());
      assertTrue(name, domain.isUnderPublicSuffix());
      assertTrue(name, domain.isTopPrivateDomain());
      assertEquals(domain.parent(), domain.publicSuffix());
    }
  }

  public void testUnderPrivateDomain() {
    for (String name : UNDER_PRIVATE_DOMAIN) {
      final InternetDomainName domain = InternetDomainName.from(name);
      assertFalse(name, domain.isPublicSuffix());
      assertTrue(name, domain.hasPublicSuffix());
      assertTrue(name, domain.isUnderPublicSuffix());
      assertFalse(name, domain.isTopPrivateDomain());
    }
  }

  public void testParent() {
    assertEquals("com", InternetDomainName.from("google.com").parent().toString());
    assertEquals("uk", InternetDomainName.from("co.uk").parent().toString());
    assertEquals("google.com", InternetDomainName.from("www.google.com").parent().toString());

    try {
      InternetDomainName.from("com").parent();
      fail("'com' should throw ISE on .parent() call");
    } catch (IllegalStateException expected) {
    }
  }

  public void testChild() {
    InternetDomainName domain = InternetDomainName.from("foo.com");

    assertEquals("www.foo.com", domain.child("www").toString());

    try {
      domain.child("www.");
      fail("www..google.com should have been invalid");
    } catch (IllegalArgumentException expected) {
      // Expected outcome
    }
  }

  public void testParentChild() {
    InternetDomainName origin = InternetDomainName.from("foo.com");
    InternetDomainName parent = origin.parent();
    assertEquals("com", parent.toString());

    // These would throw an exception if leniency were not preserved during parent() and child()
    // calls.
    InternetDomainName child = parent.child(LOTS_OF_DELTAS);
    child.child(LOTS_OF_DELTAS);
  }

  public void testValidTopPrivateDomain() {
    InternetDomainName googleDomain = InternetDomainName.from("google.com");

    assertEquals(googleDomain, googleDomain.topPrivateDomain());
    assertEquals(googleDomain, googleDomain.child("mail").topPrivateDomain());
    assertEquals(googleDomain, googleDomain.child("foo.bar").topPrivateDomain());
  }

  public void testInvalidTopPrivateDomain() {
    ImmutableSet<String> badCookieDomains = ImmutableSet.of("co.uk", "foo", "com");

    for (String domain : badCookieDomains) {
      try {
        InternetDomainName.from(domain).topPrivateDomain();
        fail(domain);
      } catch (IllegalStateException expected) {
      }
    }
  }

  public void testIsValid() {
    final Iterable<String> validCases = Iterables.concat(VALID_NAME, PS, NO_PS, NON_PS);
    final Iterable<String> invalidCases =
        Iterables.concat(INVALID_NAME, VALID_IP_ADDRS, INVALID_IP_ADDRS);

    for (String valid : validCases) {
      assertTrue(valid, InternetDomainName.isValid(valid));
    }

    for (String invalid : invalidCases) {
      assertFalse(invalid, InternetDomainName.isValid(invalid));
    }
  }

  public void testToString() {
    for (String inputName : SOMEWHERE_UNDER_PS) {
      InternetDomainName domain = InternetDomainName.from(inputName);

      /*
       * We would ordinarily use constants for the expected results, but
       * doing it by derivation allows us to reuse the test case definitions
       * used in other tests.
       */

      String expectedName = Ascii.toLowerCase(inputName);
      expectedName = expectedName.replaceAll("[\u3002\uFF0E\uFF61]", ".");

      if (expectedName.endsWith(".")) {
        expectedName = expectedName.substring(0, expectedName.length() - 1);
      }

      assertEquals(expectedName, domain.toString());
    }
  }

  public void testExclusion() {
    InternetDomainName domain = InternetDomainName.from("foo.nic.uk");
    assertTrue(domain.hasPublicSuffix());
    assertEquals("uk", domain.publicSuffix().toString());

    // Behold the weirdness!
    assertFalse(domain.publicSuffix().isPublicSuffix());
  }

  public void testMultipleUnders() {
    // PSL has both *.uk and *.sch.uk; the latter should win.
    // See http://code.google.com/p/guava-libraries/issues/detail?id=1176

    InternetDomainName domain = InternetDomainName.from("www.essex.sch.uk");
    assertTrue(domain.hasPublicSuffix());
    assertEquals("essex.sch.uk", domain.publicSuffix().toString());
    assertEquals("www.essex.sch.uk", domain.topPrivateDomain().toString());
  }

  public void testEquality() {
    new EqualsTester()
        .addEqualityGroup(idn("google.com"), idn("google.com"), idn("GOOGLE.COM"))
        .addEqualityGroup(idn("www.google.com"))
        .addEqualityGroup(UNICODE_EXAMPLE)
        .addEqualityGroup(PUNYCODE_EXAMPLE)
        .testEquals();
  }

  private static InternetDomainName idn(String domain) {
    return InternetDomainName.from(domain);
  }

  @GwtIncompatible("NullPointerTester")
  public void testNulls() {
    final NullPointerTester tester = new NullPointerTester();

    tester.testAllPublicStaticMethods(InternetDomainName.class);
    tester.testAllPublicInstanceMethods(InternetDomainName.from("google.com"));
  }
}