summaryrefslogtreecommitdiffstats
path: root/third_party/rust/litrs/src/test_util.rs
blob: fd284e984e08f65719043ae4605e0d664f15592a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
use crate::*;
use std::fmt::{Debug, Display};


#[track_caller]
pub(crate) fn assert_parse_ok_eq<T: PartialEq + Debug + Display>(
    input: &str,
    result: Result<T, ParseError>,
    expected: T,
    parse_method: &str,
) {
    match result {
        Ok(actual) if actual == expected => {
            if actual.to_string() != input {
                panic!(
                    "formatting does not yield original input `{}`: {:?}",
                    input,
                    actual,
                );
            }
        }
        Ok(actual) => {
            panic!(
                "unexpected parsing result (with `{}`) for `{}`:\nactual:    {:?}\nexpected:  {:?}",
                parse_method,
                input,
                actual,
                expected,
            );
        }
        Err(e) => {
            panic!(
                "expected `{}` to be parsed (with `{}`) successfully, but it failed: {:?}",
                input,
                parse_method,
                e,
            );
        }
    }
}

// This is not ideal, but to perform this check we need `proc-macro2`. So we
// just don't do anything if that feature is not enabled.
#[cfg(not(feature = "proc-macro2"))]
pub(crate) fn assert_roundtrip<T>(_: T, _: &str) {}

#[cfg(feature = "proc-macro2")]
#[track_caller]
pub(crate) fn assert_roundtrip<T>(ours: T, input: &str)
where
    T: std::convert::TryFrom<proc_macro2::Literal> + fmt::Debug + PartialEq + Clone,
    proc_macro2::Literal: From<T>,
    <T as std::convert::TryFrom<proc_macro2::Literal>>::Error: std::fmt::Display,
{
    let pm_lit = input.parse::<proc_macro2::Literal>()
        .expect("failed to parse input as proc_macro2::Literal");
    let t_name = std::any::type_name::<T>();

    // Unfortunately, `proc_macro2::Literal` does not implement `PartialEq`, so
    // this is the next best thing.
    if proc_macro2::Literal::from(ours.clone()).to_string() != pm_lit.to_string() {
        panic!(
            "Converting {} to proc_macro2::Literal has unexpected result:\
                \nconverted: {:?}\nexpected:  {:?}",
            t_name,
            proc_macro2::Literal::from(ours),
            pm_lit,
        );
    }

    match T::try_from(pm_lit) {
        Err(e) => {
            panic!("Trying to convert proc_macro2::Literal to {} results in error: {}", t_name, e);
        }
        Ok(res) => {
            if res != ours {
                panic!(
                    "Converting proc_macro2::Literal to {} has unexpected result:\
                        \nactual:    {:?}\nexpected:  {:?}",
                    t_name,
                    res,
                    ours,
                );
            }
        }
    }
}

macro_rules! assert_err {
    ($ty:ident, $input:literal, $kind:ident, $( $span:tt )+ ) => {
        assert_err_single!($ty::parse($input), $kind, $($span)+);
        assert_err_single!($crate::Literal::parse($input), $kind, $($span)+);
    };
}

macro_rules! assert_err_single {
    ($expr:expr, $kind:ident, $( $span:tt )+ ) => {
        let res = $expr;
        let err = match res {
            Err(e) => e,
            Ok(v) => panic!(
                "Expected `{}` to return an error, but it returned Ok({:?})",
                stringify!($expr),
                v,
            ),
        };
        if err.kind != $crate::err::ParseErrorKind::$kind {
            panic!(
                "Expected error kind {} for `{}` but got {:?}",
                stringify!($kind),
                stringify!($expr),
                err.kind,
            )
        }
        let expected_span = assert_err_single!(@span $($span)+);
        if err.span != expected_span {
            panic!(
                "Expected error span {:?} for `{}` but got {:?}",
                expected_span,
                stringify!($expr),
                err.span,
            )
        }
    };
    (@span $start:literal .. $end:literal) => { Some($start .. $end) };
    (@span $at:literal) => { Some($at.. $at + 1) };
    (@span None) => { None };
}