ethercrab backend snapshot tests

Live under crates/ethercat-esi-codegen-ethercrab/tests/.

Test Case: EL3001 backend output snapshot TEST_0420
status: open
verifies: REQ_0521, REQ_0522

Run parse → codegen → backend → prettyplease on the canonical EL3001 ESI fixture. Compare the formatted output against a committed snapshots/el3001.rs golden file using insta::assert_snapshot!. Reviewer regenerates the golden when intentional changes land; CI fails on unintentional churn. The <Dev>OpMode enum shape (Selectable PDO assignments ... (REQ_0523), Each OpMode variant carries... (REQ_0524)) is verified directly by EL7047 OpMode enum, exact l... (TEST_0870).

Test Case: EL7047 OpMode enum, exact lengths, pdo_assignment, round-trip TEST_0870
status: implemented
links incoming: REQ_0523, REQ_0524, REQ_0527, REQ_0528

Tests in crates/taktora-ethercat-esi-codegen-ethercrab-tests/tests/op_mode.rs run the EL7047 ESI through parse → codegen → backend and assert the joint per-device OpMode enum: all nine operating modes are emitted as variants (Selectable PDO assignments ... (REQ_0523)); each variant’s { inputs, outputs } payload yields the exact per-mode input_len / output_len and a decode/encode round-trip is lossless for the active mode (Each OpMode variant carries... (REQ_0524)); and pdo_assignment() returns the expected Rx (0x1C12 / SM2) and Tx (0x1C13 / SM3) u16 index lists per active mode (Per-active-mode Rx/Tx PDO-i... (REQ_0528)).

Test Case: Generated registry covers every emitted device TEST_0421
status: open
verifies: REQ_0525

For an input set with N devices, the generated module’s registry!() expansion contains exactly N entries mapping SubDeviceIdentity → factory closure. White-box test parses the generated output and counts entries.

Test Case: Generated module compiles under no_std + alloc TEST_0422
status: open
verifies: REQ_0526

A test crate at crates/ethercat-esi-codegen-ethercrab/tests/no_std_consumer/ has #![no_std] and extern crate alloc;, include!``s the generated module from a fixed input set, and compiles successfully. Catches any accidental ``std:: qualified path in the backend’s emit code.

Test Case: Backend is the sole ethercrab consumer in the toolchain TEST_0423
status: open
verifies: REQ_0520

CI shell check: cargo tree invocations for ethercat-esi, ethercat-esi-codegen, ethercat-esi-build, ethercat-esi-cli, and ethercat-esi-verify must none of them list ethercrab in the dependency graph. ethercat-esi-codegen-ethercrab and ethercat-esi-rt are the only crates where ethercrab is allowed.

Test Case: Object-dictionary emission gated by feature flag TEST_0424
status: open
verifies: REQ_0533

Build the no_std_consumer test crate twice: once without features (the generated module’s OD table is empty / absent; no symbol named OD exists) and once with --features object-dictionary (the OD static exists and has the expected entry count for the input set). Compares the two binaries’ rodata sections — the no-feature build is smaller by an amount approximating the OD table size.