#![allow(deprecated)]
use assert_cmd::prelude::*;
use predicates::prelude::*;
use std::fs;
use std::path::PathBuf;
use std::process::Command;
fn cli() -> Command {
Command::cargo_bin("tensorlogic").expect("Failed to find tensorlogic binary")
}
fn temp_file(name: &str, content: &str) -> PathBuf {
let path = std::env::temp_dir().join(name);
fs::write(&path, content).expect("Failed to write temp file");
path
}
#[test]
fn test_help_command() {
cli()
.arg("--help")
.assert()
.success()
.stdout(predicate::str::contains(
"TensorLogic command-line interface",
))
.stdout(predicate::str::contains("Usage:"));
}
#[test]
fn test_version_command() {
cli()
.arg("--version")
.assert()
.success()
.stdout(predicate::str::contains("tensorlogic"));
}
#[test]
fn test_simple_predicate_compilation() {
cli()
.arg("knows(x, y)")
.arg("--quiet")
.assert()
.success()
.stdout(predicate::str::contains("tensors"))
.stdout(predicate::str::contains("nodes"));
}
#[test]
fn test_and_expression() {
cli()
.arg("knows(x, y) AND likes(y, z)")
.arg("--quiet")
.assert()
.success();
}
#[test]
fn test_or_expression() {
cli()
.arg("person(x) OR robot(x)")
.arg("--quiet")
.assert()
.success();
}
#[test]
fn test_not_expression() {
cli().arg("NOT mortal(x)").arg("--quiet").assert().success();
}
#[test]
fn test_exists_quantifier() {
cli()
.arg("EXISTS x IN Person. knows(x, alice)")
.arg("--domains")
.arg("Person:100")
.arg("--quiet")
.assert()
.success();
}
#[test]
fn test_forall_quantifier() {
cli()
.arg("FORALL x IN Person. mortal(x)")
.arg("--domains")
.arg("Person:100")
.arg("--quiet")
.assert()
.success();
}
#[test]
fn test_implication() {
cli()
.arg("knows(x, y) -> likes(x, y)")
.arg("--quiet")
.assert()
.success();
}
#[test]
fn test_arithmetic_expression() {
cli().arg("age(x) + 10").arg("--quiet").assert().success();
}
#[test]
fn test_comparison_expression() {
cli().arg("age(x) > 18").arg("--quiet").assert().success();
}
#[test]
fn test_conditional_expression() {
cli()
.arg("IF age(x) >= 18 THEN adult(x) ELSE child(x)")
.arg("--quiet")
.assert()
.success();
}
#[test]
fn test_json_output_format() {
cli()
.arg("knows(x, y)")
.arg("--output-format")
.arg("json")
.assert()
.success()
.stdout(predicate::str::contains("tensors"))
.stdout(predicate::str::contains("nodes"));
}
#[test]
fn test_dot_output_format() {
cli()
.arg("knows(x, y) AND likes(y, z)")
.arg("--output-format")
.arg("dot")
.assert()
.success()
.stdout(predicate::str::contains("digraph"));
}
#[test]
fn test_stats_output_format() {
cli()
.arg("knows(x, y)")
.arg("--output-format")
.arg("stats")
.assert()
.success()
.stdout(predicate::str::contains("Graph Statistics"))
.stdout(predicate::str::contains("Tensors:"))
.stdout(predicate::str::contains("Nodes:"));
}
#[test]
fn test_validation_flag() {
cli()
.arg("knows(x, y) AND likes(y, z)")
.arg("--validate")
.arg("--quiet")
.assert()
.success();
}
#[test]
fn test_analyze_flag() {
cli()
.arg("knows(x, y) AND likes(y, z)")
.arg("--analyze")
.assert()
.success()
.stdout(predicate::str::contains("Tensors:").or(predicate::str::contains("tensors")));
}
#[test]
fn test_debug_flag() {
cli()
.arg("knows(x, y)")
.arg("--debug")
.arg("--quiet")
.assert()
.success();
}
#[test]
fn test_multiple_domains() {
cli()
.arg("lives_in(p, c)")
.arg("--domains")
.arg("Person:100")
.arg("--domains")
.arg("City:50")
.arg("--quiet")
.assert()
.success();
}
#[test]
fn test_soft_differentiable_strategy() {
cli()
.arg("p AND q")
.arg("--strategy")
.arg("soft_differentiable")
.arg("--quiet")
.assert()
.success();
}
#[test]
fn test_hard_boolean_strategy() {
cli()
.arg("p AND q")
.arg("--strategy")
.arg("hard_boolean")
.arg("--quiet")
.assert()
.success();
}
#[test]
fn test_fuzzy_godel_strategy() {
cli()
.arg("p AND q")
.arg("--strategy")
.arg("fuzzy_godel")
.arg("--quiet")
.assert()
.success();
}
#[test]
fn test_fuzzy_product_strategy() {
cli()
.arg("p AND q")
.arg("--strategy")
.arg("fuzzy_product")
.arg("--quiet")
.assert()
.success();
}
#[test]
fn test_fuzzy_lukasiewicz_strategy() {
cli()
.arg("p AND q")
.arg("--strategy")
.arg("fuzzy_lukasiewicz")
.arg("--quiet")
.assert()
.success();
}
#[test]
fn test_probabilistic_strategy() {
cli()
.arg("p AND q")
.arg("--strategy")
.arg("probabilistic")
.arg("--quiet")
.assert()
.success();
}
#[test]
fn test_output_to_file() {
let output_file = temp_file("test_output.txt", "");
cli()
.arg("knows(x, y)")
.arg("--output")
.arg(&output_file)
.arg("--quiet")
.assert()
.success();
let content = fs::read_to_string(&output_file).unwrap();
assert!(content.contains("tensors") || content.contains("EinsumGraph"));
fs::remove_file(output_file).ok();
}
#[test]
fn test_json_input_format() {
let json_content = r#"{"Pred":{"name":"test","args":[{"Var":"x"}]}}"#;
let json_file = temp_file("test_input.json", json_content);
cli()
.arg(&json_file)
.arg("--input-format")
.arg("json")
.arg("--quiet")
.assert()
.success();
fs::remove_file(json_file).ok();
}
#[test]
fn test_complex_nested_expression() {
cli()
.arg("(knows(x, y) AND likes(y, z)) OR (friend(x, z) AND NOT enemy(x, z))")
.arg("--quiet")
.assert()
.success();
}
#[test]
fn test_completion_command() {
cli()
.arg("completion")
.arg("bash")
.assert()
.success()
.stdout(predicate::str::contains("_tensorlogic"));
}
#[test]
fn test_backends_command() {
cli()
.arg("backends")
.assert()
.success()
.stdout(predicate::str::contains("Available Backends"));
}
#[test]
fn test_config_show_command() {
cli()
.arg("config")
.arg("show")
.assert()
.success()
.stdout(predicate::str::contains("strategy"));
}
#[test]
fn test_config_path_command() {
cli()
.arg("config")
.arg("path")
.assert()
.success()
.stdout(predicate::str::contains(".tensorlogicrc"));
}
#[test]
fn test_cache_path_command() {
cli().arg("cache").arg("path").assert().success();
}
#[test]
fn test_no_color_flag() {
cli()
.arg("knows(x, y)")
.arg("--no-color")
.arg("--quiet")
.assert()
.success();
}
#[test]
fn test_no_config_flag() {
cli()
.arg("knows(x, y)")
.arg("--no-config")
.arg("--quiet")
.assert()
.success();
}
#[test]
fn test_batch_mode_with_file() {
let batch_content = "knows(x, y)\nlikes(y, z)\n# Comment\nperson(x)";
let batch_file = temp_file("test_batch.txt", batch_content);
cli()
.arg("batch")
.arg(&batch_file)
.assert()
.success()
.stdout(predicate::str::contains("Processing"));
fs::remove_file(batch_file).ok();
}
#[test]
fn test_convert_command() {
let expr_file = temp_file("test_expr.txt", "knows(x, y)");
let output_file = temp_file("test_convert_output.json", "");
cli()
.arg("convert")
.arg(&expr_file)
.arg("--from")
.arg("expr")
.arg("--to")
.arg("json")
.arg("--output")
.arg(&output_file)
.assert()
.success();
let content = fs::read_to_string(&output_file).unwrap();
assert!(content.contains("Pred"));
fs::remove_file(expr_file).ok();
fs::remove_file(output_file).ok();
}
#[test]
fn test_invalid_expression_fails() {
cli()
.arg("") .arg("--no-color")
.assert()
.failure();
}
#[test]
fn test_invalid_strategy_fails() {
cli()
.arg("knows(x, y)")
.arg("--strategy")
.arg("nonexistent_strategy")
.assert()
.failure();
}
#[test]
fn test_missing_input_fails() {
cli().assert().failure();
}
#[test]
#[ignore] fn test_unicode_operators() {
cli().arg("p(x) ∧ q(y)").arg("--quiet").assert().success();
}
#[test]
#[ignore] fn test_unicode_quantifiers() {
cli()
.arg("∃ x IN Person. knows(x, bob)")
.arg("--domains")
.arg("Person:100")
.arg("--quiet")
.assert()
.success();
}
#[test]
fn test_parentheses_grouping() {
cli()
.arg("(p AND q) OR (r AND s)")
.arg("--quiet")
.assert()
.success();
}
#[test]
fn test_deeply_nested_expression() {
cli()
.arg("((((a AND b) OR c) AND d) OR e)")
.arg("--quiet")
.assert()
.success();
}
#[test]
fn test_multi_arity_predicates() {
cli()
.arg("rel(a, b, c, d, e)")
.arg("--quiet")
.assert()
.success();
}
#[test]
fn test_optimize_command() {
cli()
.arg("optimize")
.arg("knows(x, y) AND likes(y, z)")
.arg("--input-format")
.arg("expr")
.arg("--level")
.arg("aggressive")
.assert()
.success();
}
#[test]
fn test_benchmark_command() {
cli()
.arg("benchmark")
.arg("knows(x, y)")
.arg("--input-format")
.arg("expr")
.arg("--iterations")
.arg("5")
.assert()
.success()
.stdout(predicate::str::contains("Compilation"));
}
#[test]
fn test_profile_command() {
cli()
.arg("profile")
.arg("knows(x, y) AND likes(y, z)")
.arg("--input-format")
.arg("expr")
.arg("--warmup")
.arg("2")
.arg("--runs")
.arg("5")
.assert()
.success()
.stdout(predicate::str::contains("Profile"));
}
#[test]
#[ignore] fn test_execute_command_scirs2() {
cli()
.arg("execute")
.arg("knows(x, y) AND likes(y, z)")
.arg("--input-format")
.arg("expr")
.arg("--backend")
.arg("scirs2-cpu")
.assert()
.code(predicate::in_iter([0, 1])); }
#[test]
fn test_cache_stats_command() {
cli().arg("cache").arg("stats").assert().success();
}