NAC_Blockchain/nac-ai-valuation/tests/integration_tests.rs

552 lines
16 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//! NAC AI估值系统集成测试
//!
//! 测试所有模块的集成和端到端功能
use nac_ai_valuation::*;
use rust_decimal::Decimal;
use std::collections::HashMap;
/// 创建测试资产
fn create_test_asset() -> Asset {
Asset::new(
"test_asset_001".to_string(),
AssetType::RealEstate,
"GNACS-RE-001".to_string(),
"Manhattan Office Building".to_string(),
Decimal::new(50_000_000, 0),
"USD".to_string(),
)
}
/// 创建测试估值结果
fn create_test_valuation_result() -> FinalValuationResult {
FinalValuationResult {
valuation_xtzh: Decimal::new(500_000, 0),
confidence: 0.85,
model_results: vec![],
weights: HashMap::new(),
is_anomaly: false,
anomaly_report: None,
divergence_report: "Test divergence report".to_string(),
requires_human_review: false,
}
}
#[test]
fn test_asset_creation() {
let asset = create_test_asset();
assert_eq!(asset.id, "test_asset_001");
assert_eq!(asset.asset_type, AssetType::RealEstate);
assert_eq!(asset.gnacs_code, "GNACS-RE-001");
assert_eq!(asset.base_valuation_local, Decimal::new(50_000_000, 0));
}
#[test]
fn test_jurisdiction_info() {
let us_info = Jurisdiction::US.info();
assert_eq!(us_info.code, Jurisdiction::US);
assert!(us_info.corporate_tax_rate > 0.0);
let china_info = Jurisdiction::China.info();
assert_eq!(china_info.code, Jurisdiction::China);
assert!(china_info.corporate_tax_rate > 0.0);
}
#[test]
fn test_international_agreement_info() {
let wto_info = InternationalAgreement::WTO.info();
assert_eq!(wto_info.name, "世界贸易组织");
let rcep_info = InternationalAgreement::RCEP.info();
assert_eq!(rcep_info.name, "区域全面经济伙伴关系协定");
}
#[test]
fn test_valuation_history() {
let mut history = ValuationHistory::new(100);
let entry = ValuationHistoryEntry::new(
"test_asset_001".to_string(),
Jurisdiction::US,
InternationalAgreement::WTO,
create_test_valuation_result(),
);
history.add(entry.clone()).expect("mainnet: handle error");
let entries = history.get_by_asset("test_asset_001");
assert_eq!(entries.len(), 1);
assert_eq!(entries[0].asset_id, "test_asset_001");
}
#[test]
fn test_trend_analysis() {
let entries = vec![
ValuationHistoryEntry::new(
"test_asset_001".to_string(),
Jurisdiction::US,
InternationalAgreement::WTO,
FinalValuationResult {
valuation_xtzh: Decimal::new(1_000_000, 0),
confidence: 0.85,
model_results: vec![],
weights: HashMap::new(),
is_anomaly: false,
anomaly_report: None,
divergence_report: "Test".to_string(),
requires_human_review: false,
},
),
ValuationHistoryEntry::new(
"test_asset_001".to_string(),
Jurisdiction::US,
InternationalAgreement::WTO,
FinalValuationResult {
valuation_xtzh: Decimal::new(1_100_000, 0),
confidence: 0.88,
model_results: vec![],
weights: HashMap::new(),
is_anomaly: false,
anomaly_report: None,
divergence_report: "Test".to_string(),
requires_human_review: false,
},
),
ValuationHistoryEntry::new(
"test_asset_001".to_string(),
Jurisdiction::US,
InternationalAgreement::WTO,
FinalValuationResult {
valuation_xtzh: Decimal::new(1_200_000, 0),
confidence: 0.90,
model_results: vec![],
weights: HashMap::new(),
is_anomaly: false,
anomaly_report: None,
divergence_report: "Test".to_string(),
requires_human_review: false,
},
),
];
let trend = TrendAnalyzer::analyze(&entries).expect("mainnet: handle error");
assert_eq!(trend.data_points, 3);
assert!(trend.change_rate > 0.0); // 上升趋势
// 趋势可能是Upward或Volatile取决于标准差
assert!(trend.trend_direction == TrendDirection::Upward || trend.trend_direction == TrendDirection::Volatile);
}
#[test]
fn test_validation_rules() {
let validator = ValuationValidator::with_default_rules();
let result = FinalValuationResult {
valuation_xtzh: Decimal::new(1_000_000, 0),
confidence: 0.85,
model_results: vec![],
weights: HashMap::new(),
is_anomaly: false,
anomaly_report: None,
divergence_report: "Test".to_string(),
requires_human_review: false,
};
let validation_results = validator.validate(&result);
assert!(!validation_results.is_empty());
// 应该通过所有默认验证
let all_passed = validator.validate_all(&result);
assert!(all_passed);
}
#[test]
fn test_validation_failure() {
let validator = ValuationValidator::with_default_rules();
// 置信度过低的结果
let result = FinalValuationResult {
valuation_xtzh: Decimal::new(1_000_000, 0),
confidence: 0.3, // 低于默认的0.5
model_results: vec![],
weights: HashMap::new(),
is_anomaly: false,
anomaly_report: None,
divergence_report: "Test".to_string(),
requires_human_review: false,
};
let all_passed = validator.validate_all(&result);
assert!(!all_passed);
}
#[test]
fn test_accuracy_evaluation() {
let metrics = AccuracyEvaluator::evaluate(
Decimal::new(1_000_000, 0),
Decimal::new(1_100_000, 0),
);
assert_eq!(metrics.estimated, Decimal::new(1_000_000, 0));
assert_eq!(metrics.actual, Decimal::new(1_100_000, 0));
assert!(metrics.relative_error > 9.0 && metrics.relative_error < 10.0);
assert!(metrics.accuracy > 90.0);
}
#[test]
fn test_batch_accuracy_evaluation() {
let pairs = vec![
(Decimal::new(1_000_000, 0), Decimal::new(1_100_000, 0)),
(Decimal::new(2_000_000, 0), Decimal::new(2_050_000, 0)),
(Decimal::new(3_000_000, 0), Decimal::new(2_900_000, 0)),
];
let batch_metrics = AccuracyEvaluator::evaluate_batch(pairs);
assert_eq!(batch_metrics.total_samples, 3);
assert!(batch_metrics.avg_accuracy > 90.0);
}
#[test]
fn test_divergence_analysis() {
use chrono::Utc;
let model_results = vec![
AIValuationResult {
provider: AIProvider::ChatGPT,
valuation_xtzh: Decimal::new(1_000_000, 0),
confidence: 0.85,
reasoning: "ChatGPT reasoning".to_string(),
timestamp: Utc::now(),
},
AIValuationResult {
provider: AIProvider::DeepSeek,
valuation_xtzh: Decimal::new(1_100_000, 0),
confidence: 0.88,
reasoning: "DeepSeek reasoning".to_string(),
timestamp: Utc::now(),
},
AIValuationResult {
provider: AIProvider::DouBao,
valuation_xtzh: Decimal::new(1_050_000, 0),
confidence: 0.82,
reasoning: "DouBao reasoning".to_string(),
timestamp: Utc::now(),
},
];
let analysis = DivergenceAnalyzer::analyze(&model_results);
assert_eq!(analysis.model_count, 3);
assert_eq!(analysis.min_valuation, Decimal::new(1_000_000, 0));
assert_eq!(analysis.max_valuation, Decimal::new(1_100_000, 0));
assert!(analysis.divergence_rate < 15.0);
assert!(analysis.consistency_score > 85.0);
}
#[test]
fn test_divergence_with_outlier() {
use chrono::Utc;
let model_results = vec![
AIValuationResult {
provider: AIProvider::ChatGPT,
valuation_xtzh: Decimal::new(1_000_000, 0),
confidence: 0.85,
reasoning: "ChatGPT reasoning".to_string(),
timestamp: Utc::now(),
},
AIValuationResult {
provider: AIProvider::DeepSeek,
valuation_xtzh: Decimal::new(1_050_000, 0),
confidence: 0.88,
reasoning: "DeepSeek reasoning".to_string(),
timestamp: Utc::now(),
},
AIValuationResult {
provider: AIProvider::DouBao,
valuation_xtzh: Decimal::new(2_000_000, 0), // 异常值
confidence: 0.82,
reasoning: "DouBao reasoning".to_string(),
timestamp: Utc::now(),
},
];
let analysis = DivergenceAnalyzer::analyze(&model_results);
assert_eq!(analysis.model_count, 3);
assert!(analysis.divergence_rate > 50.0);
assert!(!analysis.outliers.is_empty());
assert!(analysis.outliers.contains(&AIProvider::DouBao));
}
#[test]
fn test_optimization_suggestions() {
use chrono::Utc;
let model_results = vec![
AIValuationResult {
provider: AIProvider::ChatGPT,
valuation_xtzh: Decimal::new(1_000_000, 0),
confidence: 0.85,
reasoning: "Test".to_string(),
timestamp: Utc::now(),
},
AIValuationResult {
provider: AIProvider::DeepSeek,
valuation_xtzh: Decimal::new(2_000_000, 0),
confidence: 0.88,
reasoning: "Test".to_string(),
timestamp: Utc::now(),
},
];
let result = FinalValuationResult {
valuation_xtzh: Decimal::new(1_500_000, 0),
confidence: 0.60,
model_results: model_results.clone(),
weights: HashMap::new(),
is_anomaly: false,
anomaly_report: None,
divergence_report: "Test".to_string(),
requires_human_review: false,
};
let divergence = DivergenceAnalyzer::analyze(&model_results);
let suggestions = ModelOptimizer::generate_suggestions(&result, &divergence);
assert!(!suggestions.is_empty());
}
#[test]
fn test_cache_operations() {
let cache = ValuationCache::new(10);
let result = create_test_valuation_result();
// 设置缓存
cache.set(
"test_asset_001",
Jurisdiction::US,
InternationalAgreement::WTO,
result.clone(),
);
// 获取缓存
let cached = cache.get(
"test_asset_001",
Jurisdiction::US,
InternationalAgreement::WTO,
);
assert!(cached.is_some());
assert_eq!(cached.expect("mainnet: handle error").valuation_xtzh, result.valuation_xtzh);
// 统计
let stats = cache.stats();
assert_eq!(stats.total_entries, 1);
assert_eq!(stats.total_accesses, 1);
}
#[test]
fn test_cache_expiry() {
let cache = ValuationCache::new(10);
let result = create_test_valuation_result();
cache.set(
"test_asset_001",
Jurisdiction::US,
InternationalAgreement::WTO,
result,
);
// 清除过期缓存(刚设置的不会过期)
cache.clear_expired();
let stats = cache.stats();
assert_eq!(stats.total_entries, 1);
assert_eq!(stats.expired_entries, 0);
}
#[test]
fn test_realtime_data_source() {
let data_source = RealtimeDataSource::new();
assert_eq!(data_source.xtzh_price_usd, Decimal::new(100, 0));
assert!(!data_source.is_stale());
}
#[test]
fn test_final_valuation_result_report() {
let result = create_test_valuation_result();
let report = result.generate_report();
assert!(report.contains("NAC AI资产估值报告"));
assert!(report.contains("500000 XTZH"));
assert!(report.contains("85.0%"));
}
#[test]
fn test_final_valuation_result_json() {
let result = create_test_valuation_result();
let json = result.to_json().expect("mainnet: handle error");
assert!(json.contains("valuation_xtzh"));
assert!(json.contains("confidence"));
assert!(json.contains("500000"));
}
#[test]
fn test_data_export_json() {
use std::path::Path;
let entries = vec![
ValuationHistoryEntry::new(
"test_asset_001".to_string(),
Jurisdiction::US,
InternationalAgreement::WTO,
create_test_valuation_result(),
),
];
let path = Path::new("/tmp/test_valuation_export.json");
let result = DataExporter::export_json(&entries, path);
assert!(result.is_ok());
// 验证文件存在
assert!(path.exists());
}
#[test]
fn test_data_export_csv() {
use std::path::Path;
let entries = vec![
ValuationHistoryEntry::new(
"test_asset_001".to_string(),
Jurisdiction::US,
InternationalAgreement::WTO,
create_test_valuation_result(),
),
];
let path = Path::new("/tmp/test_valuation_export.csv");
let result = DataExporter::export_csv(&entries, path);
assert!(result.is_ok());
// 验证文件存在
assert!(path.exists());
}
#[test]
fn test_data_export_markdown() {
use std::path::Path;
let entries = vec![
ValuationHistoryEntry::new(
"test_asset_001".to_string(),
Jurisdiction::US,
InternationalAgreement::WTO,
create_test_valuation_result(),
),
];
let trend = TrendAnalyzer::analyze(&entries).expect("mainnet: handle error");
let path = Path::new("/tmp/test_valuation_export.md");
let result = DataExporter::export_markdown(&entries, &trend, path);
assert!(result.is_ok());
// 验证文件存在
assert!(path.exists());
}
#[tokio::test]
#[ignore] // 需要真实的API密钥
async fn test_full_valuation_flow() {
// 创建估值引擎
let engine = ValuationEngine::new(
std::env::var("CHATGPT_API_KEY").unwrap_or("test_key".to_string()),
std::env::var("DEEPSEEK_API_KEY").unwrap_or("test_key".to_string()),
std::env::var("DOUBAO_API_KEY").unwrap_or("test_key".to_string()),
ValuationEngineConfig::default(),
).expect("mainnet: handle error");
// 创建资产
let asset = create_test_asset();
// 执行估值
let result = engine.appraise(
&asset,
Jurisdiction::US,
InternationalAgreement::WTO,
).await;
// 验证结果
if let Ok(result) = result {
assert!(result.valuation_xtzh > Decimal::ZERO);
assert!(result.confidence >= 0.0 && result.confidence <= 1.0);
assert!(!result.model_results.is_empty());
}
}
#[test]
fn test_all_asset_types() {
let types = vec![
AssetType::RealEstate,
AssetType::Commodity,
AssetType::FinancialAsset,
AssetType::DigitalAsset,
AssetType::IntellectualProperty,
AssetType::ArtCollectible,
AssetType::Movable,
AssetType::Receivable,
AssetType::Infrastructure,
AssetType::NaturalResource,
AssetType::ESGAsset,
AssetType::Other,
];
assert_eq!(types.len(), 12);
}
#[test]
fn test_all_jurisdictions() {
let jurisdictions = vec![
Jurisdiction::US,
Jurisdiction::EU,
Jurisdiction::China,
Jurisdiction::HongKong,
Jurisdiction::SG,
Jurisdiction::UK,
Jurisdiction::JP,
Jurisdiction::ME,
];
assert_eq!(jurisdictions.len(), 8);
// 验证每个辖区都有有效信息
for jurisdiction in jurisdictions {
let info = jurisdiction.info();
assert!(info.corporate_tax_rate >= 0.0);
assert!(info.corporate_tax_rate >= 0.0);
}
}
#[test]
fn test_all_agreements() {
let agreements = vec![
InternationalAgreement::EU,
InternationalAgreement::WTO,
InternationalAgreement::SCO,
InternationalAgreement::RCEP,
InternationalAgreement::CPTPP,
InternationalAgreement::USMCA,
InternationalAgreement::AfCFTA,
InternationalAgreement::None,
];
assert_eq!(agreements.len(), 8);
// 验证每个协定都有有效信息
for agreement in agreements {
let info = agreement.info();
assert!(!info.name.is_empty());
}
}