use std::fs;
use std::path::PathBuf;
use tempfile::TempDir;
#[test]
#[ignore] fn test_predict_quality_basic_prediction() {
let temp_dir = TempDir::new().unwrap();
create_test_metric_data(&temp_dir, "lint", 8);
let binary_path = get_pmat_binary_path();
let output = std::process::Command::new(&binary_path)
.env("PMAT_METRICS_DIR", temp_dir.path())
.args([
"predict-quality",
"--metric",
"lint",
"--threshold",
"30000",
])
.output()
.expect("Failed to run predict-quality");
let stdout = String::from_utf8_lossy(&output.stdout);
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(
output.status.success(),
"Command should succeed. stderr:\n{}\nstdout:\n{}",
stderr,
stdout
);
assert!(
stdout.contains("Quality Metrics Predictions") || stdout.contains("lint"),
"Output should contain prediction results"
);
assert!(
stdout.contains("Breach") || stdout.contains("days"),
"Output should show breach prediction"
);
}
#[test]
#[ignore] fn test_predict_quality_json_output() {
let temp_dir = TempDir::new().unwrap();
create_test_metric_data(&temp_dir, "lint", 8);
let binary_path = get_pmat_binary_path();
let output = std::process::Command::new(&binary_path)
.env("PMAT_METRICS_DIR", temp_dir.path())
.args([
"predict-quality",
"--metric",
"lint",
"--threshold",
"30000",
"--format",
"json",
])
.output()
.expect("Failed to run predict-quality with JSON output");
let stdout = String::from_utf8_lossy(&output.stdout);
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(
output.status.success(),
"Command should succeed. stderr:\n{}\nstdout:\n{}",
stderr,
stdout
);
let predictions: serde_json::Value =
serde_json::from_str(&stdout).expect("Output should be valid JSON");
assert!(predictions.is_array(), "JSON output should be an array");
let first_prediction = &predictions[0];
assert!(
first_prediction.get("metric").is_some(),
"JSON should have 'metric' field"
);
assert!(
first_prediction.get("current_value").is_some(),
"JSON should have 'current_value' field"
);
assert!(
first_prediction.get("threshold").is_some(),
"JSON should have 'threshold' field"
);
assert!(
first_prediction.get("confidence").is_some(),
"JSON should have 'confidence' field"
);
assert!(
first_prediction.get("recommendations").is_some(),
"JSON should have 'recommendations' field"
);
assert!(
first_prediction.get("forecast").is_some(),
"JSON should have 'forecast' field"
);
let forecast = first_prediction["forecast"]
.as_array()
.expect("Forecast should be an array");
assert!(!forecast.is_empty(), "Forecast should have data points");
let first_point = &forecast[0];
assert!(
first_point.get("days_ahead").is_some(),
"Forecast point should have 'days_ahead'"
);
assert!(
first_point.get("predicted_value").is_some(),
"Forecast point should have 'predicted_value'"
);
assert!(
first_point.get("lower_bound").is_some(),
"Forecast point should have 'lower_bound'"
);
assert!(
first_point.get("upper_bound").is_some(),
"Forecast point should have 'upper_bound'"
);
}
#[test]
#[ignore] fn test_predict_quality_all_metrics() {
let temp_dir = TempDir::new().unwrap();
create_test_metric_data(&temp_dir, "lint", 8);
create_test_metric_data(&temp_dir, "test-fast", 8);
let binary_path = get_pmat_binary_path();
let output = std::process::Command::new(&binary_path)
.env("PMAT_METRICS_DIR", temp_dir.path())
.args(["predict-quality", "--all"])
.output()
.expect("Failed to run predict-quality --all");
let stdout = String::from_utf8_lossy(&output.stdout);
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(
output.status.success(),
"Command should succeed. stderr:\n{}\nstdout:\n{}",
stderr,
stdout
);
assert!(
stdout.contains("lint") || stdout.contains("test-fast"),
"Output should contain multiple metrics"
);
}
#[test]
#[ignore] fn test_predict_quality_insufficient_data() {
let temp_dir = TempDir::new().unwrap();
create_test_metric_data(&temp_dir, "lint", 5);
let binary_path = get_pmat_binary_path();
let output = std::process::Command::new(&binary_path)
.env("PMAT_METRICS_DIR", temp_dir.path())
.args([
"predict-quality",
"--metric",
"lint",
"--threshold",
"30000",
])
.output()
.expect("Failed to run predict-quality");
let stdout = String::from_utf8_lossy(&output.stdout);
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(
stderr.contains("at least 7 observations") || stderr.contains("Failed to predict"),
"Should warn about insufficient observations. stderr:\n{}\nstdout:\n{}",
stderr,
stdout
);
}
#[test]
#[ignore] fn test_predict_quality_high_confidence() {
let temp_dir = TempDir::new().unwrap();
create_test_metric_data(&temp_dir, "lint", 10);
let binary_path = get_pmat_binary_path();
let output = std::process::Command::new(&binary_path)
.env("PMAT_METRICS_DIR", temp_dir.path())
.args([
"predict-quality",
"--metric",
"lint",
"--threshold",
"30000",
"--format",
"json",
])
.output()
.expect("Failed to run predict-quality");
let stdout = String::from_utf8_lossy(&output.stdout);
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(
output.status.success(),
"Command should succeed. stderr:\n{}\nstdout:\n{}",
stderr,
stdout
);
let predictions: serde_json::Value =
serde_json::from_str(&stdout).expect("Output should be valid JSON");
let confidence = predictions[0]["confidence"]
.as_f64()
.expect("Confidence should be a number");
assert!(
confidence >= 0.85,
"Confidence should be >= 0.85 (85%) for reliable predictions, got {}",
confidence
);
}
#[test]
#[ignore] fn test_predict_quality_recommendations() {
let temp_dir = TempDir::new().unwrap();
create_test_metric_data(&temp_dir, "lint", 8);
let binary_path = get_pmat_binary_path();
let output = std::process::Command::new(&binary_path)
.env("PMAT_METRICS_DIR", temp_dir.path())
.args([
"predict-quality",
"--metric",
"lint",
"--threshold",
"30000",
"--format",
"json",
])
.output()
.expect("Failed to run predict-quality");
let stdout = String::from_utf8_lossy(&output.stdout);
let predictions: serde_json::Value =
serde_json::from_str(&stdout).expect("Output should be valid JSON");
let recommendations = predictions[0]["recommendations"]
.as_array()
.expect("Recommendations should be an array");
assert!(
!recommendations.is_empty(),
"Should generate recommendations for predicted breach"
);
let recommendations_text = recommendations
.iter()
.map(|r| r.as_str().unwrap())
.collect::<Vec<_>>()
.join(" ");
assert!(
recommendations_text.contains("dependencies")
|| recommendations_text.contains("optimization"),
"Recommendations should contain actionable advice"
);
}
fn create_test_metric_data(temp_dir: &TempDir, metric_name: &str, num_observations: usize) {
let trends_dir = temp_dir.path().join("trends");
fs::create_dir_all(&trends_dir).expect("Failed to create trends directory");
let mut observations = Vec::new();
let base_timestamp = 1761740295i64; let base_value = 20000.0;
for i in 0..num_observations {
let timestamp = base_timestamp + (i as i64 * 5 * 86400); let value = base_value + (i as f64 * 1000.0);
observations.push(serde_json::json!({
"metric": metric_name,
"value": value,
"timestamp": timestamp
}));
}
let metric_file = trends_dir.join(format!("{}.json", metric_name));
fs::write(
&metric_file,
serde_json::to_string_pretty(&observations).unwrap(),
)
.expect("Failed to write metric data");
}
fn get_pmat_binary_path() -> PathBuf {
let workspace_root = std::env::current_dir()
.unwrap()
.parent()
.unwrap()
.to_path_buf();
let binary_path = workspace_root.join("target").join("debug").join("pmat");
if !binary_path.exists() {
std::process::Command::new("cargo")
.current_dir(&workspace_root)
.args(["build", "--bin", "pmat", "-p", "pmat"])
.output()
.expect("Failed to build pmat binary");
}
assert!(
binary_path.exists(),
"pmat binary should exist at {:?}",
binary_path
);
binary_path
}