# file      : tests/url/testscript
# license   : MIT; see accompanying LICENSE file

:basic
:
$*

: components
:
{
  : all
  :
  $* 'https://user@stage.b2.org:443/libbutl?f=full#description' >>EOO
  https
  user@stage.b2.org:443 name
  libbutl
  f=full
  description
  EOO

  : empty-url
  :
  $* '' >>EOO
  <null>
  <null>
  <null>
  <null>
  <null>
  EOO

  : no-id
  :
  {
    $* 'file:#f'  2>'no authority, path or query' != 0 : fragment
    $* 'file:'    2>'no authority, path or query' != 0 : none
  }

  : scheme
  :
  {
    : detected
    :
    $* 'http://build2.org' >>EOO
    http
    @build2.org:0 name
    <null>
    <null>
    <null>
    EOO

    : deduced
    :
    $* 'c:/a' >>EOO
    file
    <null>
    c:/a
    <null>
    <null>
    EOO

    $* ':/a'           2>'no scheme'      != 0 : none
    $* 'http'          2>'no scheme'      != 0 : unterminated
    $* 'ht~tp://a.com' 2>'invalid scheme' != 0 : invalid-char
    $* '1http://a.com' 2>'invalid scheme' != 0 : invalid-first-char
  }

  : authority
  {
    : absent
    :
    $* 'file:/tmp/a' >>EOO
    file
    <null>
    tmp/a
    <null>
    <null>
    EOO

    : empty
    :
    $* 'file:///tmp/a' >>EOO
    file
    @:0 name
    tmp/a
    <null>
    <null>
    EOO

    : query
    :
    $* 'http://localhost?q' >>EOO
    http
    @localhost:0 name
    <null>
    q
    <null>
    EOO

    : fragment
    :
    $* 'http://localhost#master' >>EOO
    http
    @localhost:0 name
    <null>
    <null>
    master
    EOO

    : trailing
    :
    $* 'http://localhost' >>EOO
    http
    @localhost:0 name
    <null>
    <null>
    <null>
    EOO

    : user
    :
    {
      : non-empty
      :
      $* 'http://admin@localhost' >>EOO
      http
      admin@localhost:0 name
      <null>
      <null>
      <null>
      EOO

      : empty
      :
      $* 'http://@localhost' >>EOO
      http
      @localhost:0 name
      <null>
      <null>
      <null>
      EOO
    }

    : host
    :
    {
      : ipv6
      :
      {
        : port
        :
        $* 'http://[1:2:3:4:5:6:7:8]:443' >>EOO
        http
        @1:2:3:4:5:6:7:8:443 ipv6
        <null>
        <null>
        <null>
        EOO

        : no-port
        :
        $* 'http://[1:2:3:4:5:6:7:abcd]' >>EOO
        http
        @1:2:3:4:5:6:7:abcd:0 ipv6
        <null>
        <null>
        <null>
        EOO

        : squashed2-begin
        :
        $* 'http://[::3:4:5:6:7:8]' >>EOO
        http
        @::3:4:5:6:7:8:0 ipv6
        <null>
        <null>
        <null>
        EOO

        : squashed3-end
        :
        $* 'http://[1:2:3:4:5::]' >>EOO
        http
        @1:2:3:4:5:::0 ipv6
        <null>
        <null>
        <null>
        EOO

        : squashed4-middle
        :
        $* 'http://[1:2::7:8]' >>EOO
        http
        @1:2::7:8:0 ipv6
        <null>
        <null>
        <null>
        EOO

        : squashed-all
        :
        $* 'http://[::]' >>EOO
        http
        @:::0 ipv6
        <null>
        <null>
        <null>
        EOO

        $* 'http://[123'      2>'invalid IPv6 address' != 0 : missed-bracket
        $* 'http://[123] :80' 2>'invalid IPv6 address' != 0 : extra-char

        $* 'http://[]'                      2>'invalid IPv6 address' != 0 : empty
        $* 'http://[1:2]'                   2>'invalid IPv6 address' != 0 : too-short
        $* 'http://[1:2:3:4:5:6:7:8:9]'     2>'invalid IPv6 address' != 0 : too-long1
        $* 'http://[::2:3:4:5:6:7:8:9]'     2>'invalid IPv6 address' != 0 : too-long2
        $* 'http://[::3:4::7:8:9]'          2>'invalid IPv6 address' != 0 : several-squashes
        $* 'http://[1:2:3:4::6:7:8:9]'      2>'invalid IPv6 address' != 0 : squash-one-hextet
        $* 'http://[12345:2:3:4:5:6:7:8:9]' 2>'invalid IPv6 address' != 0 : long-hextet
        $* 'http://[123z:2:3:4:5:6:7:8:9]'  2>'invalid IPv6 address' != 0 : not-hex

        : normalize
        :
        {
          test.options += -n -s

          $* 'http://[::01:0:002:00:0003]' >'http://[::1:0:2:0:3]' : strip-zeros
          $* 'http://[::ABC]'              >'http://[::abc]'       : lower-case

          $* 'http://[::]'   >'http://[::]'   : squash-all
          $* 'http://[::1]'  >'http://[::1]'  : squash-left
          $* 'http://[1::]'  >'http://[1::]'  : squash-right
          $* 'http://[1::2]' >'http://[1::2]' : squash-middle

          $* 'http://[1::0:2:0:0:3]'  >'http://[1::2:0:0:3]'    : squash-longest1
          $* 'http://[::0:2:0:0:3]'   >'http://[::2:0:0:3]'     : squash-longest2
          $* 'http://[::0:2:0:0:0:0]' >'http://[0:0:0:2::]'     : squash-longest3
          $* 'http://[0:0:1::2:3:4]'  >'http://[::1:0:0:2:3:4]' : squash-first
          $* 'http://[0:0:2:0:0:0::]' >'http://[0:0:2::]'       : squash-trailing

          $* 'http://[::1:2:3:4:5:6:7]' >'http://[0:1:2:3:4:5:6:7]' : expand-zero
        }
      }

      : ipv4
      :
      {
        : valid
        :
        $* 'http://0.10.200.255' >>EOO
        http
        @0.10.200.255:0 ipv4
        <null>
        <null>
        <null>
        EOO

        : long
        :
        $* 'http://0.10.200.255.30' >>EOO
        http
        @0.10.200.255.30:0 name
        <null>
        <null>
        <null>
        EOO

        : short
        :
        $* 'http://0.10.200' >>EOO
        http
        @0.10.200:0 name
        <null>
        <null>
        <null>
        EOO

        : missed
        :
        $* 'http://0.10..200' >>EOO
        http
        @0.10..200:0 name
        <null>
        <null>
        <null>
        EOO

        : out-of-range
        :
        $* 'http://0.10.200.256' >>EOO
        http
        @0.10.200.256:0 name
        <null>
        <null>
        <null>
        EOO

        : normalize
        :
        {
          test.options += -n -s

          $* 'http://0.010.000.00' >'http://0.10.0.0' : strip-zeros
        }
      }

      : name
      :
      {
        : valid
        :
        $* 'https://www.b2.org' >>EOO
        https
        @www.b2.org:0 name
        <null>
        <null>
        <null>
        EOO

        : encoded
        :
        {
          : valid
          :
          $* 'https://www.%62%32.org' >>EOO
          https
          @www.b2.org:0 name
          <null>
          <null>
          <null>
          EOO

          $* 'https://www.%62%3.org'  2>'invalid URL-encoding' != 0 : short
          $* 'https://www.%62%3x.org' 2>'invalid URL-encoding' != 0 : invalid
          $* 'https://www.%62%.org'   2>'invalid URL-encoding' != 0 : absent
        }

        $* 'https://www.b|2.org' 2>'invalid host name' != 0 : invalid-char

        : normalize
        :
        {
          test.options += -n

          $* -s 'http://Build2.org' >'http://build2.org' : lower-case-char
          $* -w 'http://Build2.org' >'http://build2.org' : lower-case-wchar
        }
      }

      $* 'http://admin@:80?q=' 2>'no host' != 0: no-host
    }

    : port
    :
    {
      : valid
      :
      $* 'http://build2.org:443' >>EOO
      http
      @build2.org:443 name
      <null>
      <null>
      <null>
      EOO

      $* 'http://build2.org:-433'  2>'invalid port' != 0 : invalid-char
      $* 'http://build2.org:70000' 2>'invalid port' != 0 : exceeds-max
      $* 'http://build2.org:0'     2>'invalid port' != 0 : zero
    }
  }

  : path
  :
  {
    : absent
    :
    $* 'http://b2.org' >>EOO
    http
    @b2.org:0 name
    <null>
    <null>
    <null>
    EOO

    : empty
    :
    $* 'http://b2.org/' >>EOO
    http
    @b2.org:0 name

    <null>
    <null>
    EOO

    : non-empty
    :
    $* 'http://b2.org/s/q' >>EOO
    http
    @b2.org:0 name
    s/q
    <null>
    <null>
    EOO

    : encoded
    :
    $* 'http://b2.org/%6F/s' >>EOO
    http
    @b2.org:0 name
    o/s
    <null>
    <null>
    EOO

    $* 'http:a/b/c'  2>'rootless path'    != 0 : rootless-path
    $* 'pkcs11:/abc' 2>'unexpected slash' != 0 : unexpected-slash1
    $* 'pkcs11:a/bc' 2>'unexpected slash' != 0 : unexpected-slash2
  }

  : rootless
  :
  {
    : non-empty
    :
    $* 'pkcs11:token=sign;object=SIGN%20key' >>EOO
    pkcs11
    <null>
    token=sign;object=SIGN key
    <null>
    <null>
    EOO
  }

  : query
  :
  {
    : no-fragment
    :
    $* 'http://b2.org/a?x=foo&y=bar' >>EOO
    http
    @b2.org:0 name
    a
    x=foo&y=bar
    <null>
    EOO

    : fragment
    :
    $* 'http://b2.org/a?foo#bar' >>EOO
    http
    @b2.org:0 name
    a
    foo
    bar
    EOO
  }

  : fragment
  :
  {
    $* 'http://b2.org#foo' >>EOO
    http
    @b2.org:0 name
    <null>
    <null>
    foo
    EOO
  }
}

: string
{
  test.options += -s

  : authority
  :
  {
    : host
    :
    {
      $* 'file:///a'                 >'file:///a'                 : empty
      $* 'https://[1:2:3:4:5:6:7:8]' >'https://[1:2:3:4:5:6:7:8]' : ipv6
      $* 'http://1.1.1.1'            >'http://1.1.1.1'            : ipv4
      $* 'file://a%d1%84'            >'file://a%D1%84'            : name
    }

    $* 'http://admin@localhost' >'http://admin@localhost' : user
    $* 'http://localhost:8080'  >'http://localhost:8080'  : port
    $* 'file:/a'                >'file:/a'                : absent
  }

  $* ''            >''            : empty
  $* 'file:/b%7C2' >'file:/b%7C2' : path
  $* 'http://a?q=' >'http://a?q=' : query
  $* 'http://a#f'  >'http://a#f'  : fragment

  $* 'pkcs11:object=SIGN%20key' >'pkcs11:object=SIGN%20key' : rootless
}

: wstring
:
{
  u = 'https://user@stage.b2.org:443/libbutl?f=full#description'
  $* -w "$u" >"$u"
}