use super::tags;
use alloc::{
boxed::Box,
collections::BTreeMap,
string::{String, ToString},
};
const FIXTURE: &str = include_str!("../../../../docs/wire/registry.json");
const SOURCE: &str = include_str!("tags.rs");
type Rows = BTreeMap<(String, String), u16>;
macro_rules! pin_registry {
($fixture:ident, $name:ident) => {
let entries: BTreeMap<_, _> = $fixture
.iter()
.filter(|((r, _), _)| r == stringify!($name))
.map(|((_, name), value)| (*value, name))
.collect();
for value in 0..=u16::MAX {
let row = entries.get(&value);
match (tags::$name::try_from(value), row) {
(Ok(tag), Some(name)) => {
assert_eq!(tag.wire_value(), value);
assert_eq!(alloc::format!("{tag:?}"), **name);
}
(Err(_), None) => {}
_ => {
return Err(alloc::format!(
"{} value {value} differs from the export",
stringify!($name)
)
.into());
}
}
}
};
}
#[test]
fn committed_registry_equals_every_rust_registry() -> Result<(), Box<dyn core::error::Error>> {
let source = source_rows()?;
let fixture = fixture_rows();
assert_eq!(fixture, source, "registry export is incomplete or drifted");
pin_registry!(fixture, ClientDiscriminant);
pin_registry!(fixture, ServerDiscriminant);
pin_registry!(fixture, RecordAdmissionFaultClassTag);
pin_registry!(fixture, PushDiscriminant);
pin_registry!(fixture, RecordKind);
pin_registry!(fixture, CloseCauseTag);
pin_registry!(fixture, TransportReasonTag);
pin_registry!(fixture, DecodeClass);
pin_registry!(fixture, AttemptOperation);
pin_registry!(fixture, AttemptConflict);
pin_registry!(fixture, DetachAuthorityStateTag);
pin_registry!(fixture, LeaveAuthorityStateTag);
pin_registry!(fixture, BindingStateTag);
pin_registry!(fixture, ReceiptExpiryReason);
pin_registry!(fixture, ReceiptCapacityScope);
pin_registry!(fixture, IdentityCapacityScope);
pin_registry!(fixture, ClosureScope);
pin_registry!(fixture, ResourceDimensionTag);
pin_registry!(fixture, RepaymentEdgeTag);
pin_registry!(fixture, MarkerNotDeliveredReason);
pin_registry!(fixture, MarkerMismatchReason);
pin_registry!(fixture, AckGapReason);
pin_registry!(fixture, AckRegressionReason);
pin_registry!(fixture, InvalidObserverEpochReason);
pin_registry!(fixture, InvalidObserverEpochListReason);
pin_registry!(fixture, Counter);
Ok(())
}
fn source_rows() -> Result<Rows, Box<dyn core::error::Error>> {
let mut source = Rows::new();
let mut registry = "";
for line in SOURCE.lines().map(str::trim) {
if let Some(name) = line.strip_suffix(" {")
&& name.chars().all(char::is_alphanumeric)
{
registry = name;
}
if let Some((name, value)) = line.split_once(" = ")
&& !registry.is_empty()
&& name.chars().all(char::is_alphanumeric)
{
let value = value.trim_end_matches(',');
let value = if let Some(hex) = value.strip_prefix("0x") {
u16::from_str_radix(hex, 16)?
} else {
value.parse()?
};
assert!(
source
.insert((registry.to_string(), name.to_string()), value)
.is_none()
);
}
}
Ok(source)
}
fn fixture_rows() -> Rows {
let mut fixture = Rows::new();
let mut registry = "";
for line in FIXTURE.lines().map(str::trim) {
if let Some(name) = line.strip_suffix("\": {").and_then(|s| s.strip_prefix('"')) {
registry = name;
}
if let Some((name, value)) = line
.split_once("\": ")
.and_then(|(n, v)| n.strip_prefix('"').map(|n| (n, v)))
&& let Ok(number) = value.trim_end_matches(',').parse::<u16>()
&& registry != "registries"
&& !registry.is_empty()
{
assert!(
fixture
.insert((registry.to_string(), name.to_string()), number)
.is_none()
);
}
}
fixture
}