reputation-core 0.1.0

Core calculation engine for the KnowThat Reputation System with advanced scoring algorithms
Documentation
//! Tests for edge cases and error paths to improve code coverage

use reputation_core::{Calculator, CalculatorConfig};
use reputation_types::AgentDataBuilder;
use std::path::Path;

#[test]
fn test_calculator_new_error_cases() {
    // Test invalid confidence_k
    assert!(Calculator::new(-1.0, 50.0, 80.0).is_err());
    assert!(Calculator::new(0.0, 50.0, 80.0).is_err());
    
    // Test invalid prior_base
    assert!(Calculator::new(15.0, -1.0, 80.0).is_err());
    assert!(Calculator::new(15.0, 101.0, 80.0).is_err());
    
    // Test invalid prior_max
    assert!(Calculator::new(15.0, 50.0, 40.0).is_err()); // prior_max < prior_base
    assert!(Calculator::new(15.0, 50.0, 101.0).is_err()); // prior_max > 100
    assert!(Calculator::new(15.0, 50.0, 49.9).is_err()); // prior_max < prior_base
}

#[test]
fn test_interactions_for_confidence_edge_cases() {
    let calc = Calculator::default();
    
    // Test target confidence of exactly 1.0 (should error)
    let result = calc.interactions_for_confidence(100, 1.0);
    assert!(result.is_err());
    
    // Test target confidence of 0.99999 (should work)
    let result = calc.interactions_for_confidence(100, 0.99999);
    assert!(result.is_ok());
}

#[test]
fn test_config_file_operations() {
    use tempfile::NamedTempFile;
    use std::fs;
    
    // Test reading non-existent file
    let result = CalculatorConfig::from_file(Path::new("/nonexistent/path/config.json"));
    assert!(result.is_err());
    
    // Test reading file with invalid JSON
    let temp_file = NamedTempFile::new().unwrap();
    fs::write(temp_file.path(), "invalid json content").unwrap();
    let result = CalculatorConfig::from_file(temp_file.path());
    assert!(result.is_err());
    
    // Test writing to invalid path
    let config = CalculatorConfig::default();
    let result = config.to_file(Path::new("/root/invalid/path/config.json"));
    assert!(result.is_err());
    
    // Test successful round-trip
    let temp_file = NamedTempFile::new().unwrap();
    let config = CalculatorConfig {
        confidence_k: 25.0,
        prior_base: 55.0,
        prior_max: 85.0,
    };
    
    // Write config
    config.to_file(temp_file.path()).unwrap();
    
    // Read it back
    let loaded_config = CalculatorConfig::from_file(temp_file.path()).unwrap();
    assert_eq!(loaded_config.confidence_k, 25.0);
    assert_eq!(loaded_config.prior_base, 55.0);
    assert_eq!(loaded_config.prior_max, 85.0);
}

#[test]
fn test_edge_case_calculations() {
    let calc = Calculator::default();
    
    // Test agent with very large values (but valid)
    let agent = AgentDataBuilder::new("did:test:max")
        .total_interactions(100_000_000)
        .total_reviews(50_000_000)
        .with_reviews(50_000_000, 5.0)
        .build()
        .unwrap();
    
    // Should still calculate without panic
    let result = calc.calculate(&agent);
    assert!(result.is_ok());
    let score = result.unwrap();
    assert!(score.score >= 0.0 && score.score <= 100.0);
    assert!(score.confidence >= 0.0 && score.confidence <= 1.0);
}

#[test]
fn test_predict_score_edge_cases() {
    let calc = Calculator::default();
    
    // Test prediction with agent that has maximum interactions
    let agent = AgentDataBuilder::new("did:test:maxed")
        .total_interactions(u32::MAX - 100)
        .total_reviews(1000)
        .with_reviews(1000, 4.0)
        .build()
        .unwrap();
    
    // Predicting additional interactions should handle potential overflow
    let result = calc.predict_score_change(&agent, 200, 5.0);
    assert!(result.is_ok());
}

#[test]
fn test_batch_processing_edge_cases() {
    let calc = Calculator::default();
    
    // Test batch with mix of valid and edge case agents
    let agents = vec![
        // Normal agent
        AgentDataBuilder::new("did:test:normal")
            .with_reviews(10, 4.0)
            .total_interactions(15)
            .build()
            .unwrap(),
        
        // Agent with very large values (but valid)
        AgentDataBuilder::new("did:test:max")
            .total_interactions(100_000_000)
            .total_reviews(50_000_000)
            .with_reviews(50_000_000, 5.0)
            .build()
            .unwrap(),
        
        // New agent with no data
        AgentDataBuilder::new("did:test:new")
            .build()
            .unwrap(),
    ];
    
    let results = calc.calculate_batch(&agents);
    assert_eq!(results.len(), 3);
    
    // All should succeed
    for (idx, result) in results.iter().enumerate() {
        if result.is_err() {
            eprintln!("Agent {} failed: {:?}", idx, result);
        }
        assert!(result.is_ok(), "Agent {} should succeed", idx);
    }
}