use reputation_core::{
Calculator, CalculatorPreset, BonusConfig,
BatchOptions, ConfidenceLevel
};
use reputation_types::AgentDataBuilder;
use std::sync::{Arc, Mutex};
#[test]
fn test_builder_with_batch_processing() {
let calc = Calculator::builder()
.preset(CalculatorPreset::Conservative)
.prior_base(55.0)
.build()
.unwrap();
let agents: Vec<_> = (0..100)
.map(|i| {
let mut builder = AgentDataBuilder::new(&format!("did:test:agent{}", i))
.total_interactions(i * 3)
.mcp_level((i % 4) as u8)
.identity_verified(i % 2 == 0);
if i > 0 { builder = builder.with_reviews(i * 2, 3.0 + (i as f64 * 0.01));
}
builder.build().unwrap()
})
.collect();
let results = calc.calculate_batch(&agents);
assert_eq!(results.len(), 100);
for (i, result) in results.iter().enumerate() {
let score = result.as_ref().unwrap();
let expected_conf = (i * 3) as f64 / ((i * 3) as f64 + 30.0);
assert!((score.confidence - expected_conf).abs() < 0.001);
assert!(score.components.prior_score >= 55.0);
}
}
#[test]
fn test_utility_methods_with_enhanced_scores() {
let calc = Calculator::default();
let agent = AgentDataBuilder::new("did:test:utility")
.with_reviews(15, 4.5)
.total_interactions(20)
.mcp_level(2)
.identity_verified(true)
.build()
.unwrap();
let explanation = calc.explain_score(&agent).unwrap();
assert!(explanation.explanation.contains("Prior score: 65.0"));
assert!(explanation.explanation.contains("MCP bonus: +10.0"));
assert!(explanation.explanation.contains("Identity verified: +5.0"));
assert!(explanation.explanation.contains("Confidence Level: 57.1% (Medium)"));
assert_eq!(explanation.breakdown.prior_score, 65.0);
assert_eq!(explanation.breakdown.prior_breakdown.mcp_bonus, 10.0);
assert_eq!(explanation.breakdown.confidence_level, ConfidenceLevel::Medium);
let prediction = calc.predict_score_change(&agent, 30, 5.0).unwrap();
assert!(prediction.score_change > 0.0);
assert!(prediction.confidence_change > 0.0);
let future_confidence = calc.confidence_after_interactions(20, 30);
assert!(future_confidence > 0.7);
}
#[test]
fn test_batch_with_progress_tracking_and_components() {
let progress = Arc::new(Mutex::new(Vec::new()));
let progress_clone = Arc::clone(&progress);
let options = BatchOptions {
chunk_size: Some(10),
fail_fast: false,
progress_callback: Some(Box::new(move |completed, total| {
progress_clone.lock().unwrap().push((completed, total));
})),
};
let agents: Vec<_> = (0..50)
.map(|i| {
AgentDataBuilder::new(&format!("did:test:batch{}", i))
.with_reviews(10 + i, 3.5 + (i as f64 * 0.02))
.total_interactions(15 + i)
.mcp_level(if i > 25 { 1 } else { 0 })
.build()
.unwrap()
})
.collect();
let calc = Calculator::default();
let result = calc.calculate_batch_with_options(&agents, options);
assert_eq!(result.successful_count, 50);
assert_eq!(result.failed_count, 0);
for (i, calc) in result.calculations.iter().enumerate() {
let score = calc.result.as_ref().unwrap();
if i > 25 {
assert_eq!(score.components.prior_breakdown.mcp_bonus, 5.0);
} else {
assert_eq!(score.components.prior_breakdown.mcp_bonus, 0.0);
}
assert!(score.data_points > 0);
}
let progress_log = progress.lock().unwrap();
assert!(!progress_log.is_empty());
assert!(progress_log.contains(&(50, 50)));
}
#[test]
fn test_compare_agents_with_different_builders() {
let conservative = Calculator::builder()
.preset(CalculatorPreset::Conservative)
.build()
.unwrap();
let aggressive = Calculator::builder()
.preset(CalculatorPreset::Aggressive)
.build()
.unwrap();
let agent_a = AgentDataBuilder::new("did:test:alice")
.with_reviews(30, 4.2)
.total_interactions(40)
.mcp_level(1)
.build()
.unwrap();
let agent_b = AgentDataBuilder::new("did:test:bob")
.with_reviews(30, 4.2)
.total_interactions(40)
.mcp_level(2)
.build()
.unwrap();
let cons_comparison = conservative.compare_agents(&agent_a, &agent_b).unwrap();
let aggr_comparison = aggressive.compare_agents(&agent_a, &agent_b).unwrap();
assert_eq!(cons_comparison.higher_score_agent, "did:test:bob");
assert_eq!(aggr_comparison.higher_score_agent, "did:test:bob");
assert!(cons_comparison.confidence_a < aggr_comparison.confidence_a);
assert!(cons_comparison.confidence_b < aggr_comparison.confidence_b);
}
#[test]
fn test_provisional_scores_in_batch() {
let calc = Calculator::default();
let agents = vec![
AgentDataBuilder::new("did:test:new1")
.with_reviews(1, 5.0)
.total_interactions(1)
.build()
.unwrap(),
AgentDataBuilder::new("did:test:new2")
.build()
.unwrap(),
AgentDataBuilder::new("did:test:established1")
.with_reviews(10, 4.0)
.total_interactions(15)
.build()
.unwrap(),
AgentDataBuilder::new("did:test:established2")
.with_reviews(100, 3.5)
.total_interactions(150)
.build()
.unwrap(),
];
let results = calc.calculate_batch(&agents);
assert!(results[0].as_ref().unwrap().is_provisional);
assert!(results[1].as_ref().unwrap().is_provisional);
assert!(!results[2].as_ref().unwrap().is_provisional);
assert!(!results[3].as_ref().unwrap().is_provisional);
assert_eq!(results[0].as_ref().unwrap().level, ConfidenceLevel::Low);
assert_eq!(results[1].as_ref().unwrap().level, ConfidenceLevel::Low);
assert_eq!(results[2].as_ref().unwrap().level, ConfidenceLevel::Medium);
assert_eq!(results[3].as_ref().unwrap().level, ConfidenceLevel::High);
}
#[test]
fn test_builder_bonus_config_integration() {
let bonuses = BonusConfig {
mcp_bonus_per_level: 3.0, identity_bonus: 2.0,
security_audit_bonus: 4.0,
open_source_bonus: 1.0,
age_bonus: 3.0,
};
let calc = Calculator::builder()
.prior_bonuses(bonuses)
.build()
.unwrap();
let agent = AgentDataBuilder::new("did:test:bonuses")
.with_reviews(50, 4.0)
.total_interactions(60)
.mcp_level(3)
.identity_verified(true)
.security_audit_passed(true)
.open_source(true)
.build()
.unwrap();
let score = calc.calculate(&agent).unwrap();
let breakdown = &score.components.prior_breakdown;
assert_eq!(breakdown.mcp_bonus, 15.0); assert_eq!(breakdown.identity_bonus, 5.0); assert_eq!(breakdown.security_audit_bonus, 7.0); assert_eq!(breakdown.open_source_bonus, 3.0); }
#[test]
fn test_full_phase2_workflow() {
let calc = Calculator::builder()
.confidence_k(20.0)
.prior_base(55.0)
.prior_max(85.0)
.build()
.unwrap();
let agents: Vec<_> = (0..20)
.map(|i| {
let mut builder = AgentDataBuilder::new(&format!("did:test:workflow{}", i))
.total_interactions(i * 7)
.identity_verified(i % 3 == 0);
if i > 0 { builder = builder.with_reviews(i * 5, 3.0 + (i as f64 * 0.1));
}
builder.build().unwrap()
})
.collect();
let progress_count = Arc::new(Mutex::new(0));
let progress_clone = Arc::clone(&progress_count);
let options = BatchOptions {
chunk_size: Some(5),
fail_fast: false,
progress_callback: Some(Box::new(move |completed, _total| {
*progress_clone.lock().unwrap() = completed;
})),
};
let batch_result = calc.calculate_batch_with_options(&agents, options);
assert_eq!(batch_result.successful_count, 20);
assert_eq!(batch_result.failed_count, 0);
let final_progress = *progress_count.lock().unwrap();
assert!(final_progress >= 1 && final_progress <= 20, "Progress count {} should be between 1 and 20", final_progress);
let best_idx = batch_result.calculations
.iter()
.enumerate()
.filter_map(|(i, c)| c.result.as_ref().ok().map(|s| (i, s.score)))
.max_by(|(_, a), (_, b)| a.partial_cmp(b).unwrap())
.map(|(i, _)| i)
.unwrap();
let best_agent = &agents[best_idx];
let explanation = calc.explain_score(best_agent).unwrap();
assert!(explanation.explanation.contains("Prior score: "));
assert!(explanation.breakdown.prior_score >= 55.0);
let current_interactions = best_agent.total_interactions;
let needed = calc.interactions_for_confidence(current_interactions, 0.9).unwrap();
let prediction = calc.predict_score_change(best_agent, needed, 4.5).unwrap();
assert!(prediction.confidence_change > 0.0);
let comparison = calc.compare_agents(&agents[0], best_agent).unwrap();
assert_eq!(comparison.higher_score_agent, best_agent.did);
}