//! Integration tests for fixture loading and validation. use dirigate::fixture::{load_and_validate, load_fixture, load_fixtures_from_dir, validate_fixture}; use std::path::PathBuf; fn test_fixture_path(name: &str) -> PathBuf { PathBuf::from(env!("CARGO_MANIFEST_DIR")) .join("tests") .join("fixtures") .join(name) } #[tokio::test] async fn test_load_valid_basic_fixture() { let path = test_fixture_path("valid_basic.yaml"); let fixture = load_fixture(&path).await.expect("Failed to load fixture"); assert_eq!(fixture.version, "0.1"); assert_eq!(fixture.sessions.len(), 1); assert_eq!(fixture.sessions[0].id, "session-1"); assert_eq!(fixture.sessions[0].title, "Basic Test Session"); assert_eq!(fixture.sessions[0].participants.len(), 2); assert_eq!(fixture.sessions[0].messages.len(), 2); } #[tokio::test] async fn test_load_valid_complex_fixture() { let path = test_fixture_path("valid_complex.yaml"); let fixture = load_fixture(&path).await.expect("Failed to load fixture"); assert_eq!(fixture.version, "0.1"); assert_eq!(fixture.sessions.len(), 2); // Check first session let session1 = &fixture.sessions[0]; assert_eq!(session1.id, "session-chat"); assert_eq!(session1.participants.len(), 3); assert_eq!(session1.messages.len(), 4); // Check message metadata let msg3 = &session1.messages[2]; assert!(msg3.metadata.is_some()); // Check second session with behavior override let session2 = &fixture.sessions[1]; assert_eq!(session2.id, "session-debug"); assert!(session2.behavior.is_some()); // Check responders config assert_eq!(fixture.responders.keyword_map.len(), 2); assert!(fixture.responders.random.is_some()); } #[tokio::test] async fn test_validate_valid_basic_fixture() { let path = test_fixture_path("valid_basic.yaml"); let fixture = load_fixture(&path).await.expect("Failed to load fixture"); // Should validate successfully validate_fixture(&fixture).expect("Fixture validation failed"); } #[tokio::test] async fn test_validate_valid_complex_fixture() { let path = test_fixture_path("valid_complex.yaml"); let fixture = load_fixture(&path).await.expect("Failed to load fixture"); // Should validate successfully validate_fixture(&fixture).expect("Fixture validation failed"); } #[tokio::test] async fn test_load_and_validate_valid() { let path = test_fixture_path("valid_basic.yaml"); let fixture = load_and_validate(&path).await.expect("Failed to load and validate"); assert_eq!(fixture.version, "0.1"); } #[tokio::test] async fn test_load_invalid_version() { let path = test_fixture_path("invalid_version.yaml"); let fixture = load_fixture(&path).await.expect("Failed to load fixture"); let result = validate_fixture(&fixture); assert!(result.is_err()); let err = result.unwrap_err(); assert!(err.to_string().contains("Invalid version")); } #[tokio::test] async fn test_load_and_validate_invalid_version() { let path = test_fixture_path("invalid_version.yaml"); let result = load_and_validate(&path).await; assert!(result.is_err()); let err = result.unwrap_err(); assert!(err.to_string().contains("Invalid version")); } #[tokio::test] async fn test_validate_duplicate_session_ids() { let path = test_fixture_path("invalid_duplicate_session.yaml"); let fixture = load_fixture(&path).await.expect("Failed to load fixture"); let result = validate_fixture(&fixture); assert!(result.is_err()); let err = result.unwrap_err(); assert!(err.to_string().contains("Duplicate session ID")); } #[tokio::test] async fn test_load_bad_yaml() { let path = test_fixture_path("invalid_bad_yaml.yaml"); let result = load_fixture(&path).await; assert!(result.is_err()); let err = result.unwrap_err(); assert!(err.to_string().contains("Failed to parse YAML")); } #[tokio::test] async fn test_validate_bad_timestamp() { let path = test_fixture_path("invalid_bad_timestamp.yaml"); let fixture = load_fixture(&path).await.expect("Failed to load fixture"); let result = validate_fixture(&fixture); assert!(result.is_err()); let err = result.unwrap_err(); assert!(err.to_string().contains("invalid ISO8601 timestamp")); } #[tokio::test] async fn test_load_nonexistent_file() { let path = test_fixture_path("does_not_exist.yaml"); let result = load_fixture(&path).await; assert!(result.is_err()); let err = result.unwrap_err(); assert!(err.to_string().contains("Failed to read file")); } #[tokio::test] async fn test_load_fixtures_from_directory() { let dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")) .join("tests") .join("fixtures"); let fixtures = load_fixtures_from_dir(&dir).await.expect("Failed to load fixtures from directory"); // Should load the 2 valid fixtures, skipping the invalid ones assert_eq!(fixtures.len(), 2); // Verify we got the right fixtures let ids: Vec<_> = fixtures.iter() .flat_map(|f| f.sessions.iter().map(|s| s.id.as_str())) .collect(); assert!(ids.contains(&"session-1") || ids.contains(&"session-chat")); } #[tokio::test] async fn test_load_fixtures_from_empty_directory() { // Create a temporary empty directory let temp_dir = std::env::temp_dir().join("dirigent_test_empty"); tokio::fs::create_dir_all(&temp_dir).await.ok(); let fixtures = load_fixtures_from_dir(&temp_dir).await.expect("Failed to load from empty directory"); // Should return empty vector, not error assert_eq!(fixtures.len(), 0); // Cleanup tokio::fs::remove_dir_all(&temp_dir).await.ok(); } #[tokio::test] async fn test_message_parent_references() { let path = test_fixture_path("valid_basic.yaml"); let fixture = load_and_validate(&path).await.expect("Failed to load fixture"); // Check that parent_id references are valid let session = &fixture.sessions[0]; let msg2 = &session.messages[1]; assert_eq!(msg2.parent_id, Some("msg-1".to_string())); } #[tokio::test] async fn test_session_behavior_overrides() { let path = test_fixture_path("valid_complex.yaml"); let fixture = load_and_validate(&path).await.expect("Failed to load fixture"); // Second session should have behavior overrides let session2 = &fixture.sessions[1]; assert!(session2.behavior.is_some()); let behavior = session2.behavior.as_ref().unwrap(); assert!(behavior.responder.is_some()); assert!(behavior.streaming.is_some()); } #[tokio::test] async fn test_participant_kinds() { use dirigate::fixture::ParticipantKind; let path = test_fixture_path("valid_complex.yaml"); let fixture = load_and_validate(&path).await.expect("Failed to load fixture"); let session = &fixture.sessions[0]; let participant_kinds: Vec<_> = session.participants.iter() .map(|p| &p.kind) .collect(); assert!(participant_kinds.contains(&&ParticipantKind::User)); assert!(participant_kinds.contains(&&ParticipantKind::Assistant)); assert!(participant_kinds.contains(&&ParticipantKind::System)); } #[tokio::test] async fn test_message_roles() { use dirigate::fixture::MessageRole; let path = test_fixture_path("valid_basic.yaml"); let fixture = load_and_validate(&path).await.expect("Failed to load fixture"); let messages = &fixture.sessions[0].messages; assert_eq!(messages[0].role, MessageRole::User); assert_eq!(messages[1].role, MessageRole::Assistant); } #[tokio::test] async fn test_responder_strategies() { use dirigate::fixture::ResponderStrategy; let path = test_fixture_path("valid_basic.yaml"); let fixture = load_and_validate(&path).await.expect("Failed to load fixture"); assert_eq!(fixture.responders.default_strategy, ResponderStrategy::Echo); let path2 = test_fixture_path("valid_complex.yaml"); let fixture2 = load_and_validate(&path2).await.expect("Failed to load fixture"); assert_eq!(fixture2.responders.default_strategy, ResponderStrategy::Keywords); } #[tokio::test] async fn test_streaming_configuration() { let path = test_fixture_path("valid_basic.yaml"); let fixture = load_and_validate(&path).await.expect("Failed to load fixture"); assert!(fixture.streaming.enabled); assert_eq!(fixture.streaming.tokens_per_chunk, 5); assert_eq!(fixture.streaming.chunk_interval_ms, 100); assert_eq!(fixture.streaming.jitter_ms, Some(20)); } #[tokio::test] async fn test_keyword_map() { let path = test_fixture_path("valid_basic.yaml"); let fixture = load_and_validate(&path).await.expect("Failed to load fixture"); assert_eq!(fixture.responders.keyword_map.get("hello"), Some(&"Hi there!".to_string())); assert_eq!(fixture.responders.keyword_map.get("help"), Some(&"I can assist you with various tasks.".to_string())); } #[tokio::test] async fn test_random_config() { let path = test_fixture_path("valid_complex.yaml"); let fixture = load_and_validate(&path).await.expect("Failed to load fixture"); let random_config = fixture.responders.random.as_ref().expect("Missing random config"); assert_eq!(random_config.seed, 42); assert_eq!(random_config.corpus.len(), 3); }