apollo-errors 0.7.0

Structured error handling with automatic format conversion
Documentation
//! Tests for JSON-RPC format output (to_jsonrpc)

mod common;

use apollo_errors::{CodeCase, Error as ErrorTrait, FieldCase, FormatConfig};
use common::{
    ErrorWithFields, ErrorWithRenamedField, JsonRpcError, RpcValidationError, SimpleError,
};
use insta::assert_json_snapshot;

#[test]
fn test_custom_code_with_extension_field() {
    let error = JsonRpcError::MethodNotFound {
        method: "eth_call".to_string(),
    };
    let jsonrpc = error.to_jsonrpc(FormatConfig::default()).unwrap();
    assert_json_snapshot!(jsonrpc, @r#"
    {
      "code": -32601,
      "data": {
        "diagnostic_code": "jsonrpc::method_not_found",
        "method": "eth_call"
      },
      "message": "Method not found: eth_call"
    }
    "#);
}

#[test]
fn test_default_code() {
    // When no jsonrpc_code is specified, defaults to -32000
    let error = JsonRpcError::DefaultCode;
    let jsonrpc = error.to_jsonrpc(FormatConfig::default()).unwrap();
    assert_json_snapshot!(jsonrpc, @r#"
    {
      "code": -32000,
      "data": {
        "diagnostic_code": "jsonrpc::default_code"
      },
      "message": "No code specified, uses default"
    }
    "#);
}

#[test]
fn test_struct_error_with_extensions() {
    let error = RpcValidationError {
        field: "amount".to_string(),
        reason: "must be positive".to_string(),
    };
    let jsonrpc = error.to_jsonrpc(FormatConfig::default()).unwrap();
    assert_json_snapshot!(jsonrpc, @r#"
    {
      "code": -32602,
      "data": {
        "diagnostic_code": "rpc::validation_error",
        "field": "amount",
        "reason": "must be positive"
      },
      "message": "RPC validation failed for field amount"
    }
    "#);
}

#[test]
fn test_error_without_jsonrpc_attribute() {
    // SimpleError doesn't have jsonrpc_code, should use default -32000
    let error = SimpleError::Simple;
    let jsonrpc = error.to_jsonrpc(FormatConfig::default()).unwrap();
    assert_json_snapshot!(jsonrpc, @r#"
    {
      "code": -32000,
      "data": {
        "diagnostic_code": "errors::simple"
      },
      "message": "Something went wrong"
    }
    "#);
}

#[test]
fn test_kebab_field_case_screaming_snake_code_case_jsonrpc() {
    let error = ErrorWithFields::InvalidPort {
        port: 8080,
        config_file: "/etc/config.toml".to_string(),
    };
    let config = FormatConfig {
        field_case: FieldCase::KebabCase,
        code_case: CodeCase::ScreamingSnakeCase,
    };
    let jsonrpc = error.to_jsonrpc(config).unwrap();
    assert_json_snapshot!(jsonrpc, @r#"
    {
      "code": -32000,
      "data": {
        "config-file": "/etc/config.toml",
        "diagnostic_code": "CONFIG_INVALID_PORT",
        "port": 8080
      },
      "message": "Invalid port"
    }
    "#);
}

#[test]
fn test_camel_field_case_default_code_case_jsonrpc() {
    let error = ErrorWithFields::InvalidPort {
        port: 8080,
        config_file: "/etc/config.toml".to_string(),
    };
    let config = FormatConfig {
        field_case: FieldCase::CamelCase,
        ..FormatConfig::default()
    };
    let jsonrpc = error.to_jsonrpc(config).unwrap();
    assert_json_snapshot!(jsonrpc, @r#"
    {
      "code": -32000,
      "data": {
        "configFile": "/etc/config.toml",
        "diagnostic_code": "config::invalid_port",
        "port": 8080
      },
      "message": "Invalid port"
    }
    "#);
}

#[test]
fn test_default_field_case_screaming_snake_code_case_jsonrpc() {
    let error = ErrorWithFields::InvalidPort {
        port: 8080,
        config_file: "/etc/config.toml".to_string(),
    };
    let config = FormatConfig {
        code_case: CodeCase::ScreamingSnakeCase,
        ..FormatConfig::default()
    };
    let jsonrpc = error.to_jsonrpc(config).unwrap();
    assert_json_snapshot!(jsonrpc, @r#"
    {
      "code": -32000,
      "data": {
        "config_file": "/etc/config.toml",
        "diagnostic_code": "CONFIG_INVALID_PORT",
        "port": 8080
      },
      "message": "Invalid port"
    }
    "#);
}

#[test]
fn test_renamed_field_pascal_case_screaming_snake_code_jsonrpc() {
    let error = ErrorWithRenamedField::WithRename {
        my_field: "value".to_string(),
    };
    let config = FormatConfig {
        field_case: FieldCase::PascalCase,
        code_case: CodeCase::ScreamingSnakeCase,
    };
    let jsonrpc = error.to_jsonrpc(config).unwrap();
    assert_json_snapshot!(jsonrpc, @r#"
    {
      "code": -32000,
      "data": {
        "MyRenamedField": "value",
        "diagnostic_code": "TEST_RENAMED_FIELD"
      },
      "message": "Field was renamed"
    }
    "#);
}