Axel
Axel

Reputation: 5121

How to check if error type matches a specific error type in Rust?

So I have this custom error,

use std::fmt;

#[derive(Debug)]
pub enum XError {
  TagNotFound,
}

impl std::error::Error for XError {}

impl fmt::Display for XError {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    match self {
      XError::TagNotFound => write!(f, "couldn't find tag"),
    }
  }
}

And then I have a function pub fn validate() -> Result<String, Box<dyn std::error::Error>>.

Now in my test, how do I check if error returned by validate is XError::TagNotFound?

I tried doing,

let b = validate(param)
  .unwrap_err()
  .downcast_ref::<XError::TagNotFound>();

But I get this expected type, found variant "XError::TagNotFound" not a type.

Upvotes: 3

Views: 2606

Answers (1)

Sven Marnach
Sven Marnach

Reputation: 601809

The problem with your code is that XError::TagNotFound is not a type, as the error message says. It's a variant of the XError enum.

You have a Box<dyn Error>, and you want to check whether that error is XError::TagNotFound. This check consists of two steps:

  1. Downcasting from Box<dyn Error> to XError, if possible.
  2. Checking whether the downcasted XError is XError::TagNotFound.

Step 1 can be performed using my_error.downcast_ref::<XError>(), which will return an Option<&XError>. Step 2 is normal pattern matching, and can be performed with if let, match or the matches!() macro, whatever you prefer. Here is one option:

if let Some(&XError::TagNotFound) = my_error.downcast_ref::<XError>() {
    // handle error
}

In a unit test, using the matches!() macro is probably more appropriate:

assert!(matches!(my_error.downcast_ref::<XError>(), Some(&XError::TagNotFound));

Upvotes: 9

Related Questions