use yufmath::{Yufmath, ComputeConfig, PrecisionConfig, FormatOptions, FormatType};
use yufmath::core::{Expression, Number, MathConstant, BinaryOperator};
use std::collections::HashMap;
use std::time::Duration;
use std::sync::{Arc, Mutex};
#[test]
fn test_basic_api_creation() {
let yuf = Yufmath::new();
assert!(yuf.get_config().enable_progress);
let config = ComputeConfig::new()
.with_progress(false)
.with_max_compute_time(Duration::from_secs(30));
let yuf_with_config = Yufmath::with_config(config);
assert!(!yuf_with_config.get_config().enable_progress);
assert_eq!(yuf_with_config.get_config().max_compute_time, Some(Duration::from_secs(30)));
}
#[test]
fn test_basic_computation() {
let yuf = Yufmath::new();
assert_eq!(yuf.compute("2 + 3").unwrap(), "5");
assert_eq!(yuf.compute("2 * 3").unwrap(), "6");
assert_eq!(yuf.compute("10 / 2").unwrap(), "5");
assert_eq!(yuf.compute("x + x").unwrap(), "2*x");
assert_eq!(yuf.compute("x * 1").unwrap(), "x");
assert_eq!(yuf.compute("x + 0").unwrap(), "x");
}
#[test]
fn test_expression_parsing() {
let yuf = Yufmath::new();
let num_expr = yuf.parse("42").unwrap();
assert!(matches!(num_expr, Expression::Number(_)));
let var_expr = yuf.parse("x").unwrap();
assert!(matches!(var_expr, Expression::Variable(_)));
let binary_expr = yuf.parse("x + y").unwrap();
assert!(matches!(binary_expr, Expression::BinaryOp { .. }));
let func_expr = yuf.parse("sin(x)").unwrap();
assert!(matches!(func_expr, Expression::UnaryOp { .. }));
}
#[test]
fn test_expression_simplification() {
let yuf = Yufmath::new();
let expr = yuf.parse("x + x").unwrap();
let simplified = yuf.simplify(&expr).unwrap();
let expr = yuf.parse("x * 1").unwrap();
let simplified = yuf.simplify(&expr).unwrap();
assert!(matches!(simplified, Expression::Variable(_)));
let expr = yuf.parse("x + 0").unwrap();
let simplified = yuf.simplify(&expr).unwrap();
assert!(matches!(simplified, Expression::Variable(_)));
}
#[test]
fn test_calculus_operations() {
let yuf = Yufmath::new();
let expr = yuf.parse("x^2").unwrap();
let derivative = yuf.diff(&expr, "x").unwrap();
let expr = yuf.parse("x^3").unwrap();
let derivative = yuf.differentiate(&expr, "x").unwrap();
let expr = yuf.parse("2*x").unwrap();
let integral = yuf.integrate(&expr, "x").unwrap();
}
#[test]
fn test_batch_operations() {
let yuf = Yufmath::new();
let expressions = vec!["2 + 3", "4 * 5", "10 / 2"];
let results = yuf.batch_compute(&expressions);
assert_eq!(results.len(), 3);
assert_eq!(results[0].as_ref().unwrap(), "5");
assert_eq!(results[1].as_ref().unwrap(), "20");
assert_eq!(results[2].as_ref().unwrap(), "5");
let parse_results = yuf.batch_parse(&expressions);
assert_eq!(parse_results.len(), 3);
assert!(parse_results.iter().all(|r| r.is_ok()));
let parsed_exprs: Vec<Expression> = parse_results.into_iter()
.map(|r| r.unwrap())
.collect();
let simplify_results = yuf.batch_simplify(&parsed_exprs);
assert_eq!(simplify_results.len(), 3);
assert!(simplify_results.iter().all(|r| r.is_ok()));
}
#[test]
fn test_format_options() {
let mut yuf = Yufmath::new();
yuf.set_format_options(FormatOptions {
format_type: FormatType::Standard,
precision: Some(2),
use_parentheses: false,
});
let result = yuf.compute("pi").unwrap();
yuf.set_format_options(FormatOptions {
format_type: FormatType::LaTeX,
precision: None,
use_parentheses: true,
});
let result = yuf.compute("x^2").unwrap();
}
#[test]
fn test_progress_monitoring() {
let mut yuf = Yufmath::new();
let progress_data = Arc::new(Mutex::new(Vec::new()));
let progress_data_clone = Arc::clone(&progress_data);
yuf.set_progress_callback(Box::new(move |progress| {
if let Ok(mut data) = progress_data_clone.lock() {
data.push((progress.current_step.clone(), progress.progress));
}
true }));
let result = yuf.compute_with_progress("x^2 + 2*x + 1");
assert!(result.is_ok());
if let Ok(data) = progress_data.lock() {
assert!(!data.is_empty());
assert!(data.len() >= 2);
};
}
#[test]
fn test_cancellation() {
let mut yuf = Yufmath::new();
assert!(!yuf.is_cancelled());
yuf.cancel_computation();
assert!(yuf.is_cancelled());
let _ = yuf.compute("2 + 3");
}
#[test]
fn test_performance_stats() {
let mut yuf = Yufmath::new();
let _ = yuf.compute("2 + 3");
let _ = yuf.compute("x^2");
let _ = yuf.compute("sin(pi/2)");
if let Some(stats) = yuf.get_performance_stats() {
assert!(stats.total_computations >= 3);
assert!(stats.successful_computations <= stats.total_computations);
assert!(stats.success_rate() >= 0.0 && stats.success_rate() <= 1.0);
}
yuf.reset_performance_stats();
if let Some(stats) = yuf.get_performance_stats() {
assert_eq!(stats.total_computations, 0);
assert_eq!(stats.successful_computations, 0);
}
}
#[test]
fn test_config_updates() {
let mut yuf = Yufmath::new();
assert!(yuf.get_config().enable_progress);
let new_config = ComputeConfig::new()
.with_progress(false)
.with_progress_interval(200);
yuf.update_config(new_config);
assert!(!yuf.get_config().enable_progress);
assert_eq!(yuf.get_config().progress_interval_ms, 200);
}
#[test]
fn test_precision_config() {
let precision_config = PrecisionConfig::new()
.with_force_exact(true)
.with_max_precision(500)
.with_symbolic(true)
.with_approximation_threshold(1e-10);
let config = ComputeConfig::new()
.with_precision(precision_config);
let yuf = Yufmath::with_config(config);
assert!(yuf.get_config().precision.force_exact);
assert_eq!(yuf.get_config().precision.max_precision, Some(500));
assert!(yuf.get_config().precision.allow_symbolic);
assert_eq!(yuf.get_config().precision.approximation_threshold, Some(1e-10));
}
#[test]
fn test_numerical_evaluation() {
let yuf = Yufmath::new();
let expr = yuf.parse("x^2 + 2*x + 1").unwrap();
let mut vars = HashMap::new();
vars.insert("x".to_string(), 2.0);
let result = yuf.numerical_evaluate(&expr, &vars).unwrap();
assert_eq!(result, 9.0);
let mut exact_vars = HashMap::new();
exact_vars.insert("x".to_string(), Number::from(2));
let exact_result = yuf.evaluate(&expr, &exact_vars).unwrap();
assert!(matches!(exact_result, Number::Integer(_)));
}
#[test]
fn test_polynomial_operations() {
let yuf = Yufmath::new();
let expr = yuf.parse("(x + 1)^2").unwrap();
let expanded = yuf.expand(&expr).unwrap();
let expr = yuf.parse("x^2 - 1").unwrap();
let factored = yuf.factor(&expr).unwrap();
let expr = yuf.parse("x^2 + 2*x + x^2").unwrap();
let collected = yuf.collect(&expr, "x").unwrap();
}
#[test]
fn test_advanced_math_functions() {
let yuf = Yufmath::new();
let expr = yuf.parse("sin(x)/x").unwrap();
let point = yuf.parse("0").unwrap();
let limit_result = yuf.limit(&expr, "x", &point);
let expr = yuf.parse("e^x").unwrap();
let point = yuf.parse("0").unwrap();
let series_result = yuf.series(&expr, "x", &point, 3);
}
#[test]
fn test_number_theory_functions() {
let yuf = Yufmath::new();
let a = yuf.parse("48").unwrap();
let b = yuf.parse("18").unwrap();
let gcd_result = yuf.gcd(&a, &b).unwrap();
let lcm_result = yuf.lcm(&a, &b).unwrap();
let prime_num = yuf.parse("17").unwrap();
let is_prime_result = yuf.is_prime(&prime_num).unwrap();
assert!(is_prime_result);
let composite_num = yuf.parse("15").unwrap();
let is_prime_result = yuf.is_prime(&composite_num).unwrap();
assert!(!is_prime_result);
}
#[test]
fn test_combinatorics() {
let yuf = Yufmath::new();
let n = yuf.parse("5").unwrap();
let k = yuf.parse("2").unwrap();
let binomial_result = yuf.binomial(&n, &k).unwrap();
let perm_result = yuf.permutation(&n, &k).unwrap();
}
#[test]
fn test_complex_operations() {
let yuf = Yufmath::new();
let complex_expr = yuf.parse("3 + 4*i").unwrap();
let conjugate = yuf.complex_conjugate(&complex_expr).unwrap();
let modulus = yuf.complex_modulus(&complex_expr).unwrap();
let argument = yuf.complex_argument(&complex_expr).unwrap();
}
#[test]
fn test_error_handling() {
let yuf = Yufmath::new();
let result = yuf.compute("2 + + 3");
assert!(result.is_err());
let result = yuf.compute("1/0");
let result = yuf.parse("unknown_func(x)");
assert!(result.is_err());
}
#[test]
fn test_default_implementation() {
let yuf1 = Yufmath::new();
let yuf2 = Yufmath::default();
assert_eq!(yuf1.get_config().enable_progress, yuf2.get_config().enable_progress);
assert_eq!(yuf1.get_config().progress_interval_ms, yuf2.get_config().progress_interval_ms);
}
#[test]
fn test_thread_safety() {
let yuf = Yufmath::new();
let result1 = yuf.compute("2 + 3");
let result2 = yuf.compute("4 * 5");
assert!(result1.is_ok());
assert!(result2.is_ok());
}