//! End-to-end tests: string input → final output. use std::collections::HashMap; use std::sync::Arc; use symclaw_core::ast::Expr; use symclaw_core::interner::Symbol; use symclaw_core::{ codegen, differentiate, eval, integrate, limits, number_theory, parser, poly, proof, series, simplify, solve, }; fn parse(s: &str) -> Arc { parser::parse(s).unwrap() } // ── 1. Differentiate x^3 ─────────────────────────────────────── #[test] fn e2e_differentiate_x_cubed() { let expr = parse("x^3"); let deriv = differentiate::differentiate(&expr, Symbol::new("x")); let simplified = simplify::simplify(&deriv); let s = format!("{simplified}"); assert!(s.contains("3") && s.contains("x"), "d/dx(x^3) = {s}"); } // ── 2. Integrate sin(x) ──────────────────────────────────────── #[test] fn e2e_integrate_sin() { let expr = parse("sin(x)"); let result = integrate::integrate(&expr, Symbol::new("x")).unwrap(); let s = format!("{result}"); assert!(s.contains("cos"), "∫sin(x)dx should contain cos: {s}"); } // ── 3. Solve x^2 - 4 = 0 ─────────────────────────────────────── #[test] fn e2e_solve_quadratic() { let expr = parse("x^2 - 4"); let sols = solve::solve(&expr, Symbol::new("x")); assert_eq!(sols.len(), 2, "x^2-4=0 should have 2 solutions"); let strs: Vec = sols.iter().map(|s| format!("{s}")).collect(); assert!(strs.contains(&"2".to_owned()) || strs.iter().any(|s| s.contains("2"))); } // ── 4. Limit sin(x)/x → 1 ────────────────────────────────────── #[test] fn e2e_limit_sinc() { let expr = parse("sin(x)/x"); let result = limits::limit_at(&expr, "x", 0.0); match result { limits::LimitResult::Finite(e) => { let s = format!("{e}"); assert!(s == "1" || s.starts_with("1"), "limit = {s}"); } other => panic!("expected 1, got {other:?}"), } } // ── 5. Taylor expansion of exp(x) ────────────────────────────── #[test] fn e2e_taylor_exp() { let expr = parse("exp(x)"); let point = parse("0"); let expansion = series::taylor(&expr, Symbol::new("x"), &point, 5); // Check it evaluates correctly at x=0.5 let mut vars = HashMap::new(); vars.insert(Symbol::new("x"), 0.5); let val = eval::eval(&expansion, &vars).unwrap(); assert!((val - 0.5_f64.exp()).abs() < 0.01); } // ── 6. Simplify (x+1)*(x-1) ──────────────────────────────────── #[test] fn e2e_simplify_expand() { let expr = parse("(x+1)*(x-1)"); let simplified = simplify::simplify(&expr); let s = format!("{simplified}"); // Should simplify to x^2 - 1 or equivalent assert!( s.contains("x") && (s.contains("-1") || s.contains("x^2")), "got: {s}" ); } // ── 7. Proof trace ────────────────────────────────────────────── #[test] fn e2e_proof_trace() { let expr = parse("x + 0"); let trace = proof::trace_simplify(&expr); assert_eq!(trace.result, "x"); } // ── 8. Codegen to Python ──────────────────────────────────────── #[test] fn e2e_codegen_python() { let expr = parse("x^2 + y"); let opts = codegen::CodegenOptions::new(codegen::Language::Python); let code = codegen::generate(&expr, &opts); assert!( code.contains("**") || code.contains("pow"), "Python code: {code}" ); } // ── 9. Number theory: is_prime ────────────────────────────────── #[test] fn e2e_is_prime() { assert!(number_theory::is_prime(97)); assert!(!number_theory::is_prime(42)); } // ── 10. Number theory: factorize ──────────────────────────────── #[test] fn e2e_factorize() { let factors = number_theory::factorize(360); assert_eq!(factors, vec![(2, 3), (3, 2), (5, 1)]); } // ── 11. Polynomial conversion ─────────────────────────────────── #[test] fn e2e_polynomial() { let expr = parse("x^3 + 2*x^2 + x"); let p = poly::Polynomial::from_expr(&expr).unwrap(); let back = p.to_expr(); let s = format!("{}", Arc::new(back)); assert!(s.contains("x"), "poly roundtrip: {s}"); } // ── 12. Solve linear equation ─────────────────────────────────── #[test] fn e2e_solve_linear() { let expr = parse("2*x - 6"); let sols = solve::solve(&expr, Symbol::new("x")); assert!(!sols.is_empty()); let strs: Vec = sols.iter().map(|s| format!("{s}")).collect(); assert!(strs.contains(&"3".to_owned())); } // ── 13. Differentiate trig ────────────────────────────────────── #[test] fn e2e_differentiate_cos() { let expr = parse("cos(x)"); let deriv = differentiate::differentiate(&expr, Symbol::new("x")); let s = format!("{}", simplify::simplify(&deriv)); assert!(s.contains("sin"), "d/dx(cos(x)) = {s}"); } // ── 14. Eval with variables ───────────────────────────────────── #[test] fn e2e_eval_with_vars() { let expr = parse("x^2 + y"); let mut vars = HashMap::new(); vars.insert(Symbol::new("x"), 3.0); vars.insert(Symbol::new("y"), 1.0); let val = eval::eval(&expr, &vars).unwrap(); assert!((val - 10.0).abs() < 1e-10); } // ── 15. Fibonacci ─────────────────────────────────────────────── #[test] fn e2e_fibonacci() { assert_eq!(number_theory::fibonacci(10), 55); assert_eq!(number_theory::fibonacci(0), 0); assert_eq!(number_theory::fibonacci(1), 1); } // ── 16. Simplify nested ──────────────────────────────────────── #[test] fn e2e_simplify_nested() { let expr = parse("(x * 1) + (0 + y)"); let simplified = simplify::simplify(&expr); let s = format!("{simplified}"); assert!(s.contains("x") && s.contains("y"), "simplified: {s}"); }