use dig_rpc_protocol::error::ErrorCode;
const ONION_BAND: std::ops::RangeInclusive<i32> = -32022..=-32020;
#[test]
fn range_metadata_unrepresentable_is_outside_the_onion_band() {
let code = ErrorCode::RangeMetadataUnrepresentable.code();
assert_ne!(code, -32021, "-32021 is PRIVACY_REQUIRES_LOCAL_NODE");
assert!(
!ONION_BAND.contains(&code),
"code {code} falls inside the published onion band {ONION_BAND:?}"
);
assert_eq!(
ErrorCode::RangeMetadataUnrepresentable.machine_code(),
"RANGE_METADATA_UNREPRESENTABLE"
);
assert!(
ErrorCode::RangeMetadataUnrepresentable.is_jsonrpc_reserved(),
"the code must live in the JSON-RPC implementation-defined server band"
);
}
#[test]
fn the_rustdoc_taxonomy_table_lists_every_code() {
const ERROR_MODULE_SOURCE: &str = include_str!("../src/error.rs");
let table: String = ERROR_MODULE_SOURCE
.lines()
.take_while(|line| line.starts_with("//!"))
.collect::<Vec<_>>()
.join("\n");
for code in ErrorCode::ALL {
let row = format!("| `{}` | [`{:?}`]", code.code(), code);
assert!(
table.contains(&row),
"the rustdoc taxonomy table is missing a row for {} ({}); expected to find {row:?}",
code.machine_code(),
code.code()
);
}
}
#[test]
fn range_metadata_unrepresentable_is_published_in_openrpc() {
let doc = dig_rpc_protocol::openrpc::openrpc_document("0.0.0-test");
let catalogue = doc["components"]["x-dig-errors"]
.as_array()
.expect("error catalogue is an array");
let entry = catalogue
.iter()
.find(|e| e["machineCode"] == "RANGE_METADATA_UNREPRESENTABLE")
.expect("RANGE_METADATA_UNREPRESENTABLE is absent from the OpenRPC catalogue");
assert_eq!(
entry["code"],
ErrorCode::RangeMetadataUnrepresentable.code(),
"the published number must match the enum"
);
}
#[test]
fn every_published_code_is_unique_and_in_the_jsonrpc_server_range() {
use std::collections::HashMap;
let mut seen: HashMap<i32, ErrorCode> = HashMap::new();
for &code in ErrorCode::ALL {
let n = code.code();
if let Some(&prior) = seen.get(&n) {
panic!(
"error code {n} is claimed by BOTH {} and {} — a client cannot \
branch on it, so one of them must be renumbered to a free value",
prior.machine_code(),
code.machine_code()
);
}
seen.insert(n, code);
assert!(
code.is_jsonrpc_reserved(),
"{} = {n} lies outside the JSON-RPC implementation-defined server range \
(-32768..=-32000) this crate publishes",
code.machine_code()
);
}
assert_eq!(
seen.len(),
ErrorCode::ALL.len(),
"every variant in ALL must contribute a distinct number"
);
}
#[test]
fn content_miss_inconclusive_does_not_squat_range_metadata_unrepresentable() {
let inconclusive = ErrorCode::ContentMissInconclusive;
assert_eq!(inconclusive.code(), -32017);
assert_ne!(
inconclusive.code(),
ErrorCode::MetadataTooLarge.code(),
"-32015 is METADATA_TOO_LARGE, a released dig-node code catalogued on docs.dig.net; it was picked here as \"the next free code\" against this crate's own list, which is precisely the check that does not work"
);
assert_ne!(
inconclusive.code(),
ErrorCode::RangeMetadataUnrepresentable.code(),
"-32009 is RANGE_METADATA_UNREPRESENTABLE, which is holder-FATAL; this code \
means the opposite (keep looking, this holder is still eligible)"
);
assert!(
!ONION_BAND.contains(&inconclusive.code()),
"must not fall inside the published onion band"
);
assert_eq!(inconclusive.machine_code(), "CONTENT_MISS_INCONCLUSIVE");
}
const CONSUMER_OCCUPANCY: &[(i32, Option<&str>)] = &[
(-32015, Some("METADATA_TOO_LARGE")),
(-32016, Some("PUSH_PENDING_LIMITED")),
(-32050, Some("NO_IDENTITY")),
(-32051, Some("NO_PEER_NETWORK")),
(-32052, Some("SEND_FAILED")),
(-32001, None),
(-32033, Some("CONTROL_INGRESS_LIMITED")),
(-32040, Some("WALLET_NO_CHAIN_SOURCE")),
(-32041, Some("WALLET_NOT_SYNCED")),
(-32042, Some("WALLET_READ_FAILED")),
(-32043, Some("WALLET_RATE_LIMITED")),
];
#[test]
fn no_declared_code_contradicts_the_measured_consumer_occupancy() {
for &(number, consumer_name) in CONSUMER_OCCUPANCY {
let declared = ErrorCode::ALL.iter().find(|c| c.code() == number);
match (declared, consumer_name) {
(Some(code), Some(name)) => assert_eq!(
code.machine_code(),
name,
"{number} is declared here as {} but a consumer emits it as {name}; one wire number cannot carry two meanings — renumber the new code, never the released one",
code.machine_code()
),
(Some(code), None) => panic!(
"{number} is declared here as {} but a consumer already emits it as a bare integer with no published name, so its meaning cannot be reconciled — pick a number this ecosystem does not use",
code.machine_code()
),
(None, _) => {}
}
}
}
#[test]
fn the_absorbed_consumer_codes_are_declared_with_their_released_numbers() {
for (number, name) in [
(-32015, "METADATA_TOO_LARGE"),
(-32016, "PUSH_PENDING_LIMITED"),
(-32050, "NO_IDENTITY"),
(-32051, "NO_PEER_NETWORK"),
(-32052, "SEND_FAILED"),
] {
let code = ErrorCode::ALL
.iter()
.find(|c| c.machine_code() == name)
.unwrap_or_else(|| panic!("{name} is absent from ErrorCode::ALL"));
assert_eq!(
code.code(),
number,
"{name} is a released, catalogued wire number and MUST stay {number}"
);
}
}