reputation-core 0.1.0

Core calculation engine for the KnowThat Reputation System with advanced scoring algorithms
Documentation
use reputation_core::{Calculator, CalculatorPreset, BonusConfig, CalculatorConfig};

#[test]
fn test_builder_with_defaults() {
    let calc = Calculator::builder().build().unwrap();
    
    assert_eq!(calc.confidence_k(), 15.0);
    assert_eq!(calc.prior_base(), 50.0);
    assert_eq!(calc.prior_max(), 80.0);
}

#[test]
fn test_builder_with_custom_values() {
    let calc = Calculator::builder()
        .confidence_k(25.0)
        .prior_base(55.0)
        .prior_max(88.0)
        .build()
        .unwrap();
    
    assert_eq!(calc.confidence_k(), 25.0);
    assert_eq!(calc.prior_base(), 55.0);
    assert_eq!(calc.prior_max(), 88.0);
}

#[test]
fn test_preset_testing() {
    let calc = Calculator::builder()
        .preset(CalculatorPreset::Testing)
        .build()
        .unwrap();
    
    assert_eq!(calc.confidence_k(), 5.0);
    assert_eq!(calc.prior_base(), 50.0);
    assert_eq!(calc.prior_max(), 80.0);
}

#[test]
fn test_preset_conservative() {
    let calc = Calculator::builder()
        .preset(CalculatorPreset::Conservative)
        .build()
        .unwrap();
    
    assert_eq!(calc.confidence_k(), 30.0);
    assert_eq!(calc.prior_base(), 60.0);
    assert_eq!(calc.prior_max(), 80.0);
}

#[test]
fn test_preset_aggressive() {
    let calc = Calculator::builder()
        .preset(CalculatorPreset::Aggressive)
        .build()
        .unwrap();
    
    assert_eq!(calc.confidence_k(), 10.0);
    assert_eq!(calc.prior_base(), 40.0);
    assert_eq!(calc.prior_max(), 90.0);
}

#[test]
fn test_preset_with_override() {
    let calc = Calculator::builder()
        .preset(CalculatorPreset::Testing)
        .confidence_k(8.0)  // Override preset value
        .prior_max(85.0)    // Override preset value
        .build()
        .unwrap();
    
    assert_eq!(calc.confidence_k(), 8.0);   // Overridden
    assert_eq!(calc.prior_base(), 50.0);    // From preset
    assert_eq!(calc.prior_max(), 85.0);     // Overridden
}

#[test]
fn test_builder_validation_errors() {
    // Zero confidence_k
    let result = Calculator::builder()
        .confidence_k(0.0)
        .build();
    assert!(result.is_err());
    assert!(result.unwrap_err().to_string().contains("confidence_k"));
    
    // Negative confidence_k
    let result = Calculator::builder()
        .confidence_k(-5.0)
        .build();
    assert!(result.is_err());
    
    // Negative prior_base
    let result = Calculator::builder()
        .prior_base(-10.0)
        .build();
    assert!(result.is_err());
    assert!(result.unwrap_err().to_string().contains("prior_base"));
    
    // prior_base over 100
    let result = Calculator::builder()
        .prior_base(105.0)
        .build();
    assert!(result.is_err());
    
    // prior_max less than prior_base
    let result = Calculator::builder()
        .prior_base(60.0)
        .prior_max(50.0)
        .build();
    assert!(result.is_err());
    assert!(result.unwrap_err().to_string().contains("prior_max"));
    
    // prior_max equal to prior_base
    let result = Calculator::builder()
        .prior_base(60.0)
        .prior_max(60.0)
        .build();
    assert!(result.is_err());
    
    // prior_max over 100
    let result = Calculator::builder()
        .prior_max(105.0)
        .build();
    assert!(result.is_err());
}

#[test]
fn test_builder_from_config() {
    let config = CalculatorConfig {
        confidence_k: 18.0,
        prior_base: 52.0,
        prior_max: 82.0,
    };
    
    let calc = Calculator::builder()
        .from_config(config)
        .build()
        .unwrap();
    
    assert_eq!(calc.confidence_k(), 18.0);
    assert_eq!(calc.prior_base(), 52.0);
    assert_eq!(calc.prior_max(), 82.0);
}

#[test]
fn test_builder_with_bonus_config() {
    let bonuses = BonusConfig {
        mcp_bonus_per_level: 7.0,
        identity_bonus: 8.0,
        security_audit_bonus: 10.0,
        open_source_bonus: 5.0,
        age_bonus: 6.0,
    };
    
    // The builder accepts the bonus config even though
    // the current Calculator doesn't use it yet
    let calc = Calculator::builder()
        .prior_bonuses(bonuses)
        .build()
        .unwrap();
    
    assert_eq!(calc.confidence_k(), 15.0); // Still using defaults
}

#[test]
fn test_builder_cloning() {
    let base_builder = Calculator::builder()
        .confidence_k(20.0)
        .prior_base(55.0);
    
    // Clone and modify
    let builder1 = base_builder.clone().prior_max(85.0);
    let builder2 = base_builder.clone().prior_max(90.0);
    
    let calc1 = builder1.build().unwrap();
    let calc2 = builder2.build().unwrap();
    
    // Both should have the same base values
    assert_eq!(calc1.confidence_k(), 20.0);
    assert_eq!(calc2.confidence_k(), 20.0);
    assert_eq!(calc1.prior_base(), 55.0);
    assert_eq!(calc2.prior_base(), 55.0);
    
    // But different max values
    assert_eq!(calc1.prior_max(), 85.0);
    assert_eq!(calc2.prior_max(), 90.0);
}

#[test]
fn test_builder_reset() {
    let calc = Calculator::builder()
        .confidence_k(25.0)
        .prior_base(60.0)
        .prior_max(85.0)
        .reset()  // Reset to defaults
        .build()
        .unwrap();
    
    assert_eq!(calc.confidence_k(), 15.0); // Default
    assert_eq!(calc.prior_base(), 50.0);   // Default
    assert_eq!(calc.prior_max(), 80.0);    // Default
}

#[test]
fn test_complex_builder_chain() {
    // Test that all methods can be chained together
    let calc = Calculator::builder()
        .preset(CalculatorPreset::Conservative)
        .confidence_k(25.0)  // Override preset
        .prior_base(58.0)    // Override preset
        .prior_max(87.0)     // Override preset
        .prior_bonuses(BonusConfig::default())
        .build()
        .unwrap();
    
    assert_eq!(calc.confidence_k(), 25.0);
    assert_eq!(calc.prior_base(), 58.0);
    assert_eq!(calc.prior_max(), 87.0);
}

#[test]
fn test_builder_config_inspection() {
    let builder = Calculator::builder()
        .confidence_k(22.0)
        .prior_base(56.0)
        .prior_max(84.0);
    
    let config = builder.config();
    
    assert_eq!(config.confidence_k, 22.0);
    assert_eq!(config.prior_base, 56.0);
    assert_eq!(config.prior_max, 84.0);
}

#[test]
fn test_edge_case_valid_configs() {
    // Minimum valid configuration
    let calc = Calculator::builder()
        .confidence_k(0.001)
        .prior_base(0.0)
        .prior_max(0.1)
        .build()
        .unwrap();
    
    assert_eq!(calc.confidence_k(), 0.001);
    assert_eq!(calc.prior_base(), 0.0);
    assert_eq!(calc.prior_max(), 0.1);
    
    // Maximum valid configuration
    let calc = Calculator::builder()
        .confidence_k(1000.0)
        .prior_base(99.9)
        .prior_max(100.0)
        .build()
        .unwrap();
    
    assert_eq!(calc.confidence_k(), 1000.0);
    assert_eq!(calc.prior_base(), 99.9);
    assert_eq!(calc.prior_max(), 100.0);
}

#[test]
fn test_builder_preserves_defaults_when_partial() {
    // Only set one parameter
    let calc = Calculator::builder()
        .confidence_k(20.0)
        .build()
        .unwrap();
    
    assert_eq!(calc.confidence_k(), 20.0);
    assert_eq!(calc.prior_base(), 50.0);  // Default
    assert_eq!(calc.prior_max(), 80.0);   // Default
}

#[test]
fn test_all_presets_valid() {
    // Ensure all presets produce valid calculators
    let presets = vec![
        CalculatorPreset::Testing,
        CalculatorPreset::Conservative,
        CalculatorPreset::Aggressive,
        CalculatorPreset::Default,
    ];
    
    for preset in presets {
        let calc = Calculator::builder()
            .preset(preset)
            .build()
            .unwrap();
        
        assert!(calc.confidence_k() > 0.0);
        assert!(calc.prior_base() >= 0.0 && calc.prior_base() <= 100.0);
        assert!(calc.prior_max() > calc.prior_base() && calc.prior_max() <= 100.0);
    }
}