use pmat::red_team::{CommitInfo, CommitIntent, IntentClassifier, TestChanges};
fn create_commit(
message: &str,
timestamp_seconds: i64,
files: Vec<&str>,
issue_num: Option<u32>,
issue_created: Option<i64>,
branch: &str,
added_tests: usize,
fixed_tests: usize,
) -> CommitInfo {
CommitInfo {
message: message.to_string(),
timestamp_seconds,
modified_files: files.iter().map(|s| s.to_string()).collect(),
issue_number: issue_num,
issue_created_timestamp: issue_created,
branch: branch.to_string(),
test_changes: TestChanges {
added_tests,
fixed_tests,
modified_test_files: vec![],
},
}
}
#[test]
fn test_detect_hallucination_fix_via_keyword() {
let classifier = IntentClassifier::new();
let original = create_commit(
"feat: All tests passing",
1000,
vec!["src/lib.rs"],
None,
None,
"feature/auth",
0,
0,
);
let followup = create_commit(
"fix: Actually fix failing tests",
2000,
vec!["src/lib.rs"],
None,
None,
"feature/auth",
0,
5, );
let result = classifier.classify(&original, &followup);
assert_eq!(result.intent, CommitIntent::HallucinationFix);
assert!(result.confidence > 0.5);
}
#[test]
fn test_detect_planned_iteration_via_keyword() {
let classifier = IntentClassifier::new();
let original = create_commit(
"feat: Complete user authentication",
1000,
vec!["src/auth.rs"],
None,
None,
"feature/auth",
0,
0,
);
let followup = create_commit(
"refactor: Improve authentication error handling",
2000,
vec!["src/auth.rs"],
None,
None,
"feature/auth",
3, 0,
);
let result = classifier.classify(&original, &followup);
assert_eq!(result.intent, CommitIntent::PlannedIteration);
assert!(result.confidence > 0.5);
}
#[test]
fn test_issue_created_after_commit_indicates_hallucination() {
let classifier = IntentClassifier::new();
let original = create_commit(
"feat: Bug-free implementation",
1000,
vec!["src/lib.rs"],
None,
None,
"master",
0,
0,
);
let followup = create_commit(
"fix: Resolve issue #42",
5000,
vec!["src/lib.rs"],
Some(42),
Some(2000), "master",
0,
1,
);
let result = classifier.classify(&original, &followup);
assert_eq!(result.intent, CommitIntent::HallucinationFix);
assert!(result.confidence > 0.7); }
#[test]
fn test_preexisting_issue_indicates_planned_work() {
let classifier = IntentClassifier::new();
let original = create_commit(
"feat: Implement feature X",
5000,
vec!["src/feature_x.rs"],
None,
None,
"feature/x",
0,
0,
);
let followup = create_commit(
"feat: Add error handling for feature X (closes #42)",
10000,
vec!["src/feature_x.rs"],
Some(42),
Some(1000), "feature/x",
2,
0,
);
let result = classifier.classify(&original, &followup);
assert_eq!(result.intent, CommitIntent::PlannedIteration);
assert!(result.confidence > 0.6);
}
#[test]
fn test_high_file_overlap_indicates_hallucination_fix() {
let classifier = IntentClassifier::new();
let original = create_commit(
"feat: Complete module implementation",
1000,
vec!["src/mod1.rs", "src/mod2.rs", "src/mod3.rs"],
None,
None,
"feature/module",
0,
0,
);
let followup = create_commit(
"fix: Correct module logic", 1000 + (100 * 3600), vec!["src/mod1.rs", "src/mod2.rs"], None,
None,
"hotfix/module-bug", 0,
2, );
let result = classifier.classify(&original, &followup);
assert_eq!(result.intent, CommitIntent::HallucinationFix);
}
#[test]
fn test_low_file_overlap_indicates_planned_iteration() {
let classifier = IntentClassifier::new();
let original = create_commit(
"feat: Complete module A",
1000,
vec!["src/mod_a.rs"],
None,
None,
"feature/modules",
0,
0,
);
let followup = create_commit(
"feat: Add module B",
2000,
vec![
"src/mod_b.rs",
"src/mod_c.rs",
"src/mod_d.rs",
"src/mod_e.rs",
"src/mod_f.rs",
],
None,
None,
"feature/modules",
10, 0,
);
let result = classifier.classify(&original, &followup);
assert_eq!(result.intent, CommitIntent::PlannedIteration);
}
#[test]
fn test_test_fixes_indicate_hallucination() {
let classifier = IntentClassifier::new();
let original = create_commit(
"test: All tests passing",
1000,
vec!["tests/integration.rs"],
None,
None,
"master",
0,
0,
);
let followup = create_commit(
"test: Fix test failures",
2000,
vec!["tests/integration.rs"],
None,
None,
"master",
1, 10, );
let result = classifier.classify(&original, &followup);
assert_eq!(result.intent, CommitIntent::HallucinationFix);
}
#[test]
fn test_test_additions_indicate_planned_iteration() {
let classifier = IntentClassifier::new();
let original = create_commit(
"feat: Basic feature implementation",
1000,
vec!["src/feature.rs"],
None,
None,
"feature/new",
0,
0,
);
let followup = create_commit(
"test: Expand test coverage",
2000,
vec!["tests/feature_tests.rs"],
None,
None,
"feature/new",
15, 2, );
let result = classifier.classify(&original, &followup);
assert_eq!(result.intent, CommitIntent::PlannedIteration);
}
#[test]
fn test_grace_period_indicates_planned_iteration() {
let classifier = IntentClassifier::new();
let original = create_commit(
"feat: Complete feature X",
1000,
vec!["src/feature_x.rs"],
None,
None,
"feature/x",
0,
0,
);
let followup = create_commit(
"refactor: Improve error handling in feature X", 1000 + (24 * 3600), vec!["src/feature_x.rs", "src/feature_x_errors.rs"], None,
None,
"feature/x", 5, 0,
);
let result = classifier.classify(&original, &followup);
assert_eq!(result.intent, CommitIntent::PlannedIteration);
}
#[test]
fn test_after_grace_period_different_branch_indicates_hallucination() {
let classifier = IntentClassifier::new();
let original = create_commit(
"feat: Complete feature X",
1000,
vec!["src/feature_x.rs"],
None,
None,
"feature/x",
0,
0,
);
let followup = create_commit(
"fix: Bug in feature X",
1000 + (72 * 3600), vec!["src/feature_x.rs"],
None,
None,
"hotfix/feature-x-bug", 0,
3,
);
let result = classifier.classify(&original, &followup);
assert_eq!(result.intent, CommitIntent::HallucinationFix);
}
#[test]
fn test_same_branch_indicates_planned_iteration() {
let classifier = IntentClassifier::new();
let original = create_commit(
"feat: Initial implementation",
1000,
vec!["src/lib.rs"],
None,
None,
"feature/new-module",
0,
0,
);
let followup = create_commit(
"feat: Add error handling",
2000,
vec!["src/lib.rs"],
None,
None,
"feature/new-module", 3,
0,
);
let result = classifier.classify(&original, &followup);
assert_eq!(result.intent, CommitIntent::PlannedIteration);
}
#[test]
fn test_mixed_signals_result_in_uncertain() {
let classifier = IntentClassifier::new();
let original = create_commit(
"feat: New feature",
1000,
vec!["src/feature.rs"],
None,
None,
"feature/new",
0,
0,
);
let followup = create_commit(
"chore: Update code", 1000 + (100 * 3600), vec!["src/other.rs"], None,
None,
"master", 5, 5, );
let result = classifier.classify(&original, &followup);
assert_eq!(result.intent, CommitIntent::Uncertain);
}
#[test]
fn test_unanimous_hallucination_signals_high_confidence() {
let classifier = IntentClassifier::new();
let original = create_commit(
"feat: All tests passing, bug-free",
1000,
vec!["src/lib.rs", "src/mod.rs"],
None,
None,
"master",
0,
0,
);
let followup = create_commit(
"fix: Critical bug in lib.rs (fixes #123)",
1000 + (100 * 3600), vec!["src/lib.rs", "src/mod.rs"], Some(123),
Some(5000), "hotfix/critical-bug", 0,
10, );
let result = classifier.classify(&original, &followup);
assert_eq!(result.intent, CommitIntent::HallucinationFix);
assert!(result.confidence > 0.75); }
#[test]
fn test_confidence_score_bounds() {
let classifier = IntentClassifier::new();
let original = create_commit(
"feat: Some feature",
1000,
vec!["src/lib.rs"],
None,
None,
"feature/test",
0,
0,
);
let followup = create_commit(
"refactor: Improve code",
2000,
vec!["src/lib.rs"],
None,
None,
"feature/test",
1,
0,
);
let result = classifier.classify(&original, &followup);
assert!(result.confidence >= 0.0);
assert!(result.confidence <= 1.0);
}
#[test]
fn test_classification_includes_all_signals() {
let classifier = IntentClassifier::new();
let original = create_commit(
"feat: Feature complete",
1000,
vec!["src/lib.rs"],
None,
None,
"feature/test",
0,
0,
);
let followup = create_commit(
"fix: Bug fix",
2000,
vec!["src/lib.rs"],
None,
None,
"feature/test",
0,
1,
);
let result = classifier.classify(&original, &followup);
assert_eq!(result.signals.len(), 5);
let signal_names: Vec<_> = result
.signals
.iter()
.map(|s| s.signal_name.as_str())
.collect();
assert!(signal_names.contains(&"commit_message"));
assert!(signal_names.contains(&"issue_linkage"));
assert!(signal_names.contains(&"code_churn"));
assert!(signal_names.contains(&"test_changes"));
assert!(signal_names.contains(&"temporal_context"));
}