• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1{
2    "comment": [
3        "## Tests for setters of https://url.spec.whatwg.org/#urlutils-members",
4        "",
5        "This file contains a JSON object.",
6        "Other than 'comment', each key is an attribute of the `URL` interface",
7        "defined in WHATWG’s URL Standard.",
8        "The values are arrays of test case objects for that attribute.",
9        "",
10        "To run a test case for the attribute `attr`:",
11        "",
12        "* Create a new `URL` object with the value for the 'href' key",
13        "  the constructor single parameter. (Without a base URL.)",
14        "  This must not throw.",
15        "* Set the attribute `attr` to (invoke its setter with)",
16        "  with the value of for 'new_value' key.",
17        "* The value for the 'expected' key is another object.",
18        "  For each `key` / `value` pair of that object,",
19        "  get the attribute `key` (invoke its getter).",
20        "  The returned string must be equal to `value`.",
21        "",
22        "Note: the 'href' setter is already covered by urltestdata.json."
23    ],
24    "protocol": [
25        {
26            "comment": "The empty string is not a valid scheme. Setter leaves the URL unchanged.",
27            "href": "a://example.net",
28            "new_value": "",
29            "expected": {
30                "href": "a://example.net",
31                "protocol": "a:"
32            }
33        },
34        {
35            "href": "a://example.net",
36            "new_value": "b",
37            "expected": {
38                "href": "b://example.net",
39                "protocol": "b:"
40            }
41        },
42        {
43            "href": "javascript:alert(1)",
44            "new_value": "defuse",
45            "expected": {
46                "href": "defuse:alert(1)",
47                "protocol": "defuse:"
48            }
49        },
50        {
51            "comment": "Upper-case ASCII is lower-cased",
52            "href": "a://example.net",
53            "new_value": "B",
54            "expected": {
55                "href": "b://example.net",
56                "protocol": "b:"
57            }
58        },
59        {
60            "comment": "Non-ASCII is rejected",
61            "href": "a://example.net",
62            "new_value": "é",
63            "expected": {
64                "href": "a://example.net",
65                "protocol": "a:"
66            }
67        },
68        {
69            "comment": "No leading digit",
70            "href": "a://example.net",
71            "new_value": "0b",
72            "expected": {
73                "href": "a://example.net",
74                "protocol": "a:"
75            }
76        },
77        {
78            "comment": "No leading punctuation",
79            "href": "a://example.net",
80            "new_value": "+b",
81            "expected": {
82                "href": "a://example.net",
83                "protocol": "a:"
84            }
85        },
86        {
87            "href": "a://example.net",
88            "new_value": "bC0+-.",
89            "expected": {
90                "href": "bc0+-.://example.net",
91                "protocol": "bc0+-.:"
92            }
93        },
94        {
95            "comment": "Only some punctuation is acceptable",
96            "href": "a://example.net",
97            "new_value": "b,c",
98            "expected": {
99                "href": "a://example.net",
100                "protocol": "a:"
101            }
102        },
103        {
104            "comment": "Non-ASCII is rejected",
105            "href": "a://example.net",
106            "new_value": "bé",
107            "expected": {
108                "href": "a://example.net",
109                "protocol": "a:"
110            }
111        },
112        {
113            "comment": "Can’t switch from URL containing username/password/port to file",
114            "href": "http://test@example.net",
115            "new_value": "file",
116            "expected": {
117                "href": "http://test@example.net/",
118                "protocol": "http:"
119            }
120        },
121        {
122            "href": "gopher://example.net:1234",
123            "new_value": "file",
124            "expected": {
125                "href": "gopher://example.net:1234/",
126                "protocol": "gopher:"
127            }
128        },
129        {
130            "href": "wss://x:x@example.net:1234",
131            "new_value": "file",
132            "expected": {
133                "href": "wss://x:x@example.net:1234/",
134                "protocol": "wss:"
135            }
136        },
137        {
138            "comment": "Can’t switch from file URL with no host",
139            "href": "file://localhost/",
140            "new_value": "http",
141            "expected": {
142                "href": "file:///",
143                "protocol": "file:"
144            }
145        },
146        {
147            "href": "file:///test",
148            "new_value": "gopher",
149            "expected": {
150                "href": "file:///test",
151                "protocol": "file:"
152            }
153        },
154        {
155            "href": "file:",
156            "new_value": "wss",
157            "expected": {
158                "href": "file:///",
159                "protocol": "file:"
160            }
161        },
162        {
163            "comment": "Can’t switch from special scheme to non-special",
164            "href": "http://example.net",
165            "new_value": "b",
166            "expected": {
167                "href": "http://example.net/",
168                "protocol": "http:"
169            }
170        },
171        {
172            "href": "file://hi/path",
173            "new_value": "s",
174            "expected": {
175                "href": "file://hi/path",
176                "protocol": "file:"
177            }
178        },
179        {
180            "href": "https://example.net",
181            "new_value": "s",
182            "expected": {
183                "href": "https://example.net/",
184                "protocol": "https:"
185            }
186        },
187        {
188            "href": "ftp://example.net",
189            "new_value": "test",
190            "expected": {
191                "href": "ftp://example.net/",
192                "protocol": "ftp:"
193            }
194        },
195        {
196            "comment": "Cannot-be-a-base URL doesn’t have a host, but URL in a special scheme must.",
197            "href": "mailto:me@example.net",
198            "new_value": "http",
199            "expected": {
200                "href": "mailto:me@example.net",
201                "protocol": "mailto:"
202            }
203        },
204        {
205            "comment": "Can’t switch from non-special scheme to special",
206            "href": "ssh://me@example.net",
207            "new_value": "http",
208            "expected": {
209                "href": "ssh://me@example.net",
210                "protocol": "ssh:"
211            }
212        },
213        {
214            "href": "ssh://me@example.net",
215            "new_value": "gopher",
216            "expected": {
217                "href": "ssh://me@example.net",
218                "protocol": "ssh:"
219            }
220        },
221        {
222            "href": "ssh://me@example.net",
223            "new_value": "file",
224            "expected": {
225                "href": "ssh://me@example.net",
226                "protocol": "ssh:"
227            }
228        },
229        {
230            "href": "ssh://example.net",
231            "new_value": "file",
232            "expected": {
233                "href": "ssh://example.net",
234                "protocol": "ssh:"
235            }
236        },
237        {
238            "href": "nonsense:///test",
239            "new_value": "https",
240            "expected": {
241                "href": "nonsense:///test",
242                "protocol": "nonsense:"
243            }
244        },
245        {
246            "comment": "Stuff after the first ':' is ignored",
247            "href": "http://example.net",
248            "new_value": "https:foo : bar",
249            "expected": {
250                "href": "https://example.net/",
251                "protocol": "https:"
252            }
253        },
254        {
255            "comment": "Stuff after the first ':' is ignored",
256            "href": "data:text/html,<p>Test",
257            "new_value": "view-source+data:foo : bar",
258            "expected": {
259                "href": "view-source+data:text/html,<p>Test",
260                "protocol": "view-source+data:"
261            }
262        },
263        {
264            "comment": "Port is set to null if it is the default for new scheme.",
265            "href": "http://foo.com:443/",
266            "new_value": "https",
267            "expected": {
268                "href": "https://foo.com/",
269                "protocol": "https:",
270                "port": ""
271            }
272        }
273    ],
274    "username": [
275        {
276            "comment": "No host means no username",
277            "href": "file:///home/you/index.html",
278            "new_value": "me",
279            "expected": {
280                "href": "file:///home/you/index.html",
281                "username": ""
282            }
283        },
284        {
285            "comment": "No host means no username",
286            "href": "unix:/run/foo.socket",
287            "new_value": "me",
288            "expected": {
289                "href": "unix:/run/foo.socket",
290                "username": ""
291            }
292        },
293        {
294            "comment": "Cannot-be-a-base means no username",
295            "href": "mailto:you@example.net",
296            "new_value": "me",
297            "expected": {
298                "href": "mailto:you@example.net",
299                "username": ""
300            }
301        },
302        {
303            "href": "javascript:alert(1)",
304            "new_value": "wario",
305            "expected": {
306                "href": "javascript:alert(1)",
307                "username": ""
308            }
309        },
310        {
311            "href": "http://example.net",
312            "new_value": "me",
313            "expected": {
314                "href": "http://me@example.net/",
315                "username": "me"
316            }
317        },
318        {
319            "href": "http://:secret@example.net",
320            "new_value": "me",
321            "expected": {
322                "href": "http://me:secret@example.net/",
323                "username": "me"
324            }
325        },
326        {
327            "href": "http://me@example.net",
328            "new_value": "",
329            "expected": {
330                "href": "http://example.net/",
331                "username": ""
332            }
333        },
334        {
335            "href": "http://me:secret@example.net",
336            "new_value": "",
337            "expected": {
338                "href": "http://:secret@example.net/",
339                "username": ""
340            }
341        },
342        {
343            "comment": "UTF-8 percent encoding with the userinfo encode set.",
344            "href": "http://example.net",
345            "new_value": "\u0000\u0001\t\n\r\u001f !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~\u007f\u0080\u0081Éé",
346            "expected": {
347                "href": "http://%00%01%09%0A%0D%1F%20!%22%23$%&'()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9@example.net/",
348                "username": "%00%01%09%0A%0D%1F%20!%22%23$%&'()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9"
349            }
350        },
351        {
352            "comment": "Bytes already percent-encoded are left as-is.",
353            "href": "http://example.net",
354            "new_value": "%c3%89té",
355            "expected": {
356                "href": "http://%c3%89t%C3%A9@example.net/",
357                "username": "%c3%89t%C3%A9"
358            }
359        },
360        {
361            "href": "sc:///",
362            "new_value": "x",
363            "expected": {
364                "href": "sc:///",
365                "username": ""
366            }
367        },
368        {
369            "href": "javascript://x/",
370            "new_value": "wario",
371            "expected": {
372                "href": "javascript://wario@x/",
373                "username": "wario"
374            }
375        },
376        {
377            "href": "file://test/",
378            "new_value": "test",
379            "expected": {
380                "href": "file://test/",
381                "username": ""
382            }
383        }
384    ],
385    "password": [
386        {
387            "comment": "No host means no password",
388            "href": "file:///home/me/index.html",
389            "new_value": "secret",
390            "expected": {
391                "href": "file:///home/me/index.html",
392                "password": ""
393            }
394        },
395        {
396            "comment": "No host means no password",
397            "href": "unix:/run/foo.socket",
398            "new_value": "secret",
399            "expected": {
400                "href": "unix:/run/foo.socket",
401                "password": ""
402            }
403        },
404        {
405            "comment": "Cannot-be-a-base means no password",
406            "href": "mailto:me@example.net",
407            "new_value": "secret",
408            "expected": {
409                "href": "mailto:me@example.net",
410                "password": ""
411            }
412        },
413        {
414            "href": "http://example.net",
415            "new_value": "secret",
416            "expected": {
417                "href": "http://:secret@example.net/",
418                "password": "secret"
419            }
420        },
421        {
422            "href": "http://me@example.net",
423            "new_value": "secret",
424            "expected": {
425                "href": "http://me:secret@example.net/",
426                "password": "secret"
427            }
428        },
429        {
430            "href": "http://:secret@example.net",
431            "new_value": "",
432            "expected": {
433                "href": "http://example.net/",
434                "password": ""
435            }
436        },
437        {
438            "href": "http://me:secret@example.net",
439            "new_value": "",
440            "expected": {
441                "href": "http://me@example.net/",
442                "password": ""
443            }
444        },
445        {
446            "comment": "UTF-8 percent encoding with the userinfo encode set.",
447            "href": "http://example.net",
448            "new_value": "\u0000\u0001\t\n\r\u001f !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~\u007f\u0080\u0081Éé",
449            "expected": {
450                "href": "http://:%00%01%09%0A%0D%1F%20!%22%23$%&'()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9@example.net/",
451                "password": "%00%01%09%0A%0D%1F%20!%22%23$%&'()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9"
452            }
453        },
454        {
455            "comment": "Bytes already percent-encoded are left as-is.",
456            "href": "http://example.net",
457            "new_value": "%c3%89té",
458            "expected": {
459                "href": "http://:%c3%89t%C3%A9@example.net/",
460                "password": "%c3%89t%C3%A9"
461            }
462        },
463        {
464            "href": "sc:///",
465            "new_value": "x",
466            "expected": {
467                "href": "sc:///",
468                "password": ""
469            }
470        },
471        {
472            "href": "javascript://x/",
473            "new_value": "bowser",
474            "expected": {
475                "href": "javascript://:bowser@x/",
476                "password": "bowser"
477            }
478        },
479        {
480            "href": "file://test/",
481            "new_value": "test",
482            "expected": {
483                "href": "file://test/",
484                "password": ""
485            }
486        }
487    ],
488    "host": [
489        {
490            "comment": "Non-special scheme",
491            "href": "sc://x/",
492            "new_value": "\u0000",
493            "expected": {
494                "href": "sc://x/",
495                "host": "x",
496                "hostname": "x"
497            }
498        },
499        {
500            "href": "sc://x/",
501            "new_value": "\u0009",
502            "expected": {
503                "href": "sc:///",
504                "host": "",
505                "hostname": ""
506            }
507        },
508        {
509            "href": "sc://x/",
510            "new_value": "\u000A",
511            "expected": {
512                "href": "sc:///",
513                "host": "",
514                "hostname": ""
515            }
516        },
517        {
518            "href": "sc://x/",
519            "new_value": "\u000D",
520            "expected": {
521                "href": "sc:///",
522                "host": "",
523                "hostname": ""
524            }
525        },
526        {
527            "href": "sc://x/",
528            "new_value": " ",
529            "expected": {
530                "href": "sc://x/",
531                "host": "x",
532                "hostname": "x"
533            }
534        },
535        {
536            "href": "sc://x/",
537            "new_value": "#",
538            "expected": {
539                "href": "sc:///",
540                "host": "",
541                "hostname": ""
542            }
543        },
544        {
545            "href": "sc://x/",
546            "new_value": "/",
547            "expected": {
548                "href": "sc:///",
549                "host": "",
550                "hostname": ""
551            }
552        },
553        {
554            "href": "sc://x/",
555            "new_value": "?",
556            "expected": {
557                "href": "sc:///",
558                "host": "",
559                "hostname": ""
560            }
561        },
562        {
563            "href": "sc://x/",
564            "new_value": "@",
565            "expected": {
566                "href": "sc://x/",
567                "host": "x",
568                "hostname": "x"
569            }
570        },
571        {
572            "href": "sc://x/",
573            "new_value": "ß",
574            "expected": {
575                "href": "sc://%C3%9F/",
576                "host": "%C3%9F",
577                "hostname": "%C3%9F"
578            }
579        },
580        {
581            "comment": "IDNA Nontransitional_Processing",
582            "href": "https://x/",
583            "new_value": "ß",
584            "expected": {
585                "href": "https://xn--zca/",
586                "host": "xn--zca",
587                "hostname": "xn--zca"
588            }
589        },
590        {
591            "comment": "Cannot-be-a-base means no host",
592            "href": "mailto:me@example.net",
593            "new_value": "example.com",
594            "expected": {
595                "href": "mailto:me@example.net",
596                "host": ""
597            }
598        },
599        {
600            "comment": "Cannot-be-a-base means no password",
601            "href": "data:text/plain,Stuff",
602            "new_value": "example.net",
603            "expected": {
604                "href": "data:text/plain,Stuff",
605                "host": ""
606            }
607        },
608        {
609            "href": "http://example.net",
610            "new_value": "example.com:8080",
611            "expected": {
612                "href": "http://example.com:8080/",
613                "host": "example.com:8080",
614                "hostname": "example.com",
615                "port": "8080"
616            }
617        },
618        {
619            "comment": "Port number is unchanged if not specified in the new value",
620            "href": "http://example.net:8080",
621            "new_value": "example.com",
622            "expected": {
623                "href": "http://example.com:8080/",
624                "host": "example.com:8080",
625                "hostname": "example.com",
626                "port": "8080"
627            }
628        },
629        {
630            "comment": "Port number is unchanged if not specified",
631            "href": "http://example.net:8080",
632            "new_value": "example.com:",
633            "expected": {
634                "href": "http://example.com:8080/",
635                "host": "example.com:8080",
636                "hostname": "example.com",
637                "port": "8080"
638            }
639        },
640        {
641            "comment": "The empty host is not valid for special schemes",
642            "href": "http://example.net",
643            "new_value": "",
644            "expected": {
645                "href": "http://example.net/",
646                "host": "example.net"
647            }
648        },
649        {
650            "comment": "The empty host is OK for non-special schemes",
651            "href": "view-source+http://example.net/foo",
652            "new_value": "",
653            "expected": {
654                "href": "view-source+http:///foo",
655                "host": ""
656            }
657        },
658        {
659            "comment": "Path-only URLs can gain a host",
660            "href": "a:/foo",
661            "new_value": "example.net",
662            "expected": {
663                "href": "a://example.net/foo",
664                "host": "example.net"
665            }
666        },
667        {
668            "comment": "IPv4 address syntax is normalized",
669            "href": "http://example.net",
670            "new_value": "0x7F000001:8080",
671            "expected": {
672                "href": "http://127.0.0.1:8080/",
673                "host": "127.0.0.1:8080",
674                "hostname": "127.0.0.1",
675                "port": "8080"
676            }
677        },
678        {
679            "comment": "IPv6 address syntax is normalized",
680            "href": "http://example.net",
681            "new_value": "[::0:01]:2",
682            "expected": {
683                "href": "http://[::1]:2/",
684                "host": "[::1]:2",
685                "hostname": "[::1]",
686                "port": "2"
687            }
688        },
689        {
690            "comment": "Default port number is removed",
691            "href": "http://example.net",
692            "new_value": "example.com:80",
693            "expected": {
694                "href": "http://example.com/",
695                "host": "example.com",
696                "hostname": "example.com",
697                "port": ""
698            }
699        },
700        {
701            "comment": "Default port number is removed",
702            "href": "https://example.net",
703            "new_value": "example.com:443",
704            "expected": {
705                "href": "https://example.com/",
706                "host": "example.com",
707                "hostname": "example.com",
708                "port": ""
709            }
710        },
711        {
712            "comment": "Default port number is only removed for the relevant scheme",
713            "href": "https://example.net",
714            "new_value": "example.com:80",
715            "expected": {
716                "href": "https://example.com:80/",
717                "host": "example.com:80",
718                "hostname": "example.com",
719                "port": "80"
720            }
721        },
722        {
723            "comment": "Port number is removed if new port is scheme default and existing URL has a non-default port",
724            "href": "http://example.net:8080",
725            "new_value": "example.com:80",
726            "expected": {
727                "href": "http://example.com/",
728                "host": "example.com",
729                "hostname": "example.com",
730                "port": ""
731            }
732        },
733        {
734            "comment": "Stuff after a / delimiter is ignored",
735            "href": "http://example.net/path",
736            "new_value": "example.com/stuff",
737            "expected": {
738                "href": "http://example.com/path",
739                "host": "example.com",
740                "hostname": "example.com",
741                "port": ""
742            }
743        },
744        {
745            "comment": "Stuff after a / delimiter is ignored",
746            "href": "http://example.net/path",
747            "new_value": "example.com:8080/stuff",
748            "expected": {
749                "href": "http://example.com:8080/path",
750                "host": "example.com:8080",
751                "hostname": "example.com",
752                "port": "8080"
753            }
754        },
755        {
756            "comment": "Stuff after a ? delimiter is ignored",
757            "href": "http://example.net/path",
758            "new_value": "example.com?stuff",
759            "expected": {
760                "href": "http://example.com/path",
761                "host": "example.com",
762                "hostname": "example.com",
763                "port": ""
764            }
765        },
766        {
767            "comment": "Stuff after a ? delimiter is ignored",
768            "href": "http://example.net/path",
769            "new_value": "example.com:8080?stuff",
770            "expected": {
771                "href": "http://example.com:8080/path",
772                "host": "example.com:8080",
773                "hostname": "example.com",
774                "port": "8080"
775            }
776        },
777        {
778            "comment": "Stuff after a # delimiter is ignored",
779            "href": "http://example.net/path",
780            "new_value": "example.com#stuff",
781            "expected": {
782                "href": "http://example.com/path",
783                "host": "example.com",
784                "hostname": "example.com",
785                "port": ""
786            }
787        },
788        {
789            "comment": "Stuff after a # delimiter is ignored",
790            "href": "http://example.net/path",
791            "new_value": "example.com:8080#stuff",
792            "expected": {
793                "href": "http://example.com:8080/path",
794                "host": "example.com:8080",
795                "hostname": "example.com",
796                "port": "8080"
797            }
798        },
799        {
800            "comment": "Stuff after a \\ delimiter is ignored for special schemes",
801            "href": "http://example.net/path",
802            "new_value": "example.com\\stuff",
803            "expected": {
804                "href": "http://example.com/path",
805                "host": "example.com",
806                "hostname": "example.com",
807                "port": ""
808            }
809        },
810        {
811            "comment": "Stuff after a \\ delimiter is ignored for special schemes",
812            "href": "http://example.net/path",
813            "new_value": "example.com:8080\\stuff",
814            "expected": {
815                "href": "http://example.com:8080/path",
816                "host": "example.com:8080",
817                "hostname": "example.com",
818                "port": "8080"
819            }
820        },
821        {
822            "comment": "\\ is not a delimiter for non-special schemes, but still forbidden in hosts",
823            "href": "view-source+http://example.net/path",
824            "new_value": "example.com\\stuff",
825            "expected": {
826                "href": "view-source+http://example.net/path",
827                "host": "example.net",
828                "hostname": "example.net",
829                "port": ""
830            }
831        },
832        {
833            "comment": "Anything other than ASCII digit stops the port parser in a setter but is not an error",
834            "href": "view-source+http://example.net/path",
835            "new_value": "example.com:8080stuff2",
836            "expected": {
837                "href": "view-source+http://example.com:8080/path",
838                "host": "example.com:8080",
839                "hostname": "example.com",
840                "port": "8080"
841            }
842        },
843        {
844            "comment": "Anything other than ASCII digit stops the port parser in a setter but is not an error",
845            "href": "http://example.net/path",
846            "new_value": "example.com:8080stuff2",
847            "expected": {
848                "href": "http://example.com:8080/path",
849                "host": "example.com:8080",
850                "hostname": "example.com",
851                "port": "8080"
852            }
853        },
854        {
855            "comment": "Anything other than ASCII digit stops the port parser in a setter but is not an error",
856            "href": "http://example.net/path",
857            "new_value": "example.com:8080+2",
858            "expected": {
859                "href": "http://example.com:8080/path",
860                "host": "example.com:8080",
861                "hostname": "example.com",
862                "port": "8080"
863            }
864        },
865        {
866            "comment": "Port numbers are 16 bit integers",
867            "href": "http://example.net/path",
868            "new_value": "example.com:65535",
869            "expected": {
870                "href": "http://example.com:65535/path",
871                "host": "example.com:65535",
872                "hostname": "example.com",
873                "port": "65535"
874            }
875        },
876        {
877            "comment": "Port numbers are 16 bit integers, overflowing is an error. Hostname is still set, though.",
878            "href": "http://example.net/path",
879            "new_value": "example.com:65536",
880            "expected": {
881                "href": "http://example.com/path",
882                "host": "example.com",
883                "hostname": "example.com",
884                "port": ""
885            }
886        },
887        {
888            "comment": "Broken IPv6",
889            "href": "http://example.net/",
890            "new_value": "[google.com]",
891            "expected": {
892                "href": "http://example.net/",
893                "host": "example.net",
894                "hostname": "example.net"
895            }
896        },
897        {
898            "href": "http://example.net/",
899            "new_value": "[::1.2.3.4x]",
900            "expected": {
901                "href": "http://example.net/",
902                "host": "example.net",
903                "hostname": "example.net"
904            }
905        },
906        {
907            "href": "http://example.net/",
908            "new_value": "[::1.2.3.]",
909            "expected": {
910                "href": "http://example.net/",
911                "host": "example.net",
912                "hostname": "example.net"
913            }
914        },
915        {
916            "href": "http://example.net/",
917            "new_value": "[::1.2.]",
918            "expected": {
919                "href": "http://example.net/",
920                "host": "example.net",
921                "hostname": "example.net"
922            }
923        },
924        {
925            "href": "http://example.net/",
926            "new_value": "[::1.]",
927            "expected": {
928                "href": "http://example.net/",
929                "host": "example.net",
930                "hostname": "example.net"
931            }
932        },
933        {
934            "href": "file://y/",
935            "new_value": "x:123",
936            "expected": {
937                "href": "file://y/",
938                "host": "y",
939                "hostname": "y",
940                "port": ""
941            }
942        },
943        {
944            "href": "file://y/",
945            "new_value": "loc%41lhost",
946            "expected": {
947                "href": "file:///",
948                "host": "",
949                "hostname": "",
950                "port": ""
951            }
952        },
953        {
954            "href": "file://hi/x",
955            "new_value": "",
956            "expected": {
957                "href": "file:///x",
958                "host": "",
959                "hostname": "",
960                "port": ""
961            }
962        },
963        {
964            "href": "sc://test@test/",
965            "new_value": "",
966            "expected": {
967                "href": "sc://test@test/",
968                "host": "test",
969                "hostname": "test",
970                "username": "test"
971            }
972        },
973        {
974            "href": "sc://test:12/",
975            "new_value": "",
976            "expected": {
977                "href": "sc://test:12/",
978                "host": "test:12",
979                "hostname": "test",
980                "port": "12"
981            }
982        }
983    ],
984    "hostname": [
985        {
986            "comment": "Non-special scheme",
987            "href": "sc://x/",
988            "new_value": "\u0000",
989            "expected": {
990                "href": "sc://x/",
991                "host": "x",
992                "hostname": "x"
993            }
994        },
995        {
996            "href": "sc://x/",
997            "new_value": "\u0009",
998            "expected": {
999                "href": "sc:///",
1000                "host": "",
1001                "hostname": ""
1002            }
1003        },
1004        {
1005            "href": "sc://x/",
1006            "new_value": "\u000A",
1007            "expected": {
1008                "href": "sc:///",
1009                "host": "",
1010                "hostname": ""
1011            }
1012        },
1013        {
1014            "href": "sc://x/",
1015            "new_value": "\u000D",
1016            "expected": {
1017                "href": "sc:///",
1018                "host": "",
1019                "hostname": ""
1020            }
1021        },
1022        {
1023            "href": "sc://x/",
1024            "new_value": " ",
1025            "expected": {
1026                "href": "sc://x/",
1027                "host": "x",
1028                "hostname": "x"
1029            }
1030        },
1031        {
1032            "href": "sc://x/",
1033            "new_value": "#",
1034            "expected": {
1035                "href": "sc:///",
1036                "host": "",
1037                "hostname": ""
1038            }
1039        },
1040        {
1041            "href": "sc://x/",
1042            "new_value": "/",
1043            "expected": {
1044                "href": "sc:///",
1045                "host": "",
1046                "hostname": ""
1047            }
1048        },
1049        {
1050            "href": "sc://x/",
1051            "new_value": "?",
1052            "expected": {
1053                "href": "sc:///",
1054                "host": "",
1055                "hostname": ""
1056            }
1057        },
1058        {
1059            "href": "sc://x/",
1060            "new_value": "@",
1061            "expected": {
1062                "href": "sc://x/",
1063                "host": "x",
1064                "hostname": "x"
1065            }
1066        },
1067        {
1068            "comment": "Cannot-be-a-base means no host",
1069            "href": "mailto:me@example.net",
1070            "new_value": "example.com",
1071            "expected": {
1072                "href": "mailto:me@example.net",
1073                "host": ""
1074            }
1075        },
1076        {
1077            "comment": "Cannot-be-a-base means no password",
1078            "href": "data:text/plain,Stuff",
1079            "new_value": "example.net",
1080            "expected": {
1081                "href": "data:text/plain,Stuff",
1082                "host": ""
1083            }
1084        },
1085        {
1086            "href": "http://example.net:8080",
1087            "new_value": "example.com",
1088            "expected": {
1089                "href": "http://example.com:8080/",
1090                "host": "example.com:8080",
1091                "hostname": "example.com",
1092                "port": "8080"
1093            }
1094        },
1095        {
1096            "comment": "The empty host is not valid for special schemes",
1097            "href": "http://example.net",
1098            "new_value": "",
1099            "expected": {
1100                "href": "http://example.net/",
1101                "host": "example.net"
1102            }
1103        },
1104        {
1105            "comment": "The empty host is OK for non-special schemes",
1106            "href": "view-source+http://example.net/foo",
1107            "new_value": "",
1108            "expected": {
1109                "href": "view-source+http:///foo",
1110                "host": ""
1111            }
1112        },
1113        {
1114            "comment": "Path-only URLs can gain a host",
1115            "href": "a:/foo",
1116            "new_value": "example.net",
1117            "expected": {
1118                "href": "a://example.net/foo",
1119                "host": "example.net"
1120            }
1121        },
1122        {
1123            "comment": "IPv4 address syntax is normalized",
1124            "href": "http://example.net:8080",
1125            "new_value": "0x7F000001",
1126            "expected": {
1127                "href": "http://127.0.0.1:8080/",
1128                "host": "127.0.0.1:8080",
1129                "hostname": "127.0.0.1",
1130                "port": "8080"
1131            }
1132        },
1133        {
1134            "comment": "IPv6 address syntax is normalized",
1135            "href": "http://example.net",
1136            "new_value": "[::0:01]",
1137            "expected": {
1138                "href": "http://[::1]/",
1139                "host": "[::1]",
1140                "hostname": "[::1]",
1141                "port": ""
1142            }
1143        },
1144        {
1145            "comment": "Stuff after a : delimiter is ignored",
1146            "href": "http://example.net/path",
1147            "new_value": "example.com:8080",
1148            "expected": {
1149                "href": "http://example.com/path",
1150                "host": "example.com",
1151                "hostname": "example.com",
1152                "port": ""
1153            }
1154        },
1155        {
1156            "comment": "Stuff after a : delimiter is ignored",
1157            "href": "http://example.net:8080/path",
1158            "new_value": "example.com:",
1159            "expected": {
1160                "href": "http://example.com:8080/path",
1161                "host": "example.com:8080",
1162                "hostname": "example.com",
1163                "port": "8080"
1164            }
1165        },
1166        {
1167            "comment": "Stuff after a / delimiter is ignored",
1168            "href": "http://example.net/path",
1169            "new_value": "example.com/stuff",
1170            "expected": {
1171                "href": "http://example.com/path",
1172                "host": "example.com",
1173                "hostname": "example.com",
1174                "port": ""
1175            }
1176        },
1177        {
1178            "comment": "Stuff after a ? delimiter is ignored",
1179            "href": "http://example.net/path",
1180            "new_value": "example.com?stuff",
1181            "expected": {
1182                "href": "http://example.com/path",
1183                "host": "example.com",
1184                "hostname": "example.com",
1185                "port": ""
1186            }
1187        },
1188        {
1189            "comment": "Stuff after a # delimiter is ignored",
1190            "href": "http://example.net/path",
1191            "new_value": "example.com#stuff",
1192            "expected": {
1193                "href": "http://example.com/path",
1194                "host": "example.com",
1195                "hostname": "example.com",
1196                "port": ""
1197            }
1198        },
1199        {
1200            "comment": "Stuff after a \\ delimiter is ignored for special schemes",
1201            "href": "http://example.net/path",
1202            "new_value": "example.com\\stuff",
1203            "expected": {
1204                "href": "http://example.com/path",
1205                "host": "example.com",
1206                "hostname": "example.com",
1207                "port": ""
1208            }
1209        },
1210        {
1211            "comment": "\\ is not a delimiter for non-special schemes, but still forbidden in hosts",
1212            "href": "view-source+http://example.net/path",
1213            "new_value": "example.com\\stuff",
1214            "expected": {
1215                "href": "view-source+http://example.net/path",
1216                "host": "example.net",
1217                "hostname": "example.net",
1218                "port": ""
1219            }
1220        },
1221        {
1222            "comment": "Broken IPv6",
1223            "href": "http://example.net/",
1224            "new_value": "[google.com]",
1225            "expected": {
1226                "href": "http://example.net/",
1227                "host": "example.net",
1228                "hostname": "example.net"
1229            }
1230        },
1231        {
1232            "href": "http://example.net/",
1233            "new_value": "[::1.2.3.4x]",
1234            "expected": {
1235                "href": "http://example.net/",
1236                "host": "example.net",
1237                "hostname": "example.net"
1238            }
1239        },
1240        {
1241            "href": "http://example.net/",
1242            "new_value": "[::1.2.3.]",
1243            "expected": {
1244                "href": "http://example.net/",
1245                "host": "example.net",
1246                "hostname": "example.net"
1247            }
1248        },
1249        {
1250            "href": "http://example.net/",
1251            "new_value": "[::1.2.]",
1252            "expected": {
1253                "href": "http://example.net/",
1254                "host": "example.net",
1255                "hostname": "example.net"
1256            }
1257        },
1258        {
1259            "href": "http://example.net/",
1260            "new_value": "[::1.]",
1261            "expected": {
1262                "href": "http://example.net/",
1263                "host": "example.net",
1264                "hostname": "example.net"
1265            }
1266        },
1267        {
1268            "href": "file://y/",
1269            "new_value": "x:123",
1270            "expected": {
1271                "href": "file://y/",
1272                "host": "y",
1273                "hostname": "y",
1274                "port": ""
1275            }
1276        },
1277        {
1278            "href": "file://y/",
1279            "new_value": "loc%41lhost",
1280            "expected": {
1281                "href": "file:///",
1282                "host": "",
1283                "hostname": "",
1284                "port": ""
1285            }
1286        },
1287        {
1288            "href": "file://hi/x",
1289            "new_value": "",
1290            "expected": {
1291                "href": "file:///x",
1292                "host": "",
1293                "hostname": "",
1294                "port": ""
1295            }
1296        },
1297        {
1298            "href": "sc://test@test/",
1299            "new_value": "",
1300            "expected": {
1301                "href": "sc://test@test/",
1302                "host": "test",
1303                "hostname": "test",
1304                "username": "test"
1305            }
1306        },
1307        {
1308            "href": "sc://test:12/",
1309            "new_value": "",
1310            "expected": {
1311                "href": "sc://test:12/",
1312                "host": "test:12",
1313                "hostname": "test",
1314                "port": "12"
1315            }
1316        }
1317    ],
1318    "port": [
1319        {
1320            "href": "http://example.net",
1321            "new_value": "8080",
1322            "expected": {
1323                "href": "http://example.net:8080/",
1324                "host": "example.net:8080",
1325                "hostname": "example.net",
1326                "port": "8080"
1327            }
1328        },
1329        {
1330            "comment": "Port number is removed if empty is the new value",
1331            "href": "http://example.net:8080",
1332            "new_value": "",
1333            "expected": {
1334                "href": "http://example.net/",
1335                "host": "example.net",
1336                "hostname": "example.net",
1337                "port": ""
1338            }
1339        },
1340        {
1341            "comment": "Default port number is removed",
1342            "href": "http://example.net:8080",
1343            "new_value": "80",
1344            "expected": {
1345                "href": "http://example.net/",
1346                "host": "example.net",
1347                "hostname": "example.net",
1348                "port": ""
1349            }
1350        },
1351        {
1352            "comment": "Default port number is removed",
1353            "href": "https://example.net:4433",
1354            "new_value": "443",
1355            "expected": {
1356                "href": "https://example.net/",
1357                "host": "example.net",
1358                "hostname": "example.net",
1359                "port": ""
1360            }
1361        },
1362        {
1363            "comment": "Default port number is only removed for the relevant scheme",
1364            "href": "https://example.net",
1365            "new_value": "80",
1366            "expected": {
1367                "href": "https://example.net:80/",
1368                "host": "example.net:80",
1369                "hostname": "example.net",
1370                "port": "80"
1371            }
1372        },
1373        {
1374            "comment": "Stuff after a / delimiter is ignored",
1375            "href": "http://example.net/path",
1376            "new_value": "8080/stuff",
1377            "expected": {
1378                "href": "http://example.net:8080/path",
1379                "host": "example.net:8080",
1380                "hostname": "example.net",
1381                "port": "8080"
1382            }
1383        },
1384        {
1385            "comment": "Stuff after a ? delimiter is ignored",
1386            "href": "http://example.net/path",
1387            "new_value": "8080?stuff",
1388            "expected": {
1389                "href": "http://example.net:8080/path",
1390                "host": "example.net:8080",
1391                "hostname": "example.net",
1392                "port": "8080"
1393            }
1394        },
1395        {
1396            "comment": "Stuff after a # delimiter is ignored",
1397            "href": "http://example.net/path",
1398            "new_value": "8080#stuff",
1399            "expected": {
1400                "href": "http://example.net:8080/path",
1401                "host": "example.net:8080",
1402                "hostname": "example.net",
1403                "port": "8080"
1404            }
1405        },
1406        {
1407            "comment": "Stuff after a \\ delimiter is ignored for special schemes",
1408            "href": "http://example.net/path",
1409            "new_value": "8080\\stuff",
1410            "expected": {
1411                "href": "http://example.net:8080/path",
1412                "host": "example.net:8080",
1413                "hostname": "example.net",
1414                "port": "8080"
1415            }
1416        },
1417        {
1418            "comment": "Anything other than ASCII digit stops the port parser in a setter but is not an error",
1419            "href": "view-source+http://example.net/path",
1420            "new_value": "8080stuff2",
1421            "expected": {
1422                "href": "view-source+http://example.net:8080/path",
1423                "host": "example.net:8080",
1424                "hostname": "example.net",
1425                "port": "8080"
1426            }
1427        },
1428        {
1429            "comment": "Anything other than ASCII digit stops the port parser in a setter but is not an error",
1430            "href": "http://example.net/path",
1431            "new_value": "8080stuff2",
1432            "expected": {
1433                "href": "http://example.net:8080/path",
1434                "host": "example.net:8080",
1435                "hostname": "example.net",
1436                "port": "8080"
1437            }
1438        },
1439        {
1440            "comment": "Anything other than ASCII digit stops the port parser in a setter but is not an error",
1441            "href": "http://example.net/path",
1442            "new_value": "8080+2",
1443            "expected": {
1444                "href": "http://example.net:8080/path",
1445                "host": "example.net:8080",
1446                "hostname": "example.net",
1447                "port": "8080"
1448            }
1449        },
1450        {
1451            "comment": "Port numbers are 16 bit integers",
1452            "href": "http://example.net/path",
1453            "new_value": "65535",
1454            "expected": {
1455                "href": "http://example.net:65535/path",
1456                "host": "example.net:65535",
1457                "hostname": "example.net",
1458                "port": "65535"
1459            }
1460        },
1461        {
1462            "comment": "Port numbers are 16 bit integers, overflowing is an error",
1463            "href": "http://example.net:8080/path",
1464            "new_value": "65536",
1465            "expected": {
1466                "href": "http://example.net:8080/path",
1467                "host": "example.net:8080",
1468                "hostname": "example.net",
1469                "port": "8080"
1470            }
1471        },
1472        {
1473            "comment": "Port numbers are 16 bit integers, overflowing is an error",
1474            "href": "non-special://example.net:8080/path",
1475            "new_value": "65536",
1476            "expected": {
1477                "href": "non-special://example.net:8080/path",
1478                "host": "example.net:8080",
1479                "hostname": "example.net",
1480                "port": "8080"
1481            }
1482        },
1483        {
1484            "href": "file://test/",
1485            "new_value": "12",
1486            "expected": {
1487                "href": "file://test/",
1488                "port": ""
1489            }
1490        },
1491        {
1492            "href": "file://localhost/",
1493            "new_value": "12",
1494            "expected": {
1495                "href": "file:///",
1496                "port": ""
1497            }
1498        },
1499        {
1500            "href": "non-base:value",
1501            "new_value": "12",
1502            "expected": {
1503                "href": "non-base:value",
1504                "port": ""
1505            }
1506        },
1507        {
1508            "href": "sc:///",
1509            "new_value": "12",
1510            "expected": {
1511                "href": "sc:///",
1512                "port": ""
1513            }
1514        },
1515        {
1516            "href": "sc://x/",
1517            "new_value": "12",
1518            "expected": {
1519                "href": "sc://x:12/",
1520                "port": "12"
1521            }
1522        },
1523        {
1524            "href": "javascript://x/",
1525            "new_value": "12",
1526            "expected": {
1527                "href": "javascript://x:12/",
1528                "port": "12"
1529            }
1530        }
1531    ],
1532    "pathname": [
1533        {
1534            "comment": "Cannot-be-a-base don’t have a path",
1535            "href": "mailto:me@example.net",
1536            "new_value": "/foo",
1537            "expected": {
1538                "href": "mailto:me@example.net",
1539                "pathname": "me@example.net"
1540            }
1541        },
1542        {
1543            "href": "unix:/run/foo.socket?timeout=10",
1544            "new_value": "/var/log/../run/bar.socket",
1545            "expected": {
1546                "href": "unix:/var/run/bar.socket?timeout=10",
1547                "pathname": "/var/run/bar.socket"
1548            }
1549        },
1550        {
1551            "href": "https://example.net#nav",
1552            "new_value": "home",
1553            "expected": {
1554                "href": "https://example.net/home#nav",
1555                "pathname": "/home"
1556            }
1557        },
1558        {
1559            "href": "https://example.net#nav",
1560            "new_value": "../home",
1561            "expected": {
1562                "href": "https://example.net/home#nav",
1563                "pathname": "/home"
1564            }
1565        },
1566        {
1567            "comment": "\\ is a segment delimiter for 'special' URLs",
1568            "href": "http://example.net/home?lang=fr#nav",
1569            "new_value": "\\a\\%2E\\b\\%2e.\\c",
1570            "expected": {
1571                "href": "http://example.net/a/c?lang=fr#nav",
1572                "pathname": "/a/c"
1573            }
1574        },
1575        {
1576            "comment": "\\ is *not* a segment delimiter for non-'special' URLs",
1577            "href": "view-source+http://example.net/home?lang=fr#nav",
1578            "new_value": "\\a\\%2E\\b\\%2e.\\c",
1579            "expected": {
1580                "href": "view-source+http://example.net/\\a\\%2E\\b\\%2e.\\c?lang=fr#nav",
1581                "pathname": "/\\a\\%2E\\b\\%2e.\\c"
1582            }
1583        },
1584        {
1585            "comment": "UTF-8 percent encoding with the default encode set. Tabs and newlines are removed.",
1586            "href": "a:/",
1587            "new_value": "\u0000\u0001\t\n\r\u001f !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~\u007f\u0080\u0081Éé",
1588            "expected": {
1589                "href": "a:/%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E%3F@AZ[\\]^_%60az%7B|%7D~%7F%C2%80%C2%81%C3%89%C3%A9",
1590                "pathname": "/%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E%3F@AZ[\\]^_%60az%7B|%7D~%7F%C2%80%C2%81%C3%89%C3%A9"
1591            }
1592        },
1593        {
1594            "comment": "Bytes already percent-encoded are left as-is, including %2E outside dotted segments.",
1595            "href": "http://example.net",
1596            "new_value": "%2e%2E%c3%89té",
1597            "expected": {
1598                "href": "http://example.net/%2e%2E%c3%89t%C3%A9",
1599                "pathname": "/%2e%2E%c3%89t%C3%A9"
1600            }
1601        },
1602        {
1603            "comment": "? needs to be encoded",
1604            "href": "http://example.net",
1605            "new_value": "?",
1606            "expected": {
1607                "href": "http://example.net/%3F",
1608                "pathname": "/%3F"
1609            }
1610        },
1611        {
1612            "comment": "# needs to be encoded",
1613            "href": "http://example.net",
1614            "new_value": "#",
1615            "expected": {
1616                "href": "http://example.net/%23",
1617                "pathname": "/%23"
1618            }
1619        },
1620        {
1621            "comment": "? needs to be encoded, non-special scheme",
1622            "href": "sc://example.net",
1623            "new_value": "?",
1624            "expected": {
1625                "href": "sc://example.net/%3F",
1626                "pathname": "/%3F"
1627            }
1628        },
1629        {
1630            "comment": "# needs to be encoded, non-special scheme",
1631            "href": "sc://example.net",
1632            "new_value": "#",
1633            "expected": {
1634                "href": "sc://example.net/%23",
1635                "pathname": "/%23"
1636            }
1637        },
1638        {
1639            "comment": "File URLs and (back)slashes",
1640            "href": "file://monkey/",
1641            "new_value": "\\\\",
1642            "expected": {
1643                "href": "file://monkey/",
1644                "pathname": "/"
1645            }
1646        },
1647        {
1648            "comment": "File URLs and (back)slashes",
1649            "href": "file:///unicorn",
1650            "new_value": "//\\/",
1651            "expected": {
1652                "href": "file:///",
1653                "pathname": "/"
1654            }
1655        },
1656        {
1657            "comment": "File URLs and (back)slashes",
1658            "href": "file:///unicorn",
1659            "new_value": "//monkey/..//",
1660            "expected": {
1661                "href": "file:///",
1662                "pathname": "/"
1663            }
1664        }
1665    ],
1666    "search": [
1667        {
1668            "href": "https://example.net#nav",
1669            "new_value": "lang=fr",
1670            "expected": {
1671                "href": "https://example.net/?lang=fr#nav",
1672                "search": "?lang=fr"
1673            }
1674        },
1675        {
1676            "href": "https://example.net?lang=en-US#nav",
1677            "new_value": "lang=fr",
1678            "expected": {
1679                "href": "https://example.net/?lang=fr#nav",
1680                "search": "?lang=fr"
1681            }
1682        },
1683        {
1684            "href": "https://example.net?lang=en-US#nav",
1685            "new_value": "?lang=fr",
1686            "expected": {
1687                "href": "https://example.net/?lang=fr#nav",
1688                "search": "?lang=fr"
1689            }
1690        },
1691        {
1692            "href": "https://example.net?lang=en-US#nav",
1693            "new_value": "??lang=fr",
1694            "expected": {
1695                "href": "https://example.net/??lang=fr#nav",
1696                "search": "??lang=fr"
1697            }
1698        },
1699        {
1700            "href": "https://example.net?lang=en-US#nav",
1701            "new_value": "?",
1702            "expected": {
1703                "href": "https://example.net/?#nav",
1704                "search": ""
1705            }
1706        },
1707        {
1708            "href": "https://example.net?lang=en-US#nav",
1709            "new_value": "",
1710            "expected": {
1711                "href": "https://example.net/#nav",
1712                "search": ""
1713            }
1714        },
1715        {
1716            "href": "https://example.net?lang=en-US",
1717            "new_value": "",
1718            "expected": {
1719                "href": "https://example.net/",
1720                "search": ""
1721            }
1722        },
1723        {
1724            "href": "https://example.net",
1725            "new_value": "",
1726            "expected": {
1727                "href": "https://example.net/",
1728                "search": ""
1729            }
1730        },
1731        {
1732            "comment": "UTF-8 percent encoding with the query encode set. Tabs and newlines are removed.",
1733            "href": "a:/",
1734            "new_value": "\u0000\u0001\t\n\r\u001f !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~\u007f\u0080\u0081Éé",
1735            "expected": {
1736                "href": "a:/?%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9",
1737                "search": "?%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9"
1738            }
1739        },
1740        {
1741            "comment": "Bytes already percent-encoded are left as-is",
1742            "href": "http://example.net",
1743            "new_value": "%c3%89té",
1744            "expected": {
1745                "href": "http://example.net/?%c3%89t%C3%A9",
1746                "search": "?%c3%89t%C3%A9"
1747            }
1748        }
1749    ],
1750    "hash": [
1751        {
1752            "href": "https://example.net",
1753            "new_value": "main",
1754            "expected": {
1755                "href": "https://example.net/#main",
1756                "hash": "#main"
1757            }
1758        },
1759        {
1760            "href": "https://example.net#nav",
1761            "new_value": "main",
1762            "expected": {
1763                "href": "https://example.net/#main",
1764                "hash": "#main"
1765            }
1766        },
1767        {
1768            "href": "https://example.net?lang=en-US",
1769            "new_value": "##nav",
1770            "expected": {
1771                "href": "https://example.net/?lang=en-US##nav",
1772                "hash": "##nav"
1773            }
1774        },
1775        {
1776            "href": "https://example.net?lang=en-US#nav",
1777            "new_value": "#main",
1778            "expected": {
1779                "href": "https://example.net/?lang=en-US#main",
1780                "hash": "#main"
1781            }
1782        },
1783        {
1784            "href": "https://example.net?lang=en-US#nav",
1785            "new_value": "#",
1786            "expected": {
1787                "href": "https://example.net/?lang=en-US#",
1788                "hash": ""
1789            }
1790        },
1791        {
1792            "href": "https://example.net?lang=en-US#nav",
1793            "new_value": "",
1794            "expected": {
1795                "href": "https://example.net/?lang=en-US",
1796                "hash": ""
1797            }
1798        },
1799        {
1800            "href": "http://example.net",
1801            "new_value": "#foo bar",
1802            "expected": {
1803                "href": "http://example.net/#foo%20bar",
1804                "hash": "#foo%20bar"
1805            }
1806        },
1807        {
1808            "href": "http://example.net",
1809            "new_value": "#foo\"bar",
1810            "expected": {
1811                "href": "http://example.net/#foo%22bar",
1812                "hash": "#foo%22bar"
1813            }
1814        },
1815        {
1816            "href": "http://example.net",
1817            "new_value": "#foo<bar",
1818            "expected": {
1819                "href": "http://example.net/#foo%3Cbar",
1820                "hash": "#foo%3Cbar"
1821            }
1822        },
1823        {
1824            "href": "http://example.net",
1825            "new_value": "#foo>bar",
1826            "expected": {
1827                "href": "http://example.net/#foo%3Ebar",
1828                "hash": "#foo%3Ebar"
1829            }
1830        },
1831        {
1832            "href": "http://example.net",
1833            "new_value": "#foo`bar",
1834            "expected": {
1835                "href": "http://example.net/#foo%60bar",
1836                "hash": "#foo%60bar"
1837            }
1838        },
1839        {
1840            "comment": "Simple percent-encoding; nuls, tabs, and newlines are removed",
1841            "href": "a:/",
1842            "new_value": "\u0000\u0001\t\n\r\u001f !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~\u007f\u0080\u0081Éé",
1843            "expected": {
1844                "href": "a:/#%01%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9",
1845                "hash": "#%01%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9"
1846            }
1847        },
1848        {
1849            "comment": "Bytes already percent-encoded are left as-is",
1850            "href": "http://example.net",
1851            "new_value": "%c3%89té",
1852            "expected": {
1853                "href": "http://example.net/#%c3%89t%C3%A9",
1854                "hash": "#%c3%89t%C3%A9"
1855            }
1856        },
1857        {
1858            "href": "javascript:alert(1)",
1859            "new_value": "castle",
1860            "expected": {
1861                "href": "javascript:alert(1)#castle",
1862                "hash": "#castle"
1863            }
1864        }
1865    ]
1866}
1867