'use strict';
const common = require('../common');

if (!common.hasIntl)
  common.skip('missing Intl');

const assert = require('assert');
const inspect = require('util').inspect;

const url = require('url');

// URLs to parse, and expected data
// { url : parsed }
const parseTests = {
  '//some_path': {
    href: '//some_path',
    pathname: '//some_path',
    path: '//some_path'
  },

  'http:\\\\evil-phisher\\foo.html#h\\a\\s\\h': {
    protocol: 'http:',
    slashes: true,
    host: 'evil-phisher',
    hostname: 'evil-phisher',
    pathname: '/foo.html',
    path: '/foo.html',
    hash: '#h%5Ca%5Cs%5Ch',
    href: 'http://evil-phisher/foo.html#h%5Ca%5Cs%5Ch'
  },

  'http:\\\\evil-phisher\\foo.html?json="\\"foo\\""#h\\a\\s\\h': {
    protocol: 'http:',
    slashes: true,
    host: 'evil-phisher',
    hostname: 'evil-phisher',
    pathname: '/foo.html',
    search: '?json=%22%5C%22foo%5C%22%22',
    query: 'json=%22%5C%22foo%5C%22%22',
    path: '/foo.html?json=%22%5C%22foo%5C%22%22',
    hash: '#h%5Ca%5Cs%5Ch',
    href: 'http://evil-phisher/foo.html?json=%22%5C%22foo%5C%22%22#h%5Ca%5Cs%5Ch'
  },

  'http:\\\\evil-phisher\\foo.html#h\\a\\s\\h?blarg': {
    protocol: 'http:',
    slashes: true,
    host: 'evil-phisher',
    hostname: 'evil-phisher',
    pathname: '/foo.html',
    path: '/foo.html',
    hash: '#h%5Ca%5Cs%5Ch?blarg',
    href: 'http://evil-phisher/foo.html#h%5Ca%5Cs%5Ch?blarg'
  },


  'http:\\\\evil-phisher\\foo.html': {
    protocol: 'http:',
    slashes: true,
    host: 'evil-phisher',
    hostname: 'evil-phisher',
    pathname: '/foo.html',
    path: '/foo.html',
    href: 'http://evil-phisher/foo.html'
  },

  'HTTP://www.example.com/': {
    href: 'http://www.example.com/',
    protocol: 'http:',
    slashes: true,
    host: 'www.example.com',
    hostname: 'www.example.com',
    pathname: '/',
    path: '/'
  },

  'HTTP://www.example.com': {
    href: 'http://www.example.com/',
    protocol: 'http:',
    slashes: true,
    host: 'www.example.com',
    hostname: 'www.example.com',
    pathname: '/',
    path: '/'
  },

  'http://www.ExAmPlE.com/': {
    href: 'http://www.example.com/',
    protocol: 'http:',
    slashes: true,
    host: 'www.example.com',
    hostname: 'www.example.com',
    pathname: '/',
    path: '/'
  },

  'http://user:pw@www.ExAmPlE.com/': {
    href: 'http://user:pw@www.example.com/',
    protocol: 'http:',
    slashes: true,
    auth: 'user:pw',
    host: 'www.example.com',
    hostname: 'www.example.com',
    pathname: '/',
    path: '/'
  },

  'http://USER:PW@www.ExAmPlE.com/': {
    href: 'http://USER:PW@www.example.com/',
    protocol: 'http:',
    slashes: true,
    auth: 'USER:PW',
    host: 'www.example.com',
    hostname: 'www.example.com',
    pathname: '/',
    path: '/'
  },

  'http://user@www.example.com/': {
    href: 'http://user@www.example.com/',
    protocol: 'http:',
    slashes: true,
    auth: 'user',
    host: 'www.example.com',
    hostname: 'www.example.com',
    pathname: '/',
    path: '/'
  },

  'http://user%3Apw@www.example.com/': {
    href: 'http://user:pw@www.example.com/',
    protocol: 'http:',
    slashes: true,
    auth: 'user:pw',
    host: 'www.example.com',
    hostname: 'www.example.com',
    pathname: '/',
    path: '/'
  },

  'http://x.com/path?that\'s#all, folks': {
    href: 'http://x.com/path?that%27s#all,%20folks',
    protocol: 'http:',
    slashes: true,
    host: 'x.com',
    hostname: 'x.com',
    search: '?that%27s',
    query: 'that%27s',
    pathname: '/path',
    hash: '#all,%20folks',
    path: '/path?that%27s'
  },

  'HTTP://X.COM/Y': {
    href: 'http://x.com/Y',
    protocol: 'http:',
    slashes: true,
    host: 'x.com',
    hostname: 'x.com',
    pathname: '/Y',
    path: '/Y'
  },

  // Whitespace in the front
  ' http://www.example.com/': {
    href: 'http://www.example.com/',
    protocol: 'http:',
    slashes: true,
    host: 'www.example.com',
    hostname: 'www.example.com',
    pathname: '/',
    path: '/'
  },

  // + not an invalid host character
  // per https://url.spec.whatwg.org/#host-parsing
  'http://x.y.com+a/b/c': {
    href: 'http://x.y.com+a/b/c',
    protocol: 'http:',
    slashes: true,
    host: 'x.y.com+a',
    hostname: 'x.y.com+a',
    pathname: '/b/c',
    path: '/b/c'
  },

  // An unexpected invalid char in the hostname.
  'HtTp://x.y.cOm;a/b/c?d=e#f g<h>i': {
    href: 'http://x.y.com/;a/b/c?d=e#f%20g%3Ch%3Ei',
    protocol: 'http:',
    slashes: true,
    host: 'x.y.com',
    hostname: 'x.y.com',
    pathname: ';a/b/c',
    search: '?d=e',
    query: 'd=e',
    hash: '#f%20g%3Ch%3Ei',
    path: ';a/b/c?d=e'
  },

  // Make sure that we don't accidentally lcast the path parts.
  'HtTp://x.y.cOm;A/b/c?d=e#f g<h>i': {
    href: 'http://x.y.com/;A/b/c?d=e#f%20g%3Ch%3Ei',
    protocol: 'http:',
    slashes: true,
    host: 'x.y.com',
    hostname: 'x.y.com',
    pathname: ';A/b/c',
    search: '?d=e',
    query: 'd=e',
    hash: '#f%20g%3Ch%3Ei',
    path: ';A/b/c?d=e'
  },

  'http://x...y...#p': {
    href: 'http://x...y.../#p',
    protocol: 'http:',
    slashes: true,
    host: 'x...y...',
    hostname: 'x...y...',
    hash: '#p',
    pathname: '/',
    path: '/'
  },

  'http://x/p/"quoted"': {
    href: 'http://x/p/%22quoted%22',
    protocol: 'http:',
    slashes: true,
    host: 'x',
    hostname: 'x',
    pathname: '/p/%22quoted%22',
    path: '/p/%22quoted%22'
  },

  '<http://goo.corn/bread> Is a URL!': {
    href: '%3Chttp://goo.corn/bread%3E%20Is%20a%20URL!',
    pathname: '%3Chttp://goo.corn/bread%3E%20Is%20a%20URL!',
    path: '%3Chttp://goo.corn/bread%3E%20Is%20a%20URL!'
  },

  'http://www.narwhaljs.org/blog/categories?id=news': {
    href: 'http://www.narwhaljs.org/blog/categories?id=news',
    protocol: 'http:',
    slashes: true,
    host: 'www.narwhaljs.org',
    hostname: 'www.narwhaljs.org',
    search: '?id=news',
    query: 'id=news',
    pathname: '/blog/categories',
    path: '/blog/categories?id=news'
  },

  'http://mt0.google.com/vt/lyrs=m@114&hl=en&src=api&x=2&y=2&z=3&s=': {
    href: 'http://mt0.google.com/vt/lyrs=m@114&hl=en&src=api&x=2&y=2&z=3&s=',
    protocol: 'http:',
    slashes: true,
    host: 'mt0.google.com',
    hostname: 'mt0.google.com',
    pathname: '/vt/lyrs=m@114&hl=en&src=api&x=2&y=2&z=3&s=',
    path: '/vt/lyrs=m@114&hl=en&src=api&x=2&y=2&z=3&s='
  },

  'http://mt0.google.com/vt/lyrs=m@114???&hl=en&src=api&x=2&y=2&z=3&s=': {
    href: 'http://mt0.google.com/vt/lyrs=m@114???&hl=en&src=api' +
          '&x=2&y=2&z=3&s=',
    protocol: 'http:',
    slashes: true,
    host: 'mt0.google.com',
    hostname: 'mt0.google.com',
    search: '???&hl=en&src=api&x=2&y=2&z=3&s=',
    query: '??&hl=en&src=api&x=2&y=2&z=3&s=',
    pathname: '/vt/lyrs=m@114',
    path: '/vt/lyrs=m@114???&hl=en&src=api&x=2&y=2&z=3&s='
  },

  'http://user:pass@mt0.google.com/vt/lyrs=m@114???&hl=en&src=api&x=2&y=2&z=3&s=': {
    href: 'http://user:pass@mt0.google.com/vt/lyrs=m@114???&hl=en&src=api&x=2&y=2&z=3&s=',
    protocol: 'http:',
    slashes: true,
    host: 'mt0.google.com',
    auth: 'user:pass',
    hostname: 'mt0.google.com',
    search: '???&hl=en&src=api&x=2&y=2&z=3&s=',
    query: '??&hl=en&src=api&x=2&y=2&z=3&s=',
    pathname: '/vt/lyrs=m@114',
    path: '/vt/lyrs=m@114???&hl=en&src=api&x=2&y=2&z=3&s='
  },

  'file:///etc/passwd': {
    href: 'file:///etc/passwd',
    slashes: true,
    protocol: 'file:',
    pathname: '/etc/passwd',
    hostname: '',
    host: '',
    path: '/etc/passwd'
  },

  'file://localhost/etc/passwd': {
    href: 'file://localhost/etc/passwd',
    protocol: 'file:',
    slashes: true,
    pathname: '/etc/passwd',
    hostname: 'localhost',
    host: 'localhost',
    path: '/etc/passwd'
  },

  'file://foo/etc/passwd': {
    href: 'file://foo/etc/passwd',
    protocol: 'file:',
    slashes: true,
    pathname: '/etc/passwd',
    hostname: 'foo',
    host: 'foo',
    path: '/etc/passwd'
  },

  'file:///etc/node/': {
    href: 'file:///etc/node/',
    slashes: true,
    protocol: 'file:',
    pathname: '/etc/node/',
    hostname: '',
    host: '',
    path: '/etc/node/'
  },

  'file://localhost/etc/node/': {
    href: 'file://localhost/etc/node/',
    protocol: 'file:',
    slashes: true,
    pathname: '/etc/node/',
    hostname: 'localhost',
    host: 'localhost',
    path: '/etc/node/'
  },

  'file://foo/etc/node/': {
    href: 'file://foo/etc/node/',
    protocol: 'file:',
    slashes: true,
    pathname: '/etc/node/',
    hostname: 'foo',
    host: 'foo',
    path: '/etc/node/'
  },

  'http:/baz/../foo/bar': {
    href: 'http:/baz/../foo/bar',
    protocol: 'http:',
    pathname: '/baz/../foo/bar',
    path: '/baz/../foo/bar'
  },

  'http://user:pass@example.com:8000/foo/bar?baz=quux#frag': {
    href: 'http://user:pass@example.com:8000/foo/bar?baz=quux#frag',
    protocol: 'http:',
    slashes: true,
    host: 'example.com:8000',
    auth: 'user:pass',
    port: '8000',
    hostname: 'example.com',
    hash: '#frag',
    search: '?baz=quux',
    query: 'baz=quux',
    pathname: '/foo/bar',
    path: '/foo/bar?baz=quux'
  },

  '//user:pass@example.com:8000/foo/bar?baz=quux#frag': {
    href: '//user:pass@example.com:8000/foo/bar?baz=quux#frag',
    slashes: true,
    host: 'example.com:8000',
    auth: 'user:pass',
    port: '8000',
    hostname: 'example.com',
    hash: '#frag',
    search: '?baz=quux',
    query: 'baz=quux',
    pathname: '/foo/bar',
    path: '/foo/bar?baz=quux'
  },

  '/foo/bar?baz=quux#frag': {
    href: '/foo/bar?baz=quux#frag',
    hash: '#frag',
    search: '?baz=quux',
    query: 'baz=quux',
    pathname: '/foo/bar',
    path: '/foo/bar?baz=quux'
  },

  'http:/foo/bar?baz=quux#frag': {
    href: 'http:/foo/bar?baz=quux#frag',
    protocol: 'http:',
    hash: '#frag',
    search: '?baz=quux',
    query: 'baz=quux',
    pathname: '/foo/bar',
    path: '/foo/bar?baz=quux'
  },

  'mailto:foo@bar.com?subject=hello': {
    href: 'mailto:foo@bar.com?subject=hello',
    protocol: 'mailto:',
    host: 'bar.com',
    auth: 'foo',
    hostname: 'bar.com',
    search: '?subject=hello',
    query: 'subject=hello',
    path: '?subject=hello'
  },

  'javascript:alert(\'hello\');': {
    href: 'javascript:alert(\'hello\');',
    protocol: 'javascript:',
    pathname: 'alert(\'hello\');',
    path: 'alert(\'hello\');'
  },

  'xmpp:isaacschlueter@jabber.org': {
    href: 'xmpp:isaacschlueter@jabber.org',
    protocol: 'xmpp:',
    host: 'jabber.org',
    auth: 'isaacschlueter',
    hostname: 'jabber.org'
  },

  'http://atpass:foo%40bar@127.0.0.1:8080/path?search=foo#bar': {
    href: 'http://atpass:foo%40bar@127.0.0.1:8080/path?search=foo#bar',
    protocol: 'http:',
    slashes: true,
    host: '127.0.0.1:8080',
    auth: 'atpass:foo@bar',
    hostname: '127.0.0.1',
    port: '8080',
    pathname: '/path',
    search: '?search=foo',
    query: 'search=foo',
    hash: '#bar',
    path: '/path?search=foo'
  },

  'svn+ssh://foo/bar': {
    href: 'svn+ssh://foo/bar',
    host: 'foo',
    hostname: 'foo',
    protocol: 'svn+ssh:',
    pathname: '/bar',
    path: '/bar',
    slashes: true
  },

  'dash-test://foo/bar': {
    href: 'dash-test://foo/bar',
    host: 'foo',
    hostname: 'foo',
    protocol: 'dash-test:',
    pathname: '/bar',
    path: '/bar',
    slashes: true
  },

  'dash-test:foo/bar': {
    href: 'dash-test:foo/bar',
    host: 'foo',
    hostname: 'foo',
    protocol: 'dash-test:',
    pathname: '/bar',
    path: '/bar'
  },

  'dot.test://foo/bar': {
    href: 'dot.test://foo/bar',
    host: 'foo',
    hostname: 'foo',
    protocol: 'dot.test:',
    pathname: '/bar',
    path: '/bar',
    slashes: true
  },

  'dot.test:foo/bar': {
    href: 'dot.test:foo/bar',
    host: 'foo',
    hostname: 'foo',
    protocol: 'dot.test:',
    pathname: '/bar',
    path: '/bar'
  },

  // IDNA tests
  'http://www.日本語.com/': {
    href: 'http://www.xn--wgv71a119e.com/',
    protocol: 'http:',
    slashes: true,
    host: 'www.xn--wgv71a119e.com',
    hostname: 'www.xn--wgv71a119e.com',
    pathname: '/',
    path: '/'
  },

  'http://example.Bücher.com/': {
    href: 'http://example.xn--bcher-kva.com/',
    protocol: 'http:',
    slashes: true,
    host: 'example.xn--bcher-kva.com',
    hostname: 'example.xn--bcher-kva.com',
    pathname: '/',
    path: '/'
  },

  'http://www.Äffchen.com/': {
    href: 'http://www.xn--ffchen-9ta.com/',
    protocol: 'http:',
    slashes: true,
    host: 'www.xn--ffchen-9ta.com',
    hostname: 'www.xn--ffchen-9ta.com',
    pathname: '/',
    path: '/'
  },

  'http://www.Äffchen.cOm;A/b/c?d=e#f g<h>i': {
    href: 'http://www.xn--ffchen-9ta.com/;A/b/c?d=e#f%20g%3Ch%3Ei',
    protocol: 'http:',
    slashes: true,
    host: 'www.xn--ffchen-9ta.com',
    hostname: 'www.xn--ffchen-9ta.com',
    pathname: ';A/b/c',
    search: '?d=e',
    query: 'd=e',
    hash: '#f%20g%3Ch%3Ei',
    path: ';A/b/c?d=e'
  },

  'http://SÉLIER.COM/': {
    href: 'http://xn--slier-bsa.com/',
    protocol: 'http:',
    slashes: true,
    host: 'xn--slier-bsa.com',
    hostname: 'xn--slier-bsa.com',
    pathname: '/',
    path: '/'
  },

  'http://ليهمابتكلموشعربي؟.ي؟/': {
    href: 'http://xn--egbpdaj6bu4bxfgehfvwxn.xn--egb9f/',
    protocol: 'http:',
    slashes: true,
    host: 'xn--egbpdaj6bu4bxfgehfvwxn.xn--egb9f',
    hostname: 'xn--egbpdaj6bu4bxfgehfvwxn.xn--egb9f',
    pathname: '/',
    path: '/'
  },

  'http://➡.ws/➡': {
    href: 'http://xn--hgi.ws/➡',
    protocol: 'http:',
    slashes: true,
    host: 'xn--hgi.ws',
    hostname: 'xn--hgi.ws',
    pathname: '/➡',
    path: '/➡'
  },

  'http://bucket_name.s3.amazonaws.com/image.jpg': {
    protocol: 'http:',
    slashes: true,
    host: 'bucket_name.s3.amazonaws.com',
    hostname: 'bucket_name.s3.amazonaws.com',
    pathname: '/image.jpg',
    href: 'http://bucket_name.s3.amazonaws.com/image.jpg',
    path: '/image.jpg'
  },

  'git+http://github.com/joyent/node.git': {
    protocol: 'git+http:',
    slashes: true,
    host: 'github.com',
    hostname: 'github.com',
    pathname: '/joyent/node.git',
    path: '/joyent/node.git',
    href: 'git+http://github.com/joyent/node.git'
  },

  // If local1@domain1 is uses as a relative URL it may
  // be parse into auth@hostname, but here there is no
  // way to make it work in url.parse, I add the test to be explicit
  'local1@domain1': {
    pathname: 'local1@domain1',
    path: 'local1@domain1',
    href: 'local1@domain1'
  },

  // While this may seem counter-intuitive, a browser will parse
  // <a href='www.google.com'> as a path.
  'www.example.com': {
    href: 'www.example.com',
    pathname: 'www.example.com',
    path: 'www.example.com'
  },

  // ipv6 support
  '[fe80::1]': {
    href: '[fe80::1]',
    pathname: '[fe80::1]',
    path: '[fe80::1]'
  },

  'coap://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]': {
    protocol: 'coap:',
    slashes: true,
    host: '[fedc:ba98:7654:3210:fedc:ba98:7654:3210]',
    hostname: 'fedc:ba98:7654:3210:fedc:ba98:7654:3210',
    href: 'coap://[fedc:ba98:7654:3210:fedc:ba98:7654:3210]/',
    pathname: '/',
    path: '/'
  },

  'coap://[1080:0:0:0:8:800:200C:417A]:61616/': {
    protocol: 'coap:',
    slashes: true,
    host: '[1080:0:0:0:8:800:200c:417a]:61616',
    port: '61616',
    hostname: '1080:0:0:0:8:800:200c:417a',
    href: 'coap://[1080:0:0:0:8:800:200c:417a]:61616/',
    pathname: '/',
    path: '/'
  },

  'http://user:password@[3ffe:2a00:100:7031::1]:8080': {
    protocol: 'http:',
    slashes: true,
    auth: 'user:password',
    host: '[3ffe:2a00:100:7031::1]:8080',
    port: '8080',
    hostname: '3ffe:2a00:100:7031::1',
    href: 'http://user:password@[3ffe:2a00:100:7031::1]:8080/',
    pathname: '/',
    path: '/'
  },

  'coap://u:p@[::192.9.5.5]:61616/.well-known/r?n=Temperature': {
    protocol: 'coap:',
    slashes: true,
    auth: 'u:p',
    host: '[::192.9.5.5]:61616',
    port: '61616',
    hostname: '::192.9.5.5',
    href: 'coap://u:p@[::192.9.5.5]:61616/.well-known/r?n=Temperature',
    search: '?n=Temperature',
    query: 'n=Temperature',
    pathname: '/.well-known/r',
    path: '/.well-known/r?n=Temperature'
  },

  // empty port
  'http://example.com:': {
    protocol: 'http:',
    slashes: true,
    host: 'example.com',
    hostname: 'example.com',
    href: 'http://example.com/',
    pathname: '/',
    path: '/'
  },

  'http://example.com:/a/b.html': {
    protocol: 'http:',
    slashes: true,
    host: 'example.com',
    hostname: 'example.com',
    href: 'http://example.com/a/b.html',
    pathname: '/a/b.html',
    path: '/a/b.html'
  },

  'http://example.com:?a=b': {
    protocol: 'http:',
    slashes: true,
    host: 'example.com',
    hostname: 'example.com',
    href: 'http://example.com/?a=b',
    search: '?a=b',
    query: 'a=b',
    pathname: '/',
    path: '/?a=b'
  },

  'http://example.com:#abc': {
    protocol: 'http:',
    slashes: true,
    host: 'example.com',
    hostname: 'example.com',
    href: 'http://example.com/#abc',
    hash: '#abc',
    pathname: '/',
    path: '/'
  },

  'http://[fe80::1]:/a/b?a=b#abc': {
    protocol: 'http:',
    slashes: true,
    host: '[fe80::1]',
    hostname: 'fe80::1',
    href: 'http://[fe80::1]/a/b?a=b#abc',
    search: '?a=b',
    query: 'a=b',
    hash: '#abc',
    pathname: '/a/b',
    path: '/a/b?a=b'
  },

  'http://-lovemonsterz.tumblr.com/rss': {
    protocol: 'http:',
    slashes: true,
    host: '-lovemonsterz.tumblr.com',
    hostname: '-lovemonsterz.tumblr.com',
    href: 'http://-lovemonsterz.tumblr.com/rss',
    pathname: '/rss',
    path: '/rss',
  },

  'http://-lovemonsterz.tumblr.com:80/rss': {
    protocol: 'http:',
    slashes: true,
    port: '80',
    host: '-lovemonsterz.tumblr.com:80',
    hostname: '-lovemonsterz.tumblr.com',
    href: 'http://-lovemonsterz.tumblr.com:80/rss',
    pathname: '/rss',
    path: '/rss',
  },

  'http://user:pass@-lovemonsterz.tumblr.com/rss': {
    protocol: 'http:',
    slashes: true,
    auth: 'user:pass',
    host: '-lovemonsterz.tumblr.com',
    hostname: '-lovemonsterz.tumblr.com',
    href: 'http://user:pass@-lovemonsterz.tumblr.com/rss',
    pathname: '/rss',
    path: '/rss',
  },

  'http://user:pass@-lovemonsterz.tumblr.com:80/rss': {
    protocol: 'http:',
    slashes: true,
    auth: 'user:pass',
    port: '80',
    host: '-lovemonsterz.tumblr.com:80',
    hostname: '-lovemonsterz.tumblr.com',
    href: 'http://user:pass@-lovemonsterz.tumblr.com:80/rss',
    pathname: '/rss',
    path: '/rss',
  },

  'http://_jabber._tcp.google.com/test': {
    protocol: 'http:',
    slashes: true,
    host: '_jabber._tcp.google.com',
    hostname: '_jabber._tcp.google.com',
    href: 'http://_jabber._tcp.google.com/test',
    pathname: '/test',
    path: '/test',
  },

  'http://user:pass@_jabber._tcp.google.com/test': {
    protocol: 'http:',
    slashes: true,
    auth: 'user:pass',
    host: '_jabber._tcp.google.com',
    hostname: '_jabber._tcp.google.com',
    href: 'http://user:pass@_jabber._tcp.google.com/test',
    pathname: '/test',
    path: '/test',
  },

  'http://_jabber._tcp.google.com:80/test': {
    protocol: 'http:',
    slashes: true,
    port: '80',
    host: '_jabber._tcp.google.com:80',
    hostname: '_jabber._tcp.google.com',
    href: 'http://_jabber._tcp.google.com:80/test',
    pathname: '/test',
    path: '/test',
  },

  'http://user:pass@_jabber._tcp.google.com:80/test': {
    protocol: 'http:',
    slashes: true,
    auth: 'user:pass',
    port: '80',
    host: '_jabber._tcp.google.com:80',
    hostname: '_jabber._tcp.google.com',
    href: 'http://user:pass@_jabber._tcp.google.com:80/test',
    pathname: '/test',
    path: '/test',
  },

  'http://x:1/\' <>"`/{}|\\^~`/': {
    protocol: 'http:',
    slashes: true,
    host: 'x:1',
    port: '1',
    hostname: 'x',
    pathname: '/%27%20%3C%3E%22%60/%7B%7D%7C/%5E~%60/',
    path: '/%27%20%3C%3E%22%60/%7B%7D%7C/%5E~%60/',
    href: 'http://x:1/%27%20%3C%3E%22%60/%7B%7D%7C/%5E~%60/'
  },

  'http://a@b@c/': {
    protocol: 'http:',
    slashes: true,
    auth: 'a@b',
    host: 'c',
    hostname: 'c',
    href: 'http://a%40b@c/',
    path: '/',
    pathname: '/'
  },

  'http://a@b?@c': {
    protocol: 'http:',
    slashes: true,
    auth: 'a',
    host: 'b',
    hostname: 'b',
    href: 'http://a@b/?@c',
    path: '/?@c',
    pathname: '/',
    search: '?@c',
    query: '@c'
  },

  'http://a.b/\tbc\ndr\ref g"hq\'j<kl>?mn\\op^q=r`99{st|uv}wz': {
    protocol: 'http:',
    slashes: true,
    host: 'a.b',
    port: null,
    hostname: 'a.b',
    hash: null,
    pathname: '/%09bc%0Adr%0Def%20g%22hq%27j%3Ckl%3E',
    path: '/%09bc%0Adr%0Def%20g%22hq%27j%3Ckl%3E?mn%5Cop%5Eq=r%6099%7Bst%7Cuv%7Dwz',
    search: '?mn%5Cop%5Eq=r%6099%7Bst%7Cuv%7Dwz',
    query: 'mn%5Cop%5Eq=r%6099%7Bst%7Cuv%7Dwz',
    href: 'http://a.b/%09bc%0Adr%0Def%20g%22hq%27j%3Ckl%3E?mn%5Cop%5Eq=r%6099%7Bst%7Cuv%7Dwz'
  },

  'http://a\r" \t\n<\'b:b@c\r\nd/e?f': {
    protocol: 'http:',
    slashes: true,
    auth: 'a" <\'b:b',
    host: 'cd',
    port: null,
    hostname: 'cd',
    hash: null,
    search: '?f',
    query: 'f',
    pathname: '/e',
    path: '/e?f',
    href: 'http://a%22%20%3C\'b:b@cd/e?f'
  },

  // Git urls used by npm
  'git+ssh://git@github.com:npm/npm': {
    protocol: 'git+ssh:',
    slashes: true,
    auth: 'git',
    host: 'github.com',
    port: null,
    hostname: 'github.com',
    hash: null,
    search: null,
    query: null,
    pathname: '/:npm/npm',
    path: '/:npm/npm',
    href: 'git+ssh://git@github.com/:npm/npm'
  },

  'https://*': {
    protocol: 'https:',
    slashes: true,
    auth: null,
    host: '*',
    port: null,
    hostname: '*',
    hash: null,
    search: null,
    query: null,
    pathname: '/',
    path: '/',
    href: 'https://*/'
  },

  // The following two URLs are the same, but they differ for a capital A.
  // Verify that the protocol is checked in a case-insensitive manner.
  'javascript:alert(1);a=\x27@white-listed.com\x27': {
    protocol: 'javascript:',
    slashes: null,
    auth: null,
    host: null,
    port: null,
    hostname: null,
    hash: null,
    search: null,
    query: null,
    pathname: "alert(1);a='@white-listed.com'",
    path: "alert(1);a='@white-listed.com'",
    href: "javascript:alert(1);a='@white-listed.com'"
  },

  'javAscript:alert(1);a=\x27@white-listed.com\x27': {
    protocol: 'javascript:',
    slashes: null,
    auth: null,
    host: null,
    port: null,
    hostname: null,
    hash: null,
    search: null,
    query: null,
    pathname: "alert(1);a='@white-listed.com'",
    path: "alert(1);a='@white-listed.com'",
    href: "javascript:alert(1);a='@white-listed.com'"
  },

  'ws://www.example.com': {
    protocol: 'ws:',
    slashes: true,
    hostname: 'www.example.com',
    host: 'www.example.com',
    pathname: '/',
    path: '/',
    href: 'ws://www.example.com/'
  },

  'wss://www.example.com': {
    protocol: 'wss:',
    slashes: true,
    hostname: 'www.example.com',
    host: 'www.example.com',
    pathname: '/',
    path: '/',
    href: 'wss://www.example.com/'
  },

  '//fhqwhgads@example.com/everybody-to-the-limit': {
    protocol: null,
    slashes: true,
    auth: 'fhqwhgads',
    host: 'example.com',
    port: null,
    hostname: 'example.com',
    hash: null,
    search: null,
    query: null,
    pathname: '/everybody-to-the-limit',
    path: '/everybody-to-the-limit',
    href: '//fhqwhgads@example.com/everybody-to-the-limit'
  },

  '//fhqwhgads@example.com/everybody#to-the-limit': {
    protocol: null,
    slashes: true,
    auth: 'fhqwhgads',
    host: 'example.com',
    port: null,
    hostname: 'example.com',
    hash: '#to-the-limit',
    search: null,
    query: null,
    pathname: '/everybody',
    path: '/everybody',
    href: '//fhqwhgads@example.com/everybody#to-the-limit'
  },

  '\bhttp://example.com/\b': {
    protocol: 'http:',
    slashes: true,
    auth: null,
    host: 'example.com',
    port: null,
    hostname: 'example.com',
    hash: null,
    search: null,
    query: null,
    pathname: '/',
    path: '/',
    href: 'http://example.com/'
  },

  'https://evil.com$.example.com': {
    protocol: 'https:',
    slashes: true,
    auth: null,
    host: 'evil.com$.example.com',
    port: null,
    hostname: 'evil.com$.example.com',
    hash: null,
    search: null,
    query: null,
    pathname: '/',
    path: '/',
    href: 'https://evil.com$.example.com/'
  },

  // Validate the output of hostname with commas.
  'x://0.0,1.1/': {
    protocol: 'x:',
    slashes: true,
    auth: null,
    host: '0.0,1.1',
    port: null,
    hostname: '0.0,1.1',
    hash: null,
    search: null,
    query: null,
    pathname: '/',
    path: '/',
    href: 'x://0.0,1.1/'
  }
};

for (const u in parseTests) {
  let actual = url.parse(u);
  const spaced = url.parse(`     \t  ${u}\n\t`);
  let expected = Object.assign(new url.Url(), parseTests[u]);

  Object.keys(actual).forEach(function(i) {
    if (expected[i] === undefined && actual[i] === null) {
      expected[i] = null;
    }
  });

  assert.deepStrictEqual(
    actual,
    expected,
    `parsing ${u} and expected ${inspect(expected)} but got ${inspect(actual)}`
  );
  assert.deepStrictEqual(
    spaced,
    expected,
    `expected ${inspect(expected)}, got ${inspect(spaced)}`
  );

  expected = parseTests[u].href;
  actual = url.format(parseTests[u]);

  assert.strictEqual(actual, expected,
                     `format(${u}) == ${u}\nactual:${actual}`);
}

{
  const parsed = url.parse('http://nodejs.org/')
    .resolveObject('jAvascript:alert(1);a=\x27@white-listed.com\x27');

  const expected = Object.assign(new url.Url(), {
    protocol: 'javascript:',
    slashes: null,
    auth: null,
    host: null,
    port: null,
    hostname: null,
    hash: null,
    search: null,
    query: null,
    pathname: "alert(1);a='@white-listed.com'",
    path: "alert(1);a='@white-listed.com'",
    href: "javascript:alert(1);a='@white-listed.com'"
  });

  assert.deepStrictEqual(parsed, expected);
}
