1use std::any::Any;
2use std::marker::PhantomData;
3
4use crate::arguments::VerbArgument;
5use crate::error::TestErrorCase;
6
7pub trait TestVerb<H>: 'static {
8 fn run(&self, harness: &mut H, node: &kdl::KdlNode) -> Result<(), TestErrorCase>;
9 fn clone_box(&self) -> Box<dyn TestVerb<H>>;
10}
11
12impl<H: 'static> Clone for Box<dyn TestVerb<H>> {
13 fn clone(&self) -> Self {
14 let this: &dyn TestVerb<H> = &**self;
15 this.clone_box()
16 }
17}
18
19pub struct FunctionVerb<H> {
20 func: BoxedCallable<H>,
21 _pd: PhantomData<fn(H)>,
22}
23
24impl<H> Clone for FunctionVerb<H> {
25 fn clone(&self) -> Self {
26 Self {
27 func: self.func.clone(),
28 _pd: self._pd,
29 }
30 }
31}
32
33impl<H> FunctionVerb<H> {
34 pub fn new<F, T>(func: F) -> Self
35 where
36 F: CallableVerb<H, T>,
37 {
38 FunctionVerb {
39 func: BoxedCallable::new(func),
40 _pd: PhantomData,
41 }
42 }
43}
44
45struct BoxedCallable<H> {
46 callable: Box<dyn Any>,
47 call_fn: fn(&dyn Any, &mut H, &kdl::KdlNode) -> Result<(), TestErrorCase>,
48 clone_fn: fn(&dyn Any) -> Box<dyn Any>,
49}
50
51impl<H> Clone for BoxedCallable<H> {
52 fn clone(&self) -> Self {
53 BoxedCallable {
54 callable: (self.clone_fn)(&*self.callable),
55 call_fn: self.call_fn,
56 clone_fn: self.clone_fn,
57 }
58 }
59}
60
61impl<H> BoxedCallable<H> {
62 fn new<F, T>(callable: F) -> Self
63 where
64 F: CallableVerb<H, T>,
65 {
66 BoxedCallable {
67 callable: Box::new(callable),
68 call_fn: |this, harness, node| {
69 let this: &F = this.downcast_ref().unwrap();
70 this.call(harness, node)
71 },
72 clone_fn: |this| {
73 let this: &F = this.downcast_ref().unwrap();
74 Box::new(this.clone())
75 },
76 }
77 }
78
79 fn call(&self, harness: &mut H, node: &kdl::KdlNode) -> Result<(), TestErrorCase> {
80 (self.call_fn)(&*self.callable, harness, node)
81 }
82}
83
84pub trait CallableVerb<H, T>: Clone + 'static {
85 fn call(&self, harness: &mut H, node: &kdl::KdlNode) -> Result<(), TestErrorCase>;
86}
87
88impl<H, F> CallableVerb<H, ((),)> for F
89where
90 F: Fn(&mut H) -> miette::Result<()>,
91 F: Clone + 'static,
92{
93 fn call(&self, harness: &mut H, node: &kdl::KdlNode) -> Result<(), TestErrorCase> {
94 self(harness).map_err(|error| TestErrorCase::Error {
95 error,
96 label: node.span(),
97 })
98 }
99}
100
101#[rustfmt::skip]
102macro_rules! all_the_tuples {
103 ($name:ident) => {
104 $name!([], T1);
105 $name!([T1], T2);
106 $name!([T1, T2], T3);
107 $name!([T1, T2, T3], T4);
108 $name!([T1, T2, T3, T4], T5);
109 $name!([T1, T2, T3, T4, T5], T6);
110 $name!([T1, T2, T3, T4, T5, T6], T7);
111 $name!([T1, T2, T3, T4, T5, T6, T7], T8);
112 $name!([T1, T2, T3, T4, T5, T6, T7, T8], T9);
113 $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9], T10);
114 $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], T11);
115 $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11], T12);
116 $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12], T13);
117 $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13], T14);
118 $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14], T15);
119 $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15], T16);
120 };
121}
122
123macro_rules! impl_callable {
124 (
125 [$($ty:ident),*], $last:ident
126 ) => {
127 #[allow(non_snake_case, unused_mut)]
128 impl<H, F, $($ty,)* $last> CallableVerb<H, ($($ty,)* $last,)> for F
129 where
130 F: Fn(&mut H, $($ty,)* $last,) -> miette::Result<()>,
131 F: Clone + 'static,
132 $( $ty: VerbArgument, )*
133 $last: VerbArgument,
134 {
135 fn call(&self, harness: &mut H, node: &kdl::KdlNode) -> Result<(), TestErrorCase> {
136 let mut args = node.iter();
137
138 let total_count = 1
139 $(
140 + {
141 const _: () = {
142 #[allow(unused)]
143 let $ty = ();
144 };
145 1
146 }
147
148 )*;
149
150 let mut running_count = 1;
151
152 $(
153 let arg = args.next().ok_or_else(|| TestErrorCase::MissingArgument {
154 parent: node.span(),
155 missing: format!("This verb takes {} arguments, you're missing the {}th argument.", total_count, running_count),
156 })?;
157
158 let $ty = <$ty as VerbArgument>::from_value(arg).ok_or_else(|| {
159 TestErrorCase::WrongArgumentType {
160 parent: node.name().span(),
161 argument: arg.span(),
162 expected: format!("This verb takes a '{}' as its argument here.", <$ty as VerbArgument>::TYPE_NAME),
163 }
164 })?;
165 running_count += 1;
166 )*
167
168 let _ = running_count;
169
170 let arg = args.next().ok_or_else(|| TestErrorCase::MissingArgument {
171 parent: node.span(),
172 missing: format!("This verb takes {tc} arguments, you're missing the {tc}th argument.", tc = total_count),
173 })?;
174 let $last = <$last as VerbArgument>::from_value(arg).ok_or_else(|| {
175 TestErrorCase::WrongArgumentType {
176 parent: node.name().span(),
177 argument: arg.span(),
178 expected: format!("This verb takes a '{}' as its argument here.", <$last as VerbArgument>::TYPE_NAME),
179 }
180 })?;
181
182 self(harness, $($ty,)* $last,).map_err(|error| TestErrorCase::Error {
183 error,
184 label: node.span()
185 })
186 }
187 }
188 };
189}
190
191all_the_tuples!(impl_callable);
192
193impl<H: 'static> TestVerb<H> for FunctionVerb<H> {
194 fn run(&self, harness: &mut H, node: &kdl::KdlNode) -> Result<(), TestErrorCase> {
195 let res = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
196 self.func.call(harness, node)
197 }));
198
199 match res {
200 Ok(res) => res,
201 Err(error) => {
202 let mut message = "Something went wrong".to_string();
203
204 let payload = error;
205
206 if let Some(msg) = payload.downcast_ref::<&str>() {
207 message = msg.to_string();
208 }
209
210 if let Some(msg) = payload.downcast_ref::<String>() {
211 message.clone_from(msg);
212 }
213
214 Err(TestErrorCase::Panic {
215 error: miette::Error::msg(message),
216 label: node.span(),
217 })
218 }
219 }
220 }
221
222 fn clone_box(&self) -> Box<dyn TestVerb<H>> {
223 Box::new(self.clone())
224 }
225}