vrl/compiler/
test_util.rs

1#[macro_export]
2macro_rules! test_type_def {
3    ($($name:ident { expr: $expr:expr_2021, want: $def:expr_2021, })+) => {
4        mod type_def {
5            use super::*;
6
7            $(
8                #[test]
9                fn $name() {
10                    let mut state = $crate::compiler::state::TypeState::default();
11                    #[allow(clippy::redundant_closure_call)]
12                    let expression = Box::new($expr(&mut state));
13
14                    assert_eq!(expression.type_def(&state), $def);
15                }
16            )+
17        }
18    };
19}
20
21#[macro_export]
22macro_rules! func_args {
23    () => (
24        ::std::collections::HashMap::<&'static str, $crate::value::Value>::default()
25    );
26    ($($k:tt: $v:expr_2021),+ $(,)?) => {
27        vec![$((stringify!($k), $v.into())),+]
28            .into_iter()
29            .collect::<::std::collections::HashMap<&'static str, $crate::value::Value>>()
30    };
31}
32
33#[macro_export]
34macro_rules! bench_function {
35    ($name:tt => $func:path; $($case:ident { args: $args:expr_2021, want: $(Ok($ok:expr_2021))? $(Err($err:expr_2021))? $(,)* })+) => {
36        fn $name(c: &mut criterion::Criterion) {
37            let mut group = c.benchmark_group(&format!("vrl_stdlib/functions/{}", stringify!($name)));
38            group.throughput(criterion::Throughput::Elements(1));
39            $(
40                group.bench_function(&stringify!($case).to_string(), |b| {
41                    let mut state = $crate::compiler::state::TypeState::default();
42
43                    let (expression, want) = $crate::__prep_bench_or_test!($func, &state, $args, $(Ok($crate::value::Value::from($ok)))? $(Err($err.to_owned()))?);
44                    let expression = expression.unwrap();
45                    let mut runtime_state = $crate::compiler::state::RuntimeState::default();
46                    let mut target: $crate::value::Value = ::std::collections::BTreeMap::default().into();
47                    let tz = $crate::compiler::TimeZone::Named(chrono_tz::Tz::UTC);
48                    let mut ctx = $crate::compiler::Context::new(&mut target, &mut runtime_state, &tz);
49
50                    b.iter(|| {
51                        let got = expression.resolve(&mut ctx).map_err(|e| e.to_string());
52                        debug_assert_eq!(got, want);
53                        got
54                    })
55                });
56            )+
57        }
58    };
59}
60
61#[macro_export]
62macro_rules! test_function {
63
64    ($name:tt => $func:path; $($case:ident { args: $args:expr_2021, want: $(Ok($ok:expr_2021))? $(Err($err:expr_2021))?, tdef: $tdef:expr_2021,  $(,)* })+) => {
65        test_function!($name => $func; before_each => {} $($case { args: $args, want: $(Ok($ok))? $(Err($err))?, tdef: $tdef, tz: $crate::compiler::TimeZone::Named(chrono_tz::Tz::UTC), })+);
66    };
67
68    ($name:tt => $func:path; $($case:ident { args: $args:expr_2021, want: $(Ok($ok:expr_2021))? $(Err($err:expr_2021))?, tdef: $tdef:expr_2021, tz: $tz:expr_2021,  $(,)* })+) => {
69        test_function!($name => $func; before_each => {} $($case { args: $args, want: $(Ok($ok))? $(Err($err))?, tdef: $tdef, tz: $tz, })+);
70    };
71
72    ($name:tt => $func:path; before_each => $before:block $($case:ident { args: $args:expr_2021, want: $(Ok($ok:expr_2021))? $(Err($err:expr_2021))?, tdef: $tdef:expr_2021,  $(,)* })+) => {
73        test_function!($name => $func; before_each => $before $($case { args: $args, want: $(Ok($ok))? $(Err($err))?, tdef: $tdef, tz: $crate::compiler::TimeZone::Named(chrono_tz::Tz::UTC), })+);
74    };
75
76    ($name:tt => $func:path; before_each => $before:block $($case:ident { args: $args:expr_2021, want: $(Ok($ok:expr_2021))? $(Err($err:expr_2021))?, tdef: $tdef:expr_2021, tz: $tz:expr_2021,  $(,)* })+) => {
77        paste::paste!{$(
78            #[test]
79            fn [<$name _ $case:snake:lower>]() {
80                $before
81                let state = $crate::compiler::state::TypeState::default();
82
83                let (expression, want) = $crate::__prep_bench_or_test!($func, &state, $args, $(Ok($crate::value::Value::from($ok)))? $(Err($err.to_owned()))?);
84                match expression {
85                    Ok(expression) => {
86                        let mut runtime_state = $crate::compiler::state::RuntimeState::default();
87                        let mut target: $crate::value::Value = ::std::collections::BTreeMap::default().into();
88                        let tz = $tz;
89                        let mut ctx = $crate::compiler::Context::new(&mut target, &mut runtime_state, &tz);
90
91                        let got_value = expression.resolve(&mut ctx)
92                            .map_err(|e| format!("{:#}", anyhow::anyhow!(e)));
93
94                        assert!(got_value == want, "assertion failed for `{}` case:\n  got:    {:?}\n  wanted: {:?}", stringify!($case), got_value, want);
95                        let got_tdef = expression.type_def(&state);
96                        assert_eq!(got_tdef, $tdef);
97                    }
98                    err@Err(_) => {
99                        // Allow tests against compiler errors.
100                        assert_eq!(err
101                                   // We have to map to a value just to make sure the types match even though
102                                   // it will never be used.
103                                   .map(|_| $crate::value::Value::Null)
104                                   .map_err(|e| format!("{:#}", e.message())), want);
105                    }
106                }
107            }
108        )+}
109    };
110}
111
112#[doc(hidden)]
113#[macro_export]
114macro_rules! __prep_bench_or_test {
115    ($func:path, $state:expr_2021, $args:expr_2021, $want:expr_2021) => {{
116        let config = $crate::compiler::CompileConfig::default();
117        (
118            $func.compile(
119                $state,
120                &mut $crate::compiler::function::FunctionCompileContext::new(
121                    $crate::diagnostic::Span::new(0, 0),
122                    config,
123                ),
124                $args.into(),
125            ),
126            $want,
127        )
128    }};
129}
130
131#[macro_export]
132macro_rules! type_def {
133    (unknown) => {
134        TypeDef::any()
135    };
136
137    (bytes) => {
138        TypeDef::bytes()
139    };
140
141    (object {$(unknown => $unknown:expr_2021,)? $($key:literal => $value:expr_2021,)+ }) => {{
142        #[allow(unused_mut)]
143        let mut v = $crate::value::kind::Collection::from(::std::collections::BTreeMap::from([$(($key.into(), $value.into()),)+]));
144        $(v.set_unknown($crate::value::Kind::from($unknown));)?
145
146        TypeDef::object(v)
147    }};
148
149    (array [ $($value:expr_2021,)+ ]) => {{
150        $(let v = $crate::value::kind::Collection::from_unknown($crate::value::Kind::from($value));)+
151
152        TypeDef::array(v)
153    }};
154
155    (array { $(unknown => $unknown:expr_2021,)? $($idx:literal => $value:expr_2021,)+ }) => {{
156        let mut v = $crate::value::kind::Collection::from(::std::collections::BTreeMap::from([$(($idx.into(), $value.into()),)+]));
157        $(v.set_unknown($crate::value::Kind::from($unknown));)?
158
159        TypeDef::array(v)
160    }};
161
162    (array) => {
163        TypeDef::array($crate::value::kind::Collection::any())
164    };
165}