Repository: rust-lang/socket2
Pull request #157 (2020-12-20 23:29:06)

Move tests


Patch:
diff --git a/Cargo.toml b/Cargo.toml
index 6c106ea..e7bab65 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -38,9 +38,6 @@ libc = "0.2.81"
 [target."cfg(windows)".dependencies]
 winapi = { version = "0.3.9", features = ["handleapi", "ws2ipdef", "ws2tcpip"] }
 
-[dev-dependencies]
-tempdir = "0.3"
-
 [features]
 # Enable all API, even ones not available on all OSes.
 all = []
diff --git a/src/lib.rs b/src/lib.rs
index 12294a6..1c9f725 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -123,9 +123,6 @@ mod sockaddr;
 mod socket;
 mod sockref;
 
-#[cfg(test)]
-mod tests;
-
 #[cfg(unix)]
 #[path = "sys/unix.rs"]
 mod sys;
diff --git a/src/sockaddr.rs b/src/sockaddr.rs
index f7f58d8..f2cc00b 100644
--- a/src/sockaddr.rs
+++ b/src/sockaddr.rs
@@ -233,28 +233,40 @@ impl fmt::Debug for SockAddr {
     }
 }
 
-#[cfg(test)]
-mod tests {
-    use super::*;
-    use std::net::{Ipv4Addr, Ipv6Addr};
+#[test]
+fn ipv4() {
+    use std::net::Ipv4Addr;
+    let std = SocketAddrV4::new(Ipv4Addr::new(1, 2, 3, 4), 9876);
+    let addr = SockAddr::from(std);
+    assert_eq!(addr.family(), AF_INET as sa_family_t);
+    assert_eq!(addr.len(), size_of::<sockaddr_in>() as socklen_t);
+    assert_eq!(addr.as_std(), Some(SocketAddr::V4(std)));
+    assert_eq!(addr.as_inet(), Some(std));
+    assert!(addr.as_inet6().is_none());
 
-    #[test]
-    fn conversion_v4() {
-        let addr = SocketAddrV4::new(Ipv4Addr::new(1, 2, 3, 4), 9876);
-        let sockaddr = SockAddr::from(addr);
-        assert_eq!(sockaddr.family(), AF_INET as sa_family_t);
-        assert!(sockaddr.as_inet6().is_none());
-        assert_eq!(sockaddr.as_inet(), Some(addr));
-        assert_eq!(sockaddr.as_std(), Some(SocketAddr::V4(addr)));
-    }
+    let addr = SockAddr::from(SocketAddr::from(std));
+    assert_eq!(addr.family(), AF_INET as sa_family_t);
+    assert_eq!(addr.len(), size_of::<sockaddr_in>() as socklen_t);
+    assert_eq!(addr.as_std(), Some(SocketAddr::V4(std)));
+    assert_eq!(addr.as_inet(), Some(std));
+    assert!(addr.as_inet6().is_none());
+}
 
-    #[test]
-    fn conversion_v6() {
-        let addr = SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9876, 11, 12);
-        let sockaddr = SockAddr::from(addr);
-        assert_eq!(sockaddr.family(), AF_INET6 as sa_family_t);
-        assert!(sockaddr.as_inet().is_none());
-        assert_eq!(sockaddr.as_inet6(), Some(addr));
-        assert_eq!(sockaddr.as_std(), Some(SocketAddr::V6(addr)));
-    }
+#[test]
+fn ipv6() {
+    use std::net::Ipv6Addr;
+    let std = SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9876, 11, 12);
+    let addr = SockAddr::from(std);
+    assert_eq!(addr.family(), AF_INET6 as sa_family_t);
+    assert_eq!(addr.len(), size_of::<sockaddr_in6>() as socklen_t);
+    assert_eq!(addr.as_std(), Some(SocketAddr::V6(std)));
+    assert!(addr.as_inet().is_none());
+    assert_eq!(addr.as_inet6(), Some(std));
+
+    let addr = SockAddr::from(SocketAddr::from(std));
+    assert_eq!(addr.family(), AF_INET6 as sa_family_t);
+    assert_eq!(addr.len(), size_of::<sockaddr_in6>() as socklen_t);
+    assert_eq!(addr.as_std(), Some(SocketAddr::V6(std)));
+    assert!(addr.as_inet().is_none());
+    assert_eq!(addr.as_inet6(), Some(std));
 }
diff --git a/src/socket.rs b/src/socket.rs
index 0e50b15..c025cfa 100644
--- a/src/socket.rs
+++ b/src/socket.rs
@@ -295,7 +295,6 @@ impl Socket {
     ///
     /// [`recv`]: Socket::recv
     /// [`out_of_band_inline`]: Socket::out_of_band_inline
-    #[cfg(feature = "all")]
     pub fn recv_out_of_band(&self, buf: &mut [u8]) -> io::Result<usize> {
         self.recv_with_flags(buf, sys::MSG_OOB)
     }
@@ -443,7 +442,6 @@ impl Socket {
     ///
     /// [`send`]: #method.send
     /// [`out_of_band_inline`]: #method.out_of_band_inline
-    #[cfg(feature = "all")]
     pub fn send_out_of_band(&self, buf: &[u8]) -> io::Result<usize> {
         self.send_with_flags(buf, sys::MSG_OOB)
     }
@@ -1315,109 +1313,3 @@ impl Drop for Socket {
         sys::close(self.inner);
     }
 }
-
-#[cfg(test)]
-mod test {
-    use std::net::SocketAddr;
-
-    use super::*;
-
-    #[test]
-    #[cfg(all(feature = "all", unix))]
-    fn pair() {
-        let (mut a, mut b) = Socket::pair(Domain::UNIX, Type::STREAM, None).unwrap();
-        a.write_all(b"hello world").unwrap();
-        let mut buf = [0; 11];
-        b.read_exact(&mut buf).unwrap();
-        assert_eq!(buf, &b"hello world"[..]);
-    }
-
-    #[test]
-    #[cfg(all(feature = "all", unix))]
-    fn unix() {
-        use tempdir::TempDir;
-
-        let dir = TempDir::new("unix").unwrap();
-        let addr = SockAddr::unix(dir.path().join("sock")).unwrap();
-
-        let listener = Socket::new(Domain::UNIX, Type::STREAM, None).unwrap();
-        listener.bind(&addr).unwrap();
-        listener.listen(10).unwrap();
-
-        let mut a = Socket::new(Domain::UNIX, Type::STREAM, None).unwrap();
-        a.connect(&addr).unwrap();
-
-        let mut b = listener.accept().unwrap().0;
-
-        a.write_all(b"hello world").unwrap();
-        let mut buf = [0; 11];
-        b.read_exact(&mut buf).unwrap();
-        assert_eq!(buf, &b"hello world"[..]);
-    }
-
-    #[test]
-    fn nodelay() {
-        let socket = Socket::new(Domain::IPV4, Type::STREAM, None).unwrap();
-
-        assert!(socket.set_nodelay(true).is_ok());
-
-        let result = socket.nodelay();
-
-        assert!(result.is_ok());
-        assert!(result.unwrap());
-    }
-
-    #[test]
-    #[cfg(feature = "all")]
-    fn out_of_band_inline() {
-        let socket = Socket::new(Domain::IPV4, Type::STREAM, None).unwrap();
-
-        assert_eq!(socket.out_of_band_inline().unwrap(), false);
-
-        socket.set_out_of_band_inline(true).unwrap();
-        assert_eq!(socket.out_of_band_inline().unwrap(), true);
-    }
-
-    #[test]
-    #[cfg(all(feature = "all", any(windows, target_os = "linux")))]
-    fn out_of_band_send_recv() {
-        let s1 = Socket::new(Domain::IPV4, Type::STREAM, None).unwrap();
-        s1.bind(&"127.0.0.1:0".parse::<SocketAddr>().unwrap().into())
-            .unwrap();
-        let s1_addr = s1.local_addr().unwrap();
-        s1.listen(1).unwrap();
-
-        let s2 = Socket::new(Domain::IPV4, Type::STREAM, None).unwrap();
-        s2.connect(&s1_addr).unwrap();
-
-        let (s3, _) = s1.accept().unwrap();
-
-        let mut buf = [0; 10];
-        // send some plain inband data
-        s2.send(&mut buf).unwrap();
-        // send a single out of band byte
-        assert_eq!(s2.send_out_of_band(&mut [b"!"[0]]).unwrap(), 1);
-        // recv the OOB data first
-        assert_eq!(s3.recv_out_of_band(&mut buf).unwrap(), 1);
-        assert_eq!(buf[0], b"!"[0]);
-        assert_eq!(s3.recv(&mut buf).unwrap(), 10);
-    }
-
-    #[test]
-    fn tcp() {
-        let s1 = Socket::new(Domain::IPV4, Type::STREAM, None).unwrap();
-        s1.bind(&"127.0.0.1:0".parse::<SocketAddr>().unwrap().into())
-            .unwrap();
-        let s1_addr = s1.local_addr().unwrap();
-        s1.listen(1).unwrap();
-
-        let s2 = Socket::new(Domain::IPV4, Type::STREAM, None).unwrap();
-        s2.connect(&s1_addr).unwrap();
-
-        let (s3, _) = s1.accept().unwrap();
-
-        let mut buf = [0; 11];
-        assert_eq!(s2.send(&mut buf).unwrap(), 11);
-        assert_eq!(s3.recv(&mut buf).unwrap(), 11);
-    }
-}
diff --git a/src/sys/unix.rs b/src/sys/unix.rs
index 1a0f24e..84699b7 100644
--- a/src/sys/unix.rs
+++ b/src/sys/unix.rs
@@ -54,14 +54,12 @@ pub(crate) use libc::{
 #[cfg(not(target_os = "redox"))]
 pub(crate) use libc::MSG_TRUNC;
 // Used in `Socket`.
-#[cfg(feature = "all")]
-pub(crate) use libc::MSG_OOB;
 pub(crate) use libc::{
     ip_mreq as IpMreq, ipv6_mreq as Ipv6Mreq, linger, IPPROTO_IP, IPPROTO_IPV6,
     IPV6_MULTICAST_HOPS, IPV6_MULTICAST_IF, IPV6_MULTICAST_LOOP, IPV6_UNICAST_HOPS, IPV6_V6ONLY,
     IP_ADD_MEMBERSHIP, IP_DROP_MEMBERSHIP, IP_MULTICAST_IF, IP_MULTICAST_LOOP, IP_MULTICAST_TTL,
-    IP_TTL, MSG_PEEK, SOL_SOCKET, SO_BROADCAST, SO_ERROR, SO_KEEPALIVE, SO_LINGER, SO_OOBINLINE,
-    SO_RCVBUF, SO_RCVTIMEO, SO_REUSEADDR, SO_SNDBUF, SO_SNDTIMEO, TCP_NODELAY,
+    IP_TTL, MSG_OOB, MSG_PEEK, SOL_SOCKET, SO_BROADCAST, SO_ERROR, SO_KEEPALIVE, SO_LINGER,
+    SO_OOBINLINE, SO_RCVBUF, SO_RCVTIMEO, SO_REUSEADDR, SO_SNDBUF, SO_SNDTIMEO, TCP_NODELAY,
 };
 #[cfg(not(any(
     target_os = "dragonfly",
@@ -721,14 +719,14 @@ pub(crate) fn from_in_addr(in_addr: in_addr) -> Ipv4Addr {
     Ipv4Addr::from(in_addr.s_addr.to_ne_bytes())
 }
 
-pub(crate) fn to_in6_addr(addr: &Ipv6Addr) -> libc::in6_addr {
-    let mut ret: libc::in6_addr = unsafe { mem::zeroed() };
+pub(crate) fn to_in6_addr(addr: &Ipv6Addr) -> in6_addr {
+    let mut ret: in6_addr = unsafe { mem::zeroed() };
     ret.s6_addr = addr.octets();
     return ret;
 }
 
-pub(crate) fn from_in6_addr(in6_addr: in6_addr) -> Ipv6Addr {
-    Ipv6Addr::from(in6_addr.s6_addr)
+pub(crate) fn from_in6_addr(addr: in6_addr) -> Ipv6Addr {
+    Ipv6Addr::from(addr.s6_addr)
 }
 
 /// Unix only API.
@@ -1049,12 +1047,23 @@ from!(crate::Socket, UnixListener);
 from!(crate::Socket, UnixDatagram);
 
 #[test]
-fn test_ip() {
+fn in_addr_convertion() {
     let ip = Ipv4Addr::new(127, 0, 0, 1);
-    assert_eq!(ip, from_in_addr(to_in_addr(&ip)));
+    let raw = to_in_addr(&ip);
+    assert_eq!(raw.s_addr, 127 << 0 | 1 << 24);
+    assert_eq!(from_in_addr(raw), ip);
 
     let ip = Ipv4Addr::new(127, 34, 4, 12);
-    let want = 127 << 0 | 34 << 8 | 4 << 16 | 12 << 24;
-    assert_eq!(to_in_addr(&ip).s_addr, want);
-    assert_eq!(from_in_addr(in_addr { s_addr: want }), ip);
+    let raw = to_in_addr(&ip);
+    assert_eq!(raw.s_addr, 127 << 0 | 34 << 8 | 4 << 16 | 12 << 24);
+    assert_eq!(from_in_addr(raw), ip);
+}
+
+#[test]
+fn in6_addr_convertion() {
+    let ip = Ipv6Addr::new(0x2000, 1, 2, 3, 4, 5, 6, 7);
+    let raw = to_in6_addr(&ip);
+    let want = [32, 0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7];
+    assert_eq!(raw.s6_addr, want);
+    assert_eq!(from_in6_addr(raw), ip);
 }
diff --git a/src/sys/windows.rs b/src/sys/windows.rs
index 42b8b16..3720eef 100644
--- a/src/sys/windows.rs
+++ b/src/sys/windows.rs
@@ -66,9 +66,7 @@ pub(crate) use winapi::shared::ws2ipdef::{
     IP_DROP_MEMBERSHIP, IP_MREQ as IpMreq, IP_MULTICAST_IF, IP_MULTICAST_LOOP, IP_MULTICAST_TTL,
     IP_TTL,
 };
-#[cfg(all(windows, feature = "all"))]
-pub(crate) use winapi::um::winsock2::MSG_OOB;
-pub(crate) use winapi::um::winsock2::{linger, MSG_PEEK};
+pub(crate) use winapi::um::winsock2::{linger, MSG_OOB, MSG_PEEK};
 pub(crate) const IPPROTO_IPV6: c_int = winapi::shared::ws2def::IPPROTO_IPV6 as c_int;
 
 /// Type used in set/getsockopt to retrieve the `TCP_NODELAY` option.
@@ -632,8 +630,8 @@ pub(crate) fn to_in6_addr(addr: &Ipv6Addr) -> in6_addr {
     ret
 }
 
-pub(crate) fn from_in6_addr(in6_addr: in6_addr) -> Ipv6Addr {
-    Ipv6Addr::from(*unsafe { in6_addr.u.Byte() })
+pub(crate) fn from_in6_addr(addr: in6_addr) -> Ipv6Addr {
+    Ipv6Addr::from(*unsafe { addr.u.Byte() })
 }
 
 /// Windows only API.
@@ -686,24 +684,25 @@ impl FromRawSocket for crate::Socket {
 }
 
 #[test]
-fn test_ipv4() {
+fn in_addr_convertion() {
     let ip = Ipv4Addr::new(127, 0, 0, 1);
-    assert_eq!(ip, from_in_addr(to_in_addr(&ip)));
+    let raw = to_in_addr(&ip);
+    assert_eq!(unsafe { *raw.S_un.S_addr() }, 127 << 0 | 1 << 24);
+    assert_eq!(from_in_addr(raw), ip);
 
     let ip = Ipv4Addr::new(127, 34, 4, 12);
-    let want = 127 << 0 | 34 << 8 | 4 << 16 | 12 << 24;
-    assert_eq!(unsafe { *to_in_addr(&ip).S_un.S_addr() }, want);
-    let mut addr: in_addr_S_un = unsafe { mem::zeroed() };
-    unsafe { *(addr.S_addr_mut()) = want };
-    assert_eq!(from_in_addr(IN_ADDR { S_un: addr }), ip);
+    let raw = to_in_addr(&ip);
+    assert_eq!(
+        unsafe { *raw.S_un.S_addr() },
+        127 << 0 | 34 << 8 | 4 << 16 | 12 << 24
+    );
+    assert_eq!(from_in_addr(raw), ip);
 }
 
 #[test]
-fn test_ipv6() {
-    let ip = Ipv6Addr::new(0x2000, 1, 2, 3, 4, 5, 6, 7);
-    assert_eq!(ip, from_in6_addr(to_in6_addr(&ip)));
-
+fn in6_addr_convertion() {
     let ip = Ipv6Addr::new(0x2000, 1, 2, 3, 4, 5, 6, 7);
+    let raw = to_in6_addr(&ip);
     let want = [
         0x2000u16.to_be(),
         1u16.to_be(),
@@ -714,8 +713,6 @@ fn test_ipv6() {
         6u16.to_be(),
         7u16.to_be(),
     ];
-    assert_eq!(unsafe { *to_in6_addr(&ip).u.Word() }, want);
-    let mut addr: in6_addr_u = unsafe { mem::zeroed() };
-    unsafe { *(addr.Word_mut()) = want };
-    assert_eq!(from_in6_addr(IN6_ADDR { u: addr }), ip);
+    assert_eq!(unsafe { *raw.u.Word() }, want);
+    assert_eq!(from_in6_addr(raw), ip);
 }


Test patch:
diff --git a/src/tests.rs b/src/tests.rs
deleted file mode 100644
index 4b51568..0000000
--- a/src/tests.rs
+++ /dev/null
@@ -1,293 +0,0 @@
-use std::io::Write;
-use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6};
-use std::str;
-
-use crate::{Domain, Protocol, SockAddr, Socket, Type};
-
-#[test]
-fn domain_for_address() {
-    let ipv4: SocketAddr = "127.0.0.1:8080".parse().unwrap();
-    assert!(ipv4.is_ipv4());
-    let ipv6: SocketAddr = "[::1]:8080".parse().unwrap();
-    assert!(ipv6.is_ipv6());
-
-    assert_eq!(Domain::for_address(ipv4), Domain::IPV4);
-    assert_eq!(Domain::for_address(ipv6), Domain::IPV6);
-}
-
-#[test]
-fn domain_fmt_debug() {
-    let tests = &[
-        (Domain::IPV4, "AF_INET"),
-        (Domain::IPV6, "AF_INET6"),
-        #[cfg(unix)]
-        (Domain::UNIX, "AF_UNIX"),
-        #[cfg(all(feature = "all", target_os = "linux"))]
-        (Domain::PACKET, "AF_PACKET"),
-        (0.into(), "AF_UNSPEC"),
-        (500.into(), "500"),
-    ];
-
-    let mut buf = Vec::new();
-    for (input, want) in tests {
-        buf.clear();
-        write!(buf, "{:?}", input).unwrap();
-        let got = str::from_utf8(&buf).unwrap();
-        assert_eq!(got, *want);
-    }
-}
-
-#[test]
-fn type_fmt_debug() {
-    let tests = &[
-        (Type::STREAM, "SOCK_STREAM"),
-        (Type::DGRAM, "SOCK_DGRAM"),
-        #[cfg(all(feature = "all", not(target_os = "redox")))]
-        (Type::SEQPACKET, "SOCK_SEQPACKET"),
-        #[cfg(all(feature = "all", not(target_os = "redox")))]
-        (Type::RAW, "SOCK_RAW"),
-        (500.into(), "500"),
-    ];
-
-    let mut buf = Vec::new();
-    for (input, want) in tests {
-        buf.clear();
-        write!(buf, "{:?}", input).unwrap();
-        let got = str::from_utf8(&buf).unwrap();
-        assert_eq!(got, *want);
-    }
-}
-
-#[test]
-fn protocol_fmt_debug() {
-    let tests = &[
-        (Protocol::ICMPV4, "IPPROTO_ICMP"),
-        (Protocol::ICMPV6, "IPPROTO_ICMPV6"),
-        (Protocol::TCP, "IPPROTO_TCP"),
-        (Protocol::UDP, "IPPROTO_UDP"),
-        (500.into(), "500"),
-    ];
-
-    let mut buf = Vec::new();
-    for (input, want) in tests {
-        buf.clear();
-        write!(buf, "{:?}", input).unwrap();
-        let got = str::from_utf8(&buf).unwrap();
-        assert_eq!(got, *want);
-    }
-}
-
-#[test]
-fn socket_address_ipv4() {
-    let string = "127.0.0.1:80";
-    let std = string.parse::<SocketAddrV4>().unwrap();
-    let addr = SockAddr::from(std);
-
-    assert_eq!(addr.as_std(), Some(SocketAddr::V4(std)));
-    assert_eq!(addr.as_inet(), Some(std));
-    assert!(addr.as_inet6().is_none());
-}
-
-#[test]
-fn socket_address_ipv6() {
-    let string = "[2001:db8::ff00:42:8329]:80";
-    let std = string.parse::<SocketAddrV6>().unwrap();
-    let addr = SockAddr::from(std);
-
-    assert_eq!(addr.as_std(), Some(SocketAddr::V6(std)));
-    assert!(addr.as_inet().is_none());
-    assert_eq!(addr.as_inet6(), Some(std));
-}
-
-#[test]
-#[cfg(all(unix, feature = "all"))]
-fn socket_address_unix() {
-    let string = "/tmp/socket";
-    let addr = SockAddr::unix(string).unwrap();
-    assert!(addr.as_inet().is_none());
-    assert!(addr.as_inet6().is_none());
-}
-
-/// Create a pair of non-connected UDP sockets suitable for unit tests.
-#[cfg(not(target_os = "redox"))]
-fn udp_pair_unconnected() -> (Socket, Socket) {
-    // Use ephemeral ports assigned by the OS.
-    let unspecified_addr = std::net::SocketAddrV6::new(std::net::Ipv6Addr::LOCALHOST, 0, 0, 0);
-    let socket_a = Socket::new(Domain::IPV6, Type::DGRAM, None).unwrap();
-    let socket_b = Socket::new(Domain::IPV6, Type::DGRAM, None).unwrap();
-
-    socket_a.bind(&unspecified_addr.into()).unwrap();
-    socket_b.bind(&unspecified_addr.into()).unwrap();
-
-    // Set low timeouts to prevent the tests from blocking.
-    socket_a
-        .set_read_timeout(Some(std::time::Duration::from_millis(10)))
-        .unwrap();
-    socket_b
-        .set_read_timeout(Some(std::time::Duration::from_millis(10)))
-        .unwrap();
-    socket_a
-        .set_write_timeout(Some(std::time::Duration::from_millis(10)))
-        .unwrap();
-    socket_b
-        .set_write_timeout(Some(std::time::Duration::from_millis(10)))
-        .unwrap();
-
-    (socket_a, socket_b)
-}
-
-/// Create a pair of connected UDP sockets suitable for unit tests.
-#[cfg(not(target_os = "redox"))]
-fn udp_pair_connected() -> (Socket, Socket) {
-    let (socket_a, socket_b) = udp_pair_unconnected();
-
-    let addr_a = socket_a.local_addr().unwrap();
-    let addr_b = socket_b.local_addr().unwrap();
-    socket_a.connect(&addr_b).unwrap();
-    socket_b.connect(&addr_a).unwrap();
-
-    (socket_a, socket_b)
-}
-
-#[test]
-#[cfg(not(target_os = "redox"))]
-fn send_recv_vectored() {
-    use std::io::{IoSlice, IoSliceMut};
-
-    let (socket_a, socket_b) = udp_pair_connected();
-
-    let sent = socket_a
-        .send_vectored(&[
-            IoSlice::new(b"the"),
-            IoSlice::new(b"weeknight"),
-            IoSlice::new(b"would"),
-            IoSlice::new(b"yellow"),
-        ])
-        .unwrap();
-    assert_eq!(sent, 23);
-
-    let mut the = [0u8; 3];
-    let mut wee = [0u8; 3];
-    let mut knight = [0u8; 6];
-    let mut would = [0u8; 5];
-    let mut yell = [0u8; 4];
-    let mut ow = [0u8; 2];
-
-    let (received, flags) = socket_b
-        .recv_vectored(&mut [
-            IoSliceMut::new(&mut the),
-            IoSliceMut::new(&mut wee),
-            IoSliceMut::new(&mut knight),
-            IoSliceMut::new(&mut would),
-            IoSliceMut::new(&mut yell),
-            IoSliceMut::new(&mut ow),
-        ])
-        .unwrap();
-    assert_eq!(received, 23);
-    #[cfg(all(unix, not(target_os = "redox")))]
-    assert_eq!(flags.is_end_of_record(), false);
-    #[cfg(all(unix, not(target_os = "redox")))]
-    assert_eq!(flags.is_out_of_band(), false);
-    assert_eq!(flags.is_truncated(), false);
-
-    assert_eq!(&the, b"the");
-    assert_eq!(&wee, b"wee");
-    assert_eq!(&knight, b"knight");
-    assert_eq!(&would, b"would");
-    assert_eq!(&yell, b"yell");
-    assert_eq!(&ow, b"ow");
-}
-
-#[test]
-#[cfg(not(target_os = "redox"))]
-fn send_from_recv_to_vectored() {
-    use std::io::{IoSlice, IoSliceMut};
-
-    let (socket_a, socket_b) = udp_pair_unconnected();
-    let addr_a = socket_a.local_addr().unwrap();
-    let addr_b = socket_b.local_addr().unwrap();
-
-    let sent = socket_a
-        .send_to_vectored(
-            &[
-                IoSlice::new(b"surgeon"),
-                IoSlice::new(b"has"),
-                IoSlice::new(b"menswear"),
-            ],
-            &addr_b,
-        )
-        .unwrap();
-    assert_eq!(sent, 18);
-
-    let mut surgeon = [0u8; 7];
-    let mut has = [0u8; 3];
-    let mut men = [0u8; 3];
-    let mut swear = [0u8; 5];
-    let (received, flags, addr) = socket_b
-        .recv_from_vectored(&mut [
-            IoSliceMut::new(&mut surgeon),
-            IoSliceMut::new(&mut has),
-            IoSliceMut::new(&mut men),
-            IoSliceMut::new(&mut swear),
-        ])
-        .unwrap();
-
-    assert_eq!(received, 18);
-    #[cfg(all(unix, not(target_os = "redox")))]
-    assert_eq!(flags.is_end_of_record(), false);
-    #[cfg(all(unix, not(target_os = "redox")))]
-    assert_eq!(flags.is_out_of_band(), false);
-    assert_eq!(flags.is_truncated(), false);
-    assert_eq!(addr.as_inet6().unwrap(), addr_a.as_inet6().unwrap());
-    assert_eq!(&surgeon, b"surgeon");
-    assert_eq!(&has, b"has");
-    assert_eq!(&men, b"men");
-    assert_eq!(&swear, b"swear");
-}
-
-#[test]
-#[cfg(not(target_os = "redox"))]
-fn recv_vectored_truncated() {
-    use std::io::IoSliceMut;
-
-    let (socket_a, socket_b) = udp_pair_connected();
-
-    let sent = socket_a
-        .send(b"do not feed the gremlins after midnight")
-        .unwrap();
-    assert_eq!(sent, 39);
-
-    let mut buffer = [0u8; 24];
-
-    let (received, flags) = socket_b
-        .recv_vectored(&mut [IoSliceMut::new(&mut buffer)])
-        .unwrap();
-    assert_eq!(received, 24);
-    assert_eq!(flags.is_truncated(), true);
-    assert_eq!(&buffer, b"do not feed the gremlins");
-}
-
-#[test]
-#[cfg(not(target_os = "redox"))]
-fn recv_from_vectored_truncated() {
-    use std::io::IoSliceMut;
-
-    let (socket_a, socket_b) = udp_pair_unconnected();
-    let addr_a = socket_a.local_addr().unwrap();
-    let addr_b = socket_b.local_addr().unwrap();
-
-    let sent = socket_a
-        .send_to(b"do not feed the gremlins after midnight", &addr_b)
-        .unwrap();
-    assert_eq!(sent, 39);
-
-    let mut buffer = [0u8; 24];
-
-    let (received, flags, addr) = socket_b
-        .recv_from_vectored(&mut [IoSliceMut::new(&mut buffer)])
-        .unwrap();
-    assert_eq!(received, 24);
-    assert_eq!(flags.is_truncated(), true);
-    assert_eq!(addr.as_inet6().unwrap(), addr_a.as_inet6().unwrap());
-    assert_eq!(&buffer, b"do not feed the gremlins");
-}
diff --git a/tests/options.rs b/tests/options.rs
deleted file mode 100644
index e107d08..0000000
--- a/tests/options.rs
+++ /dev/null
@@ -1,107 +0,0 @@
-//! Tests for getting and setting socket options.
-
-use std::time::Duration;
-
-use socket2::{Domain, Socket, Type};
-
-/// Macro to create a simple test to set and get a socket option.
-macro_rules! test {
-    // Test using the `arg`ument as expected return value.
-    ($( #[ $attr: meta ] )* $get_fn: ident, $set_fn: ident ( $arg: expr ) ) => {
-        test!($( #[$attr] )* $get_fn, $set_fn($arg), $arg);
-    };
-    ($( #[ $attr: meta ] )* $get_fn: ident, $set_fn: ident ( $arg: expr ), $expected: expr ) => {
-        #[test]
-        $( #[$attr] )*
-        fn $get_fn() {
-            test!(__ Domain::IPV4, $get_fn, $set_fn($arg), $expected);
-            test!(__ Domain::IPV6, $get_fn, $set_fn($arg), $expected);
-        }
-    };
-    // Only test using a IPv4 socket.
-    (IPv4 $get_fn: ident, $set_fn: ident ( $arg: expr ) ) => {
-        #[test]
-        fn $get_fn() {
-            test!(__ Domain::IPV4, $get_fn, $set_fn($arg), $arg);
-        }
-    };
-    // Only test using a IPv6 socket.
-    (IPv6 $get_fn: ident, $set_fn: ident ( $arg: expr ) ) => {
-        #[test]
-        fn $get_fn() {
-            test!(__ Domain::IPV6, $get_fn, $set_fn($arg), $arg);
-        }
-    };
-
-    // Internal to this macro.
-    (__ $ty: expr, $get_fn: ident, $set_fn: ident ( $arg: expr ), $expected: expr ) => {
-        let socket = Socket::new($ty, Type::STREAM, None).expect("failed to create `Socket`");
-
-        let initial = socket.$get_fn().expect("failed to get initial value");
-        let arg = $arg;
-        let expected = $expected;
-        assert_ne!(initial, arg, "initial value and argument are the same");
-
-        socket.$set_fn(arg).expect("failed to set option");
-        let got = socket.$get_fn().expect("failed to get value");
-        assert_eq!(got, expected, "set and get values differ");
-    };
-}
-
-const SET_BUF_SIZE: usize = 4096;
-// Linux doubles the buffer size for kernel usage, and exposes that when
-// retrieving the buffer size.
-#[cfg(not(target_os = "linux"))]
-const GET_BUF_SIZE: usize = SET_BUF_SIZE;
-#[cfg(target_os = "linux")]
-const GET_BUF_SIZE: usize = 2 * SET_BUF_SIZE;
-
-test!(nodelay, set_nodelay(true));
-test!(
-    recv_buffer_size,
-    set_recv_buffer_size(SET_BUF_SIZE),
-    GET_BUF_SIZE
-);
-test!(
-    send_buffer_size,
-    set_send_buffer_size(SET_BUF_SIZE),
-    GET_BUF_SIZE
-);
-#[cfg(not(target_os = "redox"))]
-test!(out_of_band_inline, set_out_of_band_inline(true));
-test!(reuse_address, set_reuse_address(true));
-#[cfg(all(
-    feature = "all",
-    not(any(windows, target_os = "solaris", target_os = "illumos"))
-))]
-test!(reuse_port, set_reuse_port(true));
-#[cfg(all(feature = "all", unix))]
-test!(
-    #[cfg_attr(target_os = "linux", ignore = "Different value returned")]
-    mss,
-    set_mss(256)
-);
-#[cfg(all(feature = "all", target_os = "linux"))]
-test!(
-    #[ignore = "setting `SO_MARK` requires the `CAP_NET_ADMIN` capability (works when running as root)"]
-    mark,
-    set_mark(123)
-);
-test!(linger, set_linger(Some(Duration::from_secs(10))));
-test!(
-    read_timeout,
-    set_read_timeout(Some(Duration::from_secs(10)))
-);
-test!(keepalive, set_keepalive(true));
-#[cfg(all(feature = "all", target_os = "linux"))]
-test!(freebind, set_freebind(true));
-
-test!(IPv4 ttl, set_ttl(40));
-#[cfg(not(windows))] // TODO: returns `WSAENOPROTOOPT` (10042) on Windows.
-test!(IPv4 broadcast, set_broadcast(true));
-
-test!(IPv6 unicast_hops_v6, set_unicast_hops_v6(20));
-#[cfg(not(windows))]
-test!(IPv6 only_v6, set_only_v6(true));
-#[cfg(windows)] // IPv6 socket are already IPv6 only on Windows.
-test!(IPv6 only_v6, set_only_v6(false));
diff --git a/tests/socket.rs b/tests/socket.rs
index 89d2de4..5200fc4 100644
--- a/tests/socket.rs
+++ b/tests/socket.rs
@@ -2,11 +2,21 @@
 use std::ffi::CStr;
 #[cfg(any(windows, target_vendor = "apple"))]
 use std::io;
+#[cfg(all(unix, feature = "all"))]
+use std::io::Read;
+use std::io::Write;
+#[cfg(not(target_os = "redox"))]
+use std::io::{IoSlice, IoSliceMut};
+use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
 #[cfg(unix)]
 use std::os::unix::io::AsRawFd;
 #[cfg(windows)]
 use std::os::windows::io::AsRawSocket;
+use std::str;
+use std::thread;
 use std::time::Duration;
+#[cfg(all(unix, feature = "all"))]
+use std::{env, fs};
 
 #[cfg(windows)]
 use winapi::shared::minwindef::DWORD;
@@ -15,7 +25,89 @@ use winapi::um::handleapi::GetHandleInformation;
 #[cfg(windows)]
 use winapi::um::winbase::HANDLE_FLAG_INHERIT;
 
-use socket2::{Domain, Socket, TcpKeepalive, Type};
+use socket2::{Domain, Protocol, SockAddr, Socket, TcpKeepalive, Type};
+
+#[test]
+fn domain_for_address() {
+    let ipv4: SocketAddr = "127.0.0.1:8080".parse().unwrap();
+    assert!(ipv4.is_ipv4());
+    let ipv6: SocketAddr = "[::1]:8080".parse().unwrap();
+    assert!(ipv6.is_ipv6());
+
+    assert_eq!(Domain::for_address(ipv4), Domain::IPV4);
+    assert_eq!(Domain::for_address(ipv6), Domain::IPV6);
+}
+
+#[test]
+fn domain_fmt_debug() {
+    let tests = &[
+        (Domain::IPV4, "AF_INET"),
+        (Domain::IPV6, "AF_INET6"),
+        #[cfg(unix)]
+        (Domain::UNIX, "AF_UNIX"),
+        #[cfg(all(feature = "all", target_os = "linux"))]
+        (Domain::PACKET, "AF_PACKET"),
+        (0.into(), "AF_UNSPEC"),
+        (500.into(), "500"),
+    ];
+
+    let mut buf = Vec::new();
+    for (input, want) in tests {
+        buf.clear();
+        write!(buf, "{:?}", input).unwrap();
+        let got = str::from_utf8(&buf).unwrap();
+        assert_eq!(got, *want);
+    }
+}
+
+#[test]
+fn type_fmt_debug() {
+    let tests = &[
+        (Type::STREAM, "SOCK_STREAM"),
+        (Type::DGRAM, "SOCK_DGRAM"),
+        #[cfg(feature = "all")]
+        (Type::SEQPACKET, "SOCK_SEQPACKET"),
+        #[cfg(all(feature = "all", not(target_os = "redox")))]
+        (Type::RAW, "SOCK_RAW"),
+        (500.into(), "500"),
+    ];
+
+    let mut buf = Vec::new();
+    for (input, want) in tests {
+        buf.clear();
+        write!(buf, "{:?}", input).unwrap();
+        let got = str::from_utf8(&buf).unwrap();
+        assert_eq!(got, *want);
+    }
+}
+
+#[test]
+fn protocol_fmt_debug() {
+    let tests = &[
+        (Protocol::ICMPV4, "IPPROTO_ICMP"),
+        (Protocol::ICMPV6, "IPPROTO_ICMPV6"),
+        (Protocol::TCP, "IPPROTO_TCP"),
+        (Protocol::UDP, "IPPROTO_UDP"),
+        (500.into(), "500"),
+    ];
+
+    let mut buf = Vec::new();
+    for (input, want) in tests {
+        buf.clear();
+        write!(buf, "{:?}", input).unwrap();
+        let got = str::from_utf8(&buf).unwrap();
+        assert_eq!(got, *want);
+    }
+}
+
+#[test]
+#[cfg(all(unix, feature = "all"))]
+fn socket_address_unix() {
+    let string = "/tmp/socket";
+    let addr = SockAddr::unix(string).unwrap();
+    assert!(addr.as_inet().is_none());
+    assert!(addr.as_inet6().is_none());
+}
 
 #[test]
 fn set_nonblocking() {
@@ -208,8 +300,253 @@ where
     assert_eq!(flags, want as _, "non-blocking option");
 }
 
+const DATA: &[u8] = b"hello world";
+
+#[test]
+#[cfg(all(feature = "all", unix))]
+fn pair() {
+    let (mut a, mut b) = Socket::pair(Domain::UNIX, Type::STREAM, None).unwrap();
+    a.write(DATA).unwrap();
+    let mut buf = [0; DATA.len() + 1];
+    let n = b.read(&mut buf).unwrap();
+    assert_eq!(n, DATA.len());
+    assert_eq!(&buf[..n], DATA);
+}
+
+#[test]
+#[cfg(all(feature = "all", unix))]
+fn unix() {
+    let mut path = env::temp_dir();
+    path.push("socket2");
+    let _ = fs::remove_dir_all(&path);
+    fs::create_dir_all(&path).unwrap();
+    path.push("unix");
+
+    let addr = SockAddr::unix(path).unwrap();
+
+    let listener = Socket::new(Domain::UNIX, Type::STREAM, None).unwrap();
+    listener.bind(&addr).unwrap();
+    listener.listen(10).unwrap();
+
+    let mut a = Socket::new(Domain::UNIX, Type::STREAM, None).unwrap();
+    a.connect(&addr).unwrap();
+    let mut b = listener.accept().unwrap().0;
+
+    a.write(DATA).unwrap();
+    let mut buf = [0; DATA.len() + 1];
+    let n = b.read(&mut buf).unwrap();
+    assert_eq!(n, DATA.len());
+    assert_eq!(&buf[..n], DATA);
+}
+
+#[test]
+fn out_of_band() {
+    let listener = Socket::new(Domain::IPV4, Type::STREAM, None).unwrap();
+    listener.bind(&any_ipv4()).unwrap();
+    listener.listen(1).unwrap();
+
+    let sender = Socket::new(Domain::IPV4, Type::STREAM, None).unwrap();
+    sender.bind(&any_ipv4()).unwrap();
+    sender.connect(&listener.local_addr().unwrap()).unwrap();
+
+    let (receiver, _) = listener.accept().unwrap();
+
+    sender.send(&DATA).unwrap();
+
+    const FIRST: &[u8] = b"!";
+    assert_eq!(sender.send_out_of_band(FIRST).unwrap(), FIRST.len());
+    // On macOS if no `MSG_OOB` is available it will return `EINVAL`, to prevent
+    // this from happening we'll sleep to ensure the data is present.
+    thread::sleep(Duration::from_millis(10));
+
+    let mut buf = [1; DATA.len() + 1];
+    let n = receiver.recv_out_of_band(&mut buf).unwrap();
+    assert_eq!(n, FIRST.len());
+    assert_eq!(&buf[..n], FIRST);
+
+    let n = receiver.recv(&mut buf).unwrap();
+    assert_eq!(n, DATA.len());
+    assert_eq!(&buf[..n], DATA);
+}
+
+#[test]
+#[cfg(not(target_os = "redox"))]
+fn send_recv_vectored() {
+    let (socket_a, socket_b) = udp_pair_connected();
+
+    let sent = socket_a
+        .send_vectored(&[
+            IoSlice::new(b"the"),
+            IoSlice::new(b"weeknight"),
+            IoSlice::new(b"would"),
+            IoSlice::new(b"yellow"),
+        ])
+        .unwrap();
+    assert_eq!(sent, 23);
+
+    let mut the = [0u8; 3];
+    let mut wee = [0u8; 3];
+    let mut knight = [0u8; 6];
+    let mut would = [0u8; 5];
+    let mut yell = [0u8; 4];
+    let mut ow = [0u8; 2];
+
+    let (received, flags) = socket_b
+        .recv_vectored(&mut [
+            IoSliceMut::new(&mut the),
+            IoSliceMut::new(&mut wee),
+            IoSliceMut::new(&mut knight),
+            IoSliceMut::new(&mut would),
+            IoSliceMut::new(&mut yell),
+            IoSliceMut::new(&mut ow),
+        ])
+        .unwrap();
+    assert_eq!(received, 23);
+    #[cfg(all(unix, not(target_os = "redox")))]
+    assert_eq!(flags.is_end_of_record(), false);
+    #[cfg(all(unix, not(target_os = "redox")))]
+    assert_eq!(flags.is_out_of_band(), false);
+    assert_eq!(flags.is_truncated(), false);
+
+    assert_eq!(&the, b"the");
+    assert_eq!(&wee, b"wee");
+    assert_eq!(&knight, b"knight");
+    assert_eq!(&would, b"would");
+    assert_eq!(&yell, b"yell");
+    assert_eq!(&ow, b"ow");
+}
+
 #[test]
-fn keepalive() {
+#[cfg(not(target_os = "redox"))]
+fn send_from_recv_to_vectored() {
+    let (socket_a, socket_b) = udp_pair_unconnected();
+    let addr_a = socket_a.local_addr().unwrap();
+    let addr_b = socket_b.local_addr().unwrap();
+
+    let sent = socket_a
+        .send_to_vectored(
+            &[
+                IoSlice::new(b"surgeon"),
+                IoSlice::new(b"has"),
+                IoSlice::new(b"menswear"),
+            ],
+            &addr_b,
+        )
+        .unwrap();
+    assert_eq!(sent, 18);
+
+    let mut surgeon = [0u8; 7];
+    let mut has = [0u8; 3];
+    let mut men = [0u8; 3];
+    let mut swear = [0u8; 5];
+    let (received, flags, addr) = socket_b
+        .recv_from_vectored(&mut [
+            IoSliceMut::new(&mut surgeon),
+            IoSliceMut::new(&mut has),
+            IoSliceMut::new(&mut men),
+            IoSliceMut::new(&mut swear),
+        ])
+        .unwrap();
+
+    assert_eq!(received, 18);
+    #[cfg(all(unix, not(target_os = "redox")))]
+    assert_eq!(flags.is_end_of_record(), false);
+    #[cfg(all(unix, not(target_os = "redox")))]
+    assert_eq!(flags.is_out_of_band(), false);
+    assert_eq!(flags.is_truncated(), false);
+    assert_eq!(addr.as_inet6().unwrap(), addr_a.as_inet6().unwrap());
+    assert_eq!(&surgeon, b"surgeon");
+    assert_eq!(&has, b"has");
+    assert_eq!(&men, b"men");
+    assert_eq!(&swear, b"swear");
+}
+
+#[test]
+#[cfg(not(target_os = "redox"))]
+fn recv_vectored_truncated() {
+    let (socket_a, socket_b) = udp_pair_connected();
+
+    let sent = socket_a
+        .send(b"do not feed the gremlins after midnight")
+        .unwrap();
+    assert_eq!(sent, 39);
+
+    let mut buffer = [0u8; 24];
+
+    let (received, flags) = socket_b
+        .recv_vectored(&mut [IoSliceMut::new(&mut buffer)])
+        .unwrap();
+    assert_eq!(received, 24);
+    assert_eq!(flags.is_truncated(), true);
+    assert_eq!(&buffer, b"do not feed the gremlins");
+}
+
+#[test]
+#[cfg(not(target_os = "redox"))]
+fn recv_from_vectored_truncated() {
+    let (socket_a, socket_b) = udp_pair_unconnected();
+    let addr_a = socket_a.local_addr().unwrap();
+    let addr_b = socket_b.local_addr().unwrap();
+
+    let sent = socket_a
+        .send_to(b"do not feed the gremlins after midnight", &addr_b)
+        .unwrap();
+    assert_eq!(sent, 39);
+
+    let mut buffer = [0u8; 24];
+
+    let (received, flags, addr) = socket_b
+        .recv_from_vectored(&mut [IoSliceMut::new(&mut buffer)])
+        .unwrap();
+    assert_eq!(received, 24);
+    assert_eq!(flags.is_truncated(), true);
+    assert_eq!(addr.as_inet6().unwrap(), addr_a.as_inet6().unwrap());
+    assert_eq!(&buffer, b"do not feed the gremlins");
+}
+
+/// Create a pair of non-connected UDP sockets suitable for unit tests.
+#[cfg(not(target_os = "redox"))]
+fn udp_pair_unconnected() -> (Socket, Socket) {
+    // Use ephemeral ports assigned by the OS.
+    let unspecified_addr = SocketAddrV6::new(Ipv6Addr::LOCALHOST, 0, 0, 0);
+    let socket_a = Socket::new(Domain::IPV6, Type::DGRAM, None).unwrap();
+    let socket_b = Socket::new(Domain::IPV6, Type::DGRAM, None).unwrap();
+
+    socket_a.bind(&unspecified_addr.into()).unwrap();
+    socket_b.bind(&unspecified_addr.into()).unwrap();
+
+    // Set low timeouts to prevent the tests from blocking.
+    socket_a
+        .set_read_timeout(Some(std::time::Duration::from_millis(10)))
+        .unwrap();
+    socket_b
+        .set_read_timeout(Some(std::time::Duration::from_millis(10)))
+        .unwrap();
+    socket_a
+        .set_write_timeout(Some(std::time::Duration::from_millis(10)))
+        .unwrap();
+    socket_b
+        .set_write_timeout(Some(std::time::Duration::from_millis(10)))
+        .unwrap();
+
+    (socket_a, socket_b)
+}
+
+/// Create a pair of connected UDP sockets suitable for unit tests.
+#[cfg(not(target_os = "redox"))]
+fn udp_pair_connected() -> (Socket, Socket) {
+    let (socket_a, socket_b) = udp_pair_unconnected();
+
+    let addr_a = socket_a.local_addr().unwrap();
+    let addr_b = socket_b.local_addr().unwrap();
+    socket_a.connect(&addr_b).unwrap();
+    socket_b.connect(&addr_a).unwrap();
+
+    (socket_a, socket_b)
+}
+
+#[test]
+fn tcp_keepalive() {
     let socket = Socket::new(Domain::IPV4, Type::STREAM, None).unwrap();
     let params = TcpKeepalive::new().with_time(Duration::from_secs(200));
 
@@ -301,3 +638,109 @@ fn device() {
         break;
     }
 }
+
+fn any_ipv4() -> SockAddr {
+    SocketAddrV4::new(Ipv4Addr::LOCALHOST, 0).into()
+}
+
+/// Macro to create a simple test to set and get a socket option.
+macro_rules! test {
+    // Test using the `arg`ument as expected return value.
+    ($( #[ $attr: meta ] )* $get_fn: ident, $set_fn: ident ( $arg: expr ) ) => {
+        test!($( #[$attr] )* $get_fn, $set_fn($arg), $arg);
+    };
+    ($( #[ $attr: meta ] )* $get_fn: ident, $set_fn: ident ( $arg: expr ), $expected: expr ) => {
+        #[test]
+        $( #[$attr] )*
+        fn $get_fn() {
+            test!(__ Domain::IPV4, $get_fn, $set_fn($arg), $expected);
+            test!(__ Domain::IPV6, $get_fn, $set_fn($arg), $expected);
+        }
+    };
+    // Only test using a IPv4 socket.
+    (IPv4 $get_fn: ident, $set_fn: ident ( $arg: expr ) ) => {
+        #[test]
+        fn $get_fn() {
+            test!(__ Domain::IPV4, $get_fn, $set_fn($arg), $arg);
+        }
+    };
+    // Only test using a IPv6 socket.
+    (IPv6 $get_fn: ident, $set_fn: ident ( $arg: expr ) ) => {
+        #[test]
+        fn $get_fn() {
+            test!(__ Domain::IPV6, $get_fn, $set_fn($arg), $arg);
+        }
+    };
+
+    // Internal to this macro.
+    (__ $ty: expr, $get_fn: ident, $set_fn: ident ( $arg: expr ), $expected: expr ) => {
+        let socket = Socket::new($ty, Type::STREAM, None).expect("failed to create `Socket`");
+
+        let initial = socket.$get_fn().expect("failed to get initial value");
+        let arg = $arg;
+        let expected = $expected;
+        assert_ne!(initial, arg, "initial value and argument are the same");
+
+        socket.$set_fn(arg).expect("failed to set option");
+        let got = socket.$get_fn().expect("failed to get value");
+        assert_eq!(got, expected, "set and get values differ");
+    };
+}
+
+const SET_BUF_SIZE: usize = 4096;
+// Linux doubles the buffer size for kernel usage, and exposes that when
+// retrieving the buffer size.
+#[cfg(not(target_os = "linux"))]
+const GET_BUF_SIZE: usize = SET_BUF_SIZE;
+#[cfg(target_os = "linux")]
+const GET_BUF_SIZE: usize = 2 * SET_BUF_SIZE;
+
+test!(nodelay, set_nodelay(true));
+test!(
+    recv_buffer_size,
+    set_recv_buffer_size(SET_BUF_SIZE),
+    GET_BUF_SIZE
+);
+test!(
+    send_buffer_size,
+    set_send_buffer_size(SET_BUF_SIZE),
+    GET_BUF_SIZE
+);
+#[cfg(not(target_os = "redox"))]
+test!(out_of_band_inline, set_out_of_band_inline(true));
+test!(reuse_address, set_reuse_address(true));
+#[cfg(all(
+    feature = "all",
+    not(any(windows, target_os = "solaris", target_os = "illumos"))
+))]
+test!(reuse_port, set_reuse_port(true));
+#[cfg(all(feature = "all", unix))]
+test!(
+    #[cfg_attr(target_os = "linux", ignore = "Different value returned")]
+    mss,
+    set_mss(256)
+);
+#[cfg(all(feature = "all", target_os = "linux"))]
+test!(
+    #[ignore = "setting `SO_MARK` requires the `CAP_NET_ADMIN` capability (works when running as root)"]
+    mark,
+    set_mark(123)
+);
+test!(linger, set_linger(Some(Duration::from_secs(10))));
+test!(
+    read_timeout,
+    set_read_timeout(Some(Duration::from_secs(10)))
+);
+test!(keepalive, set_keepalive(true));
+#[cfg(all(feature = "all", target_os = "linux"))]
+test!(freebind, set_freebind(true));
+
+test!(IPv4 ttl, set_ttl(40));
+#[cfg(not(windows))] // TODO: returns `WSAENOPROTOOPT` (10042) on Windows.
+test!(IPv4 broadcast, set_broadcast(true));
+
+test!(IPv6 unicast_hops_v6, set_unicast_hops_v6(20));
+#[cfg(not(windows))]
+test!(IPv6 only_v6, set_only_v6(true));
+#[cfg(windows)] // IPv6 socket are already IPv6 only on Windows.
+test!(IPv6 only_v6, set_only_v6(false));