use serial_test::serial;
use std::process::Command;
fn run_csd_rs(args: &[&str]) -> (String, String, i32) {
let output = Command::new("cargo")
.args(["run", "--bin", "csd-rs", "--"])
.args(args)
.output()
.expect("Failed to execute command");
let stdout = String::from_utf8_lossy(&output.stdout).to_string();
let stderr = String::from_utf8_lossy(&output.stderr).to_string();
let exit_code = output.status.code().unwrap_or(-1);
let stderr = stderr
.lines()
.filter(|line| {
!line.contains("Finished")
&& !line.contains("Compiling")
&& !line.contains("Running")
&& !line.trim().is_empty()
})
.collect::<Vec<_>>()
.join("\n");
(stdout, stderr, exit_code)
}
#[test]
#[serial]
fn test_cli_help() {
let (stdout, _stderr, _exit_code) = run_csd_rs(&[]);
assert!(stdout.contains("Usage: csd-rs"));
assert!(stdout.contains("to_csd"));
assert!(stdout.contains("to_csdnnz"));
assert!(stdout.contains("to_decimal"));
}
#[test]
#[serial]
fn test_cli_to_csd_basic() {
let (stdout, stderr, _exit_code) = run_csd_rs(&["to_csd", "28.5", "2"]);
assert!(stdout.contains("+00-00"));
assert_eq!(stderr.trim(), "");
}
#[test]
#[serial]
fn test_cli_to_csd_default_places() {
let (stdout, stderr, _exit_code) = run_csd_rs(&["to_csd", "28.5"]);
assert!(stdout.contains("+00-00"));
assert_eq!(stderr.trim(), "");
}
#[test]
#[serial]
fn test_cli_to_csd_zero() {
let (stdout, stderr, _exit_code) = run_csd_rs(&["to_csd", "0", "2"]);
assert!(stdout.contains("0.00"));
assert_eq!(stderr.trim(), "");
}
#[test]
#[serial]
fn test_cli_to_csd_negative() {
let (stdout, stderr, _exit_code) = run_csd_rs(&["to_csd", "-28.5", "2"]);
assert!(stdout.starts_with('-'));
assert_eq!(stderr.trim(), "");
}
#[test]
#[serial]
fn test_cli_to_csd_invalid_value() {
let (_stdout, stderr, _exit_code) = run_csd_rs(&["to_csd", "invalid"]);
assert!(stderr.contains("Error parsing value"));
}
#[test]
#[serial]
fn test_cli_to_csd_missing_value() {
let (_stdout, stderr, _exit_code) = run_csd_rs(&["to_csd"]);
assert!(stderr.contains("to_csd requires a value"));
}
#[test]
#[serial]
fn test_cli_to_csdnnz_basic() {
let (stdout, stderr, _exit_code) = run_csd_rs(&["to_csdnnz", "28.5", "4"]);
assert!(stdout.contains("+00-00"));
assert_eq!(stderr.trim(), "");
}
#[test]
#[serial]
fn test_cli_to_csdnnz_default_nnz() {
let (stdout, stderr, _exit_code) = run_csd_rs(&["to_csdnnz", "28.5"]);
assert!(stdout.contains("+00-00"));
assert_eq!(stderr.trim(), "");
}
#[test]
#[serial]
fn test_cli_to_csdnnz_zero() {
let (stdout, stderr, _exit_code) = run_csd_rs(&["to_csdnnz", "0", "4"]);
assert_eq!(stdout.trim(), "0");
assert_eq!(stderr.trim(), "");
}
#[test]
#[serial]
fn test_cli_to_csdnnz_invalid_value() {
let (_stdout, stderr, _exit_code) = run_csd_rs(&["to_csdnnz", "invalid"]);
assert!(stderr.contains("Error parsing value"));
}
#[test]
#[serial]
fn test_cli_to_csdnnz_missing_value() {
let (_stdout, stderr, _exit_code) = run_csd_rs(&["to_csdnnz"]);
assert!(stderr.contains("to_csdnnz requires a value"));
}
#[test]
#[serial]
fn test_cli_to_decimal_basic() {
let (stdout, stderr, _exit_code) = run_csd_rs(&["to_decimal", "+00-00.+"]);
assert_eq!(stdout.trim(), "28.5");
assert_eq!(stderr.trim(), "");
}
#[test]
#[serial]
fn test_cli_to_decimal_integer() {
let (stdout, stderr, _exit_code) = run_csd_rs(&["to_decimal", "+00-00"]);
assert_eq!(stdout.trim(), "28");
assert_eq!(stderr.trim(), "");
}
#[test]
#[serial]
fn test_cli_to_decimal_zero() {
let (stdout, stderr, _exit_code) = run_csd_rs(&["to_decimal", "0"]);
assert_eq!(stdout.trim(), "0");
assert_eq!(stderr.trim(), "");
}
#[test]
#[serial]
fn test_cli_to_decimal_negative() {
let (stdout, stderr, _exit_code) = run_csd_rs(&["to_decimal", "-00+00"]);
assert!(stdout.trim().starts_with('-'));
assert_eq!(stderr.trim(), "");
}
#[test]
#[serial]
fn test_cli_to_decimal_missing_csd() {
let (_stdout, stderr, _exit_code) = run_csd_rs(&["to_decimal"]);
assert!(stderr.contains("to_decimal requires a CSD string"));
}
#[test]
#[serial]
fn test_cli_to_decimal_invalid_csd() {
let (stdout, _stderr, _exit_code) = run_csd_rs(&["to_decimal", "invalid"]);
assert!(!stdout.is_empty() || stdout.is_empty()); }
#[test]
#[serial]
fn test_cli_unknown_command() {
let (_stdout, stderr, _exit_code) = run_csd_rs(&["unknown_command"]);
assert!(stderr.contains("Unknown command"));
}
#[test]
#[serial]
fn test_cli_roundtrip_to_csd_to_decimal() {
let (csd_output, _, _) = run_csd_rs(&["to_csd", "42.5", "4"]);
let csd = csd_output.trim();
let (decimal_output, _, _) = run_csd_rs(&["to_decimal", csd]);
let decimal: f64 = decimal_output.trim().parse().unwrap();
assert!((decimal - 42.5).abs() < 0.1); }
#[test]
#[serial]
fn test_cli_roundtrip_to_decimal_to_csd() {
let (decimal_output, _, _) = run_csd_rs(&["to_decimal", "+00-00.+"]);
let decimal: f64 = decimal_output.trim().parse().unwrap();
let (csd_output, _, _) = run_csd_rs(&["to_csd", &decimal.to_string(), "2"]);
assert!(csd_output.contains("+00-00"));
}
#[test]
#[serial]
fn test_cli_to_csdnnz_limits() {
let (stdout, stderr, _) = run_csd_rs(&["to_csdnnz", "28.5", "1"]);
let nnz_count = stdout.chars().filter(|c| *c == '+' || *c == '-').count();
assert!(nnz_count <= 1);
assert_eq!(stderr.trim(), "");
}
#[test]
#[serial]
fn test_cli_to_csd_with_various_places() {
let (stdout1, _, _) = run_csd_rs(&["to_csd", "28.5", "1"]);
let (stdout2, _, _) = run_csd_rs(&["to_csd", "28.5", "4"]);
let (stdout3, _, _) = run_csd_rs(&["to_csd", "28.5", "8"]);
assert!(stdout1.contains("+00-00"));
assert!(stdout2.contains("+00-00"));
assert!(stdout3.contains("+00-00"));
}
#[test]
#[serial]
fn test_cli_to_csd_large_number() {
let (stdout, stderr, _) = run_csd_rs(&["to_csd", "1000000", "2"]);
assert!(!stdout.trim().is_empty());
assert_eq!(stderr.trim(), "");
}
#[test]
#[serial]
fn test_cli_to_csd_small_fraction() {
let (stdout, stderr, _) = run_csd_rs(&["to_csd", "0.0625", "8"]);
assert!(!stdout.trim().is_empty());
assert_eq!(stderr.trim(), "");
}