specify posix.sys.socket:
- before:
    sock = require "posix.sys.socket"

    bind, setsockopt, socket = sock.bind, sock.setsockopt, sock.socket
    recvfrom, sendto = sock.recvfrom, sock.sendto
    AF_INET, AF_INET6, AF_UNIX, AF_NETLINK =
      sock.AF_INET, sock.AF_INET6, sock.AF_UNIX, sock.AF_NETLINK
    IPPROTO_TCP, SOCK_DGRAM = sock.IPPROTO_TCP, sock.SOCK_DGRAM
    SOL_SOCKET, SO_RCVTIMEO = sock.SOL_SOCKET, sock.SO_RCVTIMEO


- describe socket:
  - context with bad arguments:
      badargs.diagnose (sock.socket, "(int, int, int)")


- describe socketpair:
  - context with bad arguments:
      badargs.diagnose (sock.socketpair, "(int, int, int)")


- describe getaddrinfo:
  - before:
      getaddrinfo, typeerrors = init (sock, "getaddrinfo")

  - context with bad arguments: |
      badargs.diagnose (getaddrinfo, "(?string, ?string|int, ?table)")

      examples {
        ["it diagnoses unspecified host and service"] = function ()
          expect (getaddrinfo ()).to_raise.
            any_of (typeerrors (2, "string or int"))
        end
      }
      examples {
        ["it diagnoses invalid hints fields"] = function ()
          expect (getaddrinfo ("localhost", nil, {
            protacol=IPPROTO_TCP
          })).to_raise.any_of (typeerrors (3, nil, "protacol"))
          expect (getaddrinfo ("localhost", nil, {
            family=AF_INET, sacktype=SOCK_DGRAM, protocol=IPPROTO_TCP,
          })).to_raise.any_of (typeerrors (3, nil, "sacktype"))
        end
      }
      examples {
        ["it diagnoses wrong hints field types"] = function ()
          expect (getaddrinfo ("localhost", nil, {
            family=false,
          })).to_raise.any_of (typeerrors (3, "int", "family", "boolean"))
          expect (getaddrinfo ("localhost", nil, {
            family=AF_INET, socktype=false,
          })).to_raise.any_of (typeerrors (3, "int", "socktype", "boolean"))
          expect (getaddrinfo ("localhost", nil, {
            family=AF_INET, socktype=SOCK_DGRAM, protocol=false,
          })).to_raise.any_of (typeerrors (3, "int", "protocol", "boolean"))
          expect (getaddrinfo ("localhost", nil, {
            family=AF_INET, socktype=SOCK_DGRAM, protocol=IPPROTO_TCP, flags=false,
          })).to_raise.any_of (typeerrors (3, "int", "flags", "boolean"))
        end
      }


- describe connect:
  - before:
      connect, typeerrors = init (sock, "connect")

  - context with bad arguments: |
      badargs.diagnose (connect, "(int, table)")

      examples {
        ["it diagnoses wrong family types"] = function ()
          expect (connect (42, {family=false})).
            to_raise.any_of (typeerrors (2, "int", "family", "boolean"))
          expect (connect (42, {family=-1})).to_raise.any_of {
            "bad argument #2 to 'connect' (unsupported family type -1)",
            "bad argument #2 to '?' (unsupported family type -1)",
          }
        end
      }
      examples {
        ["it diagnoses wrong AF_INET field types"] = function ()
          expect (connect (42, {family=AF_INET, port=false})).
            to_raise.any_of (typeerrors (2, "int", "port", "boolean"))
          expect (connect (42, {family=AF_INET, port=9999, addr=false})).
            to_raise.any_of (typeerrors (2, "string", "addr", "boolean"))
        end
      }
      examples {
        ["it diagnoses invalid AF_INET fields"] = function ()
          expect (connect (42, {
            family=AF_INET, port=9999, addr="127.0.0.1", flags=false
          })).to_raise.any_of (typeerrors (2, nil, "flags"))
        end
      }
      examples {
        ["it diagnoses wrong AF_INET6 field types"] = function ()
          expect (connect (42, {family = AF_INET6, port = false})).
            to_raise.any_of (typeerrors (2, "int", "port", "boolean"))
          expect (connect (42, {family = AF_INET6, port = 9999, addr = false})).
            to_raise.any_of (typeerrors (2, "string", "addr", "boolean"))
        end
      }
      examples {
        ["it diagnoses invalid AF_INET6 fields"] = function ()
          expect (connect (42, {
            family=AF_INET6, port=9999, addr="::", flags=false
          })).to_raise.any_of (typeerrors (2, nil, "flags"))
        end
      }
      examples {
        ["it diagnoses wrong AF_UNIX field types"] = function ()
          expect (connect (42, {family = AF_UNIX, path = false})).
            to_raise.any_of (typeerrors (2, "string", "path", "boolean"))
        end
      }
      examples {
        ["it diagnoses invalid AF_UNIX fields"] = function ()
          expect (connect (42, {family=AF_UNIX, path="/tmp/afunix", port=9999})).
            to_raise.any_of (typeerrors (2, nil, "port"))
        end
      }
      if AF_NETLINK then
        examples {
          ["it diagnoses wrong AF_NETLINK field types"] = function ()
            expect (connect (42, {family = AF_NETLINK, pid = false})).
              to_raise.any_of (typeerrors (2, "int", "pid", "boolean"))
            expect (connect (42, {family = AF_NETLINK, pid = 9999, groups = false})).
              to_raise.any_of (typeerrors (2, "int", "groups", "boolean"))
          end
        }
        examples {
          ["it diagnoses invalid AF_NETLINK fields"] = function ()
            expect (connect (42, {family=AF_NETLINK, pid=9999, groups=9999, port=9999})).
              to_raise.any_of (typeerrors (2, nil, "port"))
          end
        }
      end


- describe bind:
  - before:
      bind, typeerrors = init (sock, "bind")

  - context with bad arguments: |
      badargs.diagnose (bind, "(int, table)")

      examples {
        ["it diagnoses wrong family types"] = function ()
          expect (bind (42, {family=false})).
            to_raise.any_of (typeerrors (2, "int", "family", "boolean"))
          expect (bind (42, {family=-1})).to_raise.any_of {
            "bad argument #2 to '?' (unsupported family type -1)",
            "bad argument #2 to 'bind' (unsupported family type -1)",
          }
        end
      }
      examples {
        ["it diagnoses wrong AF_INET field types"] = function ()
          expect (bind (42, {family=AF_INET, port=false})).
            to_raise.any_of (typeerrors (2, "int", "port", "boolean"))
          expect (bind (42, {family=AF_INET, port=9999, addr=false})).
            to_raise.any_of (typeerrors (2, "string", "addr", "boolean"))
        end
      }
      examples {
        ["it diagnoses invalid AF_INET fields"] = function ()
          expect (bind (42, {
            family=AF_INET, port=9999, addr="127.0.0.1", flags=false
          })).to_raise.any_of (typeerrors (2, nil, "flags"))
        end
      }
      examples {
        ["it diagnoses wrong AF_INET6 field types"] = function ()
          expect (bind (42, {family = AF_INET6, port = false})).
            to_raise.any_of (typeerrors (2, "int", "port", "boolean"))
          expect (bind (42, {family = AF_INET6, port = 9999, addr = false})).
            to_raise.any_of (typeerrors (2, "string", "addr", "boolean"))
        end
      }
      examples {
        ["it diagnoses invalid AF_INET6 fields"] = function ()
          expect (bind (42, {
            family=AF_INET6, port=9999, addr="::", flags=false
          })).to_raise.any_of (typeerrors (2, nil, "flags"))
        end
      }
      examples {
        ["it diagnoses wrong AF_UNIX field types"] = function ()
          expect (bind (42, {family = AF_UNIX, path = false})).
            to_raise.any_of (typeerrors (2, "string", "path", "boolean"))
        end
      }
      examples {
        ["it diagnoses invalid AF_UNIX fields"] = function ()
          expect (bind (42, {family=AF_UNIX, path="/tmp/afunix", port=9999})).
            to_raise.any_of (typeerrors (2, nil, "port"))
        end
      }
      if AF_NETLINK then
        examples {
          ["it diagnoses wrong AF_NETLINK field types"] = function ()
            expect (bind (42, {family = AF_NETLINK, pid = false})).
              to_raise.any_of (typeerrors (2, "int", "pid", "boolean"))
            expect (bind (42, {family = AF_NETLINK, pid = 9999, groups = false})).
              to_raise.any_of (typeerrors (2, "int", "groups", "boolean"))
          end
        }
        examples {
          ["it diagnoses invalid AF_NETLINK fields"] = function ()
            expect (bind (42, {family=AF_NETLINK, pid=9999, groups=9999, port=9999})).
              to_raise.any_of (typeerrors (2, nil, "port"))
          end
        }
      end


- describe listen:
  - context with bad arguments:
      badargs.diagnose (sock.listen, "(int, int)")


- describe accept:
  - context with bad arguments:
      badargs.diagnose (sock.accept, "(int)")


- describe recv:
  - context with bad arguments:
      badargs.diagnose (sock.recv, "(int, int)")


- describe recvfrom:
  - context with bad arguments:
      badargs.diagnose (sock.recvfrom, "(int, int)")


- describe send:
  - context with bad arguments:
      badargs.diagnose (sock.send, "(int, string)")


- describe sendto:
  - before:
      sendto, typeerrors = init (sock, "sendto")

  - context with bad arguments: |
      badargs.diagnose (sendto, "(int, string, table)")

      examples {
        ["it diagnoses wrong family types"] = function ()
          expect (sendto (42, "msg", {family=false})).
            to_raise.any_of (typeerrors (3, "int", "family", "boolean"))
          expect (sendto (42, "msg", {family=-1})).to_raise.any_of {
            "bad argument #3 to '?' (unsupported family type -1)",
            "bad argument #3 to 'sendto' (unsupported family type -1)",
          }
        end
      }
      examples {
        ["it diagnoses wrong AF_INET field types"] = function ()
          expect (sendto (42, "msg", {family=AF_INET, port=false})).
            to_raise.any_of (typeerrors (3, "int", "port", "boolean"))
          expect (sendto (42, "msg", {family=AF_INET, port=9999, addr=false})).
            to_raise.any_of (typeerrors (3, "string", "addr", "boolean"))
        end
      }
      examples {
        ["it diagnoses invalid AF_INET fields"] = function ()
          expect (sendto (42, "msg", {
            family=AF_INET, port=9999, addr="127.0.0.1", flags=false
          })).to_raise.any_of (typeerrors (3, nil, "flags"))
        end
      }
      examples {
        ["it diagnoses wrong AF_INET6 field types"] = function ()
          expect (sendto (42, "msg", {family = AF_INET6, port = false})).
            to_raise.any_of (typeerrors (3, "int", "port", "boolean"))
          expect (sendto (42, "msg", {family = AF_INET6, port = 9999, addr = false})).
            to_raise.any_of (typeerrors (3, "string", "addr", "boolean"))
        end
      }
      examples {
        ["it diagnoses invalid AF_INET6 fields"] = function ()
          expect (sendto (42, "msg", {
            family=AF_INET6, port=9999, addr="::", flags=false
          })).to_raise.any_of (typeerrors (3, nil, "flags"))
        end
      }
      examples {
        ["it diagnoses wrong AF_UNIX field types"] = function ()
          expect (sendto (42, "msg", {family = AF_UNIX, path = false})).
            to_raise.any_of (typeerrors (3, "string", "path", "boolean"))
        end
      }
      examples {
        ["it diagnoses invalid AF_UNIX fields"] = function ()
          expect (sendto (42, "msg", {family=AF_UNIX, path="/tmp/afunix", port=9999})).
            to_raise.any_of (typeerrors (3, nil, "port"))
        end
      }
      if AF_NETLINK then
        examples {
          ["it diagnoses wrong AF_NETLINK field types"] = function ()
              expect (sendto (42, "msg", {family = AF_NETLINK, pid = false})).
                to_raise.any_of (typeerrors (3, "int", "pid", "boolean"))
              expect (sendto (42, "msg", {family = AF_NETLINK, pid = 9999, groups = false})).
                to_raise.any_of (typeerrors (3, "int", "groups", "boolean"))
          end
        }
        examples {
          ["it diagnoses invalid AF_NETLINK fields"] = function ()
            expect (sendto (42, "msg", {family=AF_NETLINK, pid=9999, groups=9999, port=9999})).
              to_raise.any_of (typeerrors (3, nil, "port"))
          end
        }
      end


- describe shutdown:
  - context with bad arguments:
      badargs.diagnose (sock.shutdown, "(int, int)")


- describe setsockopt:
  - before:
      SOL_SOCKET, SO_LINGER, IPPROTO_TCP =
        sock.SOL_SOCKET, sock.SO_LINGER, sock.IPPROTO_TCP

      setsockopt, typeerrors = init (sock, "setsockopt")

  - context with bad arguments:
    - 'it diagnoses missing argument #1':
        expect (setsockopt ()).to_raise.any_of (typeerrors (1, "int"))
    - 'it diagnoses argument #1 type not int':
        expect (setsockopt (false)).to_raise.any_of (typeerrors (1, "int", "boolean"))
    - 'it diagnoses missing argument #2':
        expect (setsockopt (1)).to_raise.any_of (typeerrors (2, "int"))
    - 'it diagnoses argument #2 type not int':
        expect (setsockopt (1, false)).to_raise.any_of (typeerrors (2, "int", "boolean"))
    - 'it diagnoses missing argument #3':
        expect (setsockopt (1, 2)).to_raise.any_of (typeerrors (3, "int"))
    - 'it diagnoses argument #3 type not int':
        expect (setsockopt (1, 2, false)).to_raise.any_of (typeerrors (3, "int", "boolean"))
    - 'it diagnoses missing argument #4':
        expect (setsockopt (1, SOL_SOCKET, SO_LINGER)).
          to_raise.any_of (typeerrors (4, "int"))
    - 'it diagnoses argument #4 type not int':
        expect (setsockopt (1, SOL_SOCKET, SO_LINGER, false)).
          to_raise.any_of (typeerrors (4, "int", "boolean"))
    - 'it diagnoses missing argument #5':
        expect (setsockopt (1, SOL_SOCKET, SO_LINGER, 4)).
          to_raise.any_of (typeerrors (5, "int"))
    - 'it diagnoses argument #5 type not int':
        expect (setsockopt (1, SOL_SOCKET, SO_LINGER, 4, false)).
          to_raise.any_of (typeerrors (5, "int", "boolean"))
    - it diagnoses too many arguments:
        expect (setsockopt (1, SOL_SOCKET, IPPROTO_TCP, 4, false)).
          to_raise.any_of (typeerrors (5))
        expect (setsockopt (1, SOL_SOCKET, SO_LINGER, 4, 5, false)).
          to_raise.any_of (typeerrors (6))

  - it communicates with IPV4 and IPV6 over loopback: |
      fd = socket (AF_INET6, SOCK_DGRAM, 0)
      expect (type (fd)).to_be "number"
      expect (fd >= 0).to_be (true)

      expect (setsockopt (fd, SOL_SOCKET, SO_RCVTIMEO, 1, 0)).to_be (0)

      expect (bind (fd, { family = AF_INET6, addr = "::", port = 9999 })).
        to_be (0)

      pending "issue #92"
      sockt = { family = AF_INET, addr = "127.0.0.1", port = 59999 }
      expect (sendto (fd, "Test ipv4", sockt)).to_be (9)

      data, so = recvfrom (fd, 1024)
      expect (data).to_be "Test ipv4"
