11cb0ef41Sopenharmony_cifunction urlString({ scheme = "https",
21cb0ef41Sopenharmony_ci                     username = "username",
31cb0ef41Sopenharmony_ci                     password = "password",
41cb0ef41Sopenharmony_ci                     host = "host",
51cb0ef41Sopenharmony_ci                     port = "8000",
61cb0ef41Sopenharmony_ci                     pathname = "path",
71cb0ef41Sopenharmony_ci                     search = "query",
81cb0ef41Sopenharmony_ci                     hash = "fragment" }) {
91cb0ef41Sopenharmony_ci  return `${scheme}://${username}:${password}@${host}:${port}/${pathname}?${search}#${hash}`;
101cb0ef41Sopenharmony_ci}
111cb0ef41Sopenharmony_ci
121cb0ef41Sopenharmony_cifunction urlRecord(scheme) {
131cb0ef41Sopenharmony_ci  return new URL(urlString({ scheme }));
141cb0ef41Sopenharmony_ci}
151cb0ef41Sopenharmony_ci
161cb0ef41Sopenharmony_cifor(const scheme of ["https", "wpt++"]) {
171cb0ef41Sopenharmony_ci  for(let i = 0; i < 0x20; i++) {
181cb0ef41Sopenharmony_ci    const stripped = i === 0x09 || i === 0x0A || i === 0x0D;
191cb0ef41Sopenharmony_ci
201cb0ef41Sopenharmony_ci    // It turns out that user agents are surprisingly similar for these ranges so generate fewer
211cb0ef41Sopenharmony_ci    // tests. If this is changed also change the logic for host below.
221cb0ef41Sopenharmony_ci    if (i !== 0 && i !== 0x1F && !stripped) {
231cb0ef41Sopenharmony_ci      continue;
241cb0ef41Sopenharmony_ci    }
251cb0ef41Sopenharmony_ci
261cb0ef41Sopenharmony_ci    const cpString = String.fromCodePoint(i);
271cb0ef41Sopenharmony_ci    const cpReference = "U+" + i.toString(16).toUpperCase().padStart(4, "0");
281cb0ef41Sopenharmony_ci
291cb0ef41Sopenharmony_ci    test(() => {
301cb0ef41Sopenharmony_ci      const expected = scheme === "https" ? (stripped ? "http" : "https") : (stripped ? "wpt--" : "wpt++");
311cb0ef41Sopenharmony_ci      const url = urlRecord(scheme);
321cb0ef41Sopenharmony_ci      url.protocol = String.fromCodePoint(i) + (scheme === "https" ? "http" : "wpt--");
331cb0ef41Sopenharmony_ci      assert_equals(url.protocol, expected + ":", "property");
341cb0ef41Sopenharmony_ci      assert_equals(url.href, urlString({ scheme: expected }), "href");
351cb0ef41Sopenharmony_ci    }, `Setting protocol with leading ${cpReference} (${scheme}:)`);
361cb0ef41Sopenharmony_ci
371cb0ef41Sopenharmony_ci    test(() => {
381cb0ef41Sopenharmony_ci      const expected = scheme === "https" ? (stripped ? "http" : "https") : (stripped ? "wpt--" : "wpt++");
391cb0ef41Sopenharmony_ci      const url = urlRecord(scheme);
401cb0ef41Sopenharmony_ci      url.protocol = (scheme === "https" ? "http" : "wpt--") + String.fromCodePoint(i);
411cb0ef41Sopenharmony_ci      assert_equals(url.protocol, expected + ":", "property");
421cb0ef41Sopenharmony_ci      assert_equals(url.href, urlString({ scheme: expected }), "href");
431cb0ef41Sopenharmony_ci    }, `Setting protocol with ${cpReference} before inserted colon (${scheme}:)`);
441cb0ef41Sopenharmony_ci
451cb0ef41Sopenharmony_ci    // Cannot test protocol with trailing as the algorithm inserts a colon before proceeding
461cb0ef41Sopenharmony_ci
471cb0ef41Sopenharmony_ci    // These do no stripping
481cb0ef41Sopenharmony_ci    for (const property of ["username", "password"]) {
491cb0ef41Sopenharmony_ci      for (const [type, expected, input] of [
501cb0ef41Sopenharmony_ci        ["leading", encodeURIComponent(cpString) + "test", String.fromCodePoint(i) + "test"],
511cb0ef41Sopenharmony_ci        ["middle", "te" + encodeURIComponent(cpString) + "st", "te" + String.fromCodePoint(i) + "st"],
521cb0ef41Sopenharmony_ci        ["trailing", "test" + encodeURIComponent(cpString), "test" + String.fromCodePoint(i)]
531cb0ef41Sopenharmony_ci      ]) {
541cb0ef41Sopenharmony_ci        test(() => {
551cb0ef41Sopenharmony_ci          const url = urlRecord(scheme);
561cb0ef41Sopenharmony_ci          url[property] = input;
571cb0ef41Sopenharmony_ci          assert_equals(url[property], expected, "property");
581cb0ef41Sopenharmony_ci          assert_equals(url.href, urlString({ scheme, [property]: expected }), "href");
591cb0ef41Sopenharmony_ci        }, `Setting ${property} with ${type} ${cpReference} (${scheme}:)`);
601cb0ef41Sopenharmony_ci      }
611cb0ef41Sopenharmony_ci    }
621cb0ef41Sopenharmony_ci
631cb0ef41Sopenharmony_ci    for (const [type, expectedPart, input] of [
641cb0ef41Sopenharmony_ci      ["leading", (scheme === "https" ? cpString : encodeURIComponent(cpString)) + "test", String.fromCodePoint(i) + "test"],
651cb0ef41Sopenharmony_ci      ["middle", "te" + (scheme === "https" ? cpString : encodeURIComponent(cpString)) + "st", "te" + String.fromCodePoint(i) + "st"],
661cb0ef41Sopenharmony_ci      ["trailing", "test" + (scheme === "https" ? cpString : encodeURIComponent(cpString)), "test" + String.fromCodePoint(i)]
671cb0ef41Sopenharmony_ci    ]) {
681cb0ef41Sopenharmony_ci      test(() => {
691cb0ef41Sopenharmony_ci        const expected = i === 0x00 || (scheme === "https" && i === 0x1F) ? "host" : stripped ? "test" : expectedPart;
701cb0ef41Sopenharmony_ci        const url = urlRecord(scheme);
711cb0ef41Sopenharmony_ci        url.host = input;
721cb0ef41Sopenharmony_ci        assert_equals(url.host, expected + ":8000", "property");
731cb0ef41Sopenharmony_ci        assert_equals(url.href, urlString({ scheme, host: expected }), "href");
741cb0ef41Sopenharmony_ci      }, `Setting host with ${type} ${cpReference} (${scheme}:)`);
751cb0ef41Sopenharmony_ci
761cb0ef41Sopenharmony_ci      test(() => {
771cb0ef41Sopenharmony_ci        const expected = i === 0x00 || (scheme === "https" && i === 0x1F) ? "host" : stripped ? "test" : expectedPart;
781cb0ef41Sopenharmony_ci        const url = urlRecord(scheme);
791cb0ef41Sopenharmony_ci        url.hostname = input;
801cb0ef41Sopenharmony_ci        assert_equals(url.hostname, expected, "property");
811cb0ef41Sopenharmony_ci        assert_equals(url.href, urlString({ scheme, host: expected }), "href");
821cb0ef41Sopenharmony_ci      }, `Setting hostname with ${type} ${cpReference} (${scheme}:)`);
831cb0ef41Sopenharmony_ci    }
841cb0ef41Sopenharmony_ci
851cb0ef41Sopenharmony_ci    test(() => {
861cb0ef41Sopenharmony_ci      const expected = stripped ? "9000" : "8000";
871cb0ef41Sopenharmony_ci      const url = urlRecord(scheme);
881cb0ef41Sopenharmony_ci      url.port = String.fromCodePoint(i) + "9000";
891cb0ef41Sopenharmony_ci      assert_equals(url.port, expected, "property");
901cb0ef41Sopenharmony_ci      assert_equals(url.href, urlString({ scheme, port: expected }), "href");
911cb0ef41Sopenharmony_ci    }, `Setting port with leading ${cpReference} (${scheme}:)`);
921cb0ef41Sopenharmony_ci
931cb0ef41Sopenharmony_ci    test(() => {
941cb0ef41Sopenharmony_ci      const expected = stripped ? "9000" : "90";
951cb0ef41Sopenharmony_ci      const url = urlRecord(scheme);
961cb0ef41Sopenharmony_ci      url.port = "90" + String.fromCodePoint(i) + "00";
971cb0ef41Sopenharmony_ci      assert_equals(url.port, expected, "property");
981cb0ef41Sopenharmony_ci      assert_equals(url.href, urlString({ scheme, port: expected }), "href");
991cb0ef41Sopenharmony_ci    }, `Setting port with middle ${cpReference} (${scheme}:)`);
1001cb0ef41Sopenharmony_ci
1011cb0ef41Sopenharmony_ci    test(() => {
1021cb0ef41Sopenharmony_ci      const expected = "9000";
1031cb0ef41Sopenharmony_ci      const url = urlRecord(scheme);
1041cb0ef41Sopenharmony_ci      url.port = "9000" + String.fromCodePoint(i);
1051cb0ef41Sopenharmony_ci      assert_equals(url.port, expected, "property");
1061cb0ef41Sopenharmony_ci      assert_equals(url.href, urlString({ scheme, port: expected }), "href");
1071cb0ef41Sopenharmony_ci    }, `Setting port with trailing ${cpReference} (${scheme}:)`);
1081cb0ef41Sopenharmony_ci
1091cb0ef41Sopenharmony_ci    for (const [property, separator] of [["pathname", "/"], ["search", "?"], ["hash", "#"]]) {
1101cb0ef41Sopenharmony_ci      for (const [type, expectedPart, input] of [
1111cb0ef41Sopenharmony_ci        ["leading", encodeURIComponent(cpString) + "test", String.fromCodePoint(i) + "test"],
1121cb0ef41Sopenharmony_ci        ["middle", "te" + encodeURIComponent(cpString) + "st", "te" + String.fromCodePoint(i) + "st"],
1131cb0ef41Sopenharmony_ci        ["trailing", "test" + encodeURIComponent(cpString), "test" + String.fromCodePoint(i)]
1141cb0ef41Sopenharmony_ci      ]) {
1151cb0ef41Sopenharmony_ci        test(() => {
1161cb0ef41Sopenharmony_ci          const expected = stripped ? "test" : expectedPart;
1171cb0ef41Sopenharmony_ci          const url = urlRecord(scheme);
1181cb0ef41Sopenharmony_ci          url[property] = input;
1191cb0ef41Sopenharmony_ci          assert_equals(url[property], separator + expected, "property");
1201cb0ef41Sopenharmony_ci          assert_equals(url.href, urlString({ scheme, [property]: expected }), "href");
1211cb0ef41Sopenharmony_ci        }, `Setting ${property} with ${type} ${cpReference} (${scheme}:)`);
1221cb0ef41Sopenharmony_ci      }
1231cb0ef41Sopenharmony_ci    }
1241cb0ef41Sopenharmony_ci  }
1251cb0ef41Sopenharmony_ci}
126