#![allow(deprecated)]
use assert_cmd::Command;
use predicates::prelude::*;
use serde_json::Value;
use std::fs;
use std::time::Instant;
use tempfile::TempDir;
#[test]
#[ignore] fn test_generate_makefile_e2e() {
let temp_dir = TempDir::new().unwrap();
let mut cmd = Command::cargo_bin("pmat").unwrap();
cmd.current_dir(&temp_dir)
.args([
"generate",
"makefile",
"rust/cli",
"-p",
"project_name=integration_test",
"-p",
"has_tests=true",
"-p",
"has_benchmarks=false",
"-o",
"generated/Makefile",
"--create-dirs",
])
.assert()
.success();
let makefile_path = temp_dir.path().join("generated/Makefile");
assert!(makefile_path.exists());
let content = fs::read_to_string(makefile_path).unwrap();
assert!(content.contains("integration_test"));
assert!(content.contains("cargo build --release"));
assert!(content.contains("cargo test"));
assert!(!content.contains("cargo bench")); }
#[test]
#[ignore] fn test_generate_missing_required_params() {
let mut cmd = Command::cargo_bin("pmat").unwrap();
cmd.args(["generate", "makefile", "rust/cli"])
.assert()
.failure()
.stderr(predicate::str::contains("required parameter missing"));
}
#[test]
#[ignore] fn test_generate_invalid_template_uri() {
let mut cmd = Command::cargo_bin("pmat").unwrap();
cmd.args(["generate", "invalid", "category", "-p", "project_name=test"])
.assert()
.failure()
.code(1);
}
#[test]
#[ignore] fn test_generate_to_stdout() {
let mut cmd = Command::cargo_bin("pmat").unwrap();
cmd.args([
"generate",
"readme",
"deno/cli",
"-p",
"project_name=stdout_test",
"-p",
"description=Test output to stdout",
])
.assert()
.success()
.stdout(predicate::str::contains("# stdout_test"))
.stdout(predicate::str::contains("Test output to stdout"));
}
#[test]
#[ignore = "CLI integration test - requires binary"]
fn test_scaffold_parallel_generation() {
let temp_dir = TempDir::new().unwrap();
let start = Instant::now();
let mut cmd = Command::cargo_bin("pmat").unwrap();
cmd.current_dir(&temp_dir)
.args([
"scaffold",
"project",
"rust",
"--templates",
"makefile,readme,gitignore",
"-p",
"project_name=perf_test",
"-p",
"description=Performance test project",
"--parallel",
"4",
])
.assert()
.success();
let duration = start.elapsed();
assert!(
duration.as_millis() < 1000,
"Scaffold took {}ms",
duration.as_millis()
);
assert!(temp_dir.path().join("perf_test/Makefile").exists());
assert!(temp_dir.path().join("perf_test/README.md").exists());
assert!(temp_dir.path().join("perf_test/.gitignore").exists());
}
#[test]
#[ignore] fn test_list_json_output_schema() {
let mut cmd = Command::cargo_bin("pmat").unwrap();
let output = cmd.args(["list", "--format", "json"]).output().unwrap();
assert!(output.status.success());
let templates: Vec<Value> = serde_json::from_slice(&output.stdout).unwrap();
for template in &templates {
assert!(!template["uri"].as_str().unwrap().is_empty());
assert!(!template["name"].as_str().unwrap().is_empty());
assert!(!template["description"].as_str().unwrap().is_empty());
assert!(template["toolchain"].is_object());
if let Some(parameters) = template["parameters"].as_array() {
for param in parameters {
assert!(!param["name"].as_str().unwrap().is_empty());
assert!(param["param_type"].is_string());
}
}
}
assert!(templates.len() >= 9);
}
#[test]
#[ignore] fn test_list_table_output() {
let mut cmd = Command::cargo_bin("pmat").unwrap();
cmd.args(["list", "--format", "table"])
.assert()
.success()
.stdout(predicate::str::contains("Name"))
.stdout(predicate::str::contains("Toolchain"))
.stdout(predicate::str::contains("Category"));
}
#[test]
#[ignore] fn test_list_yaml_output() {
let mut cmd = Command::cargo_bin("pmat").unwrap();
cmd.args(["list", "--format", "yaml"])
.assert()
.success()
.stdout(predicate::str::contains("uri:"))
.stdout(predicate::str::contains("name:"))
.stdout(predicate::str::contains("toolchain:"));
}
#[test]
#[ignore] fn test_list_filtered_by_toolchain() {
let mut cmd = Command::cargo_bin("pmat").unwrap();
let output = cmd
.args(["list", "--toolchain", "rust", "--format", "json"])
.output()
.unwrap();
assert!(output.status.success());
let templates: Vec<Value> = serde_json::from_slice(&output.stdout).unwrap();
for template in &templates {
assert_eq!(template["toolchain"]["type"], "rust");
}
}
#[test]
#[ignore] fn test_list_filtered_by_category() {
let mut cmd = Command::cargo_bin("pmat").unwrap();
let output = cmd
.args(["list", "--category", "makefile", "--format", "json"])
.output()
.unwrap();
assert!(output.status.success());
let templates: Vec<Value> = serde_json::from_slice(&output.stdout).unwrap();
for template in &templates {
assert_eq!(template["category"], "makefile");
}
}
#[test]
#[ignore] fn test_search_basic() {
let mut cmd = Command::cargo_bin("pmat").unwrap();
cmd.args(["search", "rust"])
.assert()
.success()
.stdout(predicate::str::contains("rust"));
}
#[test]
#[ignore] fn test_search_with_limit() {
let mut cmd = Command::cargo_bin("pmat").unwrap();
cmd.args(["search", "cli", "--limit", "5"])
.assert()
.success();
}
#[test]
#[ignore] fn test_search_with_toolchain_filter() {
let mut cmd = Command::cargo_bin("pmat").unwrap();
cmd.args(["search", "makefile", "--toolchain", "deno"])
.assert()
.success();
}
#[test]
#[ignore] fn test_validate_success() {
let mut cmd = Command::cargo_bin("pmat").unwrap();
cmd.args([
"validate",
"template://makefile/rust/cli",
"-p",
"project_name=valid_project",
])
.assert()
.success()
.stderr(predicate::str::contains("All parameters valid"));
}
#[test]
#[ignore] fn test_validate_missing_required() {
let mut cmd = Command::cargo_bin("pmat").unwrap();
cmd.args(["validate", "template://makefile/rust/cli"])
.assert()
.failure() .stderr(predicate::str::contains("Required parameter missing"));
}
#[test]
#[ignore] fn test_context_generation_rust() {
let temp_dir = TempDir::new().unwrap();
fs::write(
temp_dir.path().join("main.rs"),
r#"
fn main() {
println!("Hello, world!");
}
fn helper() -> i32 {
42
}
"#,
)
.unwrap();
let mut cmd = Command::cargo_bin("pmat").unwrap();
cmd.current_dir(&temp_dir)
.args(["context", "--toolchain", "rust", "--format", "json"])
.assert()
.success();
}
#[test]
#[ignore] fn test_context_markdown_output() {
let temp_dir = TempDir::new().unwrap();
fs::write(
temp_dir.path().join("example.py"),
r#"
def hello():
print("Hello, world!")
class Calculator:
def add(self, a, b):
return a + b
"#,
)
.unwrap();
let mut cmd = Command::cargo_bin("pmat").unwrap();
cmd.current_dir(&temp_dir)
.args([
"context",
"--toolchain",
"python-uv",
"--format",
"markdown",
])
.assert()
.success()
.stdout(predicate::str::contains("# Project Context"))
.stdout(predicate::str::contains("## Project Structure"));
}
#[test]
#[ignore] fn test_analyze_churn_json_output() {
let mut cmd = Command::cargo_bin("pmat").unwrap();
let result = cmd
.args(["analyze", "churn", "--format", "json", "--days", "7"])
.output();
if let Ok(output) = result {
if output.status.success() {
let json: Value = serde_json::from_slice(&output.stdout).unwrap();
assert!(json.is_object());
assert!(json["period_days"].is_number());
assert!(json["files"].is_array());
}
}
}
#[test]
#[ignore] fn test_analyze_churn_csv_output() {
let mut cmd = Command::cargo_bin("pmat").unwrap();
let result = cmd
.args(["analyze", "churn", "--format", "csv", "--days", "30"])
.output();
if let Ok(output) = result {
if output.status.success() {
let csv = String::from_utf8_lossy(&output.stdout);
assert!(csv.contains("file_path,relative_path,commit_count,unique_authors,additions,deletions,churn_score"));
}
}
}
#[test]
#[ignore] fn test_analyze_complexity_summary() {
let temp_dir = TempDir::new().unwrap();
fs::write(
temp_dir.path().join("complex.rs"),
r"
fn complex_function(x: i32, y: i32) -> i32 {
if x > 0 {
if y > 0 {
return x + y;
} else {
return x - y;
}
}
match x {
0 => 0,
1..=10 => x * 2,
_ => x * 3,
}
}
",
)
.unwrap();
let mut cmd = Command::cargo_bin("pmat").unwrap();
cmd.current_dir(&temp_dir)
.args(["analyze", "complexity", "--format", "summary"])
.assert()
.success()
.stdout(predicate::str::contains("Complexity Analysis"));
}
#[test]
#[ignore] fn test_analyze_complexity_sarif_format() {
let temp_dir = TempDir::new().unwrap();
fs::write(
temp_dir.path().join("test.ts"),
r"
function complexFunction(x: number): number {
if (x > 0) {
if (x > 10) {
return x * 2;
}
return x + 1;
}
return 0;
}
",
)
.unwrap();
let mut cmd = Command::cargo_bin("pmat").unwrap();
let output = cmd
.current_dir(&temp_dir)
.args([
"analyze",
"complexity",
"--format",
"sarif",
"--max-cyclomatic",
"10",
])
.output()
.unwrap();
if output.status.success() {
let sarif: Value = serde_json::from_slice(&output.stdout).unwrap();
assert_eq!(sarif["version"], "2.1.0");
assert_eq!(
sarif["$schema"],
"https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json"
);
let runs = sarif["runs"].as_array().unwrap();
assert_eq!(runs.len(), 1);
let tool = &runs[0]["tool"]["driver"];
assert_eq!(tool["name"], "pmat");
}
}
#[test]
#[ignore] fn test_analyze_dag_mermaid_output() {
let temp_dir = TempDir::new().unwrap();
fs::write(
temp_dir.path().join("main.rs"),
r"
mod helpers;
fn main() {
helpers::greet();
process_data(42);
}
fn process_data(x: i32) -> i32 {
helpers::calculate(x)
}
",
)
.unwrap();
fs::write(
temp_dir.path().join("helpers.rs"),
r#"
pub fn greet() {
println!("Hello!");
}
pub fn calculate(x: i32) -> i32 {
x * 2
}
"#,
)
.unwrap();
let output_file = temp_dir.path().join("dag.mmd");
let mut cmd = Command::cargo_bin("pmat").unwrap();
cmd.current_dir(&temp_dir)
.args([
"analyze",
"dag",
"--dag-type",
"call-graph",
"-o",
output_file.to_str().unwrap(),
"--show-complexity",
])
.assert()
.success();
assert!(output_file.exists());
let mermaid_content = fs::read_to_string(output_file).unwrap();
assert!(mermaid_content.contains("graph"));
}
#[test]
#[ignore] fn test_error_propagation_and_codes() {
struct ErrorCase {
args: Vec<&'static str>,
expected_message: &'static str,
}
let cases = vec![
ErrorCase {
args: vec!["generate", "nonexistent", "template"],
expected_message: "Invalid template URI",
},
];
for case in cases {
let mut cmd = Command::cargo_bin("pmat").unwrap();
cmd.args(&case.args)
.assert()
.failure()
.stderr(predicate::str::contains(case.expected_message));
}
}
#[test]
#[ignore] fn test_help_output() {
let mut cmd = Command::cargo_bin("pmat").unwrap();
cmd.arg("--help")
.assert()
.success()
.stdout(predicate::str::contains(
"Professional project quantitative scaffolding and analysis toolkit",
))
.stdout(predicate::str::contains("Commands:"));
}
#[test]
#[ignore] fn test_version_output() {
let mut cmd = Command::cargo_bin("pmat").unwrap();
cmd.arg("--version")
.assert()
.success()
.stdout(predicate::str::is_match(r"pmat \d+\.\d+\.\d+").unwrap());
}
#[test]
#[ignore] fn test_subcommand_help() {
let subcommands = vec![
"generate", "scaffold", "list", "search", "validate", "context",
];
for subcmd in subcommands {
let mut cmd = Command::cargo_bin("pmat").unwrap();
cmd.args([subcmd, "--help"])
.assert()
.success()
.stdout(predicate::str::contains("Usage:"));
}
}
#[test]
#[ignore] fn test_analyze_subcommand_help() {
let mut cmd = Command::cargo_bin("pmat").unwrap();
cmd.args(["analyze", "--help"])
.assert()
.success()
.stdout(predicate::str::contains("churn"))
.stdout(predicate::str::contains("complexity"))
.stdout(predicate::str::contains("dag"));
}
#[test]
#[ignore] fn test_environment_variable_expansion() {
std::env::set_var("TEST_PROJECT_NAME", "env-test-project");
let temp_dir = TempDir::new().unwrap();
let mut cmd = Command::cargo_bin("pmat").unwrap();
cmd.current_dir(&temp_dir)
.args([
"generate",
"readme",
"rust/cli",
"-p",
"project_name=${TEST_PROJECT_NAME}",
"-p",
"description=Test project description",
"-o",
"README.md",
])
.assert()
.success();
let content = fs::read_to_string(temp_dir.path().join("README.md")).unwrap();
assert!(content.contains("${TEST_PROJECT_NAME}"));
std::env::remove_var("TEST_PROJECT_NAME");
}
#[test]
#[ignore] fn test_mode_flag_cli() {
let mut cmd = Command::cargo_bin("pmat").unwrap();
cmd.args(["--mode", "cli", "list"])
.assert()
.success()
.stdout(predicate::str::contains("Name"));
}