use wireframe::message_assembler::{AssembledMessage, MessageAssemblyError, MessageKey};
use super::{
assert_helpers::{assert_body_eq, assert_usize_field},
message_error::{MessageAssemblyErrorExpectation, matches_message_error},
};
use crate::integration_helpers::TestResult;
#[derive(Clone, Copy, Debug)]
pub struct MessageAssemblySnapshot<'a> {
last_result: Option<&'a Result<Option<AssembledMessage>, MessageAssemblyError>>,
completed_messages: &'a [AssembledMessage],
evicted_keys: &'a [MessageKey],
buffered_count: usize,
total_buffered_bytes: usize,
}
impl<'a> MessageAssemblySnapshot<'a> {
#[must_use]
pub fn new(
last_result: Option<&'a Result<Option<AssembledMessage>, MessageAssemblyError>>,
completed_messages: &'a [AssembledMessage],
evicted_keys: &'a [MessageKey],
buffered_count: usize,
total_buffered_bytes: usize,
) -> Self {
Self {
last_result,
completed_messages,
evicted_keys,
buffered_count,
total_buffered_bytes,
}
}
#[must_use]
pub fn last_completed(&self) -> Option<&'a AssembledMessage> {
match self.last_result {
Some(Ok(Some(message))) => Some(message),
_ => None,
}
}
#[must_use]
pub fn completed_for_key(&self, key: MessageKey) -> Option<&'a AssembledMessage> {
self.completed_messages
.iter()
.rev()
.find(|message| message.message_key() == key)
}
}
pub fn assert_message_assembly_incomplete(snapshot: MessageAssemblySnapshot<'_>) -> TestResult {
match snapshot.last_result {
Some(Ok(None)) => Ok(()),
_ => Err(format!(
"expected incomplete message assembly, got {}",
describe_last_result(snapshot.last_result)
)
.into()),
}
}
pub fn assert_message_assembly_completed(
snapshot: MessageAssemblySnapshot<'_>,
expected: &[u8],
) -> TestResult {
let Some(message) = snapshot.last_completed() else {
return Err(format!(
"expected completed message assembly, got {}",
describe_last_result(snapshot.last_result)
)
.into());
};
assert_body_eq(message.body(), expected, "completed message body")
}
pub fn assert_message_assembly_completed_for_key(
snapshot: MessageAssemblySnapshot<'_>,
key: MessageKey,
expected: &[u8],
) -> TestResult {
let Some(message) = snapshot.completed_for_key(key) else {
return Err(
format!("expected completed message for key {key}, but none was recorded").into(),
);
};
assert_body_eq(
message.body(),
expected,
&format!("completed message body for key {key}"),
)
}
pub fn assert_message_assembly_error(
snapshot: MessageAssemblySnapshot<'_>,
expected: MessageAssemblyErrorExpectation,
) -> TestResult {
let Some(Err(err)) = snapshot.last_result else {
return Err(format!(
"expected message assembly error, got {}",
describe_last_result(snapshot.last_result)
)
.into());
};
if matches_message_error(err, expected) {
Ok(())
} else {
Err(format!("expected {expected:?}, got {err:?}").into())
}
}
pub fn assert_message_assembly_buffered_count(
snapshot: MessageAssemblySnapshot<'_>,
expected: usize,
) -> TestResult {
assert_usize_field(snapshot.buffered_count, expected, "buffered_count")
}
pub fn assert_message_assembly_total_buffered_bytes(
snapshot: MessageAssemblySnapshot<'_>,
expected: usize,
) -> TestResult {
assert_usize_field(
snapshot.total_buffered_bytes,
expected,
"total_buffered_bytes",
)
}
pub fn assert_message_assembly_evicted(
snapshot: MessageAssemblySnapshot<'_>,
key: MessageKey,
) -> TestResult {
if snapshot.evicted_keys.contains(&key) {
Ok(())
} else {
Err(format!("expected key {key} to be evicted").into())
}
}
fn describe_last_result(
last_result: Option<&Result<Option<AssembledMessage>, MessageAssemblyError>>,
) -> String {
match last_result {
None => "no result recorded".to_string(),
Some(Ok(None)) => "incomplete assembly".to_string(),
Some(Ok(Some(message))) => {
format!("completed assembly for key {}", message.message_key())
}
Some(Err(err)) => format!("error {err:?}"),
}
}