Files
dirigate/tests/fixture_loader_tests.rs
T
g4borg c62d8daea8 chore: rename packages/ to crates/
Move all 29 workspace members from packages/<name>/ to crates/<name>/.
Updates: workspace Cargo.toml (members + path deps), justfile, root
CLAUDE.md, scripts/build/CARGO_INSTALL.md, docs/architecture/crates.md
(renamed from packages.md), structural references in docs/architecture
and docs/configuration, per-crate CLAUDE.md self-references. Historical
plans, reports, and building/ docs are left untouched.

No behavior change; just check-all stays green and fermata tests pass.
2026-04-30 21:58:57 +02:00

279 lines
9.1 KiB
Rust

//! 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);
}