use pmat::red_team::{
ClaimCategory, ClaimExtractor, CommitInfo, CommitIntent, IntentClassifier, TestChanges,
};
fn create_commit(
message: &str,
timestamp: 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: timestamp,
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_all_tests_passing_hallucination() {
let claim_extractor = ClaimExtractor::new();
let intent_classifier = IntentClassifier::new();
let original_commit = create_commit(
"feat: Complete feature X - all tests passing",
1000,
vec!["src/feature_x.rs"],
None,
None,
"feature/x",
0,
0,
);
let claims = claim_extractor.extract(&original_commit.message);
assert_eq!(claims.len(), 2); assert_eq!(claims[0].category, ClaimCategory::FeatureCompletion);
assert_eq!(claims[1].category, ClaimCategory::TestStatus);
assert!(claims[1].is_absolute);
let followup_commit = create_commit(
"fix: Fix failing tests in feature X",
1000 + (100 * 3600), vec!["src/feature_x.rs", "tests/feature_x_tests.rs"],
Some(42),
Some(5000), "hotfix/feature-x-tests",
0,
5, );
let classification = intent_classifier.classify(&original_commit, &followup_commit);
assert_eq!(classification.intent, CommitIntent::HallucinationFix);
assert!(classification.confidence > 0.7); assert_eq!(classification.signals.len(), 5);
}
#[test]
fn test_planned_iteration_not_flagged_as_hallucination() {
let claim_extractor = ClaimExtractor::new();
let intent_classifier = IntentClassifier::new();
let original_commit = create_commit(
"feat: Complete feature X (MVP - Sprint 42)\n\nScope: Basic functionality\nDeferred: Advanced features (Sprint 43)",
1000,
vec!["src/feature_x.rs"],
None,
None,
"feature/x",
0,
0,
);
let claims = claim_extractor.extract(&original_commit.message);
assert_eq!(claims.len(), 1); assert!(claims[0].has_scope_qualifier);
let followup_commit = create_commit(
"feat: Add advanced features to feature X (Sprint 43)",
1000 + (14 * 24 * 3600), vec!["src/feature_x.rs", "src/feature_x_advanced.rs"],
Some(43),
Some(500), "feature/x",
10, 0,
);
let classification = intent_classifier.classify(&original_commit, &followup_commit);
assert_eq!(classification.intent, CommitIntent::PlannedIteration);
}
#[test]
fn test_detect_coverage_hallucination() {
let claim_extractor = ClaimExtractor::new();
let intent_classifier = IntentClassifier::new();
let original_commit = create_commit(
"test: Coverage stable at 85%",
1000,
vec!["tests/integration_tests.rs"],
None,
None,
"master",
0,
0,
);
let claims = claim_extractor.extract(&original_commit.message);
assert_eq!(claims.len(), 1);
assert_eq!(claims[0].category, ClaimCategory::Coverage);
assert_eq!(claims[0].numeric_value, Some(85.0));
let followup_commit = create_commit(
"fix: Add missing tests to reach 85% coverage",
1000 + (48 * 3600), vec!["tests/integration_tests.rs", "tests/unit_tests.rs"],
None,
None,
"master",
15, 0,
);
let classification = intent_classifier.classify(&original_commit, &followup_commit);
assert!(
classification.intent == CommitIntent::HallucinationFix
|| classification.intent == CommitIntent::PlannedIteration
);
}
#[test]
fn test_multiple_claims_mixed_validity() {
let claim_extractor = ClaimExtractor::new();
let intent_classifier = IntentClassifier::new();
let original_commit = create_commit(
"feat: Complete user authentication\n\nAll tests passing\nCoverage at 90%\nZero vulnerabilities",
1000,
vec!["src/auth.rs"],
None,
None,
"feature/auth",
0,
0,
);
let claims = claim_extractor.extract(&original_commit.message);
assert_eq!(claims.len(), 4);
assert!(claims
.iter()
.all(|c| c.is_absolute || c.numeric_value.is_some()));
let followup_commit = create_commit(
"fix: Fix auth bugs and security issues",
1000 + (200 * 3600), vec!["src/auth.rs"],
Some(123),
Some(5000), "hotfix/auth-bugs",
0,
8, );
let classification = intent_classifier.classify(&original_commit, &followup_commit);
assert_eq!(classification.intent, CommitIntent::HallucinationFix);
assert!(classification.confidence > 0.7);
}
#[test]
fn test_refactoring_no_hallucination() {
let claim_extractor = ClaimExtractor::new();
let intent_classifier = IntentClassifier::new();
let original_commit = create_commit(
"feat: Basic parser implementation",
1000,
vec!["src/parser.rs"],
None,
None,
"feature/parser",
0,
0,
);
let claims = claim_extractor.extract(&original_commit.message);
assert_eq!(claims.len(), 0);
let followup_commit = create_commit(
"refactor: Improve parser performance and error handling",
1000 + (5 * 24 * 3600), vec!["src/parser.rs", "src/parser_errors.rs"],
None,
None,
"feature/parser",
5, 0,
);
let classification = intent_classifier.classify(&original_commit, &followup_commit);
assert_eq!(classification.intent, CommitIntent::PlannedIteration);
}
#[test]
fn test_grace_period_prevents_false_positive() {
let claim_extractor = ClaimExtractor::new();
let intent_classifier = IntentClassifier::new();
let original_commit = create_commit(
"feat: Complete feature Y",
1000,
vec!["src/feature_y.rs"],
None,
None,
"feature/y",
0,
0,
);
let claims = claim_extractor.extract(&original_commit.message);
assert_eq!(claims.len(), 1);
assert!(claims[0].is_absolute);
let followup_commit = create_commit(
"chore: Polish feature Y implementation", 1000 + (6 * 3600), vec!["src/feature_y.rs", "src/feature_y_utils.rs"], None,
None,
"feature/y", 2, 0,
);
let classification = intent_classifier.classify(&original_commit, &followup_commit);
assert_eq!(classification.intent, CommitIntent::PlannedIteration);
}
#[test]
fn test_cross_branch_fix_indicates_hallucination() {
let claim_extractor = ClaimExtractor::new();
let intent_classifier = IntentClassifier::new();
let original_commit = create_commit(
"feat: Complete feature Z - production ready",
1000,
vec!["src/feature_z.rs"],
None,
None,
"master",
0,
0,
);
let claims = claim_extractor.extract(&original_commit.message);
assert_eq!(claims.len(), 1);
assert_eq!(claims[0].category, ClaimCategory::FeatureCompletion);
let followup_commit = create_commit(
"fix: Critical bug in feature Z",
1000 + (72 * 3600), vec!["src/feature_z.rs"],
Some(999),
Some(1000 + (70 * 3600)), "hotfix/feature-z-critical",
0,
3,
);
let classification = intent_classifier.classify(&original_commit, &followup_commit);
assert_eq!(classification.intent, CommitIntent::HallucinationFix);
assert!(classification.confidence > 0.75);
}