use do_memory_core::SelfLearningMemory;
use do_memory_mcp::mcp::tools::advanced_pattern_analysis::{
AdvancedPatternAnalysisInput, AdvancedPatternAnalysisTool, AnalysisConfig, AnalysisType,
};
use do_memory_mcp::patterns::statistical;
use std::collections::HashMap;
use std::sync::Arc;
use tokio::time::{Duration, timeout};
#[tokio::test]
async fn test_comprehensive_statistical_analysis() {
let memory = Arc::new(SelfLearningMemory::new());
let tool = AdvancedPatternAnalysisTool::new(memory);
let mut data = HashMap::new();
data.insert(
"x".to_string(),
vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0],
);
data.insert(
"y".to_string(),
vec![2.0, 4.0, 6.0, 8.0, 10.0, 12.0, 14.0, 16.0, 18.0, 20.0],
);
data.insert(
"z".to_string(),
vec![1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0],
);
let input = AdvancedPatternAnalysisInput {
analysis_type: AnalysisType::Statistical,
time_series_data: data,
config: Some(AnalysisConfig {
significance_level: Some(0.05),
max_data_points: Some(1000),
parallel_processing: Some(false),
..Default::default()
}),
};
let result = tool.execute(input).await;
assert!(result.is_ok());
let output = result.unwrap();
assert!(output.statistical_results.is_some());
let stats = output.statistical_results.as_ref().unwrap();
assert!(!stats.correlations.is_empty());
let xy_corr = stats
.correlations
.iter()
.find(|c| {
c.variables == ("x".to_string(), "y".to_string())
|| c.variables == ("y".to_string(), "x".to_string())
})
.unwrap();
assert!(xy_corr.significant);
assert!((xy_corr.coefficient - 1.0).abs() < 0.01);
assert!(!stats.trends.is_empty());
let x_trend = stats.trends.iter().find(|t| t.variable == "x").unwrap();
assert!(x_trend.significant);
assert_eq!(x_trend.direction, statistical::TrendDirection::Increasing);
}
#[tokio::test]
async fn test_predictive_analysis_comprehensive() {
let memory = Arc::new(SelfLearningMemory::new());
let tool = AdvancedPatternAnalysisTool::new(memory);
let mut data = HashMap::new();
let mut series = vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0];
series.push(50.0); series.extend(vec![11.0, 12.0, 13.0, 14.0, 15.0]);
data.insert("trendy_with_anomaly".to_string(), series);
let input = AdvancedPatternAnalysisInput {
analysis_type: AnalysisType::Predictive,
time_series_data: data,
config: Some(AnalysisConfig {
forecast_horizon: Some(5),
anomaly_sensitivity: Some(0.3), enable_causal_inference: Some(false), ..Default::default()
}),
};
let result = tool.execute(input).await;
assert!(result.is_ok());
let output = result.unwrap();
assert!(output.predictive_results.is_some());
let pred = output.predictive_results.as_ref().unwrap();
assert!(!pred.forecasts.is_empty());
let forecast = &pred.forecasts[0];
assert_eq!(forecast.variable, "trendy_with_anomaly");
assert_eq!(forecast.point_forecasts.len(), 5);
assert!(!pred.anomalies.is_empty());
let anomaly = &pred.anomalies[0];
assert_eq!(anomaly.variable, "trendy_with_anomaly");
assert!(!anomaly.anomaly_indices.is_empty());
}
#[tokio::test]
async fn test_comprehensive_analysis_integration() {
let memory = Arc::new(SelfLearningMemory::new());
let tool = AdvancedPatternAnalysisTool::new(memory);
let mut data = HashMap::new();
data.insert(
"trend".to_string(),
vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0],
);
data.insert(
"correlated".to_string(),
vec![2.0, 4.0, 6.0, 8.0, 10.0, 12.0, 14.0, 16.0, 18.0, 20.0],
);
data.insert(
"noise".to_string(),
vec![0.5, 1.2, -0.3, 0.8, 1.5, -0.1, 0.9, 1.1, -0.4, 0.6],
);
let input = AdvancedPatternAnalysisInput {
analysis_type: AnalysisType::Comprehensive,
time_series_data: data,
config: Some(AnalysisConfig {
significance_level: Some(0.05),
forecast_horizon: Some(3),
anomaly_sensitivity: Some(0.5),
enable_causal_inference: Some(true),
max_data_points: Some(100),
parallel_processing: Some(false),
}),
};
let result = tool.execute(input).await;
assert!(result.is_ok());
let output = result.unwrap();
assert!(output.statistical_results.is_some());
assert!(output.predictive_results.is_some());
assert_eq!(output.summary.variables_analyzed, 3);
assert!(!output.summary.key_findings.is_empty());
assert!(output.summary.confidence_level > 0.0);
}
#[tokio::test]
async fn test_input_validation_edge_cases() {
let memory = Arc::new(SelfLearningMemory::new());
let tool = AdvancedPatternAnalysisTool::new(memory);
let input_empty = AdvancedPatternAnalysisInput {
analysis_type: AnalysisType::Statistical,
time_series_data: HashMap::new(),
config: None,
};
assert!(tool.validate_input(&input_empty).is_err());
let mut small_data = HashMap::new();
small_data.insert("small".to_string(), vec![1.0, 2.0]);
let input_small = AdvancedPatternAnalysisInput {
analysis_type: AnalysisType::Statistical,
time_series_data: small_data,
config: None,
};
assert!(tool.validate_input(&input_small).is_err());
let mut nan_data = HashMap::new();
nan_data.insert("nan".to_string(), vec![1.0, f64::NAN, 3.0]);
let input_nan = AdvancedPatternAnalysisInput {
analysis_type: AnalysisType::Statistical,
time_series_data: nan_data,
config: None,
};
assert!(tool.validate_input(&input_nan).is_err());
let mut inf_data = HashMap::new();
inf_data.insert("inf".to_string(), vec![1.0, f64::INFINITY, 3.0]);
let input_inf = AdvancedPatternAnalysisInput {
analysis_type: AnalysisType::Statistical,
time_series_data: inf_data,
config: None,
};
assert!(tool.validate_input(&input_inf).is_err());
let mut valid_data = HashMap::new();
valid_data.insert("valid".to_string(), vec![1.0, 2.0, 3.0, 4.0, 5.0]);
let input_invalid_sig = AdvancedPatternAnalysisInput {
analysis_type: AnalysisType::Statistical,
time_series_data: valid_data.clone(),
config: Some(AnalysisConfig {
significance_level: Some(1.5), ..Default::default()
}),
};
assert!(tool.validate_input(&input_invalid_sig).is_err());
let input_invalid_sens = AdvancedPatternAnalysisInput {
analysis_type: AnalysisType::Predictive,
time_series_data: valid_data,
config: Some(AnalysisConfig {
anomaly_sensitivity: Some(-0.1), ..Default::default()
}),
};
assert!(tool.validate_input(&input_invalid_sens).is_err());
}
#[tokio::test]
async fn test_numerical_stability() {
let memory = Arc::new(SelfLearningMemory::new());
let tool = AdvancedPatternAnalysisTool::new(memory);
let mut data = HashMap::new();
data.insert("large".to_string(), vec![1e10, 2e10, 3e10, 4e10, 5e10]);
data.insert("small".to_string(), vec![1e-10, 2e-10, 3e-10, 4e-10, 5e-10]);
data.insert("mixed".to_string(), vec![1e-6, 1e-3, 1.0, 1e3, 1e6]);
let input = AdvancedPatternAnalysisInput {
analysis_type: AnalysisType::Comprehensive,
time_series_data: data,
config: None,
};
let result = tool.execute(input).await;
assert!(
result.is_ok(),
"Analysis should handle extreme values without panicking"
);
let output = result.unwrap();
assert!(output.statistical_results.is_some());
assert!(output.predictive_results.is_some());
}
#[tokio::test]
async fn test_performance_large_dataset() {
let memory = Arc::new(SelfLearningMemory::new());
let tool = AdvancedPatternAnalysisTool::new(memory);
let mut data = HashMap::new();
let large_series: Vec<f64> = (0..500).map(|i| i as f64).collect();
for i in 0..5 {
data.insert(format!("series_{}", i), large_series.clone());
}
let input = AdvancedPatternAnalysisInput {
analysis_type: AnalysisType::Statistical, time_series_data: data,
config: Some(AnalysisConfig {
max_data_points: Some(1000),
parallel_processing: Some(false),
..Default::default()
}),
};
let result = timeout(Duration::from_secs(30), tool.execute(input)).await;
assert!(result.is_ok(), "Analysis should complete within timeout");
assert!(result.unwrap().is_ok());
}
#[tokio::test]
async fn test_memory_extraction_integration() {
let memory = Arc::new(SelfLearningMemory::new());
let tool = AdvancedPatternAnalysisTool::new(memory.clone());
let result = tool
.extract_time_series_from_memory("test query", "test_domain", 10)
.await;
assert!(result.is_err());
}
#[tokio::test]
async fn test_concurrent_execution() {
let memory = Arc::new(SelfLearningMemory::new());
let tools: Vec<_> = (0..5)
.map(|_| AdvancedPatternAnalysisTool::new(memory.clone()))
.collect();
let mut data = HashMap::new();
data.insert("test".to_string(), vec![1.0, 2.0, 3.0, 4.0, 5.0]);
let input = AdvancedPatternAnalysisInput {
analysis_type: AnalysisType::Statistical,
time_series_data: data,
config: None,
};
let tasks: Vec<_> = tools
.into_iter()
.map(|tool| {
let input_clone = input.clone();
tokio::spawn(async move { tool.execute(input_clone).await })
})
.collect();
for task in tasks {
let result = task.await.unwrap();
assert!(result.is_ok());
}
}
#[tokio::test]
async fn test_configuration_parameters() {
let memory = Arc::new(SelfLearningMemory::new());
let tool = AdvancedPatternAnalysisTool::new(memory);
let mut data = HashMap::new();
data.insert(
"test".to_string(),
vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0],
);
let input_minimal = AdvancedPatternAnalysisInput {
analysis_type: AnalysisType::Comprehensive,
time_series_data: data.clone(),
config: Some(AnalysisConfig {
significance_level: Some(0.01), forecast_horizon: Some(1), anomaly_sensitivity: Some(0.1), enable_causal_inference: Some(false), max_data_points: Some(50),
parallel_processing: Some(false),
}),
};
let result = tool.execute(input_minimal).await;
assert!(result.is_ok());
let input_default = AdvancedPatternAnalysisInput {
analysis_type: AnalysisType::Statistical,
time_series_data: data,
config: None,
};
let result_default = tool.execute(input_default).await;
assert!(result_default.is_ok());
}
#[tokio::test]
async fn test_error_handling() {
let memory = Arc::new(SelfLearningMemory::new());
let tool = AdvancedPatternAnalysisTool::new(memory);
let mut problematic_data = HashMap::new();
problematic_data.insert("zeros".to_string(), vec![0.0, 0.0, 0.0, 0.0, 0.0]);
problematic_data.insert(
"large_range".to_string(),
vec![1e-20, 1e-10, 1.0, 1e10, 1e20],
);
let input = AdvancedPatternAnalysisInput {
analysis_type: AnalysisType::Comprehensive,
time_series_data: problematic_data,
config: None,
};
let result = tool.execute(input).await;
match result {
Ok(output) => {
assert!(output.summary.variables_analyzed >= 1);
}
Err(e) => {
assert!(!e.to_string().is_empty());
}
}
}