Learn Rust With Entirely Too Many Linked Lists
43

Testing

Tests live next to the code in #[cfg(test)] mod tests. We exercise basic ops, iteration in both directions, clone, equality, and a stress loop. Then we run the same tests under Miri, which interprets the program and flags every undefined-behavior trigger we managed to write past the type system.

  1. A handful of unit tests: round-trip push/pop on each end, drain via iteration, mutate through IterMut, clone-equals-original. Together these touch every method at least once and walk both directions.
    #[cfg(test)]
    mod tests {
        use super::*;
    
        #[test]
        fn push_pop_front() {
            let mut l = LinkedList::new();
            l.push_front(1);
            l.push_front(2);
            assert_eq!(l.pop_front(), Some(2));
            assert_eq!(l.pop_front(), Some(1));
            assert_eq!(l.pop_front(), None);
        }
    
        #[test]
        fn iter_mut_doubles() {
            let mut l: LinkedList<i32> = (1..=4).collect();
            for x in l.iter_mut() { *x *= 2; }
            assert!(l.iter().copied().eq([2, 4, 6, 8]));
        }
    
        #[test]
        fn clone_eq() {
            let a: LinkedList<String> = (0..50).map(|i| i.to_string()).collect();
            let b = a.clone();
            assert_eq!(a, b);
        }
    }
  2. Run the unit tests under Miri: cargo +nightly miri test. Miri interprets every operation and validates against the stacked-borrows / tree-borrows model. Any aliasing or provenance violation we wrote earns a stack trace.
    $ rustup toolchain install nightly
    $ rustup +nightly component add miri
    $ cargo +nightly miri test
       Compiling sixth v0.1.0
         Running unittests src/lib.rs
    running 3 tests
    test sixth::tests::push_pop_front ... ok
    test sixth::tests::iter_mut_doubles ... ok
    test sixth::tests::clone_eq ... ok
    
    test result: ok. 3 passed; 0 failed