use crate::e2e::codegen::assertion_type_skip::{
streaming_assertion_type_skip_line, streaming_assertion_value_skip_line,
};
use crate::e2e::codegen::field_skip::FieldSkip;
use crate::e2e::escape::go_string_literal;
use crate::e2e::fixture::Assertion;
use std::fmt::Write as FmtWrite;
use super::AssertionRenderContext;
pub(super) fn render_streaming_field_assertion(
out: &mut String,
assertion: &Assertion,
context: &AssertionRenderContext<'_>,
) -> bool {
let Some(f) = assertion.field.as_deref() else {
return false;
};
if context.result_is_simple
|| !context.is_streaming
|| f.is_empty()
|| !crate::e2e::codegen::streaming_assertions::is_streaming_call_field(f)
{
return false;
}
let streaming_item_type = context.streaming_item_type;
if let Some(expr) =
crate::e2e::codegen::streaming_assertions::StreamingFieldResolver::accessor_with_streaming_context(
f,
"go",
"chunks",
None,
streaming_item_type,
)
{
let value_skip = || streaming_assertion_value_skip_line("\t", "//", f, &assertion.assertion_type);
if render_exact_counter(out, assertion, f, &expr) {
return true;
}
let numeric_expr = expr.clone();
let is_stream_scoped = crate::e2e::codegen::streaming_assertions::is_stream_scoped_field(f);
match assertion.assertion_type.as_str() {
"count_min" => {
if let Some(val) = &assertion.value
&& let Some(n) = val.as_u64()
{
let _ = writeln!(
out,
"\tassert.GreaterOrEqual(t, len({expr}), {n}, \"expected >= {n} chunks\")"
);
} else {
let _ = writeln!(out, "{}", value_skip());
}
}
"count_equals" => {
if let Some(val) = &assertion.value
&& let Some(n) = val.as_u64()
{
let _ = writeln!(
out,
"\tassert.Equal(t, {n}, len({expr}), \"expected exactly {n} chunks\")"
);
} else {
let _ = writeln!(out, "{}", value_skip());
}
}
"equals" => {
if let Some(serde_json::Value::String(s)) = &assertion.value {
let escaped = go_string_literal(s);
let is_deep_path = (f.contains('.') || f.contains('[')) && !is_stream_scoped;
let safe_expr = if is_deep_path {
format!("func() string {{ v := {expr}; if v == nil {{ return \"\" }}; return *v }}()")
} else {
expr.clone()
};
let _ = writeln!(out, "\tassert.Equal(t, {escaped}, {safe_expr})");
} else if let Some(val) = &assertion.value
&& let Some(n) = val.as_u64()
{
let _ = writeln!(out, "\tassert.Equal(t, {n}, {numeric_expr})");
} else {
let _ = writeln!(out, "{}", value_skip());
}
}
"not_empty" => {
let _ = writeln!(out, "\tassert.NotEmpty(t, {expr}, \"expected non-empty\")");
}
"is_empty" => {
let _ = writeln!(out, "\tassert.Empty(t, {expr}, \"expected empty\")");
}
"is_true" => {
let _ = writeln!(out, "\tassert.True(t, {expr}, \"expected true\")");
}
"is_false" => {
let _ = writeln!(out, "\tassert.False(t, {expr}, \"expected false\")");
}
"greater_than" => {
if let Some(val) = &assertion.value
&& let Some(n) = val.as_u64()
{
let _ = writeln!(out, "\tassert.Greater(t, {numeric_expr}, {n}, \"expected > {n}\")");
} else {
let _ = writeln!(out, "{}", value_skip());
}
}
"greater_than_or_equal" => {
if let Some(val) = &assertion.value
&& let Some(n) = val.as_u64()
{
let _ = writeln!(
out,
"\tassert.GreaterOrEqual(t, {numeric_expr}, {n}, \"expected >= {n}\")"
);
} else {
let _ = writeln!(out, "{}", value_skip());
}
}
"contains" => {
if let Some(serde_json::Value::String(s)) = &assertion.value {
let escaped = crate::e2e::escape::go_string_literal(s);
let _ = writeln!(out, "\tassert.Contains(t, {expr}, {escaped}, \"expected to contain\")");
} else {
let _ = writeln!(out, "{}", value_skip());
}
}
_ => {
let _ = writeln!(
out,
"{}",
streaming_assertion_type_skip_line("\t", "//", f, &assertion.assertion_type)
);
}
}
} else {
let _ = writeln!(
out,
"\t// skipped: {}",
FieldSkip::StreamingAssertionOnUnsupportedField.message(f)
);
}
true
}
fn render_exact_counter(out: &mut String, assertion: &Assertion, field: &str, expression: &str) -> bool {
if !crate::e2e::codegen::streaming_assertions::is_stream_counter_assertion(field, assertion.value.as_ref()) {
return false;
}
let Some(number) = assertion.value.as_ref().and_then(serde_json::Value::as_number) else {
return false;
};
let operator = match assertion.assertion_type.as_str() {
"equals" => "==",
"greater_than" => ">",
"greater_than_or_equal" => ">=",
"less_than" => "<",
"less_than_or_equal" => "<=",
_ => return false,
};
out.push_str(&crate::e2e::template_env::render(
"go/stream_counter.jinja",
crate::alef_context! {
expression => expression, operator => operator, value => number.to_string(),
},
));
true
}
#[cfg(test)]
#[path = "streaming_fields/counter_tests.rs"]
mod counter_tests;