1 var common = require('../common');
2 var assert = require('assert');
4 var url = require('url'),
5 util = require('util');
7 // URLs to parse, and expected data
11 'href': '//some_path',
12 'pathname': '//some_path',
16 'http:\\\\evil-phisher\\foo.html#h\\a\\s\\h': {
20 hostname: 'evil-phisher',
21 pathname: '/foo.html',
23 hash: '#h%5Ca%5Cs%5Ch',
24 href: 'http://evil-phisher/foo.html#h%5Ca%5Cs%5Ch'
27 'http:\\\\evil-phisher\\foo.html?json="\\"foo\\""#h\\a\\s\\h': {
31 hostname: 'evil-phisher',
32 pathname: '/foo.html',
33 search: '?json=%22%5C%22foo%5C%22%22',
34 query: 'json=%22%5C%22foo%5C%22%22',
35 path: '/foo.html?json=%22%5C%22foo%5C%22%22',
36 hash: '#h%5Ca%5Cs%5Ch',
37 href: 'http://evil-phisher/foo.html?json=%22%5C%22foo%5C%22%22#h%5Ca%5Cs%5Ch'
40 'http:\\\\evil-phisher\\foo.html#h\\a\\s\\h?blarg': {
44 hostname: 'evil-phisher',
45 pathname: '/foo.html',
47 hash: '#h%5Ca%5Cs%5Ch?blarg',
48 href: 'http://evil-phisher/foo.html#h%5Ca%5Cs%5Ch?blarg'
52 'http:\\\\evil-phisher\\foo.html': {
56 hostname: 'evil-phisher',
57 pathname: '/foo.html',
59 href: 'http://evil-phisher/foo.html'
62 'HTTP://www.example.com/' : {
63 'href': 'http://www.example.com/',
66 'host': 'www.example.com',
67 'hostname': 'www.example.com',
72 'HTTP://www.example.com' : {
73 'href': 'http://www.example.com/',
76 'host': 'www.example.com',
77 'hostname': 'www.example.com',
82 'http://www.ExAmPlE.com/' : {
83 'href': 'http://www.example.com/',
86 'host': 'www.example.com',
87 'hostname': 'www.example.com',
92 'http://user:pw@www.ExAmPlE.com/' : {
93 'href': 'http://user:pw@www.example.com/',
97 'host': 'www.example.com',
98 'hostname': 'www.example.com',
103 'http://USER:PW@www.ExAmPlE.com/' : {
104 'href': 'http://USER:PW@www.example.com/',
108 'host': 'www.example.com',
109 'hostname': 'www.example.com',
114 'http://user@www.example.com/' : {
115 'href': 'http://user@www.example.com/',
119 'host': 'www.example.com',
120 'hostname': 'www.example.com',
125 'http://user%3Apw@www.example.com/' : {
126 'href': 'http://user:pw@www.example.com/',
130 'host': 'www.example.com',
131 'hostname': 'www.example.com',
136 'http://x.com/path?that\'s#all, folks' : {
137 'href': 'http://x.com/path?that%27s#all,%20folks',
142 'search': '?that%27s',
145 'hash': '#all,%20folks',
146 'path': '/path?that%27s'
150 'href': 'http://x.com/Y',
159 // + not an invalid host character
160 // per https://url.spec.whatwg.org/#host-parsing
161 'http://x.y.com+a/b/c' : {
162 'href': 'http://x.y.com+a/b/c',
166 'hostname': 'x.y.com+a',
171 // an unexpected invalid char in the hostname.
172 'HtTp://x.y.cOm;a/b/c?d=e#f g<h>i' : {
173 'href': 'http://x.y.com/;a/b/c?d=e#f%20g%3Ch%3Ei',
177 'hostname': 'x.y.com',
178 'pathname': ';a/b/c',
181 'hash': '#f%20g%3Ch%3Ei',
185 // make sure that we don't accidentally lcast the path parts.
186 'HtTp://x.y.cOm;A/b/c?d=e#f g<h>i' : {
187 'href': 'http://x.y.com/;A/b/c?d=e#f%20g%3Ch%3Ei',
191 'hostname': 'x.y.com',
192 'pathname': ';A/b/c',
195 'hash': '#f%20g%3Ch%3Ei',
199 'http://x...y...#p': {
200 'href': 'http://x...y.../#p',
204 'hostname': 'x...y...',
210 'http://x/p/"quoted"': {
211 'href': 'http://x/p/%22quoted%22',
216 'pathname': '/p/%22quoted%22',
217 'path': '/p/%22quoted%22'
220 '<http://goo.corn/bread> Is a URL!': {
221 'href': '%3Chttp://goo.corn/bread%3E%20Is%20a%20URL!',
222 'pathname': '%3Chttp://goo.corn/bread%3E%20Is%20a%20URL!',
223 'path': '%3Chttp://goo.corn/bread%3E%20Is%20a%20URL!'
226 'http://www.narwhaljs.org/blog/categories?id=news' : {
227 'href': 'http://www.narwhaljs.org/blog/categories?id=news',
230 'host': 'www.narwhaljs.org',
231 'hostname': 'www.narwhaljs.org',
232 'search': '?id=news',
234 'pathname': '/blog/categories',
235 'path': '/blog/categories?id=news'
238 'http://mt0.google.com/vt/lyrs=m@114&hl=en&src=api&x=2&y=2&z=3&s=' : {
239 'href': 'http://mt0.google.com/vt/lyrs=m@114&hl=en&src=api&x=2&y=2&z=3&s=',
242 'host': 'mt0.google.com',
243 'hostname': 'mt0.google.com',
244 'pathname': '/vt/lyrs=m@114&hl=en&src=api&x=2&y=2&z=3&s=',
245 'path': '/vt/lyrs=m@114&hl=en&src=api&x=2&y=2&z=3&s='
248 'http://mt0.google.com/vt/lyrs=m@114???&hl=en&src=api&x=2&y=2&z=3&s=' : {
249 'href': 'http://mt0.google.com/vt/lyrs=m@114???&hl=en&src=api' +
253 'host': 'mt0.google.com',
254 'hostname': 'mt0.google.com',
255 'search': '???&hl=en&src=api&x=2&y=2&z=3&s=',
256 'query': '??&hl=en&src=api&x=2&y=2&z=3&s=',
257 'pathname': '/vt/lyrs=m@114',
258 'path': '/vt/lyrs=m@114???&hl=en&src=api&x=2&y=2&z=3&s='
261 'http://user:pass@mt0.google.com/vt/lyrs=m@114???&hl=en&src=api&x=2&y=2&z=3&s=':
263 'href': 'http://user:pass@mt0.google.com/vt/lyrs=m@114???' +
264 '&hl=en&src=api&x=2&y=2&z=3&s=',
267 'host': 'mt0.google.com',
269 'hostname': 'mt0.google.com',
270 'search': '???&hl=en&src=api&x=2&y=2&z=3&s=',
271 'query': '??&hl=en&src=api&x=2&y=2&z=3&s=',
272 'pathname': '/vt/lyrs=m@114',
273 'path': '/vt/lyrs=m@114???&hl=en&src=api&x=2&y=2&z=3&s='
276 'file:///etc/passwd' : {
277 'href': 'file:///etc/passwd',
280 'pathname': '/etc/passwd',
283 'path': '/etc/passwd'
286 'file://localhost/etc/passwd' : {
287 'href': 'file://localhost/etc/passwd',
290 'pathname': '/etc/passwd',
291 'hostname': 'localhost',
293 'path': '/etc/passwd'
296 'file://foo/etc/passwd' : {
297 'href': 'file://foo/etc/passwd',
300 'pathname': '/etc/passwd',
303 'path': '/etc/passwd'
306 'file:///etc/node/' : {
307 'href': 'file:///etc/node/',
310 'pathname': '/etc/node/',
316 'file://localhost/etc/node/' : {
317 'href': 'file://localhost/etc/node/',
320 'pathname': '/etc/node/',
321 'hostname': 'localhost',
326 'file://foo/etc/node/' : {
327 'href': 'file://foo/etc/node/',
330 'pathname': '/etc/node/',
336 'http:/baz/../foo/bar' : {
337 'href': 'http:/baz/../foo/bar',
339 'pathname': '/baz/../foo/bar',
340 'path': '/baz/../foo/bar'
343 'http://user:pass@example.com:8000/foo/bar?baz=quux#frag' : {
344 'href': 'http://user:pass@example.com:8000/foo/bar?baz=quux#frag',
347 'host': 'example.com:8000',
350 'hostname': 'example.com',
352 'search': '?baz=quux',
354 'pathname': '/foo/bar',
355 'path': '/foo/bar?baz=quux'
358 '//user:pass@example.com:8000/foo/bar?baz=quux#frag' : {
359 'href': '//user:pass@example.com:8000/foo/bar?baz=quux#frag',
361 'host': 'example.com:8000',
364 'hostname': 'example.com',
366 'search': '?baz=quux',
368 'pathname': '/foo/bar',
369 'path': '/foo/bar?baz=quux'
372 '/foo/bar?baz=quux#frag' : {
373 'href': '/foo/bar?baz=quux#frag',
375 'search': '?baz=quux',
377 'pathname': '/foo/bar',
378 'path': '/foo/bar?baz=quux'
381 'http:/foo/bar?baz=quux#frag' : {
382 'href': 'http:/foo/bar?baz=quux#frag',
385 'search': '?baz=quux',
387 'pathname': '/foo/bar',
388 'path': '/foo/bar?baz=quux'
391 'mailto:foo@bar.com?subject=hello' : {
392 'href': 'mailto:foo@bar.com?subject=hello',
393 'protocol': 'mailto:',
396 'hostname' : 'bar.com',
397 'search': '?subject=hello',
398 'query': 'subject=hello',
399 'path': '?subject=hello'
402 'javascript:alert(\'hello\');' : {
403 'href': 'javascript:alert(\'hello\');',
404 'protocol': 'javascript:',
405 'pathname': 'alert(\'hello\');',
406 'path': 'alert(\'hello\');'
409 'xmpp:isaacschlueter@jabber.org' : {
410 'href': 'xmpp:isaacschlueter@jabber.org',
412 'host': 'jabber.org',
413 'auth': 'isaacschlueter',
414 'hostname': 'jabber.org'
417 'http://atpass:foo%40bar@127.0.0.1:8080/path?search=foo#bar' : {
418 'href' : 'http://atpass:foo%40bar@127.0.0.1:8080/path?search=foo#bar',
419 'protocol' : 'http:',
421 'host' : '127.0.0.1:8080',
422 'auth' : 'atpass:foo@bar',
423 'hostname' : '127.0.0.1',
426 'search' : '?search=foo',
427 'query' : 'search=foo',
429 'path': '/path?search=foo'
432 'svn+ssh://foo/bar': {
433 'href': 'svn+ssh://foo/bar',
436 'protocol': 'svn+ssh:',
442 'dash-test://foo/bar': {
443 'href': 'dash-test://foo/bar',
446 'protocol': 'dash-test:',
452 'dash-test:foo/bar': {
453 'href': 'dash-test:foo/bar',
456 'protocol': 'dash-test:',
461 'dot.test://foo/bar': {
462 'href': 'dot.test://foo/bar',
465 'protocol': 'dot.test:',
471 'dot.test:foo/bar': {
472 'href': 'dot.test:foo/bar',
475 'protocol': 'dot.test:',
481 'http://www.日本語.com/' : {
482 'href': 'http://www.xn--wgv71a119e.com/',
485 'host': 'www.xn--wgv71a119e.com',
486 'hostname': 'www.xn--wgv71a119e.com',
491 'http://example.Bücher.com/' : {
492 'href': 'http://example.xn--bcher-kva.com/',
495 'host': 'example.xn--bcher-kva.com',
496 'hostname': 'example.xn--bcher-kva.com',
501 'http://www.Äffchen.com/' : {
502 'href': 'http://www.xn--ffchen-9ta.com/',
505 'host': 'www.xn--ffchen-9ta.com',
506 'hostname': 'www.xn--ffchen-9ta.com',
511 'http://www.Äffchen.cOm;A/b/c?d=e#f g<h>i' : {
512 'href': 'http://www.xn--ffchen-9ta.com/;A/b/c?d=e#f%20g%3Ch%3Ei',
515 'host': 'www.xn--ffchen-9ta.com',
516 'hostname': 'www.xn--ffchen-9ta.com',
517 'pathname': ';A/b/c',
520 'hash': '#f%20g%3Ch%3Ei',
524 'http://SÉLIER.COM/' : {
525 'href': 'http://xn--slier-bsa.com/',
528 'host': 'xn--slier-bsa.com',
529 'hostname': 'xn--slier-bsa.com',
534 'http://ليهمابتكلموشعربي؟.ي؟/' : {
535 'href': 'http://xn--egbpdaj6bu4bxfgehfvwxn.xn--egb9f/',
538 'host': 'xn--egbpdaj6bu4bxfgehfvwxn.xn--egb9f',
539 'hostname': 'xn--egbpdaj6bu4bxfgehfvwxn.xn--egb9f',
544 'http://âž¡.ws/âž¡' : {
545 'href': 'http://xn--hgi.ws/âž¡',
548 'host': 'xn--hgi.ws',
549 'hostname': 'xn--hgi.ws',
554 'http://bucket_name.s3.amazonaws.com/image.jpg': {
558 host: 'bucket_name.s3.amazonaws.com',
559 hostname: 'bucket_name.s3.amazonaws.com',
560 pathname: '/image.jpg',
561 href: 'http://bucket_name.s3.amazonaws.com/image.jpg',
565 'git+http://github.com/joyent/node.git': {
566 protocol: 'git+http:',
569 hostname: 'github.com',
570 pathname: '/joyent/node.git',
571 path: '/joyent/node.git',
572 href: 'git+http://github.com/joyent/node.git'
575 //if local1@domain1 is uses as a relative URL it may
576 //be parse into auth@hostname, but here there is no
577 //way to make it work in url.parse, I add the test to be explicit
579 'pathname': 'local1@domain1',
580 'path': 'local1@domain1',
581 'href': 'local1@domain1'
584 //While this may seem counter-intuitive, a browser will parse
585 //<a href='www.google.com'> as a path.
586 'www.example.com' : {
587 'href': 'www.example.com',
588 'pathname': 'www.example.com',
589 'path': 'www.example.com'
595 'pathname': '[fe80::1]',
599 'coap://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]': {
602 'host': '[fedc:ba98:7654:3210:fedc:ba98:7654:3210]',
603 'hostname': 'fedc:ba98:7654:3210:fedc:ba98:7654:3210',
604 'href': 'coap://[fedc:ba98:7654:3210:fedc:ba98:7654:3210]/',
609 'coap://[1080:0:0:0:8:800:200C:417A]:61616/': {
612 'host': '[1080:0:0:0:8:800:200c:417a]:61616',
614 'hostname': '1080:0:0:0:8:800:200c:417a',
615 'href': 'coap://[1080:0:0:0:8:800:200c:417a]:61616/',
620 'http://user:password@[3ffe:2a00:100:7031::1]:8080': {
623 'auth': 'user:password',
624 'host': '[3ffe:2a00:100:7031::1]:8080',
626 'hostname': '3ffe:2a00:100:7031::1',
627 'href': 'http://user:password@[3ffe:2a00:100:7031::1]:8080/',
632 'coap://u:p@[::192.9.5.5]:61616/.well-known/r?n=Temperature': {
636 'host': '[::192.9.5.5]:61616',
638 'hostname': '::192.9.5.5',
639 'href': 'coap://u:p@[::192.9.5.5]:61616/.well-known/r?n=Temperature',
640 'search': '?n=Temperature',
641 'query': 'n=Temperature',
642 'pathname': '/.well-known/r',
643 'path': '/.well-known/r?n=Temperature'
647 'http://example.com:': {
650 'host': 'example.com',
651 'hostname': 'example.com',
652 'href': 'http://example.com/',
657 'http://example.com:/a/b.html': {
660 'host': 'example.com',
661 'hostname': 'example.com',
662 'href': 'http://example.com/a/b.html',
663 'pathname': '/a/b.html',
667 'http://example.com:?a=b': {
670 'host': 'example.com',
671 'hostname': 'example.com',
672 'href': 'http://example.com/?a=b',
679 'http://example.com:#abc': {
682 'host': 'example.com',
683 'hostname': 'example.com',
684 'href': 'http://example.com/#abc',
690 'http://[fe80::1]:/a/b?a=b#abc': {
694 'hostname': 'fe80::1',
695 'href': 'http://[fe80::1]/a/b?a=b#abc',
703 'http://-lovemonsterz.tumblr.com/rss': {
706 'host': '-lovemonsterz.tumblr.com',
707 'hostname': '-lovemonsterz.tumblr.com',
708 'href': 'http://-lovemonsterz.tumblr.com/rss',
713 'http://-lovemonsterz.tumblr.com:80/rss': {
717 'host': '-lovemonsterz.tumblr.com:80',
718 'hostname': '-lovemonsterz.tumblr.com',
719 'href': 'http://-lovemonsterz.tumblr.com:80/rss',
724 'http://user:pass@-lovemonsterz.tumblr.com/rss': {
728 'host': '-lovemonsterz.tumblr.com',
729 'hostname': '-lovemonsterz.tumblr.com',
730 'href': 'http://user:pass@-lovemonsterz.tumblr.com/rss',
735 'http://user:pass@-lovemonsterz.tumblr.com:80/rss': {
740 'host': '-lovemonsterz.tumblr.com:80',
741 'hostname': '-lovemonsterz.tumblr.com',
742 'href': 'http://user:pass@-lovemonsterz.tumblr.com:80/rss',
747 'http://_jabber._tcp.google.com/test': {
750 'host': '_jabber._tcp.google.com',
751 'hostname': '_jabber._tcp.google.com',
752 'href': 'http://_jabber._tcp.google.com/test',
757 'http://user:pass@_jabber._tcp.google.com/test': {
761 'host': '_jabber._tcp.google.com',
762 'hostname': '_jabber._tcp.google.com',
763 'href': 'http://user:pass@_jabber._tcp.google.com/test',
768 'http://_jabber._tcp.google.com:80/test': {
772 'host': '_jabber._tcp.google.com:80',
773 'hostname': '_jabber._tcp.google.com',
774 'href': 'http://_jabber._tcp.google.com:80/test',
779 'http://user:pass@_jabber._tcp.google.com:80/test': {
784 'host': '_jabber._tcp.google.com:80',
785 'hostname': '_jabber._tcp.google.com',
786 'href': 'http://user:pass@_jabber._tcp.google.com:80/test',
791 'http://x:1/\' <>"`/{}|\\^~`/': {
797 pathname: '/%27%20%3C%3E%22%60/%7B%7D%7C/%5E~%60/',
798 path: '/%27%20%3C%3E%22%60/%7B%7D%7C/%5E~%60/',
799 href: 'http://x:1/%27%20%3C%3E%22%60/%7B%7D%7C/%5E~%60/'
808 href: 'http://a%40b@c/',
819 href: 'http://a@b/?@c',
826 'http://a\r" \t\n<\'b:b@c\r\nd/e?f':{
829 auth: 'a\r" \t\n<\'b:b',
836 pathname: '%0D%0Ad/e',
838 href: 'http://a%0D%22%20%09%0A%3C\'b:b@c/%0D%0Ad/e?f'
841 // git urls used by npm
842 'git+ssh://git@github.com:npm/npm': {
843 protocol: 'git+ssh:',
848 hostname: 'github.com',
852 pathname: '/:npm/npm',
854 href: 'git+ssh://git@github.com/:npm/npm'
859 for (var u in parseTests) {
860 var actual = url.parse(u),
861 spaced = url.parse(' \t ' + u + '\n\t');
862 expected = parseTests[u];
864 Object.keys(actual).forEach(function (i) {
865 if (expected[i] === undefined && actual[i] === null) {
870 assert.deepEqual(actual, expected);
871 assert.deepEqual(spaced, expected);
873 var expected = parseTests[u].href,
874 actual = url.format(parseTests[u]);
876 assert.equal(actual, expected,
877 'format(' + u + ') == ' + u + '\nactual:' + actual);
880 var parseTestsWithQueryString = {
881 '/foo/bar?baz=quux#frag' : {
882 'href': '/foo/bar?baz=quux#frag',
884 'search': '?baz=quux',
888 'pathname': '/foo/bar',
889 'path': '/foo/bar?baz=quux'
891 'http://example.com' : {
892 'href': 'http://example.com/',
895 'host': 'example.com',
896 'hostname': 'example.com',
912 pathname: '/example',
916 '/example?query=value':{
924 search: '?query=value',
925 query: { query: 'value' },
926 pathname: '/example',
927 path: '/example?query=value',
928 href: '/example?query=value'
931 for (var u in parseTestsWithQueryString) {
932 var actual = url.parse(u, true);
933 var expected = parseTestsWithQueryString[u];
934 for (var i in actual) {
935 if (actual[i] === null && expected[i] === undefined) {
940 assert.deepEqual(actual, expected);
943 // some extra formatting tests, just to verify
944 // that it'll format slightly wonky content to a valid url.
946 'http://example.com?' : {
947 'href': 'http://example.com/?',
950 'host': 'example.com',
951 'hostname': 'example.com',
956 'http://example.com?foo=bar#frag' : {
957 'href': 'http://example.com/?foo=bar#frag',
959 'host': 'example.com',
960 'hostname': 'example.com',
962 'search': '?foo=bar',
966 'http://example.com?foo=@bar#frag' : {
967 'href': 'http://example.com/?foo=@bar#frag',
969 'host': 'example.com',
970 'hostname': 'example.com',
972 'search': '?foo=@bar',
976 'http://example.com?foo=/bar/#frag' : {
977 'href': 'http://example.com/?foo=/bar/#frag',
979 'host': 'example.com',
980 'hostname': 'example.com',
982 'search': '?foo=/bar/',
983 'query': 'foo=/bar/',
986 'http://example.com?foo=?bar/#frag' : {
987 'href': 'http://example.com/?foo=?bar/#frag',
989 'host': 'example.com',
990 'hostname': 'example.com',
992 'search': '?foo=?bar/',
993 'query': 'foo=?bar/',
996 'http://example.com#frag=?bar/#frag' : {
997 'href': 'http://example.com/#frag=?bar/#frag',
999 'host': 'example.com',
1000 'hostname': 'example.com',
1001 'hash': '#frag=?bar/#frag',
1004 'http://google.com" onload="alert(42)/' : {
1005 'href': 'http://google.com/%22%20onload=%22alert(42)/',
1006 'protocol': 'http:',
1007 'host': 'google.com',
1008 'pathname': '/%22%20onload=%22alert(42)/'
1010 'http://a.com/a/b/c?s#h' : {
1011 'href': 'http://a.com/a/b/c?s#h',
1014 'pathname': 'a/b/c',
1018 'xmpp:isaacschlueter@jabber.org' : {
1019 'href': 'xmpp:isaacschlueter@jabber.org',
1020 'protocol': 'xmpp:',
1021 'host': 'jabber.org',
1022 'auth': 'isaacschlueter',
1023 'hostname': 'jabber.org'
1025 'http://atpass:foo%40bar@127.0.0.1/' : {
1026 'href': 'http://atpass:foo%40bar@127.0.0.1/',
1027 'auth': 'atpass:foo@bar',
1028 'hostname': '127.0.0.1',
1029 'protocol': 'http:',
1032 'http://atslash%2F%40:%2F%40@foo/' : {
1033 'href': 'http://atslash%2F%40:%2F%40@foo/',
1034 'auth': 'atslash/@:/@',
1036 'protocol': 'http:',
1039 'svn+ssh://foo/bar': {
1040 'href': 'svn+ssh://foo/bar',
1042 'protocol': 'svn+ssh:',
1046 'dash-test://foo/bar': {
1047 'href': 'dash-test://foo/bar',
1049 'protocol': 'dash-test:',
1053 'dash-test:foo/bar': {
1054 'href': 'dash-test:foo/bar',
1056 'protocol': 'dash-test:',
1059 'dot.test://foo/bar': {
1060 'href': 'dot.test://foo/bar',
1062 'protocol': 'dot.test:',
1066 'dot.test:foo/bar': {
1067 'href': 'dot.test:foo/bar',
1069 'protocol': 'dot.test:',
1073 'coap:u:p@[::1]:61616/.well-known/r?n=Temperature': {
1074 'href': 'coap:u:p@[::1]:61616/.well-known/r?n=Temperature',
1075 'protocol': 'coap:',
1079 'pathname': '/.well-known/r',
1080 'search': 'n=Temperature'
1082 'coap:[fedc:ba98:7654:3210:fedc:ba98:7654:3210]:61616/s/stopButton': {
1083 'href': 'coap:[fedc:ba98:7654:3210:fedc:ba98:7654:3210]:61616/s/stopButton',
1085 'host': '[fedc:ba98:7654:3210:fedc:ba98:7654:3210]:61616',
1086 'pathname': '/s/stopButton'
1089 // encode context-specific delimiters in path and query, but do not touch
1090 // other non-delimiter chars like `%`.
1091 // <https://github.com/joyent/node/issues/4082>
1094 '/path/to/%%23%3F+=&.txt?foo=theA1#bar' : {
1095 href : '/path/to/%%23%3F+=&.txt?foo=theA1#bar',
1096 pathname: '/path/to/%#?+=&.txt',
1103 // `#`,`?` in path + `#` in query
1104 '/path/to/%%23%3F+=&.txt?foo=the%231#bar' : {
1105 href : '/path/to/%%23%3F+=&.txt?foo=the%231#bar',
1106 pathname: '/path/to/%#?+=&.txt',
1113 // `?` and `#` in path and search
1114 'http://ex.com/foo%3F100%m%23r?abc=the%231?&foo=bar#frag': {
1115 href: 'http://ex.com/foo%3F100%m%23r?abc=the%231?&foo=bar#frag',
1119 search: '?abc=the#1?&foo=bar',
1120 pathname: '/foo?100%m#r',
1123 // `?` and `#` in search only
1124 'http://ex.com/fooA100%mBr?abc=the%231?&foo=bar#frag': {
1125 href: 'http://ex.com/fooA100%mBr?abc=the%231?&foo=bar#frag',
1129 search: '?abc=the#1?&foo=bar',
1130 pathname: '/fooA100%mBr',
1133 for (var u in formatTests) {
1134 var expect = formatTests[u].href;
1135 delete formatTests[u].href;
1136 var actual = url.format(u);
1137 var actualObj = url.format(formatTests[u]);
1138 assert.equal(actual, expect,
1139 'wonky format(' + u + ') == ' + expect +
1140 '\nactual:' + actual);
1141 assert.equal(actualObj, expect,
1142 'wonky format(' + JSON.stringify(formatTests[u]) +
1144 '\nactual: ' + actualObj);
1148 [from, path, expected]
1150 var relativeTests = [
1151 ['/foo/bar/baz', 'quux', '/foo/bar/quux'],
1152 ['/foo/bar/baz', 'quux/asdf', '/foo/bar/quux/asdf'],
1153 ['/foo/bar/baz', 'quux/baz', '/foo/bar/quux/baz'],
1154 ['/foo/bar/baz', '../quux/baz', '/foo/quux/baz'],
1155 ['/foo/bar/baz', '/bar', '/bar'],
1156 ['/foo/bar/baz/', 'quux', '/foo/bar/baz/quux'],
1157 ['/foo/bar/baz/', 'quux/baz', '/foo/bar/baz/quux/baz'],
1158 ['/foo/bar/baz', '../../../../../../../../quux/baz', '/quux/baz'],
1159 ['/foo/bar/baz', '../../../../../../../quux/baz', '/quux/baz'],
1161 ['/foo', '..', '/'],
1162 ['/foo/', '.', '/foo/'],
1163 ['/foo/', '..', '/'],
1164 ['/foo/bar', '.', '/foo/'],
1165 ['/foo/bar', '..', '/'],
1166 ['/foo/bar/', '.', '/foo/bar/'],
1167 ['/foo/bar/', '..', '/foo/'],
1168 ['foo/bar', '../../../baz', '../../baz'],
1169 ['foo/bar/', '../../../baz', '../baz'],
1170 ['http://example.com/b//c//d;p?q#blarg', 'https:#hash2', 'https:///#hash2'],
1171 ['http://example.com/b//c//d;p?q#blarg',
1172 'https:/p/a/t/h?s#hash2',
1173 'https://p/a/t/h?s#hash2'],
1174 ['http://example.com/b//c//d;p?q#blarg',
1175 'https://u:p@h.com/p/a/t/h?s#hash2',
1176 'https://u:p@h.com/p/a/t/h?s#hash2'],
1177 ['http://example.com/b//c//d;p?q#blarg',
1180 ['http://example.com/b//c//d;p?q#blarg',
1182 'http://example.com/b//c//d;p?q#hash2'],
1183 ['http://example.com/b//c//d;p?q#blarg',
1184 'http:/p/a/t/h?s#hash2',
1185 'http://example.com/p/a/t/h?s#hash2'],
1186 ['http://example.com/b//c//d;p?q#blarg',
1187 'http://u:p@h.com/p/a/t/h?s#hash2',
1188 'http://u:p@h.com/p/a/t/h?s#hash2'],
1189 ['http://example.com/b//c//d;p?q#blarg',
1191 'http://example.com/a/b/c/d'],
1192 ['/foo/bar/baz', '/../etc/passwd', '/etc/passwd'],
1193 ['http://localhost', 'file:///Users/foo', 'file:///Users/foo'],
1194 ['http://localhost', 'file://foo/Users', 'file://foo/Users']
1196 relativeTests.forEach(function(relativeTest) {
1197 var a = url.resolve(relativeTest[0], relativeTest[1]),
1198 e = relativeTest[2];
1200 'resolve(' + [relativeTest[0], relativeTest[1]] + ') == ' + e +
1205 // https://github.com/joyent/node/issues/568
1215 ].forEach(function(val) {
1216 assert.throws(function() { url.parse(val); }, TypeError);
1221 // Tests below taken from Chiron
1222 // http://code.google.com/p/chironjs/source/browse/trunk/src/test/http/url.js
1224 // Copyright (c) 2002-2008 Kris Kowal <http://cixar.com/~kris.kowal>
1225 // used with permission under MIT License
1227 // Changes marked with @isaacs
1230 'http://a/b/c/d;p?q',
1231 'http://a/b/c/d;p?q=1/2',
1232 'http://a/b/c/d;p=1/2?q',
1237 //[to, from, result]
1238 var relativeTests2 = [
1239 // http://lists.w3.org/Archives/Public/uri/2004Feb/0114.html
1240 ['../c', 'foo:a/b', 'foo:c'],
1241 ['foo:.', 'foo:a', 'foo:'],
1242 ['/foo/../../../bar', 'zz:abc', 'zz:/bar'],
1243 ['/foo/../bar', 'zz:abc', 'zz:/bar'],
1244 // @isaacs Disagree. Not how web browsers resolve this.
1245 ['foo/../../../bar', 'zz:abc', 'zz:bar'],
1246 // ['foo/../../../bar', 'zz:abc', 'zz:../../bar'], // @isaacs Added
1247 ['foo/../bar', 'zz:abc', 'zz:bar'],
1248 ['zz:.', 'zz:abc', 'zz:'],
1249 ['/.', bases[0], 'http://a/'],
1250 ['/.foo', bases[0], 'http://a/.foo'],
1251 ['.foo', bases[0], 'http://a/b/c/.foo'],
1253 // http://gbiv.com/protocols/uri/test/rel_examples1.html
1254 // examples from RFC 2396
1255 ['g:h', bases[0], 'g:h'],
1256 ['g', bases[0], 'http://a/b/c/g'],
1257 ['./g', bases[0], 'http://a/b/c/g'],
1258 ['g/', bases[0], 'http://a/b/c/g/'],
1259 ['/g', bases[0], 'http://a/g'],
1260 ['//g', bases[0], 'http://g/'],
1261 // changed with RFC 2396bis
1262 //('?y', bases[0], 'http://a/b/c/d;p?y'],
1263 ['?y', bases[0], 'http://a/b/c/d;p?y'],
1264 ['g?y', bases[0], 'http://a/b/c/g?y'],
1265 // changed with RFC 2396bis
1266 //('#s', bases[0], CURRENT_DOC_URI + '#s'],
1267 ['#s', bases[0], 'http://a/b/c/d;p?q#s'],
1268 ['g#s', bases[0], 'http://a/b/c/g#s'],
1269 ['g?y#s', bases[0], 'http://a/b/c/g?y#s'],
1270 [';x', bases[0], 'http://a/b/c/;x'],
1271 ['g;x', bases[0], 'http://a/b/c/g;x'],
1272 ['g;x?y#s' , bases[0], 'http://a/b/c/g;x?y#s'],
1273 // changed with RFC 2396bis
1274 //('', bases[0], CURRENT_DOC_URI],
1275 ['', bases[0], 'http://a/b/c/d;p?q'],
1276 ['.', bases[0], 'http://a/b/c/'],
1277 ['./', bases[0], 'http://a/b/c/'],
1278 ['..', bases[0], 'http://a/b/'],
1279 ['../', bases[0], 'http://a/b/'],
1280 ['../g', bases[0], 'http://a/b/g'],
1281 ['../..', bases[0], 'http://a/'],
1282 ['../../', bases[0], 'http://a/'],
1283 ['../../g' , bases[0], 'http://a/g'],
1284 ['../../../g', bases[0], ('http://a/../g', 'http://a/g')],
1285 ['../../../../g', bases[0], ('http://a/../../g', 'http://a/g')],
1286 // changed with RFC 2396bis
1287 //('/./g', bases[0], 'http://a/./g'],
1288 ['/./g', bases[0], 'http://a/g'],
1289 // changed with RFC 2396bis
1290 //('/../g', bases[0], 'http://a/../g'],
1291 ['/../g', bases[0], 'http://a/g'],
1292 ['g.', bases[0], 'http://a/b/c/g.'],
1293 ['.g', bases[0], 'http://a/b/c/.g'],
1294 ['g..', bases[0], 'http://a/b/c/g..'],
1295 ['..g', bases[0], 'http://a/b/c/..g'],
1296 ['./../g', bases[0], 'http://a/b/g'],
1297 ['./g/.', bases[0], 'http://a/b/c/g/'],
1298 ['g/./h', bases[0], 'http://a/b/c/g/h'],
1299 ['g/../h', bases[0], 'http://a/b/c/h'],
1300 ['g;x=1/./y', bases[0], 'http://a/b/c/g;x=1/y'],
1301 ['g;x=1/../y', bases[0], 'http://a/b/c/y'],
1302 ['g?y/./x', bases[0], 'http://a/b/c/g?y/./x'],
1303 ['g?y/../x', bases[0], 'http://a/b/c/g?y/../x'],
1304 ['g#s/./x', bases[0], 'http://a/b/c/g#s/./x'],
1305 ['g#s/../x', bases[0], 'http://a/b/c/g#s/../x'],
1306 ['http:g', bases[0], ('http:g', 'http://a/b/c/g')],
1307 ['http:', bases[0], ('http:', bases[0])],
1308 // not sure where this one originated
1309 ['/a/b/c/./../../g', bases[0], 'http://a/a/g'],
1311 // http://gbiv.com/protocols/uri/test/rel_examples2.html
1312 // slashes in base URI's query args
1313 ['g', bases[1], 'http://a/b/c/g'],
1314 ['./g', bases[1], 'http://a/b/c/g'],
1315 ['g/', bases[1], 'http://a/b/c/g/'],
1316 ['/g', bases[1], 'http://a/g'],
1317 ['//g', bases[1], 'http://g/'],
1318 // changed in RFC 2396bis
1319 //('?y', bases[1], 'http://a/b/c/?y'],
1320 ['?y', bases[1], 'http://a/b/c/d;p?y'],
1321 ['g?y', bases[1], 'http://a/b/c/g?y'],
1322 ['g?y/./x' , bases[1], 'http://a/b/c/g?y/./x'],
1323 ['g?y/../x', bases[1], 'http://a/b/c/g?y/../x'],
1324 ['g#s', bases[1], 'http://a/b/c/g#s'],
1325 ['g#s/./x' , bases[1], 'http://a/b/c/g#s/./x'],
1326 ['g#s/../x', bases[1], 'http://a/b/c/g#s/../x'],
1327 ['./', bases[1], 'http://a/b/c/'],
1328 ['../', bases[1], 'http://a/b/'],
1329 ['../g', bases[1], 'http://a/b/g'],
1330 ['../../', bases[1], 'http://a/'],
1331 ['../../g' , bases[1], 'http://a/g'],
1333 // http://gbiv.com/protocols/uri/test/rel_examples3.html
1334 // slashes in path params
1335 // all of these changed in RFC 2396bis
1336 ['g', bases[2], 'http://a/b/c/d;p=1/g'],
1337 ['./g', bases[2], 'http://a/b/c/d;p=1/g'],
1338 ['g/', bases[2], 'http://a/b/c/d;p=1/g/'],
1339 ['g?y', bases[2], 'http://a/b/c/d;p=1/g?y'],
1340 [';x', bases[2], 'http://a/b/c/d;p=1/;x'],
1341 ['g;x', bases[2], 'http://a/b/c/d;p=1/g;x'],
1342 ['g;x=1/./y', bases[2], 'http://a/b/c/d;p=1/g;x=1/y'],
1343 ['g;x=1/../y', bases[2], 'http://a/b/c/d;p=1/y'],
1344 ['./', bases[2], 'http://a/b/c/d;p=1/'],
1345 ['../', bases[2], 'http://a/b/c/'],
1346 ['../g', bases[2], 'http://a/b/c/g'],
1347 ['../../', bases[2], 'http://a/b/'],
1348 ['../../g' , bases[2], 'http://a/b/g'],
1350 // http://gbiv.com/protocols/uri/test/rel_examples4.html
1351 // double and triple slash, unknown scheme
1352 ['g:h', bases[3], 'g:h'],
1353 ['g', bases[3], 'fred:///s//a/b/g'],
1354 ['./g', bases[3], 'fred:///s//a/b/g'],
1355 ['g/', bases[3], 'fred:///s//a/b/g/'],
1356 ['/g', bases[3], 'fred:///g'], // may change to fred:///s//a/g
1357 ['//g', bases[3], 'fred://g'], // may change to fred:///s//g
1358 ['//g/x', bases[3], 'fred://g/x'], // may change to fred:///s//g/x
1359 ['///g', bases[3], 'fred:///g'],
1360 ['./', bases[3], 'fred:///s//a/b/'],
1361 ['../', bases[3], 'fred:///s//a/'],
1362 ['../g', bases[3], 'fred:///s//a/g'],
1364 ['../../', bases[3], 'fred:///s//'],
1365 ['../../g' , bases[3], 'fred:///s//g'],
1366 ['../../../g', bases[3], 'fred:///s/g'],
1367 // may change to fred:///s//a/../../../g
1368 ['../../../../g', bases[3], 'fred:///g'],
1370 // http://gbiv.com/protocols/uri/test/rel_examples5.html
1371 // double and triple slash, well-known scheme
1372 ['g:h', bases[4], 'g:h'],
1373 ['g', bases[4], 'http:///s//a/b/g'],
1374 ['./g', bases[4], 'http:///s//a/b/g'],
1375 ['g/', bases[4], 'http:///s//a/b/g/'],
1376 ['/g', bases[4], 'http:///g'], // may change to http:///s//a/g
1377 ['//g', bases[4], 'http://g/'], // may change to http:///s//g
1378 ['//g/x', bases[4], 'http://g/x'], // may change to http:///s//g/x
1379 ['///g', bases[4], 'http:///g'],
1380 ['./', bases[4], 'http:///s//a/b/'],
1381 ['../', bases[4], 'http:///s//a/'],
1382 ['../g', bases[4], 'http:///s//a/g'],
1383 ['../../', bases[4], 'http:///s//'],
1384 ['../../g' , bases[4], 'http:///s//g'],
1385 // may change to http:///s//a/../../g
1386 ['../../../g', bases[4], 'http:///s/g'],
1387 // may change to http:///s//a/../../../g
1388 ['../../../../g', bases[4], 'http:///g'],
1390 // from Dan Connelly's tests in http://www.w3.org/2000/10/swap/uripath.py
1391 ['bar:abc', 'foo:xyz', 'bar:abc'],
1392 ['../abc', 'http://example/x/y/z', 'http://example/x/abc'],
1393 ['http://example/x/abc', 'http://example2/x/y/z', 'http://example/x/abc'],
1394 ['../r', 'http://ex/x/y/z', 'http://ex/x/r'],
1395 ['q/r', 'http://ex/x/y', 'http://ex/x/q/r'],
1396 ['q/r#s', 'http://ex/x/y', 'http://ex/x/q/r#s'],
1397 ['q/r#s/t', 'http://ex/x/y', 'http://ex/x/q/r#s/t'],
1398 ['ftp://ex/x/q/r', 'http://ex/x/y', 'ftp://ex/x/q/r'],
1399 ['', 'http://ex/x/y', 'http://ex/x/y'],
1400 ['', 'http://ex/x/y/', 'http://ex/x/y/'],
1401 ['', 'http://ex/x/y/pdq', 'http://ex/x/y/pdq'],
1402 ['z/', 'http://ex/x/y/', 'http://ex/x/y/z/'],
1404 'file:/swap/test/animal.rdf',
1405 'file:/swap/test/animal.rdf#Animal'],
1406 ['../abc', 'file:/e/x/y/z', 'file:/e/x/abc'],
1407 ['/example/x/abc', 'file:/example2/x/y/z', 'file:/example/x/abc'],
1408 ['../r', 'file:/ex/x/y/z', 'file:/ex/x/r'],
1409 ['/r', 'file:/ex/x/y/z', 'file:/r'],
1410 ['q/r', 'file:/ex/x/y', 'file:/ex/x/q/r'],
1411 ['q/r#s', 'file:/ex/x/y', 'file:/ex/x/q/r#s'],
1412 ['q/r#', 'file:/ex/x/y', 'file:/ex/x/q/r#'],
1413 ['q/r#s/t', 'file:/ex/x/y', 'file:/ex/x/q/r#s/t'],
1414 ['ftp://ex/x/q/r', 'file:/ex/x/y', 'ftp://ex/x/q/r'],
1415 ['', 'file:/ex/x/y', 'file:/ex/x/y'],
1416 ['', 'file:/ex/x/y/', 'file:/ex/x/y/'],
1417 ['', 'file:/ex/x/y/pdq', 'file:/ex/x/y/pdq'],
1418 ['z/', 'file:/ex/x/y/', 'file:/ex/x/y/z/'],
1419 ['file://meetings.example.com/cal#m1',
1420 'file:/devel/WWW/2000/10/swap/test/reluri-1.n3',
1421 'file://meetings.example.com/cal#m1'],
1422 ['file://meetings.example.com/cal#m1',
1423 'file:/home/connolly/w3ccvs/WWW/2000/10/swap/test/reluri-1.n3',
1424 'file://meetings.example.com/cal#m1'],
1425 ['./#blort', 'file:/some/dir/foo', 'file:/some/dir/#blort'],
1426 ['./#', 'file:/some/dir/foo', 'file:/some/dir/#'],
1428 ['./', 'http://example/x/abc.efg', 'http://example/x/'],
1431 // Graham Klyne's tests
1432 // http://www.ninebynine.org/Software/HaskellUtils/Network/UriTest.xls
1433 // 01-31 are from Connelly's cases
1436 ['./q:r', 'http://ex/x/y', 'http://ex/x/q:r'],
1437 ['./p=q:r', 'http://ex/x/y', 'http://ex/x/p=q:r'],
1438 ['?pp/rr', 'http://ex/x/y?pp/qq', 'http://ex/x/y?pp/rr'],
1439 ['y/z', 'http://ex/x/y?pp/qq', 'http://ex/x/y/z'],
1440 ['local/qual@domain.org#frag',
1442 'mailto:local/qual@domain.org#frag'],
1443 ['more/qual2@domain2.org#frag',
1444 'mailto:local/qual1@domain1.org',
1445 'mailto:local/more/qual2@domain2.org#frag'],
1446 ['y?q', 'http://ex/x/y?q', 'http://ex/x/y?q'],
1447 ['/x/y?q', 'http://ex?p', 'http://ex/x/y?q'],
1448 ['c/d', 'foo:a/b', 'foo:a/c/d'],
1449 ['/c/d', 'foo:a/b', 'foo:/c/d'],
1450 ['', 'foo:a/b?c#d', 'foo:a/b?c'],
1451 ['b/c', 'foo:a', 'foo:b/c'],
1452 ['../b/c', 'foo:/a/y/z', 'foo:/a/b/c'],
1453 ['./b/c', 'foo:a', 'foo:b/c'],
1454 ['/./b/c', 'foo:a', 'foo:/b/c'],
1455 ['../../d', 'foo://a//b/c', 'foo://a/d'],
1456 ['.', 'foo:a', 'foo:'],
1457 ['..', 'foo:a', 'foo:'],
1459 // 50-57[cf. TimBL comments --
1460 // http://lists.w3.org/Archives/Public/uri/2003Feb/0028.html,
1461 // http://lists.w3.org/Archives/Public/uri/2003Jan/0008.html)
1462 ['abc', 'http://example/x/y%2Fz', 'http://example/x/abc'],
1463 ['../../x%2Fabc', 'http://example/a/x/y/z', 'http://example/a/x%2Fabc'],
1464 ['../x%2Fabc', 'http://example/a/x/y%2Fz', 'http://example/a/x%2Fabc'],
1465 ['abc', 'http://example/x%2Fy/z', 'http://example/x%2Fy/abc'],
1466 ['q%3Ar', 'http://ex/x/y', 'http://ex/x/q%3Ar'],
1467 ['/x%2Fabc', 'http://example/x/y%2Fz', 'http://example/x%2Fabc'],
1468 ['/x%2Fabc', 'http://example/x/y/z', 'http://example/x%2Fabc'],
1469 ['/x%2Fabc', 'http://example/x/y%2Fz', 'http://example/x%2Fabc'],
1472 ['local2@domain2', 'mailto:local1@domain1?query1', 'mailto:local2@domain2'],
1473 ['local2@domain2?query2',
1474 'mailto:local1@domain1',
1475 'mailto:local2@domain2?query2'],
1476 ['local2@domain2?query2',
1477 'mailto:local1@domain1?query1',
1478 'mailto:local2@domain2?query2'],
1479 ['?query2', 'mailto:local@domain?query1', 'mailto:local@domain?query2'],
1480 ['local@domain?query2', 'mailto:?query1', 'mailto:local@domain?query2'],
1481 ['?query2', 'mailto:local@domain?query1', 'mailto:local@domain?query2'],
1482 ['http://example/a/b?c/../d', 'foo:bar', 'http://example/a/b?c/../d'],
1483 ['http://example/a/b#c/../d', 'foo:bar', 'http://example/a/b#c/../d'],
1486 // @isaacs Disagree. Not how browsers do it.
1487 // ['http:this', 'http://example.org/base/uri', 'http:this'],
1489 ['http:this', 'http://example.org/base/uri', 'http://example.org/base/this'],
1490 ['http:this', 'http:base', 'http:this'],
1491 ['.//g', 'f:/a', 'f://g'],
1492 ['b/c//d/e', 'f://example.org/base/a', 'f://example.org/base/b/c//d/e'],
1493 ['m2@example.ord/c2@example.org',
1494 'mid:m@example.ord/c@example.org',
1495 'mid:m@example.ord/m2@example.ord/c2@example.org'],
1497 'file:///C:/DEV/Haskell/lib/HXmlToolbox-3.01/examples/',
1498 'file:///C:/DEV/Haskell/lib/HXmlToolbox-3.01/examples/mini1.xml'],
1499 ['../b/c', 'foo:a/y/z', 'foo:a/b/c'],
1502 ['http://diff:auth@www.example.com',
1503 'http://asdf:qwer@www.example.com',
1504 'http://diff:auth@www.example.com/']
1506 relativeTests2.forEach(function(relativeTest) {
1507 var a = url.resolve(relativeTest[1], relativeTest[0]),
1508 e = relativeTest[2];
1510 'resolve(' + [relativeTest[1], relativeTest[0]] + ') == ' + e +
1514 //if format and parse are inverse operations then
1515 //resolveObject(parse(x), y) == parse(resolve(x, y))
1517 //host and hostname are special, in this case a '' value is important
1518 var emptyIsImportant = {'host': true, 'hostname': ''};
1520 //format: [from, path, expected]
1521 relativeTests.forEach(function(relativeTest) {
1522 var actual = url.resolveObject(url.parse(relativeTest[0]), relativeTest[1]),
1523 expected = url.parse(relativeTest[2]);
1526 assert.deepEqual(actual, expected);
1528 expected = relativeTest[2];
1529 actual = url.format(actual);
1531 assert.equal(actual, expected,
1532 'format(' + actual + ') == ' + expected + '\nactual:' + actual);
1535 //format: [to, from, result]
1536 // the test: ['.//g', 'f:/a', 'f://g'] is a fundamental problem
1537 // url.parse('f:/a') does not have a host
1538 // url.resolve('f:/a', './/g') does not have a host because you have moved
1539 // down to the g directory. i.e. f: //g, however when this url is parsed
1540 // f:// will indicate that the host is g which is not the case.
1541 // it is unclear to me how to keep this information from being lost
1542 // it may be that a pathname of ////g should collapse to /g but this seems
1543 // to be a lot of work for an edge case. Right now I remove the test
1544 if (relativeTests2[181][0] === './/g' &&
1545 relativeTests2[181][1] === 'f:/a' &&
1546 relativeTests2[181][2] === 'f://g') {
1547 relativeTests2.splice(181, 1);
1549 relativeTests2.forEach(function(relativeTest) {
1550 var actual = url.resolveObject(url.parse(relativeTest[1]), relativeTest[0]),
1551 expected = url.parse(relativeTest[2]);
1553 assert.deepEqual(actual, expected);
1555 var expected = relativeTest[2],
1556 actual = url.format(actual);
1558 assert.equal(actual, expected,
1559 'format(' + relativeTest[1] + ') == ' + expected +
1560 '\nactual:' + actual);
1565 // https://github.com/iojs/io.js/pull/1036
1574 for (var i = 0; i < throws.length; i++) {
1575 assert.throws(function () { url.format(throws[i]); }, TypeError);
1577 assert(url.format('') === '');
1578 assert(url.format({}) === '');