1781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller/*
2781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller * Copyright (C) 2015 Square, Inc.
3781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller *
4781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller * Licensed under the Apache License, Version 2.0 (the "License");
5781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller * you may not use this file except in compliance with the License.
6781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller * You may obtain a copy of the License at
7781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller *
8781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller *      http://www.apache.org/licenses/LICENSE-2.0
9781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller *
10781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller * Unless required by applicable law or agreed to in writing, software
11781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller * distributed under the License is distributed on an "AS IS" BASIS,
12781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller * See the License for the specific language governing permissions and
14781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller * limitations under the License.
15781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller */
16781c9c216deed11c44044d23841a4ba6a012106eNeil Fullerpackage com.squareup.okhttp;
17781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller
18781c9c216deed11c44044d23841a4ba6a012106eNeil Fullerimport com.squareup.okhttp.WebPlatformTestRun.SubtestResult;
19781c9c216deed11c44044d23841a4ba6a012106eNeil Fullerimport com.squareup.okhttp.internal.Util;
20781c9c216deed11c44044d23841a4ba6a012106eNeil Fullerimport java.io.IOException;
21781c9c216deed11c44044d23841a4ba6a012106eNeil Fullerimport java.net.MalformedURLException;
22781c9c216deed11c44044d23841a4ba6a012106eNeil Fullerimport java.net.URL;
23781c9c216deed11c44044d23841a4ba6a012106eNeil Fullerimport java.util.ArrayList;
24781c9c216deed11c44044d23841a4ba6a012106eNeil Fullerimport java.util.List;
25781c9c216deed11c44044d23841a4ba6a012106eNeil Fullerimport okio.BufferedSource;
26781c9c216deed11c44044d23841a4ba6a012106eNeil Fullerimport okio.Okio;
27781c9c216deed11c44044d23841a4ba6a012106eNeil Fullerimport org.junit.Ignore;
28781c9c216deed11c44044d23841a4ba6a012106eNeil Fullerimport org.junit.Test;
29781c9c216deed11c44044d23841a4ba6a012106eNeil Fullerimport org.junit.runner.RunWith;
30781c9c216deed11c44044d23841a4ba6a012106eNeil Fullerimport org.junit.runners.Parameterized;
31781c9c216deed11c44044d23841a4ba6a012106eNeil Fullerimport org.junit.runners.Parameterized.Parameter;
32781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller
33781c9c216deed11c44044d23841a4ba6a012106eNeil Fullerimport static org.junit.Assert.assertEquals;
34781c9c216deed11c44044d23841a4ba6a012106eNeil Fullerimport static org.junit.Assert.assertNotNull;
35781c9c216deed11c44044d23841a4ba6a012106eNeil Fullerimport static org.junit.Assert.assertNull;
36781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller
37781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller/** Runs the web platform URL tests against Java URL models. */
38781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller@RunWith(Parameterized.class)
39781c9c216deed11c44044d23841a4ba6a012106eNeil Fullerpublic final class WebPlatformUrlTest {
40781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller  @Parameterized.Parameters(name = "{0}")
41781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller  public static List<Object[]> parameters() {
42781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller    try {
43781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller      List<WebPlatformUrlTestData> tests = loadTests();
44781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller
45781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller      // The web platform tests are run in both HTML and XHTML variants. Major browsers pass more
46781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller      // tests in HTML mode, so that's what we'll attempt to match.
47781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller      String testName = "/url/a-element.html";
48781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller      WebPlatformTestRun firefoxTestRun
49781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller          = loadTestRun("/web-platform-test-results-url-firefox-37.0.json");
50781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller      WebPlatformTestRun chromeTestRun
51781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller          = loadTestRun("/web-platform-test-results-url-chrome-42.0.json");
52781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller      WebPlatformTestRun safariTestRun
53781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller          = loadTestRun("/web-platform-test-results-url-safari-7.1.json");
54781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller
55781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller      List<Object[]> result = new ArrayList<>();
56781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller      for (WebPlatformUrlTestData urlTestData : tests) {
57781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller        String subtestName = urlTestData.toString();
58781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller        SubtestResult firefoxResult = firefoxTestRun.get(testName, subtestName);
59781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller        SubtestResult chromeResult = chromeTestRun.get(testName, subtestName);
60781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller        SubtestResult safariResult = safariTestRun.get(testName, subtestName);
61781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller        result.add(new Object[] { urlTestData, firefoxResult, chromeResult, safariResult });
62781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller      }
63781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller      return result;
64781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller    } catch (IOException e) {
65781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller      throw new AssertionError();
66781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller    }
67781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller  }
68781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller
69781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller  @Parameter(0)
70781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller  public WebPlatformUrlTestData testData;
71781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller
72781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller  @Parameter(1)
73781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller  public SubtestResult firefoxResult;
74781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller
75781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller  @Parameter(2)
76781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller  public SubtestResult chromeResultResult;
77781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller
78781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller  @Parameter(3)
79781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller  public SubtestResult safariResult;
80781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller
81781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller  private static final List<String> JAVA_NET_URL_SCHEMES
82781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller      = Util.immutableList("file", "ftp", "http", "https", "mailto");
83781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller  private static final List<String> HTTP_URL_SCHEMES
84781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller      = Util.immutableList("http", "https");
85781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller
86781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller  /** Test how {@link URL} does against the web platform test suite. */
87781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller  @Ignore // java.net.URL is broken. Not much we can do about that.
88781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller  @Test public void javaNetUrl() throws Exception {
89781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller    if (!testData.scheme.isEmpty() && !JAVA_NET_URL_SCHEMES.contains(testData.scheme)) {
90781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller      System.out.println("Ignoring unsupported scheme " + testData.scheme);
91781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller      return;
92781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller    }
93781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller
94781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller    try {
95781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller      testJavaNetUrl();
96781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller    } catch (AssertionError e) {
97781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller      if (tolerateFailure()) {
98781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller        System.out.println("Tolerable failure: " + e.getMessage());
99781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller        return;
100781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller      }
101781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller      throw e;
102781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller    }
103781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller  }
104781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller
105781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller  private void testJavaNetUrl() {
106781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller    URL url = null;
107781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller    String failureMessage = "";
108781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller    try {
109781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller      if (testData.base.equals("about:blank")) {
110781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller        url = new URL(testData.input);
111781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller      } else {
112781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller        URL baseUrl = new URL(testData.base);
113781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller        url = new URL(baseUrl, testData.input);
114781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller      }
115781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller    } catch (MalformedURLException e) {
116781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller      failureMessage = e.getMessage();
117781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller    }
118781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller
119781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller    if (testData.expectParseFailure()) {
120781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller      assertNull("Expected URL to fail parsing", url);
121781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller    } else {
122781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller      assertNotNull("Expected URL to parse successfully, but was " + failureMessage, url);
123781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller      String effectivePort = url.getPort() != -1 ? Integer.toString(url.getPort()) : "";
124781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller      String effectiveQuery = url.getQuery() != null ? "?" + url.getQuery() : "";
125781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller      String effectiveFragment = url.getRef() != null ? "#" + url.getRef() : "";
126781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller      assertEquals("scheme", testData.scheme, url.getProtocol());
127781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller      assertEquals("host", testData.host, url.getHost());
128781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller      assertEquals("port", testData.port, effectivePort);
129781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller      assertEquals("path", testData.path, url.getPath());
130781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller      assertEquals("query", testData.query, effectiveQuery);
131781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller      assertEquals("fragment", testData.fragment, effectiveFragment);
132781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller    }
133781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller  }
134781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller
135781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller  /** Test how {@link HttpUrl} does against the web platform test suite. */
136781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller  @Ignore // TODO(jwilson): implement character encoding.
137781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller  @Test public void httpUrl() throws Exception {
138781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller    if (!testData.scheme.isEmpty() && !HTTP_URL_SCHEMES.contains(testData.scheme)) {
139781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller      System.out.println("Ignoring unsupported scheme " + testData.scheme);
140781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller      return;
141781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller    }
142781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller    if (!testData.base.startsWith("https:") && !testData.base.startsWith("http:")) {
143781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller      System.out.println("Ignoring unsupported base " + testData.base);
144781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller      return;
145781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller    }
146781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller
147781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller    try {
148781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller      testHttpUrl();
149781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller    } catch (AssertionError e) {
150781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller      if (tolerateFailure()) {
151781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller        System.out.println("Tolerable failure: " + e.getMessage());
152781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller        return;
153781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller      }
154781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller      throw e;
155781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller    }
156781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller  }
157781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller
158781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller  private void testHttpUrl() {
159781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller    HttpUrl url;
160781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller    if (testData.base.equals("about:blank")) {
161781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller      url = HttpUrl.parse(testData.input);
162781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller    } else {
163781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller      HttpUrl baseUrl = HttpUrl.parse(testData.base);
164781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller      url = baseUrl.resolve(testData.input);
165781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller    }
166781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller
167781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller    if (testData.expectParseFailure()) {
168781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller      assertNull("Expected URL to fail parsing", url);
169781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller    } else {
170781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller      assertNotNull("Expected URL to parse successfully, but was null", url);
171781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller      String effectivePort = url.port() != HttpUrl.defaultPort(url.scheme())
172781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller          ? Integer.toString(url.port())
173781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller          : "";
174781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller      String effectiveQuery = url.query() != null ? "?" + url.query() : "";
175781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller      String effectiveFragment = url.fragment() != null ? "#" + url.fragment() : "";
176781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller      assertEquals("scheme", testData.scheme, url.scheme());
177781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller      assertEquals("host", testData.host, url.host());
178781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller      assertEquals("port", testData.port, effectivePort);
179781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller      assertEquals("path", testData.path, url.path());
180781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller      assertEquals("query", testData.query, effectiveQuery);
181781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller      assertEquals("fragment", testData.fragment, effectiveFragment);
182781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller    }
183781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller  }
184781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller
185781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller  /**
186781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller   * Returns true if several major browsers also fail this test, in which case the test itself is
187781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller   * questionable.
188781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller   */
189781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller  private boolean tolerateFailure() {
190781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller    return !firefoxResult.isPass()
191781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller        && !chromeResultResult.isPass()
192781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller        && !safariResult.isPass();
193781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller  }
194781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller
195781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller  private static List<WebPlatformUrlTestData> loadTests() throws IOException {
196781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller    BufferedSource source = Okio.buffer(Okio.source(
197781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller        WebPlatformUrlTest.class.getResourceAsStream("/web-platform-test-urltestdata.txt")));
198781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller    return WebPlatformUrlTestData.load(source);
199781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller  }
200781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller
201781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller  private static WebPlatformTestRun loadTestRun(String name) throws IOException {
202781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller    return WebPlatformTestRun.load(WebPlatformUrlTest.class.getResourceAsStream(name));
203781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller  }
204781c9c216deed11c44044d23841a4ba6a012106eNeil Fuller}
205