How do I assert an enum is a specific variant if I don't care about its fields?


How do I assert an enum is a specific variant if I don't care about its fields?



I'd like to check enums with fields in tests while ignoring the actual value of the fields for now.



Consider the following example:


enum MyEnum {
WithoutFields,
WithFields { field: String },
}

fn return_with_fields() -> MyEnum {
MyEnum::WithFields {
field: "some string".into(),
}
}

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

#[test]
fn example() {
assert_eq!(return_with_fields(), MyEnum::WithFields {..});
}
}



playground



I'd like to use assert_eq! here, but the compiler tells me:


assert_eq!


error: expected expression, found `}`
--> src/lib.rs:18:64
|
18 | assert_eq!(return_with_fields(), MyEnum::WithFields {..});
| ^ expected expression



This is similar to Why do I get an error when pattern matching a struct-like enum variant with fields?, but the solution does not apply in my case.



Of course, I can use match and do it myself, but being able to use assert_eq! would be less work.


match


assert_eq!





What MyEnum::WithFields {..} is suppose to do ? play.rust-lang.org/…
– Stargateur
Jul 1 at 8:08



MyEnum::WithFields {..}





Hi :) I think your question is answered by "Compare enums only by variant, not value". In short: use mem::discriminant. If you don't think this link answers your question, please explain why your question is different.
– Lukas Kalbertodt
Jul 1 at 8:15


mem::discriminant





@Stargateur it is supposed to ignore the fields value and just match on WithFields.
– Philipp Ludwig
Jul 1 at 8:29


WithFields





@LukasKalbertodt Sadly that does not work, the rust compiler still wants me to specify the field somehow.
– Philipp Ludwig
Jul 1 at 8:29





@PhilippLudwig You can't compare a variant with something that doesn't exist, do you want something like that ? play.rust-lang.org/…
– Stargateur
Jul 1 at 8:35





2 Answers
2



A simple solution here would be to do the opposite assertion:


assert!(return_with_fields() != MyEnum::WithoutFields);



or even more simply:


assert_ne!(return_with_fields(), MyEnum::WithoutFields);



Of course if you have more members in your enum, you'll have to add more asserts to cover all possible cases.



Alternatively, and this what OP probably had in mind, since assert! just panics in case of failure, the test can use pattern matching and call panic! directly in case something is wrong:


assert!


panic!


match return_with_fields() {
MyEnum::WithFields {..} => {},
MyEnum::WithoutFields => panic!("expected WithFields, got WithoutFields"),
}





Thanks, that is a good idea. I'm still wondering though if there is a more straight-forward solution. Or maybe I will just have to create my own macro.
– Philipp Ludwig
Jul 1 at 10:12





@SirDarius Thanks for providing the source, this is interesting. I will accept your answer, maybe you want to include these additional information there.
– Philipp Ludwig
Jul 1 at 12:08



Your original code can be made to work with a new macro:


macro_rules! is_enum_variant {
($v:expr, $p:pat) => (
if let $p = $v { true } else { false }
);
}

#[test]
fn example() {
assert!(is_enum_variant!(return_with_fields(), MyEnum::WithoutFields {..}));
}



Personally, I tend to add methods to my enums:


fn is_with_fields(&self) -> bool {
match self {
MyEnum::WithFields { .. } => true,
_ => false,
}
}



I also tend to avoid struct-like enums and instead put in extra work:


enum MyEnum {
WithoutFields,
WithFields(WithFields),
}

struct WithFields { field: String }

impl MyEnum {
fn is_with_fields(&self) -> bool {
match self {
MyEnum::WithFields(_) => true,
_ => false,
}
}

fn as_with_fields(&self) -> Option<&WithFields> {
match self {
MyEnum::WithFields(x) => Some(x),
_ => None,
}
}

fn into_with_fields(self) -> Option<WithFields> {
match self {
MyEnum::WithFields(x) => Some(x),
_ => None,
}
}
}



I hope that some day, enum variants can be made into their own type to avoid this extra struct.






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

List of Kim Possible characters

Audio Livestreaming with Python & Flask

NSwag: Generate C# Client from multiple Versions of an API