1use super::arg_checker;
2use kit::types::commands::AssertionResult;
3use kit::types::commands::ASSERTION_TYPE_ID;
4use txtx_addon_kit::types::functions::FunctionSpecification;
5use txtx_addon_kit::types::types::{Type, Value};
6use txtx_addon_kit::types::AuthorizationContext;
7use txtx_addon_kit::{
8 define_function, indoc,
9 types::{diagnostics::Diagnostic, functions::FunctionImplementation},
10};
11
12lazy_static! {
13 pub static ref FUNCTIONS: Vec<FunctionSpecification> = vec![
14 define_function! {
15 AssertEq => {
16 name: "assert_eq",
17 documentation: "`assert_eq` asserts that two values are equal.",
18 example: indoc!{r#"
19 output "assertion" {
20 value = std::assert_eq(action.example.result, 1)
21 }
22 "#},
23 inputs: [
24 left: {
25 documentation: "A value to compare.",
26 typing: vec![Type::null(), Type::integer(), Type::float(), Type::integer(), Type::string(), Type::bool(), Type::addon(""), Type::array(Type::null()), Type::arbitrary_object()],
27 optional: false
28 },
29 right: {
30 documentation: "The value to compare against.",
31 typing: vec![Type::null(), Type::integer(), Type::float(), Type::integer(), Type::string(), Type::bool(), Type::addon(""), Type::array(Type::null()), Type::arbitrary_object()],
32 optional: false
33 }
34 ],
35 output: {
36 documentation: "The result of the assertion.",
37 typing: Type::addon(ASSERTION_TYPE_ID)
38 },
39 }
40 },
41 define_function! {
42 AssertNe => {
43 name: "assert_ne",
44 documentation: "`assert_ne` asserts that two values are not equal.",
45 example: indoc!{r#"
46 output "assertion" {
47 value = std::assert_ne(action.example.result, 1)
48 }
49 "#},
50 inputs: [
51 left: {
52 documentation: "A value to compare.",
53 typing: vec![Type::null(), Type::integer(), Type::float(), Type::integer(), Type::string(), Type::bool(), Type::addon(""), Type::array(Type::null()), Type::arbitrary_object()],
54 optional: false
55 },
56 right: {
57 documentation: "The value to compare against.",
58 typing: vec![Type::null(), Type::integer(), Type::float(), Type::integer(), Type::string(), Type::bool(), Type::addon(""), Type::array(Type::null()), Type::arbitrary_object()],
59 optional: false
60 }
61 ],
62 output: {
63 documentation: "The result of the assertion.",
64 typing: Type::addon(ASSERTION_TYPE_ID)
65 },
66 }
67 },
68 define_function! {
69 AssertGt => {
70 name: "assert_gt",
71 documentation: "`assert_gt` asserts that the left value is greater than the right value.",
72 example: indoc!{r#"
73 output "assertion" {
74 value = std::assert_gt(action.example.result, 1)
75 }
76 "#},
77 inputs: [
78 left: {
79 documentation: "An integer or float to compare.",
80 typing: vec![Type::integer(), Type::float()],
81 optional: false
82 },
83 right: {
84 documentation: "An integer or float to compare against.",
85 typing: vec![Type::integer(), Type::float()],
86 optional: false
87 }
88 ],
89 output: {
90 documentation: "The result of the assertion.",
91 typing: Type::addon(ASSERTION_TYPE_ID)
92 },
93 }
94 },
95 define_function! {
96 AssertGte => {
97 name: "assert_gte",
98 documentation: "`assert_gte` asserts that the left value is greater than or equal to the right value.",
99 example: indoc!{r#"
100 output "assertion" {
101 value = std::assert_gte(action.example.result, 1)
102 }
103 "#},
104 inputs: [
105 left: {
106 documentation: "An integer or float to compare.",
107 typing: vec![Type::integer(), Type::float()],
108 optional: false
109 },
110 right: {
111 documentation: "An integer or float to compare against.",
112 typing: vec![Type::integer(), Type::float()],
113 optional: false
114 }
115 ],
116 output: {
117 documentation: "The result of the assertion.",
118 typing: Type::addon(ASSERTION_TYPE_ID)
119 },
120 }
121 },
122 define_function! {
123 AssertLt => {
124 name: "assert_lt",
125 documentation: "`assert_lt` asserts that the left value is less than the right value.",
126 example: indoc!{r#"
127 output "assertion" {
128 value = std::assert_lt(action.example.result, 1)
129 }
130 "#},
131 inputs: [
132 left: {
133 documentation: "An integer or float to compare.",
134 typing: vec![Type::integer(), Type::float()],
135 optional: false
136 },
137 right: {
138 documentation: "An integer or float to compare against.",
139 typing: vec![Type::integer(), Type::float()],
140 optional: false
141 }
142 ],
143 output: {
144 documentation: "The result of the assertion.",
145 typing: Type::addon(ASSERTION_TYPE_ID)
146 },
147 }
148 },
149 define_function! {
150 AssertLte => {
151 name: "assert_lte",
152 documentation: "`assert_lte` asserts that the left value is less than or equal to the right value.",
153 example: indoc!{r#"
154 output "assertion" {
155 value = std::assert_lte(action.example.result, 1)
156 }
157 "#},
158 inputs: [
159 left: {
160 documentation: "An integer or float to compare.",
161 typing: vec![Type::integer(), Type::float()],
162 optional: false
163 },
164 right: {
165 documentation: "An integer or float to compare against.",
166 typing: vec![Type::integer(), Type::float()],
167 optional: false
168 }
169 ],
170 output: {
171 documentation: "The result of the assertion.",
172 typing: Type::addon(ASSERTION_TYPE_ID)
173 },
174 }
175 }
176 ];
177}
178
179pub struct AssertEq;
180impl FunctionImplementation for AssertEq {
181 fn check_instantiability(
182 _fn_spec: &FunctionSpecification,
183 _auth_ctx: &AuthorizationContext,
184 _args: &Vec<Type>,
185 ) -> Result<Type, Diagnostic> {
186 unimplemented!()
187 }
188
189 fn run(
190 fn_spec: &FunctionSpecification,
191 _auth_ctx: &AuthorizationContext,
192 args: &Vec<Value>,
193 ) -> Result<Value, Diagnostic> {
194 arg_checker(fn_spec, args)?;
195 let left = &args[0];
196 let right = &args[1];
197 if left.eq(right) {
198 Ok(AssertionResult::Success.to_value())
199 } else {
200 Ok(AssertionResult::Failure(format!(
201 "assertion failed: expected values to be equal: left: '{}', right: '{}'",
202 left.to_string(),
203 right.to_string()
204 ))
205 .to_value())
206 }
207 }
208}
209
210pub struct AssertNe;
211impl FunctionImplementation for AssertNe {
212 fn check_instantiability(
213 _fn_spec: &FunctionSpecification,
214 _auth_ctx: &AuthorizationContext,
215 _args: &Vec<Type>,
216 ) -> Result<Type, Diagnostic> {
217 unimplemented!()
218 }
219
220 fn run(
221 fn_spec: &FunctionSpecification,
222 _auth_ctx: &AuthorizationContext,
223 args: &Vec<Value>,
224 ) -> Result<Value, Diagnostic> {
225 arg_checker(fn_spec, args)?;
226 let left = &args[0];
227 let right = &args[1];
228 if left.ne(right) {
229 Ok(AssertionResult::Success.to_value())
230 } else {
231 Ok(AssertionResult::Failure(format!(
232 "assertion failed: expected values to be not equal: left: '{}', right: '{}'",
233 left.to_string(),
234 right.to_string()
235 ))
236 .to_value())
237 }
238 }
239}
240
241pub struct AssertGt;
242impl FunctionImplementation for AssertGt {
243 fn check_instantiability(
244 _fn_spec: &FunctionSpecification,
245 _auth_ctx: &AuthorizationContext,
246 _args: &Vec<Type>,
247 ) -> Result<Type, Diagnostic> {
248 unimplemented!()
249 }
250
251 fn run(
252 fn_spec: &FunctionSpecification,
253 _auth_ctx: &AuthorizationContext,
254 args: &Vec<Value>,
255 ) -> Result<Value, Diagnostic> {
256 arg_checker(fn_spec, args)?;
257 let left = &args[0];
258 let right = &args[1];
259 match (left, right) {
260 (Value::Integer(left_int), Value::Integer(right_int)) => {
261 if left_int > right_int {
262 Ok(AssertionResult::Success.to_value())
263 } else {
264 Ok(AssertionResult::Failure(format!(
265 "assertion failed: expected left value '{}' to be greater than right value '{}'",
266 left_int, right_int
267 ))
268 .to_value())
269 }
270 }
271 (Value::Float(left_float), Value::Float(right_float)) => {
272 if left_float > right_float {
273 Ok(AssertionResult::Success.to_value())
274 } else {
275 Ok(AssertionResult::Failure(format!(
276 "assertion failed: expected left value '{}' to be greater than right value '{}'",
277 left_float, right_float
278 ))
279 .to_value())
280 }
281 }
282 (Value::Float(left_float), Value::Integer(right_int)) => {
283 if *left_float > *right_int as f64 {
284 Ok(AssertionResult::Success.to_value())
285 } else {
286 Ok(AssertionResult::Failure(format!(
287 "assertion failed: expected left value '{}' to be greater than right value '{}'",
288 left_float, right_int
289 ))
290 .to_value())
291 }
292 }
293 (Value::Integer(left_int), Value::Float(right_float)) => {
294 if *left_int as f64 > *right_float {
295 Ok(AssertionResult::Success.to_value())
296 } else {
297 Ok(AssertionResult::Failure(format!(
298 "assertion failed: expected left value '{}' to be greater than right value '{}'",
299 left_int, right_float
300 ))
301 .to_value())
302 }
303 }
304 _ => unreachable!(),
305 }
306 }
307}
308
309pub struct AssertGte;
310impl FunctionImplementation for AssertGte {
311 fn check_instantiability(
312 _fn_spec: &FunctionSpecification,
313 _auth_ctx: &AuthorizationContext,
314 _args: &Vec<Type>,
315 ) -> Result<Type, Diagnostic> {
316 unimplemented!()
317 }
318
319 fn run(
320 fn_spec: &FunctionSpecification,
321 _auth_ctx: &AuthorizationContext,
322 args: &Vec<Value>,
323 ) -> Result<Value, Diagnostic> {
324 arg_checker(fn_spec, args)?;
325 let left = &args[0];
326 let right = &args[1];
327 match (left, right) {
328 (Value::Integer(left_int), Value::Integer(right_int)) => {
329 if left_int >= right_int {
330 Ok(AssertionResult::Success.to_value())
331 } else {
332 Ok(AssertionResult::Failure(format!(
333 "assertion failed: expected left value '{}' to be greater than or equal to right value '{}'",
334 left_int, right_int
335 ))
336 .to_value())
337 }
338 }
339 (Value::Float(left_float), Value::Float(right_float)) => {
340 if left_float >= right_float {
341 Ok(AssertionResult::Success.to_value())
342 } else {
343 Ok(AssertionResult::Failure(format!(
344 "assertion failed: expected left value '{}' to be greater than or equal to right value '{}'",
345 left_float, right_float
346 ))
347 .to_value())
348 }
349 }
350 (Value::Float(left_float), Value::Integer(right_int)) => {
351 if *left_float >= *right_int as f64 {
352 Ok(AssertionResult::Success.to_value())
353 } else {
354 Ok(AssertionResult::Failure(format!(
355 "assertion failed: expected left value '{}' to be greater than or equal to right value '{}'",
356 left_float, right_int
357 ))
358 .to_value())
359 }
360 }
361 (Value::Integer(left_int), Value::Float(right_float)) => {
362 if *left_int as f64 >= *right_float {
363 Ok(AssertionResult::Success.to_value())
364 } else {
365 Ok(AssertionResult::Failure(format!(
366 "assertion failed: expected left value '{}' to be greater than or equal to right value '{}'",
367 left_int, right_float
368 ))
369 .to_value())
370 }
371 }
372 _ => unreachable!(),
373 }
374 }
375}
376
377pub struct AssertLt;
378impl FunctionImplementation for AssertLt {
379 fn check_instantiability(
380 _fn_spec: &FunctionSpecification,
381 _auth_ctx: &AuthorizationContext,
382 _args: &Vec<Type>,
383 ) -> Result<Type, Diagnostic> {
384 unimplemented!()
385 }
386
387 fn run(
388 fn_spec: &FunctionSpecification,
389 _auth_ctx: &AuthorizationContext,
390 args: &Vec<Value>,
391 ) -> Result<Value, Diagnostic> {
392 arg_checker(fn_spec, args)?;
393 let left = &args[0];
394 let right = &args[1];
395 match (left, right) {
396 (Value::Integer(left_int), Value::Integer(right_int)) => {
397 if left_int < right_int {
398 Ok(AssertionResult::Success.to_value())
399 } else {
400 Ok(AssertionResult::Failure(format!(
401 "assertion failed: expected left value '{}' to be less than right value '{}'",
402 left_int, right_int
403 ))
404 .to_value())
405 }
406 }
407 (Value::Float(left_float), Value::Float(right_float)) => {
408 if left_float < right_float {
409 Ok(AssertionResult::Success.to_value())
410 } else {
411 Ok(AssertionResult::Failure(format!(
412 "assertion failed: expected left value '{}' to be less than right value '{}'",
413 left_float, right_float
414 ))
415 .to_value())
416 }
417 }
418 (Value::Float(left_float), Value::Integer(right_int)) => {
419 if *left_float < *right_int as f64 {
420 Ok(AssertionResult::Success.to_value())
421 } else {
422 Ok(AssertionResult::Failure(format!(
423 "assertion failed: expected left value '{}' to be less than right value '{}'",
424 left_float, right_int
425 ))
426 .to_value())
427 }
428 }
429 (Value::Integer(left_int), Value::Float(right_float)) => {
430 if (*left_int as f64) < (*right_float) {
431 Ok(AssertionResult::Success.to_value())
432 } else {
433 Ok(AssertionResult::Failure(format!(
434 "assertion failed: expected left value '{}' to be less than right value '{}'",
435 left_int, right_float
436 ))
437 .to_value())
438 }
439 }
440 _ => unreachable!(),
441 }
442 }
443}
444
445pub struct AssertLte;
446impl FunctionImplementation for AssertLte {
447 fn check_instantiability(
448 _fn_spec: &FunctionSpecification,
449 _auth_ctx: &AuthorizationContext,
450 _args: &Vec<Type>,
451 ) -> Result<Type, Diagnostic> {
452 unimplemented!()
453 }
454
455 fn run(
456 fn_spec: &FunctionSpecification,
457 _auth_ctx: &AuthorizationContext,
458 args: &Vec<Value>,
459 ) -> Result<Value, Diagnostic> {
460 arg_checker(fn_spec, args)?;
461 let left = &args[0];
462 let right = &args[1];
463 match (left, right) {
464 (Value::Integer(left_int), Value::Integer(right_int)) => {
465 if left_int <= right_int {
466 Ok(AssertionResult::Success.to_value())
467 } else {
468 Ok(AssertionResult::Failure(format!(
469 "assertion failed: expected left value '{}' to be less than or equal to right value '{}'",
470 left_int, right_int
471 ))
472 .to_value())
473 }
474 }
475 (Value::Float(left_float), Value::Float(right_float)) => {
476 if left_float <= right_float {
477 Ok(AssertionResult::Success.to_value())
478 } else {
479 Ok(AssertionResult::Failure(format!(
480 "assertion failed: expected left value '{}' to be less than or equal to right value '{}'",
481 left_float, right_float
482 ))
483 .to_value())
484 }
485 }
486 (Value::Float(left_float), Value::Integer(right_int)) => {
487 if *left_float <= *right_int as f64 {
488 Ok(AssertionResult::Success.to_value())
489 } else {
490 Ok(AssertionResult::Failure(format!(
491 "assertion failed: expected left value '{}' to be less than or equal to right value '{}'",
492 left_float, right_int
493 ))
494 .to_value())
495 }
496 }
497 (Value::Integer(left_int), Value::Float(right_float)) => {
498 if (*left_int as f64) <= (*right_float) {
499 Ok(AssertionResult::Success.to_value())
500 } else {
501 Ok(AssertionResult::Failure(format!(
502 "assertion failed: expected left value '{}' to be less than or equal to right value '{}'",
503 left_int, right_float
504 ))
505 .to_value())
506 }
507 }
508 _ => unreachable!(),
509 }
510 }
511}
512
513#[cfg(test)]
514mod tests {
515 use kit::helpers::fs::FileLocation;
516 use test_case::test_case;
517
518 use super::*;
519
520 fn get_spec_by_name(name: &str) -> FunctionSpecification {
521 FUNCTIONS.iter().find(|f| f.name == name).cloned().unwrap()
522 }
523
524 fn dummy_auth_ctx() -> AuthorizationContext {
525 AuthorizationContext { workspace_location: FileLocation::working_dir() }
526 }
527
528 #[test_case("assert_eq", Value::Integer(5), Value::Integer(5), AssertionResult::Success; "assert_eq success")]
529 #[test_case("assert_eq", Value::String("foo".into()), Value::String("bar".into()), AssertionResult::Failure("assertion failed: expected values to be equal: left: 'foo', right: 'bar'".into()); "assert_eq failure")]
530 #[test_case("assert_ne", Value::Bool(true), Value::Bool(false), AssertionResult::Success; "assert_ne success")]
531 #[test_case("assert_ne", Value::Float(1.0), Value::Float(1.0), AssertionResult::Failure("assertion failed: expected values to be not equal: left: '1', right: '1'".into()); "assert_ne failure")]
532 #[test_case("assert_gt", Value::Integer(10), Value::Integer(5), AssertionResult::Success; "assert_gt success int")]
533 #[test_case("assert_gt", Value::Float(3.5), Value::Float(2.1), AssertionResult::Success; "assert_gt success float")]
534 #[test_case("assert_gt", Value::Integer(2), Value::Integer(10), AssertionResult::Failure("assertion failed: expected left value '2' to be greater than right value '10'".into()); "assert_gt failure")]
535 #[test_case("assert_gte", Value::Integer(7), Value::Integer(7), AssertionResult::Success; "assert_gte success equal")]
536 #[test_case("assert_gte", Value::Float(8.0), Value::Float(7.9), AssertionResult::Success; "assert_gte success greater")]
537 #[test_case("assert_gte", Value::Integer(1), Value::Integer(2), AssertionResult::Failure("assertion failed: expected left value '1' to be greater than or equal to right value '2'".into()); "assert_gte failure")]
538 #[test_case("assert_lt", Value::Integer(1), Value::Integer(2), AssertionResult::Success; "assert_lt success")]
539 #[test_case("assert_lt", Value::Float(3.0), Value::Float(2.1), AssertionResult::Failure("assertion failed: expected left value '3' to be less than right value '2.1'".into()); "assert_lt failure")]
540 #[test_case("assert_lte", Value::Integer(5), Value::Integer(5), AssertionResult::Success; "assert_lte success equal")]
541 #[test_case("assert_lte", Value::Float(1.1), Value::Float(2.2), AssertionResult::Success; "assert_lte success less")]
542 #[test_case("assert_lte", Value::Integer(10), Value::Integer(2), AssertionResult::Failure("assertion failed: expected left value '10' to be less than or equal to right value '2'".into()); "assert_lte failure")]
543 fn test_assertions(fn_spec_name: &str, left: Value, right: Value, expected: AssertionResult) {
544 let fn_spec = get_spec_by_name(fn_spec_name);
545 let args = vec![left, right];
546 let result = (fn_spec.runner)(&fn_spec, &dummy_auth_ctx(), &args).unwrap();
547 assert_eq!(result, expected.to_value());
548 }
549
550 #[test_case("assert_gt", Value::String("test".into()), Value::Integer(6), Diagnostic::error_from_string("function 'std::assert_gt' argument #1 (left) should be of type (integer,float), found string".into()); "assert_gt with string and integer")]
551 #[test_case("assert_gte", Value::Bool(false), Value::Float(2.5), Diagnostic::error_from_string("function 'std::assert_gte' argument #1 (left) should be of type (integer,float), found bool".into()); "assert_gte with bool and float")]
552 #[test_case("assert_lt", Value::Bool(true), Value::Float(3.5), Diagnostic::error_from_string("function 'std::assert_lt' argument #1 (left) should be of type (integer,float), found bool".into()); "assert_lt with bool and float")]
553 #[test_case("assert_lte", Value::String("test".into()), Value::Integer(6), Diagnostic::error_from_string("function 'std::assert_lte' argument #1 (left) should be of type (integer,float), found string".into()); "assert_lte with string and integer")]
554 fn test_invalid_inputs(fn_spec_name: &str, left: Value, right: Value, expected: Diagnostic) {
555 let fn_spec = get_spec_by_name(fn_spec_name);
556 let args = vec![left, right];
557 let result = (fn_spec.runner)(&fn_spec, &dummy_auth_ctx(), &args).unwrap_err();
558 assert_eq!(result, expected);
559 }
560}