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