use crate::core::ir::{ErrorDef, ErrorVariant};
use crate::e2e::fixture::Fixture;
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct SnippetErrorBranch {
pub variant: String,
pub host_type: String,
}
pub(crate) fn for_fixture(lang: &str, fixture: &Fixture, errors: &[ErrorDef]) -> Option<SnippetErrorBranch> {
let (error, variant) = super::declared_error_variant::declared_variant(fixture, errors)?;
if !super::declared_error_variant::substantiates_variant_identity(lang, variant) {
return None;
}
Some(SnippetErrorBranch {
variant: variant.name.clone(),
host_type: host_error_type(lang, &error.name, variant, errors)?,
})
}
fn host_error_type(lang: &str, error_name: &str, variant: &ErrorVariant, errors: &[ErrorDef]) -> Option<String> {
match lang {
"python" => Some(crate::codegen::error_gen::python_exception_name(
&variant.name,
error_name,
)),
"go" => Some(crate::codegen::error_gen::go_error_sentinel_name(
errors,
error_name,
&variant.name,
)),
"java" => Some(format!("{}Exception", variant.name)),
"zig" => Some(format!(
"error.{}",
crate::codegen::naming::public_host_identifier(
crate::core::config::Language::Zig,
crate::codegen::naming::PublicIdentifierKind::Type,
&variant.name,
)
)),
_ => None,
}
}
#[cfg(test)]
mod tests {
use super::{SnippetErrorBranch, for_fixture};
use crate::core::ir::{ErrorDef, ErrorVariant};
use crate::e2e::codegen::declared_error_variant::{DeclaredErrorAssertion, classify};
use crate::e2e::fixture::{Assertion, Fixture};
const BACKENDS: &[&str] = &[
"python", "go", "csharp", "java", "zig", "dart", "ruby", "c", "php", "swift", "gleam", "elixir", "r", "node",
];
fn fixture_naming(variant: &str) -> Fixture {
Fixture {
id: "auth_401".to_string(),
assertions: vec![
Assertion {
assertion_type: "error".to_string(),
..Assertion::default()
},
Assertion {
assertion_type: "error".to_string(),
value: Some(serde_json::Value::String(variant.to_string())),
..Assertion::default()
},
],
..Fixture::default()
}
}
fn variant(name: &str, code: Option<u32>) -> ErrorVariant {
ErrorVariant {
name: name.to_string(),
error_code: code,
is_unit: true,
..ErrorVariant::default()
}
}
fn errors_with(variants: Vec<ErrorVariant>) -> Vec<ErrorDef> {
vec![ErrorDef {
name: "ApiError".to_string(),
rust_path: "lib::ApiError".to_string(),
original_rust_path: String::new(),
variants,
doc: String::new(),
methods: vec![],
binding_excluded: false,
binding_exclusion_reason: None,
version: Default::default(),
}]
}
#[test]
fn branch_and_classify_never_disagree_across_backends() {
let fixture = fixture_naming("Authentication");
let errors = errors_with(vec![variant("Authentication", Some(100))]);
for lang in BACKENDS {
let branch = for_fixture(lang, &fixture, &errors);
let substantiable = classify(lang, &fixture, &errors) == DeclaredErrorAssertion::Assert("Authentication");
assert_eq!(
branch.is_some(),
substantiable,
"lang={lang}: snippet branch {branch:?} disagrees with the e2e assertion verdict"
);
}
}
#[test]
fn an_uncoded_variant_branches_only_where_identity_is_not_abi_derived() {
let fixture = fixture_naming("Authentication");
let errors = errors_with(vec![variant("Authentication", None)]);
for lang in BACKENDS {
let branch = for_fixture(lang, &fixture, &errors);
assert_eq!(
branch.is_some(),
*lang == "python",
"lang={lang}: an uncoded variant yielded {branch:?}"
);
}
}
#[test]
fn python_names_the_generated_exception_class() {
let fixture = fixture_naming("Authentication");
let errors = errors_with(vec![variant("Authentication", None)]);
assert_eq!(
for_fixture("python", &fixture, &errors),
Some(SnippetErrorBranch {
variant: "Authentication".to_string(),
host_type: "AuthenticationError".to_string(),
})
);
}
#[test]
fn a_message_style_value_never_branches() {
let fixture = fixture_naming("size must be positive");
let errors = errors_with(vec![variant("Authentication", Some(100))]);
for lang in BACKENDS {
assert_eq!(for_fixture(lang, &fixture, &errors), None, "lang={lang}");
}
}
#[test]
fn no_error_registry_never_branches() {
let fixture = fixture_naming("Authentication");
for lang in BACKENDS {
assert_eq!(for_fixture(lang, &fixture, &[]), None, "lang={lang}");
}
}
}