Gabriel Velasco
Gabriel Velasco

Reputation: 23

Using assert in error branch when running cargo test

I'm reading through the Rust book and working on part of the minigrep where it asks you to write some unit tests on the Config::new function. I'm failing on something that I didn't expect and don't understand why (Google-fu is failing me as well).

This fails

#[cfg(test)]
mod new_config_tests {
    use super::*;

    #[test]
    fn it_can_create_a_new_config() {
        let expected_query = "expected_qury";
        let expected_filename = "expected_filename.txt";
        let args: Vec<String> = vec!["program/path".to_string(), expected_query.to_string(), expected_filename.to_string()];

        // failing line
        let actual = Config::new(&args).unwrap_or_else(|err| { assert!(false); });
    }
}

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

with

error[E0308]: mismatched types
  --> src/lib.rs:19:62
   |
19 |         let actual = Config::new(&args).unwrap_or_else(|err| { assert!(false); });
   |                                                              ^^^^^^^^^^^^^^^^^^^ expected struct `Config`, found `()`

In this test, I'm just making sure that I can create a new Config and want it to fail if the Config::new function fails. I thought that using assert would be correct so that the test framework would handle the failure. If I change the assert to panic, then the tests pass as expected. Is using panic correct in the above scenario?

Upvotes: 0

Views: 1304

Answers (1)

Jmb
Jmb

Reputation: 23294

The problem is that during type-checking, the compiler doesn't (yet) realize that assert!(false) will always fail, so it has to assume that it may pass, resulting in a value of type () which is incompatible with the expected Config type.

Conversely, if you replace the assert with a call to panic, the compiler knows that panic never returns, so it doesn't matter if there is no Config to return. (Strictly speaking, panic typechecks as returning a value of type !, aka the "never" type, which is compatible with everything).

IMO you should never use assert!(false), and instead use panic when you know that a condition is always fatal. This makes your intent clearer.

Although in this specific case, it would probably be better to assert that the result is Ok:

assert!(Config::new(&args).is_ok());

Upvotes: 3

Related Questions