use super::citation::{act_refs, cites_article_or_annex};
#[test]
fn the_detectors_catch_what_they_are_for() {
let invented = act_refs("Per Regulation (EU) 2027/9999 Annex II.");
assert_eq!(
invented.first().map(|a| a.celex.as_str()),
Some("32027R9999"),
"an invented act number must still parse, or Rule B never sees it"
);
assert!(cites_article_or_annex(
"SVHC substances per REACH Article 33."
));
assert!(cites_article_or_annex(
"Contact allergens under Annex XVII entry 72."
));
assert!(!cites_article_or_annex(
"Recycled content share as a percentage of total mass."
));
for (prose, expected) in [
("Regulation (EU) 2023/1670", "32023R1670"),
("Regulation (EC) No 1907/2006", "32006R1907"),
("Directive 2011/65/EU", "32011L0065"),
("Directive (EU) 2017/1132", "32017L1132"),
("EU Battery Regulation 2023/1542", "32023R1542"),
("replacing 1222/2009", "32009R1222"),
(
"Commission Implementing Decision (EU) 2026/1736",
"32026D1736",
),
(
"Commission Implementing Decision (EU) 2015/1506",
"32015D1506",
),
("Commission Decision 2011/833/EU", "32011D0833"),
("Commission Recommendation (EU) 2021/2279", "32021H2279"),
("Toy fields per Regulation (EU) 2025/2509.", "32025R2509"),
] {
assert_eq!(
act_refs(prose).first().map(|a| a.celex.as_str()),
Some(expected),
"{prose} should resolve to {expected}"
);
}
assert_eq!(
act_refs(
"Presumption under Regulation (EU) 2024/1781 Art. 41(2), via the \
standards cited by Commission Implementing Decision (EU) 2026/1736."
)
.iter()
.map(|a| a.celex.as_str())
.collect::<Vec<_>>(),
["32024R1781", "32026D1736"],
);
for (prose, expected) in [
("Market indecision since 2023/1234", "32023R1234"),
(
"After deregulation, Directive 2011/65/EU applied",
"32011L0065",
),
("Both regulations, including 2023/1670", "32023R1670"),
] {
assert_eq!(
act_refs(prose).first().map(|a| a.celex.as_str()),
Some(expected),
"{prose} should resolve to {expected}"
);
}
for prose in [
"ISO/IEC 15459-1:2014, -2:2015 and -3:2014",
"v1.1.0 renames countryOfManufacture",
"above 0,1 % w/w",
"placed on the market from 2031-08-18",
"Annex VI Part A point 10",
"ranked 1/2 in the working plan",
] {
assert!(
act_refs(prose).is_empty(),
"{prose} must not be read as an act reference, got {:?}",
act_refs(prose)
);
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(super) enum CitationBasis {
Sourced,
Assumed,
}
pub(super) struct CitedNotModelled {
pub(super) celex: &'static str,
pub(super) reason: &'static str,
pub(super) basis: CitationBasis,
}
pub(super) const CITED_NOT_MODELLED: &[CitedNotModelled] = &[
CitedNotModelled {
celex: "32004R0648",
reason: "The old Detergents Regulation. Cited only as the act Regulation \
(EU) 2026/405 repeals: its Art. 35 reads 'Regulation (EC) No \
648/2004 is repealed with effect from 23 September 2029', and \
directs that references be read against the correlation table in \
Annex VIII. The *next* article, Art. 36, carries the transition: \
product placed before 23 September 2029 may be made available \
indefinitely, and product placed in the following year until 23 \
September 2030 — so 'repealed' on its own overstates how cleanly \
it ends, which is what a reader needs. This entry said Art. 36 \
for both, while marked as read against the Official Journal.",
basis: CitationBasis::Sourced,
},
CitedNotModelled {
celex: "32006R1907",
reason: "REACH. Cited for Art. 33 (SVHC communication duty above 0,1 % \
w/w) and Annex XVII entry 72 (restricted substances in \
textiles). A horizontal chemicals regime rather than a passport \
instrument, so it binds no product group in the catalog sense.",
basis: CitationBasis::Assumed,
},
CitedNotModelled {
celex: "32009L0048",
reason: "Toy Safety Directive. Cited for CE marking. Superseded for \
passport purposes by Regulation (EU) 2025/2509, which is \
modelled.",
basis: CitationBasis::Assumed,
},
CitedNotModelled {
celex: "32009R0661",
reason: "General safety of motor vehicles. Cited only as the source of \
the tyre noise limit values (LV) that Regulation (EU) 2020/740 \
grades against — a threshold this crate reads, not an \
obligation it carries. 2020/740's own Annex I Part C says so: \
'The external rolling noise class shall be determined … on the \
basis of the limit values (LV) set out in Part C of Annex II to \
Regulation (EC) No 661/2009.'",
basis: CitationBasis::Sourced,
},
CitedNotModelled {
celex: "32009R1222",
reason: "The old tyre labelling regulation. Cited only as the act \
Regulation (EU) 2020/740 replaced. Its Art. 17 reads \
'Regulation (EC) No 1222/2009 is repealed with effect from 1 \
May 2021', and directs that references to it be read against \
the correlation table in Annex VIII.",
basis: CitationBasis::Sourced,
},
CitedNotModelled {
celex: "32011L0065",
reason: "RoHS. Cited for the substance restrictions an electronics \
declaration references. Not a passport instrument.",
basis: CitationBasis::Assumed,
},
CitedNotModelled {
celex: "32017L1132",
reason: "Company law directive. Cited for Art. 16, which establishes the \
unique company identifier the unsold-goods schema uses for the \
EUID.",
basis: CitationBasis::Assumed,
},
CitedNotModelled {
celex: "32020R0740",
reason: "Tyre labelling. Cited for the Annex I grading scales. A \
labelling regime, not a passport obligation — the tyre passport \
duty, when one exists, will come from an ESPR delegated act.",
basis: CitationBasis::Assumed,
},
CitedNotModelled {
celex: "32023R1669",
reason: "Energy labelling for smartphones and slate tablets. The sibling \
of Regulation (EU) 2023/1670, which is modelled; this one sets \
label classes rather than passport content.",
basis: CitationBasis::Assumed,
},
CitedNotModelled {
celex: "32024R1252",
reason: "Critical Raw Materials Act. Cited as the source of the canonical \
CRM list, which Annexes I and II supply and which is why prose \
names it. 🚨 It was also recorded here as an act that 'does not \
govern disclosure'. That is false. Art. 28 requires a label \
stating whether a product incorporates permanent magnets and of \
which type, and a data carrier linked to a unique product \
identifier giving access to each magnet's weight, location and \
chemical composition; Art. 28(6) says that where a product \
passport is required under another Union act, 'the information \
referred to in paragraph 4 shall be included in that product \
passport'. Art. 28(7) puts that information's accuracy and a \
lifetime-plus-ten-years retention on the person placing the \
product on the market. Art. 29 requires the recycled share of \
eight named elements to be published on a free-access website. \
The act is still not *modelled* — no binding describes it — but \
it is a passport-content instrument, not a list of materials. \
\
Scope, because these duties are narrower than they read. Art. 28 \
binds an exhaustive list of products — MRI devices, wind energy \
generators, industrial robots, motor vehicles, light means of \
transport, cooling generators, heat pumps, electric motors \
including where integrated, washing machines, tumble driers, \
microwaves, vacuum cleaners, dishwashers — and none of the \
product groups this crate models is among them. It applies two \
years after an implementing act due 24 November 2026, and from \
24 May 2029 for MRI devices, motor vehicles and category-L \
vehicles. Art. 29 is narrower again: only those products, only \
magnet types (i) to (iii), and only where the magnets' total \
weight exceeds 0,2 kg — a threshold that is Art. 29's and not \
Art. 28's — from 24 May 2027 or two years after its delegated \
act, whichever is later. Art. 28(8) lets Union harmonisation \
legislation displace Art. 28 for a listed product, so the answer \
is per product group rather than global.",
basis: CitationBasis::Sourced,
},
];