1function urlString({ scheme = "https", 2 username = "username", 3 password = "password", 4 host = "host", 5 port = "8000", 6 pathname = "path", 7 search = "query", 8 hash = "fragment" }) { 9 return `${scheme}://${username}:${password}@${host}:${port}/${pathname}?${search}#${hash}`; 10} 11 12function urlRecord(scheme) { 13 return new URL(urlString({ scheme })); 14} 15 16for(const scheme of ["https", "wpt++"]) { 17 for(let i = 0; i < 0x20; i++) { 18 const stripped = i === 0x09 || i === 0x0A || i === 0x0D; 19 20 // It turns out that user agents are surprisingly similar for these ranges so generate fewer 21 // tests. If this is changed also change the logic for host below. 22 if (i !== 0 && i !== 0x1F && !stripped) { 23 continue; 24 } 25 26 const cpString = String.fromCodePoint(i); 27 const cpReference = "U+" + i.toString(16).toUpperCase().padStart(4, "0"); 28 29 test(() => { 30 const expected = scheme === "https" ? (stripped ? "http" : "https") : (stripped ? "wpt--" : "wpt++"); 31 const url = urlRecord(scheme); 32 url.protocol = String.fromCodePoint(i) + (scheme === "https" ? "http" : "wpt--"); 33 assert_equals(url.protocol, expected + ":", "property"); 34 assert_equals(url.href, urlString({ scheme: expected }), "href"); 35 }, `Setting protocol with leading ${cpReference} (${scheme}:)`); 36 37 test(() => { 38 const expected = scheme === "https" ? (stripped ? "http" : "https") : (stripped ? "wpt--" : "wpt++"); 39 const url = urlRecord(scheme); 40 url.protocol = (scheme === "https" ? "http" : "wpt--") + String.fromCodePoint(i); 41 assert_equals(url.protocol, expected + ":", "property"); 42 assert_equals(url.href, urlString({ scheme: expected }), "href"); 43 }, `Setting protocol with ${cpReference} before inserted colon (${scheme}:)`); 44 45 // Cannot test protocol with trailing as the algorithm inserts a colon before proceeding 46 47 // These do no stripping 48 for (const property of ["username", "password"]) { 49 for (const [type, expected, input] of [ 50 ["leading", encodeURIComponent(cpString) + "test", String.fromCodePoint(i) + "test"], 51 ["middle", "te" + encodeURIComponent(cpString) + "st", "te" + String.fromCodePoint(i) + "st"], 52 ["trailing", "test" + encodeURIComponent(cpString), "test" + String.fromCodePoint(i)] 53 ]) { 54 test(() => { 55 const url = urlRecord(scheme); 56 url[property] = input; 57 assert_equals(url[property], expected, "property"); 58 assert_equals(url.href, urlString({ scheme, [property]: expected }), "href"); 59 }, `Setting ${property} with ${type} ${cpReference} (${scheme}:)`); 60 } 61 } 62 63 for (const [type, expectedPart, input] of [ 64 ["leading", (scheme === "https" ? cpString : encodeURIComponent(cpString)) + "test", String.fromCodePoint(i) + "test"], 65 ["middle", "te" + (scheme === "https" ? cpString : encodeURIComponent(cpString)) + "st", "te" + String.fromCodePoint(i) + "st"], 66 ["trailing", "test" + (scheme === "https" ? cpString : encodeURIComponent(cpString)), "test" + String.fromCodePoint(i)] 67 ]) { 68 test(() => { 69 const expected = i === 0x00 || (scheme === "https" && i === 0x1F) ? "host" : stripped ? "test" : expectedPart; 70 const url = urlRecord(scheme); 71 url.host = input; 72 assert_equals(url.host, expected + ":8000", "property"); 73 assert_equals(url.href, urlString({ scheme, host: expected }), "href"); 74 }, `Setting host with ${type} ${cpReference} (${scheme}:)`); 75 76 test(() => { 77 const expected = i === 0x00 || (scheme === "https" && i === 0x1F) ? "host" : stripped ? "test" : expectedPart; 78 const url = urlRecord(scheme); 79 url.hostname = input; 80 assert_equals(url.hostname, expected, "property"); 81 assert_equals(url.href, urlString({ scheme, host: expected }), "href"); 82 }, `Setting hostname with ${type} ${cpReference} (${scheme}:)`); 83 } 84 85 test(() => { 86 const expected = stripped ? "9000" : "8000"; 87 const url = urlRecord(scheme); 88 url.port = String.fromCodePoint(i) + "9000"; 89 assert_equals(url.port, expected, "property"); 90 assert_equals(url.href, urlString({ scheme, port: expected }), "href"); 91 }, `Setting port with leading ${cpReference} (${scheme}:)`); 92 93 test(() => { 94 const expected = stripped ? "9000" : "90"; 95 const url = urlRecord(scheme); 96 url.port = "90" + String.fromCodePoint(i) + "00"; 97 assert_equals(url.port, expected, "property"); 98 assert_equals(url.href, urlString({ scheme, port: expected }), "href"); 99 }, `Setting port with middle ${cpReference} (${scheme}:)`); 100 101 test(() => { 102 const expected = "9000"; 103 const url = urlRecord(scheme); 104 url.port = "9000" + String.fromCodePoint(i); 105 assert_equals(url.port, expected, "property"); 106 assert_equals(url.href, urlString({ scheme, port: expected }), "href"); 107 }, `Setting port with trailing ${cpReference} (${scheme}:)`); 108 109 for (const [property, separator] of [["pathname", "/"], ["search", "?"], ["hash", "#"]]) { 110 for (const [type, expectedPart, input] of [ 111 ["leading", encodeURIComponent(cpString) + "test", String.fromCodePoint(i) + "test"], 112 ["middle", "te" + encodeURIComponent(cpString) + "st", "te" + String.fromCodePoint(i) + "st"], 113 ["trailing", "test" + encodeURIComponent(cpString), "test" + String.fromCodePoint(i)] 114 ]) { 115 test(() => { 116 const expected = stripped ? "test" : expectedPart; 117 const url = urlRecord(scheme); 118 url[property] = input; 119 assert_equals(url[property], separator + expected, "property"); 120 assert_equals(url.href, urlString({ scheme, [property]: expected }), "href"); 121 }, `Setting ${property} with ${type} ${cpReference} (${scheme}:)`); 122 } 123 } 124 } 125} 126