use super::prohibitions_generated as generated;
pub use generated::{FORBIDDEN_ATTRIBUTES, FORBIDDEN_PATHS, TOTAL_PARAMS, UNEXTRACTED};
#[must_use]
pub fn forbidden_path(path: &str) -> Option<&'static str> {
FORBIDDEN_PATHS
.iter()
.find(|(_, ctx, rel)| crate::xml::path_matches(path, ctx, rel))
.map(|(id, _, _)| *id)
}
#[must_use]
pub fn forbidden_attribute(name: &str) -> Option<&'static str> {
FORBIDDEN_ATTRIBUTES
.iter()
.find(|(_, a)| *a == name)
.map(|(id, _)| *id)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn the_tables_are_populated() {
assert!(FORBIDDEN_PATHS.len() > 900, "{}", FORBIDDEN_PATHS.len());
assert!(FORBIDDEN_ATTRIBUTES.len() > 10);
const { assert!(TOTAL_PARAMS > 1000) };
}
#[test]
fn a_root_anchored_prohibition_does_not_fire_at_depth() {
let Some((rule, ctx, rel)) = FORBIDDEN_PATHS
.iter()
.find(|(_, c, _)| c.starts_with("/ubl:"))
else {
panic!("expected a root-anchored prohibition");
};
let root = ctx
.trim_start_matches('/')
.split(':')
.next_back()
.expect("root");
assert_eq!(forbidden_path(&format!("{root}/{rel}")), Some(*rule));
assert_eq!(forbidden_path(&format!("{root}/cac:Elsewhere/{rel}")), None);
}
#[test]
fn legitimate_elements_are_not_forbidden() {
for path in [
"Invoice/cbc:ID",
"Invoice/cbc:IssueDate",
"Invoice/cac:AccountingSupplierParty/cac:Party/cac:PartyName/cbc:Name",
"Invoice/cac:LegalMonetaryTotal/cbc:PayableAmount",
"Invoice/cac:InvoiceLine/cac:Item/cbc:Name",
] {
assert_eq!(forbidden_path(path), None, "{path} must be allowed");
}
}
#[test]
fn language_id_is_forbidden_everywhere() {
assert!(forbidden_attribute("languageID").is_some());
assert_eq!(forbidden_attribute("currencyID"), None);
}
}