use rstest::*; use steel_decimal::ScriptParser; use std::collections::HashSet; #[fixture] fn parser() -> ScriptParser { ScriptParser::new() } #[rstest] #[case("(+ 1.5 2.3)", "(decimal-add \"1.5\" \"2.3\")")] #[case("(- 10 5)", "(decimal-sub \"10\" \"5\")")] #[case("(* 2.5 4)", "(decimal-mul \"2.5\" \"4\")")] #[case("(/ 15 3)", "(decimal-div \"15\" \"3\")")] fn test_basic_arithmetic_transformation(parser: ScriptParser, #[case] input: &str, #[case] expected: &str) { let result = parser.transform(input); assert_eq!(result, expected); } #[rstest] #[case("(^ 2 3)", "(decimal-pow \"2\" \"3\")")] #[case("(** 2 3)", "(decimal-pow \"2\" \"3\")")] #[case("(pow 2 3)", "(decimal-pow \"2\" \"3\")")] #[case("(sqrt 16)", "(decimal-sqrt \"16\")")] #[case("(ln 2.718)", "(decimal-ln \"2.718\")")] #[case("(log 2.718)", "(decimal-ln \"2.718\")")] #[case("(log10 100)", "(decimal-log10 \"100\")")] #[case("(exp 1)", "(decimal-exp \"1\")")] fn test_advanced_math_transformation(parser: ScriptParser, #[case] input: &str, #[case] expected: &str) { let result = parser.transform(input); assert_eq!(result, expected); } #[rstest] #[case("(sin 1.57)", "(decimal-sin \"1.57\")")] #[case("(cos 0)", "(decimal-cos \"0\")")] #[case("(tan 0.785)", "(decimal-tan \"0.785\")")] fn test_trigonometric_transformation(parser: ScriptParser, #[case] input: &str, #[case] expected: &str) { let result = parser.transform(input); assert_eq!(result, expected); } #[rstest] #[case("(> 5 3)", "(decimal-gt \"5\" \"3\")")] #[case("(< 3 5)", "(decimal-lt \"3\" \"5\")")] #[case("(= 5 5)", "(decimal-eq \"5\" \"5\")")] #[case("(>= 5 3)", "(decimal-gte \"5\" \"3\")")] #[case("(<= 3 5)", "(decimal-lte \"3\" \"5\")")] fn test_comparison_transformation(parser: ScriptParser, #[case] input: &str, #[case] expected: &str) { let result = parser.transform(input); assert_eq!(result, expected); } #[rstest] #[case("(abs -5)", "(decimal-abs \"-5\")")] #[case("(min 3 5)", "(decimal-min \"3\" \"5\")")] #[case("(max 3 5)", "(decimal-max \"3\" \"5\")")] #[case("(round 3.14159 2)", "(decimal-round \"3.14159\" \"2\")")] fn test_utility_transformation(parser: ScriptParser, #[case] input: &str, #[case] expected: &str) { let result = parser.transform(input); assert_eq!(result, expected); } #[rstest] #[case("$x", "(get-var \"x\")")] #[case("$price", "(get-var \"price\")")] #[case("$some_variable", "(get-var \"some_variable\")")] fn test_variable_transformation(parser: ScriptParser, #[case] input: &str, #[case] expected: &str) { let result = parser.transform(input); assert_eq!(result, expected); } #[rstest] #[case("42", "\"42\"")] #[case("3.14159", "\"3.14159\"")] #[case("-5.5", "\"-5.5\"")] #[case("1.5e2", "\"1.5e2\"")] #[case("2.3E-1", "\"2.3E-1\"")] fn test_number_literal_transformation(parser: ScriptParser, #[case] input: &str, #[case] expected: &str) { let result = parser.transform(input); assert_eq!(result, expected); } #[rstest] #[case( "(+ (* 2.5 3.0) (/ 15.0 3.0))", "(decimal-add (decimal-mul \"2.5\" \"3.0\") (decimal-div \"15.0\" \"3.0\"))" )] #[case( "(sqrt (+ (* $x $x) (* $y $y)))", "(decimal-sqrt (decimal-add (decimal-mul (get-var \"x\") (get-var \"x\")) (decimal-mul (get-var \"y\") (get-var \"y\"))))" )] #[case( "(/ (+ $a $b) (- $c $d))", "(decimal-div (decimal-add (get-var \"a\") (get-var \"b\")) (decimal-sub (get-var \"c\") (get-var \"d\")))" )] fn test_complex_expressions(parser: ScriptParser, #[case] input: &str, #[case] expected: &str) { let result = parser.transform(input); assert_eq!(result, expected); } #[rstest] #[case("(+ $x $y)", vec!["x", "y"])] #[case("(* $price $quantity)", vec!["price", "quantity"])] #[case("(/ (+ $a $b) $c)", vec!["a", "b", "c"])] #[case("(sqrt (+ (* $x $x) (* $y $y)))", vec!["x", "y"])] fn test_dependency_extraction(parser: ScriptParser, #[case] input: &str, #[case] expected_deps: Vec<&str>) { let deps = parser.extract_dependencies(input); let expected: HashSet = expected_deps.into_iter().map(|s| s.to_string()).collect(); assert_eq!(deps, expected); } #[rstest] #[case("(+ 1 2)", "Addition")] #[case("(- 5 3)", "Subtraction")] #[case("(* 2 4)", "Multiplication")] #[case("(/ 8 2)", "Division")] #[case("(sin 0)", "Trigonometry")] #[case("(sqrt 16)", "Square root")] #[case("(> 5 3)", "Comparison")] fn test_parser_handles_various_functions(parser: ScriptParser, #[case] input: &str, #[case] _description: &str) { let result = parser.transform(input); // Should not panic and should produce valid output assert!(!result.is_empty()); assert!(result.starts_with('(')); assert!(result.ends_with(')')); } #[rstest] fn test_parser_preserves_structure(parser: ScriptParser) { let input = "(+ (- 10 5) (* 2 3))"; let result = parser.transform(input); // Check that parentheses are balanced let open_count = result.chars().filter(|c| *c == '(').count(); let close_count = result.chars().filter(|c| *c == ')').count(); assert_eq!(open_count, close_count); // Check that the structure is preserved assert!(result.contains("decimal-add")); assert!(result.contains("decimal-sub")); assert!(result.contains("decimal-mul")); } #[rstest] fn test_parser_handles_empty_input(parser: ScriptParser) { let result = parser.transform(""); assert_eq!(result, ""); } #[rstest] fn test_parser_handles_whitespace(parser: ScriptParser) { let input = "( + 1.5 2.3 )"; let result = parser.transform(input); assert!(result.contains("decimal-add")); assert!(result.contains("\"1.5\"")); assert!(result.contains("\"2.3\"")); }