ruipacheco
ruipacheco

Reputation: 16422

How to test instantiation of struct in Rust?

I have the following struct:

pub struct Settings {
    pub something: String
}

with the following constructor:

impl Settings {
    fn new(path: &Path) -> Settings {
        if !path.exists() {
            fail!("Configuration file not found.");
        }
        return Settings{something:String::new()};
    }
}

I've created a unit test to see what happens when I create a struct with Paths that point to existing and none existing files:

mod tests {
    #[test]
    fn test_new_valid_path() {
        use configuration::Settings;
        let path = &Path::new("emperor.ini");
        let settings = Settings::new(path);
        assert!(settings);
    }

    #[test]
    fn test_new_invalid_path() {
        use configuration::Settings;
        let path = &Path::new("emperor.xml");
        let settings = Settings::new(path);
    }
}

But when I run my tests thus: rustc --test meh.rs; ./meh --nocapture I get the following output:

<std macros>:3:12: 40:20 error: cannot apply unary operator `!` to type `configuration::Settings`
<std macros>:3         if !$cond {
<std macros>:4             fail!("assertion failed: {:s}", stringify!($cond))
<std macros>:5         }
<std macros>:6     );
<std macros>:7     ($cond:expr, $($arg:expr),+) => (
<std macros>:8         if !$cond {
               ...
<std macros>:1:1: 12:2 note: in expansion of assert!
shogun.rs:40:4: 40:22 note: expansion site
error: aborting due to previous error

How can I test struct instantiation?

Upvotes: 4

Views: 5438

Answers (2)

Chris Morgan
Chris Morgan

Reputation: 90752

I think you are misunderstanding the model of how these things work.

A function that has a return type of Settings—well, its value when it returns is a Settings object which is guaranteed to be correctly instantiated. If we removed your assert!(settings); line, the code would do exactly what you’re wanting. (assert! expects a boolean as its first argument, by the way, just as if requires a boolean expression to follow it.)

If the path is one that does not exist, then the fail! will come into play and the task will fail, unwinding; the Settings::new call never returns. Triggering task failure is exactly what assert!(…) does, also.

To put it all another way: the very fact that that line is executed proves that it is initialised correctly.


Incidentally, failing like that is typically considered bad form; better would be to return an Option<Settings>, and not to use the name new but rather something that indicates that you’ll be loading it from a file; something like this:

impl Settings {
    fn load(path: &Path) -> Option<Settings> {
        if !path.exists() {
            None
        } else {
            Some(Settings { something: String::new() })
        }
    }
}

Upvotes: 7

Reboare
Reboare

Reputation: 79

I think the problem is this line

assert!(settings);

assert just throws an error if the boolean argument inside is false but settings in this case is not a boolean, it's of type configuration::Settings

cannot apply unary operator `!` to type `configuration::Settings`

To test if you've got valid settings back do something like

assert!(settings.something.is_empty())

Upvotes: 0

Related Questions