mod common;
use apollo_errors::error_catalog;
use insta::assert_json_snapshot;
fn find_error_by_name<'a>(
errors: &'a [serde_json::Value],
name: &str,
) -> Option<&'a serde_json::Value> {
errors
.iter()
.find(|e| e.get("typeName").and_then(|v| v.as_str()) == Some(name))
}
#[test]
fn test_simple_error_catalog() {
let catalog = error_catalog();
let catalog_json = serde_json::to_value(&catalog).unwrap();
let errors = catalog_json.as_array().unwrap();
let simple_error = find_error_by_name(errors, "SimpleError").unwrap();
assert_json_snapshot!(simple_error, @r#"
{
"typeName": "SimpleError",
"variants": [
{
"code": {
"camel": "errorsSimple",
"default": "errors::simple",
"kebab": "errors-simple",
"pascal": "ErrorsSimple",
"screamingSnake": "ERRORS_SIMPLE"
},
"fields": [],
"httpStatus": 500,
"message": "Something went wrong",
"name": "Simple"
},
{
"code": {
"camel": "errorsAnother",
"default": "errors::another",
"kebab": "errors-another",
"pascal": "ErrorsAnother",
"screamingSnake": "ERRORS_ANOTHER"
},
"fields": [],
"httpStatus": 500,
"message": "Another error occurred",
"name": "Another"
}
]
}
"#);
}
#[test]
fn test_error_with_fields_catalog() {
let catalog = error_catalog();
let catalog_json = serde_json::to_value(&catalog).unwrap();
let errors = catalog_json.as_array().unwrap();
let error_with_fields = find_error_by_name(errors, "ErrorWithFields").unwrap();
assert_json_snapshot!(error_with_fields, @r#"
{
"typeName": "ErrorWithFields",
"variants": [
{
"code": {
"camel": "configInvalidPort",
"default": "config::invalid_port",
"kebab": "config-invalid-port",
"pascal": "ConfigInvalidPort",
"screamingSnake": "CONFIG_INVALID_PORT"
},
"fields": [
{
"camelCase": "port",
"isExtension": true,
"kebabCase": "port",
"outputName": "port",
"pascalCase": "Port",
"rustName": "port",
"screamingSnakeCase": "PORT",
"snakeCase": "port",
"ty": "u16"
},
{
"camelCase": "configFile",
"isExtension": true,
"kebabCase": "config-file",
"outputName": "config_file",
"pascalCase": "ConfigFile",
"rustName": "config_file",
"screamingSnakeCase": "CONFIG_FILE",
"snakeCase": "config_file",
"ty": "String"
}
],
"httpStatus": 500,
"message": "Invalid port",
"name": "InvalidPort"
},
{
"code": {
"camel": "configMissing",
"default": "config::missing",
"kebab": "config-missing",
"pascal": "ConfigMissing",
"screamingSnake": "CONFIG_MISSING"
},
"fields": [
{
"camelCase": "expectedPath",
"isExtension": true,
"kebabCase": "expected-path",
"outputName": "expected_path",
"pascalCase": "ExpectedPath",
"rustName": "expected_path",
"screamingSnakeCase": "EXPECTED_PATH",
"snakeCase": "expected_path",
"ty": "String"
}
],
"httpStatus": 500,
"message": "Missing configuration",
"name": "MissingConfig"
}
]
}
"#);
}
#[test]
fn test_error_with_status_catalog() {
let catalog = error_catalog();
let catalog_json = serde_json::to_value(&catalog).unwrap();
let errors = catalog_json.as_array().unwrap();
let error_with_status = find_error_by_name(errors, "ErrorWithStatus").unwrap();
assert_json_snapshot!(error_with_status, @r#"
{
"typeName": "ErrorWithStatus",
"variants": [
{
"code": {
"camel": "resourceNotFound",
"default": "resource::not_found",
"kebab": "resource-not-found",
"pascal": "ResourceNotFound",
"screamingSnake": "RESOURCE_NOT_FOUND"
},
"fields": [],
"httpStatus": 404,
"message": "Resource not found",
"name": "NotFound"
},
{
"code": {
"camel": "requestBad",
"default": "request::bad",
"kebab": "request-bad",
"pascal": "RequestBad",
"screamingSnake": "REQUEST_BAD"
},
"fields": [],
"httpStatus": 400,
"message": "Bad request",
"name": "BadRequest"
},
{
"code": {
"camel": "serviceUnavailable",
"default": "service::unavailable",
"kebab": "service-unavailable",
"pascal": "ServiceUnavailable",
"screamingSnake": "SERVICE_UNAVAILABLE"
},
"fields": [],
"httpStatus": 503,
"message": "Service unavailable",
"name": "ServiceUnavailable"
},
{
"code": {
"camel": "internalError",
"default": "internal::error",
"kebab": "internal-error",
"pascal": "InternalError",
"screamingSnake": "INTERNAL_ERROR"
},
"fields": [],
"httpStatus": 500,
"message": "Internal error",
"name": "InternalError"
}
]
}
"#);
}
#[test]
fn test_error_with_help_catalog() {
let catalog = error_catalog();
let catalog_json = serde_json::to_value(&catalog).unwrap();
let errors = catalog_json.as_array().unwrap();
let error_with_help = find_error_by_name(errors, "ErrorWithHelp").unwrap();
assert_json_snapshot!(error_with_help, @r#"
{
"typeName": "ErrorWithHelp",
"variants": [
{
"code": {
"camel": "configError",
"default": "config::error",
"kebab": "config-error",
"pascal": "ConfigError",
"screamingSnake": "CONFIG_ERROR"
},
"fields": [],
"help": "Check your configuration file",
"httpStatus": 500,
"message": "Configuration error",
"name": "ConfigError",
"severity": "warning",
"url": "https://docs.example.com/errors/config"
}
]
}
"#);
}
#[test]
fn test_transparent_wrapper_error_catalog() {
let catalog = error_catalog();
let catalog_json = serde_json::to_value(&catalog).unwrap();
let errors = catalog_json.as_array().unwrap();
let transparent_wrapper = find_error_by_name(errors, "TransparentWrapperError").unwrap();
assert_json_snapshot!(transparent_wrapper, @r#"
{
"typeName": "TransparentWrapperError",
"variants": [
{
"code": {
"camel": "appError",
"default": "app::error",
"kebab": "app-error",
"pascal": "AppError",
"screamingSnake": "APP_ERROR"
},
"fields": [],
"httpStatus": 500,
"message": "Application error",
"name": "ApplicationError"
},
{
"code": {
"camel": "dbConnectionFailed",
"default": "db::connection_failed",
"kebab": "db-connection-failed",
"pascal": "DbConnectionFailed",
"screamingSnake": "DB_CONNECTION_FAILED"
},
"fields": [],
"help": "Check your database credentials",
"httpStatus": 503,
"message": "Database connection failed",
"name": "DatabaseError"
},
{
"code": {
"camel": "networkTimeout",
"default": "network::timeout",
"kebab": "network-timeout",
"pascal": "NetworkTimeout",
"screamingSnake": "NETWORK_TIMEOUT"
},
"fields": [
{
"camelCase": "timeoutMs",
"isExtension": true,
"kebabCase": "timeout-ms",
"outputName": "timeout_ms",
"pascalCase": "TimeoutMs",
"rustName": "timeout_ms",
"screamingSnakeCase": "TIMEOUT_MS",
"snakeCase": "timeout_ms",
"ty": "u64"
}
],
"httpStatus": 504,
"message": "Network timeout after {timeout_ms}ms",
"name": "NetworkTimeout"
}
]
}
"#);
}
#[test]
fn test_transparent_to_struct_error_catalog() {
let catalog = error_catalog();
let catalog_json = serde_json::to_value(&catalog).unwrap();
let errors = catalog_json.as_array().unwrap();
let transparent_to_struct = find_error_by_name(errors, "TransparentToStructError").unwrap();
assert_json_snapshot!(transparent_to_struct, @r#"
{
"typeName": "TransparentToStructError",
"variants": [
{
"code": {
"camel": "wrapperDirect",
"default": "wrapper::direct",
"kebab": "wrapper-direct",
"pascal": "WrapperDirect",
"screamingSnake": "WRAPPER_DIRECT"
},
"fields": [],
"httpStatus": 500,
"message": "Direct enum error",
"name": "Direct"
},
{
"code": {
"camel": "structsConfigError",
"default": "structs::config_error",
"kebab": "structs-config-error",
"pascal": "StructsConfigError",
"screamingSnake": "STRUCTS_CONFIG_ERROR"
},
"fields": [
{
"camelCase": "port",
"isExtension": true,
"kebabCase": "port",
"outputName": "port",
"pascalCase": "Port",
"rustName": "port",
"screamingSnakeCase": "PORT",
"snakeCase": "port",
"ty": "u16"
},
{
"camelCase": "configPath",
"isExtension": true,
"kebabCase": "config-path",
"outputName": "config_path",
"pascalCase": "ConfigPath",
"rustName": "config_path",
"screamingSnakeCase": "CONFIG_PATH",
"snakeCase": "config_path",
"ty": "String"
}
],
"help": "Check your configuration file",
"httpStatus": 400,
"message": "Configuration error: invalid port {port}",
"name": "ConfigStructError"
},
{
"code": {
"camel": "structsSimple",
"default": "structs::simple",
"kebab": "structs-simple",
"pascal": "StructsSimple",
"screamingSnake": "STRUCTS_SIMPLE"
},
"fields": [],
"httpStatus": 500,
"message": "Simple struct error occurred",
"name": "SimpleStructError"
}
]
}
"#);
}
#[test]
fn test_renamed_field_case_variants() {
let catalog = error_catalog();
let catalog_json = serde_json::to_value(&catalog).unwrap();
let errors = catalog_json.as_array().unwrap();
let error = find_error_by_name(errors, "ErrorWithRenamedField").unwrap();
assert_json_snapshot!(error, @r#"
{
"typeName": "ErrorWithRenamedField",
"variants": [
{
"code": {
"camel": "testRenamedField",
"default": "test::renamed_field",
"kebab": "test-renamed-field",
"pascal": "TestRenamedField",
"screamingSnake": "TEST_RENAMED_FIELD"
},
"fields": [
{
"camelCase": "myRenamedField",
"isExtension": true,
"kebabCase": "my-renamed-field",
"outputName": "myRenamedField",
"pascalCase": "MyRenamedField",
"rustName": "my_field",
"screamingSnakeCase": "MY_RENAMED_FIELD",
"snakeCase": "my_renamed_field",
"ty": "String"
}
],
"httpStatus": 500,
"message": "Field was renamed",
"name": "WithRename"
}
]
}
"#);
}