1/*
2 * Copyright (C) 2011 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.testing.SerializableTester;
21
22import junit.framework.TestCase;
23
24/**
25 * Tests for {@link HostAndPort}
26 *
27 * @author Paul Marks
28 */
29@GwtCompatible
30public class HostAndPortTest extends TestCase {
31
32  public void testFromStringWellFormed() {
33    // Well-formed inputs.
34    checkFromStringCase("google.com",           80, "google.com", 80, false);
35    checkFromStringCase("google.com",           80, "google.com", 80, false);
36    checkFromStringCase("192.0.2.1",            82, "192.0.2.1",  82, false);
37    checkFromStringCase("[2001::1]",            84, "2001::1",    84, false);
38    checkFromStringCase("2001::3",              86, "2001::3",    86, false);
39    checkFromStringCase("host:",                80, "host",       80, false);
40  }
41
42  public void testFromStringBadDefaultPort() {
43    // Well-formed strings with bad default ports.
44    checkFromStringCase("gmail.com:81",         -1, "gmail.com",  81, true);
45    checkFromStringCase("192.0.2.2:83",         -1, "192.0.2.2",  83, true);
46    checkFromStringCase("[2001::2]:85",         -1, "2001::2",    85, true);
47    checkFromStringCase("goo.gl:65535",      65536, "goo.gl",  65535, true);
48    // No port, bad default.
49    checkFromStringCase("google.com",           -1, "google.com", -1, false);
50    checkFromStringCase("192.0.2.1",         65536, "192.0.2.1",  -1, false);
51    checkFromStringCase("[2001::1]",            -1, "2001::1",    -1, false);
52    checkFromStringCase("2001::3",           65536, "2001::3",    -1, false);
53  }
54
55  public void testFromStringUnusedDefaultPort() {
56    // Default port, but unused.
57    checkFromStringCase("gmail.com:81",         77, "gmail.com",  81, true);
58    checkFromStringCase("192.0.2.2:83",         77, "192.0.2.2",  83, true);
59    checkFromStringCase("[2001::2]:85",         77, "2001::2",    85, true);
60  }
61
62  public void testFromStringBadPort() {
63    // Out-of-range ports.
64    checkFromStringCase("google.com:65536",      1, null,         99, false);
65    checkFromStringCase("google.com:9999999999", 1, null,         99, false);
66    // Invalid port parts.
67    checkFromStringCase("google.com:port",       1, null,         99, false);
68    checkFromStringCase("google.com:-25",        1, null,         99, false);
69    checkFromStringCase("google.com:+25",        1, null,         99, false);
70    checkFromStringCase("google.com:25  ",       1, null,         99, false);
71    checkFromStringCase("google.com:25\t",       1, null,         99, false);
72    checkFromStringCase("google.com:0x25 ",      1, null,         99, false);
73  }
74
75  public void testFromStringUnparseableNonsense() {
76    // Some nonsense that causes parse failures.
77    checkFromStringCase("[goo.gl]",              1, null,         99, false);
78    checkFromStringCase("[goo.gl]:80",           1, null,         99, false);
79    checkFromStringCase("[",                     1, null,         99, false);
80    checkFromStringCase("[]:",                   1, null,         99, false);
81    checkFromStringCase("[]:80",                 1, null,         99, false);
82    checkFromStringCase("[]bad",                 1, null,         99, false);
83  }
84
85  public void testFromStringParseableNonsense() {
86    // Examples of nonsense that gets through.
87    checkFromStringCase("[[:]]",                86, "[:]",        86, false);
88    checkFromStringCase("x:y:z",                87, "x:y:z",      87, false);
89    checkFromStringCase("",                     88, "",           88, false);
90    checkFromStringCase(":",                    99, "",           99, false);
91    checkFromStringCase(":123",                 -1, "",          123, true);
92    checkFromStringCase("\nOMG\t",              89, "\nOMG\t",    89, false);
93  }
94
95  private static void checkFromStringCase(
96      String hpString,
97      int defaultPort,
98      String expectHost,
99      int expectPort,
100      boolean expectHasExplicitPort) {
101    HostAndPort hp;
102    try {
103      hp = HostAndPort.fromString(hpString);
104    } catch (IllegalArgumentException e) {
105      // Make sure we expected this.
106      assertNull(expectHost);
107      return;
108    }
109    assertNotNull(expectHost);
110
111    // Apply withDefaultPort(), yielding hp2.
112    final boolean badDefaultPort = (defaultPort < 0 || defaultPort > 65535);
113    HostAndPort hp2 = null;
114    try {
115      hp2 = hp.withDefaultPort(defaultPort);
116      assertFalse(badDefaultPort);
117    } catch (IllegalArgumentException e) {
118      assertTrue(badDefaultPort);
119    }
120
121    // Check the pre-withDefaultPort() instance.
122    if (expectHasExplicitPort) {
123      assertTrue(hp.hasPort());
124      assertEquals(expectPort, hp.getPort());
125    } else {
126      assertFalse(hp.hasPort());
127      try {
128        hp.getPort();
129        fail("Expected IllegalStateException");
130      } catch (IllegalStateException expected) {
131      }
132    }
133    assertEquals(expectHost, hp.getHostText());
134
135    // Check the post-withDefaultPort() instance (if any).
136    if (!badDefaultPort) {
137      try {
138        int port = hp2.getPort();
139        assertTrue(expectPort != -1);
140        assertEquals(expectPort, port);
141      } catch (IllegalStateException e) {
142        // Make sure we expected this to fail.
143        assertEquals(-1, expectPort);
144      }
145      assertEquals(expectHost, hp2.getHostText());
146    }
147  }
148
149  public void testFromParts() {
150    HostAndPort hp = HostAndPort.fromParts("gmail.com", 81);
151    assertEquals("gmail.com", hp.getHostText());
152    assertTrue(hp.hasPort());
153    assertEquals(81, hp.getPort());
154
155    try {
156      HostAndPort.fromParts("gmail.com:80", 81);
157      fail("Expected IllegalArgumentException");
158    } catch (IllegalArgumentException expected) {
159    }
160
161    try {
162      HostAndPort.fromParts("gmail.com", -1);
163      fail("Expected IllegalArgumentException");
164    } catch (IllegalArgumentException expected) {
165    }
166  }
167
168  public void testFromHost() {
169    HostAndPort hp = HostAndPort.fromHost("gmail.com");
170    assertEquals("gmail.com", hp.getHostText());
171    assertFalse(hp.hasPort());
172
173    hp = HostAndPort.fromHost("[::1]");
174    assertEquals("::1", hp.getHostText());
175    assertFalse(hp.hasPort());
176
177    try {
178      HostAndPort.fromHost("gmail.com:80");
179      fail("Expected IllegalArgumentException");
180    } catch (IllegalArgumentException expected) {
181    }
182
183    try {
184      HostAndPort.fromHost("[gmail.com]");
185      fail("Expected IllegalArgumentException");
186    } catch (IllegalArgumentException expected) {
187    }
188  }
189
190  public void testGetPortOrDefault() {
191    assertEquals(80, HostAndPort.fromString("host:80").getPortOrDefault(123));
192    assertEquals(123, HostAndPort.fromString("host").getPortOrDefault(123));
193  }
194
195  public void testHashCodeAndEquals() {
196    HostAndPort hp1 = HostAndPort.fromString("foo::123");
197    HostAndPort hp2 = HostAndPort.fromString("foo::123");
198    HostAndPort hp3 = HostAndPort.fromString("[foo::123]");
199    HostAndPort hp4 = HostAndPort.fromParts("[foo::123]", 80);
200    HostAndPort hp5 = HostAndPort.fromString("[foo::123]:80");
201    assertEquals(hp1.hashCode(), hp1.hashCode());
202    assertEquals(hp1.hashCode(), hp2.hashCode());
203    assertFalse(hp1.hashCode() == hp3.hashCode());
204    assertFalse(hp3.hashCode() == hp4.hashCode());
205    assertEquals(hp4.hashCode(), hp5.hashCode());
206
207    assertTrue(hp1.equals(hp1));
208    assertTrue(hp1.equals(hp2));
209    assertFalse(hp1.equals(hp3));
210    assertFalse(hp3.equals(hp4));
211    assertTrue(hp4.equals(hp5));
212    assertFalse(hp1.equals(null));
213  }
214
215  public void testRequireBracketsForIPv6() {
216    // Bracketed IPv6 works fine.
217    assertEquals("::1", HostAndPort.fromString("[::1]").requireBracketsForIPv6().getHostText());
218    assertEquals("::1", HostAndPort.fromString("[::1]:80").requireBracketsForIPv6().getHostText());
219    // Non-bracketed non-IPv6 works fine.
220    assertEquals("x", HostAndPort.fromString("x").requireBracketsForIPv6().getHostText());
221    assertEquals("x", HostAndPort.fromString("x:80").requireBracketsForIPv6().getHostText());
222
223    // Non-bracketed IPv6 fails.
224    try {
225      HostAndPort.fromString("::1").requireBracketsForIPv6();
226      fail("Expected IllegalArgumentException");
227    } catch (IllegalArgumentException expected) {
228    }
229  }
230
231  public void testToString() {
232    // With ports.
233    assertEquals("foo:101", "" + HostAndPort.fromString("foo:101"));
234    assertEquals(":102", HostAndPort.fromString(":102").toString());
235    assertEquals("[1::2]:103", HostAndPort.fromParts("1::2", 103).toString());
236    assertEquals("[::1]:104", HostAndPort.fromString("[::1]:104").toString());
237
238    // Without ports.
239    assertEquals("foo", "" + HostAndPort.fromString("foo"));
240    assertEquals("", HostAndPort.fromString("").toString());
241    assertEquals("[1::2]", HostAndPort.fromString("1::2").toString());
242    assertEquals("[::1]", HostAndPort.fromString("[::1]").toString());
243
244    // Garbage in, garbage out.
245    assertEquals("[::]]:107", HostAndPort.fromParts("::]", 107).toString());
246    assertEquals("[[:]]:108", HostAndPort.fromString("[[:]]:108").toString());
247  }
248
249  public void testSerialization() {
250    SerializableTester.reserializeAndAssert(HostAndPort.fromParts("host", 80));
251    SerializableTester.reserializeAndAssert(HostAndPort.fromString("host"));
252    SerializableTester.reserializeAndAssert(HostAndPort.fromString("host:80"));
253    SerializableTester.reserializeAndAssert(HostAndPort.fromString("[::1]:104"));
254    SerializableTester.reserializeAndAssert(HostAndPort.fromParts("1::2", 103));
255  }
256}
257