304 lines
6.2 KiB
Rust
304 lines
6.2 KiB
Rust
#![allow(clippy::uninlined_format_args)]
|
|
|
|
use std::fmt::{self, Display};
|
|
use thiserror::Error;
|
|
|
|
fn assert<T: Display>(expected: &str, value: T) {
|
|
assert_eq!(expected, value.to_string());
|
|
}
|
|
|
|
#[test]
|
|
fn test_braced() {
|
|
#[derive(Error, Debug)]
|
|
#[error("braced error: {msg}")]
|
|
struct Error {
|
|
msg: String,
|
|
}
|
|
|
|
let msg = "T".to_owned();
|
|
assert("braced error: T", Error { msg });
|
|
}
|
|
|
|
#[test]
|
|
fn test_braced_unused() {
|
|
#[derive(Error, Debug)]
|
|
#[error("braced error")]
|
|
struct Error {
|
|
extra: usize,
|
|
}
|
|
|
|
assert("braced error", Error { extra: 0 });
|
|
}
|
|
|
|
#[test]
|
|
fn test_tuple() {
|
|
#[derive(Error, Debug)]
|
|
#[error("tuple error: {0}")]
|
|
struct Error(usize);
|
|
|
|
assert("tuple error: 0", Error(0));
|
|
}
|
|
|
|
#[test]
|
|
fn test_unit() {
|
|
#[derive(Error, Debug)]
|
|
#[error("unit error")]
|
|
struct Error;
|
|
|
|
assert("unit error", Error);
|
|
}
|
|
|
|
#[test]
|
|
fn test_enum() {
|
|
#[derive(Error, Debug)]
|
|
enum Error {
|
|
#[error("braced error: {id}")]
|
|
Braced { id: usize },
|
|
#[error("tuple error: {0}")]
|
|
Tuple(usize),
|
|
#[error("unit error")]
|
|
Unit,
|
|
}
|
|
|
|
assert("braced error: 0", Error::Braced { id: 0 });
|
|
assert("tuple error: 0", Error::Tuple(0));
|
|
assert("unit error", Error::Unit);
|
|
}
|
|
|
|
#[test]
|
|
fn test_constants() {
|
|
#[derive(Error, Debug)]
|
|
#[error("{MSG}: {id:?} (code {CODE:?})")]
|
|
struct Error {
|
|
id: &'static str,
|
|
}
|
|
|
|
const MSG: &str = "failed to do";
|
|
const CODE: usize = 9;
|
|
|
|
assert("failed to do: \"\" (code 9)", Error { id: "" });
|
|
}
|
|
|
|
#[test]
|
|
fn test_inherit() {
|
|
#[derive(Error, Debug)]
|
|
#[error("{0}")]
|
|
enum Error {
|
|
Some(&'static str),
|
|
#[error("other error")]
|
|
Other(&'static str),
|
|
}
|
|
|
|
assert("some error", Error::Some("some error"));
|
|
assert("other error", Error::Other("..."));
|
|
}
|
|
|
|
#[test]
|
|
fn test_brace_escape() {
|
|
#[derive(Error, Debug)]
|
|
#[error("fn main() {{}}")]
|
|
struct Error;
|
|
|
|
assert("fn main() {}", Error);
|
|
}
|
|
|
|
#[test]
|
|
fn test_expr() {
|
|
#[derive(Error, Debug)]
|
|
#[error("1 + 1 = {}", 1 + 1)]
|
|
struct Error;
|
|
assert("1 + 1 = 2", Error);
|
|
}
|
|
|
|
#[test]
|
|
fn test_nested() {
|
|
#[derive(Error, Debug)]
|
|
#[error("!bool = {}", not(.0))]
|
|
struct Error(bool);
|
|
|
|
#[allow(clippy::trivially_copy_pass_by_ref)]
|
|
fn not(bool: &bool) -> bool {
|
|
!*bool
|
|
}
|
|
|
|
assert("!bool = false", Error(true));
|
|
}
|
|
|
|
#[test]
|
|
fn test_match() {
|
|
#[derive(Error, Debug)]
|
|
#[error("{}: {0}", match .1 {
|
|
Some(n) => format!("error occurred with {}", n),
|
|
None => "there was an empty error".to_owned(),
|
|
})]
|
|
struct Error(String, Option<usize>);
|
|
|
|
assert(
|
|
"error occurred with 1: ...",
|
|
Error("...".to_owned(), Some(1)),
|
|
);
|
|
assert(
|
|
"there was an empty error: ...",
|
|
Error("...".to_owned(), None),
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_nested_display() {
|
|
// Same behavior as the one in `test_match`, but without String allocations.
|
|
#[derive(Error, Debug)]
|
|
#[error("{}", {
|
|
struct Msg<'a>(&'a String, &'a Option<usize>);
|
|
impl<'a> Display for Msg<'a> {
|
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
|
match self.1 {
|
|
Some(n) => write!(formatter, "error occurred with {}", n),
|
|
None => write!(formatter, "there was an empty error"),
|
|
}?;
|
|
write!(formatter, ": {}", self.0)
|
|
}
|
|
}
|
|
Msg(.0, .1)
|
|
})]
|
|
struct Error(String, Option<usize>);
|
|
|
|
assert(
|
|
"error occurred with 1: ...",
|
|
Error("...".to_owned(), Some(1)),
|
|
);
|
|
assert(
|
|
"there was an empty error: ...",
|
|
Error("...".to_owned(), None),
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_void() {
|
|
#[allow(clippy::empty_enum)]
|
|
#[derive(Error, Debug)]
|
|
#[error("...")]
|
|
pub enum Error {}
|
|
|
|
let _: Error;
|
|
}
|
|
|
|
#[test]
|
|
fn test_mixed() {
|
|
#[derive(Error, Debug)]
|
|
#[error("a={a} :: b={} :: c={c} :: d={d}", 1, c = 2, d = 3)]
|
|
struct Error {
|
|
a: usize,
|
|
d: usize,
|
|
}
|
|
|
|
assert("a=0 :: b=1 :: c=2 :: d=3", Error { a: 0, d: 0 });
|
|
}
|
|
|
|
#[test]
|
|
fn test_ints() {
|
|
#[derive(Error, Debug)]
|
|
enum Error {
|
|
#[error("error {0}")]
|
|
Tuple(usize, usize),
|
|
#[error("error {0}", '?')]
|
|
Struct { v: usize },
|
|
}
|
|
|
|
assert("error 9", Error::Tuple(9, 0));
|
|
assert("error ?", Error::Struct { v: 0 });
|
|
}
|
|
|
|
#[test]
|
|
fn test_trailing_comma() {
|
|
#[derive(Error, Debug)]
|
|
#[error(
|
|
"error {0}",
|
|
)]
|
|
#[rustfmt::skip]
|
|
struct Error(char);
|
|
|
|
assert("error ?", Error('?'));
|
|
}
|
|
|
|
#[test]
|
|
fn test_field() {
|
|
#[derive(Debug)]
|
|
struct Inner {
|
|
data: usize,
|
|
}
|
|
|
|
#[derive(Error, Debug)]
|
|
#[error("{}", .0.data)]
|
|
struct Error(Inner);
|
|
|
|
assert("0", Error(Inner { data: 0 }));
|
|
}
|
|
|
|
#[test]
|
|
fn test_macro_rules() {
|
|
// Regression test for https://github.com/dtolnay/thiserror/issues/86
|
|
|
|
macro_rules! decl_error {
|
|
($variant:ident($value:ident)) => {
|
|
#[derive(Debug, Error)]
|
|
pub enum Error0 {
|
|
#[error("{0:?}")]
|
|
$variant($value),
|
|
}
|
|
|
|
#[derive(Debug, Error)]
|
|
#[error("{0:?}")]
|
|
pub enum Error1 {
|
|
$variant($value),
|
|
}
|
|
};
|
|
}
|
|
|
|
decl_error!(Repro(u8));
|
|
|
|
assert("0", Error0::Repro(0));
|
|
assert("0", Error1::Repro(0));
|
|
}
|
|
|
|
#[test]
|
|
fn test_raw() {
|
|
#[derive(Error, Debug)]
|
|
#[error("braced raw error: {r#fn}")]
|
|
struct Error {
|
|
r#fn: &'static str,
|
|
}
|
|
|
|
assert("braced raw error: T", Error { r#fn: "T" });
|
|
}
|
|
|
|
#[test]
|
|
fn test_raw_enum() {
|
|
#[derive(Error, Debug)]
|
|
enum Error {
|
|
#[error("braced raw error: {r#fn}")]
|
|
Braced { r#fn: &'static str },
|
|
}
|
|
|
|
assert("braced raw error: T", Error::Braced { r#fn: "T" });
|
|
}
|
|
|
|
#[test]
|
|
fn test_raw_conflict() {
|
|
#[derive(Error, Debug)]
|
|
enum Error {
|
|
#[error("braced raw error: {r#func}, {func}", func = "U")]
|
|
Braced { r#func: &'static str },
|
|
}
|
|
|
|
assert("braced raw error: T, U", Error::Braced { r#func: "T" });
|
|
}
|
|
|
|
#[test]
|
|
fn test_keyword() {
|
|
#[derive(Error, Debug)]
|
|
#[error("error: {type}", type = 1)]
|
|
struct Error;
|
|
|
|
assert("error: 1", Error);
|
|
}
|