From b53cf149ad8d7c46572e4567ca949b4f82ebb22c Mon Sep 17 00:00:00 2001 From: eregon Date: Fri, 3 Aug 2018 16:19:40 +0000 Subject: Update to ruby/spec@9be7c7e git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@64180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- spec/ruby/library/date/iso8601_spec.rb | 37 +++ spec/ruby/library/date/parse_spec.rb | 5 + spec/ruby/library/socket/addrinfo/afamily_spec.rb | 5 +- spec/ruby/library/socket/addrinfo/bind_spec.rb | 3 +- .../ruby/library/socket/addrinfo/canonname_spec.rb | 12 +- .../library/socket/addrinfo/connect_from_spec.rb | 75 +++++ spec/ruby/library/socket/addrinfo/connect_spec.rb | 35 +++ .../library/socket/addrinfo/connect_to_spec.rb | 75 +++++ .../socket/addrinfo/family_addrinfo_spec.rb | 115 +++++++ spec/ruby/library/socket/addrinfo/foreach_spec.rb | 9 + .../library/socket/addrinfo/getaddrinfo_spec.rb | 88 ++++++ .../library/socket/addrinfo/getnameinfo_spec.rb | 44 +++ .../library/socket/addrinfo/initialize_spec.rb | 340 ++++++++++++++++++++- .../socket/addrinfo/inspect_sockaddr_spec.rb | 55 +++- spec/ruby/library/socket/addrinfo/inspect_spec.rb | 65 ++++ .../library/socket/addrinfo/ip_address_spec.rb | 55 +++- spec/ruby/library/socket/addrinfo/ip_port_spec.rb | 5 +- spec/ruby/library/socket/addrinfo/ip_spec.rb | 36 ++- .../ruby/library/socket/addrinfo/ip_unpack_spec.rb | 5 +- .../library/socket/addrinfo/ipv4_loopback_spec.rb | 17 +- .../library/socket/addrinfo/ipv4_multicast_spec.rb | 39 +-- .../library/socket/addrinfo/ipv4_private_spec.rb | 14 +- spec/ruby/library/socket/addrinfo/ipv4_spec.rb | 5 +- .../library/socket/addrinfo/ipv6_linklocal_spec.rb | 18 ++ .../library/socket/addrinfo/ipv6_loopback_spec.rb | 9 +- .../library/socket/addrinfo/ipv6_mc_global_spec.rb | 20 ++ .../socket/addrinfo/ipv6_mc_linklocal_spec.rb | 19 ++ .../socket/addrinfo/ipv6_mc_nodelocal_spec.rb | 18 ++ .../socket/addrinfo/ipv6_mc_orglocal_spec.rb | 18 ++ .../socket/addrinfo/ipv6_mc_sitelocal_spec.rb | 18 ++ .../library/socket/addrinfo/ipv6_multicast_spec.rb | 26 +- .../library/socket/addrinfo/ipv6_sitelocal_spec.rb | 18 ++ spec/ruby/library/socket/addrinfo/ipv6_spec.rb | 5 +- .../library/socket/addrinfo/ipv6_to_ipv4_spec.rb | 66 ++++ .../socket/addrinfo/ipv6_unique_local_spec.rb | 18 ++ .../socket/addrinfo/ipv6_unspecified_spec.rb | 15 + .../library/socket/addrinfo/ipv6_v4compat_spec.rb | 20 ++ .../library/socket/addrinfo/ipv6_v4mapped_spec.rb | 20 ++ spec/ruby/library/socket/addrinfo/listen_spec.rb | 34 +++ .../library/socket/addrinfo/marshal_dump_spec.rb | 82 +++++ .../library/socket/addrinfo/marshal_load_spec.rb | 35 +++ spec/ruby/library/socket/addrinfo/pfamily_spec.rb | 11 +- spec/ruby/library/socket/addrinfo/protocol_spec.rb | 28 +- .../library/socket/addrinfo/shared/to_sockaddr.rb | 24 +- spec/ruby/library/socket/addrinfo/socktype_spec.rb | 27 +- spec/ruby/library/socket/addrinfo/tcp_spec.rb | 42 ++- spec/ruby/library/socket/addrinfo/to_s_spec.rb | 3 +- .../library/socket/addrinfo/to_sockaddr_spec.rb | 3 +- spec/ruby/library/socket/addrinfo/udp_spec.rb | 42 ++- .../ruby/library/socket/addrinfo/unix_path_spec.rb | 19 +- spec/ruby/library/socket/addrinfo/unix_spec.rb | 39 ++- .../library/socket/ancillarydata/cmsg_is_spec.rb | 31 ++ .../ruby/library/socket/ancillarydata/data_spec.rb | 9 + .../library/socket/ancillarydata/family_spec.rb | 9 + .../socket/ancillarydata/initialize_spec.rb | 282 +++++++++++++++++ spec/ruby/library/socket/ancillarydata/int_spec.rb | 43 +++ .../socket/ancillarydata/ip_pktinfo_spec.rb | 145 +++++++++ .../socket/ancillarydata/ipv6_pktinfo_addr_spec.rb | 11 + .../ancillarydata/ipv6_pktinfo_ifindex_spec.rb | 11 + .../socket/ancillarydata/ipv6_pktinfo_spec.rb | 89 ++++++ .../library/socket/ancillarydata/level_spec.rb | 9 + .../ruby/library/socket/ancillarydata/type_spec.rb | 9 + .../socket/ancillarydata/unix_rights_spec.rb | 59 ++++ .../library/socket/basicsocket/close_read_spec.rb | 10 +- .../library/socket/basicsocket/close_write_spec.rb | 10 +- .../socket/basicsocket/connect_address_spec.rb | 150 +++++++++ .../basicsocket/do_not_reverse_lookup_spec.rb | 2 +- .../ruby/library/socket/basicsocket/for_fd_spec.rb | 23 +- .../library/socket/basicsocket/getpeereid_spec.rb | 36 +++ .../library/socket/basicsocket/getpeername_spec.rb | 7 +- .../library/socket/basicsocket/getsockname_spec.rb | 4 +- .../library/socket/basicsocket/getsockopt_spec.rb | 144 ++++++++- spec/ruby/library/socket/basicsocket/ioctl_spec.rb | 3 +- .../socket/basicsocket/recv_nonblock_spec.rb | 64 +++- spec/ruby/library/socket/basicsocket/recv_spec.rb | 67 +++- .../socket/basicsocket/recvmsg_nonblock_spec.rb | 204 +++++++++++++ .../library/socket/basicsocket/recvmsg_spec.rb | 197 ++++++++++++ spec/ruby/library/socket/basicsocket/send_spec.rb | 131 +++++++- .../socket/basicsocket/sendmsg_nonblock_spec.rb | 104 +++++++ .../library/socket/basicsocket/sendmsg_spec.rb | 111 +++++++ .../library/socket/basicsocket/setsockopt_spec.rb | 123 +++++++- .../library/socket/basicsocket/shutdown_spec.rb | 153 +++++++++- .../library/socket/constants/constants_spec.rb | 16 +- spec/ruby/library/socket/fixtures/classes.rb | 65 +++- spec/ruby/library/socket/ipsocket/addr_spec.rb | 65 +++- .../library/socket/ipsocket/getaddress_spec.rb | 4 +- spec/ruby/library/socket/ipsocket/peeraddr_spec.rb | 68 ++++- spec/ruby/library/socket/ipsocket/recvfrom_spec.rb | 55 +++- spec/ruby/library/socket/option/bool_spec.rb | 10 +- spec/ruby/library/socket/option/initialize_spec.rb | 83 +++++ spec/ruby/library/socket/option/inspect_spec.rb | 3 +- spec/ruby/library/socket/option/int_spec.rb | 23 +- spec/ruby/library/socket/option/linger_spec.rb | 16 +- spec/ruby/library/socket/option/new_spec.rb | 2 +- spec/ruby/library/socket/shared/pack_sockaddr.rb | 42 ++- spec/ruby/library/socket/shared/recv_nonblock.rb | 52 ---- spec/ruby/library/socket/shared/socketpair.rb | 115 +++++++ .../ruby/library/socket/socket/accept_loop_spec.rb | 80 +++++ .../library/socket/socket/accept_nonblock_spec.rb | 107 ++++++- spec/ruby/library/socket/socket/accept_spec.rb | 122 +++++++- spec/ruby/library/socket/socket/bind_spec.rb | 71 ++++- .../library/socket/socket/connect_nonblock_spec.rb | 56 +++- spec/ruby/library/socket/socket/connect_spec.rb | 48 ++- spec/ruby/library/socket/socket/for_fd_spec.rb | 3 +- .../ruby/library/socket/socket/getaddrinfo_spec.rb | 279 ++++++++++++++++- .../library/socket/socket/gethostbyaddr_spec.rb | 121 +++++++- .../library/socket/socket/gethostbyname_spec.rb | 124 +++++++- .../ruby/library/socket/socket/gethostname_spec.rb | 2 +- spec/ruby/library/socket/socket/getifaddrs_spec.rb | 108 +++++++ .../ruby/library/socket/socket/getnameinfo_spec.rb | 94 +++++- .../library/socket/socket/getservbyname_spec.rb | 10 +- .../library/socket/socket/getservbyport_spec.rb | 23 ++ spec/ruby/library/socket/socket/initialize_spec.rb | 87 ++++++ .../library/socket/socket/ip_address_list_spec.rb | 50 +++ .../library/socket/socket/ipv6only_bang_spec.rb | 17 ++ spec/ruby/library/socket/socket/listen_spec.rb | 50 ++- .../library/socket/socket/local_address_spec.rb | 43 +++ spec/ruby/library/socket/socket/new_spec.rb | 2 +- .../library/socket/socket/pack_sockaddr_in_spec.rb | 2 +- .../library/socket/socket/pack_sockaddr_un_spec.rb | 2 +- spec/ruby/library/socket/socket/pair_spec.rb | 2 +- .../socket/socket/recvfrom_nonblock_spec.rb | 110 ++++++- spec/ruby/library/socket/socket/recvfrom_spec.rb | 92 +++++- .../library/socket/socket/remote_address_spec.rb | 54 ++++ .../ruby/library/socket/socket/sockaddr_in_spec.rb | 2 +- .../ruby/library/socket/socket/sockaddr_un_spec.rb | 2 +- spec/ruby/library/socket/socket/socket_spec.rb | 2 +- spec/ruby/library/socket/socket/socketpair_spec.rb | 2 +- spec/ruby/library/socket/socket/sysaccept_spec.rb | 93 +++++- .../library/socket/socket/tcp_server_loop_spec.rb | 47 +++ .../socket/socket/tcp_server_sockets_spec.rb | 39 +++ spec/ruby/library/socket/socket/tcp_spec.rb | 70 +++++ .../socket/socket/udp_server_loop_on_spec.rb | 47 +++ .../library/socket/socket/udp_server_loop_spec.rb | 47 +++ .../library/socket/socket/udp_server_recv_spec.rb | 32 ++ .../socket/socket/udp_server_sockets_spec.rb | 39 +++ .../library/socket/socket/unix_server_loop_spec.rb | 51 ++++ .../socket/socket/unix_server_socket_spec.rb | 48 +++ spec/ruby/library/socket/socket/unix_spec.rb | 45 +++ .../socket/socket/unpack_sockaddr_in_spec.rb | 27 +- .../socket/socket/unpack_sockaddr_un_spec.rb | 6 +- spec/ruby/library/socket/spec_helper.rb | 16 + .../socket/tcpserver/accept_nonblock_spec.rb | 38 ++- spec/ruby/library/socket/tcpserver/accept_spec.rb | 37 ++- spec/ruby/library/socket/tcpserver/gets_spec.rb | 2 +- .../library/socket/tcpserver/initialize_spec.rb | 99 ++++++ spec/ruby/library/socket/tcpserver/listen_spec.rb | 26 +- spec/ruby/library/socket/tcpserver/new_spec.rb | 4 +- .../library/socket/tcpserver/sysaccept_spec.rb | 40 ++- .../library/socket/tcpsocket/gethostbyname_spec.rb | 62 +++- .../library/socket/tcpsocket/initialize_spec.rb | 61 ++++ .../library/socket/tcpsocket/local_address_spec.rb | 73 +++++ .../socket/tcpsocket/partially_closable_spec.rb | 2 +- .../library/socket/tcpsocket/recv_nonblock_spec.rb | 2 +- spec/ruby/library/socket/tcpsocket/recv_spec.rb | 28 ++ .../socket/tcpsocket/remote_address_spec.rb | 72 +++++ .../library/socket/tcpsocket/setsockopt_spec.rb | 2 +- spec/ruby/library/socket/tcpsocket/shared/new.rb | 2 +- spec/ruby/library/socket/udpsocket/bind_spec.rb | 49 ++- spec/ruby/library/socket/udpsocket/connect_spec.rb | 35 +++ .../library/socket/udpsocket/initialize_spec.rb | 36 +++ spec/ruby/library/socket/udpsocket/inspect_spec.rb | 25 ++ .../library/socket/udpsocket/local_address_spec.rb | 80 +++++ spec/ruby/library/socket/udpsocket/new_spec.rb | 2 +- spec/ruby/library/socket/udpsocket/open_spec.rb | 2 +- .../socket/udpsocket/recvfrom_nonblock_spec.rb | 88 ++++++ .../socket/udpsocket/remote_address_spec.rb | 79 +++++ spec/ruby/library/socket/udpsocket/send_spec.rb | 80 ++++- spec/ruby/library/socket/udpsocket/write_spec.rb | 2 +- .../socket/unixserver/accept_nonblock_spec.rb | 58 +++- spec/ruby/library/socket/unixserver/accept_spec.rb | 58 +++- spec/ruby/library/socket/unixserver/for_fd_spec.rb | 2 +- .../library/socket/unixserver/initialize_spec.rb | 28 ++ spec/ruby/library/socket/unixserver/listen_spec.rb | 21 ++ spec/ruby/library/socket/unixserver/new_spec.rb | 2 +- spec/ruby/library/socket/unixserver/open_spec.rb | 3 +- spec/ruby/library/socket/unixserver/shared/new.rb | 3 +- .../library/socket/unixserver/sysaccept_spec.rb | 52 ++++ spec/ruby/library/socket/unixsocket/addr_spec.rb | 12 +- .../library/socket/unixsocket/initialize_spec.rb | 38 +++ .../ruby/library/socket/unixsocket/inspect_spec.rb | 2 +- .../socket/unixsocket/local_address_spec.rb | 45 +++ spec/ruby/library/socket/unixsocket/new_spec.rb | 2 +- spec/ruby/library/socket/unixsocket/open_spec.rb | 3 +- spec/ruby/library/socket/unixsocket/pair_spec.rb | 2 +- .../socket/unixsocket/partially_closable_spec.rb | 2 +- spec/ruby/library/socket/unixsocket/path_spec.rb | 2 +- .../library/socket/unixsocket/peeraddr_spec.rb | 2 +- .../ruby/library/socket/unixsocket/recv_io_spec.rb | 47 ++- .../library/socket/unixsocket/recvfrom_spec.rb | 54 +++- .../socket/unixsocket/remote_address_spec.rb | 45 +++ .../ruby/library/socket/unixsocket/send_io_spec.rb | 25 +- spec/ruby/library/socket/unixsocket/shared/new.rb | 2 +- .../library/socket/unixsocket/socketpair_spec.rb | 40 +++ spec/ruby/library/weakref/allocate_spec.rb | 8 + spec/ruby/library/weakref/new_spec.rb | 13 + spec/ruby/library/zlib/deflate/deflate_spec.rb | 2 +- spec/ruby/library/zlib/deflate_spec.rb | 8 + spec/ruby/library/zlib/inflate_spec.rb | 8 + 199 files changed, 8264 insertions(+), 432 deletions(-) create mode 100644 spec/ruby/library/date/iso8601_spec.rb create mode 100644 spec/ruby/library/socket/addrinfo/connect_from_spec.rb create mode 100644 spec/ruby/library/socket/addrinfo/connect_spec.rb create mode 100644 spec/ruby/library/socket/addrinfo/connect_to_spec.rb create mode 100644 spec/ruby/library/socket/addrinfo/family_addrinfo_spec.rb create mode 100644 spec/ruby/library/socket/addrinfo/foreach_spec.rb create mode 100644 spec/ruby/library/socket/addrinfo/getaddrinfo_spec.rb create mode 100644 spec/ruby/library/socket/addrinfo/getnameinfo_spec.rb create mode 100644 spec/ruby/library/socket/addrinfo/inspect_spec.rb create mode 100644 spec/ruby/library/socket/addrinfo/ipv6_linklocal_spec.rb create mode 100644 spec/ruby/library/socket/addrinfo/ipv6_mc_global_spec.rb create mode 100644 spec/ruby/library/socket/addrinfo/ipv6_mc_linklocal_spec.rb create mode 100644 spec/ruby/library/socket/addrinfo/ipv6_mc_nodelocal_spec.rb create mode 100644 spec/ruby/library/socket/addrinfo/ipv6_mc_orglocal_spec.rb create mode 100644 spec/ruby/library/socket/addrinfo/ipv6_mc_sitelocal_spec.rb create mode 100644 spec/ruby/library/socket/addrinfo/ipv6_sitelocal_spec.rb create mode 100644 spec/ruby/library/socket/addrinfo/ipv6_to_ipv4_spec.rb create mode 100644 spec/ruby/library/socket/addrinfo/ipv6_unique_local_spec.rb create mode 100644 spec/ruby/library/socket/addrinfo/ipv6_unspecified_spec.rb create mode 100644 spec/ruby/library/socket/addrinfo/ipv6_v4compat_spec.rb create mode 100644 spec/ruby/library/socket/addrinfo/ipv6_v4mapped_spec.rb create mode 100644 spec/ruby/library/socket/addrinfo/listen_spec.rb create mode 100644 spec/ruby/library/socket/addrinfo/marshal_dump_spec.rb create mode 100644 spec/ruby/library/socket/addrinfo/marshal_load_spec.rb create mode 100644 spec/ruby/library/socket/ancillarydata/cmsg_is_spec.rb create mode 100644 spec/ruby/library/socket/ancillarydata/data_spec.rb create mode 100644 spec/ruby/library/socket/ancillarydata/family_spec.rb create mode 100644 spec/ruby/library/socket/ancillarydata/initialize_spec.rb create mode 100644 spec/ruby/library/socket/ancillarydata/int_spec.rb create mode 100644 spec/ruby/library/socket/ancillarydata/ip_pktinfo_spec.rb create mode 100644 spec/ruby/library/socket/ancillarydata/ipv6_pktinfo_addr_spec.rb create mode 100644 spec/ruby/library/socket/ancillarydata/ipv6_pktinfo_ifindex_spec.rb create mode 100644 spec/ruby/library/socket/ancillarydata/ipv6_pktinfo_spec.rb create mode 100644 spec/ruby/library/socket/ancillarydata/level_spec.rb create mode 100644 spec/ruby/library/socket/ancillarydata/type_spec.rb create mode 100644 spec/ruby/library/socket/ancillarydata/unix_rights_spec.rb create mode 100644 spec/ruby/library/socket/basicsocket/connect_address_spec.rb create mode 100644 spec/ruby/library/socket/basicsocket/getpeereid_spec.rb create mode 100644 spec/ruby/library/socket/basicsocket/recvmsg_nonblock_spec.rb create mode 100644 spec/ruby/library/socket/basicsocket/recvmsg_spec.rb create mode 100644 spec/ruby/library/socket/basicsocket/sendmsg_nonblock_spec.rb create mode 100644 spec/ruby/library/socket/basicsocket/sendmsg_spec.rb create mode 100644 spec/ruby/library/socket/option/initialize_spec.rb delete mode 100644 spec/ruby/library/socket/shared/recv_nonblock.rb create mode 100644 spec/ruby/library/socket/socket/accept_loop_spec.rb create mode 100644 spec/ruby/library/socket/socket/getifaddrs_spec.rb create mode 100644 spec/ruby/library/socket/socket/getservbyport_spec.rb create mode 100644 spec/ruby/library/socket/socket/initialize_spec.rb create mode 100644 spec/ruby/library/socket/socket/ip_address_list_spec.rb create mode 100644 spec/ruby/library/socket/socket/ipv6only_bang_spec.rb create mode 100644 spec/ruby/library/socket/socket/local_address_spec.rb create mode 100644 spec/ruby/library/socket/socket/remote_address_spec.rb create mode 100644 spec/ruby/library/socket/socket/tcp_server_loop_spec.rb create mode 100644 spec/ruby/library/socket/socket/tcp_server_sockets_spec.rb create mode 100644 spec/ruby/library/socket/socket/tcp_spec.rb create mode 100644 spec/ruby/library/socket/socket/udp_server_loop_on_spec.rb create mode 100644 spec/ruby/library/socket/socket/udp_server_loop_spec.rb create mode 100644 spec/ruby/library/socket/socket/udp_server_recv_spec.rb create mode 100644 spec/ruby/library/socket/socket/udp_server_sockets_spec.rb create mode 100644 spec/ruby/library/socket/socket/unix_server_loop_spec.rb create mode 100644 spec/ruby/library/socket/socket/unix_server_socket_spec.rb create mode 100644 spec/ruby/library/socket/socket/unix_spec.rb create mode 100644 spec/ruby/library/socket/spec_helper.rb create mode 100644 spec/ruby/library/socket/tcpserver/initialize_spec.rb create mode 100644 spec/ruby/library/socket/tcpsocket/initialize_spec.rb create mode 100644 spec/ruby/library/socket/tcpsocket/local_address_spec.rb create mode 100644 spec/ruby/library/socket/tcpsocket/recv_spec.rb create mode 100644 spec/ruby/library/socket/tcpsocket/remote_address_spec.rb create mode 100644 spec/ruby/library/socket/udpsocket/connect_spec.rb create mode 100644 spec/ruby/library/socket/udpsocket/initialize_spec.rb create mode 100644 spec/ruby/library/socket/udpsocket/inspect_spec.rb create mode 100644 spec/ruby/library/socket/udpsocket/local_address_spec.rb create mode 100644 spec/ruby/library/socket/udpsocket/recvfrom_nonblock_spec.rb create mode 100644 spec/ruby/library/socket/udpsocket/remote_address_spec.rb create mode 100644 spec/ruby/library/socket/unixserver/initialize_spec.rb create mode 100644 spec/ruby/library/socket/unixserver/listen_spec.rb create mode 100644 spec/ruby/library/socket/unixserver/sysaccept_spec.rb create mode 100644 spec/ruby/library/socket/unixsocket/initialize_spec.rb create mode 100644 spec/ruby/library/socket/unixsocket/local_address_spec.rb create mode 100644 spec/ruby/library/socket/unixsocket/remote_address_spec.rb create mode 100644 spec/ruby/library/socket/unixsocket/socketpair_spec.rb create mode 100644 spec/ruby/library/weakref/allocate_spec.rb create mode 100644 spec/ruby/library/weakref/new_spec.rb create mode 100644 spec/ruby/library/zlib/deflate_spec.rb create mode 100644 spec/ruby/library/zlib/inflate_spec.rb (limited to 'spec/ruby/library') diff --git a/spec/ruby/library/date/iso8601_spec.rb b/spec/ruby/library/date/iso8601_spec.rb new file mode 100644 index 0000000000..41f055e648 --- /dev/null +++ b/spec/ruby/library/date/iso8601_spec.rb @@ -0,0 +1,37 @@ +require_relative '../../spec_helper' +require 'date' + +describe "Date.iso8601" do + it "parses YYYY-MM-DD into a Date object" do + d = Date.iso8601("2018-01-01") + d.should == Date.civil(2018, 1, 1) + end + + it "parses YYYYMMDD into a Date object" do + d = Date.iso8601("20180715") + d.should == Date.civil(2018, 7, 15) + end + + it "parses a negative Date" do + d = Date.iso8601("-4712-01-01") + d.should == Date.civil(-4712, 1, 1) + end + + it "parses a Symbol into a Date object" do + d = Date.iso8601(:'2015-10-15') + d.should == Date.civil(2015, 10, 15) + end + + it "parses a StringSubclass into a Date object" do + d = Date.iso8601(Class.new(String).new("-4712-01-01")) + d.should == Date.civil(-4712, 1, 1) + end + + it "raises an ArgumentError when passed a Symbol without a valid Date" do + lambda { Date.iso8601(:test) }.should raise_error(ArgumentError) + end + + it "raises a TypeError when passed an Object" do + lambda { Date.iso8601(Object.new) }.should raise_error(TypeError) + end +end diff --git a/spec/ruby/library/date/parse_spec.rb b/spec/ruby/library/date/parse_spec.rb index 0c21e9aeba..09e072ba3e 100644 --- a/spec/ruby/library/date/parse_spec.rb +++ b/spec/ruby/library/date/parse_spec.rb @@ -64,6 +64,11 @@ describe "Date#parse" do d = Date.parse("19101101") d.should == Date.civil(1910, 11, 1) end + + it "raises a TypeError trying to parse non-String-like object" do + lambda { Date.parse(1) }.should raise_error(TypeError) + lambda { Date.parse(:invalid) }.should raise_error(TypeError) + end end describe "Date#parse with '.' separator" do diff --git a/spec/ruby/library/socket/addrinfo/afamily_spec.rb b/spec/ruby/library/socket/addrinfo/afamily_spec.rb index 5e61c8f99c..7229dab9de 100644 --- a/spec/ruby/library/socket/addrinfo/afamily_spec.rb +++ b/spec/ruby/library/socket/addrinfo/afamily_spec.rb @@ -1,5 +1,4 @@ -require_relative '../../../spec_helper' -require 'socket' +require_relative '../spec_helper' describe "Addrinfo#afamily" do describe "for an ipv4 socket" do @@ -24,7 +23,7 @@ describe "Addrinfo#afamily" do end end - platform_is_not :windows do + with_feature :unix_socket do describe "for a unix socket" do before :each do @addrinfo = Addrinfo.unix("/tmp/sock") diff --git a/spec/ruby/library/socket/addrinfo/bind_spec.rb b/spec/ruby/library/socket/addrinfo/bind_spec.rb index 8a20ab54d4..6f78890a4d 100644 --- a/spec/ruby/library/socket/addrinfo/bind_spec.rb +++ b/spec/ruby/library/socket/addrinfo/bind_spec.rb @@ -1,6 +1,5 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' -require 'socket' describe "Addrinfo#bind" do diff --git a/spec/ruby/library/socket/addrinfo/canonname_spec.rb b/spec/ruby/library/socket/addrinfo/canonname_spec.rb index 6105d905d6..a1cc8b3980 100644 --- a/spec/ruby/library/socket/addrinfo/canonname_spec.rb +++ b/spec/ruby/library/socket/addrinfo/canonname_spec.rb @@ -1,6 +1,5 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' -require 'socket' describe "Addrinfo#canonname" do @@ -16,4 +15,13 @@ describe "Addrinfo#canonname" do canonname.should == nil end end + + describe 'when the canonical name is not available' do + it 'returns nil' do + addr = Addrinfo.new(Socket.sockaddr_in(0, '127.0.0.1')) + + addr.canonname.should be_nil + end + end + end diff --git a/spec/ruby/library/socket/addrinfo/connect_from_spec.rb b/spec/ruby/library/socket/addrinfo/connect_from_spec.rb new file mode 100644 index 0000000000..55fce2e159 --- /dev/null +++ b/spec/ruby/library/socket/addrinfo/connect_from_spec.rb @@ -0,0 +1,75 @@ +require_relative '../spec_helper' +require_relative '../fixtures/classes' + +describe 'Addrinfo#connect_from' do + SocketSpecs.each_ip_protocol do |family, ip_address| + before do + @server = TCPServer.new(ip_address, 0) + @port = @server.connect_address.ip_port + @addr = Addrinfo.tcp(ip_address, @port) + end + + after do + @socket.close if @socket + @server.close + end + + describe 'using separate arguments' do + it 'returns a Socket when no block is given' do + @socket = @addr.connect_from(ip_address, 0) + @socket.should be_an_instance_of(Socket) + end + + it 'yields the Socket when a block is given' do + @addr.connect_from(ip_address, 0) do |socket| + socket.should be_an_instance_of(Socket) + end + end + + it 'treats the last argument as a set of options if it is a Hash' do + @socket = @addr.connect_from(ip_address, 0, timeout: 2) + @socket.should be_an_instance_of(Socket) + end + + it 'binds the socket to the local address' do + @socket = @addr.connect_from(ip_address, 0) + + @socket.local_address.ip_address.should == ip_address + + @socket.local_address.ip_port.should > 0 + @socket.local_address.ip_port.should_not == @port + end + end + + describe 'using an Addrinfo as the 1st argument' do + before do + @from_addr = Addrinfo.tcp(ip_address, 0) + end + + it 'returns a Socket when no block is given' do + @socket = @addr.connect_from(@from_addr) + @socket.should be_an_instance_of(Socket) + end + + it 'yields the Socket when a block is given' do + @addr.connect_from(@from_addr) do |socket| + socket.should be_an_instance_of(Socket) + end + end + + it 'treats the last argument as a set of options if it is a Hash' do + @socket = @addr.connect_from(@from_addr, timeout: 2) + @socket.should be_an_instance_of(Socket) + end + + it 'binds the socket to the local address' do + @socket = @addr.connect_from(@from_addr) + + @socket.local_address.ip_address.should == ip_address + + @socket.local_address.ip_port.should > 0 + @socket.local_address.ip_port.should_not == @port + end + end + end +end diff --git a/spec/ruby/library/socket/addrinfo/connect_spec.rb b/spec/ruby/library/socket/addrinfo/connect_spec.rb new file mode 100644 index 0000000000..1c2dc609ca --- /dev/null +++ b/spec/ruby/library/socket/addrinfo/connect_spec.rb @@ -0,0 +1,35 @@ +require_relative '../spec_helper' +require_relative '../fixtures/classes' + +describe 'Addrinfo#connect' do + SocketSpecs.each_ip_protocol do |family, ip_address| + before do + @server = TCPServer.new(ip_address, 0) + @port = @server.connect_address.ip_port + end + + after do + @socket.close if @socket + @server.close + end + + it 'returns a Socket when no block is given' do + addr = Addrinfo.tcp(ip_address, @port) + @socket = addr.connect + @socket.should be_an_instance_of(Socket) + end + + it 'yields a Socket when a block is given' do + addr = Addrinfo.tcp(ip_address, @port) + addr.connect do |socket| + socket.should be_an_instance_of(Socket) + end + end + + it 'accepts a Hash of options' do + addr = Addrinfo.tcp(ip_address, @port) + @socket = addr.connect(timeout: 2) + @socket.should be_an_instance_of(Socket) + end + end +end diff --git a/spec/ruby/library/socket/addrinfo/connect_to_spec.rb b/spec/ruby/library/socket/addrinfo/connect_to_spec.rb new file mode 100644 index 0000000000..69666da19b --- /dev/null +++ b/spec/ruby/library/socket/addrinfo/connect_to_spec.rb @@ -0,0 +1,75 @@ +require_relative '../spec_helper' +require_relative '../fixtures/classes' + +describe 'Addrinfo#connect_to' do + SocketSpecs.each_ip_protocol do |family, ip_address| + before do + @server = TCPServer.new(ip_address, 0) + @port = @server.connect_address.ip_port + @addr = Addrinfo.tcp(ip_address, 0) + end + + after do + @socket.close if @socket + @server.close + end + + describe 'using separate arguments' do + it 'returns a Socket when no block is given' do + @socket = @addr.connect_to(ip_address, @port) + @socket.should be_an_instance_of(Socket) + end + + it 'yields the Socket when a block is given' do + @addr.connect_to(ip_address, @port) do |socket| + socket.should be_an_instance_of(Socket) + end + end + + it 'treats the last argument as a set of options if it is a Hash' do + @socket = @addr.connect_to(ip_address, @port, timeout: 2) + @socket.should be_an_instance_of(Socket) + end + + it 'binds the Addrinfo to the local address' do + @socket = @addr.connect_to(ip_address, @port) + + @socket.local_address.ip_address.should == ip_address + + @socket.local_address.ip_port.should > 0 + @socket.local_address.ip_port.should_not == @port + end + end + + describe 'using an Addrinfo as the 1st argument' do + before do + @to_addr = Addrinfo.tcp(ip_address, @port) + end + + it 'returns a Socket when no block is given' do + @socket = @addr.connect_to(@to_addr) + @socket.should be_an_instance_of(Socket) + end + + it 'yields the Socket when a block is given' do + @addr.connect_to(@to_addr) do |socket| + socket.should be_an_instance_of(Socket) + end + end + + it 'treats the last argument as a set of options if it is a Hash' do + @socket = @addr.connect_to(@to_addr, timeout: 2) + @socket.should be_an_instance_of(Socket) + end + + it 'binds the socket to the local address' do + @socket = @addr.connect_to(@to_addr) + + @socket.local_address.ip_address.should == ip_address + + @socket.local_address.ip_port.should > 0 + @socket.local_address.ip_port.should_not == @port + end + end + end +end diff --git a/spec/ruby/library/socket/addrinfo/family_addrinfo_spec.rb b/spec/ruby/library/socket/addrinfo/family_addrinfo_spec.rb new file mode 100644 index 0000000000..d3419daaaf --- /dev/null +++ b/spec/ruby/library/socket/addrinfo/family_addrinfo_spec.rb @@ -0,0 +1,115 @@ +require_relative '../spec_helper' + +describe 'Addrinfo#family_addrinfo' do + it 'raises ArgumentError if no arguments are given' do + addr = Addrinfo.tcp('127.0.0.1', 0) + + lambda { addr.family_addrinfo }.should raise_error(ArgumentError) + end + + describe 'using multiple arguments' do + describe 'with an IP Addrinfo' do + before do + @source = Addrinfo.tcp('127.0.0.1', 0) + end + + it 'raises ArgumentError if only 1 argument is given' do + lambda { @source.family_addrinfo('127.0.0.1') }.should raise_error(ArgumentError) + end + + it 'raises ArgumentError if more than 2 arguments are given' do + lambda { @source.family_addrinfo('127.0.0.1', 0, 666) }.should raise_error(ArgumentError) + end + + it 'returns an Addrinfo when a host and port are given' do + addr = @source.family_addrinfo('127.0.0.1', 0) + + addr.should be_an_instance_of(Addrinfo) + end + + describe 'the returned Addrinfo' do + before do + @addr = @source.family_addrinfo('127.0.0.1', 0) + end + + it 'uses the same address family as the source Addrinfo' do + @addr.afamily.should == @source.afamily + end + + it 'uses the same protocol family as the source Addrinfo' do + @addr.pfamily.should == @source.pfamily + end + + it 'uses the same socket type as the source Addrinfo' do + @addr.socktype.should == @source.socktype + end + + it 'uses the same protocol as the source Addrinfo' do + @addr.protocol.should == @source.protocol + end + end + end + + with_feature :unix_socket do + describe 'with a UNIX Addrinfo' do + before do + @source = Addrinfo.unix('cats') + end + + it 'raises ArgumentError if more than 1 argument is given' do + lambda { @source.family_addrinfo('foo', 'bar') }.should raise_error(ArgumentError) + end + + it 'returns an Addrinfo when a UNIX socket path is given' do + addr = @source.family_addrinfo('dogs') + + addr.should be_an_instance_of(Addrinfo) + end + + describe 'the returned Addrinfo' do + before do + @addr = @source.family_addrinfo('dogs') + end + + it 'uses AF_UNIX as the address family' do + @addr.afamily.should == Socket::AF_UNIX + end + + it 'uses PF_UNIX as the protocol family' do + @addr.pfamily.should == Socket::PF_UNIX + end + + it 'uses the given socket path' do + @addr.unix_path.should == 'dogs' + end + end + end + end + end + + describe 'using an Addrinfo as the 1st argument' do + before do + @source = Addrinfo.tcp('127.0.0.1', 0) + end + + it 'returns the input Addrinfo' do + input = Addrinfo.tcp('127.0.0.2', 0) + @source.family_addrinfo(input).should == input + end + + it 'raises ArgumentError if more than 1 argument is given' do + input = Addrinfo.tcp('127.0.0.2', 0) + lambda { @source.family_addrinfo(input, 666) }.should raise_error(ArgumentError) + end + + it "raises ArgumentError if the protocol families don't match" do + input = Addrinfo.tcp('::1', 0) + lambda { @source.family_addrinfo(input) }.should raise_error(ArgumentError) + end + + it "raises ArgumentError if the socket types don't match" do + input = Addrinfo.udp('127.0.0.1', 0) + lambda { @source.family_addrinfo(input) }.should raise_error(ArgumentError) + end + end +end diff --git a/spec/ruby/library/socket/addrinfo/foreach_spec.rb b/spec/ruby/library/socket/addrinfo/foreach_spec.rb new file mode 100644 index 0000000000..75c1d1dea2 --- /dev/null +++ b/spec/ruby/library/socket/addrinfo/foreach_spec.rb @@ -0,0 +1,9 @@ +require_relative '../spec_helper' + +describe 'Addrinfo.foreach' do + it 'yields Addrinfo instances to the supplied block' do + Addrinfo.foreach('localhost', 80) do |addr| + addr.should be_an_instance_of(Addrinfo) + end + end +end diff --git a/spec/ruby/library/socket/addrinfo/getaddrinfo_spec.rb b/spec/ruby/library/socket/addrinfo/getaddrinfo_spec.rb new file mode 100644 index 0000000000..f0e4b3c986 --- /dev/null +++ b/spec/ruby/library/socket/addrinfo/getaddrinfo_spec.rb @@ -0,0 +1,88 @@ +require_relative '../spec_helper' +require_relative '../fixtures/classes' + +describe 'Addrinfo.getaddrinfo' do + it 'returns an Array of Addrinfo instances' do + array = Addrinfo.getaddrinfo('localhost', 80) + + array.should be_an_instance_of(Array) + array[0].should be_an_instance_of(Addrinfo) + end + + SocketSpecs.each_ip_protocol do |family, ip_address| + it 'sets the IP address of the Addrinfo instances' do + array = Addrinfo.getaddrinfo(ip_address, 80) + + array[0].ip_address.should == ip_address + end + + it 'sets the port of the Addrinfo instances' do + array = Addrinfo.getaddrinfo(ip_address, 80) + + array[0].ip_port.should == 80 + end + + it 'sets the address family of the Addrinfo instances' do + array = Addrinfo.getaddrinfo(ip_address, 80) + + array[0].afamily.should == family + end + + it 'sets the protocol family of the Addrinfo instances' do + array = Addrinfo.getaddrinfo(ip_address, 80) + + array[0].pfamily.should == family + end + end + + guard -> { SocketSpecs.ipv6_available? } do + it 'sets a custom protocol family of the Addrinfo instances' do + array = Addrinfo.getaddrinfo('localhost', 80, Socket::PF_INET6) + + array[0].pfamily.should == Socket::PF_INET6 + end + + it 'sets a corresponding address family based on a custom protocol family' do + array = Addrinfo.getaddrinfo('localhost', 80, Socket::PF_INET6) + + array[0].afamily.should == Socket::AF_INET6 + end + end + + platform_is_not :windows do + it 'sets the default socket type of the Addrinfo instances' do + array = Addrinfo.getaddrinfo('localhost', 80) + possible = [Socket::SOCK_STREAM, Socket::SOCK_DGRAM] + + possible.should include(array[0].socktype) + end + end + + it 'sets a custom socket type of the Addrinfo instances' do + array = Addrinfo.getaddrinfo('localhost', 80, nil, Socket::SOCK_DGRAM) + + array[0].socktype.should == Socket::SOCK_DGRAM + end + + platform_is_not :windows do + it 'sets the default socket protocol of the Addrinfo instances' do + array = Addrinfo.getaddrinfo('localhost', 80) + possible = [Socket::IPPROTO_TCP, Socket::IPPROTO_UDP] + + possible.should include(array[0].protocol) + end + end + + it 'sets a custom socket protocol of the Addrinfo instances' do + array = Addrinfo.getaddrinfo('localhost', 80, nil, nil, Socket::IPPROTO_UDP) + + array[0].protocol.should == Socket::IPPROTO_UDP + end + + it 'sets the canonical name when AI_CANONNAME is given as a flag' do + array = Addrinfo + .getaddrinfo('localhost', 80, nil, nil, nil, Socket::AI_CANONNAME) + + array[0].canonname.should be_an_instance_of(String) + end +end diff --git a/spec/ruby/library/socket/addrinfo/getnameinfo_spec.rb b/spec/ruby/library/socket/addrinfo/getnameinfo_spec.rb new file mode 100644 index 0000000000..eb600f3e66 --- /dev/null +++ b/spec/ruby/library/socket/addrinfo/getnameinfo_spec.rb @@ -0,0 +1,44 @@ +require_relative '../spec_helper' +require_relative '../fixtures/classes' + +describe 'Addrinfo#getnameinfo' do + describe 'using an IP Addrinfo' do + SocketSpecs.each_ip_protocol do |family, ip_address| + before do + @addr = Addrinfo.tcp(ip_address, 80) + end + + it 'returns the node and service names' do + host, service = @addr.getnameinfo + + host.should be_an_instance_of(String) + service.should == 'http' + end + + it 'accepts flags as a Fixnum as the first argument' do + host, service = @addr.getnameinfo(Socket::NI_NUMERICSERV) + + host.should be_an_instance_of(String) + service.should == '80' + end + end + end + + platform_is :linux do + with_feature :unix_socket do + describe 'using a UNIX Addrinfo' do + before do + @addr = Addrinfo.unix('cats') + @host = Socket.gethostname + end + + it 'returns the hostname and UNIX socket path' do + host, path = @addr.getnameinfo + + host.should == @host + path.should == 'cats' + end + end + end + end +end diff --git a/spec/ruby/library/socket/addrinfo/initialize_spec.rb b/spec/ruby/library/socket/addrinfo/initialize_spec.rb index 7a6475018a..42a09ebd68 100644 --- a/spec/ruby/library/socket/addrinfo/initialize_spec.rb +++ b/spec/ruby/library/socket/addrinfo/initialize_spec.rb @@ -1,5 +1,4 @@ -require_relative '../../../spec_helper' -require 'socket' +require_relative '../spec_helper' describe "Addrinfo#initialize" do @@ -22,6 +21,12 @@ describe "Addrinfo#initialize" do @addrinfo.pfamily.should == Socket::PF_UNSPEC end + it 'returns AF_INET as the default address family' do + addr = Addrinfo.new(Socket.sockaddr_in(80, '127.0.0.1')) + + addr.afamily.should == Socket::AF_INET + end + it "returns the INET6 afamily" do @addrinfo.afamily.should == Socket::AF_INET6 end @@ -142,7 +147,7 @@ describe "Addrinfo#initialize" do @addrinfo.ip_port.should == 46102 end - it "returns the Socket::UNSPEC pfamily" do + it "returns the Socket::PF_INET pfamily" do @addrinfo.pfamily.should == Socket::PF_INET end @@ -159,6 +164,46 @@ describe "Addrinfo#initialize" do end end + describe 'with a valid IP address' do + # Uses AF_INET6 since AF_INET is the default, making it a better test + # that Addrinfo actually sets the family correctly. + before do + @sockaddr = ['AF_INET6', 80, 'hostname', '::1'] + end + + it 'returns an Addrinfo with the correct IP' do + addr = Addrinfo.new(@sockaddr) + + addr.ip_address.should == '::1' + end + + it 'returns an Addrinfo with the correct address family' do + addr = Addrinfo.new(@sockaddr) + + addr.afamily.should == Socket::AF_INET6 + end + + it 'returns an Addrinfo with the correct protocol family' do + addr = Addrinfo.new(@sockaddr) + + addr.pfamily.should == Socket::PF_INET6 + end + + it 'returns an Addrinfo with the correct port' do + addr = Addrinfo.new(@sockaddr) + + addr.ip_port.should == 80 + end + end + + describe 'with an invalid IP address' do + it 'raises SocketError' do + block = lambda { Addrinfo.new(['AF_INET6', 80, 'hostname', '127.0.0.1']) } + + block.should raise_error(SocketError) + end + end + describe "with a family given" do before :each do @addrinfo = Addrinfo.new(["AF_INET", 46102, "localhost", "127.0.0.1"], Socket::PF_INET) @@ -217,6 +262,38 @@ describe "Addrinfo#initialize" do it "returns the 0 protocol" do @addrinfo.protocol.should == 0 end + + [:SOCK_STREAM, :SOCK_DGRAM, :SOCK_RAW].each do |type| + it "overwrites the socket type #{type}" do + sockaddr = ['AF_INET', 80, 'hostname', '127.0.0.1'] + + value = Socket.const_get(type) + addr = Addrinfo.new(sockaddr, nil, value) + + addr.socktype.should == value + end + end + + with_feature :sock_packet do + [:SOCK_SEQPACKET].each do |type| + it "overwrites the socket type #{type}" do + sockaddr = ['AF_INET', 80, 'hostname', '127.0.0.1'] + + value = Socket.const_get(type) + addr = Addrinfo.new(sockaddr, nil, value) + + addr.socktype.should == value + end + end + end + + it "raises SocketError when using SOCK_RDM" do + sockaddr = ['AF_INET', 80, 'hostname', '127.0.0.1'] + value = Socket::SOCK_RDM + block = lambda { Addrinfo.new(sockaddr, nil, value) } + + block.should raise_error(SocketError) + end end describe "with a family, socket type and protocol" do @@ -250,4 +327,261 @@ describe "Addrinfo#initialize" do end end + describe 'using an Array with extra arguments' do + describe 'with the AF_INET6 address family and an explicit protocol family' do + before do + @sockaddr = ['AF_INET6', 80, 'hostname', '127.0.0.1'] + end + + it "raises SocketError when using any Socket constant except except AF_INET(6)/PF_INET(6)" do + Socket.constants.grep(/(^AF_|^PF_)(?!INET)/).each do |constant| + value = Socket.const_get(constant) + -> { + Addrinfo.new(@sockaddr, value) + }.should raise_error(SocketError) + end + end + end + + describe 'with the AF_INET address family and an explicit socket protocol' do + before do + @sockaddr = ['AF_INET', 80, 'hostname', '127.0.0.1'] + end + + describe 'and no socket type is given' do + valid = [:IPPROTO_IP, :IPPROTO_UDP, :IPPROTO_HOPOPTS] + + valid.each do |type| + it "overwrites the protocol when using #{type}" do + value = Socket.const_get(type) + addr = Addrinfo.new(@sockaddr, nil, nil, value) + + addr.protocol.should == value + end + end + + platform_is_not :windows do + (Socket.constants.grep(/^IPPROTO/) - valid).each do |type| + it "raises SocketError when using #{type}" do + value = Socket.const_get(type) + block = lambda { Addrinfo.new(@sockaddr, nil, nil, value) } + + block.should raise_error(SocketError) + end + end + end + end + + describe 'and the socket type is set to SOCK_DGRAM' do + before do + @socktype = Socket::SOCK_DGRAM + end + + valid = [:IPPROTO_IP, :IPPROTO_UDP, :IPPROTO_HOPOPTS] + + valid.each do |type| + it "overwrites the protocol when using #{type}" do + value = Socket.const_get(type) + addr = Addrinfo.new(@sockaddr, nil, @socktype, value) + + addr.protocol.should == value + end + end + + platform_is_not :windows do + (Socket.constants.grep(/^IPPROTO/) - valid).each do |type| + it "raises SocketError when using #{type}" do + value = Socket.const_get(type) + block = lambda { Addrinfo.new(@sockaddr, nil, @socktype, value) } + + block.should raise_error(SocketError) + end + end + end + end + + with_feature :sock_packet do + describe 'and the socket type is set to SOCK_PACKET' do + before do + @socktype = Socket::SOCK_PACKET + end + + Socket.constants.grep(/^IPPROTO/).each do |type| + it "raises SocketError when using #{type}" do + value = Socket.const_get(type) + block = lambda { Addrinfo.new(@sockaddr, nil, @socktype, value) } + + block.should raise_error(SocketError) + end + end + end + end + + describe 'and the socket type is set to SOCK_RAW' do + before do + @socktype = Socket::SOCK_RAW + end + + Socket.constants.grep(/^IPPROTO/).each do |type| + it "overwrites the protocol when using #{type}" do + value = Socket.const_get(type) + addr = Addrinfo.new(@sockaddr, nil, @socktype, value) + + addr.protocol.should == value + end + end + end + + describe 'and the socket type is set to SOCK_RDM' do + before do + @socktype = Socket::SOCK_RDM + end + + Socket.constants.grep(/^IPPROTO/).each do |type| + it "raises SocketError when using #{type}" do + value = Socket.const_get(type) + block = lambda { Addrinfo.new(@sockaddr, nil, @socktype, value) } + + block.should raise_error(SocketError) + end + end + end + + platform_is_not :windows do + describe 'and the socket type is set to SOCK_SEQPACKET' do + before do + @socktype = Socket::SOCK_SEQPACKET + end + + valid = [:IPPROTO_IP, :IPPROTO_HOPOPTS] + + valid.each do |type| + it "overwrites the protocol when using #{type}" do + value = Socket.const_get(type) + addr = Addrinfo.new(@sockaddr, nil, @socktype, value) + + addr.protocol.should == value + end + end + + (Socket.constants.grep(/^IPPROTO/) - valid).each do |type| + it "raises SocketError when using #{type}" do + value = Socket.const_get(type) + block = lambda { Addrinfo.new(@sockaddr, nil, @socktype, value) } + + block.should raise_error(SocketError) + end + end + end + end + + describe 'and the socket type is set to SOCK_STREAM' do + before do + @socktype = Socket::SOCK_STREAM + end + + valid = [:IPPROTO_IP, :IPPROTO_TCP, :IPPROTO_HOPOPTS] + + valid.each do |type| + it "overwrites the protocol when using #{type}" do + value = Socket.const_get(type) + addr = Addrinfo.new(@sockaddr, nil, @socktype, value) + + addr.protocol.should == value + end + end + + platform_is_not :windows do + (Socket.constants.grep(/^IPPROTO/) - valid).each do |type| + it "raises SocketError when using #{type}" do + value = Socket.const_get(type) + block = lambda { Addrinfo.new(@sockaddr, nil, @socktype, value) } + + block.should raise_error(SocketError) + end + end + end + end + end + end + + describe 'with Symbols' do + before do + @sockaddr = Socket.sockaddr_in(80, '127.0.0.1') + end + + it 'returns an Addrinfo with :PF_INET family' do + addr = Addrinfo.new(@sockaddr, :PF_INET) + + addr.pfamily.should == Socket::PF_INET + end + + it 'returns an Addrinfo with :INET family' do + addr = Addrinfo.new(@sockaddr, :INET) + + addr.pfamily.should == Socket::PF_INET + end + + it 'returns an Addrinfo with :SOCK_STREAM as the socket type' do + addr = Addrinfo.new(@sockaddr, nil, :SOCK_STREAM) + + addr.socktype.should == Socket::SOCK_STREAM + end + + it 'returns an Addrinfo with :STREAM as the socket type' do + addr = Addrinfo.new(@sockaddr, nil, :STREAM) + + addr.socktype.should == Socket::SOCK_STREAM + end + end + + describe 'with Strings' do + before do + @sockaddr = Socket.sockaddr_in(80, '127.0.0.1') + end + + it 'returns an Addrinfo with "PF_INET" family' do + addr = Addrinfo.new(@sockaddr, 'PF_INET') + + addr.pfamily.should == Socket::PF_INET + end + + it 'returns an Addrinfo with "INET" family' do + addr = Addrinfo.new(@sockaddr, 'INET') + + addr.pfamily.should == Socket::PF_INET + end + + it 'returns an Addrinfo with "SOCK_STREAM" as the socket type' do + addr = Addrinfo.new(@sockaddr, nil, 'SOCK_STREAM') + + addr.socktype.should == Socket::SOCK_STREAM + end + + it 'returns an Addrinfo with "STREAM" as the socket type' do + addr = Addrinfo.new(@sockaddr, nil, 'STREAM') + + addr.socktype.should == Socket::SOCK_STREAM + end + end + + with_feature :unix_socket do + describe 'using separate arguments for a Unix socket' do + before do + @sockaddr = Socket.pack_sockaddr_un('socket') + end + + it 'returns an Addrinfo with the correct unix path' do + Addrinfo.new(@sockaddr).unix_path.should == 'socket' + end + + it 'returns an Addrinfo with the correct protocol family' do + Addrinfo.new(@sockaddr).pfamily.should == Socket::PF_UNSPEC + end + + it 'returns an Addrinfo with the correct address family' do + Addrinfo.new(@sockaddr).afamily.should == Socket::AF_UNIX + end + end + end end diff --git a/spec/ruby/library/socket/addrinfo/inspect_sockaddr_spec.rb b/spec/ruby/library/socket/addrinfo/inspect_sockaddr_spec.rb index 2a5990cd47..70ca4dd4d7 100644 --- a/spec/ruby/library/socket/addrinfo/inspect_sockaddr_spec.rb +++ b/spec/ruby/library/socket/addrinfo/inspect_sockaddr_spec.rb @@ -1,25 +1,50 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' -require 'socket' describe 'Addrinfo#inspect_sockaddr' do - it 'IPv4' do - Addrinfo.tcp('127.0.0.1', 80).inspect_sockaddr.should == '127.0.0.1:80' - Addrinfo.tcp('127.0.0.1', 0).inspect_sockaddr.should == '127.0.0.1' + describe 'using an IPv4 address' do + it 'returns a String containing the IP address and port number' do + addr = Addrinfo.tcp('127.0.0.1', 80) + + addr.inspect_sockaddr.should == '127.0.0.1:80' + end + + it 'returns a String containing just the IP address when no port is given' do + addr = Addrinfo.tcp('127.0.0.1', 0) + + addr.inspect_sockaddr.should == '127.0.0.1' + end end - it 'IPv6' do - Addrinfo.tcp('::1', 80).inspect_sockaddr.should == '[::1]:80' - Addrinfo.tcp('::1', 0).inspect_sockaddr.should == '::1' - ip = '2001:0db8:85a3:0000:0000:8a2e:0370:7334' - Addrinfo.tcp(ip, 80).inspect_sockaddr.should == '[2001:db8:85a3::8a2e:370:7334]:80' - Addrinfo.tcp(ip, 0).inspect_sockaddr.should == '2001:db8:85a3::8a2e:370:7334' + describe 'using an IPv6 address' do + before :each do + @ip = '2001:0db8:85a3:0000:0000:8a2e:0370:7334' + end + + it 'returns a String containing the IP address and port number' do + Addrinfo.tcp('::1', 80).inspect_sockaddr.should == '[::1]:80' + Addrinfo.tcp(@ip, 80).inspect_sockaddr.should == '[2001:db8:85a3::8a2e:370:7334]:80' + end + + it 'returns a String containing just the IP address when no port is given' do + Addrinfo.tcp('::1', 0).inspect_sockaddr.should == '::1' + Addrinfo.tcp(@ip, 0).inspect_sockaddr.should == '2001:db8:85a3::8a2e:370:7334' + end end - platform_is_not :windows do - it 'UNIX' do - Addrinfo.unix('/tmp/sock').inspect_sockaddr.should == '/tmp/sock' - Addrinfo.unix('rel').inspect_sockaddr.should == 'UNIX rel' + with_feature :unix_socket do + describe 'using a UNIX path' do + it 'returns a String containing the UNIX path' do + addr = Addrinfo.unix('/foo/bar') + + addr.inspect_sockaddr.should == '/foo/bar' + end + + it 'returns a String containing the UNIX path when using a relative path' do + addr = Addrinfo.unix('foo') + + addr.inspect_sockaddr.should == 'UNIX foo' + end end end end diff --git a/spec/ruby/library/socket/addrinfo/inspect_spec.rb b/spec/ruby/library/socket/addrinfo/inspect_spec.rb new file mode 100644 index 0000000000..98e1e83ffa --- /dev/null +++ b/spec/ruby/library/socket/addrinfo/inspect_spec.rb @@ -0,0 +1,65 @@ +require_relative '../spec_helper' + +describe 'Addrinfo#inspect' do + describe 'using an IPv4 Addrinfo' do + it 'returns a String when using a TCP Addrinfo' do + addr = Addrinfo.tcp('127.0.0.1', 80) + + addr.inspect.should == '#' + end + + it 'returns a String when using an UDP Addrinfo' do + addr = Addrinfo.udp('127.0.0.1', 80) + + addr.inspect.should == '#' + end + + it 'returns a String when using an Addrinfo without a port' do + addr = Addrinfo.ip('127.0.0.1') + + addr.inspect.should == '#' + end + end + + describe 'using an IPv6 Addrinfo' do + it 'returns a String when using a TCP Addrinfo' do + addr = Addrinfo.tcp('::1', 80) + + addr.inspect.should == '#' + end + + it 'returns a String when using an UDP Addrinfo' do + addr = Addrinfo.udp('::1', 80) + + addr.inspect.should == '#' + end + + it 'returns a String when using an Addrinfo without a port' do + addr = Addrinfo.ip('::1') + + addr.inspect.should == '#' + end + end + + with_feature :unix_socket do + describe 'using a UNIX Addrinfo' do + it 'returns a String' do + addr = Addrinfo.unix('/foo') + + addr.inspect.should == '#' + end + + it 'returns a String when using a relative UNIX path' do + addr = Addrinfo.unix('foo') + + addr.inspect.should == '#' + end + + it 'returns a String when using a DGRAM socket' do + addr = Addrinfo.unix('/foo', Socket::SOCK_DGRAM) + + addr.inspect.should == '#' + end + end + end +end diff --git a/spec/ruby/library/socket/addrinfo/ip_address_spec.rb b/spec/ruby/library/socket/addrinfo/ip_address_spec.rb index c36399bf0c..004de37254 100644 --- a/spec/ruby/library/socket/addrinfo/ip_address_spec.rb +++ b/spec/ruby/library/socket/addrinfo/ip_address_spec.rb @@ -1,5 +1,4 @@ -require_relative '../../../spec_helper' -require 'socket' +require_relative '../spec_helper' describe "Addrinfo#ip_address" do describe "for an ipv4 socket" do @@ -22,7 +21,7 @@ describe "Addrinfo#ip_address" do end end - platform_is_not :windows do + with_feature :unix_socket do describe "for a unix socket" do before :each do @addrinfo = Addrinfo.unix("/tmp/sock") @@ -33,4 +32,54 @@ describe "Addrinfo#ip_address" do end end end + + describe 'with an Array as the socket address' do + it 'returns the IP as a String' do + sockaddr = ['AF_INET', 80, 'localhost', '127.0.0.1'] + addr = Addrinfo.new(sockaddr) + + addr.ip_address.should == '127.0.0.1' + end + end + + describe 'without an IP address' do + before do + @ips = ['127.0.0.1', '0.0.0.0', '::1'] + end + + # Both these cases seem to return different values at times on MRI. Since + # this is network dependent we can't rely on an exact IP being returned. + it 'returns the local IP address when using an empty String as the IP' do + sockaddr = Socket.sockaddr_in(80, '') + addr = Addrinfo.new(sockaddr) + + @ips.include?(addr.ip_address).should == true + end + + it 'returns the local IP address when using nil as the IP' do + sockaddr = Socket.sockaddr_in(80, nil) + addr = Addrinfo.new(sockaddr) + + @ips.include?(addr.ip_address).should == true + end + end + + # On MRI calling Addrinfo#ip_address with AF_UNSPEC as the address family is + # supposed to raise a SocketError. MRI however doesn't provide a way to + # actually initialize an Addrinfo with AF_UNSPEC, nor does it allow stubbing + # of any methods since Addrinfo doesn't use any Ruby methods for checking the + # IP address. As a result we can only run this test on Rubinius. + with_feature :pure_ruby_addrinfo do + describe 'with a non IPv4 or IPv6 address' do + it 'raises SocketError' do + sockaddr = Socket.sockaddr_in(80, '127.0.0.1') + addr = Addrinfo.new(sockaddr) + + addr.stub!(:ipv4?).and_return(false) + addr.stub!(:ipv6?).and_return(false) + + lambda { addr.ip_address }.should raise_error(SocketError) + end + end + end end diff --git a/spec/ruby/library/socket/addrinfo/ip_port_spec.rb b/spec/ruby/library/socket/addrinfo/ip_port_spec.rb index ace6c00ff4..6cf9e7a18e 100644 --- a/spec/ruby/library/socket/addrinfo/ip_port_spec.rb +++ b/spec/ruby/library/socket/addrinfo/ip_port_spec.rb @@ -1,5 +1,4 @@ -require_relative '../../../spec_helper' -require 'socket' +require_relative '../spec_helper' describe "Addrinfo#ip_port" do describe "for an ipv4 socket" do @@ -22,7 +21,7 @@ describe "Addrinfo#ip_port" do end end - platform_is_not :windows do + with_feature :unix_socket do describe "for a unix socket" do before :each do @addrinfo = Addrinfo.unix("/tmp/sock") diff --git a/spec/ruby/library/socket/addrinfo/ip_spec.rb b/spec/ruby/library/socket/addrinfo/ip_spec.rb index 6eabbccef8..80e7a62df7 100644 --- a/spec/ruby/library/socket/addrinfo/ip_spec.rb +++ b/spec/ruby/library/socket/addrinfo/ip_spec.rb @@ -1,5 +1,5 @@ -require_relative '../../../spec_helper' -require 'socket' +require_relative '../spec_helper' +require_relative '../fixtures/classes' describe "Addrinfo#ip?" do describe "for an ipv4 socket" do @@ -22,15 +22,43 @@ describe "Addrinfo#ip?" do end end - platform_is_not :windows do + with_feature :unix_socket do describe "for a unix socket" do before :each do @addrinfo = Addrinfo.unix("/tmp/sock") end - it "returns Socket::AF_INET6" do + it "returns false" do @addrinfo.ip?.should be_false end end end end + +describe 'Addrinfo.ip' do + SocketSpecs.each_ip_protocol do |family, ip_address| + it 'returns an Addrinfo instance' do + Addrinfo.ip(ip_address).should be_an_instance_of(Addrinfo) + end + + it 'sets the IP address' do + Addrinfo.ip(ip_address).ip_address.should == ip_address + end + + it 'sets the port to 0' do + Addrinfo.ip(ip_address).ip_port.should == 0 + end + + it 'sets the address family' do + Addrinfo.ip(ip_address).afamily.should == family + end + + it 'sets the protocol family' do + Addrinfo.ip(ip_address).pfamily.should == family + end + + it 'sets the socket type to 0' do + Addrinfo.ip(ip_address).socktype.should == 0 + end + end +end diff --git a/spec/ruby/library/socket/addrinfo/ip_unpack_spec.rb b/spec/ruby/library/socket/addrinfo/ip_unpack_spec.rb index caa34d521d..57ae79a6c8 100644 --- a/spec/ruby/library/socket/addrinfo/ip_unpack_spec.rb +++ b/spec/ruby/library/socket/addrinfo/ip_unpack_spec.rb @@ -1,5 +1,4 @@ -require_relative '../../../spec_helper' -require 'socket' +require_relative '../spec_helper' describe "Addrinfo#ip_unpack" do describe "for an ipv4 socket" do @@ -22,7 +21,7 @@ describe "Addrinfo#ip_unpack" do end end - platform_is_not :windows do + with_feature :unix_socket do describe "for a unix socket" do before :each do @addrinfo = Addrinfo.unix("/tmp/sock") diff --git a/spec/ruby/library/socket/addrinfo/ipv4_loopback_spec.rb b/spec/ruby/library/socket/addrinfo/ipv4_loopback_spec.rb index bff15fd407..f5bab711db 100644 --- a/spec/ruby/library/socket/addrinfo/ipv4_loopback_spec.rb +++ b/spec/ruby/library/socket/addrinfo/ipv4_loopback_spec.rb @@ -1,19 +1,16 @@ -require_relative '../../../spec_helper' -require 'socket' +require_relative '../spec_helper' describe "Addrinfo#ipv4_loopback?" do describe "for an ipv4 socket" do - before :each do - @loopback = Addrinfo.tcp("127.0.0.1", 80) - @other = Addrinfo.tcp("0.0.0.0", 80) - end - it "returns true for the loopback address" do - @loopback.ipv4_loopback?.should be_true + Addrinfo.ip('127.0.0.1').ipv4_loopback?.should == true + Addrinfo.ip('127.0.0.2').ipv4_loopback?.should == true + Addrinfo.ip('127.255.0.1').ipv4_loopback?.should == true + Addrinfo.ip('127.255.255.255').ipv4_loopback?.should == true end it "returns false for another address" do - @other.ipv4_loopback?.should be_false + Addrinfo.ip('255.255.255.0').ipv4_loopback?.should be_false end end @@ -32,7 +29,7 @@ describe "Addrinfo#ipv4_loopback?" do end end - platform_is_not :windows do + with_feature :unix_socket do describe "for a unix socket" do before :each do @addrinfo = Addrinfo.unix("/tmp/sock") diff --git a/spec/ruby/library/socket/addrinfo/ipv4_multicast_spec.rb b/spec/ruby/library/socket/addrinfo/ipv4_multicast_spec.rb index bc6d5afa2d..81a68d3d13 100644 --- a/spec/ruby/library/socket/addrinfo/ipv4_multicast_spec.rb +++ b/spec/ruby/library/socket/addrinfo/ipv4_multicast_spec.rb @@ -1,38 +1,21 @@ -require_relative '../../../spec_helper' -require 'socket' +require_relative '../spec_helper' describe "Addrinfo#ipv4_multicast?" do - describe "for an ipv4 socket" do - before :each do - @multicast = Addrinfo.tcp("224.0.0.1", 80) - @other = Addrinfo.tcp("0.0.0.0", 80) - end - - it "returns true for the loopback address" do - @multicast.ipv4_multicast?.should be_true - end - - it "returns false for another address" do - @other.ipv4_multicast?.should be_false - end + it 'returns true for a multicast address' do + Addrinfo.ip('224.0.0.0').ipv4_multicast?.should == true + Addrinfo.ip('224.0.0.9').ipv4_multicast?.should == true + Addrinfo.ip('239.255.255.250').ipv4_multicast?.should == true end - describe "for an ipv6 socket" do - before :each do - @multicast = Addrinfo.tcp("ff02::1", 80) - @other = Addrinfo.tcp("::", 80) - end - - it "returns false for the loopback address" do - @multicast.ipv4_multicast?.should be_false - end + it 'returns false for a regular addrss' do + Addrinfo.ip('8.8.8.8').ipv4_multicast?.should == false + end - it "returns false for another address" do - @other.ipv4_multicast?.should be_false - end + it 'returns false for an IPv6 address' do + Addrinfo.ip('::1').ipv4_multicast?.should == false end - platform_is_not :windows do + with_feature :unix_socket do describe "for a unix socket" do before :each do @addrinfo = Addrinfo.unix("/tmp/sock") diff --git a/spec/ruby/library/socket/addrinfo/ipv4_private_spec.rb b/spec/ruby/library/socket/addrinfo/ipv4_private_spec.rb index 6ef5f5574a..733577609e 100644 --- a/spec/ruby/library/socket/addrinfo/ipv4_private_spec.rb +++ b/spec/ruby/library/socket/addrinfo/ipv4_private_spec.rb @@ -1,5 +1,4 @@ -require_relative '../../../spec_helper' -require 'socket' +require_relative '../spec_helper' describe "Addrinfo#ipv4_private?" do describe "for an ipv4 socket" do @@ -9,7 +8,14 @@ describe "Addrinfo#ipv4_private?" do end it "returns true for a private address" do - @private.ipv4_private?.should be_true + Addrinfo.ip('10.0.0.0').ipv4_private?.should == true + Addrinfo.ip('10.0.0.5').ipv4_private?.should == true + + Addrinfo.ip('172.16.0.0').ipv4_private?.should == true + Addrinfo.ip('172.16.0.5').ipv4_private?.should == true + + Addrinfo.ip('192.168.0.0').ipv4_private?.should == true + Addrinfo.ip('192.168.0.5').ipv4_private?.should == true end it "returns false for a public address" do @@ -27,7 +33,7 @@ describe "Addrinfo#ipv4_private?" do end end - platform_is_not :windows do + with_feature :unix_socket do describe "for a unix socket" do before :each do @addrinfo = Addrinfo.unix("/tmp/sock") diff --git a/spec/ruby/library/socket/addrinfo/ipv4_spec.rb b/spec/ruby/library/socket/addrinfo/ipv4_spec.rb index 7f8926a497..7cba8209b6 100644 --- a/spec/ruby/library/socket/addrinfo/ipv4_spec.rb +++ b/spec/ruby/library/socket/addrinfo/ipv4_spec.rb @@ -1,5 +1,4 @@ -require_relative '../../../spec_helper' -require 'socket' +require_relative '../spec_helper' describe "Addrinfo#ipv4?" do describe "for an ipv4 socket" do @@ -22,7 +21,7 @@ describe "Addrinfo#ipv4?" do end end - platform_is_not :windows do + with_feature :unix_socket do describe "for a unix socket" do before :each do @addrinfo = Addrinfo.unix("/tmp/sock") diff --git a/spec/ruby/library/socket/addrinfo/ipv6_linklocal_spec.rb b/spec/ruby/library/socket/addrinfo/ipv6_linklocal_spec.rb new file mode 100644 index 0000000000..fadc612fb7 --- /dev/null +++ b/spec/ruby/library/socket/addrinfo/ipv6_linklocal_spec.rb @@ -0,0 +1,18 @@ +require_relative '../spec_helper' + +describe 'Addrinfo#ipv6_linklocal?' do + it 'returns true for a link-local address' do + Addrinfo.ip('fe80::').ipv6_linklocal?.should == true + Addrinfo.ip('fe81::').ipv6_linklocal?.should == true + Addrinfo.ip('fe8f::').ipv6_linklocal?.should == true + Addrinfo.ip('fe80::1').ipv6_linklocal?.should == true + end + + it 'returns false for a regular address' do + Addrinfo.ip('::1').ipv6_linklocal?.should == false + end + + it 'returns false for an IPv4 address' do + Addrinfo.ip('127.0.0.1').ipv6_linklocal?.should == false + end +end diff --git a/spec/ruby/library/socket/addrinfo/ipv6_loopback_spec.rb b/spec/ruby/library/socket/addrinfo/ipv6_loopback_spec.rb index e078bce30c..9ff8f107bf 100644 --- a/spec/ruby/library/socket/addrinfo/ipv6_loopback_spec.rb +++ b/spec/ruby/library/socket/addrinfo/ipv6_loopback_spec.rb @@ -1,5 +1,4 @@ -require_relative '../../../spec_helper' -require 'socket' +require_relative '../spec_helper' describe "Addrinfo#ipv6_loopback?" do describe "for an ipv4 socket" do @@ -8,7 +7,7 @@ describe "Addrinfo#ipv6_loopback?" do @other = Addrinfo.tcp("0.0.0.0", 80) end - it "returns true for the loopback address" do + it "returns false for the loopback address" do @loopback.ipv6_loopback?.should be_false end @@ -23,7 +22,7 @@ describe "Addrinfo#ipv6_loopback?" do @other = Addrinfo.tcp("::", 80) end - it "returns false for the loopback address" do + it "returns true for the loopback address" do @loopback.ipv6_loopback?.should be_true end @@ -32,7 +31,7 @@ describe "Addrinfo#ipv6_loopback?" do end end - platform_is_not :windows do + with_feature :unix_socket do describe "for a unix socket" do before :each do @addrinfo = Addrinfo.unix("/tmp/sock") diff --git a/spec/ruby/library/socket/addrinfo/ipv6_mc_global_spec.rb b/spec/ruby/library/socket/addrinfo/ipv6_mc_global_spec.rb new file mode 100644 index 0000000000..9c8e4dccb4 --- /dev/null +++ b/spec/ruby/library/socket/addrinfo/ipv6_mc_global_spec.rb @@ -0,0 +1,20 @@ +require_relative '../spec_helper' + +describe 'Addrinfo#ipv6_mc_global?' do + it 'returns true for a multi-cast address in the global scope' do + Addrinfo.ip('ff1e::').ipv6_mc_global?.should == true + Addrinfo.ip('fffe::').ipv6_mc_global?.should == true + Addrinfo.ip('ff0e::').ipv6_mc_global?.should == true + Addrinfo.ip('ff1e::1').ipv6_mc_global?.should == true + end + + it 'returns false for a regular IPv6 address' do + Addrinfo.ip('::1').ipv6_mc_global?.should == false + Addrinfo.ip('ff1a::').ipv6_mc_global?.should == false + Addrinfo.ip('ff1f::1').ipv6_mc_global?.should == false + end + + it 'returns false for an IPv4 address' do + Addrinfo.ip('127.0.0.1').ipv6_mc_global?.should == false + end +end diff --git a/spec/ruby/library/socket/addrinfo/ipv6_mc_linklocal_spec.rb b/spec/ruby/library/socket/addrinfo/ipv6_mc_linklocal_spec.rb new file mode 100644 index 0000000000..dd52a9ad8b --- /dev/null +++ b/spec/ruby/library/socket/addrinfo/ipv6_mc_linklocal_spec.rb @@ -0,0 +1,19 @@ +require_relative '../spec_helper' + +describe 'Addrinfo#ipv6_mc_linklocal?' do + it 'returns true for a multi-cast link-local address' do + Addrinfo.ip('ff12::').ipv6_mc_linklocal?.should == true + Addrinfo.ip('ff02::').ipv6_mc_linklocal?.should == true + Addrinfo.ip('fff2::').ipv6_mc_linklocal?.should == true + Addrinfo.ip('ff12::1').ipv6_mc_linklocal?.should == true + end + + it 'returns false for a regular IPv6 address' do + Addrinfo.ip('::1').ipv6_mc_linklocal?.should == false + Addrinfo.ip('fff1::').ipv6_mc_linklocal?.should == false + end + + it 'returns false for an IPv4 address' do + Addrinfo.ip('127.0.0.1').ipv6_mc_linklocal?.should == false + end +end diff --git a/spec/ruby/library/socket/addrinfo/ipv6_mc_nodelocal_spec.rb b/spec/ruby/library/socket/addrinfo/ipv6_mc_nodelocal_spec.rb new file mode 100644 index 0000000000..b3cf5ffbab --- /dev/null +++ b/spec/ruby/library/socket/addrinfo/ipv6_mc_nodelocal_spec.rb @@ -0,0 +1,18 @@ +require_relative '../spec_helper' + +describe 'Addrinfo#ipv6_mc_nodelocal?' do + it 'returns true for a multi-cast node-local address' do + Addrinfo.ip('ff11::').ipv6_mc_nodelocal?.should == true + Addrinfo.ip('ff01::').ipv6_mc_nodelocal?.should == true + Addrinfo.ip('fff1::').ipv6_mc_nodelocal?.should == true + Addrinfo.ip('ff11::1').ipv6_mc_nodelocal?.should == true + end + + it 'returns false for a regular IPv6 address' do + Addrinfo.ip('::1').ipv6_mc_nodelocal?.should == false + end + + it 'returns false for an IPv4 address' do + Addrinfo.ip('127.0.0.1').ipv6_mc_nodelocal?.should == false + end +end diff --git a/spec/ruby/library/socket/addrinfo/ipv6_mc_orglocal_spec.rb b/spec/ruby/library/socket/addrinfo/ipv6_mc_orglocal_spec.rb new file mode 100644 index 0000000000..90653dd49c --- /dev/null +++ b/spec/ruby/library/socket/addrinfo/ipv6_mc_orglocal_spec.rb @@ -0,0 +1,18 @@ +require_relative '../spec_helper' + +describe 'Addrinfo#ipv6_mc_orglocal?' do + it 'returns true for a multi-cast org-local address' do + Addrinfo.ip('ff18::').ipv6_mc_orglocal?.should == true + Addrinfo.ip('ff08::').ipv6_mc_orglocal?.should == true + Addrinfo.ip('fff8::').ipv6_mc_orglocal?.should == true + Addrinfo.ip('ff18::1').ipv6_mc_orglocal?.should == true + end + + it 'returns false for a regular IPv6 address' do + Addrinfo.ip('::1').ipv6_mc_orglocal?.should == false + end + + it 'returns false for an IPv4 address' do + Addrinfo.ip('127.0.0.1').ipv6_mc_orglocal?.should == false + end +end diff --git a/spec/ruby/library/socket/addrinfo/ipv6_mc_sitelocal_spec.rb b/spec/ruby/library/socket/addrinfo/ipv6_mc_sitelocal_spec.rb new file mode 100644 index 0000000000..686b625e0d --- /dev/null +++ b/spec/ruby/library/socket/addrinfo/ipv6_mc_sitelocal_spec.rb @@ -0,0 +1,18 @@ +require_relative '../spec_helper' + +describe 'Addrinfo#ipv6_mc_sitelocal?' do + it 'returns true for a multi-cast site-local address' do + Addrinfo.ip('ff15::').ipv6_mc_sitelocal?.should == true + Addrinfo.ip('ff05::').ipv6_mc_sitelocal?.should == true + Addrinfo.ip('fff5::').ipv6_mc_sitelocal?.should == true + Addrinfo.ip('ff15::1').ipv6_mc_sitelocal?.should == true + end + + it 'returns false for a regular IPv6 address' do + Addrinfo.ip('::1').ipv6_mc_sitelocal?.should == false + end + + it 'returns false for an IPv4 address' do + Addrinfo.ip('127.0.0.1').ipv6_mc_sitelocal?.should == false + end +end diff --git a/spec/ruby/library/socket/addrinfo/ipv6_multicast_spec.rb b/spec/ruby/library/socket/addrinfo/ipv6_multicast_spec.rb index cdb6c798c0..c25322869c 100644 --- a/spec/ruby/library/socket/addrinfo/ipv6_multicast_spec.rb +++ b/spec/ruby/library/socket/addrinfo/ipv6_multicast_spec.rb @@ -1,5 +1,4 @@ -require_relative '../../../spec_helper' -require 'socket' +require_relative '../spec_helper' describe "Addrinfo#ipv6_multicast?" do describe "for an ipv4 socket" do @@ -8,7 +7,7 @@ describe "Addrinfo#ipv6_multicast?" do @other = Addrinfo.tcp("0.0.0.0", 80) end - it "returns true for the loopback address" do + it "returns true for a multicast address" do @multicast.ipv6_multicast?.should be_false end @@ -18,21 +17,24 @@ describe "Addrinfo#ipv6_multicast?" do end describe "for an ipv6 socket" do - before :each do - @multicast = Addrinfo.tcp("ff02::1", 80) - @other = Addrinfo.tcp("::", 80) - end - - it "returns false for the loopback address" do - @multicast.ipv6_multicast?.should be_true + it "returns true for a multicast address" do + Addrinfo.ip('ff00::').ipv6_multicast?.should == true + Addrinfo.ip('ff00::1').ipv6_multicast?.should == true + Addrinfo.ip('ff08::1').ipv6_multicast?.should == true + Addrinfo.ip('fff8::1').ipv6_multicast?.should == true + + Addrinfo.ip('ff02::').ipv6_multicast?.should == true + Addrinfo.ip('ff02::1').ipv6_multicast?.should == true + Addrinfo.ip('ff0f::').ipv6_multicast?.should == true end it "returns false for another address" do - @other.ipv6_multicast?.should be_false + Addrinfo.ip('::1').ipv6_multicast?.should == false + Addrinfo.ip('fe80::').ipv6_multicast?.should == false end end - platform_is_not :windows do + with_feature :unix_socket do describe "for a unix socket" do before :each do @addrinfo = Addrinfo.unix("/tmp/sock") diff --git a/spec/ruby/library/socket/addrinfo/ipv6_sitelocal_spec.rb b/spec/ruby/library/socket/addrinfo/ipv6_sitelocal_spec.rb new file mode 100644 index 0000000000..f0c382f00c --- /dev/null +++ b/spec/ruby/library/socket/addrinfo/ipv6_sitelocal_spec.rb @@ -0,0 +1,18 @@ +require_relative '../spec_helper' + +describe 'Addrinfo#ipv6_sitelocal?' do + it 'returns true for a site-local address' do + Addrinfo.ip('feef::').ipv6_sitelocal?.should == true + Addrinfo.ip('fee0::').ipv6_sitelocal?.should == true + Addrinfo.ip('fee2::').ipv6_sitelocal?.should == true + Addrinfo.ip('feef::1').ipv6_sitelocal?.should == true + end + + it 'returns false for a regular IPv6 address' do + Addrinfo.ip('::1').ipv6_sitelocal?.should == false + end + + it 'returns false for an IPv4 address' do + Addrinfo.ip('127.0.0.1').ipv6_sitelocal?.should == false + end +end diff --git a/spec/ruby/library/socket/addrinfo/ipv6_spec.rb b/spec/ruby/library/socket/addrinfo/ipv6_spec.rb index 02908b793f..131e38849c 100644 --- a/spec/ruby/library/socket/addrinfo/ipv6_spec.rb +++ b/spec/ruby/library/socket/addrinfo/ipv6_spec.rb @@ -1,5 +1,4 @@ -require_relative '../../../spec_helper' -require 'socket' +require_relative '../spec_helper' describe "Addrinfo#ipv6?" do describe "for an ipv4 socket" do @@ -22,7 +21,7 @@ describe "Addrinfo#ipv6?" do end end - platform_is_not :windows do + with_feature :unix_socket do describe "for a unix socket" do before :each do @addrinfo = Addrinfo.unix("/tmp/sock") diff --git a/spec/ruby/library/socket/addrinfo/ipv6_to_ipv4_spec.rb b/spec/ruby/library/socket/addrinfo/ipv6_to_ipv4_spec.rb new file mode 100644 index 0000000000..48c1706459 --- /dev/null +++ b/spec/ruby/library/socket/addrinfo/ipv6_to_ipv4_spec.rb @@ -0,0 +1,66 @@ +require_relative '../spec_helper' + +describe 'Addrinfo#ipv6_to_ipv4' do + it 'returns an Addrinfo for ::192.168.1.1' do + addr = Addrinfo.ip('::192.168.1.1').ipv6_to_ipv4 + + addr.should be_an_instance_of(Addrinfo) + + addr.afamily.should == Socket::AF_INET + addr.ip_address.should == '192.168.1.1' + end + + it 'returns an Addrinfo for ::0.0.1.1' do + addr = Addrinfo.ip('::0.0.1.1').ipv6_to_ipv4 + + addr.should be_an_instance_of(Addrinfo) + + addr.afamily.should == Socket::AF_INET + addr.ip_address.should == '0.0.1.1' + end + + it 'returns an Addrinfo for ::0.0.1.0' do + addr = Addrinfo.ip('::0.0.1.0').ipv6_to_ipv4 + + addr.should be_an_instance_of(Addrinfo) + + addr.afamily.should == Socket::AF_INET + addr.ip_address.should == '0.0.1.0' + end + + it 'returns an Addrinfo for ::0.1.0.0' do + addr = Addrinfo.ip('::0.1.0.0').ipv6_to_ipv4 + + addr.should be_an_instance_of(Addrinfo) + + addr.afamily.should == Socket::AF_INET + addr.ip_address.should == '0.1.0.0' + end + + it 'returns an Addrinfo for ::ffff:192.168.1.1' do + addr = Addrinfo.ip('::ffff:192.168.1.1').ipv6_to_ipv4 + + addr.should be_an_instance_of(Addrinfo) + + addr.afamily.should == Socket::AF_INET + addr.ip_address.should == '192.168.1.1' + end + + it 'returns nil for ::0.0.0.1' do + Addrinfo.ip('::0.0.0.1').ipv6_to_ipv4.should be_nil + end + + it 'returns nil for a pure IPv6 Addrinfo' do + Addrinfo.ip('::1').ipv6_to_ipv4.should be_nil + end + + it 'returns nil for an IPv4 Addrinfo' do + Addrinfo.ip('192.168.1.1').ipv6_to_ipv4.should be_nil + end + + with_feature :unix_socket do + it 'returns nil for a UNIX Addrinfo' do + Addrinfo.unix('foo').ipv6_to_ipv4.should be_nil + end + end +end diff --git a/spec/ruby/library/socket/addrinfo/ipv6_unique_local_spec.rb b/spec/ruby/library/socket/addrinfo/ipv6_unique_local_spec.rb new file mode 100644 index 0000000000..b80a15fcb0 --- /dev/null +++ b/spec/ruby/library/socket/addrinfo/ipv6_unique_local_spec.rb @@ -0,0 +1,18 @@ +require_relative '../spec_helper' + +describe 'Addrinfo#ipv6_unique_local?' do + it 'returns true for an unique local IPv6 address' do + Addrinfo.ip('fc00::').ipv6_unique_local?.should == true + Addrinfo.ip('fd00::').ipv6_unique_local?.should == true + Addrinfo.ip('fcff::').ipv6_unique_local?.should == true + end + + it 'returns false for a regular IPv6 address' do + Addrinfo.ip('::1').ipv6_unique_local?.should == false + Addrinfo.ip('fe00::').ipv6_unique_local?.should == false + end + + it 'returns false for an IPv4 address' do + Addrinfo.ip('127.0.0.1').ipv6_unique_local?.should == false + end +end diff --git a/spec/ruby/library/socket/addrinfo/ipv6_unspecified_spec.rb b/spec/ruby/library/socket/addrinfo/ipv6_unspecified_spec.rb new file mode 100644 index 0000000000..dd79d57503 --- /dev/null +++ b/spec/ruby/library/socket/addrinfo/ipv6_unspecified_spec.rb @@ -0,0 +1,15 @@ +require_relative '../spec_helper' + +describe 'Addrinfo#ipv6_unspecified?' do + it 'returns true for an unspecified IPv6 address' do + Addrinfo.ip('::').ipv6_unspecified?.should == true + end + + it 'returns false for a regular IPv6 address' do + Addrinfo.ip('::1').ipv6_unspecified?.should == false + end + + it 'returns false for an IPv4 address' do + Addrinfo.ip('127.0.0.1').ipv6_unspecified?.should == false + end +end diff --git a/spec/ruby/library/socket/addrinfo/ipv6_v4compat_spec.rb b/spec/ruby/library/socket/addrinfo/ipv6_v4compat_spec.rb new file mode 100644 index 0000000000..ab8388a21b --- /dev/null +++ b/spec/ruby/library/socket/addrinfo/ipv6_v4compat_spec.rb @@ -0,0 +1,20 @@ +require_relative '../spec_helper' + +describe 'Addrinfo#ipv6_v4compat?' do + it 'returns true for an IPv4 compatible address' do + Addrinfo.ip('::127.0.0.1').ipv6_v4compat?.should == true + Addrinfo.ip('::192.168.1.1').ipv6_v4compat?.should == true + end + + it 'returns false for an IPv4 mapped address' do + Addrinfo.ip('::ffff:192.168.1.1').ipv6_v4compat?.should == false + end + + it 'returns false for a regular IPv6 address' do + Addrinfo.ip('::1').ipv6_v4compat?.should == false + end + + it 'returns false for an IPv4 address' do + Addrinfo.ip('127.0.0.1').ipv6_v4compat?.should == false + end +end diff --git a/spec/ruby/library/socket/addrinfo/ipv6_v4mapped_spec.rb b/spec/ruby/library/socket/addrinfo/ipv6_v4mapped_spec.rb new file mode 100644 index 0000000000..82b272c165 --- /dev/null +++ b/spec/ruby/library/socket/addrinfo/ipv6_v4mapped_spec.rb @@ -0,0 +1,20 @@ +require_relative '../spec_helper' + +describe 'Addrinfo#ipv6_v4mapped?' do + it 'returns true for an IPv4 compatible address' do + Addrinfo.ip('::ffff:192.168.1.1').ipv6_v4mapped?.should == true + end + + it 'returns false for an IPv4 compatible address' do + Addrinfo.ip('::192.168.1.1').ipv6_v4mapped?.should == false + Addrinfo.ip('::127.0.0.1').ipv6_v4mapped?.should == false + end + + it 'returns false for a regular IPv6 address' do + Addrinfo.ip('::1').ipv6_v4mapped?.should == false + end + + it 'returns false for an IPv4 address' do + Addrinfo.ip('127.0.0.1').ipv6_v4mapped?.should == false + end +end diff --git a/spec/ruby/library/socket/addrinfo/listen_spec.rb b/spec/ruby/library/socket/addrinfo/listen_spec.rb new file mode 100644 index 0000000000..714a96ed6c --- /dev/null +++ b/spec/ruby/library/socket/addrinfo/listen_spec.rb @@ -0,0 +1,34 @@ +require_relative '../spec_helper' + +describe 'Addrinfo#listen' do + before do + @addr = Addrinfo.tcp('127.0.0.1', 0) + @socket = nil + end + + after do + @socket.close if @socket + end + + it 'returns a Socket when no block is given' do + @socket = @addr.listen + + @socket.should be_an_instance_of(Socket) + end + + it 'yields the Socket if a block is given' do + @addr.listen do |socket| + socket.should be_an_instance_of(Socket) + end + end + + it 'closes the socket if a block is given' do + socket = nil + + @addr.listen do |sock| + socket = sock + end + + socket.closed?.should == true + end +end diff --git a/spec/ruby/library/socket/addrinfo/marshal_dump_spec.rb b/spec/ruby/library/socket/addrinfo/marshal_dump_spec.rb new file mode 100644 index 0000000000..2d69a33b53 --- /dev/null +++ b/spec/ruby/library/socket/addrinfo/marshal_dump_spec.rb @@ -0,0 +1,82 @@ +require_relative '../spec_helper' + +describe 'Addrinfo#marshal_dump' do + describe 'using an IP Addrinfo' do + before do + @addr = Addrinfo.getaddrinfo('localhost', 80, :INET, :STREAM, + Socket::IPPROTO_TCP, Socket::AI_CANONNAME)[0] + end + + it 'returns an Array' do + @addr.marshal_dump.should be_an_instance_of(Array) + end + + describe 'the returned Array' do + before do + @array = @addr.marshal_dump + end + + it 'includes the address family as the 1st value' do + @array[0].should == 'AF_INET' + end + + it 'includes the IP address as the 2nd value' do + @array[1].should == [@addr.ip_address, @addr.ip_port.to_s] + end + + it 'includes the protocol family as the 3rd value' do + @array[2].should == 'PF_INET' + end + + it 'includes the socket type as the 4th value' do + @array[3].should == 'SOCK_STREAM' + end + + it 'includes the protocol as the 5th value' do + @array[4].should == 'IPPROTO_TCP' + end + + it 'includes the canonical name as the 6th value' do + @array[5].should == @addr.canonname + end + end + end + + with_feature :unix_socket do + describe 'using a UNIX Addrinfo' do + before do + @addr = Addrinfo.unix('foo') + end + + it 'returns an Array' do + @addr.marshal_dump.should be_an_instance_of(Array) + end + + describe 'the returned Array' do + before do + @array = @addr.marshal_dump + end + + it 'includes the address family as the 1st value' do + @array[0].should == 'AF_UNIX' + end + + it 'includes the UNIX path as the 2nd value' do + @array[1].should == @addr.unix_path + end + + it 'includes the protocol family as the 3rd value' do + @array[2].should == 'PF_UNIX' + end + + it 'includes the socket type as the 4th value' do + @array[3].should == 'SOCK_STREAM' + end + + it 'includes the protocol as the 5th value' do + @array[4].should == 0 + end + end + end + end +end diff --git a/spec/ruby/library/socket/addrinfo/marshal_load_spec.rb b/spec/ruby/library/socket/addrinfo/marshal_load_spec.rb new file mode 100644 index 0000000000..aa20865224 --- /dev/null +++ b/spec/ruby/library/socket/addrinfo/marshal_load_spec.rb @@ -0,0 +1,35 @@ +require_relative '../spec_helper' + +describe 'Addrinfo#marshal_load' do + describe 'using an IP address' do + it 'returns a new Addrinfo' do + source = Addrinfo.getaddrinfo('localhost', 80, :INET, :STREAM, + Socket::IPPROTO_TCP, Socket::AI_CANONNAME)[0] + + addr = Marshal.load(Marshal.dump(source)) + + addr.afamily.should == source.afamily + addr.pfamily.should == source.pfamily + addr.socktype.should == source.socktype + addr.protocol.should == source.protocol + addr.ip_address.should == source.ip_address + addr.ip_port.should == source.ip_port + addr.canonname.should == source.canonname + end + end + + with_feature :unix_socket do + describe 'using a UNIX socket' do + it 'returns a new Addrinfo' do + source = Addrinfo.unix('foo') + addr = Marshal.load(Marshal.dump(source)) + + addr.afamily.should == source.afamily + addr.pfamily.should == source.pfamily + addr.socktype.should == source.socktype + addr.protocol.should == source.protocol + addr.unix_path.should == source.unix_path + end + end + end +end diff --git a/spec/ruby/library/socket/addrinfo/pfamily_spec.rb b/spec/ruby/library/socket/addrinfo/pfamily_spec.rb index 6a6bd542f7..984744a964 100644 --- a/spec/ruby/library/socket/addrinfo/pfamily_spec.rb +++ b/spec/ruby/library/socket/addrinfo/pfamily_spec.rb @@ -1,7 +1,12 @@ -require_relative '../../../spec_helper' -require 'socket' +require_relative '../spec_helper' describe "Addrinfo#pfamily" do + it 'returns PF_UNSPEC as the default socket family' do + sockaddr = Socket.pack_sockaddr_in(80, 'localhost') + + Addrinfo.new(sockaddr).pfamily.should == Socket::PF_UNSPEC + end + describe "for an ipv4 socket" do before :each do @@ -24,7 +29,7 @@ describe "Addrinfo#pfamily" do end end - platform_is_not :windows do + with_feature :unix_socket do describe "for a unix socket" do before :each do @addrinfo = Addrinfo.unix("/tmp/sock") diff --git a/spec/ruby/library/socket/addrinfo/protocol_spec.rb b/spec/ruby/library/socket/addrinfo/protocol_spec.rb index 72f4f93b5c..ea143fc4a8 100644 --- a/spec/ruby/library/socket/addrinfo/protocol_spec.rb +++ b/spec/ruby/library/socket/addrinfo/protocol_spec.rb @@ -1,30 +1,16 @@ -require_relative '../../../spec_helper' -require 'socket' +require_relative '../spec_helper' describe "Addrinfo#protocol" do - describe "for an ipv4 socket" do - - before :each do - @addrinfo = Addrinfo.tcp("127.0.0.1", 80) - end - - it "returns Socket::IPPROTO_TCP" do - @addrinfo.protocol.should == Socket::IPPROTO_TCP - end - + it 'returns 0 by default' do + Addrinfo.ip('127.0.0.1').protocol.should == 0 end - describe "for an ipv6 socket" do - before :each do - @addrinfo = Addrinfo.tcp("::1", 80) - end - - it "returns Socket::IPPROTO_TCP" do - @addrinfo.protocol.should == Socket::IPPROTO_TCP - end + it 'returns a custom protocol when given' do + Addrinfo.tcp('127.0.0.1', 80).protocol.should == Socket::IPPROTO_TCP + Addrinfo.tcp('::1', 80).protocol.should == Socket::IPPROTO_TCP end - platform_is_not :windows do + with_feature :unix_socket do describe "for a unix socket" do before :each do @addrinfo = Addrinfo.unix("/tmp/sock") diff --git a/spec/ruby/library/socket/addrinfo/shared/to_sockaddr.rb b/spec/ruby/library/socket/addrinfo/shared/to_sockaddr.rb index 86819a31b0..c32da5986d 100644 --- a/spec/ruby/library/socket/addrinfo/shared/to_sockaddr.rb +++ b/spec/ruby/library/socket/addrinfo/shared/to_sockaddr.rb @@ -6,7 +6,7 @@ describe :socket_addrinfo_to_sockaddr, :shared => true do end it "returns a sockaddr packed structure" do - @addrinfo.send(@method).should be_kind_of(String) + @addrinfo.send(@method).should == Socket.sockaddr_in(80, '127.0.0.1') end end @@ -16,20 +16,36 @@ describe :socket_addrinfo_to_sockaddr, :shared => true do end it "returns a sockaddr packed structure" do - @addrinfo.send(@method).should be_kind_of(String) + @addrinfo.send(@method).should == Socket.sockaddr_in(80, '::1') end end - platform_is_not :windows do + with_feature :unix_socket do describe "for a unix socket" do before :each do @addrinfo = Addrinfo.unix("/tmp/sock") end it "returns a sockaddr packed structure" do - @addrinfo.send(@method).should be_kind_of(String) + @addrinfo.send(@method).should == Socket.sockaddr_un('/tmp/sock') end end end + describe 'using a Addrinfo with just an IP address' do + it 'returns a String' do + addr = Addrinfo.ip('127.0.0.1') + + addr.send(@method).should == Socket.sockaddr_in(0, '127.0.0.1') + end + end + + describe 'using a Addrinfo without an IP and port' do + it 'returns a String' do + addr = Addrinfo.new(['AF_INET', 0, '', '']) + + addr.send(@method).should == Socket.sockaddr_in(0, '') + end + end + end diff --git a/spec/ruby/library/socket/addrinfo/socktype_spec.rb b/spec/ruby/library/socket/addrinfo/socktype_spec.rb index c38c629c96..b994bea140 100644 --- a/spec/ruby/library/socket/addrinfo/socktype_spec.rb +++ b/spec/ruby/library/socket/addrinfo/socktype_spec.rb @@ -1,30 +1,15 @@ -require_relative '../../../spec_helper' -require 'socket' +require_relative '../spec_helper' describe "Addrinfo#socktype" do - describe "for an ipv4 socket" do - - before :each do - @addrinfo = Addrinfo.tcp("127.0.0.1", 80) - end - - it "returns Socket::SOCK_STREAM" do - @addrinfo.socktype.should == Socket::SOCK_STREAM - end - + it 'returns 0 by default' do + Addrinfo.ip('127.0.0.1').socktype.should == 0 end - describe "for an ipv6 socket" do - before :each do - @addrinfo = Addrinfo.tcp("::1", 80) - end - - it "returns Socket::SOCK_STREAM" do - @addrinfo.socktype.should == Socket::SOCK_STREAM - end + it 'returns the socket type when given' do + Addrinfo.tcp('127.0.0.1', 80).socktype.should == Socket::SOCK_STREAM end - platform_is_not :windows do + with_feature :unix_socket do describe "for a unix socket" do before :each do @addrinfo = Addrinfo.unix("/tmp/sock") diff --git a/spec/ruby/library/socket/addrinfo/tcp_spec.rb b/spec/ruby/library/socket/addrinfo/tcp_spec.rb index 39406b64ee..c74c9c21c2 100644 --- a/spec/ruby/library/socket/addrinfo/tcp_spec.rb +++ b/spec/ruby/library/socket/addrinfo/tcp_spec.rb @@ -1,20 +1,34 @@ -require_relative '../../../spec_helper' -require 'socket' +require_relative '../spec_helper' +require_relative '../fixtures/classes' -describe "Addrinfo.tcp" do +describe 'Addrinfo.tcp' do + SocketSpecs.each_ip_protocol do |family, ip_address| + it 'returns an Addrinfo instance' do + Addrinfo.tcp(ip_address, 80).should be_an_instance_of(Addrinfo) + end - before :each do - @addrinfo = Addrinfo.tcp("localhost", "smtp") - end + it 'sets the IP address' do + Addrinfo.tcp(ip_address, 80).ip_address.should == ip_address + end - it "creates a addrinfo for a tcp socket" do - ["::1", "127.0.0.1"].should include(@addrinfo.ip_address) - [Socket::PF_INET, Socket::PF_INET6].should include(@addrinfo.pfamily) - @addrinfo.ip_port.should == 25 - @addrinfo.socktype.should == Socket::SOCK_STREAM - platform_is_not :solaris do - @addrinfo.protocol.should == Socket::IPPROTO_TCP + it 'sets the port' do + Addrinfo.tcp(ip_address, 80).ip_port.should == 80 + end + + it 'sets the address family' do + Addrinfo.tcp(ip_address, 80).afamily.should == family end - end + it 'sets the protocol family' do + Addrinfo.tcp(ip_address, 80).pfamily.should == family + end + + it 'sets the socket type' do + Addrinfo.tcp(ip_address, 80).socktype.should == Socket::SOCK_STREAM + end + + it 'sets the socket protocol' do + Addrinfo.tcp(ip_address, 80).protocol.should == Socket::IPPROTO_TCP + end + end end diff --git a/spec/ruby/library/socket/addrinfo/to_s_spec.rb b/spec/ruby/library/socket/addrinfo/to_s_spec.rb index 5ac31e3099..ddf994e051 100644 --- a/spec/ruby/library/socket/addrinfo/to_s_spec.rb +++ b/spec/ruby/library/socket/addrinfo/to_s_spec.rb @@ -1,6 +1,5 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative 'shared/to_sockaddr' -require 'socket' describe "Addrinfo#to_s" do it_behaves_like :socket_addrinfo_to_sockaddr, :to_s diff --git a/spec/ruby/library/socket/addrinfo/to_sockaddr_spec.rb b/spec/ruby/library/socket/addrinfo/to_sockaddr_spec.rb index eee9f961b2..b9f75454bd 100644 --- a/spec/ruby/library/socket/addrinfo/to_sockaddr_spec.rb +++ b/spec/ruby/library/socket/addrinfo/to_sockaddr_spec.rb @@ -1,6 +1,5 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative 'shared/to_sockaddr' -require 'socket' describe "Addrinfo#to_sockaddr" do it_behaves_like :socket_addrinfo_to_sockaddr, :to_sockaddr diff --git a/spec/ruby/library/socket/addrinfo/udp_spec.rb b/spec/ruby/library/socket/addrinfo/udp_spec.rb index 237afdbc61..b05cbf9b0b 100644 --- a/spec/ruby/library/socket/addrinfo/udp_spec.rb +++ b/spec/ruby/library/socket/addrinfo/udp_spec.rb @@ -1,20 +1,36 @@ -require_relative '../../../spec_helper' -require 'socket' +require_relative '../spec_helper' +require_relative '../fixtures/classes' -describe "Addrinfo.udp" do +describe 'Addrinfo.udp' do + SocketSpecs.each_ip_protocol do |family, ip_address| + it 'returns an Addrinfo instance' do + Addrinfo.udp(ip_address, 80).should be_an_instance_of(Addrinfo) + end - before :each do - @addrinfo = Addrinfo.udp("localhost", "daytime") - end + it 'sets the IP address' do + Addrinfo.udp(ip_address, 80).ip_address.should == ip_address + end + + it 'sets the port' do + Addrinfo.udp(ip_address, 80).ip_port.should == 80 + end + + it 'sets the address family' do + Addrinfo.udp(ip_address, 80).afamily.should == family + end + + it 'sets the protocol family' do + Addrinfo.udp(ip_address, 80).pfamily.should == family + end + + it 'sets the socket type' do + Addrinfo.udp(ip_address, 80).socktype.should == Socket::SOCK_DGRAM + end - it "creates a addrinfo for a tcp socket" do - ["::1", "127.0.0.1"].should include(@addrinfo.ip_address) - [Socket::PF_INET, Socket::PF_INET6].should include(@addrinfo.pfamily) - @addrinfo.ip_port.should == 13 - @addrinfo.socktype.should == Socket::SOCK_DGRAM platform_is_not :solaris do - @addrinfo.protocol.should == Socket::IPPROTO_UDP + it 'sets the socket protocol' do + Addrinfo.udp(ip_address, 80).protocol.should == Socket::IPPROTO_UDP + end end end - end diff --git a/spec/ruby/library/socket/addrinfo/unix_path_spec.rb b/spec/ruby/library/socket/addrinfo/unix_path_spec.rb index 1168a225b0..0f25881724 100644 --- a/spec/ruby/library/socket/addrinfo/unix_path_spec.rb +++ b/spec/ruby/library/socket/addrinfo/unix_path_spec.rb @@ -1,7 +1,6 @@ -require_relative '../../../spec_helper' -require 'socket' +require_relative '../spec_helper' -platform_is_not :windows do +with_feature :unix_socket do describe "Addrinfo#unix_path" do describe "for an ipv4 socket" do @@ -25,15 +24,13 @@ platform_is_not :windows do end end - platform_is_not :windows do - describe "for a unix socket" do - before :each do - @addrinfo = Addrinfo.unix("/tmp/sock") - end + describe "for a unix socket" do + before :each do + @addrinfo = Addrinfo.unix("/tmp/sock") + end - it "returns the socket path" do - @addrinfo.unix_path.should == "/tmp/sock" - end + it "returns the socket path" do + @addrinfo.unix_path.should == "/tmp/sock" end end end diff --git a/spec/ruby/library/socket/addrinfo/unix_spec.rb b/spec/ruby/library/socket/addrinfo/unix_spec.rb index 599c20e815..4596ece17e 100644 --- a/spec/ruby/library/socket/addrinfo/unix_spec.rb +++ b/spec/ruby/library/socket/addrinfo/unix_spec.rb @@ -1,18 +1,35 @@ -require_relative '../../../spec_helper' -require 'socket' +require_relative '../spec_helper' -describe "Addrinfo.unix" do +with_feature :unix_socket do + describe 'Addrinfo.unix' do + it 'returns an Addrinfo instance' do + Addrinfo.unix('socket').should be_an_instance_of(Addrinfo) + end - platform_is_not :windows do - before :each do - @addrinfo = Addrinfo.unix("/tmp/sock") + it 'sets the IP address' do + Addrinfo.unix('socket').unix_path.should == 'socket' + end + + it 'sets the address family' do + Addrinfo.unix('socket').afamily.should == Socket::AF_UNIX + end + + it 'sets the protocol family' do + Addrinfo.unix('socket').pfamily.should == Socket::PF_UNIX + end + + it 'sets the socket type' do + Addrinfo.unix('socket').socktype.should == Socket::SOCK_STREAM + end + + it 'sets a custom socket type' do + addr = Addrinfo.unix('socket', Socket::SOCK_DGRAM) + + addr.socktype.should == Socket::SOCK_DGRAM end - it "creates a addrinfo for a unix socket" do - @addrinfo.pfamily.should == Socket::PF_UNIX - @addrinfo.socktype.should == Socket::SOCK_STREAM - @addrinfo.protocol.should == 0 - @addrinfo.unix_path.should == "/tmp/sock" + it 'sets the socket protocol to 0' do + Addrinfo.unix('socket').protocol.should == 0 end end end diff --git a/spec/ruby/library/socket/ancillarydata/cmsg_is_spec.rb b/spec/ruby/library/socket/ancillarydata/cmsg_is_spec.rb new file mode 100644 index 0000000000..e423e0ef05 --- /dev/null +++ b/spec/ruby/library/socket/ancillarydata/cmsg_is_spec.rb @@ -0,0 +1,31 @@ +require_relative '../spec_helper' + +with_feature :ancillary_data do + describe 'Socket::AncillaryData#cmsg_is?' do + describe 'using :INET, :IP, :TTL as the family, level, and type' do + before do + @data = Socket::AncillaryData.new(:INET, :IP, :TTL, '') + end + + it 'returns true when comparing with IPPROTO_IP and IP_TTL' do + @data.cmsg_is?(Socket::IPPROTO_IP, Socket::IP_TTL).should == true + end + + it 'returns true when comparing with :IP and :TTL' do + @data.cmsg_is?(:IP, :TTL).should == true + end + + it 'returns false when comparing with :IP and :PKTINFO' do + @data.cmsg_is?(:IP, :PKTINFO).should == false + end + + it 'returns false when comparing with :SOCKET and :RIGHTS' do + @data.cmsg_is?(:SOCKET, :RIGHTS).should == false + end + + it 'raises SocketError when comparign with :IPV6 and :RIGHTS' do + lambda { @data.cmsg_is?(:IPV6, :RIGHTS) }.should raise_error(SocketError) + end + end + end +end diff --git a/spec/ruby/library/socket/ancillarydata/data_spec.rb b/spec/ruby/library/socket/ancillarydata/data_spec.rb new file mode 100644 index 0000000000..5a1a446dd5 --- /dev/null +++ b/spec/ruby/library/socket/ancillarydata/data_spec.rb @@ -0,0 +1,9 @@ +require_relative '../spec_helper' + +with_feature :ancillary_data do + describe 'Socket::AncillaryData#data' do + it 'returns the data as a String' do + Socket::AncillaryData.new(:INET, :SOCKET, :RIGHTS, 'ugh').data.should == 'ugh' + end + end +end diff --git a/spec/ruby/library/socket/ancillarydata/family_spec.rb b/spec/ruby/library/socket/ancillarydata/family_spec.rb new file mode 100644 index 0000000000..b742e0c6db --- /dev/null +++ b/spec/ruby/library/socket/ancillarydata/family_spec.rb @@ -0,0 +1,9 @@ +require_relative '../spec_helper' + +with_feature :ancillary_data do + describe 'Socket::AncillaryData#family' do + it 'returns the family as a Fixnum' do + Socket::AncillaryData.new(:INET, :SOCKET, :RIGHTS, '').family.should == Socket::AF_INET + end + end +end diff --git a/spec/ruby/library/socket/ancillarydata/initialize_spec.rb b/spec/ruby/library/socket/ancillarydata/initialize_spec.rb new file mode 100644 index 0000000000..659a29e24a --- /dev/null +++ b/spec/ruby/library/socket/ancillarydata/initialize_spec.rb @@ -0,0 +1,282 @@ +require_relative '../spec_helper' + +with_feature :ancillary_data do + describe 'Socket::AncillaryData#initialize' do + describe 'using Fixnums for the family, level, and type' do + before do + @data = Socket::AncillaryData + .new(Socket::AF_INET, Socket::IPPROTO_IP, Socket::IP_RECVTTL, 'ugh') + end + + it 'sets the address family' do + @data.family.should == Socket::AF_INET + end + + it 'sets the message level' do + @data.level.should == Socket::IPPROTO_IP + end + + it 'sets the message type' do + @data.type.should == Socket::IP_RECVTTL + end + + it 'sets the data' do + @data.data.should == 'ugh' + end + end + + describe 'using Symbols for the family, level, and type' do + before do + @data = Socket::AncillaryData.new(:INET, :IPPROTO_IP, :RECVTTL, 'ugh') + end + + it 'sets the address family' do + @data.family.should == Socket::AF_INET + end + + it 'sets the message level' do + @data.level.should == Socket::IPPROTO_IP + end + + it 'sets the message type' do + @data.type.should == Socket::IP_RECVTTL + end + + it 'sets the data' do + @data.data.should == 'ugh' + end + end + + describe 'using Strings for the family, level, and type' do + before do + @data = Socket::AncillaryData.new('INET', 'IPPROTO_IP', 'RECVTTL', 'ugh') + end + + it 'sets the address family' do + @data.family.should == Socket::AF_INET + end + + it 'sets the message level' do + @data.level.should == Socket::IPPROTO_IP + end + + it 'sets the message type' do + @data.type.should == Socket::IP_RECVTTL + end + + it 'sets the data' do + @data.data.should == 'ugh' + end + end + + describe 'using custom objects with a to_str method for the family, level, and type' do + before do + fmock = mock(:family) + lmock = mock(:level) + tmock = mock(:type) + dmock = mock(:data) + + fmock.stub!(:to_str).and_return('INET') + lmock.stub!(:to_str).and_return('IP') + tmock.stub!(:to_str).and_return('RECVTTL') + dmock.stub!(:to_str).and_return('ugh') + + @data = Socket::AncillaryData.new(fmock, lmock, tmock, dmock) + end + + it 'sets the address family' do + @data.family.should == Socket::AF_INET + end + + it 'sets the message level' do + @data.level.should == Socket::IPPROTO_IP + end + + it 'sets the message type' do + @data.type.should == Socket::IP_RECVTTL + end + + it 'sets the data' do + @data.data.should == 'ugh' + end + end + + describe 'using :AF_INET as the family and :SOCKET as the level' do + it 'sets the type to SCM_RIGHTS when using :RIGHTS as the type argument' do + Socket::AncillaryData.new(:INET, :SOCKET, :RIGHTS, '').type.should == Socket::SCM_RIGHTS + end + + it 'sets the type to SCM_TIMESTAMP when using :TIMESTAMP as the type argument' do + Socket::AncillaryData.new(:INET, :SOCKET, :TIMESTAMP, '').type.should == Socket::SCM_TIMESTAMP + end + + it 'raises TypeError when using a numeric string as the type argument' do + lambda { + Socket::AncillaryData.new(:INET, :IGMP, Socket::SCM_RIGHTS.to_s, '') + }.should raise_error(TypeError) + end + + it 'raises SocketError when using :RECVTTL as the type argument' do + lambda { + Socket::AncillaryData.new(:INET, :SOCKET, :RECVTTL, '') + }.should raise_error(SocketError) + end + + it 'raises SocketError when using :MOO as the type argument' do + lambda { + Socket::AncillaryData.new(:INET, :SOCKET, :MOO, '') + }.should raise_error(SocketError) + end + + it 'raises SocketError when using :IP_RECVTTL as the type argument' do + lambda { + Socket::AncillaryData.new(:INET, :SOCKET, :IP_RECVTTL, '') + }.should raise_error(SocketError) + end + end + + describe 'using :AF_INET as the family and :SOCKET as the level' do + it 'sets the type to SCM_RIGHTS when using :RIGHTS as the type argument' do + Socket::AncillaryData.new(:INET, :SOCKET, :RIGHTS, '').type.should == Socket::SCM_RIGHTS + end + end + + describe 'using :AF_INET as the family and :IP as the level' do + it 'sets the type to IP_RECVTTL when using :RECVTTL as the type argument' do + Socket::AncillaryData.new(:INET, :IP, :RECVTTL, '').type.should == Socket::IP_RECVTTL + end + + with_feature :ip_mtu do + it 'sets the type to IP_MTU when using :MTU as the type argument' do + Socket::AncillaryData.new(:INET, :IP, :MTU, '').type.should == Socket::IP_MTU + end + end + + it 'raises SocketError when using :RIGHTS as the type argument' do + lambda { + Socket::AncillaryData.new(:INET, :IP, :RIGHTS, '') + }.should raise_error(SocketError) + end + + it 'raises SocketError when using :MOO as the type argument' do + lambda { + Socket::AncillaryData.new(:INET, :IP, :MOO, '') + }.should raise_error(SocketError) + end + end + + describe 'using :AF_INET as the family and :IPV6 as the level' do + it 'sets the type to IPV6_CHECKSUM when using :CHECKSUM as the type argument' do + Socket::AncillaryData.new(:INET, :IPV6, :CHECKSUM, '').type.should == Socket::IPV6_CHECKSUM + end + + with_feature :ipv6_nexthop do + it 'sets the type to IPV6_NEXTHOP when using :NEXTHOP as the type argument' do + Socket::AncillaryData.new(:INET, :IPV6, :NEXTHOP, '').type.should == Socket::IPV6_NEXTHOP + end + end + + it 'raises SocketError when using :RIGHTS as the type argument' do + lambda { + Socket::AncillaryData.new(:INET, :IPV6, :RIGHTS, '') + }.should raise_error(SocketError) + end + + it 'raises SocketError when using :MOO as the type argument' do + lambda { + Socket::AncillaryData.new(:INET, :IPV6, :MOO, '') + }.should raise_error(SocketError) + end + end + + describe 'using :AF_INET as the family and :TCP as the level' do + with_feature :tcp_cork do + it 'sets the type to TCP_CORK when using :CORK as the type argument' do + Socket::AncillaryData.new(:INET, :TCP, :CORK, '').type.should == Socket::TCP_CORK + end + end + + with_feature :tcp_info do + it 'sets the type to TCP_INFO when using :INFO as the type argument' do + Socket::AncillaryData.new(:INET, :TCP, :INFO, '').type.should == Socket::TCP_INFO + end + end + + it 'raises SocketError when using :RIGHTS as the type argument' do + lambda { + Socket::AncillaryData.new(:INET, :TCP, :RIGHTS, '') + }.should raise_error(SocketError) + end + + it 'raises SocketError when using :MOO as the type argument' do + lambda { + Socket::AncillaryData.new(:INET, :TCP, :MOO, '') + }.should raise_error(SocketError) + end + end + + describe 'using :AF_INET as the family and :UDP as the level' do + with_feature :udp_cork do + it 'sets the type to UDP_CORK when using :CORK as the type argument' do + Socket::AncillaryData.new(:INET, :UDP, :CORK, '').type.should == Socket::UDP_CORK + end + end + + it 'raises SocketError when using :RIGHTS as the type argument' do + lambda { + Socket::AncillaryData.new(:INET, :UDP, :RIGHTS, '') + }.should raise_error(SocketError) + end + + it 'raises SocketError when using :MOO as the type argument' do + lambda { + Socket::AncillaryData.new(:INET, :UDP, :MOO, '') + }.should raise_error(SocketError) + end + end + + describe 'using :AF_UNIX as the family and :SOCKET as the level' do + it 'sets the type to SCM_RIGHTS when using :RIGHTS as the type argument' do + Socket::AncillaryData.new(:UNIX, :SOCKET, :RIGHTS, '').type.should == Socket::SCM_RIGHTS + end + + it 'raises SocketError when using :CORK sa the type argument' do + lambda { + Socket::AncillaryData.new(:UNIX, :SOCKET, :CORK, '') + }.should raise_error(SocketError) + end + end + + describe 'using :AF_UNIX as the family and :IP as the level' do + it 'raises SocketError' do + lambda { + Socket::AncillaryData.new(:UNIX, :IP, :RECVTTL, '') + }.should raise_error(SocketError) + end + end + + describe 'using :AF_UNIX as the family and :IPV6 as the level' do + it 'raises SocketError' do + lambda { + Socket::AncillaryData.new(:UNIX, :IPV6, :NEXTHOP, '') + }.should raise_error(SocketError) + end + end + + describe 'using :AF_UNIX as the family and :TCP as the level' do + it 'raises SocketError' do + lambda { + Socket::AncillaryData.new(:UNIX, :TCP, :CORK, '') + }.should raise_error(SocketError) + end + end + + describe 'using :AF_UNIX as the family and :UDP as the level' do + it 'raises SocketError' do + lambda { + Socket::AncillaryData.new(:UNIX, :UDP, :CORK, '') + }.should raise_error(SocketError) + end + end + end +end diff --git a/spec/ruby/library/socket/ancillarydata/int_spec.rb b/spec/ruby/library/socket/ancillarydata/int_spec.rb new file mode 100644 index 0000000000..75608a28b8 --- /dev/null +++ b/spec/ruby/library/socket/ancillarydata/int_spec.rb @@ -0,0 +1,43 @@ +require_relative '../spec_helper' + +with_feature :ancillary_data do + describe 'Socket::AncillaryData.int' do + before do + @data = Socket::AncillaryData.int(:INET, :SOCKET, :RIGHTS, 4) + end + + it 'returns a Socket::AncillaryData' do + @data.should be_an_instance_of(Socket::AncillaryData) + end + + it 'sets the family to AF_INET' do + @data.family.should == Socket::AF_INET + end + + it 'sets the level SOL_SOCKET' do + @data.level.should == Socket::SOL_SOCKET + end + + it 'sets the type SCM_RIGHTS' do + @data.type.should == Socket::SCM_RIGHTS + end + + it 'sets the data to a packed String' do + @data.data.should == [4].pack('I') + end + end + + describe 'Socket::AncillaryData#int' do + it 'returns the data as a Fixnum' do + data = Socket::AncillaryData.int(:UNIX, :SOCKET, :RIGHTS, 4) + + data.int.should == 4 + end + + it 'raises when the data is not a Fixnum' do + data = Socket::AncillaryData.new(:UNIX, :SOCKET, :RIGHTS, 'ugh') + + lambda { data.int }.should raise_error(TypeError) + end + end +end diff --git a/spec/ruby/library/socket/ancillarydata/ip_pktinfo_spec.rb b/spec/ruby/library/socket/ancillarydata/ip_pktinfo_spec.rb new file mode 100644 index 0000000000..aaf5b80a23 --- /dev/null +++ b/spec/ruby/library/socket/ancillarydata/ip_pktinfo_spec.rb @@ -0,0 +1,145 @@ +require_relative '../spec_helper' + +with_feature :ancillary_data do + describe 'Socket::AncillaryData.ip_pktinfo' do + describe 'with a source address and index' do + before do + @data = Socket::AncillaryData.ip_pktinfo(Addrinfo.ip('127.0.0.1'), 4) + end + + it 'returns a Socket::AncillaryData' do + @data.should be_an_instance_of(Socket::AncillaryData) + end + + it 'sets the family to AF_INET' do + @data.family.should == Socket::AF_INET + end + + it 'sets the level to IPPROTO_IP' do + @data.level.should == Socket::IPPROTO_IP + end + + it 'sets the type to IP_PKTINFO' do + @data.type.should == Socket::IP_PKTINFO + end + end + + describe 'with a source address, index, and destination address' do + before do + source = Addrinfo.ip('127.0.0.1') + dest = Addrinfo.ip('127.0.0.5') + @data = Socket::AncillaryData.ip_pktinfo(source, 4, dest) + end + + it 'returns a Socket::AncillaryData' do + @data.should be_an_instance_of(Socket::AncillaryData) + end + + it 'sets the family to AF_INET' do + @data.family.should == Socket::AF_INET + end + + it 'sets the level to IPPROTO_IP' do + @data.level.should == Socket::IPPROTO_IP + end + + it 'sets the type to IP_PKTINFO' do + @data.type.should == Socket::IP_PKTINFO + end + end + end + + describe 'Socket::AncillaryData#ip_pktinfo' do + describe 'using an Addrinfo without a port number' do + before do + @source = Addrinfo.ip('127.0.0.1') + @dest = Addrinfo.ip('127.0.0.5') + @data = Socket::AncillaryData.ip_pktinfo(@source, 4, @dest) + end + + it 'returns an Array' do + @data.ip_pktinfo.should be_an_instance_of(Array) + end + + describe 'the returned Array' do + before do + @info = @data.ip_pktinfo + end + + it 'stores an Addrinfo at index 0' do + @info[0].should be_an_instance_of(Addrinfo) + end + + it 'stores the ifindex at index 1' do + @info[1].should be_an_instance_of(Fixnum) + end + + it 'stores an Addrinfo at index 2' do + @info[2].should be_an_instance_of(Addrinfo) + end + end + + describe 'the source Addrinfo' do + before do + @addr = @data.ip_pktinfo[0] + end + + it 'uses the correct IP address' do + @addr.ip_address.should == '127.0.0.1' + end + + it 'is not the same object as the input Addrinfo' do + @addr.should_not == @source + end + end + + describe 'the ifindex' do + it 'is a Fixnum' do + @data.ip_pktinfo[1].should == 4 + end + end + + describe 'the destination Addrinfo' do + before do + @addr = @data.ip_pktinfo[2] + end + + it 'uses the correct IP address' do + @addr.ip_address.should == '127.0.0.5' + end + + it 'is not the same object as the input Addrinfo' do + @addr.should_not == @dest + end + end + end + + describe 'using an Addrinfo with a port number' do + before do + @source = Addrinfo.tcp('127.0.0.1', 80) + @dest = Addrinfo.tcp('127.0.0.5', 85) + @data = Socket::AncillaryData.ip_pktinfo(@source, 4, @dest) + end + + describe 'the source Addrinfo' do + before do + @addr = @data.ip_pktinfo[0] + end + + it 'does not contain a port number' do + @addr.ip_port.should == 0 + end + end + + describe 'the destination Addrinfo' do + before do + @addr = @data.ip_pktinfo[2] + end + + it 'does not contain a port number' do + @addr.ip_port.should == 0 + end + end + end + end +end diff --git a/spec/ruby/library/socket/ancillarydata/ipv6_pktinfo_addr_spec.rb b/spec/ruby/library/socket/ancillarydata/ipv6_pktinfo_addr_spec.rb new file mode 100644 index 0000000000..f70fe27d6a --- /dev/null +++ b/spec/ruby/library/socket/ancillarydata/ipv6_pktinfo_addr_spec.rb @@ -0,0 +1,11 @@ +require_relative '../spec_helper' + +with_feature :ancillary_data, :ipv6_pktinfo do + describe 'Socket::AncillaryData#ipv6_pktinfo_addr' do + it 'returns an Addrinfo' do + data = Socket::AncillaryData.ipv6_pktinfo(Addrinfo.ip('::1'), 4) + + data.ipv6_pktinfo_addr.should be_an_instance_of(Addrinfo) + end + end +end diff --git a/spec/ruby/library/socket/ancillarydata/ipv6_pktinfo_ifindex_spec.rb b/spec/ruby/library/socket/ancillarydata/ipv6_pktinfo_ifindex_spec.rb new file mode 100644 index 0000000000..bda37eec98 --- /dev/null +++ b/spec/ruby/library/socket/ancillarydata/ipv6_pktinfo_ifindex_spec.rb @@ -0,0 +1,11 @@ +require_relative '../spec_helper' + +with_feature :ancillary_data, :ipv6_pktinfo do + describe 'Socket::AncillaryData#ipv6_pktinfo_ifindex' do + it 'returns an Addrinfo' do + data = Socket::AncillaryData.ipv6_pktinfo(Addrinfo.ip('::1'), 4) + + data.ipv6_pktinfo_ifindex.should == 4 + end + end +end diff --git a/spec/ruby/library/socket/ancillarydata/ipv6_pktinfo_spec.rb b/spec/ruby/library/socket/ancillarydata/ipv6_pktinfo_spec.rb new file mode 100644 index 0000000000..6315aba89c --- /dev/null +++ b/spec/ruby/library/socket/ancillarydata/ipv6_pktinfo_spec.rb @@ -0,0 +1,89 @@ +require_relative '../spec_helper' + +with_feature :ancillary_data, :ipv6_pktinfo do + describe 'Socket::AncillaryData.ipv6_pktinfo' do + before do + @data = Socket::AncillaryData.ipv6_pktinfo(Addrinfo.ip('::1'), 4) + end + + it 'returns a Socket::AncillaryData' do + @data.should be_an_instance_of(Socket::AncillaryData) + end + + it 'sets the family to AF_INET' do + @data.family.should == Socket::AF_INET6 + end + + it 'sets the level to IPPROTO_IP' do + @data.level.should == Socket::IPPROTO_IPV6 + end + + it 'sets the type to IP_PKTINFO' do + @data.type.should == Socket::IPV6_PKTINFO + end + end + + describe 'Socket::AncillaryData#ipv6_pktinfo' do + describe 'using an Addrinfo without a port number' do + before do + @source = Addrinfo.ip('::1') + @data = Socket::AncillaryData.ipv6_pktinfo(@source, 4) + end + + it 'returns an Array' do + @data.ipv6_pktinfo.should be_an_instance_of(Array) + end + + describe 'the returned Array' do + before do + @info = @data.ipv6_pktinfo + end + + it 'stores an Addrinfo at index 0' do + @info[0].should be_an_instance_of(Addrinfo) + end + + it 'stores the ifindex at index 1' do + @info[1].should be_an_instance_of(Fixnum) + end + end + + describe 'the source Addrinfo' do + before do + @addr = @data.ipv6_pktinfo[0] + end + + it 'uses the correct IP address' do + @addr.ip_address.should == '::1' + end + + it 'is not the same object as the input Addrinfo' do + @addr.should_not == @source + end + end + + describe 'the ifindex' do + it 'is a Fixnum' do + @data.ipv6_pktinfo[1].should == 4 + end + end + end + + describe 'using an Addrinfo with a port number' do + before do + @source = Addrinfo.tcp('::1', 80) + @data = Socket::AncillaryData.ipv6_pktinfo(@source, 4) + end + + describe 'the source Addrinfo' do + before do + @addr = @data.ipv6_pktinfo[0] + end + + it 'does not contain a port number' do + @addr.ip_port.should == 0 + end + end + end + end +end diff --git a/spec/ruby/library/socket/ancillarydata/level_spec.rb b/spec/ruby/library/socket/ancillarydata/level_spec.rb new file mode 100644 index 0000000000..40b070a6d8 --- /dev/null +++ b/spec/ruby/library/socket/ancillarydata/level_spec.rb @@ -0,0 +1,9 @@ +require_relative '../spec_helper' + +with_feature :ancillary_data do + describe 'Socket::AncillaryData#level' do + it 'returns the level as a Fixnum' do + Socket::AncillaryData.new(:INET, :SOCKET, :RIGHTS, '').level.should == Socket::SOL_SOCKET + end + end +end diff --git a/spec/ruby/library/socket/ancillarydata/type_spec.rb b/spec/ruby/library/socket/ancillarydata/type_spec.rb new file mode 100644 index 0000000000..1a4b04ed57 --- /dev/null +++ b/spec/ruby/library/socket/ancillarydata/type_spec.rb @@ -0,0 +1,9 @@ +require_relative '../spec_helper' + +with_feature :ancillary_data do + describe 'Socket::AncillaryData#type' do + it 'returns the type as a Fixnum' do + Socket::AncillaryData.new(:INET, :SOCKET, :RIGHTS, '').type.should == Socket::SCM_RIGHTS + end + end +end diff --git a/spec/ruby/library/socket/ancillarydata/unix_rights_spec.rb b/spec/ruby/library/socket/ancillarydata/unix_rights_spec.rb new file mode 100644 index 0000000000..0bbef4c08d --- /dev/null +++ b/spec/ruby/library/socket/ancillarydata/unix_rights_spec.rb @@ -0,0 +1,59 @@ +require_relative '../spec_helper' + +with_feature :ancillary_data do + describe 'Socket::AncillaryData.unix_rights' do + describe 'using a list of IO objects' do + before do + @data = Socket::AncillaryData.unix_rights(STDOUT, STDERR) + end + + it 'sets the family to AF_UNIX' do + @data.family.should == Socket::AF_UNIX + end + + it 'sets the level to SOL_SOCKET' do + @data.level.should == Socket::SOL_SOCKET + end + + it 'sets the type to SCM_RIGHTS' do + @data.type.should == Socket::SCM_RIGHTS + end + + it 'sets the data to a String containing the file descriptors' do + @data.data.unpack('I*').should == [STDOUT.fileno, STDERR.fileno] + end + end + + describe 'using non IO objects' do + it 'raises TypeError' do + lambda { Socket::AncillaryData.unix_rights(10) }.should raise_error(TypeError) + end + end + end + + describe 'Socket::AncillaryData#unix_rights' do + it 'returns the data as an Array of IO objects' do + data = Socket::AncillaryData.unix_rights(STDOUT, STDERR) + + data.unix_rights.should == [STDOUT, STDERR] + end + + it 'returns nil when the data is not a list of file descriptors' do + data = Socket::AncillaryData.new(:UNIX, :SOCKET, :RIGHTS, '') + + data.unix_rights.should be_nil + end + + it 'raises TypeError when the level is not SOL_SOCKET' do + data = Socket::AncillaryData.new(:INET, :IP, :RECVTTL, '') + + lambda { data.unix_rights }.should raise_error(TypeError) + end + + it 'raises TypeError when the type is not SCM_RIGHTS' do + data = Socket::AncillaryData.new(:INET, :SOCKET, :TIMESTAMP, '') + + lambda { data.unix_rights }.should raise_error(TypeError) + end + end +end diff --git a/spec/ruby/library/socket/basicsocket/close_read_spec.rb b/spec/ruby/library/socket/basicsocket/close_read_spec.rb index 13894bc0c5..c989fcaf72 100644 --- a/spec/ruby/library/socket/basicsocket/close_read_spec.rb +++ b/spec/ruby/library/socket/basicsocket/close_read_spec.rb @@ -1,4 +1,4 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' describe "Socket::BasicSocket#close_read" do @@ -15,13 +15,13 @@ describe "Socket::BasicSocket#close_read" do lambda { @server.read }.should raise_error(IOError) end - it "it works on sockets with closed ends" do + it 'does not raise when called on a socket already closed for reading' do + @server.close_read @server.close_read - lambda { @server.close_read }.should_not raise_error(Exception) lambda { @server.read }.should raise_error(IOError) end - it "does not close the socket" do + it 'does not fully close the socket' do @server.close_read @server.closed?.should be_false end @@ -32,7 +32,7 @@ describe "Socket::BasicSocket#close_read" do @server.closed?.should be_true end - it "raises IOError on closed socket" do + it 'raises IOError when called on a fully closed socket' do @server.close lambda { @server.close_read }.should raise_error(IOError) end diff --git a/spec/ruby/library/socket/basicsocket/close_write_spec.rb b/spec/ruby/library/socket/basicsocket/close_write_spec.rb index 194df1d535..f37e0e5074 100644 --- a/spec/ruby/library/socket/basicsocket/close_write_spec.rb +++ b/spec/ruby/library/socket/basicsocket/close_write_spec.rb @@ -1,4 +1,4 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' describe "Socket::BasicSocket#close_write" do @@ -15,13 +15,13 @@ describe "Socket::BasicSocket#close_write" do lambda { @server.write("foo") }.should raise_error(IOError) end - it "works on sockets with closed write ends" do + it 'does not raise when called on a socket already closed for writing' do + @server.close_write @server.close_write - lambda { @server.close_write }.should_not raise_error(Exception) lambda { @server.write("foo") }.should raise_error(IOError) end - it "does not close the socket" do + it 'does not fully close the socket' do @server.close_write @server.closed?.should be_false end @@ -37,7 +37,7 @@ describe "Socket::BasicSocket#close_write" do @server.closed?.should be_true end - it "raises IOError on closed socket" do + it 'raises IOError when called on a fully closed socket' do @server.close lambda { @server.close_write }.should raise_error(IOError) end diff --git a/spec/ruby/library/socket/basicsocket/connect_address_spec.rb b/spec/ruby/library/socket/basicsocket/connect_address_spec.rb new file mode 100644 index 0000000000..cb05d3bfe1 --- /dev/null +++ b/spec/ruby/library/socket/basicsocket/connect_address_spec.rb @@ -0,0 +1,150 @@ +require_relative '../spec_helper' +require_relative '../fixtures/classes' + +describe 'Socket#connect_address' do + describe 'using an unbound socket' do + after do + @sock.close + end + + it 'raises SocketError' do + @sock = Socket.new(:INET, :STREAM) + + lambda { @sock.connect_address }.should raise_error(SocketError) + end + end + + describe 'using a socket bound to 0.0.0.0' do + before do + @sock = Socket.new(:INET, :STREAM) + @sock.bind(Socket.sockaddr_in(0, '0.0.0.0')) + end + + after do + @sock.close + end + + it 'returns an Addrinfo' do + @sock.connect_address.should be_an_instance_of(Addrinfo) + end + + it 'uses 127.0.0.1 as the IP address' do + @sock.connect_address.ip_address.should == '127.0.0.1' + end + + it 'uses the correct port number' do + @sock.connect_address.ip_port.should > 0 + end + + it 'uses AF_INET as the address family' do + @sock.connect_address.afamily.should == Socket::AF_INET + end + + it 'uses PF_INET as the address family' do + @sock.connect_address.pfamily.should == Socket::PF_INET + end + + it 'uses SOCK_STREAM as the socket type' do + @sock.connect_address.socktype.should == Socket::SOCK_STREAM + end + + it 'uses 0 as the protocol' do + @sock.connect_address.protocol.should == 0 + end + end + + describe 'using a socket bound to ::' do + before do + @sock = Socket.new(:INET6, :STREAM) + @sock.bind(Socket.sockaddr_in(0, '::')) + end + + after do + @sock.close + end + + it 'returns an Addrinfo' do + @sock.connect_address.should be_an_instance_of(Addrinfo) + end + + it 'uses ::1 as the IP address' do + @sock.connect_address.ip_address.should == '::1' + end + + it 'uses the correct port number' do + @sock.connect_address.ip_port.should > 0 + end + + it 'uses AF_INET6 as the address family' do + @sock.connect_address.afamily.should == Socket::AF_INET6 + end + + it 'uses PF_INET6 as the address family' do + @sock.connect_address.pfamily.should == Socket::PF_INET6 + end + + it 'uses SOCK_STREAM as the socket type' do + @sock.connect_address.socktype.should == Socket::SOCK_STREAM + end + + it 'uses 0 as the protocol' do + @sock.connect_address.protocol.should == 0 + end + end + + with_feature :unix_socket do + describe 'using an unbound UNIX socket' do + before do + @path = SocketSpecs.socket_path + @server = UNIXServer.new(@path) + @client = UNIXSocket.new(@path) + end + + after do + @client.close + @server.close + rm_r(@path) + end + + it 'raises SocketError' do + lambda { @client.connect_address }.should raise_error(SocketError) + end + end + + describe 'using a bound UNIX socket' do + before do + @path = SocketSpecs.socket_path + @sock = UNIXServer.new(@path) + end + + after do + @sock.close + rm_r(@path) + end + + it 'returns an Addrinfo' do + @sock.connect_address.should be_an_instance_of(Addrinfo) + end + + it 'uses the correct socket path' do + @sock.connect_address.unix_path.should == @path + end + + it 'uses AF_UNIX as the address family' do + @sock.connect_address.afamily.should == Socket::AF_UNIX + end + + it 'uses PF_UNIX as the protocol family' do + @sock.connect_address.pfamily.should == Socket::PF_UNIX + end + + it 'uses SOCK_STREAM as the socket type' do + @sock.connect_address.socktype.should == Socket::SOCK_STREAM + end + + it 'uses 0 as the protocol' do + @sock.connect_address.protocol.should == 0 + end + end + end +end diff --git a/spec/ruby/library/socket/basicsocket/do_not_reverse_lookup_spec.rb b/spec/ruby/library/socket/basicsocket/do_not_reverse_lookup_spec.rb index 479a1fdac8..85a66275f8 100644 --- a/spec/ruby/library/socket/basicsocket/do_not_reverse_lookup_spec.rb +++ b/spec/ruby/library/socket/basicsocket/do_not_reverse_lookup_spec.rb @@ -1,4 +1,4 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' describe "BasicSocket.do_not_reverse_lookup" do diff --git a/spec/ruby/library/socket/basicsocket/for_fd_spec.rb b/spec/ruby/library/socket/basicsocket/for_fd_spec.rb index affe8c2428..9c9e6a8b55 100644 --- a/spec/ruby/library/socket/basicsocket/for_fd_spec.rb +++ b/spec/ruby/library/socket/basicsocket/for_fd_spec.rb @@ -1,14 +1,14 @@ - -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' -describe "BasicSocket#for_fd" do +describe "BasicSocket.for_fd" do before :each do @server = TCPServer.new(0) @s2 = nil end after :each do + @socket1.close if @socket1 @server.close if @server end @@ -18,4 +18,21 @@ describe "BasicSocket#for_fd" do @s2.should be_kind_of(TCPServer) @s2.fileno.should == @server.fileno end + + it 'returns a new socket for a file descriptor' do + @socket1 = Socket.new(:INET, :DGRAM) + socket2 = Socket.for_fd(@socket1.fileno) + socket2.autoclose = false + + socket2.should be_an_instance_of(Socket) + socket2.fileno.should == @socket1.fileno + end + + it 'sets the socket into binary mode' do + @socket1 = Socket.new(:INET, :DGRAM) + socket2 = Socket.for_fd(@socket1.fileno) + socket2.autoclose = false + + socket2.binmode?.should be_true + end end diff --git a/spec/ruby/library/socket/basicsocket/getpeereid_spec.rb b/spec/ruby/library/socket/basicsocket/getpeereid_spec.rb new file mode 100644 index 0000000000..9eeb6d0e0b --- /dev/null +++ b/spec/ruby/library/socket/basicsocket/getpeereid_spec.rb @@ -0,0 +1,36 @@ +require_relative '../spec_helper' +require_relative '../fixtures/classes' + +describe 'BasicSocket#getpeereid' do + with_feature :unix_socket do + describe 'using a UNIXSocket' do + before do + @path = SocketSpecs.socket_path + @server = UNIXServer.new(@path) + @client = UNIXSocket.new(@path) + end + + after do + @client.close + @server.close + + rm_r(@path) + end + + it 'returns an Array with the user and group ID' do + @client.getpeereid.should == [Process.euid, Process.egid] + end + end + end + + describe 'using an IPSocket' do + after do + @sock.close + end + + it 'raises NoMethodError' do + @sock = TCPServer.new('127.0.0.1', 0) + lambda { @sock.getpeereid }.should raise_error(NoMethodError) + end + end +end diff --git a/spec/ruby/library/socket/basicsocket/getpeername_spec.rb b/spec/ruby/library/socket/basicsocket/getpeername_spec.rb index c2636f764e..23c73056cd 100644 --- a/spec/ruby/library/socket/basicsocket/getpeername_spec.rb +++ b/spec/ruby/library/socket/basicsocket/getpeername_spec.rb @@ -1,4 +1,4 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' describe "Socket::BasicSocket#getpeername" do @@ -19,8 +19,7 @@ describe "Socket::BasicSocket#getpeername" do @client.getpeername.should == server_sockaddr end - # Catch general exceptions to prevent NotImplementedError - it "raises an error if socket's not connected" do - lambda { @server.getpeername }.should raise_error(Exception) + it 'raises Errno::ENOTCONN for a disconnected socket' do + lambda { @server.getpeername }.should raise_error(Errno::ENOTCONN) end end diff --git a/spec/ruby/library/socket/basicsocket/getsockname_spec.rb b/spec/ruby/library/socket/basicsocket/getsockname_spec.rb index 581eb68599..a2c5980a9e 100644 --- a/spec/ruby/library/socket/basicsocket/getsockname_spec.rb +++ b/spec/ruby/library/socket/basicsocket/getsockname_spec.rb @@ -1,4 +1,4 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' describe "Socket::BasicSocket#getsockname" do @@ -20,7 +20,7 @@ describe "Socket::BasicSocket#getsockname" do sockaddr[0].should == @socket.addr[1] end - it "returns empty sockaddr for unbinded sockets" do + it 'returns a default socket address for a disconnected socket' do @socket = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0) sockaddr = Socket.unpack_sockaddr_in(@socket.getsockname) sockaddr.should == [0, "0.0.0.0"] diff --git a/spec/ruby/library/socket/basicsocket/getsockopt_spec.rb b/spec/ruby/library/socket/basicsocket/getsockopt_spec.rb index 7040aac5e9..926d7505e8 100644 --- a/spec/ruby/library/socket/basicsocket/getsockopt_spec.rb +++ b/spec/ruby/library/socket/basicsocket/getsockopt_spec.rb @@ -1,4 +1,4 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' describe "BasicSocket#getsockopt" do @@ -43,4 +43,146 @@ describe "BasicSocket#getsockopt" do it "raises a SystemCallError with an invalid socket option" do lambda { @sock.getsockopt Socket::SOL_SOCKET, -1 }.should raise_error(Errno::ENOPROTOOPT) end + + it 'returns a Socket::Option using a constant' do + opt = @sock.getsockopt(Socket::SOL_SOCKET, Socket::SO_TYPE) + + opt.should be_an_instance_of(Socket::Option) + end + + it 'returns a Socket::Option for a boolean option' do + opt = @sock.getsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEADDR) + + opt.bool.should == false + end + + it 'returns a Socket::Option for a numeric option' do + opt = @sock.getsockopt(Socket::IPPROTO_IP, Socket::IP_TTL) + + opt.int.should be_an_instance_of(Fixnum) + end + + it 'returns a Socket::Option for a struct option' do + opt = @sock.getsockopt(Socket::SOL_SOCKET, Socket::SO_LINGER) + + opt.linger.should == [false, 0] + end + + it 'raises Errno::ENOPROTOOPT when requesting an invalid option' do + lambda { @sock.getsockopt(Socket::SOL_SOCKET, -1) }.should raise_error(Errno::ENOPROTOOPT) + end + + describe 'using Symbols as arguments' do + it 'returns a Socket::Option for arguments :SOCKET and :TYPE' do + opt = @sock.getsockopt(:SOCKET, :TYPE) + + opt.level.should == Socket::SOL_SOCKET + opt.optname.should == Socket::SO_TYPE + end + + it 'returns a Socket::Option for arguments :IP and :TTL' do + opt = @sock.getsockopt(:IP, :TTL) + + opt.level.should == Socket::IPPROTO_IP + opt.optname.should == Socket::IP_TTL + end + + it 'returns a Socket::Option for arguments :SOCKET and :REUSEADDR' do + opt = @sock.getsockopt(:SOCKET, :REUSEADDR) + + opt.level.should == Socket::SOL_SOCKET + opt.optname.should == Socket::SO_REUSEADDR + end + + it 'returns a Socket::Option for arguments :SOCKET and :LINGER' do + opt = @sock.getsockopt(:SOCKET, :LINGER) + + opt.level.should == Socket::SOL_SOCKET + opt.optname.should == Socket::SO_LINGER + end + + with_feature :udp_cork do + it 'returns a Socket::Option for arguments :UDP and :CORK' do + sock = Socket.new(:INET, :DGRAM) + begin + opt = sock.getsockopt(:UDP, :CORK) + + opt.level.should == Socket::IPPROTO_UDP + opt.optname.should == Socket::UDP_CORK + ensure + sock.close + end + end + end + end + + describe 'using Strings as arguments' do + it 'returns a Socket::Option for arguments "SOCKET" and "TYPE"' do + opt = @sock.getsockopt("SOCKET", "TYPE") + + opt.level.should == Socket::SOL_SOCKET + opt.optname.should == Socket::SO_TYPE + end + + it 'returns a Socket::Option for arguments "IP" and "TTL"' do + opt = @sock.getsockopt("IP", "TTL") + + opt.level.should == Socket::IPPROTO_IP + opt.optname.should == Socket::IP_TTL + end + + it 'returns a Socket::Option for arguments "SOCKET" and "REUSEADDR"' do + opt = @sock.getsockopt("SOCKET", "REUSEADDR") + + opt.level.should == Socket::SOL_SOCKET + opt.optname.should == Socket::SO_REUSEADDR + end + + it 'returns a Socket::Option for arguments "SOCKET" and "LINGER"' do + opt = @sock.getsockopt("SOCKET", "LINGER") + + opt.level.should == Socket::SOL_SOCKET + opt.optname.should == Socket::SO_LINGER + end + + with_feature :udp_cork do + it 'returns a Socket::Option for arguments "UDP" and "CORK"' do + sock = Socket.new("INET", "DGRAM") + begin + opt = sock.getsockopt("UDP", "CORK") + + opt.level.should == Socket::IPPROTO_UDP + opt.optname.should == Socket::UDP_CORK + ensure + sock.close + end + end + end + end + + describe 'using a String based option' do + it 'allows unpacking of a boolean option' do + opt = @sock.getsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEADDR).to_s + + opt.unpack('i').should == [0] + end + + it 'allows unpacking of a numeric option' do + opt = @sock.getsockopt(Socket::IPPROTO_IP, Socket::IP_TTL).to_s + array = opt.unpack('i') + + array[0].should be_an_instance_of(Fixnum) + array[0].should > 0 + end + + it 'allows unpacking of a struct option' do + opt = @sock.getsockopt(Socket::SOL_SOCKET, Socket::SO_LINGER).to_s + + if opt.bytesize == 8 + opt.unpack('ii').should == [0, 0] + else + opt.unpack('i').should == [0] + end + end + end end diff --git a/spec/ruby/library/socket/basicsocket/ioctl_spec.rb b/spec/ruby/library/socket/basicsocket/ioctl_spec.rb index 6ce314b6fb..615d92bea8 100644 --- a/spec/ruby/library/socket/basicsocket/ioctl_spec.rb +++ b/spec/ruby/library/socket/basicsocket/ioctl_spec.rb @@ -1,5 +1,4 @@ -require_relative '../../../spec_helper' -require 'socket' +require_relative '../spec_helper' describe "Socket::BasicSocket#ioctl" do platform_is :linux do diff --git a/spec/ruby/library/socket/basicsocket/recv_nonblock_spec.rb b/spec/ruby/library/socket/basicsocket/recv_nonblock_spec.rb index 8fc0dce4f0..1b6027d26c 100644 --- a/spec/ruby/library/socket/basicsocket/recv_nonblock_spec.rb +++ b/spec/ruby/library/socket/basicsocket/recv_nonblock_spec.rb @@ -1,7 +1,65 @@ -require_relative '../../../spec_helper' -require_relative '../shared/recv_nonblock' +require_relative '../spec_helper' require_relative '../fixtures/classes' describe "Socket::BasicSocket#recv_nonblock" do - it_behaves_like :socket_recv_nonblock, :recv_nonblock + SocketSpecs.each_ip_protocol do |family, ip_address| + before :each do + @s1 = Socket.new(family, :DGRAM) + @s2 = Socket.new(family, :DGRAM) + end + + after :each do + @s1.close unless @s1.closed? + @s2.close unless @s2.closed? + end + + platform_is_not :windows do + describe 'using an unbound socket' do + it 'raises an exception extending IO::WaitReadable' do + lambda { @s1.recv_nonblock(1) }.should raise_error(IO::WaitReadable) + end + end + end + + it "raises an exception extending IO::WaitReadable if there's no data available" do + @s1.bind(Socket.pack_sockaddr_in(0, ip_address)) + lambda { + @s1.recv_nonblock(5) + }.should raise_error(IO::WaitReadable) { |e| + platform_is_not :windows do + e.should be_kind_of(Errno::EAGAIN) + end + platform_is :windows do + e.should be_kind_of(Errno::EWOULDBLOCK) + end + } + end + + it "receives data after it's ready" do + @s1.bind(Socket.pack_sockaddr_in(0, ip_address)) + @s2.send("aaa", 0, @s1.getsockname) + IO.select([@s1], nil, nil, 2) + @s1.recv_nonblock(5).should == "aaa" + end + + it "allows an output buffer as third argument" do + @s1.bind(Socket.pack_sockaddr_in(0, ip_address)) + @s2.send("data", 0, @s1.getsockname) + IO.select([@s1], nil, nil, 2) + + buf = "foo" + @s1.recv_nonblock(5, 0, buf) + buf.should == "data" + end + + it "does not block if there's no data available" do + @s1.bind(Socket.pack_sockaddr_in(0, ip_address)) + @s2.send("a", 0, @s1.getsockname) + IO.select([@s1], nil, nil, 2) + @s1.recv_nonblock(1).should == "a" + lambda { + @s1.recv_nonblock(5) + }.should raise_error(IO::WaitReadable) + end + end end diff --git a/spec/ruby/library/socket/basicsocket/recv_spec.rb b/spec/ruby/library/socket/basicsocket/recv_spec.rb index 7677d4ff8c..a277dc2d97 100644 --- a/spec/ruby/library/socket/basicsocket/recv_spec.rb +++ b/spec/ruby/library/socket/basicsocket/recv_spec.rb @@ -1,5 +1,5 @@ # -*- encoding: binary -*- -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' describe "BasicSocket#recv" do @@ -92,3 +92,68 @@ describe "BasicSocket#recv" do socket.close end end + +describe 'BasicSocket#recv' do + SocketSpecs.each_ip_protocol do |family, ip_address| + before do + @server = Socket.new(family, :DGRAM) + @client = Socket.new(family, :DGRAM) + end + + after do + @client.close + @server.close + end + + describe 'using an unbound socket' do + it 'blocks the caller' do + lambda { @server.recv(4) }.should block_caller + end + end + + describe 'using a bound socket' do + before do + @server.bind(Socket.sockaddr_in(0, ip_address)) + end + + describe 'without any data available' do + it 'blocks the caller' do + lambda { @server.recv(4) }.should block_caller + end + end + + describe 'with data available' do + before do + @client.connect(@server.getsockname) + end + + it 'reads the given amount of bytes' do + @client.write('hello') + + @server.recv(2).should == 'he' + end + + it 'reads the given amount of bytes when it exceeds the data size' do + @client.write('he') + + @server.recv(6).should == 'he' + end + + it 'blocks the caller when called twice without new data being available' do + @client.write('hello') + + @server.recv(2).should == 'he' + + lambda { @server.recv(4) }.should block_caller + end + + it 'takes a peek at the data when using the MSG_PEEK flag' do + @client.write('hello') + + @server.recv(2, Socket::MSG_PEEK).should == 'he' + @server.recv(2).should == 'he' + end + end + end + end +end diff --git a/spec/ruby/library/socket/basicsocket/recvmsg_nonblock_spec.rb b/spec/ruby/library/socket/basicsocket/recvmsg_nonblock_spec.rb new file mode 100644 index 0000000000..698b9e7ba5 --- /dev/null +++ b/spec/ruby/library/socket/basicsocket/recvmsg_nonblock_spec.rb @@ -0,0 +1,204 @@ +require_relative '../spec_helper' +require_relative '../fixtures/classes' + +describe 'BasicSocket#recvmsg_nonblock' do + SocketSpecs.each_ip_protocol do |family, ip_address| + describe 'using a disconnected socket' do + before do + @client = Socket.new(family, :DGRAM) + @server = Socket.new(family, :DGRAM) + end + + after do + @client.close + @server.close + end + + platform_is_not :windows do + describe 'using an unbound socket' do + it 'raises an exception extending IO::WaitReadable' do + lambda { @server.recvmsg_nonblock }.should raise_error(IO::WaitReadable) + end + end + end + + describe 'using a bound socket' do + before do + @server.bind(Socket.sockaddr_in(0, ip_address)) + end + + describe 'without any data available' do + it 'raises an exception extending IO::WaitReadable' do + lambda { @server.recvmsg_nonblock }.should raise_error(IO::WaitReadable) + end + end + + describe 'with data available' do + before do + @client.connect(@server.getsockname) + + @client.write('hello') + + IO.select([@server], nil, nil, 5) + end + + it 'returns an Array containing the data, an Addrinfo and the flags' do + @server.recvmsg_nonblock.should be_an_instance_of(Array) + end + + describe 'without a maximum message length' do + it 'reads all the available data' do + @server.recvmsg_nonblock[0].should == 'hello' + end + end + + describe 'with a maximum message length' do + platform_is_not :windows do + it 'reads up to the maximum amount of bytes' do + @server.recvmsg_nonblock(2)[0].should == 'he' + end + end + end + + describe 'the returned Array' do + before do + @array = @server.recvmsg_nonblock + end + + it 'stores the message at index 0' do + @array[0].should == 'hello' + end + + it 'stores an Addrinfo at index 1' do + @array[1].should be_an_instance_of(Addrinfo) + end + + platform_is_not :windows do + it 'stores the flags at index 2' do + @array[2].should be_an_instance_of(Fixnum) + end + end + + describe 'the returned Addrinfo' do + before do + @addr = @array[1] + end + + it 'uses the IP address of the client' do + @addr.ip_address.should == @client.local_address.ip_address + end + + it 'uses the correct address family' do + @addr.afamily.should == family + end + + it 'uses the correct protocol family' do + @addr.pfamily.should == family + end + + it 'uses the correct socket type' do + @addr.socktype.should == Socket::SOCK_DGRAM + end + + it 'uses the port number of the client' do + @addr.ip_port.should == @client.local_address.ip_port + end + end + end + end + end + end + + platform_is_not :windows do + describe 'using a connected socket' do + before do + @client = Socket.new(family, :STREAM) + @server = Socket.new(family, :STREAM) + + @server.bind(Socket.sockaddr_in(0, ip_address)) + @server.listen(1) + + @client.connect(@server.getsockname) + end + + after do + @client.close + @server.close + end + + describe 'without any data available' do + it 'raises IO::WaitReadable' do + lambda { + socket, _ = @server.accept + begin + socket.recvmsg_nonblock + ensure + socket.close + end + }.should raise_error(IO::WaitReadable) + end + end + + describe 'with data available' do + before do + @client.write('hello') + + @socket, _ = @server.accept + end + + after do + @socket.close + end + + it 'returns an Array containing the data, an Addrinfo and the flags' do + @socket.recvmsg_nonblock.should be_an_instance_of(Array) + end + + describe 'the returned Array' do + before do + @array = @socket.recvmsg_nonblock + end + + it 'stores the message at index 0' do + @array[0].should == 'hello' + end + + it 'stores an Addrinfo at index 1' do + @array[1].should be_an_instance_of(Addrinfo) + end + + it 'stores the flags at index 2' do + @array[2].should be_an_instance_of(Fixnum) + end + + describe 'the returned Addrinfo' do + before do + @addr = @array[1] + end + + it 'raises when receiving the ip_address message' do + lambda { @addr.ip_address }.should raise_error(SocketError) + end + + it 'uses the correct address family' do + @addr.afamily.should == Socket::AF_UNSPEC + end + + it 'uses 0 for the protocol family' do + @addr.pfamily.should == 0 + end + + it 'uses the correct socket type' do + @addr.socktype.should == Socket::SOCK_STREAM + end + + it 'raises when receiving the ip_port message' do + lambda { @addr.ip_port }.should raise_error(SocketError) + end + end + end + end + end + end + end +end diff --git a/spec/ruby/library/socket/basicsocket/recvmsg_spec.rb b/spec/ruby/library/socket/basicsocket/recvmsg_spec.rb new file mode 100644 index 0000000000..d7de83d72b --- /dev/null +++ b/spec/ruby/library/socket/basicsocket/recvmsg_spec.rb @@ -0,0 +1,197 @@ +require_relative '../spec_helper' +require_relative '../fixtures/classes' + +describe 'BasicSocket#recvmsg' do + SocketSpecs.each_ip_protocol do |family, ip_address| + describe 'using a disconnected socket' do + before do + @client = Socket.new(family, :DGRAM) + @server = Socket.new(family, :DGRAM) + end + + after do + @client.close + @server.close + end + + platform_is_not :windows do + describe 'using an unbound socket' do + it 'blocks the caller' do + lambda { @server.recvmsg }.should block_caller + end + end + end + + describe 'using a bound socket' do + before do + @server.bind(Socket.sockaddr_in(0, ip_address)) + end + + describe 'without any data available' do + it 'blocks the caller' do + lambda { @server.recvmsg }.should block_caller + end + end + + describe 'with data available' do + before do + @client.connect(@server.getsockname) + + @client.write('hello') + end + + it 'returns an Array containing the data, an Addrinfo and the flags' do + @server.recvmsg.should be_an_instance_of(Array) + end + + describe 'without a maximum message length' do + it 'reads all the available data' do + @server.recvmsg[0].should == 'hello' + end + end + + describe 'with a maximum message length' do + it 'reads up to the maximum amount of bytes' do + @server.recvmsg(2)[0].should == 'he' + end + end + + describe 'the returned Array' do + before do + @array = @server.recvmsg + end + + it 'stores the message at index 0' do + @array[0].should == 'hello' + end + + it 'stores an Addrinfo at index 1' do + @array[1].should be_an_instance_of(Addrinfo) + end + + platform_is_not :windows do + it 'stores the flags at index 2' do + @array[2].should be_an_instance_of(Fixnum) + end + end + + describe 'the returned Addrinfo' do + before do + @addr = @array[1] + end + + it 'uses the IP address of the client' do + @addr.ip_address.should == @client.local_address.ip_address + end + + it 'uses the correct address family' do + @addr.afamily.should == family + end + + it 'uses the correct protocol family' do + @addr.pfamily.should == family + end + + it 'uses the correct socket type' do + @addr.socktype.should == Socket::SOCK_DGRAM + end + + it 'uses the port number of the client' do + @addr.ip_port.should == @client.local_address.ip_port + end + end + end + end + end + end + + platform_is_not :windows do + describe 'using a connected socket' do + before do + @client = Socket.new(family, :STREAM) + @server = Socket.new(family, :STREAM) + + @server.bind(Socket.sockaddr_in(0, ip_address)) + @server.listen(1) + + @client.connect(@server.getsockname) + end + + after do + @client.close + @server.close + end + + describe 'without any data available' do + it 'blocks the caller' do + socket, _ = @server.accept + begin + lambda { socket.recvmsg }.should block_caller + ensure + socket.close + end + end + end + + describe 'with data available' do + before do + @client.write('hello') + @socket, _ = @server.accept + end + + after do + @socket.close + end + + it 'returns an Array containing the data, an Addrinfo and the flags' do + @socket.recvmsg.should be_an_instance_of(Array) + end + + describe 'the returned Array' do + before do + @array = @socket.recvmsg + end + + it 'stores the message at index 0' do + @array[0].should == 'hello' + end + + it 'stores an Addrinfo at index 1' do + @array[1].should be_an_instance_of(Addrinfo) + end + + it 'stores the flags at index 2' do + @array[2].should be_an_instance_of(Fixnum) + end + + describe 'the returned Addrinfo' do + before do + @addr = @array[1] + end + + it 'raises when receiving the ip_address message' do + lambda { @addr.ip_address }.should raise_error(SocketError) + end + + it 'uses the correct address family' do + @addr.afamily.should == Socket::AF_UNSPEC + end + + it 'returns 0 for the protocol family' do + @addr.pfamily.should == 0 + end + + it 'uses the correct socket type' do + @addr.socktype.should == Socket::SOCK_STREAM + end + + it 'raises when receiving the ip_port message' do + lambda { @addr.ip_port }.should raise_error(SocketError) + end + end + end + end + end + end + end +end diff --git a/spec/ruby/library/socket/basicsocket/send_spec.rb b/spec/ruby/library/socket/basicsocket/send_spec.rb index e2e0ce592e..c8d2af8f7a 100644 --- a/spec/ruby/library/socket/basicsocket/send_spec.rb +++ b/spec/ruby/library/socket/basicsocket/send_spec.rb @@ -1,4 +1,4 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' describe "BasicSocket#send" do @@ -83,3 +83,132 @@ describe "BasicSocket#send" do data.should == 'hello' end end + +describe 'BasicSocket#send' do + SocketSpecs.each_ip_protocol do |family, ip_address| + describe 'using a disconnected socket' do + before do + @client = Socket.new(family, :DGRAM) + @server = Socket.new(family, :DGRAM) + + @server.bind(Socket.sockaddr_in(0, ip_address)) + end + + after do + @client.close + @server.close + end + + describe 'without a destination address' do + it "raises #{SocketSpecs.dest_addr_req_error}" do + lambda { @client.send('hello', 0) }.should raise_error(SocketSpecs.dest_addr_req_error) + end + end + + describe 'with a destination address as a String' do + it 'returns the amount of sent bytes' do + @client.send('hello', 0, @server.getsockname).should == 5 + end + + it 'does not persist the connection after writing to the socket' do + @client.send('hello', 0, @server.getsockname) + + lambda { @client.send('hello', 0) }.should raise_error(SocketSpecs.dest_addr_req_error) + end + end + + describe 'with a destination address as an Addrinfo' do + it 'returns the amount of sent bytes' do + @client.send('hello', 0, @server.connect_address).should == 5 + end + end + end + + describe 'using a connected UDP socket' do + before do + @client = Socket.new(family, :DGRAM) + @server = Socket.new(family, :DGRAM) + + @server.bind(Socket.sockaddr_in(0, ip_address)) + end + + after do + @client.close + @server.close + end + + describe 'without a destination address argument' do + before do + @client.connect(@server.getsockname) + end + + it 'returns the amount of bytes written' do + @client.send('hello', 0).should == 5 + end + end + + describe 'with a destination address argument' do + before do + @alt_server = Socket.new(family, :DGRAM) + + @alt_server.bind(Socket.sockaddr_in(0, ip_address)) + end + + after do + @alt_server.close + end + + it 'sends the message to the given address instead' do + @client.send('hello', 0, @alt_server.getsockname).should == 5 + + lambda { @server.recv(5) }.should block_caller + + @alt_server.recv(5).should == 'hello' + end + + it 'does not persist the alternative connection after writing to the socket' do + @client.send('hello', 0, @alt_server.getsockname) + + @client.connect(@server.getsockname) + @client.send('world', 0) + + @server.recv(5).should == 'world' + end + end + end + + platform_is_not :windows do + describe 'using a connected TCP socket' do + before do + @client = Socket.new(family, :STREAM) + @server = Socket.new(family, :STREAM) + + @server.bind(Socket.sockaddr_in(0, ip_address)) + @server.listen(1) + + @client.connect(@server.getsockname) + end + + after do + @client.close + @server.close + end + + describe 'using the MSG_OOB flag' do + it 'sends an out-of-band message' do + @server.setsockopt(:SOCKET, :OOBINLINE, true) + + @client.send('a', Socket::MSG_OOB).should == 1 + + socket, _ = @server.accept + begin + socket.recv(1, Socket::MSG_OOB).should == 'a' + ensure + socket.close + end + end + end + end + end + end +end diff --git a/spec/ruby/library/socket/basicsocket/sendmsg_nonblock_spec.rb b/spec/ruby/library/socket/basicsocket/sendmsg_nonblock_spec.rb new file mode 100644 index 0000000000..de5e2aa749 --- /dev/null +++ b/spec/ruby/library/socket/basicsocket/sendmsg_nonblock_spec.rb @@ -0,0 +1,104 @@ +require_relative '../spec_helper' +require_relative '../fixtures/classes' + +describe 'BasicSocket#sendmsg_nonblock' do + SocketSpecs.each_ip_protocol do |family, ip_address| + describe 'using a disconnected socket' do + before do + @client = Socket.new(family, :DGRAM) + @server = Socket.new(family, :DGRAM) + + @server.bind(Socket.sockaddr_in(0, ip_address)) + end + + after do + @client.close + @server.close + end + + describe 'without a destination address' do + it "raises #{SocketSpecs.dest_addr_req_error}" do + lambda { @client.sendmsg_nonblock('hello') }.should raise_error(SocketSpecs.dest_addr_req_error) + end + end + + describe 'with a destination address as a String' do + it 'returns the amount of sent bytes' do + @client.sendmsg_nonblock('hello', 0, @server.getsockname).should == 5 + end + end + + describe 'with a destination address as an Addrinfo' do + it 'returns the amount of sent bytes' do + @client.sendmsg_nonblock('hello', 0, @server.connect_address).should == 5 + end + end + end + + describe 'using a connected UDP socket' do + before do + @client = Socket.new(family, :DGRAM) + @server = Socket.new(family, :DGRAM) + + @server.bind(Socket.sockaddr_in(0, ip_address)) + end + + after do + @client.close + @server.close + end + + describe 'without a destination address argument' do + before do + @client.connect(@server.getsockname) + end + + it 'returns the amount of bytes written' do + @client.sendmsg_nonblock('hello').should == 5 + end + end + + describe 'with a destination address argument' do + before do + @alt_server = Socket.new(family, :DGRAM) + @alt_server.bind(Socket.sockaddr_in(0, ip_address)) + end + + after do + @alt_server.close + end + + it 'sends the message to the given address instead' do + @client.sendmsg_nonblock('hello', 0, @alt_server.getsockname).should == 5 + lambda { @server.recv(5) }.should block_caller + @alt_server.recv(5).should == 'hello' + end + end + end + + platform_is_not :windows do + describe 'using a connected TCP socket' do + before do + @client = Socket.new(family, :STREAM) + @server = Socket.new(family, :STREAM) + + @server.bind(Socket.sockaddr_in(0, ip_address)) + @server.listen(1) + + @client.connect(@server.getsockname) + end + + after do + @client.close + @server.close + end + + it 'raises IO::WaitWritable when the underlying buffer is full' do + lambda { + 10.times { @client.sendmsg_nonblock('hello' * 1_000_000) } + }.should raise_error(IO::WaitWritable) + end + end + end + end +end diff --git a/spec/ruby/library/socket/basicsocket/sendmsg_spec.rb b/spec/ruby/library/socket/basicsocket/sendmsg_spec.rb new file mode 100644 index 0000000000..f2c11f443a --- /dev/null +++ b/spec/ruby/library/socket/basicsocket/sendmsg_spec.rb @@ -0,0 +1,111 @@ +require_relative '../spec_helper' +require_relative '../fixtures/classes' + +describe 'BasicSocket#sendmsg' do + SocketSpecs.each_ip_protocol do |family, ip_address| + describe 'using a disconnected socket' do + before do + @client = Socket.new(family, :DGRAM) + @server = Socket.new(family, :DGRAM) + + @server.bind(Socket.sockaddr_in(0, ip_address)) + end + + after do + @client.close + @server.close + end + + platform_is_not :windows do + describe 'without a destination address' do + it "raises #{SocketSpecs.dest_addr_req_error}" do + lambda { @client.sendmsg('hello') }.should raise_error(SocketSpecs.dest_addr_req_error) + end + end + end + + describe 'with a destination address as a String' do + it 'returns the amount of sent bytes' do + @client.sendmsg('hello', 0, @server.getsockname).should == 5 + end + end + + describe 'with a destination address as an Addrinfo' do + it 'returns the amount of sent bytes' do + @client.sendmsg('hello', 0, @server.connect_address).should == 5 + end + end + end + + describe 'using a connected UDP socket' do + before do + @client = Socket.new(family, :DGRAM) + @server = Socket.new(family, :DGRAM) + + @server.bind(Socket.sockaddr_in(0, ip_address)) + end + + after do + @client.close + @server.close + end + + describe 'without a destination address argument' do + before do + @client.connect(@server.getsockname) + end + + it 'returns the amount of bytes written' do + @client.sendmsg('hello').should == 5 + end + end + + describe 'with a destination address argument' do + before do + @alt_server = Socket.new(family, :DGRAM) + + @alt_server.bind(Socket.sockaddr_in(0, ip_address)) + end + + after do + @alt_server.close + end + + it 'sends the message to the given address instead' do + @client.sendmsg('hello', 0, @alt_server.getsockname).should == 5 + + lambda { @server.recv(5) }.should block_caller + + @alt_server.recv(5).should == 'hello' + end + end + end + + platform_is_not :windows do # spurious + describe 'using a connected TCP socket' do + before do + @client = Socket.new(family, :STREAM) + @server = Socket.new(family, :STREAM) + + @server.bind(Socket.sockaddr_in(0, ip_address)) + @server.listen(1) + + @client.connect(@server.getsockname) + end + + after do + @client.close + @server.close + end + + it 'blocks when the underlying buffer is full' do + # Buffer sizes may differ per platform, so sadly this is the only + # reliable way of testing blocking behaviour. + lambda do + 10.times { @client.sendmsg('hello' * 1_000_000) } + end.should block_caller + end + end + end + end +end diff --git a/spec/ruby/library/socket/basicsocket/setsockopt_spec.rb b/spec/ruby/library/socket/basicsocket/setsockopt_spec.rb index 7d2a303699..cafcfc202a 100644 --- a/spec/ruby/library/socket/basicsocket/setsockopt_spec.rb +++ b/spec/ruby/library/socket/basicsocket/setsockopt_spec.rb @@ -1,4 +1,4 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' describe "BasicSocket#setsockopt" do @@ -211,3 +211,124 @@ describe "BasicSocket#setsockopt" do end end end + +describe 'BasicSocket#setsockopt' do + describe 'using a STREAM socket' do + before do + @socket = Socket.new(:INET, :STREAM) + end + + after do + @socket.close + end + + describe 'using separate arguments with Symbols' do + it 'raises TypeError when the first argument is nil' do + lambda { @socket.setsockopt(nil, :REUSEADDR, true) }.should raise_error(TypeError) + end + + it 'sets a boolean option' do + @socket.setsockopt(:SOCKET, :REUSEADDR, true).should == 0 + @socket.getsockopt(:SOCKET, :REUSEADDR).bool.should == true + end + + it 'sets an integer option' do + @socket.setsockopt(:IP, :TTL, 255).should == 0 + @socket.getsockopt(:IP, :TTL).int.should == 255 + end + + it 'sets an IPv6 boolean option' do + socket = Socket.new(:INET6, :STREAM) + begin + socket.setsockopt(:IPV6, :V6ONLY, true).should == 0 + socket.getsockopt(:IPV6, :V6ONLY).bool.should == true + ensure + socket.close + end + end + + platform_is_not :windows do + it 'raises Errno::EINVAL when setting an invalid option value' do + lambda { @socket.setsockopt(:SOCKET, :OOBINLINE, 'bla') }.should raise_error(Errno::EINVAL) + end + end + end + + describe 'using separate arguments with Symbols' do + it 'sets a boolean option' do + @socket.setsockopt('SOCKET', 'REUSEADDR', true).should == 0 + @socket.getsockopt(:SOCKET, :REUSEADDR).bool.should == true + end + + it 'sets an integer option' do + @socket.setsockopt('IP', 'TTL', 255).should == 0 + @socket.getsockopt(:IP, :TTL).int.should == 255 + end + end + + describe 'using separate arguments with constants' do + it 'sets a boolean option' do + @socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEADDR, true).should == 0 + @socket.getsockopt(:SOCKET, :REUSEADDR).bool.should == true + end + + it 'sets an integer option' do + @socket.setsockopt(Socket::IPPROTO_IP, Socket::IP_TTL, 255).should == 0 + @socket.getsockopt(:IP, :TTL).int.should == 255 + end + end + + describe 'using separate arguments with custom objects' do + it 'sets a boolean option' do + level = mock(:level) + name = mock(:name) + + level.stub!(:to_str).and_return('SOCKET') + name.stub!(:to_str).and_return('REUSEADDR') + + @socket.setsockopt(level, name, true).should == 0 + end + end + + describe 'using a Socket::Option as the first argument' do + it 'sets a boolean option' do + @socket.setsockopt(Socket::Option.bool(:INET, :SOCKET, :REUSEADDR, true)).should == 0 + @socket.getsockopt(:SOCKET, :REUSEADDR).bool.should == true + end + + it 'sets an integer option' do + @socket.setsockopt(Socket::Option.int(:INET, :IP, :TTL, 255)).should == 0 + @socket.getsockopt(:IP, :TTL).int.should == 255 + end + + it 'raises ArgumentError when passing 2 arguments' do + option = Socket::Option.bool(:INET, :SOCKET, :REUSEADDR, true) + lambda { @socket.setsockopt(option, :REUSEADDR) }.should raise_error(ArgumentError) + end + + it 'raises TypeError when passing 3 arguments' do + option = Socket::Option.bool(:INET, :SOCKET, :REUSEADDR, true) + lambda { @socket.setsockopt(option, :REUSEADDR, true) }.should raise_error(TypeError) + end + end + end + + with_feature :unix_socket do + describe 'using a UNIX socket' do + before do + @path = SocketSpecs.socket_path + @server = UNIXServer.new(@path) + end + + after do + @server.close + rm_r @path + end + + it 'sets a boolean option' do + @server.setsockopt(:SOCKET, :REUSEADDR, true) + @server.getsockopt(:SOCKET, :REUSEADDR).bool.should == true + end + end + end +end diff --git a/spec/ruby/library/socket/basicsocket/shutdown_spec.rb b/spec/ruby/library/socket/basicsocket/shutdown_spec.rb index 67b15908e5..40e2d77570 100644 --- a/spec/ruby/library/socket/basicsocket/shutdown_spec.rb +++ b/spec/ruby/library/socket/basicsocket/shutdown_spec.rb @@ -1,6 +1,155 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' -describe "Socket::BasicSocket#shutdown" do +platform_is_not :windows do # hangs + describe "Socket::BasicSocket#shutdown" do + SocketSpecs.each_ip_protocol do |family, ip_address| + before do + @server = Socket.new(family, :STREAM) + @client = Socket.new(family, :STREAM) + @server.bind(Socket.sockaddr_in(0, ip_address)) + @server.listen(1) + + @client.connect(@server.getsockname) + end + + after do + @client.close + @server.close + end + + describe 'using a Fixnum' do + it 'shuts down a socket for reading' do + @client.shutdown(Socket::SHUT_RD) + + @client.recv(1).should be_empty + end + + it 'shuts down a socket for writing' do + @client.shutdown(Socket::SHUT_WR) + + lambda { @client.write('hello') }.should raise_error(Errno::EPIPE) + end + + it 'shuts down a socket for reading and writing' do + @client.shutdown(Socket::SHUT_RDWR) + + @client.recv(1).should be_empty + + lambda { @client.write('hello') }.should raise_error(Errno::EPIPE) + end + + it 'raises ArgumentError when using an invalid option' do + lambda { @server.shutdown(666) }.should raise_error(ArgumentError) + end + end + + describe 'using a Symbol' do + it 'shuts down a socket for reading using :RD' do + @client.shutdown(:RD) + + @client.recv(1).should be_empty + end + + it 'shuts down a socket for reading using :SHUT_RD' do + @client.shutdown(:SHUT_RD) + + @client.recv(1).should be_empty + end + + it 'shuts down a socket for writing using :WR' do + @client.shutdown(:WR) + + lambda { @client.write('hello') }.should raise_error(Errno::EPIPE) + end + + it 'shuts down a socket for writing using :SHUT_WR' do + @client.shutdown(:SHUT_WR) + + lambda { @client.write('hello') }.should raise_error(Errno::EPIPE) + end + + it 'shuts down a socket for reading and writing' do + @client.shutdown(:RDWR) + + @client.recv(1).should be_empty + + lambda { @client.write('hello') }.should raise_error(Errno::EPIPE) + end + + it 'raises ArgumentError when using an invalid option' do + lambda { @server.shutdown(:Nope) }.should raise_error(SocketError) + end + end + + describe 'using a String' do + it 'shuts down a socket for reading using "RD"' do + @client.shutdown('RD') + + @client.recv(1).should be_empty + end + + it 'shuts down a socket for reading using "SHUT_RD"' do + @client.shutdown('SHUT_RD') + + @client.recv(1).should be_empty + end + + it 'shuts down a socket for writing using "WR"' do + @client.shutdown('WR') + + lambda { @client.write('hello') }.should raise_error(Errno::EPIPE) + end + + it 'shuts down a socket for writing using "SHUT_WR"' do + @client.shutdown('SHUT_WR') + + lambda { @client.write('hello') }.should raise_error(Errno::EPIPE) + end + + it 'raises ArgumentError when using an invalid option' do + lambda { @server.shutdown('Nope') }.should raise_error(SocketError) + end + end + + describe 'using an object that responds to #to_str' do + before do + @dummy = mock(:dummy) + end + + it 'shuts down a socket for reading using "RD"' do + @dummy.stub!(:to_str).and_return('RD') + + @client.shutdown(@dummy) + + @client.recv(1).should be_empty + end + + it 'shuts down a socket for reading using "SHUT_RD"' do + @dummy.stub!(:to_str).and_return('SHUT_RD') + + @client.shutdown(@dummy) + + @client.recv(1).should be_empty + end + + it 'shuts down a socket for reading and writing' do + @dummy.stub!(:to_str).and_return('RDWR') + + @client.shutdown(@dummy) + + @client.recv(1).should be_empty + + lambda { @client.write('hello') }.should raise_error(Errno::EPIPE) + end + end + + describe 'using an object that does not respond to #to_str' do + it 'raises TypeError' do + lambda { @server.shutdown(mock(:dummy)) }.should raise_error(TypeError) + end + end + end + end end diff --git a/spec/ruby/library/socket/constants/constants_spec.rb b/spec/ruby/library/socket/constants/constants_spec.rb index 7e87aff2ee..2d44636abd 100644 --- a/spec/ruby/library/socket/constants/constants_spec.rb +++ b/spec/ruby/library/socket/constants/constants_spec.rb @@ -1,6 +1,5 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' -include Socket::Constants describe "Socket::Constants" do it "defines socket types" do @@ -87,4 +86,17 @@ describe "Socket::Constants" do Socket::Constants.should have_constant(c) end end + + platform_is_not :windows do + it 'defines SCM options' do + Socket::Constants.should have_constant('SCM_CREDENTIALS') + end + + it 'defines error options' do + consts = ["EAI_ADDRFAMILY", "EAI_NODATA"] + consts.each do |c| + Socket::Constants.should have_constant(c) + end + end + end end diff --git a/spec/ruby/library/socket/fixtures/classes.rb b/spec/ruby/library/socket/fixtures/classes.rb index b8e5d2a38d..1098b04a5e 100644 --- a/spec/ruby/library/socket/fixtures/classes.rb +++ b/spec/ruby/library/socket/fixtures/classes.rb @@ -1,16 +1,16 @@ require 'socket' module SocketSpecs - # helper to get the hostname associated to 127.0.0.1 - def self.hostname + # helper to get the hostname associated to 127.0.0.1 or the given ip + def self.hostname(ip = "127.0.0.1") # Calculate each time, without caching, since the result might # depend on things like do_not_reverse_lookup mode, which is # changing from test to test - Socket.getaddrinfo("127.0.0.1", nil)[0][2] + Socket.getaddrinfo(ip, nil)[0][2] end - def self.hostnamev6 - Socket.getaddrinfo("::1", nil)[0][2] + def self.hostname_reverse_lookup(ip = "127.0.0.1") + Socket.getaddrinfo(ip, nil, 0, 0, 0, 0, true)[0][2] end def self.addr(which=:ipv4) @@ -47,6 +47,61 @@ module SocketSpecs File.delete(path) if File.exist?(path) end + def self.ipv6_available? + @ipv6_available ||= begin + server = TCPServer.new('::1', 0) + rescue Errno::EADDRNOTAVAIL + :no + else + server.close + :yes + end + @ipv6_available == :yes + end + + def self.each_ip_protocol + describe 'using IPv4' do + yield Socket::AF_INET, '127.0.0.1', 'AF_INET' + end + + guard -> { SocketSpecs.ipv6_available? } do + describe 'using IPv6' do + yield Socket::AF_INET6, '::1', 'AF_INET6' + end + end + end + + def self.loop_with_timeout(timeout = 5) + require 'timeout' + time = Time.now + + loop do + if Time.now - time >= timeout + raise TimeoutError, "Did not succeed within #{timeout} seconds" + end + + sleep 0.01 # necessary on OSX; don't know why + yield + end + end + + def self.wait_until_success(timeout = 5) + loop_with_timeout(timeout) do + begin + return yield + rescue + end + end + end + + def self.dest_addr_req_error + error = Errno::EDESTADDRREQ + platform_is :windows do + error = Errno::ENOTCONN + end + error + end + # TCPServer echo server accepting one connection class SpecTCPServer attr_reader :hostname, :port diff --git a/spec/ruby/library/socket/ipsocket/addr_spec.rb b/spec/ruby/library/socket/ipsocket/addr_spec.rb index 2e5ae51d15..07f4cb20c9 100644 --- a/spec/ruby/library/socket/ipsocket/addr_spec.rb +++ b/spec/ruby/library/socket/ipsocket/addr_spec.rb @@ -1,4 +1,4 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' describe "Socket::IPSocket#addr" do @@ -40,3 +40,66 @@ describe "Socket::IPSocket#addr" do addrinfo[3].should == "127.0.0.1" end end + +describe 'Socket::IPSocket#addr' do + SocketSpecs.each_ip_protocol do |family, ip_address, family_name| + before do + @server = TCPServer.new(ip_address, 0) + @port = @server.connect_address.ip_port + end + + after do + @server.close + end + + describe 'without reverse lookups' do + before do + @hostname = Socket.getaddrinfo(ip_address, nil)[0][2] + end + + it 'returns an Array containing address information' do + @server.addr.should == [family_name, @port, @hostname, ip_address] + end + end + + describe 'with reverse lookups' do + before do + @hostname = Socket.getaddrinfo(ip_address, nil, nil, 0, 0, 0, true)[0][2] + end + + describe 'using true as the argument' do + it 'returns an Array containing address information' do + @server.addr(true).should == [family_name, @port, @hostname, ip_address] + end + end + + describe 'using :hostname as the argument' do + it 'returns an Array containing address information' do + @server.addr(:hostname).should == [family_name, @port, @hostname, ip_address] + end + end + + describe 'using :cats as the argument' do + it 'raises ArgumentError' do + lambda { @server.addr(:cats) }.should raise_error(ArgumentError) + end + end + end + + describe 'with do_not_reverse_lookup disabled on socket level' do + before do + @server.do_not_reverse_lookup = false + + @hostname = Socket.getaddrinfo(ip_address, nil, nil, 0, 0, 0, true)[0][2] + end + + after do + @server.do_not_reverse_lookup = true + end + + it 'returns an Array containing address information' do + @server.addr.should == [family_name, @port, @hostname, ip_address] + end + end + end +end diff --git a/spec/ruby/library/socket/ipsocket/getaddress_spec.rb b/spec/ruby/library/socket/ipsocket/getaddress_spec.rb index 10161dbaea..2ee35af5b5 100644 --- a/spec/ruby/library/socket/ipsocket/getaddress_spec.rb +++ b/spec/ruby/library/socket/ipsocket/getaddress_spec.rb @@ -1,4 +1,4 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' describe "Socket::IPSocket#getaddress" do @@ -11,6 +11,7 @@ describe "Socket::IPSocket#getaddress" do it "returns the IP address when passed an IP" do IPSocket.getaddress("127.0.0.1").should == "127.0.0.1" IPSocket.getaddress("0.0.0.0").should == "0.0.0.0" + IPSocket.getaddress('::1').should == '::1' end # There is no way to make this fail-proof on all machines, because @@ -23,5 +24,4 @@ describe "Socket::IPSocket#getaddress" do }.should raise_error(SocketError) end end - end diff --git a/spec/ruby/library/socket/ipsocket/peeraddr_spec.rb b/spec/ruby/library/socket/ipsocket/peeraddr_spec.rb index bfbe0b2c12..26aa61d1c4 100644 --- a/spec/ruby/library/socket/ipsocket/peeraddr_spec.rb +++ b/spec/ruby/library/socket/ipsocket/peeraddr_spec.rb @@ -1,4 +1,4 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' describe "Socket::IPSocket#peeraddr" do @@ -49,3 +49,69 @@ describe "Socket::IPSocket#peeraddr" do addrinfo[3].should == "127.0.0.1" end end + +describe 'Socket::IPSocket#peeraddr' do + SocketSpecs.each_ip_protocol do |family, ip_address, family_name| + before do + @server = TCPServer.new(ip_address, 0) + @port = @server.connect_address.ip_port + @client = TCPSocket.new(ip_address, @port) + end + + after do + @client.close + @server.close + end + + describe 'without reverse lookups' do + before do + @hostname = Socket.getaddrinfo(ip_address, nil)[0][2] + end + + it 'returns an Array containing address information' do + @client.peeraddr.should == [family_name, @port, @hostname, ip_address] + end + end + + describe 'with reverse lookups' do + before do + @hostname = Socket.getaddrinfo(ip_address, nil, nil, 0, 0, 0, true)[0][2] + end + + describe 'using true as the argument' do + it 'returns an Array containing address information' do + @client.peeraddr(true).should == [family_name, @port, @hostname, ip_address] + end + end + + describe 'using :hostname as the argument' do + it 'returns an Array containing address information' do + @client.peeraddr(:hostname).should == [family_name, @port, @hostname, ip_address] + end + end + + describe 'using :cats as the argument' do + it 'raises ArgumentError' do + lambda { @client.peeraddr(:cats) }.should raise_error(ArgumentError) + end + end + end + + describe 'with do_not_reverse_lookup disabled on socket level' do + before do + @client.do_not_reverse_lookup = false + + @hostname = Socket.getaddrinfo(ip_address, nil, nil, 0, 0, 0, true)[0][2] + @port = @client.local_address.ip_port + end + + after do + @client.do_not_reverse_lookup = true + end + + it 'returns an Array containing address information' do + @client.addr.should == [family_name, @port, @hostname, ip_address] + end + end + end +end diff --git a/spec/ruby/library/socket/ipsocket/recvfrom_spec.rb b/spec/ruby/library/socket/ipsocket/recvfrom_spec.rb index b8537fbe47..3bcb7b8f02 100644 --- a/spec/ruby/library/socket/ipsocket/recvfrom_spec.rb +++ b/spec/ruby/library/socket/ipsocket/recvfrom_spec.rb @@ -1,8 +1,7 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' describe "Socket::IPSocket#recvfrom" do - before :each do @server = TCPServer.new("127.0.0.1", 0) @port = @server.addr[1] @@ -68,5 +67,57 @@ describe "Socket::IPSocket#recvfrom" do # This does not apply to every platform, dependant on recvfrom(2) # data.last.should == nil end +end + +describe 'Socket::IPSocket#recvfrom' do + SocketSpecs.each_ip_protocol do |family, ip_address, family_name| + before do + @server = UDPSocket.new(family) + @client = UDPSocket.new(family) + + @server.bind(ip_address, 0) + @client.connect(ip_address, @server.connect_address.ip_port) + + @hostname = Socket.getaddrinfo(ip_address, nil)[0][2] + end + + after do + @client.close + @server.close + end + + it 'returns an Array containing up to N bytes and address information' do + @client.write('hello') + + port = @client.local_address.ip_port + ret = @server.recvfrom(2) + + ret.should == ['he', [family_name, port, @hostname, ip_address]] + end + it 'allows specifying of flags when receiving data' do + @client.write('hello') + + @server.recvfrom(2, Socket::MSG_PEEK)[0].should == 'he' + + @server.recvfrom(2)[0].should == 'he' + end + + describe 'using reverse lookups' do + before do + @server.do_not_reverse_lookup = false + + @hostname = Socket.getaddrinfo(ip_address, nil, 0, 0, 0, 0, true)[0][2] + end + + it 'includes the hostname in the address Array' do + @client.write('hello') + + port = @client.local_address.ip_port + ret = @server.recvfrom(2) + + ret.should == ['he', [family_name, port, @hostname, ip_address]] + end + end + end end diff --git a/spec/ruby/library/socket/option/bool_spec.rb b/spec/ruby/library/socket/option/bool_spec.rb index 31be00fee3..c4f8a277ba 100644 --- a/spec/ruby/library/socket/option/bool_spec.rb +++ b/spec/ruby/library/socket/option/bool_spec.rb @@ -1,4 +1,4 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' describe "Socket::Option.bool" do @@ -18,8 +18,10 @@ describe "Socket::Option#bool" do Socket::Option.bool(:INET, :SOCKET, :KEEPALIVE, false).bool.should == false end - it "raises TypeError if option has not good size" do - so = Socket::Option.new(:UNSPEC, :SOCKET, :SO_LINGER, [0, 0].pack('i*')) - lambda { so.bool }.should raise_error(TypeError) + platform_is_not :windows do + it 'raises TypeError when called on a non boolean option' do + opt = Socket::Option.linger(1, 4) + lambda { opt.bool }.should raise_error(TypeError) + end end end diff --git a/spec/ruby/library/socket/option/initialize_spec.rb b/spec/ruby/library/socket/option/initialize_spec.rb new file mode 100644 index 0000000000..986cfa8ad4 --- /dev/null +++ b/spec/ruby/library/socket/option/initialize_spec.rb @@ -0,0 +1,83 @@ +require_relative '../spec_helper' + +describe 'Socket::Option#initialize' do + before do + @bool = [0].pack('i') + end + + describe 'using Fixnums' do + it 'returns a Socket::Option' do + opt = Socket::Option + .new(Socket::AF_INET, Socket::SOL_SOCKET, Socket::SO_KEEPALIVE, @bool) + + opt.should be_an_instance_of(Socket::Option) + + opt.family.should == Socket::AF_INET + opt.level.should == Socket::SOL_SOCKET + opt.optname.should == Socket::SO_KEEPALIVE + opt.data.should == @bool + end + end + + describe 'using Symbols' do + it 'returns a Socket::Option' do + opt = Socket::Option.new(:INET, :SOCKET, :KEEPALIVE, @bool) + + opt.should be_an_instance_of(Socket::Option) + + opt.family.should == Socket::AF_INET + opt.level.should == Socket::SOL_SOCKET + opt.optname.should == Socket::SO_KEEPALIVE + opt.data.should == @bool + end + + it 'raises when using an invalid address family' do + lambda { + Socket::Option.new(:INET2, :SOCKET, :KEEPALIVE, @bool) + }.should raise_error(SocketError) + end + + it 'raises when using an invalid level' do + lambda { + Socket::Option.new(:INET, :CATS, :KEEPALIVE, @bool) + }.should raise_error(SocketError) + end + + it 'raises when using an invalid option name' do + lambda { + Socket::Option.new(:INET, :SOCKET, :CATS, @bool) + }.should raise_error(SocketError) + end + end + + describe 'using Strings' do + it 'returns a Socket::Option' do + opt = Socket::Option.new('INET', 'SOCKET', 'KEEPALIVE', @bool) + + opt.should be_an_instance_of(Socket::Option) + + opt.family.should == Socket::AF_INET + opt.level.should == Socket::SOL_SOCKET + opt.optname.should == Socket::SO_KEEPALIVE + opt.data.should == @bool + end + + it 'raises when using an invalid address family' do + lambda { + Socket::Option.new('INET2', 'SOCKET', 'KEEPALIVE', @bool) + }.should raise_error(SocketError) + end + + it 'raises when using an invalid level' do + lambda { + Socket::Option.new('INET', 'CATS', 'KEEPALIVE', @bool) + }.should raise_error(SocketError) + end + + it 'raises when using an invalid option name' do + lambda { + Socket::Option.new('INET', 'SOCKET', 'CATS', @bool) + }.should raise_error(SocketError) + end + end +end diff --git a/spec/ruby/library/socket/option/inspect_spec.rb b/spec/ruby/library/socket/option/inspect_spec.rb index 2a03421710..ebea940d2f 100644 --- a/spec/ruby/library/socket/option/inspect_spec.rb +++ b/spec/ruby/library/socket/option/inspect_spec.rb @@ -1,7 +1,6 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' -require 'socket' describe 'Socket::Option#inspect' do it 'correctly returns SO_LINGER value' do diff --git a/spec/ruby/library/socket/option/int_spec.rb b/spec/ruby/library/socket/option/int_spec.rb index b270374f62..5c67ec26d8 100644 --- a/spec/ruby/library/socket/option/int_spec.rb +++ b/spec/ruby/library/socket/option/int_spec.rb @@ -1,4 +1,4 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' describe "Socket::Option.int" do @@ -10,6 +10,17 @@ describe "Socket::Option.int" do so.optname.should == Socket::Constants::SO_KEEPALIVE so.data.should == [5].pack('i') end + + it 'returns a Socket::Option' do + opt = Socket::Option.int(:INET, :IP, :TTL, 4) + + opt.should be_an_instance_of(Socket::Option) + + opt.family.should == Socket::AF_INET + opt.level.should == Socket::IPPROTO_IP + opt.optname.should == Socket::IP_TTL + opt.data.should == [4].pack('i') + end end describe "Socket::Option#int" do @@ -19,10 +30,14 @@ describe "Socket::Option#int" do so = Socket::Option.int(:INET, :SOCKET, :KEEPALIVE, 32765) so.int.should == 32765 + + Socket::Option.int(:INET, :IP, :TTL, 4).int.should == 4 end - it "raises TypeError if option has not good size" do - so = Socket::Option.new(:UNSPEC, :SOCKET, :SO_LINGER, [0, 0].pack('i*')) - lambda { so.int }.should raise_error(TypeError) + platform_is_not :windows do + it 'raises TypeError when called on a non integer option' do + opt = Socket::Option.linger(1, 4) + lambda { opt.int }.should raise_error(TypeError) + end end end diff --git a/spec/ruby/library/socket/option/linger_spec.rb b/spec/ruby/library/socket/option/linger_spec.rb index 2090c8a0e8..94467ebf71 100644 --- a/spec/ruby/library/socket/option/linger_spec.rb +++ b/spec/ruby/library/socket/option/linger_spec.rb @@ -1,4 +1,4 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' option_pack = 'i*' @@ -10,9 +10,11 @@ describe "Socket::Option.linger" do it "creates a new Socket::Option for SO_LINGER" do so = Socket::Option.linger(1, 10) so.should be_an_instance_of(Socket::Option) + so.family.should == Socket::Constants::AF_UNSPEC so.level.should == Socket::Constants::SOL_SOCKET so.optname.should == Socket::Constants::SO_LINGER + so.data.should == [1, 10].pack(option_pack) end @@ -53,10 +55,22 @@ describe "Socket::Option#linger" do lambda { so.linger }.should raise_error(TypeError) end + it 'raises TypeError when called on a non SOL_SOCKET/SO_LINGER option' do + opt = Socket::Option.int(:INET, :IP, :TTL, 4) + + lambda { opt.linger }.should raise_error(TypeError) + end + platform_is_not :windows do it "raises TypeError if option has not good size" do so = Socket::Option.int(:AF_UNSPEC, :SOL_SOCKET, :LINGER, 1) lambda { so.linger }.should raise_error(TypeError) end end + + it 'raises TypeError when called on a non linger option' do + opt = Socket::Option.new(:INET, :SOCKET, :LINGER, '') + + lambda { opt.linger }.should raise_error(TypeError) + end end diff --git a/spec/ruby/library/socket/option/new_spec.rb b/spec/ruby/library/socket/option/new_spec.rb index b2c76fb24d..f3b7b31c91 100644 --- a/spec/ruby/library/socket/option/new_spec.rb +++ b/spec/ruby/library/socket/option/new_spec.rb @@ -1,4 +1,4 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' describe "Socket::Option.new" do diff --git a/spec/ruby/library/socket/shared/pack_sockaddr.rb b/spec/ruby/library/socket/shared/pack_sockaddr.rb index 4ffa02a8d8..714becc488 100644 --- a/spec/ruby/library/socket/shared/pack_sockaddr.rb +++ b/spec/ruby/library/socket/shared/pack_sockaddr.rb @@ -18,10 +18,28 @@ describe :socket_pack_sockaddr_in, shared: true do sockaddr_in = Socket.public_send(@method, nil, '127.0.0.1') Socket.unpack_sockaddr_in(sockaddr_in).should == [0, '127.0.0.1'] end + + describe 'using an IPv4 address' do + it 'returns a String of 16 bytes' do + str = Socket.public_send(@method, 80, '127.0.0.1') + + str.should be_an_instance_of(String) + str.bytesize.should == 16 + end + end + + describe 'using an IPv6 address' do + it 'returns a String of 28 bytes' do + str = Socket.public_send(@method, 80, '::1') + + str.should be_an_instance_of(String) + str.bytesize.should == 28 + end + end end describe :socket_pack_sockaddr_un, shared: true do - platform_is_not :windows do + with_feature :unix_socket do it 'should be idempotent' do bytes = Socket.public_send(@method, '/tmp/foo').bytes bytes[2..9].should == [47, 116, 109, 112, 47, 102, 111, 111] @@ -40,10 +58,28 @@ describe :socket_pack_sockaddr_un, shared: true do end end + platform_is :linux do + it 'returns a String of 110 bytes' do + str = Socket.public_send(@method, '/tmp/test.sock') + + str.should be_an_instance_of(String) + str.bytesize.should == 110 + end + end + + platform_is :bsd do + it 'returns a String of 106 bytes' do + str = Socket.public_send(@method, '/tmp/test.sock') + + str.should be_an_instance_of(String) + str.bytesize.should == 106 + end + end + platform_is_not :windows, :aix do - it "raises if path length exceeds max size" do + it "raises ArgumentError for paths that are too long" do # AIX doesn't raise error - long_path = Array.new(512, 0).join + long_path = 'a' * 110 lambda { Socket.public_send(@method, long_path) }.should raise_error(ArgumentError) end end diff --git a/spec/ruby/library/socket/shared/recv_nonblock.rb b/spec/ruby/library/socket/shared/recv_nonblock.rb deleted file mode 100644 index 2b584d52a2..0000000000 --- a/spec/ruby/library/socket/shared/recv_nonblock.rb +++ /dev/null @@ -1,52 +0,0 @@ -describe :socket_recv_nonblock, shared: true do - before :each do - @s1 = Socket.new(Socket::AF_INET, Socket::SOCK_DGRAM, 0) - @s2 = Socket.new(Socket::AF_INET, Socket::SOCK_DGRAM, 0) - end - - after :each do - @s1.close unless @s1.closed? - @s2.close unless @s2.closed? - end - - it "raises an exception extending IO::WaitReadable if there's no data available" do - @s1.bind(Socket.pack_sockaddr_in(0, "127.0.0.1")) - lambda { - @s1.recv_nonblock(5) - }.should raise_error(IO::WaitReadable) { |e| - platform_is_not :windows do - e.should be_kind_of(Errno::EAGAIN) - end - platform_is :windows do - e.should be_kind_of(Errno::EWOULDBLOCK) - end - } - end - - it "receives data after it's ready" do - @s1.bind(Socket.pack_sockaddr_in(0, "127.0.0.1")) - @s2.send("aaa", 0, @s1.getsockname) - IO.select([@s1], nil, nil, 2) - @s1.recv_nonblock(5).should == "aaa" - end - - it "allows an output buffer as third argument" do - @s1.bind(Socket.pack_sockaddr_in(0, "127.0.0.1")) - @s2.send("data", 0, @s1.getsockname) - IO.select([@s1], nil, nil, 2) - - buf = "foo" - @s1.recv_nonblock(5, 0, buf) - buf.should == "data" - end - - it "does not block if there's no data available" do - @s1.bind(Socket.pack_sockaddr_in(0, "127.0.0.1")) - @s2.send("a", 0, @s1.getsockname) - IO.select([@s1], nil, nil, 2) - @s1.recv_nonblock(1).should == "a" - lambda { - @s1.recv_nonblock(5) - }.should raise_error(IO::WaitReadable) - end -end diff --git a/spec/ruby/library/socket/shared/socketpair.rb b/spec/ruby/library/socket/shared/socketpair.rb index 03ee0e1a52..1e08deccc2 100644 --- a/spec/ruby/library/socket/shared/socketpair.rb +++ b/spec/ruby/library/socket/shared/socketpair.rb @@ -19,5 +19,120 @@ describe :socket_socketpair, shared: true do s2.close end end + + describe 'using a Fixnum as the 1st and 2nd argument' do + it 'returns two Socket objects' do + s1, s2 = Socket.public_send(@method, Socket::AF_UNIX, Socket::SOCK_STREAM) + + s1.should be_an_instance_of(Socket) + s2.should be_an_instance_of(Socket) + s1.close + s2.close + end + end + + describe 'using a Symbol as the 1st and 2nd argument' do + it 'returns two Socket objects' do + s1, s2 = Socket.public_send(@method, :UNIX, :STREAM) + + s1.should be_an_instance_of(Socket) + s2.should be_an_instance_of(Socket) + s1.close + s2.close + end + + it 'raises SocketError for an unknown address family' do + lambda { Socket.public_send(@method, :CATS, :STREAM) }.should raise_error(SocketError) + end + + it 'raises SocketError for an unknown socket type' do + lambda { Socket.public_send(@method, :UNIX, :CATS) }.should raise_error(SocketError) + end + end + + describe 'using a String as the 1st and 2nd argument' do + it 'returns two Socket objects' do + s1, s2 = Socket.public_send(@method, 'UNIX', 'STREAM') + + s1.should be_an_instance_of(Socket) + s2.should be_an_instance_of(Socket) + s1.close + s2.close + end + + it 'raises SocketError for an unknown address family' do + lambda { Socket.public_send(@method, 'CATS', 'STREAM') }.should raise_error(SocketError) + end + + it 'raises SocketError for an unknown socket type' do + lambda { Socket.public_send(@method, 'UNIX', 'CATS') }.should raise_error(SocketError) + end + end + + describe 'using an object that responds to #to_str as the 1st and 2nd argument' do + it 'returns two Socket objects' do + family = mock(:family) + type = mock(:type) + + family.stub!(:to_str).and_return('UNIX') + type.stub!(:to_str).and_return('STREAM') + + s1, s2 = Socket.public_send(@method, family, type) + + s1.should be_an_instance_of(Socket) + s2.should be_an_instance_of(Socket) + s1.close + s2.close + end + + it 'raises TypeError when #to_str does not return a String' do + family = mock(:family) + type = mock(:type) + + family.stub!(:to_str).and_return(Socket::AF_UNIX) + type.stub!(:to_str).and_return(Socket::SOCK_STREAM) + + lambda { Socket.public_send(@method, family, type) }.should raise_error(TypeError) + end + + it 'raises SocketError for an unknown address family' do + family = mock(:family) + type = mock(:type) + + family.stub!(:to_str).and_return('CATS') + type.stub!(:to_str).and_return('STREAM') + + lambda { Socket.public_send(@method, family, type) }.should raise_error(SocketError) + end + + it 'raises SocketError for an unknown socket type' do + family = mock(:family) + type = mock(:type) + + family.stub!(:to_str).and_return('UNIX') + type.stub!(:to_str).and_return('CATS') + + lambda { Socket.public_send(@method, family, type) }.should raise_error(SocketError) + end + end + + it 'accepts a custom protocol as a Fixnum as the 3rd argument' do + s1, s2 = Socket.public_send(@method, :UNIX, :STREAM, Socket::IPPROTO_IP) + s1.should be_an_instance_of(Socket) + s2.should be_an_instance_of(Socket) + s1.close + s2.close + end + + it 'connects the returned Socket objects' do + s1, s2 = Socket.public_send(@method, :UNIX, :STREAM) + begin + s1.write('hello') + s2.recv(5).should == 'hello' + ensure + s1.close + s2.close + end + end end end diff --git a/spec/ruby/library/socket/socket/accept_loop_spec.rb b/spec/ruby/library/socket/socket/accept_loop_spec.rb new file mode 100644 index 0000000000..88bd1c556c --- /dev/null +++ b/spec/ruby/library/socket/socket/accept_loop_spec.rb @@ -0,0 +1,80 @@ +require_relative '../spec_helper' + +describe 'Socket.accept_loop' do + before do + @server = Socket.new(:INET, :STREAM) + @client = Socket.new(:INET, :STREAM) + + @server.bind(Socket.sockaddr_in(0, '127.0.0.1')) + @server.listen(1) + end + + after do + @client.close + @server.close + end + + describe 'using an Array of Sockets' do + describe 'without any available connections' do + it 'blocks the caller' do + lambda { Socket.accept_loop([@server]) }.should block_caller + end + end + + describe 'with available connections' do + before do + @client.connect(@server.getsockname) + end + + it 'yields a Socket and an Addrinfo' do + conn = nil + addr = nil + + Socket.accept_loop([@server]) do |connection, address| + conn = connection + addr = address + break + end + + begin + conn.should be_an_instance_of(Socket) + addr.should be_an_instance_of(Addrinfo) + ensure + conn.close + end + end + end + end + + describe 'using separate Socket arguments' do + describe 'without any available connections' do + it 'blocks the caller' do + lambda { Socket.accept_loop(@server) }.should block_caller + end + end + + describe 'with available connections' do + before do + @client.connect(@server.getsockname) + end + + it 'yields a Socket and an Addrinfo' do + conn = nil + addr = nil + + Socket.accept_loop(@server) do |connection, address| + conn = connection + addr = address + break + end + + begin + conn.should be_an_instance_of(Socket) + addr.should be_an_instance_of(Addrinfo) + ensure + conn.close + end + end + end + end +end diff --git a/spec/ruby/library/socket/socket/accept_nonblock_spec.rb b/spec/ruby/library/socket/socket/accept_nonblock_spec.rb index 44f3be9c0e..201d472f16 100644 --- a/spec/ruby/library/socket/socket/accept_nonblock_spec.rb +++ b/spec/ruby/library/socket/socket/accept_nonblock_spec.rb @@ -1,8 +1,6 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' -require 'socket' - describe "Socket#accept_nonblock" do before :each do @hostname = "127.0.0.1" @@ -33,3 +31,106 @@ describe "Socket#accept_nonblock" do @socket.accept_nonblock(exception: false).should == :wait_readable end end + +describe 'Socket#accept_nonblock' do + SocketSpecs.each_ip_protocol do |family, ip_address| + before do + @server = Socket.new(family, :STREAM, 0) + @sockaddr = Socket.sockaddr_in(0, ip_address) + end + + after do + @server.close unless @server.closed? + end + + describe 'using an unbound socket' do + it 'raises Errno::EINVAL' do + lambda { @server.accept_nonblock }.should raise_error(Errno::EINVAL) + end + end + + describe "using a bound socket that's not listening" do + before do + @server.bind(@sockaddr) + end + + it 'raises Errno::EINVAL' do + lambda { @server.accept_nonblock }.should raise_error(Errno::EINVAL) + end + end + + describe 'using a closed socket' do + it 'raises IOError' do + @server.close + + lambda { @server.accept_nonblock }.should raise_error(IOError) + end + end + + describe "using a bound socket that's listening" do + before do + @server.bind(@sockaddr) + @server.listen(1) + end + + describe 'without a connected client' do + it 'raises IO::WaitReadable' do + lambda { @server.accept_nonblock }.should raise_error(IO::WaitReadable) + end + end + + platform_is_not :windows do + describe 'with a connected client' do + before do + addr = Socket.sockaddr_in(@server.local_address.ip_port, ip_address) + @client = Socket.new(family, :STREAM, 0) + + @client.connect(addr) + end + + after do + @socket.close if @socket + @client.close + end + + it 'returns an Array containing a Socket and an Addrinfo' do + @socket, addrinfo = @server.accept_nonblock + + @socket.should be_an_instance_of(Socket) + addrinfo.should be_an_instance_of(Addrinfo) + end + + describe 'the returned Addrinfo' do + before do + @socket, @addr = @server.accept_nonblock + end + + it 'uses AF_INET as the address family' do + @addr.afamily.should == family + end + + it 'uses PF_INET as the protocol family' do + @addr.pfamily.should == family + end + + it 'uses SOCK_STREAM as the socket type' do + @addr.socktype.should == Socket::SOCK_STREAM + end + + it 'uses 0 as the protocol' do + @addr.protocol.should == 0 + end + + it 'uses the same IP address as the client Socket' do + @addr.ip_address.should == @client.local_address.ip_address + end + + it 'uses the same port as the client Socket' do + @addr.ip_port.should == @client.local_address.ip_port + end + end + end + end + end + end +end diff --git a/spec/ruby/library/socket/socket/accept_spec.rb b/spec/ruby/library/socket/socket/accept_spec.rb index 1658a2b81f..2c71d435ac 100644 --- a/spec/ruby/library/socket/socket/accept_spec.rb +++ b/spec/ruby/library/socket/socket/accept_spec.rb @@ -1,2 +1,122 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' + +describe 'Socket#accept' do + SocketSpecs.each_ip_protocol do |family, ip_address| + before do + @server = Socket.new(family, :STREAM, 0) + @sockaddr = Socket.sockaddr_in(0, ip_address) + end + + after do + @server.close unless @server.closed? + end + + platform_is_not :windows do # hangs + describe 'using an unbound socket' do + it 'raises Errno::EINVAL' do + lambda { @server.accept }.should raise_error(Errno::EINVAL) + end + end + + describe "using a bound socket that's not listening" do + before do + @server.bind(@sockaddr) + end + + it 'raises Errno::EINVAL' do + lambda { @server.accept }.should raise_error(Errno::EINVAL) + end + end + end + + describe 'using a closed socket' do + it 'raises IOError' do + @server.close + + lambda { @server.accept }.should raise_error(IOError) + end + end + + describe "using a bound socket that's listening" do + before do + @server.bind(@sockaddr) + @server.listen(1) + + server_ip = @server.local_address.ip_port + @server_addr = Socket.sockaddr_in(server_ip, ip_address) + end + + describe 'without a connected client' do + it 'blocks the caller until a connection is available' do + client = Socket.new(family, :STREAM, 0) + thread = Thread.new do + @server.accept + end + + client.connect(@server_addr) + + thread.join(5) + value = thread.value + begin + value.should be_an_instance_of(Array) + ensure + client.close + value[0].close + end + end + end + + describe 'with a connected client' do + before do + addr = Socket.sockaddr_in(@server.local_address.ip_port, ip_address) + @client = Socket.new(family, :STREAM, 0) + + @client.connect(addr) + end + + after do + @socket.close if @socket + @client.close + end + + it 'returns an Array containing a Socket and an Addrinfo' do + @socket, addrinfo = @server.accept + + @socket.should be_an_instance_of(Socket) + addrinfo.should be_an_instance_of(Addrinfo) + end + + describe 'the returned Addrinfo' do + before do + @socket, @addr = @server.accept + end + + it 'uses AF_INET as the address family' do + @addr.afamily.should == family + end + + it 'uses PF_INET as the protocol family' do + @addr.pfamily.should == family + end + + it 'uses SOCK_STREAM as the socket type' do + @addr.socktype.should == Socket::SOCK_STREAM + end + + it 'uses 0 as the protocol' do + @addr.protocol.should == 0 + end + + it 'uses the same IP address as the client Socket' do + @addr.ip_address.should == @client.local_address.ip_address + end + + it 'uses the same port as the client Socket' do + @addr.ip_port.should == @client.local_address.ip_port + end + end + end + end + end +end diff --git a/spec/ruby/library/socket/socket/bind_spec.rb b/spec/ruby/library/socket/socket/bind_spec.rb index 09dbd624b5..338b19bbfc 100644 --- a/spec/ruby/library/socket/socket/bind_spec.rb +++ b/spec/ruby/library/socket/socket/bind_spec.rb @@ -1,11 +1,9 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' -include Socket::Constants - describe "Socket#bind on SOCK_DGRAM socket" do before :each do - @sock = Socket.new(AF_INET, SOCK_DGRAM, 0) + @sock = Socket.new(Socket::AF_INET, Socket::SOCK_DGRAM, 0) @sockaddr = Socket.pack_sockaddr_in(0, "127.0.0.1") end @@ -45,8 +43,8 @@ end describe "Socket#bind on SOCK_STREAM socket" do before :each do - @sock = Socket.new(AF_INET, SOCK_STREAM, 0) - @sock.setsockopt(SOL_SOCKET, SO_REUSEADDR, true) + @sock = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0) + @sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEADDR, true) @sockaddr = Socket.pack_sockaddr_in(0, "127.0.0.1") end @@ -83,3 +81,64 @@ describe "Socket#bind on SOCK_STREAM socket" do end end end + +describe 'Socket#bind' do + SocketSpecs.each_ip_protocol do |family, ip_address| + describe 'using a packed socket address' do + before do + @socket = Socket.new(family, :DGRAM) + @sockaddr = Socket.sockaddr_in(0, ip_address) + end + + after do + @socket.close + end + + it 'returns 0 when successfully bound' do + @socket.bind(@sockaddr).should == 0 + end + + it 'raises Errno::EINVAL when binding to an already bound port' do + @socket.bind(@sockaddr) + + lambda { @socket.bind(@sockaddr) }.should raise_error(Errno::EINVAL) + end + + it 'raises Errno::EADDRNOTAVAIL when the specified sockaddr is not available' do + ip = family == Socket::AF_INET ? '4.3.2.1' : '::2' + sockaddr1 = Socket.sockaddr_in(0, ip) + + lambda { @socket.bind(sockaddr1) }.should raise_error(Errno::EADDRNOTAVAIL) + end + + platform_is_not :windows do + it 'raises Errno::EACCES when the user is not allowed to bind to the port' do + sockaddr1 = Socket.pack_sockaddr_in(1, ip_address) + + lambda { @socket.bind(sockaddr1); }.should raise_error(Errno::EACCES) + end + end + end + + describe 'using an Addrinfo' do + before do + @addr = Addrinfo.udp(ip_address, 0) + @socket = Socket.new(@addr.afamily, @addr.socktype) + end + + after do + @socket.close + end + + it 'binds to an Addrinfo' do + @socket.bind(@addr).should == 0 + @socket.local_address.should be_an_instance_of(Addrinfo) + end + + it 'uses a new Addrinfo for the local address' do + @socket.bind(@addr) + @socket.local_address.should_not == @addr + end + end + end +end diff --git a/spec/ruby/library/socket/socket/connect_nonblock_spec.rb b/spec/ruby/library/socket/socket/connect_nonblock_spec.rb index caac24401c..21ef2b4a94 100644 --- a/spec/ruby/library/socket/socket/connect_nonblock_spec.rb +++ b/spec/ruby/library/socket/socket/connect_nonblock_spec.rb @@ -1,8 +1,6 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' -require 'socket' - describe "Socket#connect_nonblock" do before :each do @hostname = "127.0.0.1" @@ -69,3 +67,55 @@ describe "Socket#connect_nonblock" do end end end + +describe 'Socket#connect_nonblock' do + SocketSpecs.each_ip_protocol do |family, ip_address| + describe 'using a DGRAM socket' do + before do + @server = Socket.new(family, :DGRAM) + @client = Socket.new(family, :DGRAM) + @sockaddr = Socket.sockaddr_in(0, ip_address) + + @server.bind(@sockaddr) + end + + after do + @client.close + @server.close + end + + it 'returns 0 when successfully connected using a String' do + @client.connect_nonblock(@server.getsockname).should == 0 + end + + it 'returns 0 when successfully connected using an Addrinfo' do + @client.connect_nonblock(@server.connect_address).should == 0 + end + + it 'raises TypeError when passed a Fixnum' do + lambda { @client.connect_nonblock(666) }.should raise_error(TypeError) + end + end + + describe 'using a STREAM socket' do + before do + @server = Socket.new(family, :STREAM) + @client = Socket.new(family, :STREAM) + @sockaddr = Socket.sockaddr_in(0, ip_address) + end + + after do + @client.close + @server.close + end + + it 'raises IO:EINPROGRESSWaitWritable when the connection would block' do + @server.bind(@sockaddr) + + lambda { + @client.connect_nonblock(@server.getsockname) + }.should raise_error(IO::EINPROGRESSWaitWritable) + end + end + end +end diff --git a/spec/ruby/library/socket/socket/connect_spec.rb b/spec/ruby/library/socket/socket/connect_spec.rb index 1658a2b81f..1e2982bfde 100644 --- a/spec/ruby/library/socket/socket/connect_spec.rb +++ b/spec/ruby/library/socket/socket/connect_spec.rb @@ -1,2 +1,48 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' + +describe 'Socket#connect' do + SocketSpecs.each_ip_protocol do |family, ip_address| + before do + @server = Socket.new(family, :STREAM) + @client = Socket.new(family, :STREAM) + + @server.bind(Socket.sockaddr_in(0, ip_address)) + end + + after do + @client.close + @server.close + end + + it 'returns 0 when connected successfully using a String' do + @server.listen(1) + + @client.connect(@server.getsockname).should == 0 + end + + it 'returns 0 when connected successfully using an Addrinfo' do + @server.listen(1) + + @client.connect(@server.connect_address).should == 0 + end + + it 'raises Errno::EISCONN when already connected' do + @server.listen(1) + + @client.connect(@server.getsockname).should == 0 + + lambda { + @client.connect(@server.getsockname) + }.should raise_error(Errno::EISCONN) + end + + it 'raises Errno::ECONNREFUSED or Errno::ETIMEDOUT when the connection failed' do + begin + @client.connect(@server.getsockname) + rescue => e + [Errno::ECONNREFUSED, Errno::ETIMEDOUT].include?(e.class).should == true + end + end + end +end diff --git a/spec/ruby/library/socket/socket/for_fd_spec.rb b/spec/ruby/library/socket/socket/for_fd_spec.rb index 6ea6d9cf83..e89228d436 100644 --- a/spec/ruby/library/socket/socket/for_fd_spec.rb +++ b/spec/ruby/library/socket/socket/for_fd_spec.rb @@ -1,6 +1,5 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' -require 'socket' describe "Socket.for_fd" do before :each do diff --git a/spec/ruby/library/socket/socket/getaddrinfo_spec.rb b/spec/ruby/library/socket/socket/getaddrinfo_spec.rb index 64183b38d0..bc6e9e8f9d 100644 --- a/spec/ruby/library/socket/socket/getaddrinfo_spec.rb +++ b/spec/ruby/library/socket/socket/getaddrinfo_spec.rb @@ -1,9 +1,7 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' -require 'socket' - -describe "Socket#getaddrinfo" do +describe "Socket.getaddrinfo" do before :each do @do_not_reverse_lookup = BasicSocket.do_not_reverse_lookup BasicSocket.do_not_reverse_lookup = true @@ -53,10 +51,10 @@ describe "Socket#getaddrinfo" do end end - # #getaddrinfo will return a INADDR_ANY address (0.0.0.0 - # or "::") if it's a passive socket. In the case of non-passive + # #getaddrinfo will return a INADDR_ANY address (0.0.0.0 or "::") + # if it's a passive socket. In the case of non-passive # sockets (AI_PASSIVE not set) it should return the loopback - # address (127.0.0.1 or "::1". + # address (127.0.0.1 or "::1"). it "accepts empty addresses for IPv4 passive sockets" do res = Socket.getaddrinfo(nil, "discard", @@ -110,3 +108,270 @@ describe "Socket#getaddrinfo" do end end end + +describe 'Socket.getaddrinfo' do + describe 'without global reverse lookups' do + it 'returns an Array' do + Socket.getaddrinfo(nil, 'http').should be_an_instance_of(Array) + end + + it 'accepts a Fixnum as the address family' do + array = Socket.getaddrinfo(nil, 'http', Socket::AF_INET)[0] + + array[0].should == 'AF_INET' + array[1].should == 80 + array[2].should == '127.0.0.1' + array[3].should == '127.0.0.1' + array[4].should == Socket::AF_INET + array[5].should be_an_instance_of(Fixnum) + array[6].should be_an_instance_of(Fixnum) + end + + it 'accepts a Fixnum as the address family using IPv6' do + array = Socket.getaddrinfo(nil, 'http', Socket::AF_INET6)[0] + + array[0].should == 'AF_INET6' + array[1].should == 80 + array[2].should == '::1' + array[3].should == '::1' + array[4].should == Socket::AF_INET6 + array[5].should be_an_instance_of(Fixnum) + array[6].should be_an_instance_of(Fixnum) + end + + it 'accepts a Symbol as the address family' do + array = Socket.getaddrinfo(nil, 'http', :INET)[0] + + array[0].should == 'AF_INET' + array[1].should == 80 + array[2].should == '127.0.0.1' + array[3].should == '127.0.0.1' + array[4].should == Socket::AF_INET + array[5].should be_an_instance_of(Fixnum) + array[6].should be_an_instance_of(Fixnum) + end + + it 'accepts a Symbol as the address family using IPv6' do + array = Socket.getaddrinfo(nil, 'http', :INET6)[0] + + array[0].should == 'AF_INET6' + array[1].should == 80 + array[2].should == '::1' + array[3].should == '::1' + array[4].should == Socket::AF_INET6 + array[5].should be_an_instance_of(Fixnum) + array[6].should be_an_instance_of(Fixnum) + end + + it 'accepts a String as the address family' do + array = Socket.getaddrinfo(nil, 'http', 'INET')[0] + + array[0].should == 'AF_INET' + array[1].should == 80 + array[2].should == '127.0.0.1' + array[3].should == '127.0.0.1' + array[4].should == Socket::AF_INET + array[5].should be_an_instance_of(Fixnum) + array[6].should be_an_instance_of(Fixnum) + end + + it 'accepts a String as the address family using IPv6' do + array = Socket.getaddrinfo(nil, 'http', 'INET6')[0] + + array[0].should == 'AF_INET6' + array[1].should == 80 + array[2].should == '::1' + array[3].should == '::1' + array[4].should == Socket::AF_INET6 + array[5].should be_an_instance_of(Fixnum) + array[6].should be_an_instance_of(Fixnum) + end + + it 'accepts an object responding to #to_str as the host' do + dummy = mock(:dummy) + + dummy.stub!(:to_str).and_return('127.0.0.1') + + array = Socket.getaddrinfo(dummy, 'http')[0] + + array[0].should == 'AF_INET' + array[1].should == 80 + array[2].should == '127.0.0.1' + array[3].should == '127.0.0.1' + array[4].should == Socket::AF_INET + array[5].should be_an_instance_of(Fixnum) + array[6].should be_an_instance_of(Fixnum) + end + + it 'accepts an object responding to #to_str as the address family' do + dummy = mock(:dummy) + + dummy.stub!(:to_str).and_return('INET') + + array = Socket.getaddrinfo(nil, 'http', dummy)[0] + + array[0].should == 'AF_INET' + array[1].should == 80 + array[2].should == '127.0.0.1' + array[3].should == '127.0.0.1' + array[4].should == Socket::AF_INET + array[5].should be_an_instance_of(Fixnum) + array[6].should be_an_instance_of(Fixnum) + end + + ipproto_tcp = Socket::IPPROTO_TCP + platform_is :windows do + ipproto_tcp = 0 + end + + it 'accepts a Fixnum as the socket type' do + Socket.getaddrinfo(nil, 'http', :INET, Socket::SOCK_STREAM)[0].should == [ + 'AF_INET', + 80, + '127.0.0.1', + '127.0.0.1', + Socket::AF_INET, + Socket::SOCK_STREAM, + ipproto_tcp + ] + end + + it 'accepts a Symbol as the socket type' do + Socket.getaddrinfo(nil, 'http', :INET, :STREAM)[0].should == [ + 'AF_INET', + 80, + '127.0.0.1', + '127.0.0.1', + Socket::AF_INET, + Socket::SOCK_STREAM, + ipproto_tcp + ] + end + + it 'accepts a String as the socket type' do + Socket.getaddrinfo(nil, 'http', :INET, 'STREAM')[0].should == [ + 'AF_INET', + 80, + '127.0.0.1', + '127.0.0.1', + Socket::AF_INET, + Socket::SOCK_STREAM, + ipproto_tcp + ] + end + + it 'accepts an object responding to #to_str as the socket type' do + dummy = mock(:dummy) + + dummy.stub!(:to_str).and_return('STREAM') + + Socket.getaddrinfo(nil, 'http', :INET, dummy)[0].should == [ + 'AF_INET', + 80, + '127.0.0.1', + '127.0.0.1', + Socket::AF_INET, + Socket::SOCK_STREAM, + ipproto_tcp + ] + end + + platform_is_not :windows do + it 'accepts a Fixnum as the protocol family' do + addr = Socket.getaddrinfo(nil, 'http', :INET, :DGRAM, Socket::IPPROTO_UDP) + + addr[0].should == [ + 'AF_INET', + 80, + '127.0.0.1', + '127.0.0.1', + Socket::AF_INET, + Socket::SOCK_DGRAM, + Socket::IPPROTO_UDP + ] + end + end + + it 'accepts a Fixnum as the flags' do + addr = Socket.getaddrinfo(nil, 'http', :INET, :STREAM, + Socket::IPPROTO_TCP, Socket::AI_PASSIVE) + + addr[0].should == [ + 'AF_INET', + 80, + '0.0.0.0', + '0.0.0.0', + Socket::AF_INET, + Socket::SOCK_STREAM, + Socket::IPPROTO_TCP + ] + end + + it 'performs a reverse lookup when the reverse_lookup argument is true' do + addr = Socket.getaddrinfo(nil, 'http', :INET, :STREAM, + Socket::IPPROTO_TCP, 0, true)[0] + + addr[0].should == 'AF_INET' + addr[1].should == 80 + + addr[2].should be_an_instance_of(String) + addr[2].should_not == addr[3] + + addr[3].should == '127.0.0.1' + end + + it 'performs a reverse lookup when the reverse_lookup argument is :hostname' do + addr = Socket.getaddrinfo(nil, 'http', :INET, :STREAM, + Socket::IPPROTO_TCP, 0, :hostname)[0] + + addr[0].should == 'AF_INET' + addr[1].should == 80 + + addr[2].should be_an_instance_of(String) + addr[2].should_not == addr[3] + + addr[3].should == '127.0.0.1' + end + + it 'performs a reverse lookup when the reverse_lookup argument is :numeric' do + addr = Socket.getaddrinfo(nil, 'http', :INET, :STREAM, + Socket::IPPROTO_TCP, 0, :numeric)[0] + + addr.should == [ + 'AF_INET', + 80, + '127.0.0.1', + '127.0.0.1', + Socket::AF_INET, + Socket::SOCK_STREAM, + Socket::IPPROTO_TCP + ] + end + end + + describe 'with global reverse lookups' do + before do + @do_not_reverse_lookup = BasicSocket.do_not_reverse_lookup + BasicSocket.do_not_reverse_lookup = false + end + + after do + BasicSocket.do_not_reverse_lookup = @do_not_reverse_lookup + end + + it 'returns an address honoring the global lookup option' do + addr = Socket.getaddrinfo(nil, 'http', :INET)[0] + + addr[0].should == 'AF_INET' + addr[1].should == 80 + + # We don't have control over this value and there's no way to test this + # without relying on Socket.getaddrinfo()'s own behaviour (meaning this + # test would faily any way of the method was not implemented correctly). + addr[2].should be_an_instance_of(String) + addr[2].should_not == addr[3] + + addr[3].should == '127.0.0.1' + end + end +end diff --git a/spec/ruby/library/socket/socket/gethostbyaddr_spec.rb b/spec/ruby/library/socket/socket/gethostbyaddr_spec.rb index 1658a2b81f..cad6ed2dd0 100644 --- a/spec/ruby/library/socket/socket/gethostbyaddr_spec.rb +++ b/spec/ruby/library/socket/socket/gethostbyaddr_spec.rb @@ -1,2 +1,121 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' +require 'ipaddr' + +describe 'Socket.gethostbyaddr' do + describe 'using an IPv4 address' do + before do + @addr = IPAddr.new('127.0.0.1').hton + end + + describe 'without an explicit address family' do + it 'returns an Array' do + Socket.gethostbyaddr(@addr).should be_an_instance_of(Array) + end + + describe 'the returned Array' do + before do + @array = Socket.gethostbyaddr(@addr) + end + + it 'includes the hostname as the first value' do + @array[0].should == SocketSpecs.hostname_reverse_lookup + end + + it 'includes the aliases as the 2nd value' do + @array[1].should be_an_instance_of(Array) + + @array[1].each do |val| + val.should be_an_instance_of(String) + end + end + + it 'includes the address type as the 3rd value' do + @array[2].should == Socket::AF_INET + end + + it 'includes all address strings as the remaining values' do + @array[3].should == @addr + + @array[4..-1].each do |val| + val.should be_an_instance_of(String) + end + end + end + end + + describe 'with an explicit address family' do + it 'returns an Array when using a Fixnum as the address family' do + Socket.gethostbyaddr(@addr, Socket::AF_INET).should be_an_instance_of(Array) + end + + it 'returns an Array when using a Symbol as the address family' do + Socket.gethostbyaddr(@addr, :INET).should be_an_instance_of(Array) + end + + it 'raises SocketError when the address is not supported by the family' do + lambda { Socket.gethostbyaddr(@addr, :INET6) }.should raise_error(SocketError) + end + end + end + + guard -> { SocketSpecs.ipv6_available? } do + describe 'using an IPv6 address' do + before do + @addr = IPAddr.new('::1').hton + end + + describe 'without an explicit address family' do + it 'returns an Array' do + Socket.gethostbyaddr(@addr).should be_an_instance_of(Array) + end + + describe 'the returned Array' do + before do + @array = Socket.gethostbyaddr(@addr) + end + + it 'includes the hostname as the first value' do + @array[0].should == SocketSpecs.hostname_reverse_lookup("::1") + end + + it 'includes the aliases as the 2nd value' do + @array[1].should be_an_instance_of(Array) + + @array[1].each do |val| + val.should be_an_instance_of(String) + end + end + + it 'includes the address type as the 3rd value' do + @array[2].should == Socket::AF_INET6 + end + + it 'includes all address strings as the remaining values' do + @array[3].should be_an_instance_of(String) + + @array[4..-1].each do |val| + val.should be_an_instance_of(String) + end + end + end + end + + describe 'with an explicit address family' do + it 'returns an Array when using a Fixnum as the address family' do + Socket.gethostbyaddr(@addr, Socket::AF_INET6).should be_an_instance_of(Array) + end + + it 'returns an Array when using a Symbol as the address family' do + Socket.gethostbyaddr(@addr, :INET6).should be_an_instance_of(Array) + end + + platform_is_not :windows do + it 'raises SocketError when the address is not supported by the family' do + lambda { Socket.gethostbyaddr(@addr, :INET) }.should raise_error(SocketError) + end + end + end + end + end +end diff --git a/spec/ruby/library/socket/socket/gethostbyname_spec.rb b/spec/ruby/library/socket/socket/gethostbyname_spec.rb index 23880bb42d..9367030e25 100644 --- a/spec/ruby/library/socket/socket/gethostbyname_spec.rb +++ b/spec/ruby/library/socket/socket/gethostbyname_spec.rb @@ -1,9 +1,7 @@ # -*- encoding: binary -*- -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' -require 'socket' - describe "Socket#gethostbyname" do it "returns broadcast address info for ''" do addr = Socket.gethostbyname(''); @@ -15,3 +13,123 @@ describe "Socket#gethostbyname" do addr.should == ["0.0.0.0", [], 2, "\000\000\000\000"] end end + +describe 'Socket.gethostbyname' do + it 'returns an Array' do + Socket.gethostbyname('127.0.0.1').should be_an_instance_of(Array) + end + + describe 'the returned Array' do + before do + @array = Socket.gethostbyname('127.0.0.1') + end + + it 'includes the hostname as the first value' do + @array[0].should == '127.0.0.1' + end + + it 'includes the aliases as the 2nd value' do + @array[1].should be_an_instance_of(Array) + + @array[1].each do |val| + val.should be_an_instance_of(String) + end + end + + it 'includes the address type as the 3rd value' do + possible = [Socket::AF_INET, Socket::AF_INET6] + + possible.include?(@array[2]).should == true + end + + it 'includes the address strings as the remaining values' do + @array[3].should be_an_instance_of(String) + + @array[4..-1].each do |val| + val.should be_an_instance_of(String) + end + end + end + + describe 'using as the input address' do + describe 'the returned Array' do + before do + @addr = Socket.gethostbyname('') + end + + it 'includes the broadcast address as the first value' do + @addr[0].should == '255.255.255.255' + end + + it 'includes the address type as the 3rd value' do + @addr[2].should == Socket::AF_INET + end + + it 'includes the address string as the 4th value' do + @addr[3].should == [255, 255, 255, 255].pack('C4') + end + end + end + + describe 'using as the input address' do + describe 'the returned Array' do + before do + @addr = Socket.gethostbyname('') + end + + it 'includes the wildcard address as the first value' do + @addr[0].should == '0.0.0.0' + end + + it 'includes the address type as the 3rd value' do + @addr[2].should == Socket::AF_INET + end + + it 'includes the address string as the 4th value' do + @addr[3].should == [0, 0, 0, 0].pack('C4') + end + end + end + + describe 'using an IPv4 address' do + describe 'the returned Array' do + before do + @addr = Socket.gethostbyname('127.0.0.1') + end + + it 'includes the IP address as the first value' do + @addr[0].should == '127.0.0.1' + end + + it 'includes the address type as the 3rd value' do + @addr[2].should == Socket::AF_INET + end + + it 'includes the address string as the 4th value' do + @addr[3].should == [127, 0, 0, 1].pack('C4') + end + end + end + + guard -> { SocketSpecs.ipv6_available? } do + describe 'using an IPv6 address' do + describe 'the returned Array' do + before do + @addr = Socket.gethostbyname('::1') + end + + it 'includes the IP address as the first value' do + @addr[0].should == '::1' + end + + it 'includes the address type as the 3rd value' do + @addr[2].should == Socket::AF_INET6 + end + + it 'includes the address string as the 4th value' do + @addr[3].should == [0, 0, 0, 0, 0, 0, 0, 1].pack('n8') + end + end + end + end +end diff --git a/spec/ruby/library/socket/socket/gethostname_spec.rb b/spec/ruby/library/socket/socket/gethostname_spec.rb index 7308d8294b..4b79747b27 100644 --- a/spec/ruby/library/socket/socket/gethostname_spec.rb +++ b/spec/ruby/library/socket/socket/gethostname_spec.rb @@ -1,4 +1,4 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' describe "Socket.gethostname" do diff --git a/spec/ruby/library/socket/socket/getifaddrs_spec.rb b/spec/ruby/library/socket/socket/getifaddrs_spec.rb new file mode 100644 index 0000000000..1a767c56ab --- /dev/null +++ b/spec/ruby/library/socket/socket/getifaddrs_spec.rb @@ -0,0 +1,108 @@ +require_relative '../spec_helper' + +describe 'Socket.getifaddrs' do + before do + @ifaddrs = Socket.getifaddrs + end + + it 'returns an Array' do + @ifaddrs.should be_an_instance_of(Array) + end + + describe 'the returned Array' do + it 'should not be empty' do + @ifaddrs.should_not be_empty + end + + it 'contains instances of Socket::Ifaddr' do + @ifaddrs.each do |ifaddr| + ifaddr.should be_an_instance_of(Socket::Ifaddr) + end + end + end + + describe 'each returned Socket::Ifaddr' do + it 'has an interface index' do + @ifaddrs.each do |ifaddr| + ifaddr.ifindex.should be_an_instance_of(Fixnum) + end + end + + it 'has an interface name' do + @ifaddrs.each do |ifaddr| + ifaddr.name.should be_an_instance_of(String) + end + end + + it 'has a set of flags' do + @ifaddrs.each do |ifaddr| + ifaddr.flags.should be_an_instance_of(Fixnum) + end + end + end + + describe 'the Socket::Ifaddr address' do + before do + @addrs = @ifaddrs.map(&:addr).compact + end + + it 'is an Addrinfo' do + @addrs.each do |addr| + addr.should be_an_instance_of(Addrinfo) + end + end + + it 'has an address family' do + @addrs.each do |addr| + addr.afamily.should be_an_instance_of(Fixnum) + addr.afamily.should_not == Socket::AF_UNSPEC + end + end + end + + platform_is_not :windows do + describe 'the Socket::Ifaddr broadcast address' do + before do + @addrs = @ifaddrs.map(&:broadaddr).compact + end + + it 'is an Addrinfo' do + @addrs.each do |addr| + addr.should be_an_instance_of(Addrinfo) + end + end + + it 'has an address family' do + @addrs.each do |addr| + addr.afamily.should be_an_instance_of(Fixnum) + addr.afamily.should_not == Socket::AF_UNSPEC + end + end + end + + describe 'the Socket::Ifaddr netmask address' do + before do + @addrs = @ifaddrs.map(&:netmask).compact + end + + it 'is an Addrinfo' do + @addrs.each do |addr| + addr.should be_an_instance_of(Addrinfo) + end + end + + it 'has an address family' do + @addrs.each do |addr| + addr.afamily.should be_an_instance_of(Fixnum) + addr.afamily.should_not == Socket::AF_UNSPEC + end + end + + it 'has an IP address' do + @addrs.each do |addr| + addr.ip_address.should be_an_instance_of(String) + end + end + end + end +end diff --git a/spec/ruby/library/socket/socket/getnameinfo_spec.rb b/spec/ruby/library/socket/socket/getnameinfo_spec.rb index da6d5a46e5..394a90cb47 100644 --- a/spec/ruby/library/socket/socket/getnameinfo_spec.rb +++ b/spec/ruby/library/socket/socket/getnameinfo_spec.rb @@ -1,8 +1,6 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' -require 'socket' - describe "Socket.getnameinfo" do before :each do @reverse_lookup = BasicSocket.do_not_reverse_lookup @@ -62,5 +60,95 @@ describe "Socket.getnameinfo" do name_info = Socket.getnameinfo ["AF_INET", 9, 'foo', '127.0.0.1'] name_info[1].should == 'discard' end +end + +describe 'Socket.getnameinfo' do + describe 'using a String as the first argument' do + before do + @addr = Socket.sockaddr_in(80, '127.0.0.1') + end + + it 'raises SocketError when using an invalid String' do + lambda { Socket.getnameinfo('cats') }.should raise_error(SocketError) + end + + describe 'without custom flags' do + it 'returns an Array containing the hostname and service name' do + Socket.getnameinfo(@addr).should == [SocketSpecs.hostname_reverse_lookup, 'http'] + end + end + + describe 'using NI_NUMERICHOST as the flag' do + it 'returns an Array containing the numeric hostname and service name' do + array = Socket.getnameinfo(@addr, Socket::NI_NUMERICHOST) + + %w{127.0.0.1 ::1}.include?(array[0]).should == true + + array[1].should == 'http' + end + end + end + + SocketSpecs.each_ip_protocol do |family, ip_address, family_name| + before do + @hostname = SocketSpecs.hostname_reverse_lookup(ip_address) + end + describe 'using a 3 element Array as the first argument' do + before do + @addr = [family_name, 80, @hostname] + end + + it 'raises ArgumentError when using an invalid Array' do + lambda { Socket.getnameinfo([family_name]) }.should raise_error(ArgumentError) + end + + describe 'without custom flags' do + it 'returns an Array containing the hostname and service name' do + array = Socket.getnameinfo(@addr) + array.should be_an_instance_of(Array) + array[0].should include(@hostname) + array[1].should == 'http' + end + end + + platform_is_not :windows do + describe 'using NI_NUMERICHOST as the flag' do + it 'returns an Array containing the numeric hostname and service name' do + Socket.getnameinfo(@addr, Socket::NI_NUMERICHOST).should == [ip_address, 'http'] + end + end + end + end + + describe 'using a 4 element Array as the first argument' do + before do + @addr = [family_name, 80, ip_address, ip_address] + end + + describe 'without custom flags' do + it 'returns an Array containing the hostname and service name' do + array = Socket.getnameinfo(@addr) + array.should be_an_instance_of(Array) + array[0].should == @hostname + array[1].should == 'http' + end + + it 'uses the 3rd value as the hostname if the 4th is not present' do + addr = [family_name, 80, ip_address, nil] + + array = Socket.getnameinfo(addr) + array.should be_an_instance_of(Array) + array[0].should == @hostname + array[1].should == 'http' + end + end + + describe 'using NI_NUMERICHOST as the flag' do + it 'returns an Array containing the numeric hostname and service name' do + Socket.getnameinfo(@addr, Socket::NI_NUMERICHOST).should == [ip_address, 'http'] + end + end + end + end end diff --git a/spec/ruby/library/socket/socket/getservbyname_spec.rb b/spec/ruby/library/socket/socket/getservbyname_spec.rb index dd05de90b6..d80e948a1b 100644 --- a/spec/ruby/library/socket/socket/getservbyname_spec.rb +++ b/spec/ruby/library/socket/socket/getservbyname_spec.rb @@ -1,4 +1,4 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' describe "Socket#getservbyname" do @@ -10,6 +10,14 @@ describe "Socket#getservbyname" do Socket.getservbyname('discard', 'tcp').should == 9 end + it 'returns the port for service "http"' do + Socket.getservbyname('http').should == 80 + end + + it 'returns the port for service "http" with protocol "tcp"' do + Socket.getservbyname('http', 'tcp').should == 80 + end + it "returns the port for service 'domain' with protocol 'udp'" do Socket.getservbyname('domain', 'udp').should == 53 end diff --git a/spec/ruby/library/socket/socket/getservbyport_spec.rb b/spec/ruby/library/socket/socket/getservbyport_spec.rb new file mode 100644 index 0000000000..9be2ac527e --- /dev/null +++ b/spec/ruby/library/socket/socket/getservbyport_spec.rb @@ -0,0 +1,23 @@ +require_relative '../spec_helper' + +describe 'Socket.getservbyport' do + platform_is_not :windows do + it 'returns the service name as a String' do + Socket.getservbyport(514).should == 'shell' + end + end + + platform_is :windows do + it 'returns the service name as a String' do + Socket.getservbyport(514).should == 'cmd' + end + end + + it 'returns the service name when using a custom protocol name' do + Socket.getservbyport(514, 'udp').should == 'syslog' + end + + it 'raises SocketError for an unknown port number' do + lambda { Socket.getservbyport(0) }.should raise_error(SocketError) + end +end diff --git a/spec/ruby/library/socket/socket/initialize_spec.rb b/spec/ruby/library/socket/socket/initialize_spec.rb new file mode 100644 index 0000000000..375eabfbcb --- /dev/null +++ b/spec/ruby/library/socket/socket/initialize_spec.rb @@ -0,0 +1,87 @@ +require_relative '../spec_helper' + +describe 'Socket#initialize' do + before do + @socket = nil + end + + after do + @socket.close if @socket + end + + describe 'using a Fixnum as the 1st and 2nd arguments' do + it 'returns a Socket' do + @socket = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM) + + @socket.should be_an_instance_of(Socket) + end + end + + describe 'using Symbols as the 1st and 2nd arguments' do + it 'returns a Socket' do + @socket = Socket.new(:INET, :STREAM) + + @socket.should be_an_instance_of(Socket) + end + end + + describe 'using Strings as the 1st and 2nd arguments' do + it 'returns a Socket' do + @socket = Socket.new('INET', 'STREAM') + + @socket.should be_an_instance_of(Socket) + end + end + + describe 'using objects that respond to #to_str' do + it 'returns a Socket' do + family = mock(:family) + type = mock(:type) + + family.stub!(:to_str).and_return('AF_INET') + type.stub!(:to_str).and_return('STREAM') + + @socket = Socket.new(family, type) + + @socket.should be_an_instance_of(Socket) + end + + it 'raises TypeError when the #to_str method does not return a String' do + family = mock(:family) + type = mock(:type) + + family.stub!(:to_str).and_return(Socket::AF_INET) + type.stub!(:to_str).and_return(Socket::SOCK_STREAM) + + lambda { Socket.new(family, type) }.should raise_error(TypeError) + end + end + + describe 'using a custom protocol' do + it 'returns a Socket when using a Fixnum' do + @socket = Socket.new(:INET, :STREAM, Socket::IPPROTO_TCP) + + @socket.should be_an_instance_of(Socket) + end + + it 'raises TypeError when using a Symbol' do + lambda { Socket.new(:INET, :STREAM, :TCP) }.should raise_error(TypeError) + end + end + + it 'sets the do_not_reverse_lookup option' do + @socket = Socket.new(:INET, :STREAM) + + @socket.do_not_reverse_lookup.should == Socket.do_not_reverse_lookup + end + + it "sets basic IO accessors" do + @socket = Socket.new(:INET, :STREAM) + @socket.lineno.should == 0 + end + + it "sets the socket to binary mode" do + @socket = Socket.new(:INET, :STREAM) + @socket.binmode?.should be_true + end +end diff --git a/spec/ruby/library/socket/socket/ip_address_list_spec.rb b/spec/ruby/library/socket/socket/ip_address_list_spec.rb new file mode 100644 index 0000000000..f97c2d7f85 --- /dev/null +++ b/spec/ruby/library/socket/socket/ip_address_list_spec.rb @@ -0,0 +1,50 @@ +require_relative '../spec_helper' + +describe 'Socket.ip_address_list' do + it 'returns an Array' do + Socket.ip_address_list.should be_an_instance_of(Array) + end + + describe 'the returned Array' do + before do + @array = Socket.ip_address_list + end + + it 'is not empty' do + @array.should_not be_empty + end + + it 'contains Addrinfo objects' do + @array.each do |klass| + klass.should be_an_instance_of(Addrinfo) + end + end + end + + describe 'each returned Addrinfo' do + before do + @array = Socket.ip_address_list + end + + it 'has a non-empty IP address' do + @array.each do |addr| + addr.ip_address.should be_an_instance_of(String) + addr.ip_address.should_not be_empty + end + end + + it 'has an address family' do + families = [Socket::AF_INET, Socket::AF_INET6] + + @array.each do |addr| + families.include?(addr.afamily).should == true + end + end + + it 'uses 0 as the port number' do + @array.each do |addr| + addr.ip_port.should == 0 + end + end + end +end diff --git a/spec/ruby/library/socket/socket/ipv6only_bang_spec.rb b/spec/ruby/library/socket/socket/ipv6only_bang_spec.rb new file mode 100644 index 0000000000..73f3ce1642 --- /dev/null +++ b/spec/ruby/library/socket/socket/ipv6only_bang_spec.rb @@ -0,0 +1,17 @@ +require_relative '../spec_helper' + +describe 'Socket#ipv6only!' do + before do + @socket = Socket.new(:INET6, :DGRAM) + end + + after do + @socket.close + end + + it 'enables IPv6 only mode' do + @socket.ipv6only! + + @socket.getsockopt(:IPV6, :V6ONLY).bool.should == true + end +end diff --git a/spec/ruby/library/socket/socket/listen_spec.rb b/spec/ruby/library/socket/socket/listen_spec.rb index 3ef503ec2e..326307f942 100644 --- a/spec/ruby/library/socket/socket/listen_spec.rb +++ b/spec/ruby/library/socket/socket/listen_spec.rb @@ -1,11 +1,9 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' -include Socket::Constants - describe "Socket#listen" do before :each do - @socket = Socket.new(AF_INET, SOCK_STREAM, 0) + @socket = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0) end after :each do @@ -20,3 +18,47 @@ describe "Socket#listen" do @socket.listen(1).should == 0 end end + +describe 'Socket#listen' do + SocketSpecs.each_ip_protocol do |family, ip_address| + describe 'using a DGRAM socket' do + before do + @server = Socket.new(family, :DGRAM) + @client = Socket.new(family, :DGRAM) + + @server.bind(Socket.sockaddr_in(0, ip_address)) + end + + after do + @client.close + @server.close + end + + it 'raises Errno::EOPNOTSUPP' do + lambda { @server.listen(1) }.should raise_error(Errno::EOPNOTSUPP) + end + end + + describe 'using a STREAM socket' do + before do + @server = Socket.new(family, :STREAM) + @client = Socket.new(family, :STREAM) + + @server.bind(Socket.sockaddr_in(0, ip_address)) + end + + after do + @client.close + @server.close + end + + it 'returns 0' do + @server.listen(1).should == 0 + end + + it "raises when the given argument can't be coerced to a Fixnum" do + lambda { @server.listen('cats') }.should raise_error(TypeError) + end + end + end +end diff --git a/spec/ruby/library/socket/socket/local_address_spec.rb b/spec/ruby/library/socket/socket/local_address_spec.rb new file mode 100644 index 0000000000..3687f93a0c --- /dev/null +++ b/spec/ruby/library/socket/socket/local_address_spec.rb @@ -0,0 +1,43 @@ +require_relative '../spec_helper' + +describe 'Socket#local_address' do + before do + @sock = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, Socket::IPPROTO_TCP) + end + + after do + @sock.close + end + + it 'returns an Addrinfo' do + @sock.local_address.should be_an_instance_of(Addrinfo) + end + + describe 'the returned Addrinfo' do + it 'uses AF_INET as the address family' do + @sock.local_address.afamily.should == Socket::AF_INET + end + + it 'uses PF_INET as the protocol family' do + @sock.local_address.pfamily.should == Socket::PF_INET + end + + it 'uses SOCK_STREAM as the socket type' do + @sock.local_address.socktype.should == Socket::SOCK_STREAM + end + + it 'uses 0.0.0.0 as the IP address' do + @sock.local_address.ip_address.should == '0.0.0.0' + end + + platform_is_not :windows do + it 'uses 0 as the port' do + @sock.local_address.ip_port.should == 0 + end + end + + it 'uses 0 as the protocol' do + @sock.local_address.protocol.should == 0 + end + end +end diff --git a/spec/ruby/library/socket/socket/new_spec.rb b/spec/ruby/library/socket/socket/new_spec.rb index 1658a2b81f..b2ec607f6a 100644 --- a/spec/ruby/library/socket/socket/new_spec.rb +++ b/spec/ruby/library/socket/socket/new_spec.rb @@ -1,2 +1,2 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' diff --git a/spec/ruby/library/socket/socket/pack_sockaddr_in_spec.rb b/spec/ruby/library/socket/socket/pack_sockaddr_in_spec.rb index a8f1f924d8..63d4724453 100644 --- a/spec/ruby/library/socket/socket/pack_sockaddr_in_spec.rb +++ b/spec/ruby/library/socket/socket/pack_sockaddr_in_spec.rb @@ -1,4 +1,4 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' require_relative '../shared/pack_sockaddr' diff --git a/spec/ruby/library/socket/socket/pack_sockaddr_un_spec.rb b/spec/ruby/library/socket/socket/pack_sockaddr_un_spec.rb index 16a286cf6a..1ee0bc6157 100644 --- a/spec/ruby/library/socket/socket/pack_sockaddr_un_spec.rb +++ b/spec/ruby/library/socket/socket/pack_sockaddr_un_spec.rb @@ -1,4 +1,4 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' require_relative '../shared/pack_sockaddr' diff --git a/spec/ruby/library/socket/socket/pair_spec.rb b/spec/ruby/library/socket/socket/pair_spec.rb index db11e5d92b..292eacd38d 100644 --- a/spec/ruby/library/socket/socket/pair_spec.rb +++ b/spec/ruby/library/socket/socket/pair_spec.rb @@ -1,4 +1,4 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' require_relative '../shared/socketpair' diff --git a/spec/ruby/library/socket/socket/recvfrom_nonblock_spec.rb b/spec/ruby/library/socket/socket/recvfrom_nonblock_spec.rb index 1658a2b81f..76a07e3bfb 100644 --- a/spec/ruby/library/socket/socket/recvfrom_nonblock_spec.rb +++ b/spec/ruby/library/socket/socket/recvfrom_nonblock_spec.rb @@ -1,2 +1,110 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' + +describe 'Socket#recvfrom_nonblock' do + SocketSpecs.each_ip_protocol do |family, ip_address| + before do + @server = Socket.new(family, :DGRAM) + @client = Socket.new(family, :DGRAM) + end + + after do + @client.close + @server.close + end + + platform_is_not :windows do + describe 'using an unbound socket' do + it 'raises IO::WaitReadable' do + lambda { @server.recvfrom_nonblock(1) }.should raise_error(IO::WaitReadable) + end + end + end + + describe 'using a bound socket' do + before do + @server.bind(Socket.sockaddr_in(0, ip_address)) + @client.connect(@server.getsockname) + end + + describe 'without any data available' do + it 'raises IO::WaitReadable' do + lambda { @server.recvfrom_nonblock(1) }.should raise_error(IO::WaitReadable) + end + end + + describe 'with data available' do + before do + @client.write('hello') + end + + platform_is_not :windows do + it 'returns an Array containing the data and an Addrinfo' do + ret = @server.recvfrom_nonblock(1) + + ret.should be_an_instance_of(Array) + ret.length.should == 2 + end + end + + describe 'the returned data' do + it 'is the same as the sent data' do + 5.times do + @client.write('hello') + + msg, _ = @server.recvfrom_nonblock(5) + + msg.should == 'hello' + end + end + end + + platform_is_not :windows do + describe 'the returned Array' do + before do + @array = @server.recvfrom_nonblock(1) + end + + it 'contains the data at index 0' do + @array[0].should == 'h' + end + + it 'contains an Addrinfo at index 1' do + @array[1].should be_an_instance_of(Addrinfo) + end + end + + describe 'the returned Addrinfo' do + before do + @addr = @server.recvfrom_nonblock(1)[1] + end + + it 'uses AF_INET as the address family' do + @addr.afamily.should == family + end + + it 'uses SOCK_DGRAM as the socket type' do + @addr.socktype.should == Socket::SOCK_DGRAM + end + + it 'uses PF_INET as the protocol family' do + @addr.pfamily.should == family + end + + it 'uses 0 as the protocol' do + @addr.protocol.should == 0 + end + + it 'uses the IP address of the client' do + @addr.ip_address.should == ip_address + end + + it 'uses the port of the client' do + @addr.ip_port.should == @client.local_address.ip_port + end + end + end + end + end + end +end diff --git a/spec/ruby/library/socket/socket/recvfrom_spec.rb b/spec/ruby/library/socket/socket/recvfrom_spec.rb index 1658a2b81f..7f0714511c 100644 --- a/spec/ruby/library/socket/socket/recvfrom_spec.rb +++ b/spec/ruby/library/socket/socket/recvfrom_spec.rb @@ -1,2 +1,92 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' + +describe 'Socket#recvfrom' do + SocketSpecs.each_ip_protocol do |family, ip_address| + before do + @server = Socket.new(family, :DGRAM) + @client = Socket.new(family, :DGRAM) + end + + after do + @client.close + @server.close + end + + describe 'using an unbound socket' do + it 'blocks the caller' do + lambda { @server.recvfrom(1) }.should block_caller + end + end + + describe 'using a bound socket' do + before do + @server.bind(Socket.sockaddr_in(0, ip_address)) + @client.connect(@server.getsockname) + end + + describe 'without any data available' do + it 'blocks the caller' do + lambda { @server.recvfrom(1) }.should block_caller + end + end + + describe 'with data available' do + before do + @client.write('hello') + end + + it 'returns an Array containing the data and an Addrinfo' do + ret = @server.recvfrom(1) + + ret.should be_an_instance_of(Array) + ret.length.should == 2 + end + + describe 'the returned Array' do + before do + @array = @server.recvfrom(1) + end + + it 'contains the data at index 0' do + @array[0].should == 'h' + end + + it 'contains an Addrinfo at index 1' do + @array[1].should be_an_instance_of(Addrinfo) + end + end + + describe 'the returned Addrinfo' do + before do + @addr = @server.recvfrom(1)[1] + end + + it 'uses AF_INET as the address family' do + @addr.afamily.should == family + end + + it 'uses SOCK_DGRAM as the socket type' do + @addr.socktype.should == Socket::SOCK_DGRAM + end + + it 'uses PF_INET as the protocol family' do + @addr.pfamily.should == family + end + + it 'uses 0 as the protocol' do + @addr.protocol.should == 0 + end + + it 'uses the IP address of the client' do + @addr.ip_address.should == ip_address + end + + it 'uses the port of the client' do + @addr.ip_port.should == @client.local_address.ip_port + end + end + end + end + end +end diff --git a/spec/ruby/library/socket/socket/remote_address_spec.rb b/spec/ruby/library/socket/socket/remote_address_spec.rb new file mode 100644 index 0000000000..24d60d7f58 --- /dev/null +++ b/spec/ruby/library/socket/socket/remote_address_spec.rb @@ -0,0 +1,54 @@ +require_relative '../spec_helper' +require_relative '../fixtures/classes' + +describe 'Socket#remote_address' do + SocketSpecs.each_ip_protocol do |family, ip_address| + before do + @server = Socket.new(family, :STREAM) + + @server.bind(Socket.sockaddr_in(0, ip_address)) + @server.listen(1) + + @host = @server.local_address.ip_address + @port = @server.local_address.ip_port + @client = Socket.new(family, :STREAM, Socket::IPPROTO_TCP) + + @client.connect(Socket.sockaddr_in(@port, @host)) + end + + after do + @client.close + @server.close + end + + it 'returns an Addrinfo' do + @client.remote_address.should be_an_instance_of(Addrinfo) + end + + describe 'the returned Addrinfo' do + it 'uses AF_INET as the address family' do + @client.remote_address.afamily.should == family + end + + it 'uses PF_INET as the protocol family' do + @client.remote_address.pfamily.should == family + end + + it 'uses SOCK_STREAM as the socket type' do + @client.remote_address.socktype.should == Socket::SOCK_STREAM + end + + it 'uses the correct IP address' do + @client.remote_address.ip_address.should == @host + end + + it 'uses the correct port' do + @client.remote_address.ip_port.should == @port + end + + it 'uses 0 as the protocol' do + @client.remote_address.protocol.should == 0 + end + end + end +end diff --git a/spec/ruby/library/socket/socket/sockaddr_in_spec.rb b/spec/ruby/library/socket/socket/sockaddr_in_spec.rb index 64645f179d..8ee956ac26 100644 --- a/spec/ruby/library/socket/socket/sockaddr_in_spec.rb +++ b/spec/ruby/library/socket/socket/sockaddr_in_spec.rb @@ -1,4 +1,4 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' require_relative '../shared/pack_sockaddr' diff --git a/spec/ruby/library/socket/socket/sockaddr_un_spec.rb b/spec/ruby/library/socket/socket/sockaddr_un_spec.rb index b8f148ca13..8922ff4d6d 100644 --- a/spec/ruby/library/socket/socket/sockaddr_un_spec.rb +++ b/spec/ruby/library/socket/socket/sockaddr_un_spec.rb @@ -1,4 +1,4 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' require_relative '../shared/pack_sockaddr' diff --git a/spec/ruby/library/socket/socket/socket_spec.rb b/spec/ruby/library/socket/socket/socket_spec.rb index ee003f84ec..5a3d6733e0 100644 --- a/spec/ruby/library/socket/socket/socket_spec.rb +++ b/spec/ruby/library/socket/socket/socket_spec.rb @@ -1,4 +1,4 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' describe "Socket" do diff --git a/spec/ruby/library/socket/socket/socketpair_spec.rb b/spec/ruby/library/socket/socket/socketpair_spec.rb index 495585e8dc..5b8311124e 100644 --- a/spec/ruby/library/socket/socket/socketpair_spec.rb +++ b/spec/ruby/library/socket/socket/socketpair_spec.rb @@ -1,4 +1,4 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' require_relative '../shared/socketpair' diff --git a/spec/ruby/library/socket/socket/sysaccept_spec.rb b/spec/ruby/library/socket/socket/sysaccept_spec.rb index 1658a2b81f..17b1a8a2f0 100644 --- a/spec/ruby/library/socket/socket/sysaccept_spec.rb +++ b/spec/ruby/library/socket/socket/sysaccept_spec.rb @@ -1,2 +1,93 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' + +describe 'Socket#sysaccept' do + SocketSpecs.each_ip_protocol do |family, ip_address| + before do + @server = Socket.new(family, :STREAM) + @sockaddr = Socket.sockaddr_in(0, ip_address) + end + + after do + @server.close + end + + platform_is_not :windows do # hangs + describe 'using an unbound socket' do + it 'raises Errno::EINVAL' do + lambda { @server.sysaccept }.should raise_error(Errno::EINVAL) + end + end + + describe "using a bound socket that's not listening" do + before do + @server.bind(@sockaddr) + end + + it 'raises Errno::EINVAL' do + lambda { @server.sysaccept }.should raise_error(Errno::EINVAL) + end + end + end + + describe "using a bound socket that's listening" do + before do + @server.bind(@sockaddr) + @server.listen(1) + + server_ip = @server.local_address.ip_port + @server_addr = Socket.sockaddr_in(server_ip, ip_address) + end + + after do + Socket.for_fd(@fd).close if @fd + end + + describe 'without a connected client' do + before do + @client = Socket.new(family, :STREAM) + end + + after do + @client.close + end + + it 'blocks the caller until a connection is available' do + thread = Thread.new do + @fd, _ = @server.sysaccept + end + + @client.connect(@server_addr) + + thread.join(5) + + thread.value.should be_an_instance_of(Array) + end + end + + describe 'with a connected client' do + before do + @client = Socket.new(family, :STREAM) + @client.connect(@server.getsockname) + end + + after do + @client.close + end + + it 'returns an Array containing a Fixnum and an Addrinfo' do + @fd, addrinfo = @server.sysaccept + + @fd.should be_an_instance_of(Fixnum) + addrinfo.should be_an_instance_of(Addrinfo) + end + + it 'returns a new file descriptor' do + @fd, _ = @server.sysaccept + + @fd.should_not == @client.fileno + end + end + end + end +end diff --git a/spec/ruby/library/socket/socket/tcp_server_loop_spec.rb b/spec/ruby/library/socket/socket/tcp_server_loop_spec.rb new file mode 100644 index 0000000000..617e3d445c --- /dev/null +++ b/spec/ruby/library/socket/socket/tcp_server_loop_spec.rb @@ -0,0 +1,47 @@ +require_relative '../spec_helper' +require_relative '../fixtures/classes' + +describe 'Socket.tcp_server_loop' do + describe 'when no connections are available' do + it 'blocks the caller' do + lambda { Socket.tcp_server_loop('127.0.0.1', 0) }.should block_caller + end + end + + describe 'when a connection is available' do + before do + @client = Socket.new(:INET, :STREAM) + @port = 9998 + end + + after do + @sock.close if @sock + @client.close + end + + it 'yields a Socket and an Addrinfo' do + @sock, addr = nil + + thread = Thread.new do + Socket.tcp_server_loop('127.0.0.1', @port) do |socket, addrinfo| + @sock = socket + addr = addrinfo + + break + end + end + + SocketSpecs.wait_until_success do + @client.connect(Socket.sockaddr_in(@port, '127.0.0.1')) + end + + # At this point the connection has been set up but the thread may not yet + # have returned, thus we'll need to wait a little longer for it to + # complete. + thread.join(2) + + @sock.should be_an_instance_of(Socket) + addr.should be_an_instance_of(Addrinfo) + end + end +end diff --git a/spec/ruby/library/socket/socket/tcp_server_sockets_spec.rb b/spec/ruby/library/socket/socket/tcp_server_sockets_spec.rb new file mode 100644 index 0000000000..10c030a8ce --- /dev/null +++ b/spec/ruby/library/socket/socket/tcp_server_sockets_spec.rb @@ -0,0 +1,39 @@ +require_relative '../spec_helper' + +describe 'Socket.tcp_server_sockets' do + describe 'without a block' do + before do + @sockets = nil + end + + after do + @sockets.each(&:close) + end + + it 'returns an Array of Socket objects' do + @sockets = Socket.tcp_server_sockets(0) + + @sockets.should be_an_instance_of(Array) + @sockets[0].should be_an_instance_of(Socket) + end + end + + describe 'with a block' do + it 'yields the sockets to the supplied block' do + Socket.tcp_server_sockets(0) do |sockets| + sockets.should be_an_instance_of(Array) + sockets[0].should be_an_instance_of(Socket) + end + end + + it 'closes all sockets after the block returns' do + sockets = nil + + Socket.tcp_server_sockets(0) { |socks| sockets = socks } + + sockets.each do |socket| + socket.closed?.should == true + end + end + end +end diff --git a/spec/ruby/library/socket/socket/tcp_spec.rb b/spec/ruby/library/socket/socket/tcp_spec.rb new file mode 100644 index 0000000000..29f166ffc5 --- /dev/null +++ b/spec/ruby/library/socket/socket/tcp_spec.rb @@ -0,0 +1,70 @@ +require_relative '../spec_helper' + +describe 'Socket.tcp' do + before do + @server = Socket.new(:INET, :STREAM) + @client = nil + + @server.bind(Socket.sockaddr_in(0, '127.0.0.1')) + @server.listen(1) + + @host = @server.connect_address.ip_address + @port = @server.connect_address.ip_port + end + + after do + @client.close if @client && !@client.closed? + @client = nil + + @server.close + end + + it 'returns a Socket when no block is given' do + @client = Socket.tcp(@host, @port) + + @client.should be_an_instance_of(Socket) + end + + it 'yields the Socket when a block is given' do + Socket.tcp(@host, @port) do |socket| + socket.should be_an_instance_of(Socket) + end + end + + it 'closes the Socket automatically when a block is given' do + Socket.tcp(@host, @port) do |socket| + @socket = socket + end + + @socket.closed?.should == true + end + + it 'binds to a local address and port when specified' do + @client = Socket.tcp(@host, @port, @host, 0) + + @client.local_address.ip_address.should == @host + + @client.local_address.ip_port.should > 0 + @client.local_address.ip_port.should_not == @port + end + + it 'raises ArgumentError when 6 arguments are provided' do + lambda { + Socket.tcp(@host, @port, @host, 0, {:connect_timeout => 1}, 10) + }.should raise_error(ArgumentError) + end + + it 'connects to the server' do + @client = Socket.tcp(@host, @port) + + @client.write('hello') + + connection, _ = @server.accept + + begin + connection.recv(5).should == 'hello' + ensure + connection.close + end + end +end diff --git a/spec/ruby/library/socket/socket/udp_server_loop_on_spec.rb b/spec/ruby/library/socket/socket/udp_server_loop_on_spec.rb new file mode 100644 index 0000000000..1cb82d72be --- /dev/null +++ b/spec/ruby/library/socket/socket/udp_server_loop_on_spec.rb @@ -0,0 +1,47 @@ +require_relative '../spec_helper' + +describe 'Socket.udp_server_loop_on' do + before do + @server = Socket.new(:INET, :DGRAM) + + @server.bind(Socket.sockaddr_in(0, '127.0.0.1')) + end + + after do + @server.close + end + + describe 'when no connections are available' do + it 'blocks the caller' do + lambda { Socket.udp_server_loop_on([@server]) }.should block_caller + end + end + + describe 'when a connection is available' do + before do + @client = Socket.new(:INET, :DGRAM) + end + + after do + @client.close + end + + it 'yields the message and a Socket::UDPSource' do + msg = nil + src = nil + + @client.connect(@server.getsockname) + @client.write('hello') + + Socket.udp_server_loop_on([@server]) do |message, source| + msg = message + src = source + + break + end + + msg.should == 'hello' + src.should be_an_instance_of(Socket::UDPSource) + end + end +end diff --git a/spec/ruby/library/socket/socket/udp_server_loop_spec.rb b/spec/ruby/library/socket/socket/udp_server_loop_spec.rb new file mode 100644 index 0000000000..95f73a5c35 --- /dev/null +++ b/spec/ruby/library/socket/socket/udp_server_loop_spec.rb @@ -0,0 +1,47 @@ +require_relative '../spec_helper' +require_relative '../fixtures/classes' + +describe 'Socket.udp_server_loop' do + describe 'when no connections are available' do + it 'blocks the caller' do + lambda { Socket.udp_server_loop('127.0.0.1', 0) }.should block_caller + end + end + + describe 'when a connection is available' do + before do + @client = Socket.new(:INET, :DGRAM) + @port = 9997 + end + + after do + @client.close + end + + it 'yields the message and a Socket::UDPSource' do + msg, src = nil + + Thread.new do + Socket.udp_server_loop('127.0.0.1', @port) do |message, source| + msg = message + src = source + + break + end + end + + # Because this will return even if the server is up and running (it's UDP + # after all) we'll have to write and wait until "msg" is set. + @client.connect(Socket.sockaddr_in(@port, '127.0.0.1')) + + SocketSpecs.loop_with_timeout do + SocketSpecs.wait_until_success { @client.write('hello') } + + break if msg + end + + msg.should == 'hello' + src.should be_an_instance_of(Socket::UDPSource) + end + end +end diff --git a/spec/ruby/library/socket/socket/udp_server_recv_spec.rb b/spec/ruby/library/socket/socket/udp_server_recv_spec.rb new file mode 100644 index 0000000000..05fef4bca8 --- /dev/null +++ b/spec/ruby/library/socket/socket/udp_server_recv_spec.rb @@ -0,0 +1,32 @@ +require_relative '../spec_helper' + +describe 'Socket.udp_server_recv' do + before do + @server = Socket.new(:INET, :DGRAM) + @client = Socket.new(:INET, :DGRAM) + + @server.bind(Socket.sockaddr_in(0, '127.0.0.1')) + @client.connect(@server.getsockname) + end + + after do + @client.close + @server.close + end + + it 'yields the message and a Socket::UDPSource' do + msg = nil + src = nil + + @client.write('hello') + + Socket.udp_server_recv([@server]) do |message, source| + msg = message + src = source + break + end + + msg.should == 'hello' + src.should be_an_instance_of(Socket::UDPSource) + end +end diff --git a/spec/ruby/library/socket/socket/udp_server_sockets_spec.rb b/spec/ruby/library/socket/socket/udp_server_sockets_spec.rb new file mode 100644 index 0000000000..3aeb472dda --- /dev/null +++ b/spec/ruby/library/socket/socket/udp_server_sockets_spec.rb @@ -0,0 +1,39 @@ +require_relative '../spec_helper' + +describe 'Socket.udp_server_sockets' do + describe 'without a block' do + before do + @sockets = nil + end + + after do + @sockets.each(&:close) + end + + it 'returns an Array of Socket objects' do + @sockets = Socket.udp_server_sockets(0) + + @sockets.should be_an_instance_of(Array) + @sockets[0].should be_an_instance_of(Socket) + end + end + + describe 'with a block' do + it 'yields the sockets to the supplied block' do + Socket.udp_server_sockets(0) do |sockets| + sockets.should be_an_instance_of(Array) + sockets[0].should be_an_instance_of(Socket) + end + end + + it 'closes all sockets after the block returns' do + sockets = nil + + Socket.udp_server_sockets(0) { |socks| sockets = socks } + + sockets.each do |socket| + socket.closed?.should == true + end + end + end +end diff --git a/spec/ruby/library/socket/socket/unix_server_loop_spec.rb b/spec/ruby/library/socket/socket/unix_server_loop_spec.rb new file mode 100644 index 0000000000..52c535cd45 --- /dev/null +++ b/spec/ruby/library/socket/socket/unix_server_loop_spec.rb @@ -0,0 +1,51 @@ +require_relative '../spec_helper' +require_relative '../fixtures/classes' + +with_feature :unix_socket do + describe 'Socket.unix_server_loop' do + before do + @path = SocketSpecs.socket_path + end + + after do + rm_r(@path) if File.file?(@path) + end + + describe 'when no connections are available' do + it 'blocks the caller' do + lambda { Socket.unix_server_loop(@path) }.should block_caller + end + end + + describe 'when a connection is available' do + before do + @client = nil + end + + after do + @sock.close if @sock + @client.close if @client + end + + it 'yields a Socket and an Addrinfo' do + @sock, addr = nil + + thread = Thread.new do + Socket.unix_server_loop(@path) do |socket, addrinfo| + @sock = socket + addr = addrinfo + + break + end + end + + @client = SocketSpecs.wait_until_success { Socket.unix(@path) } + + thread.join(2) + + @sock.should be_an_instance_of(Socket) + addr.should be_an_instance_of(Addrinfo) + end + end + end +end diff --git a/spec/ruby/library/socket/socket/unix_server_socket_spec.rb b/spec/ruby/library/socket/socket/unix_server_socket_spec.rb new file mode 100644 index 0000000000..fc357740fa --- /dev/null +++ b/spec/ruby/library/socket/socket/unix_server_socket_spec.rb @@ -0,0 +1,48 @@ +require_relative '../spec_helper' +require_relative '../fixtures/classes' + +with_feature :unix_socket do + describe 'Socket.unix_server_socket' do + before do + @path = SocketSpecs.socket_path + end + + after do + rm_r(@path) + end + + describe 'when no block is given' do + before do + @socket = nil + end + + after do + @socket.close + end + + it 'returns a Socket' do + @socket = Socket.unix_server_socket(@path) + + @socket.should be_an_instance_of(Socket) + end + end + + describe 'when a block is given' do + it 'yields a Socket' do + Socket.unix_server_socket(@path) do |sock| + sock.should be_an_instance_of(Socket) + end + end + + it 'closes the Socket when the block returns' do + socket = nil + + Socket.unix_server_socket(@path) do |sock| + socket = sock + end + + socket.should be_an_instance_of(Socket) + end + end + end +end diff --git a/spec/ruby/library/socket/socket/unix_spec.rb b/spec/ruby/library/socket/socket/unix_spec.rb new file mode 100644 index 0000000000..add54a097d --- /dev/null +++ b/spec/ruby/library/socket/socket/unix_spec.rb @@ -0,0 +1,45 @@ +require_relative '../spec_helper' +require_relative '../fixtures/classes' + +with_feature :unix_socket do + describe 'Socket.unix' do + before do + @path = SocketSpecs.socket_path + @server = UNIXServer.new(@path) + @socket = nil + end + + after do + @server.close + @socket.close if @socket + + rm_r(@path) + end + + describe 'when no block is given' do + it 'returns a Socket' do + @socket = Socket.unix(@path) + + @socket.should be_an_instance_of(Socket) + end + end + + describe 'when a block is given' do + it 'yields a Socket' do + Socket.unix(@path) do |sock| + sock.should be_an_instance_of(Socket) + end + end + + it 'closes the Socket when the block returns' do + socket = nil + + Socket.unix(@path) do |sock| + socket = sock + end + + socket.closed?.should == true + end + end + end +end diff --git a/spec/ruby/library/socket/socket/unpack_sockaddr_in_spec.rb b/spec/ruby/library/socket/socket/unpack_sockaddr_in_spec.rb index c76a2c54de..579ae307df 100644 --- a/spec/ruby/library/socket/socket/unpack_sockaddr_in_spec.rb +++ b/spec/ruby/library/socket/socket/unpack_sockaddr_in_spec.rb @@ -1,9 +1,7 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' -require 'socket' describe "Socket.unpack_sockaddr_in" do - it "decodes the host name and port number of a packed sockaddr_in" do sockaddr = Socket.sockaddr_in 3333, '127.0.0.1' Socket.unpack_sockaddr_in(sockaddr).should == [3333, '127.0.0.1'] @@ -14,7 +12,27 @@ describe "Socket.unpack_sockaddr_in" do Socket.unpack_sockaddr_in(addrinfo).should == [3333, '127.0.0.1'] end - platform_is_not :windows do + describe 'using an IPv4 address' do + it 'returns an Array containing the port and IP address' do + port = 80 + ip = '127.0.0.1' + addr = Socket.pack_sockaddr_in(port, ip) + + Socket.unpack_sockaddr_in(addr).should == [port, ip] + end + end + + describe 'using an IPv6 address' do + it 'returns an Array containing the port and IP address' do + port = 80 + ip = '::1' + addr = Socket.pack_sockaddr_in(port, ip) + + Socket.unpack_sockaddr_in(addr).should == [port, ip] + end + end + + with_feature :unix_socket do it "raises an ArgumentError when the sin_family is not AF_INET" do sockaddr = Socket.sockaddr_un '/tmp/x' lambda { Socket.unpack_sockaddr_in sockaddr }.should raise_error(ArgumentError) @@ -25,5 +43,4 @@ describe "Socket.unpack_sockaddr_in" do lambda { Socket.unpack_sockaddr_in(addrinfo) }.should raise_error(ArgumentError) end end - end diff --git a/spec/ruby/library/socket/socket/unpack_sockaddr_un_spec.rb b/spec/ruby/library/socket/socket/unpack_sockaddr_un_spec.rb index 8dd68b9f99..39e33c90e9 100644 --- a/spec/ruby/library/socket/socket/unpack_sockaddr_un_spec.rb +++ b/spec/ruby/library/socket/socket/unpack_sockaddr_un_spec.rb @@ -1,8 +1,8 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' -describe 'Socket.unpack_sockaddr_un' do - platform_is_not :windows do +with_feature :unix_socket do + describe 'Socket.unpack_sockaddr_un' do it 'decodes sockaddr to unix path' do sockaddr = Socket.sockaddr_un('/tmp/sock') Socket.unpack_sockaddr_un(sockaddr).should == '/tmp/sock' diff --git a/spec/ruby/library/socket/spec_helper.rb b/spec/ruby/library/socket/spec_helper.rb new file mode 100644 index 0000000000..5a6dea7aa7 --- /dev/null +++ b/spec/ruby/library/socket/spec_helper.rb @@ -0,0 +1,16 @@ +require_relative '../../spec_helper' +require 'socket' + +if %w[rbx truffleruby].include?(RUBY_ENGINE) + MSpec.enable_feature :pure_ruby_addrinfo +end + +MSpec.enable_feature :sock_packet if Socket.const_defined?(:SOCK_PACKET) +MSpec.enable_feature :unix_socket unless PlatformGuard.windows? +MSpec.enable_feature :udp_cork if Socket.const_defined?(:UDP_CORK) +MSpec.enable_feature :tcp_cork if Socket.const_defined?(:TCP_CORK) +MSpec.enable_feature :ipv6_pktinfo if Socket.const_defined?(:IPV6_PKTINFO) +MSpec.enable_feature :ip_mtu if Socket.const_defined?(:IP_MTU) +MSpec.enable_feature :ipv6_nexthop if Socket.const_defined?(:IPV6_NEXTHOP) +MSpec.enable_feature :tcp_info if Socket.const_defined?(:TCP_INFO) +MSpec.enable_feature :ancillary_data if Socket.const_defined?(:AncillaryData) diff --git a/spec/ruby/library/socket/tcpserver/accept_nonblock_spec.rb b/spec/ruby/library/socket/tcpserver/accept_nonblock_spec.rb index 8566081d2f..27d6a0d08e 100644 --- a/spec/ruby/library/socket/tcpserver/accept_nonblock_spec.rb +++ b/spec/ruby/library/socket/tcpserver/accept_nonblock_spec.rb @@ -1,4 +1,4 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' describe "Socket::TCPServer.accept_nonblock" do @@ -46,3 +46,39 @@ describe "Socket::TCPServer.accept_nonblock" do end end end + +describe 'TCPServer#accept_nonblock' do + SocketSpecs.each_ip_protocol do |family, ip_address| + before do + @server = TCPServer.new(ip_address, 0) + end + + after do + @server.close + end + + describe 'without a connected client' do + it 'raises IO::WaitReadable' do + lambda { @server.accept_nonblock }.should raise_error(IO::WaitReadable) + end + end + + platform_is_not :windows do # spurious + describe 'with a connected client' do + before do + @client = TCPSocket.new(ip_address, @server.connect_address.ip_port) + end + + after do + @socket.close if @socket + @client.close + end + + it 'returns a TCPSocket' do + @socket = @server.accept_nonblock + @socket.should be_an_instance_of(TCPSocket) + end + end + end + end +end diff --git a/spec/ruby/library/socket/tcpserver/accept_spec.rb b/spec/ruby/library/socket/tcpserver/accept_spec.rb index b374899409..f0ef9cc727 100644 --- a/spec/ruby/library/socket/tcpserver/accept_spec.rb +++ b/spec/ruby/library/socket/tcpserver/accept_spec.rb @@ -1,7 +1,6 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' - describe "TCPServer#accept" do before :each do @server = TCPServer.new("127.0.0.1", 0) @@ -64,3 +63,37 @@ describe "TCPServer#accept" do lambda { @server.accept }.should raise_error(IOError) end end + +describe 'TCPServer#accept' do + SocketSpecs.each_ip_protocol do |family, ip_address| + before do + @server = TCPServer.new(ip_address, 0) + end + + after do + @server.close + end + + describe 'without a connected client' do + it 'blocks the caller' do + lambda { @server.accept }.should block_caller + end + end + + describe 'with a connected client' do + before do + @client = TCPSocket.new(ip_address, @server.connect_address.ip_port) + end + + after do + @socket.close if @socket + @client.close + end + + it 'returns a TCPSocket' do + @socket = @server.accept + @socket.should be_an_instance_of(TCPSocket) + end + end + end +end diff --git a/spec/ruby/library/socket/tcpserver/gets_spec.rb b/spec/ruby/library/socket/tcpserver/gets_spec.rb index 6324986111..936295dce2 100644 --- a/spec/ruby/library/socket/tcpserver/gets_spec.rb +++ b/spec/ruby/library/socket/tcpserver/gets_spec.rb @@ -1,4 +1,4 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' describe "TCPServer#gets" do diff --git a/spec/ruby/library/socket/tcpserver/initialize_spec.rb b/spec/ruby/library/socket/tcpserver/initialize_spec.rb new file mode 100644 index 0000000000..2de8c764b2 --- /dev/null +++ b/spec/ruby/library/socket/tcpserver/initialize_spec.rb @@ -0,0 +1,99 @@ +require_relative '../spec_helper' +require_relative '../fixtures/classes' + +describe 'TCPServer#initialize' do + describe 'with a single Fixnum argument' do + before do + @server = TCPServer.new(0) + end + + after do + @server.close + end + + it 'sets the port to the given argument' do + @server.local_address.ip_port.should be_an_instance_of(Fixnum) + @server.local_address.ip_port.should > 0 + end + + platform_is_not :windows do + it 'sets the hostname to 0.0.0.0' do + @server.local_address.ip_address.should == '0.0.0.0' + end + end + + it "sets the socket to binmode" do + @server.binmode?.should be_true + end + end + + describe 'with a single String argument containing a numeric value' do + before do + @server = TCPServer.new('0') + end + + after do + @server.close + end + + it 'sets the port to the given argument' do + @server.local_address.ip_port.should be_an_instance_of(Fixnum) + @server.local_address.ip_port.should > 0 + end + + platform_is_not :windows do + it 'sets the hostname to 0.0.0.0' do + @server.local_address.ip_address.should == '0.0.0.0' + end + end + end + + describe 'with a single String argument containing a non numeric value' do + it 'raises SocketError' do + lambda { TCPServer.new('cats') }.should raise_error(SocketError) + end + end + + describe 'with a String and a Fixnum' do + SocketSpecs.each_ip_protocol do |family, ip_address| + before do + @server = TCPServer.new(ip_address, 0) + end + + after do + @server.close + end + + it 'sets the port to the given port argument' do + @server.local_address.ip_port.should be_an_instance_of(Fixnum) + @server.local_address.ip_port.should > 0 + end + + it 'sets the hostname to the given host argument' do + @server.local_address.ip_address.should == ip_address + end + end + end + + describe 'with a String and a custom object' do + before do + dummy = mock(:dummy) + dummy.stub!(:to_str).and_return('0') + + @server = TCPServer.new('127.0.0.1', dummy) + end + + after do + @server.close + end + + it 'sets the port to the given port argument' do + @server.local_address.ip_port.should be_an_instance_of(Fixnum) + @server.local_address.ip_port.should > 0 + end + + it 'sets the hostname to the given host argument' do + @server.local_address.ip_address.should == '127.0.0.1' + end + end +end diff --git a/spec/ruby/library/socket/tcpserver/listen_spec.rb b/spec/ruby/library/socket/tcpserver/listen_spec.rb index 77a1120158..1e17de06f1 100644 --- a/spec/ruby/library/socket/tcpserver/listen_spec.rb +++ b/spec/ruby/library/socket/tcpserver/listen_spec.rb @@ -1,18 +1,22 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' -require 'socket' - describe 'TCPServer#listen' do - before :each do - @server = TCPServer.new(SocketSpecs.hostname, 0) - end + SocketSpecs.each_ip_protocol do |family, ip_address| + before do + @server = TCPServer.new(ip_address, 0) + end - after :each do - @server.close unless @server.closed? - end + after do + @server.close + end + + it 'returns 0' do + @server.listen(1).should == 0 + end - it 'returns 0' do - @server.listen(10).should == 0 + it "raises when the given argument can't be coerced to a Fixnum" do + lambda { @server.listen('cats') }.should raise_error(TypeError) + end end end diff --git a/spec/ruby/library/socket/tcpserver/new_spec.rb b/spec/ruby/library/socket/tcpserver/new_spec.rb index 7504fbe128..94033411e3 100644 --- a/spec/ruby/library/socket/tcpserver/new_spec.rb +++ b/spec/ruby/library/socket/tcpserver/new_spec.rb @@ -1,4 +1,4 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' describe "TCPServer.new" do @@ -25,7 +25,7 @@ describe "TCPServer.new" do addr[2].should =~ /^#{SocketSpecs.hostname}\b/ addr[3].should == '127.0.0.1' else - addr[2].should =~ /^#{SocketSpecs.hostnamev6}\b/ + addr[2].should =~ /^#{SocketSpecs.hostname('::1')}\b/ addr[3].should == '::1' end end diff --git a/spec/ruby/library/socket/tcpserver/sysaccept_spec.rb b/spec/ruby/library/socket/tcpserver/sysaccept_spec.rb index aa6cb2bb50..144b6806f1 100644 --- a/spec/ruby/library/socket/tcpserver/sysaccept_spec.rb +++ b/spec/ruby/library/socket/tcpserver/sysaccept_spec.rb @@ -1,8 +1,6 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' -require 'socket' - describe "TCPServer#sysaccept" do before :each do @server = TCPServer.new(SocketSpecs.hostname, 0) @@ -30,3 +28,39 @@ describe "TCPServer#sysaccept" do end end end + +describe 'TCPServer#sysaccept' do + SocketSpecs.each_ip_protocol do |family, ip_address| + before do + @server = TCPServer.new(ip_address, 0) + end + + after do + @server.close + end + + describe 'without a connected client' do + it 'blocks the caller' do + lambda { @server.sysaccept }.should block_caller + end + end + + describe 'with a connected client' do + before do + @client = TCPSocket.new(ip_address, @server.connect_address.ip_port) + end + + after do + Socket.for_fd(@fd).close if @fd + @client.close + end + + it 'returns a new file descriptor as a Fixnum' do + @fd = @server.sysaccept + + @fd.should be_an_instance_of(Fixnum) + @fd.should_not == @client.fileno + end + end + end +end diff --git a/spec/ruby/library/socket/tcpsocket/gethostbyname_spec.rb b/spec/ruby/library/socket/tcpsocket/gethostbyname_spec.rb index 9f25280a70..230d14bfb0 100644 --- a/spec/ruby/library/socket/tcpsocket/gethostbyname_spec.rb +++ b/spec/ruby/library/socket/tcpsocket/gethostbyname_spec.rb @@ -1,4 +1,4 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' # TODO: verify these for windows @@ -49,3 +49,63 @@ describe "TCPSocket#gethostbyname" do @host_info[1].should be_kind_of(Array) end end + +describe 'TCPSocket#gethostbyname' do + it 'returns an Array' do + TCPSocket.gethostbyname('127.0.0.1').should be_an_instance_of(Array) + end + + describe 'using a hostname' do + describe 'the returned Array' do + before do + @array = TCPSocket.gethostbyname('127.0.0.1') + end + + it 'includes the canonical name as the 1st value' do + @array[0].should == '127.0.0.1' + end + + it 'includes an array of alternative hostnames as the 2nd value' do + @array[1].should be_an_instance_of(Array) + end + + it 'includes the address family as the 3rd value' do + @array[2].should be_an_instance_of(Fixnum) + end + + it 'includes the IP addresses as all the remaining values' do + ips = %w{::1 127.0.0.1} + + ips.include?(@array[3]).should == true + + # Not all machines might have both IPv4 and IPv6 set up, so this value is + # optional. + ips.include?(@array[4]).should == true if @array[4] + end + end + end + + SocketSpecs.each_ip_protocol do |family, ip_address| + describe 'the returned Array' do + before do + @array = TCPSocket.gethostbyname(ip_address) + end + + it 'includes the IP address as the 1st value' do + @array[0].should == ip_address + end + + it 'includes an empty list of aliases as the 2nd value' do + @array[1].should == [] + end + + it 'includes the address family as the 3rd value' do + @array[2].should == family + end + + it 'includes the IP address as the 4th value' do + @array[3].should == ip_address + end + end + end +end diff --git a/spec/ruby/library/socket/tcpsocket/initialize_spec.rb b/spec/ruby/library/socket/tcpsocket/initialize_spec.rb new file mode 100644 index 0000000000..184f9abb7d --- /dev/null +++ b/spec/ruby/library/socket/tcpsocket/initialize_spec.rb @@ -0,0 +1,61 @@ +require_relative '../spec_helper' +require_relative '../fixtures/classes' + +describe 'TCPSocket#initialize' do + SocketSpecs.each_ip_protocol do |family, ip_address| + describe 'when no server is listening on the given address' do + it 'raises Errno::ECONNREFUSED' do + lambda { TCPSocket.new(ip_address, 666) }.should raise_error(Errno::ECONNREFUSED) + end + end + + describe 'when a server is listening on the given address' do + before do + @server = TCPServer.new(ip_address, 0) + @port = @server.connect_address.ip_port + end + + after do + @client.close if @client + @server.close + end + + it 'returns a TCPSocket when using a Fixnum as the port' do + @client = TCPSocket.new(ip_address, @port) + @client.should be_an_instance_of(TCPSocket) + end + + it 'returns a TCPSocket when using a String as the port' do + @client = TCPSocket.new(ip_address, @port.to_s) + @client.should be_an_instance_of(TCPSocket) + end + + it 'raises SocketError when the port number is a non numeric String' do + lambda { TCPSocket.new(ip_address, 'cats') }.should raise_error(SocketError) + end + + it 'set the socket to binmode' do + @client = TCPSocket.new(ip_address, @port) + @client.binmode?.should be_true + end + + it 'connects to the right address' do + @client = TCPSocket.new(ip_address, @port) + + @client.remote_address.ip_address.should == @server.local_address.ip_address + @client.remote_address.ip_port.should == @server.local_address.ip_port + end + + describe 'using a local address and service' do + it 'binds the client socket to the local address and service' do + @client = TCPSocket.new(ip_address, @port, ip_address, 0) + + @client.local_address.ip_address.should == ip_address + + @client.local_address.ip_port.should > 0 + @client.local_address.ip_port.should_not == @port + end + end + end + end +end diff --git a/spec/ruby/library/socket/tcpsocket/local_address_spec.rb b/spec/ruby/library/socket/tcpsocket/local_address_spec.rb new file mode 100644 index 0000000000..ce66d5ff8f --- /dev/null +++ b/spec/ruby/library/socket/tcpsocket/local_address_spec.rb @@ -0,0 +1,73 @@ +require_relative '../spec_helper' +require_relative '../fixtures/classes' + +describe 'TCPSocket#local_address' do + SocketSpecs.each_ip_protocol do |family, ip_address| + before do + @server = TCPServer.new(ip_address, 0) + @host = @server.connect_address.ip_address + @port = @server.connect_address.ip_port + end + + after do + @server.close + end + + describe 'using an explicit hostname' do + before do + @sock = TCPSocket.new(@host, @port) + end + + after do + @sock.close + end + + it 'returns an Addrinfo' do + @sock.local_address.should be_an_instance_of(Addrinfo) + end + + describe 'the returned Addrinfo' do + it 'uses AF_INET as the address family' do + @sock.local_address.afamily.should == family + end + + it 'uses PF_INET as the protocol family' do + @sock.local_address.pfamily.should == family + end + + it 'uses SOCK_STREAM as the socket type' do + @sock.local_address.socktype.should == Socket::SOCK_STREAM + end + + it 'uses the correct IP address' do + @sock.local_address.ip_address.should == @host + end + + it 'uses a randomly assigned local port' do + @sock.local_address.ip_port.should > 0 + @sock.local_address.ip_port.should_not == @port + end + + it 'uses 0 as the protocol' do + @sock.local_address.protocol.should == 0 + end + end + end + + describe 'using an implicit hostname' do + before do + @sock = TCPSocket.new(nil, @port) + end + + after do + @sock.close + end + + describe 'the returned Addrinfo' do + it 'uses the correct IP address' do + @sock.local_address.ip_address.should == @host + end + end + end + end +end diff --git a/spec/ruby/library/socket/tcpsocket/partially_closable_spec.rb b/spec/ruby/library/socket/tcpsocket/partially_closable_spec.rb index 9416d5c71d..a381627a39 100644 --- a/spec/ruby/library/socket/tcpsocket/partially_closable_spec.rb +++ b/spec/ruby/library/socket/tcpsocket/partially_closable_spec.rb @@ -1,4 +1,4 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' require_relative '../shared/partially_closable_sockets' diff --git a/spec/ruby/library/socket/tcpsocket/recv_nonblock_spec.rb b/spec/ruby/library/socket/tcpsocket/recv_nonblock_spec.rb index 23bba526e8..bfd815c658 100644 --- a/spec/ruby/library/socket/tcpsocket/recv_nonblock_spec.rb +++ b/spec/ruby/library/socket/tcpsocket/recv_nonblock_spec.rb @@ -1,4 +1,4 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' describe "TCPSocket#recv_nonblock" do diff --git a/spec/ruby/library/socket/tcpsocket/recv_spec.rb b/spec/ruby/library/socket/tcpsocket/recv_spec.rb new file mode 100644 index 0000000000..f380db670d --- /dev/null +++ b/spec/ruby/library/socket/tcpsocket/recv_spec.rb @@ -0,0 +1,28 @@ +require_relative '../spec_helper' +require_relative '../fixtures/classes' + +describe 'TCPSocket#recv' do + SocketSpecs.each_ip_protocol do |family, ip_address| + before do + @server = TCPServer.new(ip_address, 0) + @client = TCPSocket.new(ip_address, @server.connect_address.ip_port) + end + + after do + @client.close + @server.close + end + + it 'returns the message data' do + @client.write('hello') + + socket = @server.accept + + begin + socket.recv(5).should == 'hello' + ensure + socket.close + end + end + end +end diff --git a/spec/ruby/library/socket/tcpsocket/remote_address_spec.rb b/spec/ruby/library/socket/tcpsocket/remote_address_spec.rb new file mode 100644 index 0000000000..eb9dabc075 --- /dev/null +++ b/spec/ruby/library/socket/tcpsocket/remote_address_spec.rb @@ -0,0 +1,72 @@ +require_relative '../spec_helper' +require_relative '../fixtures/classes' + +describe 'TCPSocket#remote_address' do + SocketSpecs.each_ip_protocol do |family, ip_address| + before do + @server = TCPServer.new(ip_address, 0) + @host = @server.connect_address.ip_address + @port = @server.connect_address.ip_port + end + + after do + @server.close + end + + describe 'using an explicit hostname' do + before do + @sock = TCPSocket.new(@host, @port) + end + + after do + @sock.close + end + + it 'returns an Addrinfo' do + @sock.remote_address.should be_an_instance_of(Addrinfo) + end + + describe 'the returned Addrinfo' do + it 'uses AF_INET as the address family' do + @sock.remote_address.afamily.should == family + end + + it 'uses PF_INET as the protocol family' do + @sock.remote_address.pfamily.should == family + end + + it 'uses SOCK_STREAM as the socket type' do + @sock.remote_address.socktype.should == Socket::SOCK_STREAM + end + + it 'uses the correct IP address' do + @sock.remote_address.ip_address.should == @host + end + + it 'uses the correct port' do + @sock.remote_address.ip_port.should == @port + end + + it 'uses 0 as the protocol' do + @sock.remote_address.protocol.should == 0 + end + end + end + + describe 'using an implicit hostname' do + before do + @sock = TCPSocket.new(nil, @port) + end + + after do + @sock.close + end + + describe 'the returned Addrinfo' do + it 'uses the correct IP address' do + @sock.remote_address.ip_address.should == @host + end + end + end + end +end diff --git a/spec/ruby/library/socket/tcpsocket/setsockopt_spec.rb b/spec/ruby/library/socket/tcpsocket/setsockopt_spec.rb index c9b0ff16dc..8b728b7522 100644 --- a/spec/ruby/library/socket/tcpsocket/setsockopt_spec.rb +++ b/spec/ruby/library/socket/tcpsocket/setsockopt_spec.rb @@ -1,4 +1,4 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' describe "TCPSocket#setsockopt" do diff --git a/spec/ruby/library/socket/tcpsocket/shared/new.rb b/spec/ruby/library/socket/tcpsocket/shared/new.rb index c66479a2d8..818bd69a91 100644 --- a/spec/ruby/library/socket/tcpsocket/shared/new.rb +++ b/spec/ruby/library/socket/tcpsocket/shared/new.rb @@ -1,4 +1,4 @@ -require_relative '../../../../spec_helper' +require_relative '../../spec_helper' require_relative '../../fixtures/classes' describe :tcpsocket_new, shared: true do diff --git a/spec/ruby/library/socket/udpsocket/bind_spec.rb b/spec/ruby/library/socket/udpsocket/bind_spec.rb index be62608e1b..4dbdb285f6 100644 --- a/spec/ruby/library/socket/udpsocket/bind_spec.rb +++ b/spec/ruby/library/socket/udpsocket/bind_spec.rb @@ -1,8 +1,7 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' -describe "UDPSocket.bind" do - +describe "UDPSocket#bind" do before :each do @socket = UDPSocket.new end @@ -34,9 +33,51 @@ describe "UDPSocket.bind" do end it "binds to INADDR_ANY if the hostname is empty" do - @socket.bind("", 0) + @socket.bind("", 0).should == 0 port, host = Socket.unpack_sockaddr_in(@socket.getsockname) host.should == "0.0.0.0" port.should == @socket.addr[1] end end + +describe 'UDPSocket#bind' do + SocketSpecs.each_ip_protocol do |family, ip_address| + before do + @socket = UDPSocket.new(family) + end + + after do + @socket.close + end + + it 'binds to an address and port' do + @socket.bind(ip_address, 0).should == 0 + + @socket.local_address.ip_address.should == ip_address + @socket.local_address.ip_port.should > 0 + end + + it 'binds to an address and port using String arguments' do + @socket.bind(ip_address, '0').should == 0 + + @socket.local_address.ip_address.should == ip_address + @socket.local_address.ip_port.should > 0 + end + + it 'can receive data after being bound to an address' do + @socket.bind(ip_address, 0) + + addr = @socket.connect_address + client = UDPSocket.new(family) + + client.connect(addr.ip_address, addr.ip_port) + client.write('hello') + + begin + @socket.recv(6).should == 'hello' + ensure + client.close + end + end + end +end diff --git a/spec/ruby/library/socket/udpsocket/connect_spec.rb b/spec/ruby/library/socket/udpsocket/connect_spec.rb new file mode 100644 index 0000000000..d92bdeb981 --- /dev/null +++ b/spec/ruby/library/socket/udpsocket/connect_spec.rb @@ -0,0 +1,35 @@ +require_relative '../spec_helper' +require_relative '../fixtures/classes' + +describe 'UDPSocket#connect' do + SocketSpecs.each_ip_protocol do |family, ip_address| + before do + @socket = UDPSocket.new(family) + end + + after do + @socket.close + end + + it 'connects to an address even when it is not used' do + @socket.connect(ip_address, 9996).should == 0 + end + + it 'can send data after connecting' do + receiver = UDPSocket.new(family) + + receiver.bind(ip_address, 0) + + addr = receiver.connect_address + + @socket.connect(addr.ip_address, addr.ip_port) + @socket.write('hello') + + begin + receiver.recv(6).should == 'hello' + ensure + receiver.close + end + end + end +end diff --git a/spec/ruby/library/socket/udpsocket/initialize_spec.rb b/spec/ruby/library/socket/udpsocket/initialize_spec.rb new file mode 100644 index 0000000000..5df3bf9800 --- /dev/null +++ b/spec/ruby/library/socket/udpsocket/initialize_spec.rb @@ -0,0 +1,36 @@ +require_relative '../spec_helper' + +describe 'UDPSocket#initialize' do + after do + @socket.close if @socket + end + + it 'initializes a new UDPSocket' do + @socket = UDPSocket.new + @socket.should be_an_instance_of(UDPSocket) + end + + it 'initializes a new UDPSocket using a Fixnum' do + @socket = UDPSocket.new(Socket::AF_INET) + @socket.should be_an_instance_of(UDPSocket) + end + + it 'initializes a new UDPSocket using a Symbol' do + @socket = UDPSocket.new(:INET) + @socket.should be_an_instance_of(UDPSocket) + end + + it 'initializes a new UDPSocket using a String' do + @socket = UDPSocket.new('INET') + @socket.should be_an_instance_of(UDPSocket) + end + + it 'sets the socket to binmode' do + @socket = UDPSocket.new(:INET) + @socket.binmode?.should be_true + end + + it 'raises Errno::EAFNOSUPPORT when given an invalid address family' do + lambda { UDPSocket.new(666) }.should raise_error(Errno::EAFNOSUPPORT) + end +end diff --git a/spec/ruby/library/socket/udpsocket/inspect_spec.rb b/spec/ruby/library/socket/udpsocket/inspect_spec.rb new file mode 100644 index 0000000000..201e8b3fc6 --- /dev/null +++ b/spec/ruby/library/socket/udpsocket/inspect_spec.rb @@ -0,0 +1,25 @@ +require_relative '../spec_helper' + +describe 'UDPSocket#inspect' do + before do + @socket = UDPSocket.new + @socket.bind('127.0.0.1', 0) + end + + after do + @socket.close + end + + ruby_version_is ""..."2.5" do + it 'returns a String with the fd' do + @socket.inspect.should == "#" + end + end + + ruby_version_is "2.5" do + it 'returns a String with the fd, family, address and port' do + port = @socket.addr[1] + @socket.inspect.should == "#" + end + end +end diff --git a/spec/ruby/library/socket/udpsocket/local_address_spec.rb b/spec/ruby/library/socket/udpsocket/local_address_spec.rb new file mode 100644 index 0000000000..92e4cc10c7 --- /dev/null +++ b/spec/ruby/library/socket/udpsocket/local_address_spec.rb @@ -0,0 +1,80 @@ +require_relative '../spec_helper' +require_relative '../fixtures/classes' + +describe 'UDPSocket#local_address' do + SocketSpecs.each_ip_protocol do |family, ip_address| + before do + @server = Socket.new(family, :DGRAM, Socket::IPPROTO_UDP) + + @server.bind(Socket.sockaddr_in(0, ip_address)) + + @host = @server.connect_address.ip_address + @port = @server.connect_address.ip_port + end + + after do + @server.close + end + + describe 'using an explicit hostname' do + before do + @sock = UDPSocket.new(family) + + @sock.connect(@host, @port) + end + + after do + @sock.close + end + + it 'returns an Addrinfo' do + @sock.local_address.should be_an_instance_of(Addrinfo) + end + + describe 'the returned Addrinfo' do + it 'uses the correct address family' do + @sock.local_address.afamily.should == family + end + + it 'uses the correct protocol family' do + @sock.local_address.pfamily.should == family + end + + it 'uses SOCK_DGRAM as the socket type' do + @sock.local_address.socktype.should == Socket::SOCK_DGRAM + end + + it 'uses the correct IP address' do + @sock.local_address.ip_address.should == @host + end + + it 'uses a randomly assigned local port' do + @sock.local_address.ip_port.should > 0 + @sock.local_address.ip_port.should_not == @port + end + + it 'uses 0 as the protocol' do + @sock.local_address.protocol.should == 0 + end + end + end + + describe 'using an implicit hostname' do + before do + @sock = UDPSocket.new(family) + + @sock.connect(nil, @port) + end + + after do + @sock.close + end + + describe 'the returned Addrinfo' do + it 'uses the correct IP address' do + @sock.local_address.ip_address.should == @host + end + end + end + end +end diff --git a/spec/ruby/library/socket/udpsocket/new_spec.rb b/spec/ruby/library/socket/udpsocket/new_spec.rb index b2662277c4..30e7103d16 100644 --- a/spec/ruby/library/socket/udpsocket/new_spec.rb +++ b/spec/ruby/library/socket/udpsocket/new_spec.rb @@ -1,4 +1,4 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' describe 'UDPSocket.new' do diff --git a/spec/ruby/library/socket/udpsocket/open_spec.rb b/spec/ruby/library/socket/udpsocket/open_spec.rb index 2db17fe090..e4dbb2ee2a 100644 --- a/spec/ruby/library/socket/udpsocket/open_spec.rb +++ b/spec/ruby/library/socket/udpsocket/open_spec.rb @@ -1,4 +1,4 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' describe "UDPSocket.open" do diff --git a/spec/ruby/library/socket/udpsocket/recvfrom_nonblock_spec.rb b/spec/ruby/library/socket/udpsocket/recvfrom_nonblock_spec.rb new file mode 100644 index 0000000000..48b7360035 --- /dev/null +++ b/spec/ruby/library/socket/udpsocket/recvfrom_nonblock_spec.rb @@ -0,0 +1,88 @@ +require_relative '../spec_helper' +require_relative '../fixtures/classes' + +describe 'UDPSocket#recvfrom_nonblock' do + SocketSpecs.each_ip_protocol do |family, ip_address, family_name| + before do + @server = UDPSocket.new(family) + @client = UDPSocket.new(family) + end + + after do + @client.close + @server.close + end + + platform_is_not :windows do + describe 'using an unbound socket' do + it 'raises IO::WaitReadable' do + lambda { @server.recvfrom_nonblock(1) }.should raise_error(IO::WaitReadable) + end + end + end + + describe 'using a bound socket' do + before do + @server.bind(ip_address, 0) + + addr = @server.connect_address + + @client.connect(addr.ip_address, addr.ip_port) + end + + describe 'without any data available' do + it 'raises IO::WaitReadable' do + lambda { @server.recvfrom_nonblock(1) }.should raise_error(IO::WaitReadable) + end + end + + platform_is_not :windows do + describe 'with data available' do + before do + @client.write('hello') + end + + it 'returns an Array containing the data and an Array' do + @server.recvfrom_nonblock(1).should be_an_instance_of(Array) + end + + describe 'the returned Array' do + before do + @array = @server.recvfrom_nonblock(1) + end + + it 'contains the data at index 0' do + @array[0].should == 'h' + end + + it 'contains an Array at index 1' do + @array[1].should be_an_instance_of(Array) + end + end + + describe 'the returned address Array' do + before do + @addr = @server.recvfrom_nonblock(1)[1] + end + + it 'uses the correct address family' do + @addr[0].should == family_name + end + + it 'uses the port of the client' do + @addr[1].should == @client.local_address.ip_port + end + + it 'uses the hostname of the client' do + @addr[2].should == ip_address + end + + it 'uses the IP address of the client' do + @addr[3].should == ip_address + end + end + end + end + end + end +end diff --git a/spec/ruby/library/socket/udpsocket/remote_address_spec.rb b/spec/ruby/library/socket/udpsocket/remote_address_spec.rb new file mode 100644 index 0000000000..94889ce560 --- /dev/null +++ b/spec/ruby/library/socket/udpsocket/remote_address_spec.rb @@ -0,0 +1,79 @@ +require_relative '../spec_helper' +require_relative '../fixtures/classes' + +describe 'UDPSocket#remote_address' do + SocketSpecs.each_ip_protocol do |family, ip_address| + before do + @server = Socket.new(family, :DGRAM, Socket::IPPROTO_UDP) + + @server.bind(Socket.sockaddr_in(0, ip_address)) + + @host = @server.connect_address.ip_address + @port = @server.connect_address.ip_port + end + + after do + @server.close + end + + describe 'using an explicit hostname' do + before do + @sock = UDPSocket.new(family) + + @sock.connect(@host, @port) + end + + after do + @sock.close + end + + it 'returns an Addrinfo' do + @sock.remote_address.should be_an_instance_of(Addrinfo) + end + + describe 'the returned Addrinfo' do + it 'uses the correct address family' do + @sock.remote_address.afamily.should == family + end + + it 'uses the correct protocol family' do + @sock.remote_address.pfamily.should == family + end + + it 'uses SOCK_DGRAM as the socket type' do + @sock.remote_address.socktype.should == Socket::SOCK_DGRAM + end + + it 'uses the correct IP address' do + @sock.remote_address.ip_address.should == @host + end + + it 'uses the correct port' do + @sock.remote_address.ip_port.should == @port + end + + it 'uses 0 as the protocol' do + @sock.remote_address.protocol.should == 0 + end + end + end + + describe 'using an implicit hostname' do + before do + @sock = UDPSocket.new(family) + + @sock.connect(nil, @port) + end + + after do + @sock.close + end + + describe 'the returned Addrinfo' do + it 'uses the correct IP address' do + @sock.remote_address.ip_address.should == @host + end + end + end + end +end diff --git a/spec/ruby/library/socket/udpsocket/send_spec.rb b/spec/ruby/library/socket/udpsocket/send_spec.rb index 0159e25214..b84e84b056 100644 --- a/spec/ruby/library/socket/udpsocket/send_spec.rb +++ b/spec/ruby/library/socket/udpsocket/send_spec.rb @@ -1,7 +1,7 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' -describe "UDPSocket.send" do +describe "UDPSocket#send" do before :each do @port = nil @server_thread = Thread.new do @@ -76,3 +76,79 @@ describe "UDPSocket.send" do end end end + +describe 'UDPSocket#send' do + SocketSpecs.each_ip_protocol do |family, ip_address| + before do + @server = UDPSocket.new(family) + @client = UDPSocket.new(family) + + @server.bind(ip_address, 0) + + @addr = @server.connect_address + end + + after do + @server.close + @client.close + end + + describe 'using a disconnected socket' do + describe 'without a destination address' do + it "raises #{SocketSpecs.dest_addr_req_error}" do + lambda { @client.send('hello', 0) }.should raise_error(SocketSpecs.dest_addr_req_error) + end + end + + describe 'with a destination address as separate arguments' do + it 'returns the amount of sent bytes' do + @client.send('hello', 0, @addr.ip_address, @addr.ip_port).should == 5 + end + + it 'does not persist the connection after sending data' do + @client.send('hello', 0, @addr.ip_address, @addr.ip_port) + + lambda { @client.send('hello', 0) }.should raise_error(SocketSpecs.dest_addr_req_error) + end + end + + describe 'with a destination address as a single String argument' do + it 'returns the amount of sent bytes' do + @client.send('hello', 0, @server.getsockname).should == 5 + end + end + end + + describe 'using a connected socket' do + describe 'without an explicit destination address' do + before do + @client.connect(@addr.ip_address, @addr.ip_port) + end + + it 'returns the amount of bytes written' do + @client.send('hello', 0).should == 5 + end + end + + describe 'with an explicit destination address' do + before do + @alt_server = UDPSocket.new(family) + + @alt_server.bind(ip_address, 0) + end + + after do + @alt_server.close + end + + it 'sends the data to the given address instead' do + @client.send('hello', 0, @alt_server.getsockname).should == 5 + + lambda { @server.recv(5) }.should block_caller + + @alt_server.recv(5).should == 'hello' + end + end + end + end +end diff --git a/spec/ruby/library/socket/udpsocket/write_spec.rb b/spec/ruby/library/socket/udpsocket/write_spec.rb index c2a36eaa7a..e960de1baf 100644 --- a/spec/ruby/library/socket/udpsocket/write_spec.rb +++ b/spec/ruby/library/socket/udpsocket/write_spec.rb @@ -1,4 +1,4 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' describe "UDPSocket#write" do diff --git a/spec/ruby/library/socket/unixserver/accept_nonblock_spec.rb b/spec/ruby/library/socket/unixserver/accept_nonblock_spec.rb index 27603aeabd..3ebe38a090 100644 --- a/spec/ruby/library/socket/unixserver/accept_nonblock_spec.rb +++ b/spec/ruby/library/socket/unixserver/accept_nonblock_spec.rb @@ -1,4 +1,4 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' describe "UNIXServer#accept_nonblock" do @@ -34,3 +34,59 @@ describe "UNIXServer#accept_nonblock" do end end end + +with_feature :unix_socket do + describe 'UNIXServer#accept_nonblock' do + before do + @path = SocketSpecs.socket_path + @server = UNIXServer.new(@path) + end + + after do + @server.close + rm_r(@path) + end + + describe 'without a client' do + it 'raises IO::WaitReadable' do + lambda { @server.accept_nonblock }.should raise_error(IO::WaitReadable) + end + end + + describe 'with a client' do + before do + @client = UNIXSocket.new(@path) + end + + after do + @client.close + @socket.close if @socket + end + + describe 'without any data' do + it 'returns a UNIXSocket' do + @socket = @server.accept_nonblock + @socket.should be_an_instance_of(UNIXSocket) + end + end + + describe 'with data available' do + before do + @client.write('hello') + end + + it 'returns a UNIXSocket' do + @socket = @server.accept_nonblock + @socket.should be_an_instance_of(UNIXSocket) + end + + describe 'the returned UNIXSocket' do + it 'can read the data written' do + @socket = @server.accept_nonblock + @socket.recv(5).should == 'hello' + end + end + end + end + end +end diff --git a/spec/ruby/library/socket/unixserver/accept_spec.rb b/spec/ruby/library/socket/unixserver/accept_spec.rb index 3c34fce59a..a1570f7013 100644 --- a/spec/ruby/library/socket/unixserver/accept_spec.rb +++ b/spec/ruby/library/socket/unixserver/accept_spec.rb @@ -1,4 +1,4 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' platform_is_not :windows do @@ -59,3 +59,59 @@ platform_is_not :windows do end end end + +with_feature :unix_socket do + describe 'UNIXServer#accept' do + before do + @path = SocketSpecs.socket_path + @server = UNIXServer.new(@path) + end + + after do + @server.close + rm_r(@path) + end + + describe 'without a client' do + it 'blocks the calling thread' do + lambda { @server.accept }.should block_caller + end + end + + describe 'with a client' do + before do + @client = UNIXSocket.new(@path) + end + + after do + @client.close + @socket.close if @socket + end + + describe 'without any data' do + it 'returns a UNIXSocket' do + @socket = @server.accept + @socket.should be_an_instance_of(UNIXSocket) + end + end + + describe 'with data available' do + before do + @client.write('hello') + end + + it 'returns a UNIXSocket' do + @socket = @server.accept + @socket.should be_an_instance_of(UNIXSocket) + end + + describe 'the returned UNIXSocket' do + it 'can read the data written' do + @socket = @server.accept + @socket.recv(5).should == 'hello' + end + end + end + end + end +end diff --git a/spec/ruby/library/socket/unixserver/for_fd_spec.rb b/spec/ruby/library/socket/unixserver/for_fd_spec.rb index 9f243c50a8..4f3816ad37 100644 --- a/spec/ruby/library/socket/unixserver/for_fd_spec.rb +++ b/spec/ruby/library/socket/unixserver/for_fd_spec.rb @@ -1,4 +1,4 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' platform_is_not :windows do diff --git a/spec/ruby/library/socket/unixserver/initialize_spec.rb b/spec/ruby/library/socket/unixserver/initialize_spec.rb new file mode 100644 index 0000000000..cb186ceb76 --- /dev/null +++ b/spec/ruby/library/socket/unixserver/initialize_spec.rb @@ -0,0 +1,28 @@ +require_relative '../spec_helper' +require_relative '../fixtures/classes' + +with_feature :unix_socket do + describe 'UNIXServer#initialize' do + before do + @path = SocketSpecs.socket_path + @server = UNIXServer.new(@path) + end + + after do + @server.close if @server + rm_r @path + end + + it 'returns a new UNIXServer' do + @server.should be_an_instance_of(UNIXServer) + end + + it 'sets the socket to binmode' do + @server.binmode?.should be_true + end + + it 'raises Errno::EADDRINUSE when the socket is already in use' do + lambda { UNIXServer.new(@path) }.should raise_error(Errno::EADDRINUSE) + end + end +end diff --git a/spec/ruby/library/socket/unixserver/listen_spec.rb b/spec/ruby/library/socket/unixserver/listen_spec.rb new file mode 100644 index 0000000000..b90b3bbb09 --- /dev/null +++ b/spec/ruby/library/socket/unixserver/listen_spec.rb @@ -0,0 +1,21 @@ +require_relative '../spec_helper' +require_relative '../fixtures/classes' + +with_feature :unix_socket do + describe 'UNIXServer#listen' do + before do + @path = SocketSpecs.socket_path + @server = UNIXServer.new(@path) + end + + after do + @server.close + + rm_r(@path) + end + + it 'returns 0' do + @server.listen(1).should == 0 + end + end +end diff --git a/spec/ruby/library/socket/unixserver/new_spec.rb b/spec/ruby/library/socket/unixserver/new_spec.rb index 0523054952..f831f40bc6 100644 --- a/spec/ruby/library/socket/unixserver/new_spec.rb +++ b/spec/ruby/library/socket/unixserver/new_spec.rb @@ -1,4 +1,4 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative 'shared/new' describe "UNIXServer.new" do diff --git a/spec/ruby/library/socket/unixserver/open_spec.rb b/spec/ruby/library/socket/unixserver/open_spec.rb index 3bbfff42e5..f2506d9f6f 100644 --- a/spec/ruby/library/socket/unixserver/open_spec.rb +++ b/spec/ruby/library/socket/unixserver/open_spec.rb @@ -1,4 +1,5 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' +require_relative '../fixtures/classes' require_relative 'shared/new' describe "UNIXServer.open" do diff --git a/spec/ruby/library/socket/unixserver/shared/new.rb b/spec/ruby/library/socket/unixserver/shared/new.rb index e19a1582b6..35395826c9 100644 --- a/spec/ruby/library/socket/unixserver/shared/new.rb +++ b/spec/ruby/library/socket/unixserver/shared/new.rb @@ -1,6 +1,5 @@ -require_relative '../../../../spec_helper' +require_relative '../../spec_helper' require_relative '../../fixtures/classes' -require 'tempfile' describe :unixserver_new, shared: true do platform_is_not :windows do diff --git a/spec/ruby/library/socket/unixserver/sysaccept_spec.rb b/spec/ruby/library/socket/unixserver/sysaccept_spec.rb new file mode 100644 index 0000000000..864913af82 --- /dev/null +++ b/spec/ruby/library/socket/unixserver/sysaccept_spec.rb @@ -0,0 +1,52 @@ +require_relative '../spec_helper' +require_relative '../fixtures/classes' + +with_feature :unix_socket do + describe 'UNIXServer#sysaccept' do + before do + @path = SocketSpecs.socket_path + @server = UNIXServer.new(@path) + end + + after do + @server.close + + rm_r(@path) + end + + describe 'without a client' do + it 'blocks the calling thread' do + lambda { @server.sysaccept }.should block_caller + end + end + + describe 'with a client' do + before do + @client = UNIXSocket.new(@path) + end + + after do + Socket.for_fd(@fd).close if @fd + @client.close + end + + describe 'without any data' do + it 'returns a Fixnum' do + @fd = @server.sysaccept + @fd.should be_an_instance_of(Fixnum) + end + end + + describe 'with data available' do + before do + @client.write('hello') + end + + it 'returns a Fixnum' do + @fd = @server.sysaccept + @fd.should be_an_instance_of(Fixnum) + end + end + end + end +end diff --git a/spec/ruby/library/socket/unixsocket/addr_spec.rb b/spec/ruby/library/socket/unixsocket/addr_spec.rb index 4fd3e30532..e8431bea16 100644 --- a/spec/ruby/library/socket/unixsocket/addr_spec.rb +++ b/spec/ruby/library/socket/unixsocket/addr_spec.rb @@ -1,4 +1,4 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' describe "UNIXSocket#addr" do @@ -16,8 +16,13 @@ describe "UNIXSocket#addr" do SocketSpecs.rm_socket @path end + it "returns an array" do + @client.addr.should be_kind_of(Array) + end + it "returns the address family of this socket in an array" do @client.addr[0].should == "AF_UNIX" + @server.addr[0].should == "AF_UNIX" end it "returns the path of the socket in an array if it's a server" do @@ -27,10 +32,5 @@ describe "UNIXSocket#addr" do it "returns an empty string for path if it's a client" do @client.addr[1].should == "" end - - it "returns an array" do - @client.addr.should be_kind_of(Array) - end end - end diff --git a/spec/ruby/library/socket/unixsocket/initialize_spec.rb b/spec/ruby/library/socket/unixsocket/initialize_spec.rb new file mode 100644 index 0000000000..a6217d404f --- /dev/null +++ b/spec/ruby/library/socket/unixsocket/initialize_spec.rb @@ -0,0 +1,38 @@ +require_relative '../spec_helper' +require_relative '../fixtures/classes' + +with_feature :unix_socket do + describe 'UNIXSocket#initialize' do + describe 'using a non existing path' do + it 'raises Errno::ENOENT' do + lambda { UNIXSocket.new(SocketSpecs.socket_path) }.should raise_error(Errno::ENOENT) + end + end + + describe 'using an existing socket path' do + before do + @path = SocketSpecs.socket_path + @server = UNIXServer.new(@path) + @socket = UNIXSocket.new(@path) + end + + after do + @socket.close + @server.close + rm_r(@path) + end + + it 'returns a new UNIXSocket' do + @socket.should be_an_instance_of(UNIXSocket) + end + + it 'sets the socket path to an empty String' do + @socket.path.should == '' + end + + it 'sets the socket to binmode' do + @socket.binmode?.should be_true + end + end + end +end diff --git a/spec/ruby/library/socket/unixsocket/inspect_spec.rb b/spec/ruby/library/socket/unixsocket/inspect_spec.rb index 52b2f508c0..d2e3cabbd3 100644 --- a/spec/ruby/library/socket/unixsocket/inspect_spec.rb +++ b/spec/ruby/library/socket/unixsocket/inspect_spec.rb @@ -1,4 +1,4 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' describe "UNIXSocket#inspect" do diff --git a/spec/ruby/library/socket/unixsocket/local_address_spec.rb b/spec/ruby/library/socket/unixsocket/local_address_spec.rb new file mode 100644 index 0000000000..8c77519830 --- /dev/null +++ b/spec/ruby/library/socket/unixsocket/local_address_spec.rb @@ -0,0 +1,45 @@ +require_relative '../spec_helper' +require_relative '../fixtures/classes' + +with_feature :unix_socket do + describe 'UNIXSocket#local_address' do + before do + @path = SocketSpecs.socket_path + @server = UNIXServer.new(@path) + @client = UNIXSocket.new(@path) + end + + after do + @client.close + @server.close + + rm_r(@path) + end + + it 'returns an Addrinfo' do + @client.local_address.should be_an_instance_of(Addrinfo) + end + + describe 'the returned Addrinfo' do + it 'uses AF_UNIX as the address family' do + @client.local_address.afamily.should == Socket::AF_UNIX + end + + it 'uses PF_UNIX as the protocol family' do + @client.local_address.pfamily.should == Socket::PF_UNIX + end + + it 'uses SOCK_STREAM as the socket type' do + @client.local_address.socktype.should == Socket::SOCK_STREAM + end + + it 'uses an empty socket path' do + @client.local_address.unix_path.should == '' + end + + it 'uses 0 as the protocol' do + @client.local_address.protocol.should == 0 + end + end + end +end diff --git a/spec/ruby/library/socket/unixsocket/new_spec.rb b/spec/ruby/library/socket/unixsocket/new_spec.rb index 8b87e9f8c2..05a6b3eda2 100644 --- a/spec/ruby/library/socket/unixsocket/new_spec.rb +++ b/spec/ruby/library/socket/unixsocket/new_spec.rb @@ -1,4 +1,4 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative 'shared/new' describe "UNIXSocket.new" do diff --git a/spec/ruby/library/socket/unixsocket/open_spec.rb b/spec/ruby/library/socket/unixsocket/open_spec.rb index d15487be94..6c4b7c5676 100644 --- a/spec/ruby/library/socket/unixsocket/open_spec.rb +++ b/spec/ruby/library/socket/unixsocket/open_spec.rb @@ -1,4 +1,5 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' +require_relative '../fixtures/classes' require_relative 'shared/new' describe "UNIXSocket.open" do diff --git a/spec/ruby/library/socket/unixsocket/pair_spec.rb b/spec/ruby/library/socket/unixsocket/pair_spec.rb index ba69776b53..845ff76ecc 100644 --- a/spec/ruby/library/socket/unixsocket/pair_spec.rb +++ b/spec/ruby/library/socket/unixsocket/pair_spec.rb @@ -1,4 +1,4 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' require_relative '../shared/partially_closable_sockets' diff --git a/spec/ruby/library/socket/unixsocket/partially_closable_spec.rb b/spec/ruby/library/socket/unixsocket/partially_closable_spec.rb index bbe1a8a5ba..78a64fe6be 100644 --- a/spec/ruby/library/socket/unixsocket/partially_closable_spec.rb +++ b/spec/ruby/library/socket/unixsocket/partially_closable_spec.rb @@ -1,4 +1,4 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' require_relative '../shared/partially_closable_sockets' diff --git a/spec/ruby/library/socket/unixsocket/path_spec.rb b/spec/ruby/library/socket/unixsocket/path_spec.rb index 9808e4132d..317ffc0975 100644 --- a/spec/ruby/library/socket/unixsocket/path_spec.rb +++ b/spec/ruby/library/socket/unixsocket/path_spec.rb @@ -1,4 +1,4 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' describe "UNIXSocket#path" do diff --git a/spec/ruby/library/socket/unixsocket/peeraddr_spec.rb b/spec/ruby/library/socket/unixsocket/peeraddr_spec.rb index bb22a38b8e..ec57b40970 100644 --- a/spec/ruby/library/socket/unixsocket/peeraddr_spec.rb +++ b/spec/ruby/library/socket/unixsocket/peeraddr_spec.rb @@ -1,4 +1,4 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' describe "UNIXSocket#peeraddr" do diff --git a/spec/ruby/library/socket/unixsocket/recv_io_spec.rb b/spec/ruby/library/socket/unixsocket/recv_io_spec.rb index 688f1b6436..533f02a0fa 100644 --- a/spec/ruby/library/socket/unixsocket/recv_io_spec.rb +++ b/spec/ruby/library/socket/unixsocket/recv_io_spec.rb @@ -1,4 +1,4 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' describe "UNIXSocket#recv_io" do @@ -38,7 +38,50 @@ describe "UNIXSocket#recv_io" do @socket = @server.accept @io = @socket.recv_io(File) - @io.should be_kind_of(File) + @io.should be_an_instance_of(File) + end + end +end + +with_feature :unix_socket do + describe 'UNIXSocket#recv_io' do + before do + @file = File.open('/dev/null', 'w') + @client, @server = UNIXSocket.socketpair + end + + after do + @client.close + @server.close + @io.close if @io + @file.close + end + + describe 'without a custom class' do + it 'returns an IO' do + @client.send_io(@file) + + @io = @server.recv_io + @io.should be_an_instance_of(IO) + end + end + + describe 'with a custom class' do + it 'returns an instance of the custom class' do + @client.send_io(@file) + + @io = @server.recv_io(File) + @io.should be_an_instance_of(File) + end + end + + describe 'with a custom mode' do + it 'opens the IO using the given mode' do + @client.send_io(@file) + + @io = @server.recv_io(File, File::WRONLY) + @io.should be_an_instance_of(File) + end end end end diff --git a/spec/ruby/library/socket/unixsocket/recvfrom_spec.rb b/spec/ruby/library/socket/unixsocket/recvfrom_spec.rb index d142d84fdc..f24caaf686 100644 --- a/spec/ruby/library/socket/unixsocket/recvfrom_spec.rb +++ b/spec/ruby/library/socket/unixsocket/recvfrom_spec.rb @@ -1,8 +1,7 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' describe "UNIXSocket#recvfrom" do - platform_is_not :windows do before :each do @path = SocketSpecs.socket_path @@ -43,5 +42,56 @@ describe "UNIXSocket#recvfrom" do sock.close end end +end + + +with_feature :unix_socket do + describe 'UNIXSocket#recvfrom' do + describe 'using a socket pair' do + before do + @client, @server = UNIXSocket.socketpair + @client.write('hello') + end + + after do + @client.close + @server.close + end + + it 'returns an Array containing the data and address information' do + @server.recvfrom(5).should == ['hello', ['AF_UNIX', '']] + end + end + + # These specs are taken from the rdoc examples on UNIXSocket#recvfrom. + describe 'using a UNIX socket constructed using UNIXSocket.for_fd' do + before do + @path1 = SocketSpecs.socket_path + @path2 = SocketSpecs.socket_path + '2' + rm_r(@path2) + @client_raw = Socket.new(:UNIX, :DGRAM) + @client_raw.bind(Socket.sockaddr_un(@path1)) + + @server_raw = Socket.new(:UNIX, :DGRAM) + @server_raw.bind(Socket.sockaddr_un(@path2)) + + @socket = UNIXSocket.for_fd(@server_raw.fileno) + end + + after do + @client_raw.close + @server_raw.close # also closes @socket + + rm_r @path1 + rm_r @path2 + end + + it 'returns an Array containing the data and address information' do + @client_raw.send('hello', 0, Socket.sockaddr_un(@path2)) + + @socket.recvfrom(5).should == ['hello', ['AF_UNIX', @path1]] + end + end + end end diff --git a/spec/ruby/library/socket/unixsocket/remote_address_spec.rb b/spec/ruby/library/socket/unixsocket/remote_address_spec.rb new file mode 100644 index 0000000000..0b416254d0 --- /dev/null +++ b/spec/ruby/library/socket/unixsocket/remote_address_spec.rb @@ -0,0 +1,45 @@ +require_relative '../spec_helper' +require_relative '../fixtures/classes' + +with_feature :unix_socket do + describe 'UNIXSocket#remote_address' do + before do + @path = SocketSpecs.socket_path + @server = UNIXServer.new(@path) + @client = UNIXSocket.new(@path) + end + + after do + @client.close + @server.close + + rm_r(@path) + end + + it 'returns an Addrinfo' do + @client.remote_address.should be_an_instance_of(Addrinfo) + end + + describe 'the returned Addrinfo' do + it 'uses AF_UNIX as the address family' do + @client.remote_address.afamily.should == Socket::AF_UNIX + end + + it 'uses PF_UNIX as the protocol family' do + @client.remote_address.pfamily.should == Socket::PF_UNIX + end + + it 'uses SOCK_STREAM as the socket type' do + @client.remote_address.socktype.should == Socket::SOCK_STREAM + end + + it 'uses the correct socket path' do + @client.remote_address.unix_path.should == @path + end + + it 'uses 0 as the protocol' do + @client.remote_address.protocol.should == 0 + end + end + end +end diff --git a/spec/ruby/library/socket/unixsocket/send_io_spec.rb b/spec/ruby/library/socket/unixsocket/send_io_spec.rb index fbc99be38d..a2a7d26539 100644 --- a/spec/ruby/library/socket/unixsocket/send_io_spec.rb +++ b/spec/ruby/library/socket/unixsocket/send_io_spec.rb @@ -1,4 +1,4 @@ -require_relative '../../../spec_helper' +require_relative '../spec_helper' require_relative '../fixtures/classes' describe "UNIXSocket#send_io" do @@ -33,3 +33,26 @@ describe "UNIXSocket#send_io" do end end end + +with_feature :unix_socket do + describe 'UNIXSocket#send_io' do + before do + @file = File.open('/dev/null', 'w') + @client, @server = UNIXSocket.socketpair + end + + after do + @client.close + @server.close + @io.close if @io + @file.close + end + + it 'sends an IO object' do + @client.send_io(@file) + + @io = @server.recv_io + @io.should be_an_instance_of(IO) + end + end +end diff --git a/spec/ruby/library/socket/unixsocket/shared/new.rb b/spec/ruby/library/socket/unixsocket/shared/new.rb index afb57f95cf..76a4e1701e 100644 --- a/spec/ruby/library/socket/unixsocket/shared/new.rb +++ b/spec/ruby/library/socket/unixsocket/shared/new.rb @@ -1,4 +1,4 @@ -require_relative '../../../../spec_helper' +require_relative '../../spec_helper' require_relative '../../fixtures/classes' describe :unixsocket_new, shared: true do diff --git a/spec/ruby/library/socket/unixsocket/socketpair_spec.rb b/spec/ruby/library/socket/unixsocket/socketpair_spec.rb new file mode 100644 index 0000000000..3e9646f76b --- /dev/null +++ b/spec/ruby/library/socket/unixsocket/socketpair_spec.rb @@ -0,0 +1,40 @@ +require_relative '../spec_helper' + +with_feature :unix_socket do + describe 'UNIXSocket.socketpair' do + before do + @s1, @s2 = UNIXSocket.socketpair + end + + after do + @s1.close + @s2.close + end + + it 'returns two UNIXSockets' do + @s1.should be_an_instance_of(UNIXSocket) + @s2.should be_an_instance_of(UNIXSocket) + end + + it 'connects the sockets to each other' do + @s1.write('hello') + + @s2.recv(5).should == 'hello' + end + + it 'sets the socket paths to empty Strings' do + @s1.path.should == '' + @s2.path.should == '' + end + + it 'sets the socket addresses to empty Strings' do + @s1.addr.should == ['AF_UNIX', ''] + @s2.addr.should == ['AF_UNIX', ''] + end + + it 'sets the socket peer addresses to empty Strings' do + @s1.peeraddr.should == ['AF_UNIX', ''] + @s2.peeraddr.should == ['AF_UNIX', ''] + end + end +end diff --git a/spec/ruby/library/weakref/allocate_spec.rb b/spec/ruby/library/weakref/allocate_spec.rb new file mode 100644 index 0000000000..76e81c4e5e --- /dev/null +++ b/spec/ruby/library/weakref/allocate_spec.rb @@ -0,0 +1,8 @@ +require_relative '../../spec_helper' +require 'weakref' + +describe "WeakRef#allocate" do + it "assigns nil as the reference" do + lambda { WeakRef.allocate.__getobj__ }.should raise_error(WeakRef::RefError) + end +end diff --git a/spec/ruby/library/weakref/new_spec.rb b/spec/ruby/library/weakref/new_spec.rb new file mode 100644 index 0000000000..6290e61fe3 --- /dev/null +++ b/spec/ruby/library/weakref/new_spec.rb @@ -0,0 +1,13 @@ +require_relative '../../spec_helper' +require 'weakref' + +describe "WeakRef#new" do + it "creates a subclass correctly" do + wr2 = Class.new(WeakRef) { + def __getobj__ + :dummy + end + } + wr2.new(Object.new).__getobj__.should == :dummy + end +end diff --git a/spec/ruby/library/zlib/deflate/deflate_spec.rb b/spec/ruby/library/zlib/deflate/deflate_spec.rb index 67bcf22d49..828880f8d8 100644 --- a/spec/ruby/library/zlib/deflate/deflate_spec.rb +++ b/spec/ruby/library/zlib/deflate/deflate_spec.rb @@ -25,7 +25,7 @@ describe "Zlib::Deflate.deflate" do random_generator = Random.new(0) deflated = '' - Zlib.deflate(random_generator.bytes(20000)) do |chunk| + Zlib::Deflate.deflate(random_generator.bytes(20000)) do |chunk| deflated << chunk end diff --git a/spec/ruby/library/zlib/deflate_spec.rb b/spec/ruby/library/zlib/deflate_spec.rb new file mode 100644 index 0000000000..01538dd4e6 --- /dev/null +++ b/spec/ruby/library/zlib/deflate_spec.rb @@ -0,0 +1,8 @@ +require_relative '../../spec_helper' +require "zlib" + +describe "Zlib#deflate" do + it "deflates some data" do + Zlib.deflate("1" * 10).should == [120, 156, 51, 52, 132, 1, 0, 10, 145, 1, 235].pack('C*') + end +end diff --git a/spec/ruby/library/zlib/inflate_spec.rb b/spec/ruby/library/zlib/inflate_spec.rb new file mode 100644 index 0000000000..393bea4f3c --- /dev/null +++ b/spec/ruby/library/zlib/inflate_spec.rb @@ -0,0 +1,8 @@ +require_relative '../../spec_helper' +require "zlib" + +describe "Zlib#inflate" do + it "inflates some data" do + Zlib.inflate([120, 156, 51, 52, 132, 1, 0, 10, 145, 1, 235].pack('C*')).should == "1" * 10 + end +end -- cgit v1.2.3