use std::fmt::Write as FmtWrite;
use crate::e2e::fixture::Fixture;
pub(crate) fn render(fixture: &Fixture, line_prefix: &str, language: &str) -> String {
if !fixture.assertions.iter().any(|a| a.assertion_type == "error") {
return String::new();
}
let mut out = String::new();
let mut consumed_the_primary_error_check = false;
for assertion in &fixture.assertions {
if !consumed_the_primary_error_check && assertion.assertion_type == "error" {
consumed_the_primary_error_check = true;
continue;
}
let field = assertion.field.as_deref().unwrap_or("<none>");
let _ = writeln!(
out,
"{line_prefix}skipped: assertion type '{}' has no accessor for error field {field} in this backend",
assertion.assertion_type
);
}
super::fail_on_unsupported_assertion_type_markers(&out, language, &fixture.id);
out
}
pub(crate) fn emit(out: &mut String, fixture: &Fixture, line_prefix: &str, language: &str) {
out.push_str(&render(fixture, line_prefix, language));
}
#[cfg(test)]
mod tests {
use super::*;
use crate::e2e::fixture::Assertion;
fn assertion(assertion_type: &str, field: Option<&str>) -> Assertion {
Assertion {
assertion_type: assertion_type.to_string(),
field: field.map(str::to_string),
..Assertion::default()
}
}
fn fixture_with(assertions: Vec<Assertion>) -> Fixture {
Fixture {
id: "rate_limited".to_string(),
assertions,
..Fixture::default()
}
}
#[test]
fn a_lone_error_assertion_renders_no_marker() {
let fixture = fixture_with(vec![assertion("error", None)]);
let _ = crate::e2e::codegen::take_skip_records();
assert_eq!(render(&fixture, " // ", "go"), "");
assert!(crate::e2e::codegen::take_skip_records().is_empty());
}
#[test]
fn an_error_field_equals_assertion_is_named_and_counted() {
let fixture = fixture_with(vec![
assertion("error", None),
assertion("equals", Some("error.status_code")),
]);
let _ = crate::e2e::codegen::take_skip_records();
let rendered = render(&fixture, "\t// ", "go");
assert_eq!(
rendered,
"\t// skipped: assertion type 'equals' has no accessor for error field error.status_code in this \
backend\n"
);
let records = crate::e2e::codegen::take_skip_records();
assert_eq!(records.len(), 1, "got: {records:?}");
assert_eq!(records[0].field, "equals");
assert_eq!(records[0].language, "go");
assert_eq!(records[0].fixture_id, "rate_limited");
assert_eq!(records[0].origin, crate::e2e::codegen::SkipOrigin::AssertionType);
assert_eq!(
records[0].verdict,
crate::e2e::codegen::SkipVerdict::AwaitingGeneratorSupport
);
}
#[test]
fn a_second_error_assertion_is_also_named() {
let fixture = fixture_with(vec![assertion("error", None), assertion("error", None)]);
let _ = crate::e2e::codegen::take_skip_records();
let rendered = render(&fixture, " # ", "ruby");
assert_eq!(
rendered,
" # skipped: assertion type 'error' has no accessor for error field <none> in this backend\n"
);
assert_eq!(crate::e2e::codegen::take_skip_records().len(), 1);
}
#[test]
fn a_fixture_with_no_error_assertion_renders_nothing() {
let fixture = fixture_with(vec![
assertion("equals", Some("status_code")),
assertion("not_empty", Some("content")),
]);
let _ = crate::e2e::codegen::take_skip_records();
assert_eq!(render(&fixture, " // ", "dart"), "");
assert!(crate::e2e::codegen::take_skip_records().is_empty());
}
#[test]
fn every_trailing_assertion_gets_its_own_line() {
let fixture = fixture_with(vec![
assertion("error", None),
assertion("equals", Some("error.status_code")),
assertion("contains", Some("error.message")),
]);
let _ = crate::e2e::codegen::take_skip_records();
let rendered = render(&fixture, " // ", "swift");
assert_eq!(rendered.lines().count(), 2, "got: {rendered}");
assert_eq!(crate::e2e::codegen::take_skip_records().len(), 2);
}
}