use super::*;
mod property_tests {
use proptest::prelude::*;
proptest! {
#[test]
fn basic_property_stability(_input in ".*") {
prop_assert!(true);
}
#[test]
fn module_consistency_check(_x in 0u32..1000) {
prop_assert!(_x < 1001);
}
}
}
mod unit_tests {
use super::*;
use crate::tdg::Grade;
use std::path::{Path, PathBuf};
fn make_test_config(path: PathBuf) -> TdgCommandConfig {
TdgCommandConfig {
path,
command: None,
format: TdgOutputFormat::Table,
config: None,
quiet: false,
include_components: false,
min_grade: None,
output: None,
with_git_context: false,
explain: false,
threshold: 10,
baseline: None,
viz: false,
viz_theme: "default".to_string(),
}
}
fn make_test_score(total: f32, grade: Grade) -> crate::tdg::TdgScore {
crate::tdg::TdgScore {
total,
grade,
confidence: 0.95,
language: crate::tdg::Language::Rust,
structural_complexity: 20.0,
semantic_complexity: 15.0,
duplication_ratio: 5.0,
coupling_score: 10.0,
doc_coverage: 8.0,
consistency_score: 7.0,
entropy_score: 20.0,
file_path: None,
penalties_applied: vec![],
critical_defects_count: 0,
has_critical_defects: false,
has_contract_coverage: false,
}
}
mod format_grade_tests {
use super::*;
#[test]
fn test_format_grade_a_plus() {
assert_eq!(format_grade(Grade::APLus), "A+");
}
#[test]
fn test_format_grade_a() {
assert_eq!(format_grade(Grade::A), "A");
}
#[test]
fn test_format_grade_a_minus() {
assert_eq!(format_grade(Grade::AMinus), "A-");
}
#[test]
fn test_format_grade_b_plus() {
assert_eq!(format_grade(Grade::BPlus), "B+");
}
#[test]
fn test_format_grade_b() {
assert_eq!(format_grade(Grade::B), "B");
}
#[test]
fn test_format_grade_b_minus() {
assert_eq!(format_grade(Grade::BMinus), "B-");
}
#[test]
fn test_format_grade_c_plus() {
assert_eq!(format_grade(Grade::CPlus), "C+");
}
#[test]
fn test_format_grade_c() {
assert_eq!(format_grade(Grade::C), "C");
}
#[test]
fn test_format_grade_c_minus() {
assert_eq!(format_grade(Grade::CMinus), "C-");
}
#[test]
fn test_format_grade_d() {
assert_eq!(format_grade(Grade::D), "D");
}
#[test]
fn test_format_grade_f() {
assert_eq!(format_grade(Grade::F), "F");
}
#[test]
fn test_format_grade_all_grades_return_non_empty() {
let grades = [
Grade::APLus,
Grade::A,
Grade::AMinus,
Grade::BPlus,
Grade::B,
Grade::BMinus,
Grade::CPlus,
Grade::C,
Grade::CMinus,
Grade::D,
Grade::F,
];
for grade in grades {
let formatted = format_grade(grade);
assert!(
!formatted.is_empty(),
"Grade {:?} formatted to empty string",
grade
);
assert!(
formatted.len() <= 2,
"Grade {:?} formatted to {} (too long)",
grade,
formatted
);
}
}
}
mod parse_grade_tests {
use super::*;
#[test]
fn test_parse_grade_a_plus() {
assert_eq!(parse_grade("A+").unwrap(), Grade::APLus);
}
#[test]
fn test_parse_grade_a() {
assert_eq!(parse_grade("A").unwrap(), Grade::A);
}
#[test]
fn test_parse_grade_a_minus() {
assert_eq!(parse_grade("A-").unwrap(), Grade::AMinus);
}
#[test]
fn test_parse_grade_b_plus() {
assert_eq!(parse_grade("B+").unwrap(), Grade::BPlus);
}
#[test]
fn test_parse_grade_b() {
assert_eq!(parse_grade("B").unwrap(), Grade::B);
}
#[test]
fn test_parse_grade_b_minus() {
assert_eq!(parse_grade("B-").unwrap(), Grade::BMinus);
}
#[test]
fn test_parse_grade_c_plus() {
assert_eq!(parse_grade("C+").unwrap(), Grade::CPlus);
}
#[test]
fn test_parse_grade_c() {
assert_eq!(parse_grade("C").unwrap(), Grade::C);
}
#[test]
fn test_parse_grade_c_minus() {
assert_eq!(parse_grade("C-").unwrap(), Grade::CMinus);
}
#[test]
fn test_parse_grade_d() {
assert_eq!(parse_grade("D").unwrap(), Grade::D);
}
#[test]
fn test_parse_grade_f() {
assert_eq!(parse_grade("F").unwrap(), Grade::F);
}
#[test]
fn test_parse_grade_lowercase() {
assert_eq!(parse_grade("a+").unwrap(), Grade::APLus);
assert_eq!(parse_grade("b").unwrap(), Grade::B);
assert_eq!(parse_grade("c-").unwrap(), Grade::CMinus);
assert_eq!(parse_grade("f").unwrap(), Grade::F);
}
#[test]
fn test_parse_grade_mixed_case() {
assert_eq!(parse_grade("a+").unwrap(), Grade::APLus);
assert_eq!(parse_grade("A+").unwrap(), Grade::APLus);
}
#[test]
fn test_parse_grade_invalid() {
let err = parse_grade("X").err().unwrap();
assert!(err.to_string().contains("Invalid grade"));
}
#[test]
fn test_parse_grade_empty() {
let err = parse_grade("").err().unwrap();
assert!(err.to_string().contains("Invalid grade"));
}
#[test]
fn test_parse_grade_whitespace() {
let err = parse_grade(" A").err().unwrap();
assert!(err.to_string().contains("Invalid grade"));
}
#[test]
fn test_parse_format_roundtrip() {
let grades = [
Grade::APLus,
Grade::A,
Grade::AMinus,
Grade::BPlus,
Grade::B,
Grade::BMinus,
Grade::CPlus,
Grade::C,
Grade::CMinus,
Grade::D,
Grade::F,
];
for grade in grades {
let formatted = format_grade(grade);
let parsed = parse_grade(&formatted).unwrap();
assert_eq!(grade, parsed, "Roundtrip failed for {:?}", grade);
}
}
}
mod is_analyzable_file_tests {
use super::*;
#[test]
fn test_rust_file() {
assert!(is_analyzable_file(Path::new("test.rs")));
}
#[test]
fn test_python_file() {
assert!(is_analyzable_file(Path::new("test.py")));
}
#[test]
fn test_javascript_file() {
assert!(is_analyzable_file(Path::new("test.js")));
}
#[test]
fn test_typescript_files() {
assert!(is_analyzable_file(Path::new("test.ts")));
assert!(is_analyzable_file(Path::new("component.tsx")));
}
#[test]
fn test_jsx_file() {
assert!(is_analyzable_file(Path::new("component.jsx")));
}
#[test]
fn test_java_file() {
assert!(is_analyzable_file(Path::new("Main.java")));
}
#[test]
fn test_c_cpp_files() {
assert!(is_analyzable_file(Path::new("main.c")));
assert!(is_analyzable_file(Path::new("main.cpp")));
assert!(is_analyzable_file(Path::new("header.h")));
assert!(is_analyzable_file(Path::new("header.hpp")));
}
#[test]
fn test_go_file() {
assert!(is_analyzable_file(Path::new("main.go")));
}
#[test]
fn test_ruby_file() {
assert!(is_analyzable_file(Path::new("app.rb")));
}
#[test]
fn test_php_file() {
assert!(is_analyzable_file(Path::new("index.php")));
}
#[test]
fn test_swift_file() {
assert!(is_analyzable_file(Path::new("App.swift")));
}
#[test]
fn test_kotlin_files() {
assert!(is_analyzable_file(Path::new("Main.kt")));
assert!(is_analyzable_file(Path::new("build.kts")));
}
#[test]
fn test_non_analyzable_files() {
assert!(!is_analyzable_file(Path::new("readme.md")));
assert!(!is_analyzable_file(Path::new("data.json")));
assert!(!is_analyzable_file(Path::new("config.toml")));
assert!(!is_analyzable_file(Path::new("Makefile")));
assert!(!is_analyzable_file(Path::new("style.css")));
assert!(!is_analyzable_file(Path::new("index.html")));
}
#[test]
fn test_no_extension() {
assert!(!is_analyzable_file(Path::new("Dockerfile")));
assert!(!is_analyzable_file(Path::new("README")));
}
#[test]
fn test_hidden_file_with_extension() {
assert!(is_analyzable_file(Path::new(".hidden.rs")));
}
#[test]
fn test_deeply_nested_path() {
assert!(is_analyzable_file(Path::new("a/b/c/d/e/f/g/h/file.rs")));
}
#[test]
fn test_unicode_filename() {
assert!(is_analyzable_file(Path::new("日本語.rs")));
assert!(is_analyzable_file(Path::new("файл.py")));
}
#[test]
fn test_empty_path() {
assert!(!is_analyzable_file(Path::new("")));
}
#[test]
fn test_all_supported_extensions() {
let extensions = [
"rs", "py", "js", "ts", "tsx", "jsx", "java", "c", "cpp", "h", "hpp", "go", "rb",
"php", "swift", "kt", "kts",
];
for ext in extensions {
let path = format!("file.{}", ext);
assert!(
is_analyzable_file(Path::new(&path)),
"Expected {} to be analyzable",
path
);
}
}
}
mod truncate_string_tests {
use super::*;
#[test]
fn test_short_string_padded() {
let result = truncate_string("hello", 10);
assert_eq!(result.trim(), "hello");
assert_eq!(result.len(), 10);
}
#[test]
fn test_exact_length_string() {
let result = truncate_string("hello", 5);
assert_eq!(result.trim(), "hello");
}
#[test]
fn test_long_string_truncated() {
let result = truncate_string("hello world", 8);
assert_eq!(result, "hello...");
}
#[test]
fn test_empty_string() {
let result = truncate_string("", 10);
assert_eq!(result.len(), 10);
assert_eq!(result.trim(), "");
}
#[test]
fn test_truncate_minimum_length() {
let result = truncate_string("abcdef", 3);
assert_eq!(result, "...");
}
#[test]
fn test_truncate_preserves_start() {
let result = truncate_string("abcdefghijklmnop", 10);
assert!(result.starts_with("abcdefg"));
assert!(result.ends_with("..."));
}
}
mod tdg_command_config_tests {
use super::*;
#[test]
fn test_default_config_creation() {
let config = make_test_config(PathBuf::from("."));
assert_eq!(config.path, PathBuf::from("."));
assert!(!config.quiet);
assert!(!config.include_components);
assert!(config.min_grade.is_none());
assert!(config.command.is_none());
}
#[test]
fn test_config_with_all_options() {
let config = TdgCommandConfig {
path: PathBuf::from("/tmp/test"),
command: None,
format: TdgOutputFormat::Json,
config: Some(PathBuf::from("/tmp/config.toml")),
quiet: true,
include_components: true,
min_grade: Some("B".to_string()),
output: Some(PathBuf::from("/tmp/output.json")),
with_git_context: true,
explain: true,
threshold: 15,
baseline: Some("HEAD~5".to_string()),
viz: true,
viz_theme: "high-contrast".to_string(),
};
assert_eq!(config.threshold, 15);
assert!(config.include_components);
assert!(config.quiet);
assert!(config.explain);
assert!(config.viz);
}
}
mod validate_minimum_grade_tests {
use super::*;
#[test]
fn test_no_minimum_grade_always_passes() {
let config = make_test_config(PathBuf::from("."));
let score = make_test_score(10.0, Grade::F);
let result = validate_minimum_grade(&score, &config);
assert!(result.is_ok());
}
#[test]
fn test_grade_equals_minimum() {
let mut config = make_test_config(PathBuf::from("."));
config.min_grade = Some("B".to_string());
let score = make_test_score(75.0, Grade::B);
let result = validate_minimum_grade(&score, &config);
assert!(result.is_ok());
}
}
mod format_tdg_output_tests {
use super::*;
#[test]
fn test_quiet_mode_outputs_score_only() {
let mut config = make_test_config(PathBuf::from("."));
config.quiet = true;
let score = make_test_score(85.5, Grade::B);
let result = format_tdg_output(&score, None, &config).unwrap();
assert_eq!(result, "85.5");
}
#[test]
fn test_table_format_contains_header() {
let mut config = make_test_config(PathBuf::from("."));
config.format = TdgOutputFormat::Table;
let score = make_test_score(85.5, Grade::B);
let result = format_tdg_output(&score, None, &config).unwrap();
assert!(result.contains("TDG Score Report"));
assert!(result.contains("85.5"));
}
#[test]
fn test_json_format_is_valid_json() {
let mut config = make_test_config(PathBuf::from("."));
config.format = TdgOutputFormat::Json;
let score = make_test_score(75.0, Grade::B);
let result = format_tdg_output(&score, None, &config).unwrap();
let parsed: serde_json::Value = serde_json::from_str(&result).unwrap();
assert!(parsed.get("score").is_some());
}
#[test]
fn test_markdown_format_has_header() {
let mut config = make_test_config(PathBuf::from("."));
config.format = TdgOutputFormat::Markdown;
let score = make_test_score(80.0, Grade::BPlus);
let result = format_tdg_output(&score, None, &config).unwrap();
assert!(result.contains("# TDG Score Report"));
assert!(result.contains("**Overall Score**"));
}
#[test]
fn test_include_components_shows_breakdown() {
let mut config = make_test_config(PathBuf::from("."));
config.include_components = true;
config.format = TdgOutputFormat::Table;
let score = make_test_score(80.0, Grade::BPlus);
let result = format_tdg_output(&score, None, &config).unwrap();
assert!(result.contains("Breakdown"));
assert!(result.contains("Structural"));
}
}
mod format_tdg_score_tests {
use super::*;
#[test]
fn test_table_without_components() {
let score = make_test_score(75.0, Grade::B);
let result = format_tdg_score(score, None, TdgOutputFormat::Table, false).unwrap();
assert!(result.contains("TDG Score Report"));
assert!(!result.contains("Breakdown"));
}
#[test]
fn test_table_with_components() {
let score = make_test_score(75.0, Grade::B);
let result = format_tdg_score(score, None, TdgOutputFormat::Table, true).unwrap();
assert!(result.contains("Breakdown"));
assert!(result.contains("Structural"));
assert!(result.contains("Semantic"));
}
#[test]
fn test_json_output_structure() {
let score = make_test_score(75.0, Grade::B);
let result = format_tdg_score(score, None, TdgOutputFormat::Json, false).unwrap();
let parsed: serde_json::Value = serde_json::from_str(&result).unwrap();
assert_eq!(parsed["score"]["total"], 75.0);
assert_eq!(parsed["score"]["grade"], "B");
}
#[test]
fn test_json_with_components() {
let score = make_test_score(75.0, Grade::B);
let result = format_tdg_score(score, None, TdgOutputFormat::Json, true).unwrap();
let parsed: serde_json::Value = serde_json::from_str(&result).unwrap();
assert!(parsed["score"]["breakdown"].is_object());
}
#[test]
fn test_json_without_components_null_breakdown() {
let score = make_test_score(75.0, Grade::B);
let result = format_tdg_score(score, None, TdgOutputFormat::Json, false).unwrap();
let parsed: serde_json::Value = serde_json::from_str(&result).unwrap();
assert!(parsed["score"]["breakdown"].is_null());
}
#[test]
fn test_markdown_output() {
let score = make_test_score(75.0, Grade::B);
let result = format_tdg_score(score, None, TdgOutputFormat::Markdown, false).unwrap();
assert!(result.contains("# TDG Score Report"));
assert!(result.contains("**Overall Score**"));
}
#[test]
fn test_markdown_with_components() {
let score = make_test_score(75.0, Grade::B);
let result = format_tdg_score(score, None, TdgOutputFormat::Markdown, true).unwrap();
assert!(result.contains("## Component Breakdown"));
assert!(result.contains("| Component | Score | Max |"));
}
#[test]
fn test_sarif_output_is_score_only() {
let score = make_test_score(75.0, Grade::B);
let result = format_tdg_score(score, None, TdgOutputFormat::Sarif, false).unwrap();
assert_eq!(result.trim(), "75.0");
}
#[test]
fn test_with_file_path() {
let mut score = make_test_score(88.0, Grade::BPlus);
score.file_path = Some(PathBuf::from("src/handlers/tdg.rs"));
let result =
format_tdg_score(score.clone(), None, TdgOutputFormat::Table, false).unwrap();
assert!(result.contains("src/handlers/tdg.rs"));
let result =
format_tdg_score(score.clone(), None, TdgOutputFormat::Markdown, false).unwrap();
assert!(result.contains("**File**: `src/handlers/tdg.rs`"));
let result = format_tdg_score(score, None, TdgOutputFormat::Json, false).unwrap();
let parsed: serde_json::Value = serde_json::from_str(&result).unwrap();
assert!(parsed["file"].as_str().unwrap().contains("tdg.rs"));
}
#[test]
fn test_with_git_context() {
let score = make_test_score(80.0, Grade::B);
let git_context = crate::models::git_context::GitContext {
commit_sha: "abc123def456789".to_string(),
commit_sha_short: "abc123d".to_string(),
branch: "main".to_string(),
author_name: "Test Author".to_string(),
author_email: "test@example.com".to_string(),
commit_timestamp: chrono::Utc::now(),
commit_message: "Test commit".to_string(),
tags: vec!["v1.0".to_string()],
parent_commits: vec![],
remote_url: None,
is_clean: true,
uncommitted_files: 0,
};
let result = format_tdg_score(
score.clone(),
Some(&git_context),
TdgOutputFormat::Table,
false,
)
.unwrap();
assert!(result.contains("Git Context"));
assert!(result.contains("abc123d"));
assert!(result.contains("main"));
let result =
format_tdg_score(score, Some(&git_context), TdgOutputFormat::Json, false).unwrap();
let parsed: serde_json::Value = serde_json::from_str(&result).unwrap();
assert_eq!(parsed["git_context"]["branch"], "main");
assert_eq!(parsed["git_context"]["is_clean"], true);
}
}
mod format_comparison_tests {
use super::*;
fn make_comparison() -> crate::tdg::Comparison {
crate::tdg::Comparison {
source1: make_test_score(70.0, Grade::C),
source2: make_test_score(85.0, Grade::B),
delta: 15.0,
improvement_percentage: 21.4,
winner: "source2".to_string(),
improvements: vec!["duplication".to_string()],
regressions: vec![],
}
}
#[test]
fn test_table_format() {
let comparison = make_comparison();
let result = format_comparison(comparison, TdgOutputFormat::Table).unwrap();
assert!(result.contains("TDG Comparison"));
assert!(result.contains("70.0"));
assert!(result.contains("85.0"));
assert!(result.contains("+15.0"));
}
#[test]
fn test_json_format() {
let comparison = make_comparison();
let result = format_comparison(comparison, TdgOutputFormat::Json).unwrap();
let parsed: serde_json::Value = serde_json::from_str(&result).unwrap();
assert_eq!(parsed["source1"]["total"], 70.0);
assert_eq!(parsed["source2"]["total"], 85.0);
assert_eq!(parsed["difference"], 15.0);
assert_eq!(parsed["winner"], "source2");
}
#[test]
fn test_markdown_uses_json() {
let comparison = make_comparison();
let result = format_comparison(comparison, TdgOutputFormat::Markdown).unwrap();
let parsed: Result<serde_json::Value, _> = serde_json::from_str(&result);
assert!(parsed.is_ok());
}
}
mod write_tdg_output_tests {
use super::*;
use tempfile::TempDir;
#[test]
fn test_write_to_stdout() {
let config = make_test_config(PathBuf::from("."));
let result = write_tdg_output("test output", &config);
assert!(result.is_ok());
}
#[test]
fn test_write_to_file() {
let temp_dir = TempDir::new().unwrap();
let output_path = temp_dir.path().join("output.txt");
let mut config = make_test_config(temp_dir.path().to_path_buf());
config.output = Some(output_path.clone());
let result = write_tdg_output("test output content", &config);
assert!(result.is_ok());
assert!(output_path.exists());
let content = std::fs::read_to_string(&output_path).unwrap();
assert_eq!(content, "test output content");
}
}
mod load_tdg_configuration_tests {
use super::*;
use tempfile::TempDir;
#[test]
fn test_default_config() {
let config = make_test_config(PathBuf::from("."));
let result = load_tdg_configuration(&config);
assert!(result.is_ok());
}
#[test]
fn test_missing_config_file() {
let mut config = make_test_config(PathBuf::from("."));
config.config = Some(PathBuf::from("/nonexistent/config.toml"));
let result = load_tdg_configuration(&config);
assert!(result.is_err());
}
#[test]
fn test_invalid_toml_config() {
let temp_dir = TempDir::new().unwrap();
let config_path = temp_dir.path().join("invalid.toml");
std::fs::write(&config_path, "this is not valid toml [[[").unwrap();
let mut config = make_test_config(temp_dir.path().to_path_buf());
config.config = Some(config_path);
let result = load_tdg_configuration(&config);
assert!(result.is_err());
}
}
mod format_history_output_tests {
use super::*;
use crate::tdg::storage::{ComponentScores, FileIdentity, FullTdgRecord};
fn make_test_record(path: &str, total: f32, commit_sha: &str) -> FullTdgRecord {
FullTdgRecord {
identity: FileIdentity {
path: PathBuf::from(path),
content_hash: blake3::hash(path.as_bytes()),
size_bytes: 1024,
modified_time: std::time::SystemTime::now(),
},
score: crate::tdg::TdgScore {
total,
grade: if total >= 80.0 { Grade::B } else { Grade::C },
confidence: 0.9,
language: crate::tdg::Language::Rust,
structural_complexity: 15.0,
semantic_complexity: 12.0,
duplication_ratio: 8.0,
coupling_score: 10.0,
doc_coverage: 5.0,
consistency_score: 5.0,
entropy_score: total - 55.0,
file_path: Some(PathBuf::from(path)),
penalties_applied: vec![],
critical_defects_count: 0,
has_critical_defects: false,
has_contract_coverage: false,
},
components: ComponentScores::default(),
semantic_sig: crate::tdg::storage::SemanticSignature {
ast_structure_hash: 12345,
identifier_pattern: "test".to_string(),
control_flow_pattern: "linear".to_string(),
import_dependencies: vec![],
},
metadata: crate::tdg::storage::AnalysisMetadata {
analyzer_version: "1.0.0".to_string(),
analysis_duration_ms: 100,
language_confidence: 0.95,
analysis_timestamp: std::time::SystemTime::now(),
cache_hit: false,
},
git_context: Some(crate::models::git_context::GitContext {
commit_sha: commit_sha.to_string(),
commit_sha_short: commit_sha[..7.min(commit_sha.len())].to_string(),
branch: "main".to_string(),
author_name: "Developer".to_string(),
author_email: "dev@test.com".to_string(),
commit_timestamp: chrono::Utc::now(),
commit_message: "Update".to_string(),
tags: vec![],
parent_commits: vec![],
remote_url: None,
is_clean: true,
uncommitted_files: 0,
}),
}
}
#[test]
fn test_table_format_with_git_context() {
let records = vec![make_test_record("test.rs", 80.0, "abcdef123456")];
let result = format_history_output(&records, TdgOutputFormat::Table).unwrap();
assert!(result.contains("TDG History"));
assert!(result.contains("abcdef1"));
assert!(result.contains("main"));
}
#[test]
fn test_json_format_with_git_context() {
let records = vec![make_test_record("test.rs", 80.0, "abcdef123456")];
let result = format_history_output(&records, TdgOutputFormat::Json).unwrap();
let parsed: serde_json::Value = serde_json::from_str(&result).unwrap();
assert_eq!(parsed["total_records"], 1);
assert!(parsed["history"].is_array());
}
#[test]
fn test_empty_records() {
let records: Vec<FullTdgRecord> = vec![];
let result = format_history_output(&records, TdgOutputFormat::Table).unwrap();
assert!(result.contains("TDG History"));
}
#[test]
fn test_multiple_records() {
let records = vec![
make_test_record("src/lib.rs", 85.0, "abc1234567890"),
make_test_record("src/main.rs", 75.0, "def4567890abc"),
make_test_record("src/utils.rs", 90.0, "ghi7890abcdef"),
];
let result = format_history_output(&records, TdgOutputFormat::Table).unwrap();
assert!(result.contains("abc1234"));
assert!(result.contains("def4567"));
assert!(result.contains("ghi7890"));
let result = format_history_output(&records, TdgOutputFormat::Json).unwrap();
let parsed: serde_json::Value = serde_json::from_str(&result).unwrap();
assert_eq!(parsed["total_records"], 3);
}
}
mod display_gate_result_tests {
use super::*;
use crate::tdg::{GateResult, Severity, Violation, ViolationType};
#[test]
fn test_display_passed_result() {
let result = GateResult {
passed: true,
gate_name: "RegressionGate".to_string(),
violations: vec![],
message: "All quality checks passed".to_string(),
};
display_gate_result_table(&result);
}
#[test]
fn test_display_failed_result_with_violations() {
let result = GateResult {
passed: false,
gate_name: "MinimumGradeGate".to_string(),
violations: vec![Violation {
path: PathBuf::from("bad_file.rs"),
violation_type: ViolationType::BelowMinimum,
severity: Severity::Error,
message: "Grade C is below minimum B".to_string(),
old_score: None,
new_score: 72.0,
old_grade: None,
new_grade: Grade::C,
}],
message: "1 violation found".to_string(),
};
display_gate_result_table(&result);
}
#[test]
fn test_display_multiple_violations() {
let result = GateResult {
passed: false,
gate_name: "QualityGate".to_string(),
violations: vec![
Violation {
path: PathBuf::from("file1.rs"),
violation_type: ViolationType::BelowMinimum,
severity: Severity::Error,
message: "Below minimum".to_string(),
old_score: None,
new_score: 60.0,
old_grade: None,
new_grade: Grade::C,
},
Violation {
path: PathBuf::from("file2.rs"),
violation_type: ViolationType::Regression,
severity: Severity::Critical,
message: "Regression".to_string(),
old_score: Some(85.0),
new_score: 70.0,
old_grade: Some(Grade::B),
new_grade: Grade::C,
},
],
message: "2 violations found".to_string(),
};
display_gate_result_table(&result);
}
}
}
#[cfg(all(test, feature = "broken-tests"))]
#[path = "tdg_handlers_coverage_tests.rs"]
mod coverage_tests;
#[cfg(all(test, feature = "broken-tests"))]
#[path = "tdg_handlers_coverage_tests2.rs"]
mod coverage_tests2;