Răsfoiți Sursa

tests: remove mock and use rstest in more places

Thibaut Vandervelden 1 an în urmă
părinte
comite
6466817a66

+ 1 - 92
src/iface/interface/mod.rs

@@ -230,7 +230,7 @@ use check;
 /// a dependency on heap allocation, it instead owns a `BorrowMut<[T]>`, which can be
 /// a `&mut [T]`, or `Vec<T>` if a heap is available.
 pub struct Interface {
-    inner: InterfaceInner,
+    pub(crate) inner: InterfaceInner,
     fragments: FragmentsBuffer,
     fragmenter: Fragmenter,
 }
@@ -968,97 +968,6 @@ impl InterfaceInner {
         None
     }
 
-    #[cfg(test)]
-    pub(crate) fn mock() -> Self {
-        Self {
-            caps: DeviceCapabilities {
-                #[cfg(feature = "medium-ethernet")]
-                medium: crate::phy::Medium::Ethernet,
-                #[cfg(all(not(feature = "medium-ethernet"), feature = "medium-ip"))]
-                medium: crate::phy::Medium::Ip,
-                #[cfg(all(not(feature = "medium-ethernet"), feature = "medium-ieee802154"))]
-                medium: crate::phy::Medium::Ieee802154,
-
-                checksum: crate::phy::ChecksumCapabilities {
-                    #[cfg(feature = "proto-ipv4")]
-                    icmpv4: crate::phy::Checksum::Both,
-                    #[cfg(feature = "proto-ipv6")]
-                    icmpv6: crate::phy::Checksum::Both,
-                    ipv4: crate::phy::Checksum::Both,
-                    tcp: crate::phy::Checksum::Both,
-                    udp: crate::phy::Checksum::Both,
-                },
-                max_burst_size: None,
-                #[cfg(feature = "medium-ethernet")]
-                max_transmission_unit: 1514,
-                #[cfg(not(feature = "medium-ethernet"))]
-                max_transmission_unit: 1500,
-            },
-            now: Instant::from_millis_const(0),
-
-            ip_addrs: Vec::from_slice(&[
-                #[cfg(feature = "proto-ipv4")]
-                IpCidr::Ipv4(Ipv4Cidr::new(Ipv4Address::new(192, 168, 1, 1), 24)),
-                #[cfg(feature = "proto-ipv6")]
-                IpCidr::Ipv6(Ipv6Cidr::new(
-                    Ipv6Address([0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]),
-                    64,
-                )),
-            ])
-            .unwrap(),
-            rand: Rand::new(1234),
-            routes: Routes::new(),
-
-            #[cfg(feature = "proto-ipv4")]
-            any_ip: false,
-
-            #[cfg(feature = "medium-ieee802154")]
-            pan_id: Some(crate::wire::Ieee802154Pan(0xabcd)),
-            #[cfg(feature = "medium-ieee802154")]
-            sequence_no: 1,
-
-            #[cfg(feature = "proto-sixlowpan-fragmentation")]
-            tag: 1,
-
-            #[cfg(feature = "proto-sixlowpan")]
-            sixlowpan_address_context: Vec::new(),
-
-            #[cfg(feature = "proto-ipv4-fragmentation")]
-            ipv4_id: 1,
-
-            #[cfg(all(
-                feature = "medium-ip",
-                not(feature = "medium-ethernet"),
-                not(feature = "medium-ieee802154")
-            ))]
-            hardware_addr: crate::wire::HardwareAddress::Ip,
-
-            #[cfg(feature = "medium-ethernet")]
-            hardware_addr: crate::wire::HardwareAddress::Ethernet(crate::wire::EthernetAddress([
-                0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
-            ])),
-
-            #[cfg(all(
-                not(feature = "medium-ip"),
-                not(feature = "medium-ethernet"),
-                feature = "medium-ieee802154"
-            ))]
-            hardware_addr: crate::wire::HardwareAddress::Ieee802154(
-                crate::wire::Ieee802154Address::Extended([
-                    0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x2, 0x2,
-                ]),
-            ),
-
-            #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
-            neighbor_cache: NeighborCache::new(),
-
-            #[cfg(feature = "proto-igmp")]
-            igmp_report_state: IgmpReportState::Inactive,
-            #[cfg(feature = "proto-igmp")]
-            ipv4_multicast_groups: LinearMap::new(),
-        }
-    }
-
     #[cfg(test)]
     #[allow(unused)] // unused depending on which sockets are enabled
     pub(crate) fn set_now(&mut self, now: Instant) {

+ 9 - 6
src/iface/interface/tests/ipv4.rs

@@ -364,7 +364,7 @@ fn test_handle_valid_arp_request(#[case] medium: Medium) {
 
     let local_ip_addr = Ipv4Address([0x7f, 0x00, 0x00, 0x01]);
     let remote_ip_addr = Ipv4Address([0x7f, 0x00, 0x00, 0x02]);
-    let local_hw_addr = EthernetAddress([0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
+    let local_hw_addr = EthernetAddress([0x02, 0x02, 0x02, 0x02, 0x02, 0x02]);
     let remote_hw_addr = EthernetAddress([0x52, 0x54, 0x00, 0x00, 0x00, 0x00]);
 
     let repr = ArpRepr::EthernetIpv4 {
@@ -470,7 +470,7 @@ fn test_arp_flush_after_update_ip(#[case] medium: Medium) {
 
     let local_ip_addr = Ipv4Address([0x7f, 0x00, 0x00, 0x01]);
     let remote_ip_addr = Ipv4Address([0x7f, 0x00, 0x00, 0x02]);
-    let local_hw_addr = EthernetAddress([0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
+    let local_hw_addr = EthernetAddress([0x02, 0x02, 0x02, 0x02, 0x02, 0x02]);
     let remote_hw_addr = EthernetAddress([0x52, 0x54, 0x00, 0x00, 0x00, 0x00]);
 
     let repr = ArpRepr::EthernetIpv4 {
@@ -615,7 +615,10 @@ fn test_icmpv4_socket(#[case] medium: Medium) {
 #[case(Medium::Ethernet)]
 #[cfg(all(feature = "proto-igmp", feature = "medium-ethernet"))]
 fn test_handle_igmp(#[case] medium: Medium) {
-    fn recv_igmp(device: &mut Loopback, timestamp: Instant) -> Vec<(Ipv4Repr, IgmpRepr)> {
+    fn recv_igmp(
+        device: &mut crate::tests::TestingDevice,
+        timestamp: Instant,
+    ) -> Vec<(Ipv4Repr, IgmpRepr)> {
         let caps = device.capabilities();
         let checksum_caps = &caps.checksum;
         recv_all(device, timestamp)
@@ -649,7 +652,7 @@ fn test_handle_igmp(#[case] medium: Medium) {
     let (mut iface, mut sockets, mut device) = setup(medium);
 
     // Join multicast groups
-    let timestamp = Instant::now();
+    let timestamp = Instant::ZERO;
     for group in &groups {
         iface
             .join_multicast_group(&mut device, *group, timestamp)
@@ -671,7 +674,7 @@ fn test_handle_igmp(#[case] medium: Medium) {
     }
 
     // General query
-    let timestamp = Instant::now();
+    let timestamp = Instant::ZERO;
     const GENERAL_QUERY_BYTES: &[u8] = &[
         0x46, 0xc0, 0x00, 0x24, 0xed, 0xb4, 0x00, 0x00, 0x01, 0x02, 0x47, 0x43, 0xac, 0x16, 0x63,
         0x04, 0xe0, 0x00, 0x00, 0x01, 0x94, 0x04, 0x00, 0x00, 0x11, 0x64, 0xec, 0x8f, 0x00, 0x00,
@@ -692,7 +695,7 @@ fn test_handle_igmp(#[case] medium: Medium) {
     iface.socket_ingress(&mut device, &mut sockets);
 
     // Leave multicast groups
-    let timestamp = Instant::now();
+    let timestamp = Instant::ZERO;
     for group in &groups {
         iface
             .leave_multicast_group(&mut device, *group, timestamp)

+ 1 - 1
src/iface/interface/tests/ipv6.rs

@@ -554,7 +554,7 @@ fn test_handle_valid_ndisc_request(#[case] medium: Medium) {
 
     let local_ip_addr = Ipv6Address::new(0xfdbe, 0, 0, 0, 0, 0, 0, 1);
     let remote_ip_addr = Ipv6Address::new(0xfdbe, 0, 0, 0, 0, 0, 0, 2);
-    let local_hw_addr = EthernetAddress([0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
+    let local_hw_addr = EthernetAddress([0x02, 0x02, 0x02, 0x02, 0x02, 0x02]);
     let remote_hw_addr = EthernetAddress([0x52, 0x54, 0x00, 0x00, 0x00, 0x00]);
 
     let solicit = Icmpv6Repr::Ndisc(NdiscRepr::NeighborSolicit {

+ 7 - 41
src/iface/interface/tests/mod.rs

@@ -8,12 +8,16 @@ mod sixlowpan;
 #[cfg(feature = "proto-igmp")]
 use std::vec::Vec;
 
+use crate::tests::setup;
+
 use rstest::*;
 
 use super::*;
 
 use crate::iface::Interface;
-use crate::phy::{ChecksumCapabilities, Loopback};
+use crate::phy::ChecksumCapabilities;
+#[cfg(feature = "alloc")]
+use crate::phy::Loopback;
 use crate::time::Instant;
 
 #[allow(unused)]
@@ -23,46 +27,8 @@ fn fill_slice(s: &mut [u8], val: u8) {
     }
 }
 
-fn setup<'a>(medium: Medium) -> (Interface, SocketSet<'a>, Loopback) {
-    let mut device = Loopback::new(medium);
-
-    let config = Config::new(match medium {
-        #[cfg(feature = "medium-ethernet")]
-        Medium::Ethernet => HardwareAddress::Ethernet(Default::default()),
-        #[cfg(feature = "medium-ip")]
-        Medium::Ip => HardwareAddress::Ip,
-        #[cfg(feature = "medium-ieee802154")]
-        Medium::Ieee802154 => HardwareAddress::Ieee802154(Default::default()),
-    });
-
-    let mut iface = Interface::new(config, &mut device, Instant::ZERO);
-
-    #[cfg(feature = "proto-ipv4")]
-    {
-        iface.update_ip_addrs(|ip_addrs| {
-            ip_addrs
-                .push(IpCidr::new(IpAddress::v4(127, 0, 0, 1), 8))
-                .unwrap();
-        });
-    }
-
-    #[cfg(feature = "proto-ipv6")]
-    {
-        iface.update_ip_addrs(|ip_addrs| {
-            ip_addrs
-                .push(IpCidr::new(IpAddress::v6(0, 0, 0, 0, 0, 0, 0, 1), 128))
-                .unwrap();
-            ip_addrs
-                .push(IpCidr::new(IpAddress::v6(0xfdbe, 0, 0, 0, 0, 0, 0, 1), 64))
-                .unwrap();
-        });
-    }
-
-    (iface, SocketSet::new(vec![]), device)
-}
-
 #[cfg(feature = "proto-igmp")]
-fn recv_all(device: &mut Loopback, timestamp: Instant) -> Vec<Vec<u8>> {
+fn recv_all(device: &mut crate::tests::TestingDevice, timestamp: Instant) -> Vec<Vec<u8>> {
     let mut pkts = Vec::new();
     while let Some((rx, _tx)) = device.receive(timestamp) {
         rx.consume(|pkt| {
@@ -88,7 +54,7 @@ impl TxToken for MockTxToken {
 
 #[test]
 #[should_panic(expected = "The hardware address does not match the medium of the interface.")]
-#[cfg(all(feature = "medium-ip", feature = "medium-ethernet"))]
+#[cfg(all(feature = "medium-ip", feature = "medium-ethernet", feature = "alloc"))]
 fn test_new_panic() {
     let mut device = Loopback::new(Medium::Ethernet);
     let config = Config::new(HardwareAddress::Ip);

+ 12 - 12
src/iface/interface/tests/sixlowpan.rs

@@ -230,10 +230,10 @@ fn test_echo_request_sixlowpan_128_bytes() {
     );
 
     assert_eq!(
-        device.queue[0],
+        device.queue.pop_front().unwrap(),
         &[
-            0x41, 0xcc, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
-            0x0, 0x0, 0x0, 0x0, 0xc0, 0xb0, 0x5, 0x4e, 0x7a, 0x11, 0x3a, 0x92, 0xfc, 0x48, 0xc2,
+            0x41, 0xcc, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2,
+            0x2, 0x2, 0x2, 0x2, 0xc0, 0xb0, 0x5, 0x4e, 0x7a, 0x11, 0x3a, 0x92, 0xfc, 0x48, 0xc2,
             0xa4, 0x41, 0xfc, 0x76, 0x40, 0x42, 0x42, 0x42, 0x42, 0x42, 0xb, 0x1a, 0x81, 0x0, 0x0,
             0x0, 0x0, 0x27, 0x0, 0x2, 0xa2, 0xc2, 0x2d, 0x63, 0x0, 0x0, 0x0, 0x0, 0xd9, 0x5e, 0xc,
             0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
@@ -247,10 +247,10 @@ fn test_echo_request_sixlowpan_128_bytes() {
     iface.poll(Instant::now(), &mut device, &mut sockets);
 
     assert_eq!(
-        device.queue[1],
+        device.queue.pop_front().unwrap(),
         &[
-            0x41, 0xcc, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
-            0x0, 0x0, 0x0, 0x0, 0xe0, 0xb0, 0x5, 0x4e, 0xf, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d,
+            0x41, 0xcc, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2,
+            0x2, 0x2, 0x2, 0x2, 0xe0, 0xb0, 0x5, 0x4e, 0xf, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d,
             0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b,
             0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
             0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
@@ -384,10 +384,10 @@ In at rhoncus tortor. Cras blandit tellus diam, varius vestibulum nibh commodo n
     iface.poll(Instant::now(), &mut device, &mut sockets);
 
     assert_eq!(
-        device.queue[0],
+        device.queue.pop_front().unwrap(),
         &[
-            0x41, 0xcc, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
-            0x0, 0x0, 0x0, 0x0, 0xc0, 0xb4, 0x5, 0x4e, 0x7e, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+            0x41, 0xcc, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2,
+            0x2, 0x2, 0x2, 0x2, 0xc0, 0xb4, 0x5, 0x4e, 0x7e, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
             0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf0, 0x4, 0xd2, 0x4, 0xd2, 0xf6,
             0x4d, 0x4c, 0x6f, 0x72, 0x65, 0x6d, 0x20, 0x69, 0x70, 0x73, 0x75, 0x6d, 0x20, 0x64,
             0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x73, 0x69, 0x74, 0x20, 0x61, 0x6d, 0x65, 0x74, 0x2c,
@@ -399,10 +399,10 @@ In at rhoncus tortor. Cras blandit tellus diam, varius vestibulum nibh commodo n
     );
 
     assert_eq!(
-        device.queue[1],
+        device.queue.pop_front().unwrap(),
         &[
-            0x41, 0xcc, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
-            0x0, 0x0, 0x0, 0x0, 0xe0, 0xb4, 0x5, 0x4e, 0xf, 0x6f, 0x72, 0x74, 0x6f, 0x72, 0x2e,
+            0x41, 0xcc, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2,
+            0x2, 0x2, 0x2, 0x2, 0xe0, 0xb4, 0x5, 0x4e, 0xf, 0x6f, 0x72, 0x74, 0x6f, 0x72, 0x2e,
             0x20, 0x43, 0x72, 0x61, 0x73, 0x20, 0x62, 0x6c, 0x61, 0x6e, 0x64, 0x69, 0x74, 0x20,
             0x74, 0x65, 0x6c, 0x6c, 0x75, 0x73, 0x20, 0x64, 0x69, 0x61, 0x6d, 0x2c, 0x20, 0x76,
             0x61, 0x72, 0x69, 0x75, 0x73, 0x20, 0x76, 0x65, 0x73, 0x74, 0x69, 0x62, 0x75, 0x6c,

+ 10 - 0
src/lib.rs

@@ -167,3 +167,13 @@ pub mod socket;
 pub mod storage;
 pub mod time;
 pub mod wire;
+
+#[cfg(all(
+    test,
+    any(
+        feature = "medium-ethernet",
+        feature = "medium-ip",
+        feature = "medium-ieee802154"
+    )
+))]
+mod tests;

+ 62 - 36
src/socket/dhcpv4.rs

@@ -1048,28 +1048,34 @@ mod test {
     // =========================================================================================//
     // Tests
 
-    fn socket() -> TestSocket {
+    use crate::phy::Medium;
+    use crate::tests::setup;
+    use rstest::*;
+
+    fn socket(medium: Medium) -> TestSocket {
+        let (iface, _, _) = setup(medium);
         let mut s = Socket::new();
         assert_eq!(s.poll(), Some(Event::Deconfigured));
         TestSocket {
             socket: s,
-            cx: Context::mock(),
+            cx: iface.inner,
         }
     }
 
-    fn socket_different_port() -> TestSocket {
+    fn socket_different_port(medium: Medium) -> TestSocket {
+        let (iface, _, _) = setup(medium);
         let mut s = Socket::new();
         s.set_ports(DIFFERENT_SERVER_PORT, DIFFERENT_CLIENT_PORT);
 
         assert_eq!(s.poll(), Some(Event::Deconfigured));
         TestSocket {
             socket: s,
-            cx: Context::mock(),
+            cx: iface.inner,
         }
     }
 
-    fn socket_bound() -> TestSocket {
-        let mut s = socket();
+    fn socket_bound(medium: Medium) -> TestSocket {
+        let mut s = socket(medium);
         s.state = ClientState::Renewing(RenewState {
             config: Config {
                 server: ServerInfo {
@@ -1090,9 +1096,11 @@ mod test {
         s
     }
 
-    #[test]
-    fn test_bind() {
-        let mut s = socket();
+    #[rstest]
+    #[case::ip(Medium::Ethernet)]
+    #[cfg(feature = "medium-ethernet")]
+    fn test_bind(#[case] medium: Medium) {
+        let mut s = socket(medium);
 
         recv!(s, [(IP_BROADCAST, UDP_SEND, DHCP_DISCOVER)]);
         assert_eq!(s.poll(), None);
@@ -1126,9 +1134,11 @@ mod test {
         }
     }
 
-    #[test]
-    fn test_bind_different_ports() {
-        let mut s = socket_different_port();
+    #[rstest]
+    #[case::ip(Medium::Ethernet)]
+    #[cfg(feature = "medium-ethernet")]
+    fn test_bind_different_ports(#[case] medium: Medium) {
+        let mut s = socket_different_port(medium);
 
         recv!(s, [(IP_BROADCAST, UDP_SEND_DIFFERENT_PORT, DHCP_DISCOVER)]);
         assert_eq!(s.poll(), None);
@@ -1162,9 +1172,11 @@ mod test {
         }
     }
 
-    #[test]
-    fn test_discover_retransmit() {
-        let mut s = socket();
+    #[rstest]
+    #[case::ip(Medium::Ethernet)]
+    #[cfg(feature = "medium-ethernet")]
+    fn test_discover_retransmit(#[case] medium: Medium) {
+        let mut s = socket(medium);
 
         recv!(s, time 0, [(IP_BROADCAST, UDP_SEND, DHCP_DISCOVER)]);
         recv!(s, time 1_000, []);
@@ -1177,9 +1189,11 @@ mod test {
         recv!(s, time 20_000, [(IP_BROADCAST, UDP_SEND, DHCP_REQUEST)]);
     }
 
-    #[test]
-    fn test_request_retransmit() {
-        let mut s = socket();
+    #[rstest]
+    #[case::ip(Medium::Ethernet)]
+    #[cfg(feature = "medium-ethernet")]
+    fn test_request_retransmit(#[case] medium: Medium) {
+        let mut s = socket(medium);
 
         recv!(s, time 0, [(IP_BROADCAST, UDP_SEND, DHCP_DISCOVER)]);
         send!(s, time 0, (IP_RECV, UDP_RECV, dhcp_offer()));
@@ -1203,9 +1217,11 @@ mod test {
         }
     }
 
-    #[test]
-    fn test_request_timeout() {
-        let mut s = socket();
+    #[rstest]
+    #[case::ip(Medium::Ethernet)]
+    #[cfg(feature = "medium-ethernet")]
+    fn test_request_timeout(#[case] medium: Medium) {
+        let mut s = socket(medium);
 
         recv!(s, time 0, [(IP_BROADCAST, UDP_SEND, DHCP_DISCOVER)]);
         send!(s, time 0, (IP_RECV, UDP_RECV, dhcp_offer()));
@@ -1224,9 +1240,11 @@ mod test {
         recv!(s, time 60_000, [(IP_BROADCAST, UDP_SEND, DHCP_REQUEST)]);
     }
 
-    #[test]
-    fn test_request_nak() {
-        let mut s = socket();
+    #[rstest]
+    #[case::ip(Medium::Ethernet)]
+    #[cfg(feature = "medium-ethernet")]
+    fn test_request_nak(#[case] medium: Medium) {
+        let mut s = socket(medium);
 
         recv!(s, time 0, [(IP_BROADCAST, UDP_SEND, DHCP_DISCOVER)]);
         send!(s, time 0, (IP_RECV, UDP_RECV, dhcp_offer()));
@@ -1235,9 +1253,11 @@ mod test {
         recv!(s, time 0, [(IP_BROADCAST, UDP_SEND, DHCP_DISCOVER)]);
     }
 
-    #[test]
-    fn test_renew() {
-        let mut s = socket_bound();
+    #[rstest]
+    #[case::ip(Medium::Ethernet)]
+    #[cfg(feature = "medium-ethernet")]
+    fn test_renew(#[case] medium: Medium) {
+        let mut s = socket_bound(medium);
 
         recv!(s, []);
         assert_eq!(s.poll(), None);
@@ -1266,9 +1286,11 @@ mod test {
         }
     }
 
-    #[test]
-    fn test_renew_rebind_retransmit() {
-        let mut s = socket_bound();
+    #[rstest]
+    #[case::ip(Medium::Ethernet)]
+    #[cfg(feature = "medium-ethernet")]
+    fn test_renew_rebind_retransmit(#[case] medium: Medium) {
+        let mut s = socket_bound(medium);
 
         recv!(s, []);
         // First renew attempt at T1
@@ -1306,9 +1328,11 @@ mod test {
         }
     }
 
-    #[test]
-    fn test_renew_rebind_timeout() {
-        let mut s = socket_bound();
+    #[rstest]
+    #[case::ip(Medium::Ethernet)]
+    #[cfg(feature = "medium-ethernet")]
+    fn test_renew_rebind_timeout(#[case] medium: Medium) {
+        let mut s = socket_bound(medium);
 
         recv!(s, []);
         // First renew attempt at T1
@@ -1334,9 +1358,11 @@ mod test {
         }
     }
 
-    #[test]
-    fn test_renew_nak() {
-        let mut s = socket_bound();
+    #[rstest]
+    #[case::ip(Medium::Ethernet)]
+    #[cfg(feature = "medium-ethernet")]
+    fn test_renew_nak(#[case] medium: Medium) {
+        let mut s = socket_bound(medium);
 
         recv!(s, time 500_000, [(IP_SEND, UDP_SEND, DHCP_RENEW)]);
         send!(s, time 500_000, (IP_SERVER_BROADCAST, UDP_RECV, DHCP_NAK));

+ 102 - 60
src/socket/icmp.rs

@@ -647,6 +647,10 @@ mod tests_common {
 
 #[cfg(all(test, feature = "proto-ipv4"))]
 mod test_ipv4 {
+    use crate::phy::Medium;
+    use crate::tests::setup;
+    use rstest::*;
+
     use super::tests_common::*;
     use crate::wire::{Icmpv4DstUnreachable, IpEndpoint, Ipv4Address};
 
@@ -689,16 +693,17 @@ mod test_ipv4 {
         assert_eq!(socket.send_slice(b"abcdef", REMOTE_IPV4.into()), Ok(()));
     }
 
-    #[test]
-    fn test_send_dispatch() {
+    #[rstest]
+    #[case::ethernet(Medium::Ethernet)]
+    #[cfg(feature = "medium-ethernet")]
+    fn test_send_dispatch(#[case] medium: Medium) {
+        let (mut iface, _, _) = setup(medium);
+        let cx = iface.context();
+
         let mut socket = socket(buffer(0), buffer(1));
-        let mut cx = Context::mock();
         let checksum = ChecksumCapabilities::default();
 
-        assert_eq!(
-            socket.dispatch(&mut cx, |_, _| unreachable!()),
-            Ok::<_, ()>(())
-        );
+        assert_eq!(socket.dispatch(cx, |_, _| unreachable!()), Ok::<_, ()>(()));
 
         // This buffer is too long
         assert_eq!(
@@ -722,7 +727,7 @@ mod test_ipv4 {
         assert!(!socket.can_send());
 
         assert_eq!(
-            socket.dispatch(&mut cx, |_, (ip_repr, icmp_repr)| {
+            socket.dispatch(cx, |_, (ip_repr, icmp_repr)| {
                 assert_eq!(ip_repr, LOCAL_IPV4_REPR);
                 assert_eq!(icmp_repr, ECHOV4_REPR.into());
                 Err(())
@@ -733,7 +738,7 @@ mod test_ipv4 {
         assert!(!socket.can_send());
 
         assert_eq!(
-            socket.dispatch(&mut cx, |_, (ip_repr, icmp_repr)| {
+            socket.dispatch(cx, |_, (ip_repr, icmp_repr)| {
                 assert_eq!(ip_repr, LOCAL_IPV4_REPR);
                 assert_eq!(icmp_repr, ECHOV4_REPR.into());
                 Ok::<_, ()>(())
@@ -744,10 +749,14 @@ mod test_ipv4 {
         assert!(socket.can_send());
     }
 
-    #[test]
-    fn test_set_hop_limit_v4() {
+    #[rstest]
+    #[case::ethernet(Medium::Ethernet)]
+    #[cfg(feature = "medium-ethernet")]
+    fn test_set_hop_limit_v4(#[case] medium: Medium) {
+        let (mut iface, _, _) = setup(medium);
+        let cx = iface.context();
+
         let mut s = socket(buffer(0), buffer(1));
-        let mut cx = Context::mock();
         let checksum = ChecksumCapabilities::default();
 
         let mut bytes = [0xff; 24];
@@ -761,7 +770,7 @@ mod test_ipv4 {
             Ok(())
         );
         assert_eq!(
-            s.dispatch(&mut cx, |_, (ip_repr, _)| {
+            s.dispatch(cx, |_, (ip_repr, _)| {
                 assert_eq!(
                     ip_repr,
                     IpRepr::Ipv4(Ipv4Repr {
@@ -778,10 +787,14 @@ mod test_ipv4 {
         );
     }
 
-    #[test]
-    fn test_recv_process() {
+    #[rstest]
+    #[case::ethernet(Medium::Ethernet)]
+    #[cfg(feature = "medium-ethernet")]
+    fn test_recv_process(#[case] medium: Medium) {
+        let (mut iface, _, _) = setup(medium);
+        let cx = iface.context();
+
         let mut socket = socket(buffer(1), buffer(1));
-        let mut cx = Context::mock();
         assert_eq!(socket.bind(Endpoint::Ident(0x1234)), Ok(()));
 
         assert!(!socket.can_recv());
@@ -794,21 +807,25 @@ mod test_ipv4 {
         ECHOV4_REPR.emit(&mut packet, &checksum);
         let data = &*packet.into_inner();
 
-        assert!(socket.accepts(&mut cx, &REMOTE_IPV4_REPR, &ECHOV4_REPR.into()));
-        socket.process(&mut cx, &REMOTE_IPV4_REPR, &ECHOV4_REPR.into());
+        assert!(socket.accepts(cx, &REMOTE_IPV4_REPR, &ECHOV4_REPR.into()));
+        socket.process(cx, &REMOTE_IPV4_REPR, &ECHOV4_REPR.into());
         assert!(socket.can_recv());
 
-        assert!(socket.accepts(&mut cx, &REMOTE_IPV4_REPR, &ECHOV4_REPR.into()));
-        socket.process(&mut cx, &REMOTE_IPV4_REPR, &ECHOV4_REPR.into());
+        assert!(socket.accepts(cx, &REMOTE_IPV4_REPR, &ECHOV4_REPR.into()));
+        socket.process(cx, &REMOTE_IPV4_REPR, &ECHOV4_REPR.into());
 
         assert_eq!(socket.recv(), Ok((data, REMOTE_IPV4.into())));
         assert!(!socket.can_recv());
     }
 
-    #[test]
-    fn test_accept_bad_id() {
+    #[rstest]
+    #[case::ethernet(Medium::Ethernet)]
+    #[cfg(feature = "medium-ethernet")]
+    fn test_accept_bad_id(#[case] medium: Medium) {
+        let (mut iface, _, _) = setup(medium);
+        let cx = iface.context();
+
         let mut socket = socket(buffer(1), buffer(1));
-        let mut cx = Context::mock();
         assert_eq!(socket.bind(Endpoint::Ident(0x1234)), Ok(()));
 
         let checksum = ChecksumCapabilities::default();
@@ -823,13 +840,17 @@ mod test_ipv4 {
 
         // Ensure that a packet with an identifier that isn't the bound
         // ID is not accepted
-        assert!(!socket.accepts(&mut cx, &REMOTE_IPV4_REPR, &icmp_repr.into()));
+        assert!(!socket.accepts(cx, &REMOTE_IPV4_REPR, &icmp_repr.into()));
     }
 
-    #[test]
-    fn test_accepts_udp() {
+    #[rstest]
+    #[case::ethernet(Medium::Ethernet)]
+    #[cfg(feature = "medium-ethernet")]
+    fn test_accepts_udp(#[case] medium: Medium) {
+        let (mut iface, _, _) = setup(medium);
+        let cx = iface.context();
+
         let mut socket = socket(buffer(1), buffer(1));
-        let mut cx = Context::mock();
         assert_eq!(socket.bind(Endpoint::Udp(LOCAL_END_V4.into())), Ok(()));
 
         let checksum = ChecksumCapabilities::default();
@@ -856,7 +877,7 @@ mod test_ipv4 {
                 payload_len: 12,
                 hop_limit: 0x40,
             },
-            data: data,
+            data,
         };
         let ip_repr = IpRepr::Ipv4(Ipv4Repr {
             src_addr: REMOTE_IPV4,
@@ -870,8 +891,8 @@ mod test_ipv4 {
 
         // Ensure we can accept ICMP error response to the bound
         // UDP port
-        assert!(socket.accepts(&mut cx, &ip_repr, &icmp_repr.into()));
-        socket.process(&mut cx, &ip_repr, &icmp_repr.into());
+        assert!(socket.accepts(cx, &ip_repr, &icmp_repr.into()));
+        socket.process(cx, &ip_repr, &icmp_repr.into());
         assert!(socket.can_recv());
 
         let mut bytes = [0x00; 46];
@@ -887,6 +908,10 @@ mod test_ipv4 {
 
 #[cfg(all(test, feature = "proto-ipv6"))]
 mod test_ipv6 {
+    use crate::phy::Medium;
+    use crate::tests::setup;
+    use rstest::*;
+
     use super::tests_common::*;
 
     use crate::wire::{Icmpv6DstUnreachable, IpEndpoint, Ipv6Address};
@@ -931,16 +956,17 @@ mod test_ipv6 {
         assert_eq!(socket.send_slice(b"abcdef", REMOTE_IPV6.into()), Ok(()));
     }
 
-    #[test]
-    fn test_send_dispatch() {
+    #[rstest]
+    #[case::ethernet(Medium::Ethernet)]
+    #[cfg(feature = "medium-ethernet")]
+    fn test_send_dispatch(#[case] medium: Medium) {
+        let (mut iface, _, _) = setup(medium);
+        let cx = iface.context();
+
         let mut socket = socket(buffer(0), buffer(1));
-        let mut cx = Context::mock();
         let checksum = ChecksumCapabilities::default();
 
-        assert_eq!(
-            socket.dispatch(&mut cx, |_, _| unreachable!()),
-            Ok::<_, ()>(())
-        );
+        assert_eq!(socket.dispatch(cx, |_, _| unreachable!()), Ok::<_, ()>(()));
 
         // This buffer is too long
         assert_eq!(
@@ -969,7 +995,7 @@ mod test_ipv6 {
         assert!(!socket.can_send());
 
         assert_eq!(
-            socket.dispatch(&mut cx, |_, (ip_repr, icmp_repr)| {
+            socket.dispatch(cx, |_, (ip_repr, icmp_repr)| {
                 assert_eq!(ip_repr, LOCAL_IPV6_REPR);
                 assert_eq!(icmp_repr, ECHOV6_REPR.into());
                 Err(())
@@ -980,7 +1006,7 @@ mod test_ipv6 {
         assert!(!socket.can_send());
 
         assert_eq!(
-            socket.dispatch(&mut cx, |_, (ip_repr, icmp_repr)| {
+            socket.dispatch(cx, |_, (ip_repr, icmp_repr)| {
                 assert_eq!(ip_repr, LOCAL_IPV6_REPR);
                 assert_eq!(icmp_repr, ECHOV6_REPR.into());
                 Ok::<_, ()>(())
@@ -991,10 +1017,14 @@ mod test_ipv6 {
         assert!(socket.can_send());
     }
 
-    #[test]
-    fn test_set_hop_limit() {
+    #[rstest]
+    #[case::ethernet(Medium::Ethernet)]
+    #[cfg(feature = "medium-ethernet")]
+    fn test_set_hop_limit(#[case] medium: Medium) {
+        let (mut iface, _, _) = setup(medium);
+        let cx = iface.context();
+
         let mut s = socket(buffer(0), buffer(1));
-        let mut cx = Context::mock();
         let checksum = ChecksumCapabilities::default();
 
         let mut bytes = vec![0xff; 24];
@@ -1013,7 +1043,7 @@ mod test_ipv6 {
             Ok(())
         );
         assert_eq!(
-            s.dispatch(&mut cx, |_, (ip_repr, _)| {
+            s.dispatch(cx, |_, (ip_repr, _)| {
                 assert_eq!(
                     ip_repr,
                     IpRepr::Ipv6(Ipv6Repr {
@@ -1030,10 +1060,14 @@ mod test_ipv6 {
         );
     }
 
-    #[test]
-    fn test_recv_process() {
+    #[rstest]
+    #[case::ethernet(Medium::Ethernet)]
+    #[cfg(feature = "medium-ethernet")]
+    fn test_recv_process(#[case] medium: Medium) {
+        let (mut iface, _, _) = setup(medium);
+        let cx = iface.context();
+
         let mut socket = socket(buffer(1), buffer(1));
-        let mut cx = Context::mock();
         assert_eq!(socket.bind(Endpoint::Ident(0x1234)), Ok(()));
 
         assert!(!socket.can_recv());
@@ -1051,21 +1085,25 @@ mod test_ipv6 {
         );
         let data = &*packet.into_inner();
 
-        assert!(socket.accepts(&mut cx, &REMOTE_IPV6_REPR, &ECHOV6_REPR.into()));
-        socket.process(&mut cx, &REMOTE_IPV6_REPR, &ECHOV6_REPR.into());
+        assert!(socket.accepts(cx, &REMOTE_IPV6_REPR, &ECHOV6_REPR.into()));
+        socket.process(cx, &REMOTE_IPV6_REPR, &ECHOV6_REPR.into());
         assert!(socket.can_recv());
 
-        assert!(socket.accepts(&mut cx, &REMOTE_IPV6_REPR, &ECHOV6_REPR.into()));
-        socket.process(&mut cx, &REMOTE_IPV6_REPR, &ECHOV6_REPR.into());
+        assert!(socket.accepts(cx, &REMOTE_IPV6_REPR, &ECHOV6_REPR.into()));
+        socket.process(cx, &REMOTE_IPV6_REPR, &ECHOV6_REPR.into());
 
         assert_eq!(socket.recv(), Ok((data, REMOTE_IPV6.into())));
         assert!(!socket.can_recv());
     }
 
-    #[test]
-    fn test_accept_bad_id() {
+    #[rstest]
+    #[case::ethernet(Medium::Ethernet)]
+    #[cfg(feature = "medium-ethernet")]
+    fn test_accept_bad_id(#[case] medium: Medium) {
+        let (mut iface, _, _) = setup(medium);
+        let cx = iface.context();
+
         let mut socket = socket(buffer(1), buffer(1));
-        let mut cx = Context::mock();
         assert_eq!(socket.bind(Endpoint::Ident(0x1234)), Ok(()));
 
         let checksum = ChecksumCapabilities::default();
@@ -1085,13 +1123,17 @@ mod test_ipv6 {
 
         // Ensure that a packet with an identifier that isn't the bound
         // ID is not accepted
-        assert!(!socket.accepts(&mut cx, &REMOTE_IPV6_REPR, &icmp_repr.into()));
+        assert!(!socket.accepts(cx, &REMOTE_IPV6_REPR, &icmp_repr.into()));
     }
 
-    #[test]
-    fn test_accepts_udp() {
+    #[rstest]
+    #[case::ethernet(Medium::Ethernet)]
+    #[cfg(feature = "medium-ethernet")]
+    fn test_accepts_udp(#[case] medium: Medium) {
+        let (mut iface, _, _) = setup(medium);
+        let cx = iface.context();
+
         let mut socket = socket(buffer(1), buffer(1));
-        let mut cx = Context::mock();
         assert_eq!(socket.bind(Endpoint::Udp(LOCAL_END_V6.into())), Ok(()));
 
         let checksum = ChecksumCapabilities::default();
@@ -1118,7 +1160,7 @@ mod test_ipv6 {
                 payload_len: 12,
                 hop_limit: 0x40,
             },
-            data: data,
+            data,
         };
         let ip_repr = IpRepr::Ipv6(Ipv6Repr {
             src_addr: REMOTE_IPV6,
@@ -1132,8 +1174,8 @@ mod test_ipv6 {
 
         // Ensure we can accept ICMP error response to the bound
         // UDP port
-        assert!(socket.accepts(&mut cx, &ip_repr, &icmp_repr.into()));
-        socket.process(&mut cx, &ip_repr, &icmp_repr.into());
+        assert!(socket.accepts(cx, &ip_repr, &icmp_repr.into()));
+        socket.process(cx, &ip_repr, &icmp_repr.into());
         assert!(socket.can_recv());
 
         let mut bytes = [0x00; 66];

+ 90 - 81
src/socket/raw.rs

@@ -445,6 +445,10 @@ impl<'a> Socket<'a> {
 
 #[cfg(test)]
 mod test {
+    use crate::phy::Medium;
+    use crate::tests::setup;
+    use rstest::*;
+
     use super::*;
     use crate::wire::IpRepr;
     #[cfg(feature = "proto-ipv4")]
@@ -539,10 +543,17 @@ mod test {
                     assert_eq!(socket.send_slice(&[0; 56][..]), Err(SendError::BufferFull));
                 }
 
-                #[test]
-                fn test_send_dispatch() {
+                #[rstest]
+                #[case::ip(Medium::Ip)]
+                #[cfg(feature = "medium-ip")]
+                #[case::ethernet(Medium::Ethernet)]
+                #[cfg(feature = "medium-ethernet")]
+                #[case::ieee802154(Medium::Ieee802154)]
+                #[cfg(feature = "medium-ieee802154")]
+                fn test_send_dispatch(#[case] medium: Medium) {
+                    let (mut iface, _, _) = setup(medium);
+                    let mut cx = iface.context();
                     let mut socket = $socket(buffer(0), buffer(1));
-                    let mut cx = Context::mock();
 
                     assert!(socket.can_send());
                     assert_eq!(
@@ -575,10 +586,17 @@ mod test {
                     assert!(socket.can_send());
                 }
 
-                #[test]
-                fn test_recv_truncated_slice() {
+                #[rstest]
+                #[case::ip(Medium::Ip)]
+                #[cfg(feature = "medium-ip")]
+                #[case::ethernet(Medium::Ethernet)]
+                #[cfg(feature = "medium-ethernet")]
+                #[case::ieee802154(Medium::Ieee802154)]
+                #[cfg(feature = "medium-ieee802154")]
+                fn test_recv_truncated_slice(#[case] medium: Medium) {
+                    let (mut iface, _, _) = setup(medium);
+                    let mut cx = iface.context();
                     let mut socket = $socket(buffer(1), buffer(0));
-                    let mut cx = Context::mock();
 
                     assert!(socket.accepts(&$hdr));
                     socket.process(&mut cx, &$hdr, &$payload);
@@ -588,10 +606,17 @@ mod test {
                     assert_eq!(&slice, &$packet[..slice.len()]);
                 }
 
-                #[test]
-                fn test_recv_truncated_packet() {
+                #[rstest]
+                #[case::ip(Medium::Ip)]
+                #[cfg(feature = "medium-ip")]
+                #[case::ethernet(Medium::Ethernet)]
+                #[cfg(feature = "medium-ethernet")]
+                #[case::ieee802154(Medium::Ieee802154)]
+                #[cfg(feature = "medium-ieee802154")]
+                fn test_recv_truncated_packet(#[case] medium: Medium) {
+                    let (mut iface, _, _) = setup(medium);
+                    let mut cx = iface.context();
                     let mut socket = $socket(buffer(1), buffer(0));
-                    let mut cx = Context::mock();
 
                     let mut buffer = vec![0; 128];
                     buffer[..$packet.len()].copy_from_slice(&$packet[..]);
@@ -600,10 +625,17 @@ mod test {
                     socket.process(&mut cx, &$hdr, &buffer);
                 }
 
-                #[test]
-                fn test_peek_truncated_slice() {
+                #[rstest]
+                #[case::ip(Medium::Ip)]
+                #[cfg(feature = "medium-ip")]
+                #[case::ethernet(Medium::Ethernet)]
+                #[cfg(feature = "medium-ethernet")]
+                #[case::ieee802154(Medium::Ieee802154)]
+                #[cfg(feature = "medium-ieee802154")]
+                fn test_peek_truncated_slice(#[case] medium: Medium) {
+                    let (mut iface, _, _) = setup(medium);
+                    let mut cx = iface.context();
                     let mut socket = $socket(buffer(1), buffer(0));
-                    let mut cx = Context::mock();
 
                     assert!(socket.accepts(&$hdr));
                     socket.process(&mut cx, &$hdr, &$payload);
@@ -637,159 +669,136 @@ mod test {
         ipv6_locals::PACKET_PAYLOAD
     );
 
-    #[test]
-    #[cfg(feature = "proto-ipv4")]
-    fn test_send_illegal() {
+    #[rstest]
+    #[case::ip(Medium::Ip)]
+    #[case::ethernet(Medium::Ethernet)]
+    #[cfg(feature = "medium-ethernet")]
+    #[case::ieee802154(Medium::Ieee802154)]
+    #[cfg(feature = "medium-ieee802154")]
+    fn test_send_illegal(#[case] medium: Medium) {
         #[cfg(feature = "proto-ipv4")]
         {
+            let (mut iface, _, _) = setup(medium);
+            let cx = iface.context();
             let mut socket = ipv4_locals::socket(buffer(0), buffer(2));
-            let mut cx = Context::mock();
 
             let mut wrong_version = ipv4_locals::PACKET_BYTES;
             Ipv4Packet::new_unchecked(&mut wrong_version).set_version(6);
 
             assert_eq!(socket.send_slice(&wrong_version[..]), Ok(()));
-            assert_eq!(
-                socket.dispatch(&mut cx, |_, _| unreachable!()),
-                Ok::<_, ()>(())
-            );
+            assert_eq!(socket.dispatch(cx, |_, _| unreachable!()), Ok::<_, ()>(()));
 
             let mut wrong_protocol = ipv4_locals::PACKET_BYTES;
             Ipv4Packet::new_unchecked(&mut wrong_protocol).set_next_header(IpProtocol::Tcp);
 
             assert_eq!(socket.send_slice(&wrong_protocol[..]), Ok(()));
-            assert_eq!(
-                socket.dispatch(&mut cx, |_, _| unreachable!()),
-                Ok::<_, ()>(())
-            );
+            assert_eq!(socket.dispatch(cx, |_, _| unreachable!()), Ok::<_, ()>(()));
         }
         #[cfg(feature = "proto-ipv6")]
         {
+            let (mut iface, _, _) = setup(medium);
+            let cx = iface.context();
             let mut socket = ipv6_locals::socket(buffer(0), buffer(2));
-            let mut cx = Context::mock();
 
             let mut wrong_version = ipv6_locals::PACKET_BYTES;
             Ipv6Packet::new_unchecked(&mut wrong_version[..]).set_version(4);
 
             assert_eq!(socket.send_slice(&wrong_version[..]), Ok(()));
-            assert_eq!(
-                socket.dispatch(&mut cx, |_, _| unreachable!()),
-                Ok::<_, ()>(())
-            );
+            assert_eq!(socket.dispatch(cx, |_, _| unreachable!()), Ok::<_, ()>(()));
 
             let mut wrong_protocol = ipv6_locals::PACKET_BYTES;
             Ipv6Packet::new_unchecked(&mut wrong_protocol[..]).set_next_header(IpProtocol::Tcp);
 
             assert_eq!(socket.send_slice(&wrong_protocol[..]), Ok(()));
-            assert_eq!(
-                socket.dispatch(&mut cx, |_, _| unreachable!()),
-                Ok::<_, ()>(())
-            );
+            assert_eq!(socket.dispatch(cx, |_, _| unreachable!()), Ok::<_, ()>(()));
         }
     }
 
-    #[test]
-    fn test_recv_process() {
+    #[rstest]
+    #[case::ip(Medium::Ip)]
+    #[cfg(feature = "medium-ip")]
+    #[case::ethernet(Medium::Ethernet)]
+    #[cfg(feature = "medium-ethernet")]
+    #[case::ieee802154(Medium::Ieee802154)]
+    #[cfg(feature = "medium-ieee802154")]
+    fn test_recv_process(#[case] medium: Medium) {
         #[cfg(feature = "proto-ipv4")]
         {
+            let (mut iface, _, _) = setup(medium);
+            let cx = iface.context();
             let mut socket = ipv4_locals::socket(buffer(1), buffer(0));
             assert!(!socket.can_recv());
-            let mut cx = Context::mock();
 
             let mut cksumd_packet = ipv4_locals::PACKET_BYTES;
             Ipv4Packet::new_unchecked(&mut cksumd_packet).fill_checksum();
 
             assert_eq!(socket.recv(), Err(RecvError::Exhausted));
             assert!(socket.accepts(&ipv4_locals::HEADER_REPR));
-            socket.process(
-                &mut cx,
-                &ipv4_locals::HEADER_REPR,
-                &ipv4_locals::PACKET_PAYLOAD,
-            );
+            socket.process(cx, &ipv4_locals::HEADER_REPR, &ipv4_locals::PACKET_PAYLOAD);
             assert!(socket.can_recv());
 
             assert!(socket.accepts(&ipv4_locals::HEADER_REPR));
-            socket.process(
-                &mut cx,
-                &ipv4_locals::HEADER_REPR,
-                &ipv4_locals::PACKET_PAYLOAD,
-            );
+            socket.process(cx, &ipv4_locals::HEADER_REPR, &ipv4_locals::PACKET_PAYLOAD);
             assert_eq!(socket.recv(), Ok(&cksumd_packet[..]));
             assert!(!socket.can_recv());
         }
         #[cfg(feature = "proto-ipv6")]
         {
+            let (mut iface, _, _) = setup(medium);
+            let cx = iface.context();
             let mut socket = ipv6_locals::socket(buffer(1), buffer(0));
             assert!(!socket.can_recv());
-            let mut cx = Context::mock();
 
             assert_eq!(socket.recv(), Err(RecvError::Exhausted));
             assert!(socket.accepts(&ipv6_locals::HEADER_REPR));
-            socket.process(
-                &mut cx,
-                &ipv6_locals::HEADER_REPR,
-                &ipv6_locals::PACKET_PAYLOAD,
-            );
+            socket.process(cx, &ipv6_locals::HEADER_REPR, &ipv6_locals::PACKET_PAYLOAD);
             assert!(socket.can_recv());
 
             assert!(socket.accepts(&ipv6_locals::HEADER_REPR));
-            socket.process(
-                &mut cx,
-                &ipv6_locals::HEADER_REPR,
-                &ipv6_locals::PACKET_PAYLOAD,
-            );
+            socket.process(cx, &ipv6_locals::HEADER_REPR, &ipv6_locals::PACKET_PAYLOAD);
             assert_eq!(socket.recv(), Ok(&ipv6_locals::PACKET_BYTES[..]));
             assert!(!socket.can_recv());
         }
     }
 
-    #[test]
-    fn test_peek_process() {
+    #[rstest]
+    #[case::ip(Medium::Ip)]
+    #[case::ethernet(Medium::Ethernet)]
+    #[cfg(feature = "medium-ethernet")]
+    #[case::ieee802154(Medium::Ieee802154)]
+    #[cfg(feature = "medium-ieee802154")]
+    fn test_peek_process(#[case] medium: Medium) {
         #[cfg(feature = "proto-ipv4")]
         {
+            let (mut iface, _, _) = setup(medium);
+            let cx = iface.context();
             let mut socket = ipv4_locals::socket(buffer(1), buffer(0));
-            let mut cx = Context::mock();
 
             let mut cksumd_packet = ipv4_locals::PACKET_BYTES;
             Ipv4Packet::new_unchecked(&mut cksumd_packet).fill_checksum();
 
             assert_eq!(socket.peek(), Err(RecvError::Exhausted));
             assert!(socket.accepts(&ipv4_locals::HEADER_REPR));
-            socket.process(
-                &mut cx,
-                &ipv4_locals::HEADER_REPR,
-                &ipv4_locals::PACKET_PAYLOAD,
-            );
+            socket.process(cx, &ipv4_locals::HEADER_REPR, &ipv4_locals::PACKET_PAYLOAD);
 
             assert!(socket.accepts(&ipv4_locals::HEADER_REPR));
-            socket.process(
-                &mut cx,
-                &ipv4_locals::HEADER_REPR,
-                &ipv4_locals::PACKET_PAYLOAD,
-            );
+            socket.process(cx, &ipv4_locals::HEADER_REPR, &ipv4_locals::PACKET_PAYLOAD);
             assert_eq!(socket.peek(), Ok(&cksumd_packet[..]));
             assert_eq!(socket.recv(), Ok(&cksumd_packet[..]));
             assert_eq!(socket.peek(), Err(RecvError::Exhausted));
         }
         #[cfg(feature = "proto-ipv6")]
         {
+            let (mut iface, _, _) = setup(medium);
+            let cx = iface.context();
             let mut socket = ipv6_locals::socket(buffer(1), buffer(0));
-            let mut cx = Context::mock();
 
             assert_eq!(socket.peek(), Err(RecvError::Exhausted));
             assert!(socket.accepts(&ipv6_locals::HEADER_REPR));
-            socket.process(
-                &mut cx,
-                &ipv6_locals::HEADER_REPR,
-                &ipv6_locals::PACKET_PAYLOAD,
-            );
+            socket.process(cx, &ipv6_locals::HEADER_REPR, &ipv6_locals::PACKET_PAYLOAD);
 
             assert!(socket.accepts(&ipv6_locals::HEADER_REPR));
-            socket.process(
-                &mut cx,
-                &ipv6_locals::HEADER_REPR,
-                &ipv6_locals::PACKET_PAYLOAD,
-            );
+            socket.process(cx, &ipv6_locals::HEADER_REPR, &ipv6_locals::PACKET_PAYLOAD);
             assert_eq!(socket.peek(), Ok(&ipv6_locals::PACKET_BYTES[..]));
             assert_eq!(socket.recv(), Ok(&ipv6_locals::PACKET_BYTES[..]));
             assert_eq!(socket.peek(), Err(RecvError::Exhausted));

+ 10 - 3
src/socket/tcp.rs

@@ -2378,7 +2378,10 @@ impl<'a> fmt::Write for Socket<'a> {
     }
 }
 
-#[cfg(test)]
+// TODO: TCP should work for all features. For now, we only test with the IP feature. We could do
+// it for other features as well with rstest, however, this means we have to modify a lot of the
+// tests in here, which I didn't had the time for at the moment.
+#[cfg(all(test, feature = "medium-ip"))]
 mod test {
     use super::*;
     use crate::wire::IpRepr;
@@ -2624,12 +2627,16 @@ mod test {
     }
 
     fn socket_with_buffer_sizes(tx_len: usize, rx_len: usize) -> TestSocket {
+        let (iface, _, _) = crate::tests::setup(crate::phy::Medium::Ip);
+
         let rx_buffer = SocketBuffer::new(vec![0; rx_len]);
         let tx_buffer = SocketBuffer::new(vec![0; tx_len]);
         let mut socket = Socket::new(rx_buffer, tx_buffer);
         socket.set_ack_delay(None);
-        let cx = Context::mock();
-        TestSocket { socket, cx }
+        TestSocket {
+            socket,
+            cx: iface.inner,
+        }
     }
 
     fn socket_syn_received_with_buffer_sizes(tx_len: usize, rx_len: usize) -> TestSocket {

+ 118 - 44
src/socket/udp.rs

@@ -560,6 +560,10 @@ mod test {
     use super::*;
     use crate::wire::{IpRepr, UdpRepr};
 
+    use crate::phy::Medium;
+    use crate::tests::setup;
+    use rstest::*;
+
     fn buffer(packets: usize) -> PacketBuffer<'static> {
         PacketBuffer::new(
             (0..packets)
@@ -702,16 +706,23 @@ mod test {
         assert_eq!(socket.send_slice(b"abcdef", REMOTE_END), Ok(()));
     }
 
-    #[test]
-    fn test_send_dispatch() {
+    #[rstest]
+    #[case::ip(Medium::Ip)]
+    #[cfg(feature = "medium-ip")]
+    #[case::ethernet(Medium::Ethernet)]
+    #[cfg(feature = "medium-ethernet")]
+    #[case::ieee802154(Medium::Ieee802154)]
+    #[cfg(feature = "medium-ieee802154")]
+    fn test_send_dispatch(#[case] medium: Medium) {
+        let (mut iface, _, _) = setup(medium);
+        let cx = iface.context();
         let mut socket = socket(buffer(0), buffer(1));
-        let mut cx = Context::mock();
 
         assert_eq!(socket.bind(LOCAL_END), Ok(()));
 
         assert!(socket.can_send());
         assert_eq!(
-            socket.dispatch(&mut cx, |_, _, _| unreachable!()),
+            socket.dispatch(cx, |_, _, _| unreachable!()),
             Ok::<_, ()>(())
         );
 
@@ -723,7 +734,7 @@ mod test {
         assert!(!socket.can_send());
 
         assert_eq!(
-            socket.dispatch(&mut cx, |_, _, (ip_repr, udp_repr, payload)| {
+            socket.dispatch(cx, |_, _, (ip_repr, udp_repr, payload)| {
                 assert_eq!(ip_repr, LOCAL_IP_REPR);
                 assert_eq!(udp_repr, LOCAL_UDP_REPR);
                 assert_eq!(payload, PAYLOAD);
@@ -734,7 +745,7 @@ mod test {
         assert!(!socket.can_send());
 
         assert_eq!(
-            socket.dispatch(&mut cx, |_, _, (ip_repr, udp_repr, payload)| {
+            socket.dispatch(cx, |_, _, (ip_repr, udp_repr, payload)| {
                 assert_eq!(ip_repr, LOCAL_IP_REPR);
                 assert_eq!(udp_repr, LOCAL_UDP_REPR);
                 assert_eq!(payload, PAYLOAD);
@@ -745,19 +756,27 @@ mod test {
         assert!(socket.can_send());
     }
 
-    #[test]
-    fn test_recv_process() {
+    #[rstest]
+    #[case::ip(Medium::Ip)]
+    #[cfg(feature = "medium-ip")]
+    #[case::ethernet(Medium::Ethernet)]
+    #[cfg(feature = "medium-ethernet")]
+    #[case::ieee802154(Medium::Ieee802154)]
+    #[cfg(feature = "medium-ieee802154")]
+    fn test_recv_process(#[case] medium: Medium) {
+        let (mut iface, _, _) = setup(medium);
+        let cx = iface.context();
+
         let mut socket = socket(buffer(1), buffer(0));
-        let mut cx = Context::mock();
 
         assert_eq!(socket.bind(LOCAL_PORT), Ok(()));
 
         assert!(!socket.can_recv());
         assert_eq!(socket.recv(), Err(RecvError::Exhausted));
 
-        assert!(socket.accepts(&mut cx, &REMOTE_IP_REPR, &REMOTE_UDP_REPR));
+        assert!(socket.accepts(cx, &REMOTE_IP_REPR, &REMOTE_UDP_REPR));
         socket.process(
-            &mut cx,
+            cx,
             PacketMeta::default(),
             &REMOTE_IP_REPR,
             &REMOTE_UDP_REPR,
@@ -765,9 +784,9 @@ mod test {
         );
         assert!(socket.can_recv());
 
-        assert!(socket.accepts(&mut cx, &REMOTE_IP_REPR, &REMOTE_UDP_REPR));
+        assert!(socket.accepts(cx, &REMOTE_IP_REPR, &REMOTE_UDP_REPR));
         socket.process(
-            &mut cx,
+            cx,
             PacketMeta::default(),
             &REMOTE_IP_REPR,
             &REMOTE_UDP_REPR,
@@ -778,17 +797,25 @@ mod test {
         assert!(!socket.can_recv());
     }
 
-    #[test]
-    fn test_peek_process() {
+    #[rstest]
+    #[case::ip(Medium::Ip)]
+    #[cfg(feature = "medium-ip")]
+    #[case::ethernet(Medium::Ethernet)]
+    #[cfg(feature = "medium-ethernet")]
+    #[case::ieee802154(Medium::Ieee802154)]
+    #[cfg(feature = "medium-ieee802154")]
+    fn test_peek_process(#[case] medium: Medium) {
+        let (mut iface, _, _) = setup(medium);
+        let cx = iface.context();
+
         let mut socket = socket(buffer(1), buffer(0));
-        let mut cx = Context::mock();
 
         assert_eq!(socket.bind(LOCAL_PORT), Ok(()));
 
         assert_eq!(socket.peek(), Err(RecvError::Exhausted));
 
         socket.process(
-            &mut cx,
+            cx,
             PacketMeta::default(),
             &REMOTE_IP_REPR,
             &REMOTE_UDP_REPR,
@@ -799,16 +826,24 @@ mod test {
         assert_eq!(socket.peek(), Err(RecvError::Exhausted));
     }
 
-    #[test]
-    fn test_recv_truncated_slice() {
+    #[rstest]
+    #[case::ip(Medium::Ip)]
+    #[cfg(feature = "medium-ip")]
+    #[case::ethernet(Medium::Ethernet)]
+    #[cfg(feature = "medium-ethernet")]
+    #[case::ieee802154(Medium::Ieee802154)]
+    #[cfg(feature = "medium-ieee802154")]
+    fn test_recv_truncated_slice(#[case] medium: Medium) {
+        let (mut iface, _, _) = setup(medium);
+        let cx = iface.context();
+
         let mut socket = socket(buffer(1), buffer(0));
-        let mut cx = Context::mock();
 
         assert_eq!(socket.bind(LOCAL_PORT), Ok(()));
 
-        assert!(socket.accepts(&mut cx, &REMOTE_IP_REPR, &REMOTE_UDP_REPR));
+        assert!(socket.accepts(cx, &REMOTE_IP_REPR, &REMOTE_UDP_REPR));
         socket.process(
-            &mut cx,
+            cx,
             PacketMeta::default(),
             &REMOTE_IP_REPR,
             &REMOTE_UDP_REPR,
@@ -823,15 +858,23 @@ mod test {
         assert_eq!(&slice, b"abcd");
     }
 
-    #[test]
-    fn test_peek_truncated_slice() {
+    #[rstest]
+    #[case::ip(Medium::Ip)]
+    #[cfg(feature = "medium-ip")]
+    #[case::ethernet(Medium::Ethernet)]
+    #[cfg(feature = "medium-ethernet")]
+    #[case::ieee802154(Medium::Ieee802154)]
+    #[cfg(feature = "medium-ieee802154")]
+    fn test_peek_truncated_slice(#[case] medium: Medium) {
+        let (mut iface, _, _) = setup(medium);
+        let cx = iface.context();
+
         let mut socket = socket(buffer(1), buffer(0));
-        let mut cx = Context::mock();
 
         assert_eq!(socket.bind(LOCAL_PORT), Ok(()));
 
         socket.process(
-            &mut cx,
+            cx,
             PacketMeta::default(),
             &REMOTE_IP_REPR,
             &REMOTE_UDP_REPR,
@@ -852,17 +895,25 @@ mod test {
         assert_eq!(socket.peek_slice(&mut slice[..]), Err(RecvError::Exhausted));
     }
 
-    #[test]
-    fn test_set_hop_limit() {
+    #[rstest]
+    #[case::ip(Medium::Ip)]
+    #[cfg(feature = "medium-ip")]
+    #[case::ethernet(Medium::Ethernet)]
+    #[cfg(feature = "medium-ethernet")]
+    #[case::ieee802154(Medium::Ieee802154)]
+    #[cfg(feature = "medium-ieee802154")]
+    fn test_set_hop_limit(#[case] medium: Medium) {
+        let (mut iface, _, _) = setup(medium);
+        let cx = iface.context();
+
         let mut s = socket(buffer(0), buffer(1));
-        let mut cx = Context::mock();
 
         assert_eq!(s.bind(LOCAL_END), Ok(()));
 
         s.set_hop_limit(Some(0x2a));
         assert_eq!(s.send_slice(b"abcdef", REMOTE_END), Ok(()));
         assert_eq!(
-            s.dispatch(&mut cx, |_, _, (ip_repr, _, _)| {
+            s.dispatch(cx, |_, _, (ip_repr, _, _)| {
                 assert_eq!(
                     ip_repr,
                     IpReprIpvX(IpvXRepr {
@@ -879,30 +930,45 @@ mod test {
         );
     }
 
-    #[test]
-    fn test_doesnt_accept_wrong_port() {
+    #[rstest]
+    #[case::ip(Medium::Ip)]
+    #[cfg(feature = "medium-ip")]
+    #[case::ethernet(Medium::Ethernet)]
+    #[cfg(feature = "medium-ethernet")]
+    #[case::ieee802154(Medium::Ieee802154)]
+    #[cfg(feature = "medium-ieee802154")]
+    fn test_doesnt_accept_wrong_port(#[case] medium: Medium) {
+        let (mut iface, _, _) = setup(medium);
+        let cx = iface.context();
+
         let mut socket = socket(buffer(1), buffer(0));
-        let mut cx = Context::mock();
 
         assert_eq!(socket.bind(LOCAL_PORT), Ok(()));
 
         let mut udp_repr = REMOTE_UDP_REPR;
-        assert!(socket.accepts(&mut cx, &REMOTE_IP_REPR, &udp_repr));
+        assert!(socket.accepts(cx, &REMOTE_IP_REPR, &udp_repr));
         udp_repr.dst_port += 1;
-        assert!(!socket.accepts(&mut cx, &REMOTE_IP_REPR, &udp_repr));
+        assert!(!socket.accepts(cx, &REMOTE_IP_REPR, &udp_repr));
     }
 
-    #[test]
-    fn test_doesnt_accept_wrong_ip() {
-        let mut cx = Context::mock();
+    #[rstest]
+    #[case::ip(Medium::Ip)]
+    #[cfg(feature = "medium-ip")]
+    #[case::ethernet(Medium::Ethernet)]
+    #[cfg(feature = "medium-ethernet")]
+    #[case::ieee802154(Medium::Ieee802154)]
+    #[cfg(feature = "medium-ieee802154")]
+    fn test_doesnt_accept_wrong_ip(#[case] medium: Medium) {
+        let (mut iface, _, _) = setup(medium);
+        let cx = iface.context();
 
         let mut port_bound_socket = socket(buffer(1), buffer(0));
         assert_eq!(port_bound_socket.bind(LOCAL_PORT), Ok(()));
-        assert!(port_bound_socket.accepts(&mut cx, &BAD_IP_REPR, &REMOTE_UDP_REPR));
+        assert!(port_bound_socket.accepts(cx, &BAD_IP_REPR, &REMOTE_UDP_REPR));
 
         let mut ip_bound_socket = socket(buffer(1), buffer(0));
         assert_eq!(ip_bound_socket.bind(LOCAL_END), Ok(()));
-        assert!(!ip_bound_socket.accepts(&mut cx, &BAD_IP_REPR, &REMOTE_UDP_REPR));
+        assert!(!ip_bound_socket.accepts(cx, &BAD_IP_REPR, &REMOTE_UDP_REPR));
     }
 
     #[test]
@@ -919,12 +985,20 @@ mod test {
         assert_eq!(socket.send_slice(&too_large[..16 * 4], REMOTE_END), Ok(()));
     }
 
-    #[test]
-    fn test_process_empty_payload() {
+    #[rstest]
+    #[case::ip(Medium::Ip)]
+    #[cfg(feature = "medium-ip")]
+    #[case::ethernet(Medium::Ethernet)]
+    #[cfg(feature = "medium-ethernet")]
+    #[case::ieee802154(Medium::Ieee802154)]
+    #[cfg(feature = "medium-ieee802154")]
+    fn test_process_empty_payload(#[case] medium: Medium) {
         let meta = Box::leak(Box::new([PacketMetadata::EMPTY]));
         let recv_buffer = PacketBuffer::new(&mut meta[..], vec![]);
         let mut socket = socket(recv_buffer, buffer(0));
-        let mut cx = Context::mock();
+
+        let (mut iface, _, _) = setup(medium);
+        let cx = iface.context();
 
         assert_eq!(socket.bind(LOCAL_PORT), Ok(()));
 
@@ -932,7 +1006,7 @@ mod test {
             src_port: REMOTE_PORT,
             dst_port: LOCAL_PORT,
         };
-        socket.process(&mut cx, PacketMeta::default(), &REMOTE_IP_REPR, &repr, &[]);
+        socket.process(cx, PacketMeta::default(), &REMOTE_IP_REPR, &repr, &[]);
         assert_eq!(socket.recv(), Ok((&[][..], REMOTE_END.into())));
     }
 

+ 148 - 0
src/tests.rs

@@ -0,0 +1,148 @@
+use crate::iface::*;
+use crate::wire::*;
+
+pub(crate) fn setup<'a>(medium: Medium) -> (Interface, SocketSet<'a>, TestingDevice) {
+    let mut device = TestingDevice::new(medium);
+
+    let config = Config::new(match medium {
+        #[cfg(feature = "medium-ethernet")]
+        Medium::Ethernet => {
+            HardwareAddress::Ethernet(EthernetAddress([0x02, 0x02, 0x02, 0x02, 0x02, 0x02]))
+        }
+        #[cfg(feature = "medium-ip")]
+        Medium::Ip => HardwareAddress::Ip,
+        #[cfg(feature = "medium-ieee802154")]
+        Medium::Ieee802154 => HardwareAddress::Ieee802154(Ieee802154Address::Extended([
+            0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+        ])),
+    });
+
+    let mut iface = Interface::new(config, &mut device, Instant::ZERO);
+
+    #[cfg(feature = "proto-ipv4")]
+    {
+        iface.update_ip_addrs(|ip_addrs| {
+            ip_addrs
+                .push(IpCidr::new(IpAddress::v4(192, 168, 1, 1), 24))
+                .unwrap();
+            ip_addrs
+                .push(IpCidr::new(IpAddress::v4(127, 0, 0, 1), 8))
+                .unwrap();
+        });
+    }
+
+    #[cfg(feature = "proto-ipv6")]
+    {
+        iface.update_ip_addrs(|ip_addrs| {
+            ip_addrs
+                .push(IpCidr::new(IpAddress::v6(0xfe80, 0, 0, 0, 0, 0, 0, 1), 64))
+                .unwrap();
+            ip_addrs
+                .push(IpCidr::new(IpAddress::v6(0, 0, 0, 0, 0, 0, 0, 1), 128))
+                .unwrap();
+            ip_addrs
+                .push(IpCidr::new(IpAddress::v6(0xfdbe, 0, 0, 0, 0, 0, 0, 1), 64))
+                .unwrap();
+        });
+    }
+
+    (iface, SocketSet::new(vec![]), device)
+}
+
+use heapless::Deque;
+use heapless::Vec;
+
+use crate::phy::{self, Device, DeviceCapabilities, Medium};
+use crate::time::Instant;
+
+/// A testing device.
+#[derive(Debug)]
+pub struct TestingDevice {
+    pub(crate) queue: Deque<Vec<u8, 1514>, 4>,
+    max_transmission_unit: usize,
+    medium: Medium,
+}
+
+#[allow(clippy::new_without_default)]
+impl TestingDevice {
+    /// Creates a testing device.
+    ///
+    /// Every packet transmitted through this device will be received through it
+    /// in FIFO order.
+    pub fn new(medium: Medium) -> Self {
+        TestingDevice {
+            queue: Deque::new(),
+            max_transmission_unit: match medium {
+                #[cfg(feature = "medium-ethernet")]
+                Medium::Ethernet => 1514,
+                #[cfg(feature = "medium-ip")]
+                Medium::Ip => 1500,
+                #[cfg(feature = "medium-ieee802154")]
+                Medium::Ieee802154 => 1500,
+            },
+            medium,
+        }
+    }
+}
+
+impl Device for TestingDevice {
+    type RxToken<'a> = RxToken;
+    type TxToken<'a> = TxToken<'a>;
+
+    fn capabilities(&self) -> DeviceCapabilities {
+        DeviceCapabilities {
+            medium: self.medium,
+            max_transmission_unit: self.max_transmission_unit,
+            ..DeviceCapabilities::default()
+        }
+    }
+
+    fn receive(&mut self, _timestamp: Instant) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
+        self.queue.pop_front().map(move |buffer| {
+            let rx = RxToken { buffer };
+            let tx = TxToken {
+                queue: &mut self.queue,
+            };
+            (rx, tx)
+        })
+    }
+
+    fn transmit(&mut self, _timestamp: Instant) -> Option<Self::TxToken<'_>> {
+        Some(TxToken {
+            queue: &mut self.queue,
+        })
+    }
+}
+
+#[doc(hidden)]
+pub struct RxToken {
+    buffer: Vec<u8, 1514>,
+}
+
+impl phy::RxToken for RxToken {
+    fn consume<R, F>(mut self, f: F) -> R
+    where
+        F: FnOnce(&mut [u8]) -> R,
+    {
+        f(&mut self.buffer)
+    }
+}
+
+#[doc(hidden)]
+#[derive(Debug)]
+pub struct TxToken<'a> {
+    queue: &'a mut Deque<Vec<u8, 1514>, 4>,
+}
+
+impl<'a> phy::TxToken for TxToken<'a> {
+    fn consume<R, F>(self, len: usize, f: F) -> R
+    where
+        F: FnOnce(&mut [u8]) -> R,
+    {
+        let mut buffer = Vec::new();
+        buffer.resize(len, 0).unwrap();
+        let result = f(&mut buffer);
+        self.queue.push_back(buffer).unwrap();
+        result
+    }
+}