lundi 20 janvier 2020

Designing unit tests when `Result` is not `Copy`

I have a unit test for a container type I'm working on implementing:

    #[test]
    fn test_get_mut_normal_tail() -> Result<(), ListError> {
        let mut actual_list: ArrayList<u64> = ArrayList::new();
        let expected_list: ArrayList<u64> = ArrayList {
            elems: vec![1, 2, 3, 8]
        };

        actual_list.append(1)?;
        actual_list.append(2)?;
        actual_list.append(3)?;
        actual_list.append(4)?;

        let actual_res: Result<&mut u64, ListError> = actual_list.get_mut(3);
        let expected_res: Result<&mut u64, ListError> = Ok(&mut 4);

        let elem = actual_res.unwrap();
        *elem *= 2;

        assert_eq!(actual_list, expected_list);
        assert_eq!(actual_res, expected_res);

        Ok(())
    }

However, rustc complains with:

error[E0382]: borrow of moved value: `actual_res`
   --> src\arraylist.rs:358:9
    |
351 |         let actual_res: Result<&mut u64, ListError> = actual_list.get_mut(3);
    |             ---------- move occurs because `actual_res` has type `std::result::Result<&mut u64, list::ListError>`, which does not implement the `Copy` trait
...
354 |         let elem = actual_res.unwrap();
    |                    ---------- value moved here
...
358 |         assert_eq!(actual_res, expected_res);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ value borrowed here after move
    |
    = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)

Which I don't understand, because the Result docs indicate that Result implements Copy (provided both of the contained types do also). Clearly &mut u64 implements Copy and my ListError type derives it also:

#[derive(Clone, Copy, PartialEq, Debug)]
pub enum ListError {
    OutOfBounds,
    Impossible,
}

The code for ArrayList::get_mut() is here, if relevant:

    fn get_mut(&mut self, pos: usize) -> Result<&mut T, ListError> {
        if pos >= self.elems.len() { /* bounds check */
            return Err(ListError::OutOfBounds);
        }

        match self.elems.get_mut(pos) {
            Some(elem) => Ok(elem),
            None => Err(ListError::OutOfBounds)
        }
    }

In summary, I have two questions:

  1. How do I fix this error?
  2. Is there an underlying issue in either my test or my implementation?

Aucun commentaire:

Enregistrer un commentaire