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.
This commit is contained in:
@@ -0,0 +1,278 @@
|
||||
//! 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);
|
||||
}
|
||||
Reference in New Issue
Block a user