Почему не проходит тест ржавчины с небезопасным кодом, но тот же код в интеграционном тесте проходит?

Я пытаюсь написать тест ржавчины для метода под названием insert, Функция тестирования вызывается в последней строке теста, и когда я ее закомментирую, тест проходит нормально.

Сообщение об ошибке:

$ cargo test
   Compiling reproduce v0.1.0 
(file:///home/user/reproduce)                                                           
    Finished dev [unoptimized + debuginfo] target(s) in 2.03s
     Running target/debug/deps/reproduce-17ad4bb50aa9c47e

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

   Doc-tests reproduce

running 1 test
test src/lib.rs - MyStruct::method (line 19) ... FAILED

failures:

failures:
    src/lib.rs - MyStruct::method (line 19)

test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out

error: test failed, to rerun pass '--doc'

Код:

impl MyStruct {
    pub fn new(lsb: u8, step: usize) -> MyStruct {
        let mask: u8 = match lsb {
            1 => 0b0000_0001,
            2 => 0b0000_0011,
            _ => 0b0000_1111
        };

        MyStruct { lsb, mask, step }
    }

    /// # Examples
    /// ```
    /// extern crate reproduce;
    /// extern crate rgb;
    ///
    /// use std::slice;
    /// use rgb::RGB;
    ///
    /// let msg = "This is a secret message".as_bytes();
    /// let img = vec![RGB {r: 0, g: 0, b: 0}; 800*500];
    ///
    /// // Create a reference to the bytes of img
    /// let p: *const Vec<RGB<u8>> = &img;
    /// let p: *const u8 = p as *const u8;
    /// let p: &[u8] = unsafe { 
    ///     slice::from_raw_parts(p, 3*800*500)
    /// };
    ///
    /// let settings = reproduce::MyStruct::new(2, 12);
    /// let new_data = settings.method(p, &msg);
    /// ```
    pub fn method(&self, img: &[u8], msg: &[u8]) -> Vec<u8> {
        let mut ret = img.to_vec();
        let mut n = 0;

        for ch in msg.iter() {
            for i in 1..=8/self.lsb {
                let shift = (self.lsb*i) as u32;
                ret[n] = (ret[n] & !self.mask) |
                    (ch & self.mask.rotate_right(shift)).rotate_left(shift);
                n += self.step;
            }
        }

        ret
    }
}

Может ли быть так, что существуют специальные правила для прохождения теста rustdoc (например, использование assert! макрос, чтобы доказать, что он возвращает правильное значение)?

Я спрашиваю, потому что мой метод проходит тест интеграции с очень похожим кодом, поэтому я уверен, что это правильно

1 ответ

Решение

Это не имеет ничего общего с тем, что он работает в тесте rustdoc. Ваш код демонстрирует неопределенное поведение, потому что он некачественный. Запуск того же кода вне теста также паникует для меня.

Вы делаете предположения о том, как распределена память - предположения, которые никоим образом не подкрепляются гарантиями компилятора. "Правильный" способ получить указатель был бы следующим:

let p = img.as_ptr() as *const u8;

Тем не менее, хотя это снимает предположение о том, как Vec выложен, остальная часть кода все еще принимает макет RGB, Это изменение перестает паниковать из-за меня, но я не могу быть уверен, что оно работает правильно, и я не могу знать, сломается ли оно на каком-то другом компьютере или на моем после следующего обновления Rust.

Я спрашиваю, потому что мой метод проходит тест интеграции с очень похожим кодом, поэтому я уверен, что это правильно

Это точно опасность неопределенного поведения, и именно поэтому unsafe следует использовать только в коде, который не только хорошо протестирован, но и где допущения и гарантии хорошо понятны.

Другие вопросы по тегам