Распаковка и проверка объекта черты - PullRequest
0 голосов
/ 16 февраля 2020

Вот простое приложение, которое дублирует 2 раза на стандартный вывод содержимого стандартного ввода:

use std::{
    io,
    io::{stdin, stdout, Read, Write},
    num::NonZeroUsize,
};

fn dup_input(
    input: &mut Box<dyn Read>,
    output: &mut Box<dyn Write>,
    count: NonZeroUsize,
) -> io::Result<()> {
    let mut buf = Vec::new();

    input.read_to_end(&mut buf)?;

    for _idx in 0..count.get() {
        output.write_all(&buf)?;
    }

    Ok(())
}

fn main() {
    let mut input: Box<dyn Read> = Box::new(stdin());
    let mut output: Box<dyn Write> = Box::new(stdout());

    dup_input(&mut input, &mut output, NonZeroUsize::new(2).unwrap())
        .expect("Failed to duplicate input");
}

Эта часть отлично работает. Я хочу поставить модульный тест поверх этого, и в этом проблема. Самое близкое, что я должен построить, это следующая попытка:

#[cfg(test)]
mod tests {
    use super::*;
    use std::{any::Any, io::Cursor};

    #[test]
    fn test() {
        let mut input: Box<dyn Read> = Box::new(Cursor::new([b't', b'e', b's', b't', b'\n']));
        let mut output: Box<dyn Write + Any> = Box::new(Vec::<u8>::new());

        assert!(dup_input(&mut input, &mut output, NonZeroUsize::new(3).unwrap()).is_ok());

        assert_eq!(output.downcast::<Vec<u8>>().unwrap().len(), 15);
    }
}

, но ржавчина 1.41.0 не согласна:

$ cargo test
   Compiling unbox-example v0.1.0 (/XXX/unbox-example)
error[E0225]: only auto traits can be used as additional traits in a trait object
  --> src/main.rs:39:41
   |
39 |         let mut output: Box<dyn Write + Any> = Box::new(Vec::<u8>::new());
   |                                 -----   ^^^
   |                                 |       |
   |                                 |       additional non-auto trait
   |                                 |       trait alias used in trait object type (additional use)
   |                                 first non-auto trait
   |                                 trait alias used in trait object type (first use)

error[E0308]: mismatched types
  --> src/main.rs:41:39
   |
41 |         assert!(dup_input(&mut input, &mut output, NonZeroUsize::new(3).unwrap()).is_ok());
   |                                       ^^^^^^^^^^^ expected trait `std::io::Write`, found a different trait `std::io::Write`
   |
   = note: expected mutable reference `&mut std::boxed::Box<(dyn std::io::Write + 'static)>`
              found mutable reference `&mut std::boxed::Box<(dyn std::io::Write + 'static)>`

error[E0599]: no method named `downcast` found for type `std::boxed::Box<(dyn std::io::Write + 'static)>` in the current scope
  --> src/main.rs:43:27
   |
43 |         assert_eq!(output.downcast::<Vec<u8>>().unwrap().len(), 15);
   |                           ^^^^^^^^ method not found in `std::boxed::Box<(dyn std::io::Write + 'static)>`

error: aborting due to 3 previous errors

Some errors have detailed explanations: E0225, E0308, E0599.
For more information about an error, try `rustc --explain E0225`.
error: could not compile `unbox-example`.

To learn more, run the command again with --verbose.

Есть ли способ изменить юнит тестировать без изменения основного кода? Примечание. Я мог бы использовать универсальные шаблоны при реализации dup_input и значительно облегчить решение проблемы, но этот код является частью более широкого приложения, и мне нужно использовать объекты признаков чтения / записи.

1 Ответ

0 голосов
/ 17 февраля 2020

Передача изменчивой ссылки на Box на dup_input излишне сложна. Вы можете просто передать изменяемую ссылку на объект черты.

use std::{
    io,
    io::{stdin, stdout, Read, Write},
    num::NonZeroUsize,
};

fn dup_input(
    input: &mut dyn Read,
    output: &mut dyn Write,
    count: NonZeroUsize,
) -> io::Result<()> {
    let mut buf = Vec::new();

    input.read_to_end(&mut buf)?;

    for _idx in 0..count.get() {
        output.write_all(&buf)?;
    }

    Ok(())
}

fn main() {
    let mut input = stdin();
    let mut output = stdout();

    dup_input(&mut input, &mut output, NonZeroUsize::new(2).unwrap())
        .expect("Failed to duplicate input");
}

В этой версии тест можно записать так:

#[cfg(test)]
mod tests {
    use super::*;
    use std::io::Cursor;

    #[test]
    fn test() {
        let mut input = Cursor::new([b't', b'e', b's', b't', b'\n']);
        let mut output = Vec::<u8>::new();

        assert!(dup_input(&mut input, &mut output, NonZeroUsize::new(3).unwrap()).is_ok());

        assert_eq!(output.len(), 15);
    }
}

Нам не нужно использовать Any вообще здесь: output это просто Vec<u8>.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...