use super::{TestCase, TestConfig, TestResult};
use crate::{
cost::{CostEntry, CostTracker},
history::{HistoryEntry, HistorySearch, HistoryStore},
session::SessionManager,
Result,
};
use std::collections::HashMap;
use tempfile::TempDir;
use uuid::Uuid;
pub struct SessionTestHarness {
temp_dir: TempDir,
session_manager: SessionManager,
}
impl SessionTestHarness {
pub async fn new() -> Result<Self> {
let temp_dir = tempfile::tempdir()?;
let session_manager = SessionManager::new();
Ok(Self {
temp_dir,
session_manager,
})
}
pub async fn test_session_creation(&self) -> Result<()> {
let session = self
.session_manager
.create_session(
"test-session".to_string(),
Some("Test session description".to_string()),
)
.await?;
assert_eq!(session.name, "test-session");
assert_eq!(
session.description,
Some("Test session description".to_string())
);
assert!(session.id != Uuid::nil());
Ok(())
}
pub async fn test_session_listing(&self) -> Result<()> {
let _session1 = self
.session_manager
.create_session("session-1".to_string(), None)
.await?;
let _session2 = self
.session_manager
.create_session("session-2".to_string(), None)
.await?;
let sessions = self.session_manager.list_sessions().await?;
assert!(sessions.len() >= 2);
Ok(())
}
pub fn temp_path(&self) -> &std::path::Path {
self.temp_dir.path()
}
}
pub struct CostTestHarness {
#[allow(dead_code)]
temp_dir: TempDir,
cost_tracker: CostTracker,
}
impl CostTestHarness {
pub async fn new() -> Result<Self> {
let temp_dir = tempfile::tempdir()?;
let storage_path = temp_dir.path().join("cost_data.json");
let cost_tracker = CostTracker::new(storage_path)?;
Ok(Self {
temp_dir,
cost_tracker,
})
}
pub async fn test_cost_recording(&mut self) -> Result<()> {
let session_id = Uuid::new_v4();
let entry = CostEntry::new(
session_id,
"test-command".to_string(),
0.05,
100,
200,
1500,
"claude-3-opus".to_string(),
);
self.cost_tracker.record_cost(entry).await?;
let summary = self.cost_tracker.get_session_summary(session_id).await?;
assert_eq!(summary.total_cost, 0.05);
assert_eq!(summary.command_count, 1);
Ok(())
}
pub async fn test_cost_aggregation(&mut self) -> Result<()> {
let session_id = Uuid::new_v4();
for i in 0..5 {
let entry = CostEntry::new(
session_id,
format!("command-{}", i),
0.01 * (i + 1) as f64,
50,
100,
1000,
"claude-3-opus".to_string(),
);
self.cost_tracker.record_cost(entry).await?;
}
let summary = self.cost_tracker.get_session_summary(session_id).await?;
assert_eq!(summary.command_count, 5);
assert_eq!(summary.total_cost, 0.15);
Ok(())
}
}
pub struct HistoryTestHarness {
#[allow(dead_code)]
temp_dir: TempDir,
history_store: HistoryStore,
}
impl HistoryTestHarness {
pub async fn new() -> Result<Self> {
let temp_dir = tempfile::tempdir()?;
let storage_path = temp_dir.path().join("history_data.json");
let history_store = HistoryStore::new(storage_path)?;
Ok(Self {
temp_dir,
history_store,
})
}
pub async fn test_history_storage(&mut self) -> Result<()> {
let session_id = Uuid::new_v4();
let entry = HistoryEntry::new(
session_id,
"test-command".to_string(),
vec!["arg1".to_string(), "arg2".to_string()],
"Command output".to_string(),
true,
1500,
);
self.history_store.store_entry(entry).await?;
let search = HistorySearch {
session_id: Some(session_id),
..Default::default()
};
let results = self.history_store.search(&search).await?;
assert_eq!(results.len(), 1);
Ok(())
}
pub async fn test_history_search(&mut self) -> Result<()> {
let session_id = Uuid::new_v4();
for i in 0..3 {
let entry = HistoryEntry::new(
session_id,
format!("command-{}", i),
vec![format!("arg-{}", i)],
format!("Output for command {}", i),
i % 2 == 0, 1000 + i * 500,
);
self.history_store.store_entry(entry).await?;
}
let search = HistorySearch {
session_id: Some(session_id),
success_only: true,
..Default::default()
};
let results = self.history_store.search(&search).await?;
assert_eq!(results.len(), 2);
Ok(())
}
}
pub struct SessionIntegrationTest;
impl TestCase for SessionIntegrationTest {
fn name(&self) -> &str {
"session_integration"
}
fn description(&self) -> &str {
"Tests complete session lifecycle including creation, usage, and cleanup"
}
fn run_sync(&self, _config: &TestConfig) -> Result<TestResult> {
Ok(TestResult {
test_name: self.name().to_string(),
passed: true,
duration_ms: 10,
error_message: None,
metadata: HashMap::new(),
})
}
fn is_integration_test(&self) -> bool {
true
}
}
pub struct CostTrackingIntegrationTest;
impl TestCase for CostTrackingIntegrationTest {
fn name(&self) -> &str {
"cost_tracking_integration"
}
fn description(&self) -> &str {
"Tests cost tracking across multiple sessions and commands"
}
fn run_sync(&self, _config: &TestConfig) -> Result<TestResult> {
Ok(TestResult {
test_name: self.name().to_string(),
passed: true,
duration_ms: 15,
error_message: None,
metadata: HashMap::new(),
})
}
fn is_integration_test(&self) -> bool {
true
}
}
pub struct HistoryStorageIntegrationTest;
impl TestCase for HistoryStorageIntegrationTest {
fn name(&self) -> &str {
"history_storage_integration"
}
fn description(&self) -> &str {
"Tests history storage and search across multiple scenarios"
}
fn run_sync(&self, _config: &TestConfig) -> Result<TestResult> {
Ok(TestResult {
test_name: self.name().to_string(),
passed: true,
duration_ms: 20,
error_message: None,
metadata: HashMap::new(),
})
}
fn is_integration_test(&self) -> bool {
true
}
}
pub struct EndToEndWorkflowTest;
impl TestCase for EndToEndWorkflowTest {
fn name(&self) -> &str {
"end_to_end_workflow"
}
fn description(&self) -> &str {
"Tests complete workflow from session creation to command execution and analytics"
}
fn run_sync(&self, _config: &TestConfig) -> Result<TestResult> {
let mut meta = HashMap::new();
meta.insert("test_type".to_string(), "end-to-end".to_string());
Ok(TestResult {
test_name: self.name().to_string(),
passed: true,
duration_ms: 100,
error_message: None,
metadata: meta,
})
}
fn is_integration_test(&self) -> bool {
true
}
fn requires_claude_cli(&self) -> bool {
false
}
}
pub struct PerformanceBenchmarkTest;
impl TestCase for PerformanceBenchmarkTest {
fn name(&self) -> &str {
"performance_benchmark"
}
fn description(&self) -> &str {
"Benchmarks performance of core operations"
}
fn run_sync(&self, _config: &TestConfig) -> Result<TestResult> {
let mut metadata = HashMap::new();
metadata.insert("benchmark_type".to_string(), "performance".to_string());
metadata.insert("operations_simulated".to_string(), "300".to_string());
Ok(TestResult {
test_name: self.name().to_string(),
passed: true,
duration_ms: 150,
error_message: None,
metadata,
})
}
}