use crate::e2e::escape::escape_csharp;
use crate::e2e::fixture::Fixture;
pub(super) fn declared_error_value_check(fixture: &Fixture, errors: &[crate::core::ir::ErrorDef]) -> Option<String> {
use crate::e2e::codegen::declared_error_variant::{DeclaredErrorAssertion, classify, declared_variant, skip_line};
match classify("csharp", fixture, errors) {
DeclaredErrorAssertion::Undeclared => None,
DeclaredErrorAssertion::Assert(declared) => {
if let Some((_, variant)) = declared_variant(fixture, errors) {
Some(format!(" Assert.IsType<{}Exception>(thrown);", variant.name))
} else {
let escaped = escape_csharp(declared);
Some(format!(
" Assert.True(thrown.Message != null && thrown.Message.Contains(\"{escaped}\") \
|| thrown.GetType().Name.Contains(\"{escaped}\"), \"expected error to match: {escaped}\");"
))
}
}
DeclaredErrorAssertion::Unsubstantiable(variant) => {
Some(skip_line(" ", "//", variant, &fixture.id, "csharp"))
}
}
}
#[cfg(test)]
mod tests {
use super::declared_error_value_check;
use crate::core::ir::{ErrorDef, ErrorVariant};
use crate::e2e::fixture::{Assertion, Fixture};
fn fixture_with_declared_error(value: &str) -> Fixture {
Fixture {
id: "declares_error".to_string(),
assertions: vec![Assertion {
assertion_type: "error".to_string(),
value: Some(serde_json::Value::String(value.to_string())),
..Assertion::default()
}],
..Fixture::default()
}
}
fn api_error(variants: &[(&str, &str)]) -> ErrorDef {
ErrorDef {
name: "ApiError".to_string(),
rust_path: "lib::ApiError".to_string(),
original_rust_path: String::new(),
variants: variants
.iter()
.map(|(name, message_template)| ErrorVariant {
name: name.to_string(),
message_template: Some(message_template.to_string()),
is_unit: true,
..ErrorVariant::default()
})
.collect(),
doc: String::new(),
methods: vec![],
binding_excluded: false,
binding_exclusion_reason: None,
version: Default::default(),
}
}
#[test]
fn asserts_the_exact_type_for_a_substantiable_variant() {
let fixture = fixture_with_declared_error("Authentication");
let errors = vec![api_error(&[("Authentication", "Authentication failed: {reason}")])];
let check = declared_error_value_check(&fixture, &errors).expect("expected a rendered assertion");
assert_eq!(check, " Assert.IsType<AuthenticationException>(thrown);");
}
#[test]
fn renders_a_different_exact_assertion_for_a_different_variant() {
let errors = vec![api_error(&[
("Authentication", "Authentication failed: {reason}"),
("BadRequest", "Bad request: {reason}"),
])];
let auth_fixture = fixture_with_declared_error("Authentication");
let auth_check = declared_error_value_check(&auth_fixture, &errors).expect("expected a rendered assertion");
assert_eq!(auth_check, " Assert.IsType<AuthenticationException>(thrown);");
let bad_request_fixture = fixture_with_declared_error("BadRequest");
let bad_request_check =
declared_error_value_check(&bad_request_fixture, &errors).expect("expected a rendered assertion");
assert_eq!(bad_request_check, " Assert.IsType<BadRequestException>(thrown);");
assert_ne!(auth_check, bad_request_check);
}
#[test]
fn a_variant_with_no_message_template_still_renders_the_skip() {
let fixture = fixture_with_declared_error("Unknown");
let mut error = api_error(&[]);
error.variants.push(ErrorVariant {
name: "Unknown".to_string(),
message_template: None,
is_unit: true,
..ErrorVariant::default()
});
let errors = vec![error];
let check = declared_error_value_check(&fixture, &errors).expect("expected a rendered skip");
assert_eq!(
check,
" // skipped: declared error variant 'Unknown' not yet preserved as a distinct identity by \
this backend's generator"
);
}
}