How do you write exhaustive tests for enums?

When I write test functions for a enum, I want to make them exhaustive so that I don't forget to update them when I add a new variant to the enum.

For example, suppose you have the following code:

pub enum Palette {
    Light,
    Dark,
}

impl Palette {
    pub fn to_argb_colors(&self) -> Vec<u32> {
        todo!();
    }
}

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

    #[test]
    fn test_argb_colors() {
        assert_eq!(Palette::Light.to_argb_colors(), Vec::new());
        assert_eq!(Palette::Dark.to_argb_colors(), Vec::new());
    }
}

Adding a new variant Palette::HighContrast immediately makes the test incomplete.

How can I make it exhaustive?

You can use pattern matching for exhausting all possible variants on an enum

2 Likes

How about something like this:

#[test]
fn test_argb_colors() {
    use Palette::*;
    for pal in [Light, Dark] {
        match pal {
            Light => assert_eq!(pal.to_argb_colors(), Vec::new()),
            Dark => assert_eq!(pal.to_argb_colors(), Vec::new()),
        }
    }
}

(untested)

2 Likes

I think I'd use strum to create an iterator over every variant:

/*
[dependencies]
strum = { version = "^0.24.1", features = ["derive"] }
*/
use strum::{EnumIter, IntoEnumIterator};

#[derive(EnumIter, Debug)]
pub enum Palette {
    Light,
    Dark,
}

impl Palette {
    pub fn to_argb_colors(&self) -> Vec<u32> {
        vec![]
    }
}

fn main() {
    for v in Palette::iter() {
        println!("{v:?}");
        assert_eq!(v.to_argb_colors(), Vec::new());   
    }
}

Rustexplorer.

4 Likes

I'll try a combination of strum and pattern matching. Thank you guys very much.

1 Like

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.