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