diff --git a/lib/foundation/fabro-api/tests/workflow_version_round_trip.rs b/lib/foundation/fabro-api/tests/workflow_version_round_trip.rs index 894c1c910..3bf0c8835 100644 --- a/lib/foundation/fabro-api/tests/workflow_version_round_trip.rs +++ b/lib/foundation/fabro-api/tests/workflow_version_round_trip.rs @@ -1,12 +1,14 @@ use std::any::{TypeId, type_name}; use fabro_api::types::{ - WorkflowPath as ApiWorkflowPath, WorkflowVersion as ApiWorkflowVersion, - WorkflowVersionId as ApiWorkflowVersionId, + CreateWorkflowVersionResponse, WorkflowPath as ApiWorkflowPath, + WorkflowVersion as ApiWorkflowVersion, WorkflowVersionId as ApiWorkflowVersionId, }; use fabro_types::{WorkflowPath, WorkflowVersion, WorkflowVersionId}; use serde_json::json; +const DEPENDENCY_ID: &str = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"; + #[test] fn workflow_version_schemas_reuse_domain_types() { assert_same_type::(); @@ -22,13 +24,38 @@ fn workflow_version_round_trips_exact_wire_shape() { "prompts/goal.md": "Ship it", "workflow.fabro": "digraph W { start [shape=Mdiamond] exit [shape=Msquare] start -> exit }" }, - "workflow_dependencies": {} + "workflow_dependencies": { "children/check.fabro": DEPENDENCY_ID } }); let version: ApiWorkflowVersion = serde_json::from_value(value.clone()).unwrap(); assert_eq!(serde_json::to_value(version).unwrap(), value); } +#[test] +fn create_workflow_version_response_round_trips_exact_wire_shape() { + let value = json!({ "workflow_version_id": DEPENDENCY_ID }); + + let response: CreateWorkflowVersionResponse = serde_json::from_value(value.clone()).unwrap(); + assert_eq!(serde_json::to_value(&response).unwrap(), value); +} + +#[test] +fn workflow_version_id_emits_the_documented_lowercase_pattern() { + // Input is accepted case-insensitively, but serialization must match the + // OpenAPI schema pattern `^[0-9a-f]{64}$`. + let id = serde_json::from_value::(json!(DEPENDENCY_ID.to_uppercase())) + .unwrap(); + let emitted = serde_json::to_value(id).unwrap(); + assert_eq!(emitted, json!(DEPENDENCY_ID)); + + let text = emitted.as_str().unwrap(); + assert_eq!(text.len(), 64); + assert!( + text.bytes() + .all(|byte| matches!(byte, b'0'..=b'9' | b'a'..=b'f')) + ); +} + #[test] fn workflow_version_replacement_rejects_unknown_fields() { let value = json!({