#![allow(clippy::expect_used, clippy::panic)]
use std::collections::BTreeMap;
use std::path::PathBuf;
use zerodds_ast_layout::{Dialect, Encoding, Endianness, EnumHolderWidth, EnumeratorValue};
use zerodds_wire_probe::encode::{encode, hex, model_from_idl_in_dialect};
use zerodds_wire_probe::value::ProbeRequest;
const MEMBER_CASES: [&str; 8] = [
"enum-bitbound-8-plain",
"enum-bitbound-8-plain-unannotated",
"enum-bitbound-8-value",
"enum-bitbound-8-value-unannotated",
"enum-bitbound-16-plain",
"enum-bitbound-16-plain-unannotated",
"enum-bitbound-16-value",
"enum-bitbound-16-value-unannotated",
];
const OPENDDS_ORDINAL_NUMBERED: [&str; 4] = [
"enum-bitbound-8-value",
"enum-bitbound-8-value-unannotated",
"enum-bitbound-16-value",
"enum-bitbound-16-value-unannotated",
];
fn repository_root() -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("..")
.join("..")
}
fn recorded() -> BTreeMap<(String, String, String, String), String> {
let mut rows = BTreeMap::new();
let path = repository_root().join("tests/interop-results/sources/vendor-corpus.tsv");
let text = std::fs::read_to_string(path).expect("tests/interop-results/sources");
for line in text.lines() {
let f: Vec<&str> = line.split('\t').collect();
if f.len() < 6
|| f[4] != "wrote"
|| !MEMBER_CASES.contains(&f[0]) && !ELEMENT_CASES.iter().any(|(name, _)| *name == f[0])
{
continue;
}
rows.insert(
(
f[0].to_string(),
f[1].to_string(),
f[2].to_string(),
f[3].to_string(),
),
f[5].to_string(),
);
}
rows
}
type Combination = (Dialect, EnumHolderWidth);
fn combinations() -> Vec<Combination> {
let mut out = Vec::new();
for dialect in Dialect::ALL {
for width in EnumHolderWidth::ALL {
out.push((dialect, width));
}
}
out
}
fn written(
case: &str,
encoding: Encoding,
endianness: Endianness,
combination: Combination,
) -> Option<String> {
let directory = repository_root().join("tests/interop-corpus").join(case);
let idl = std::fs::read_to_string(directory.join("type.idl")).ok()?;
let type_name = std::fs::read_to_string(directory.join("type")).ok()?;
let values: serde_json::Value =
serde_json::from_str(&std::fs::read_to_string(directory.join("values.json")).ok()?).ok()?;
let ast = model_from_idl_in_dialect(&idl, &format!("{case}/type.idl"), combination.0).ok()?;
let mut request =
ProbeRequest::in_dialect(type_name.trim(), encoding, endianness, combination.0);
request.enum_holder = combination.1;
request.enumerator_value = EnumeratorValue::Declared;
encode(&ast, &request, &values).ok().map(|b| hex(&b))
}
fn matching(case: &str, version: &str, endian: &str, theirs: &str) -> Vec<Combination> {
let encoding = if version == "xcdr1" {
Encoding::PlainCdr1
} else {
Encoding::PlainCdr2
};
let endianness = if endian == "be" {
Endianness::Big
} else {
Endianness::Little
};
combinations()
.into_iter()
.filter(|combination| {
written(case, encoding, endianness, *combination).as_deref() == Some(theirs)
})
.collect()
}
#[test]
fn the_two_widths_are_told_apart() {
let rows = recorded();
assert!(
!rows.is_empty(),
"no recorded rows were read from tests/interop-results/sources — this check must not \
pass by finding nothing"
);
let mut compared = 0usize;
for case in MEMBER_CASES {
for (system, expected) in [
("cyclone", EnumHolderWidth::Declared),
("fastdds", EnumHolderWidth::BitBoundDroppedByFrontEnd),
] {
for version in ["xcdr1", "xcdr2"] {
for endian in ["le", "be"] {
let key = (
case.to_string(),
system.to_string(),
version.to_string(),
endian.to_string(),
);
let Some(theirs) = rows.get(&key) else {
panic!("{case} {system} {version} {endian} is not in vendor-corpus.tsv");
};
let found = matching(case, version, endian, theirs);
assert!(
!found.is_empty(),
"{case} {system} {version} {endian}: none of the {} combinations \
reproduce {theirs}",
combinations().len()
);
for (dialect, width) in &found {
assert_eq!(
*width,
expected,
"{case} {system} {version} {endian}: reproduced under \
{}/{} — the holder width is not pinned by these octets",
dialect.as_str(),
width.as_str()
);
}
compared += 1;
}
}
}
}
assert_eq!(
compared,
MEMBER_CASES.len() * 2 * 2 * 2,
"the sweep compared {compared} rows"
);
}
const ELEMENT_CASES: [(&str, bool); 4] = [
("array-3d-enum", true),
("array-3d-enum-unannotated", true),
("combined-everything", false),
("combined-everything-unannotated", false),
];
#[test]
fn the_element_position_is_wired_too() {
let rows = recorded();
let mut compared = 0usize;
for (case, cyclone_usable) in ELEMENT_CASES {
let mut systems: Vec<(&str, EnumHolderWidth)> =
vec![("fastdds", EnumHolderWidth::BitBoundDroppedByFrontEnd)];
if cyclone_usable {
systems.push(("cyclone", EnumHolderWidth::Declared));
}
for (system, expected) in systems {
for version in ["xcdr1", "xcdr2"] {
for endian in ["le", "be"] {
let key = (
case.to_string(),
system.to_string(),
version.to_string(),
endian.to_string(),
);
let Some(theirs) = rows.get(&key) else {
panic!("{case} {system} {version} {endian} is not in vendor-corpus.tsv");
};
let found = matching(case, version, endian, theirs);
assert!(
!found.is_empty(),
"{case} {system} {version} {endian}: none of the {} combinations \
reproduce {theirs} — the holder width does not reach an enumeration \
at a collection's element position",
combinations().len()
);
for (dialect, width) in &found {
assert_eq!(
*width,
expected,
"{case} {system} {version} {endian}: reproduced under {}/{}",
dialect.as_str(),
width.as_str()
);
}
compared += 1;
}
}
}
}
assert_eq!(
compared,
(2 * 2 + 2) * 2 * 2,
"the sweep compared {compared} rows"
);
}
#[test]
fn opendds_closes_on_the_holder_and_not_on_the_numbering() {
let rows = recorded();
let mut closed = 0usize;
let mut open = 0usize;
for case in MEMBER_CASES {
for version in ["xcdr1", "xcdr2"] {
for endian in ["le", "be"] {
let key = (
case.to_string(),
"opendds".to_string(),
version.to_string(),
endian.to_string(),
);
let Some(theirs) = rows.get(&key) else {
panic!("{case} opendds {version} {endian} is not in vendor-corpus.tsv");
};
let found = matching(case, version, endian, theirs);
if OPENDDS_ORDINAL_NUMBERED.contains(&case) {
assert!(
found.is_empty(),
"{case} opendds {version} {endian}: reproduced by {found:?} on the \
holder's axis alone — the numbering would then not be part of this \
cause, and `enumerator_value.rs` says it is"
);
open += 1;
} else {
assert!(
!found.is_empty(),
"{case} opendds {version} {endian}: none of the {} combinations \
reproduce {theirs}",
combinations().len()
);
for (dialect, width) in &found {
assert_eq!(
*width,
EnumHolderWidth::BitBoundDroppedByFrontEnd,
"{case} opendds {version} {endian}: reproduced under {}/{}",
dialect.as_str(),
width.as_str()
);
}
closed += 1;
}
}
}
}
assert_eq!(closed, 16, "OpenDDS `-plain` rows closed: {closed}");
assert_eq!(open, 16, "OpenDDS `-value` rows still open: {open}");
}
#[test]
fn the_sites_go_through_the_crossing() {
const SITES: [(&str, usize, usize); 8] = [
("crates/ast-layout/src/xcdr.rs", 3, 0),
("crates/wire-codec/src/encode.rs", 1, 1),
("crates/wire-codec/src/decode.rs", 1, 1),
("crates/lang-rules/src/encode.rs", 3, 0),
("crates/ast-layout/src/plan.rs", 2, 1),
("crates/lang-rules/src/emit/encode.rs", 0, 0),
("crates/lang-rules/src/emit/decode.rs", 0, 1),
("crates/wire-probe/src/corba_idl.rs", 0, 1),
];
for (path, crossings, straight) in SITES {
let text = std::fs::read_to_string(repository_root().join(path))
.unwrap_or_else(|error| panic!("{path}: {error}"));
let is_definition = path.ends_with("ast-layout/src/xcdr.rs");
let found = text.matches("enumeration_bit_bound(").count() - usize::from(is_definition);
assert_eq!(
found, crossings,
"{path} calls the crossing {found} times, not {crossings}"
);
let raw = text.matches("effective_bit_bound(").count() - usize::from(is_definition);
assert_eq!(
raw, straight,
"{path} reads the declared bound straight {raw} times, not {straight} — a site that \
does so for an enumeration bypasses the axis and nothing at run time says so"
);
}
}