pub trait EventCodec<T> {
fn encode(&self, envelope: &super::CloudEventsEnvelope<T>)
-> crate::HexResult<std::vec::Vec<u8>>;
fn decode(&self, bytes: &[u8]) -> crate::HexResult<super::CloudEventsEnvelope<T>>;
}
#[cfg(test)]
mod tests {
use super::*;
struct TestEvent {
id: std::string::String,
value: std::string::String,
}
impl crate::domain::DomainEvent for TestEvent {
fn event_type(&self) -> &str {
"com.test.event"
}
fn aggregate_id(&self) -> std::string::String {
self.id.clone()
}
}
struct MockCodec;
impl EventCodec<TestEvent> for MockCodec {
fn encode(
&self,
envelope: &super::super::CloudEventsEnvelope<TestEvent>,
) -> crate::HexResult<std::vec::Vec<u8>> {
envelope.validate()?;
let mut parts = std::vec::Vec::new();
parts.push(envelope.id.clone());
parts.push(envelope.source.clone());
parts.push(envelope.r#type.clone());
if let std::option::Option::Some(ref subject) = envelope.subject {
parts.push(subject.clone());
} else {
parts.push(std::string::String::from(""));
}
let encoded = parts.join("|");
std::result::Result::Ok(encoded.into_bytes())
}
fn decode(
&self,
bytes: &[u8],
) -> crate::HexResult<super::super::CloudEventsEnvelope<TestEvent>> {
let string = std::string::String::from_utf8(bytes.to_vec())
.map_err(|_| crate::Hexserror::validation("Invalid UTF-8"))?;
let parts: std::vec::Vec<&str> = string.split('|').collect();
if parts.len() < 4 {
return std::result::Result::Err(crate::Hexserror::validation("Invalid format"));
}
let mut envelope = super::super::CloudEventsEnvelope::new(
std::string::String::from(parts[0]),
std::string::String::from(parts[1]),
std::string::String::from(parts[2]),
);
if !parts[3].is_empty() {
envelope.subject = std::option::Option::Some(std::string::String::from(parts[3]));
}
std::result::Result::Ok(envelope)
}
}
#[test]
fn test_encode_creates_bytes() {
let codec = MockCodec;
let event = TestEvent {
id: std::string::String::from("test-123"),
value: std::string::String::from("test value"),
};
let envelope = super::super::CloudEventsEnvelope::from_domain_event(
std::string::String::from("evt-001"),
std::string::String::from("/test/source"),
event,
);
let result = codec.encode(&envelope);
std::assert!(result.is_ok());
let bytes = result.unwrap();
std::assert!(!bytes.is_empty());
}
#[test]
fn test_decode_reconstructs_envelope() {
let codec = MockCodec;
let original = super::super::CloudEventsEnvelope::<TestEvent>::new(
std::string::String::from("evt-001"),
std::string::String::from("/test/source"),
std::string::String::from("com.test.event"),
);
let bytes = codec.encode(&original).unwrap();
let decoded = codec.decode(&bytes).unwrap();
std::assert_eq!(decoded.id, original.id);
std::assert_eq!(decoded.source, original.source);
std::assert_eq!(decoded.r#type, original.r#type);
}
#[test]
fn test_encode_decode_roundtrip() {
let codec = MockCodec;
let event = TestEvent {
id: std::string::String::from("test-456"),
value: std::string::String::from("roundtrip test"),
};
let original = super::super::CloudEventsEnvelope::from_domain_event(
std::string::String::from("evt-roundtrip"),
std::string::String::from("/roundtrip/source"),
event,
);
let bytes = codec.encode(&original).unwrap();
let decoded = codec.decode(&bytes).unwrap();
std::assert_eq!(decoded.id, original.id);
std::assert_eq!(decoded.source, original.source);
std::assert_eq!(decoded.r#type, original.r#type);
std::assert_eq!(decoded.subject, original.subject);
}
#[test]
fn test_encode_validates_envelope() {
let codec = MockCodec;
let envelope = super::super::CloudEventsEnvelope::<TestEvent>::new(
std::string::String::from(""),
std::string::String::from("/test/source"),
std::string::String::from("com.test.event"),
);
let result = codec.encode(&envelope);
std::assert!(result.is_err());
}
#[test]
fn test_decode_rejects_invalid_format() {
let codec = MockCodec;
let invalid_bytes = b"invalid";
let result = codec.decode(invalid_bytes);
std::assert!(result.is_err());
}
#[test]
fn test_decode_rejects_invalid_utf8() {
let codec = MockCodec;
let invalid_bytes = vec![0xFF, 0xFE, 0xFD];
let result = codec.decode(&invalid_bytes);
std::assert!(result.is_err());
}
}