pmat 3.11.0

PMAT - Zero-config AI context generation and code quality toolkit (CLI, MCP, HTTP)
//! Hallucination Detection Tests - Sprint 37 (EXTREME TDD - GREEN Phase)
//!
//! Tests for semantic entropy-based hallucination detection in documentation.
//! These tests validate the HallucinationDetector implementation.
//!
//! Based on peer-reviewed research:
//! - Semantic Entropy (Farquhar et al., Nature 2024)
//! - MIND framework (IJCAI 2025)
//! - Unified Detection Framework (Complex & Intelligent Systems 2025)

use crate::services::hallucination_detector::*;
use std::path::PathBuf;

// ============================================================================
// Test Fixture Helpers
// ============================================================================

fn create_test_code_facts_with_typescript() -> CodeFactDatabase {
    let markdown = r#"
Supported languages:
- TypeScript
- JavaScript
- Rust
    "#;
    CodeFactDatabase::from_markdown(markdown).unwrap()
}

fn create_test_code_facts_analysis_only() -> CodeFactDatabase {
    let mut db = CodeFactDatabase::new();
    db.add_capability("analyze".to_string());
    db
}

fn create_test_code_facts_no_haskell() -> CodeFactDatabase {
    let markdown = r#"
Supported languages:
- Rust
- TypeScript
- Python
    "#;
    CodeFactDatabase::from_markdown(markdown).unwrap()
}

fn create_test_code_facts_realistic() -> CodeFactDatabase {
    let markdown = r#"
Supported languages:
- Rust
- TypeScript
- Python

Functions:
- analyze()
- detect()
- validate()
    "#;
    let mut db = CodeFactDatabase::from_markdown(markdown).unwrap();
    db.add_capability("analyze".to_string());
    db
}

#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod green_phase_tests {
    use super::*;

    /// RED TEST 1: ClaimExtractor must extract capability claims from documentation
    ///
    /// # Acceptance Criteria
    /// - Extract "PMAT can analyze X" patterns
    /// - Identify claim type as Capability
    /// - Parse entities (languages, file types, etc.)
    ///
    /// # Test Cases
    /// 1. Simple capability: "PMAT can analyze Rust code"
    /// 2. Complex capability: "PMAT can analyze TypeScript files for complexity metrics"
    /// 3. Negative capability: "PMAT cannot compile code"
    #[test]
    fn green_claim_extractor_must_parse_capability_claims() {
        // ARRANGE
        let documentation = r#"
# PMAT Features

PMAT can analyze Rust code complexity.
PMAT can analyze TypeScript files for complexity metrics.
PMAT cannot compile code - it only analyzes existing source.
        "#;

        let extractor = ClaimExtractor::new();

        // ACT
        let claims = extractor.extract_claims(documentation);

        // ASSERT
        assert_eq!(claims.len(), 3, "Should extract 3 claims");

        // Claim 1: Positive capability
        let claim1 = &claims[0];
        assert_eq!(claim1.claim_type, ClaimType::Capability);
        assert_eq!(claim1.text, "PMAT can analyze Rust code complexity");
        assert!(
            claim1
                .entities
                .contains(&Entity::Language("Rust".to_string())),
            "Should identify Rust language entity"
        );

        // Claim 2: Complex capability
        let claim2 = &claims[1];
        assert_eq!(claim2.claim_type, ClaimType::Capability);
        assert!(claim2
            .entities
            .contains(&Entity::Language("TypeScript".to_string())));

        // Claim 3: Negative capability
        let claim3 = &claims[2];
        assert_eq!(claim3.claim_type, ClaimType::Capability);
        assert!(claim3.is_negative, "Should detect negative capability");
    }

    /// RED TEST 2: CodeFactDatabase must load AST facts from deep context
    ///
    /// # Acceptance Criteria
    /// - Parse deep_context.md generated by pmat context
    /// - Extract all functions, classes, modules
    /// - Build searchable index by language and entity type
    ///
    /// # Test Case
    /// Given a deep context with Rust functions, verify facts are accessible
    #[test]
    fn green_code_fact_database_must_load_from_deep_context() {
        // ARRANGE
        let deep_context = r#"
## File: server/src/main.rs

Functions:
- main() (line 10)
- run_server() (line 25)

## Language Support

Supported languages:
- Rust
- TypeScript
- Python
        "#;

        // ACT
        let fact_db = CodeFactDatabase::from_markdown(deep_context).unwrap();

        // ASSERT
        assert!(fact_db.has_function("main"), "Should find main() function");
        assert!(
            fact_db.has_function("run_server"),
            "Should find run_server() function"
        );
        assert!(
            fact_db.has_language_support("Rust"),
            "Should find Rust language support"
        );
        assert!(
            fact_db.has_language_support("TypeScript"),
            "Should find TypeScript language support"
        );
    }

    /// RED TEST 3: SemanticSimilarity must calculate confidence scores
    ///
    /// # Acceptance Criteria
    /// - Return score 0.0-1.0 for claim vs fact similarity
    /// - High score (>0.9) for verified claims
    /// - Low score (<0.3) for contradictory claims
    /// - Medium score (0.3-0.7) for unverified claims
    ///
    /// # Test Cases
    /// - Verified: "PMAT can analyze Rust" vs fact "Rust language supported"
    /// - Contradiction: "PMAT can compile code" vs fact "Analysis only, no compilation"
    #[test]
    // GREEN: Will fail until SemanticSimilarity is implemented
    fn green_semantic_similarity_must_score_claim_vs_fact() {
        // ARRANGE
        let similarity = SemanticSimilarity::new();

        let verified_claim = "PMAT can analyze Rust code complexity";
        let verified_fact = "Rust language analysis supported with complexity metrics";

        let contradictory_claim = "PMAT can compile Rust to native binaries";
        let contradictory_fact = "PMAT analyzes code but does not compile it";

        // ACT
        let verified_score = similarity.calculate(verified_claim, verified_fact);
        let contradictory_score = similarity.calculate(contradictory_claim, contradictory_fact);

        // ASSERT
        assert!(
            verified_score > 0.9,
            "Verified claim should have high similarity: {}",
            verified_score
        );
        assert!(
            contradictory_score < 0.3,
            "Contradictory claim should have low similarity: {}",
            contradictory_score
        );
    }

    /// RED TEST 4: HallucinationDetector must detect verified claims
    ///
    /// # Acceptance Criteria
    /// - Return ValidationStatus::Verified for true claims
    /// - Provide high confidence score (>0.9)
    /// - Include evidence from codebase
    ///
    /// # Test Case
    /// Claim: "PMAT can analyze TypeScript complexity"
    /// Fact: TypeScript analyzer exists in codebase
    #[test]
    // GREEN: Will fail until HallucinationDetector is implemented
    fn green_hallucination_detector_must_verify_true_claims() {
        // ARRANGE
        let code_facts = create_test_code_facts_with_typescript();
        let detector = HallucinationDetector::new(code_facts);

        let claim = Claim {
            source_file: PathBuf::from("README.md"),
            line_number: 10,
            text: "PMAT can analyze TypeScript complexity".to_string(),
            claim_type: ClaimType::Capability,
            entities: vec![Entity::Language("TypeScript".to_string())],
            is_negative: false,
        };

        // ACT
        let result = detector.validate_claim(&claim).unwrap();

        // ASSERT
        assert_eq!(
            result.status,
            ValidationStatus::Verified,
            "True claim should be verified"
        );
        assert!(
            result.confidence > 0.9,
            "Confidence should be high: {}",
            result.confidence
        );
        assert!(
            result.evidence.is_some(),
            "Should provide evidence from codebase"
        );
    }

    /// RED TEST 5: HallucinationDetector must detect contradictions
    ///
    /// # Acceptance Criteria
    /// - Return ValidationStatus::Contradiction for false claims
    /// - Provide low confidence score (<0.3)
    /// - Include evidence showing contradiction
    ///
    /// # Test Case
    /// Claim: "PMAT can compile code to native binaries"
    /// Fact: PMAT only analyzes, does not compile
    #[test]
    // GREEN: Will fail until HallucinationDetector is implemented
    fn green_hallucination_detector_must_detect_contradictions() {
        // ARRANGE
        let code_facts = create_test_code_facts_analysis_only();
        let detector = HallucinationDetector::new(code_facts);

        let claim = Claim {
            source_file: PathBuf::from("README.md"),
            line_number: 20,
            text: "PMAT can compile Rust code to native binaries".to_string(),
            claim_type: ClaimType::Capability,
            entities: vec![
                Entity::Language("Rust".to_string()),
                Entity::Capability("compile".to_string()),
            ],
            is_negative: false,
        };

        // ACT
        let result = detector.validate_claim(&claim).unwrap();

        // ASSERT
        assert_eq!(
            result.status,
            ValidationStatus::Contradiction,
            "False claim should be detected as contradiction"
        );
        assert!(
            result.confidence < 0.3,
            "Confidence should be low: {}",
            result.confidence
        );
        assert!(
            result.evidence.is_some(),
            "Should provide contradictory evidence"
        );
    }

    /// RED TEST 6: HallucinationDetector must detect unverified claims
    ///
    /// # Acceptance Criteria
    /// - Return ValidationStatus::Unverified for claims without evidence
    /// - Provide medium confidence score (0.3-0.7)
    ///
    /// # Test Case
    /// Claim: "PMAT can analyze Haskell code"
    /// Fact: No Haskell support in codebase (yet)
    #[test]
    // GREEN: Will fail until HallucinationDetector is implemented
    fn green_hallucination_detector_must_detect_unverified_claims() {
        // ARRANGE
        let code_facts = create_test_code_facts_no_haskell();
        let detector = HallucinationDetector::new(code_facts);

        let claim = Claim {
            source_file: PathBuf::from("README.md"),
            line_number: 30,
            text: "PMAT can analyze Haskell complexity metrics".to_string(),
            claim_type: ClaimType::Capability,
            entities: vec![Entity::Language("Haskell".to_string())],
            is_negative: false,
        };

        // ACT
        let result = detector.validate_claim(&claim).unwrap();

        // ASSERT
        assert_eq!(
            result.status,
            ValidationStatus::Unverified,
            "Unverified claim should be detected"
        );
        assert!(
            result.confidence >= 0.3 && result.confidence <= 0.7,
            "Confidence should be medium: {}",
            result.confidence
        );
    }

    /// RED TEST 7: End-to-end validation of README.md
    ///
    /// # Acceptance Criteria
    /// - Extract all claims from README.md
    /// - Validate each claim against codebase
    /// - Report verification status for each claim
    /// - Fail if any contradiction found
    ///
    /// # Test Case
    /// README with 3 claims (1 verified, 1 unverified, 1 contradiction)
    #[test]
    // GREEN: Will fail until full integration is implemented
    fn green_end_to_end_readme_validation() {
        // ARRANGE
        let readme = r#"
# PMAT - Code Analysis Tool

## Features

PMAT can analyze Rust code complexity.
PMAT can analyze Haskell functional programming patterns.
PMAT can compile Rust code to WebAssembly.
        "#;

        let code_facts = create_test_code_facts_realistic();
        let validator = DocAccuracyValidator::new(code_facts);

        // ACT
        let results = validator
            .validate_documentation(readme, "README.md")
            .unwrap();

        // ASSERT
        assert_eq!(results.len(), 3, "Should validate 3 claims");

        // Claim 1: Verified (Rust analysis exists)
        assert_eq!(results[0].status, ValidationStatus::Verified);

        // Claim 2: Unverified (Haskell not supported yet)
        assert_eq!(results[1].status, ValidationStatus::Unverified);

        // Claim 3: Contradiction (PMAT doesn't compile)
        assert_eq!(results[2].status, ValidationStatus::Contradiction);

        // Overall validation should fail due to contradiction
        assert!(
            validator.has_contradictions(&results),
            "Should detect contradiction"
        );
    }
}