How best way to assert Box<Error>?

Hi folks,

I'm starting in Rust and doing some exercises of Rust Book, I was in doubt about the best way to assert Box on my test.

pub fn new(args: &[String]) -> Result<Config, &'static str> {
   if args.len() < 3 {
      return Err("not enough arguments");
   }
   let query = args[1].clone();
   let filename = args[2].clone();
   Ok(Config {query, filename})
}

#[test]
fn test_file_not_found() {
   let error_expected = "No such file or directory (os error 2)";
   let config = Config::new(&vec![String::from("name app"),
                          String::from("command"),
                          String::from("file.txt")]);

   let result = run(config.unwrap())
            .map_err(|error| error.to_string());

   assert_eq!(result.unwrap_err().to_string(), error_expected);
}

Please, can anyone help me?

You mean, test that a Box<dyn Error> is what you expect? Using to_string() seems reasonable to me. If you wanted to test more than the message, you can try downcasting and walking the source() results, etc, but that seems like overkill to me in this case.

Incidentally, you're calling to_string() in both your map_err and after your unwrap_err. You could just do this.

    let result = run(config.unwrap()).map_err(|error| error.to_string());
    assert_eq!(result.unwrap_err(), error_expected);
2 Likes

I'm not sure what type your run() function returns but if wanted something a bit more robust you could do as @quinedot suggested and check for an io::ErrorKind::NotFound using the following little underlying_io_error_kind function. For example:

use std::error::Error;
use std::io;

#[test]
fn test_file_not_found() {
    ...

    let err = run(...).unwrap_err();
    assert_eq!(underlying_io_error_kind(err), Some(io::ErrorKind::NotFound));
}

fn underlying_io_error_kind(mut err: &(dyn Error + 'static)) -> Option<io::ErrorKind> {
    loop {
        match err.downcast_ref::<io::Error>() {
            Some(io_err) => break Some(io_err.kind()),
            None => err = err.source()?,
        }
    }
}
2 Likes

Sorry, I forgot to put run function.

pub fn run(config: Config) -> Result<(), Box<Error>>{
    let mut file = File::open(config.filename)?;

    let mut contents = String::new();
    file.read_to_string(&mut contents)?;

    println!("{:?}", search(&config.query, &contents));
    Ok(())
}

Thanks, for your explanation. Now, it's clear.

I liked it, I will put on my project, thanks

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.