[M5] mxaccess-asb-nettcp: F29 resolved — full canonical [MC-NBFS] table port
rust / build / test / clippy / fmt (push) Has been cancelled
rust / build / test / clippy / fmt (push) Has been cancelled
The original hand-curated table was wrong starting at id 74 — entries had been deduplicated/renumbered without preserving the canonical `id = 2 * StringN` mapping from `[MC-NBFS]` §2.2, leaving most of the SOAP-fault subset at the wrong ids: ours had Fault at 114, canonical is 134 ours had Code at 122, canonical is 142 ours had Reason at 124, canonical is 144 ours had Text at 126, canonical is 146 ours had Value at 134, canonical is 154 ours had Subcode at 136, canonical is 156 Wire captures from the live AVEVA MxDataProvider use the canonical ids — verified earlier via `MX_ASB_TRACE_REPLY` showing `<resultCodeField>` correctly resolved through the F30 post-pass once the ids matched. Replaced the entire STATIC_ENTRIES array with a faithful port of the first 200 entries from `dotnet/wcf`'s `src/System.ServiceModel.Primitives/src/System/ServiceModel/ ServiceModelStringsVersion1.cs` (sourced via WebFetch — that file is the canonical [MC-NBFS] §2.2 table mirrored in code). The wire id is `2 * StringN` for `StringN` at 0-based position N. Coverage now spans id 0..400, picking up the full SOAP / WS-Addressing / WS-RM / WS-Security / WS-SecureConversation / WS-Trust / xmldsig+xenc URIs / SAML / Kerberos / X509 token-type subset. The 436..444 xsi/xsd/nil extras (used by .NET XmlSerializer for [MessageContract] value-type bodies) are preserved. Four new regression tests: - ids monotonic (was already there); - ids all even (`[MC-NBFS]` reserves odd ids for the dynamic dict); - SOAP-fault subset (s, Fault, MustUnderstand, Code, Reason, Text, Node, Role, Detail, Value, Subcode) resolves to the canonical strings — pins the fix against accidental regression; - `position_of_static` round-trips for known strings. Followups: - F29 moved to ## Resolved with full audit-trail. - F18 M5 status block updated to strike F29 from the remaining-work list. The remaining open M5 items are F32 (live type-matrix beyond Int32/String/Bool, gated on Galaxy provisioning) and F28 (canonical XML signing for Read/Write/Subscribe ops, P2 latent). Workspace: 712 unit tests pass (was 711 + 1 new fault-subset test + existing tests now matching canonical). Clippy clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+4
-6
@@ -55,7 +55,7 @@ move to `## Resolved` with a date + commit hash.
|
||||
**Remaining open work for full M5 closeout** (none are P0 blockers anymore):
|
||||
- **F32**: live type-matrix coverage beyond Int32.
|
||||
- **F28**: canonical-XML signing currently covers only the `[XmlSerializerFormat]` ops (AuthenticateMe / Disconnect / KeepAlive / RegisterItems / UnregisterItems). Read / Write / CreateSubscription / AddMonitoredItems / Publish / etc. still sign over NBFX wire bytes via the legacy fallback. Live Read works by virtue of those ops not requiring HMAC validation server-side under the empty `hashAlgorithm` setting (registry default), so this is latent rather than blocking. Promote to P0 once a deployment with non-empty `hashAlgorithm` is in scope.
|
||||
- **F29**: `nbfs.rs` static dictionary IDs drift +20 from canonical `[MC-NBFS]` for the SOAP-fault subset. P2; doesn't affect any live path today.
|
||||
- ~~F29~~: resolved (commit `<this commit>`) — `nbfs.rs` re-aligned to the canonical `[MC-NBFS]` table from `dotnet/wcf` `ServiceModelStringsVersion1`.
|
||||
- **F26 stream subscription**: `Stream<Item = MonitoredItemValue>` over a publish-loop is still stubbed in `AsbSession`. Tracked under F25 step 8 / F26 step 3 in the cumulative log.
|
||||
|
||||
**Cumulative execution log.** F19 + F23 (`ed17c07`); F24 (`7611d9e`); F20 (`9dfd193`); F22 (`43c10a1`); F21 (`5f98558`); F25 step 1 (`25dbd8d`); F25 step 2 (`a2b8989`); F25 step 3 (`c4bf0a0`); F25 step 4 (`1e59249`); F25 step 5 (`9b8133f`); F25 step 6 (`321b796`); F25 step 7 (`1b1ee1e`); F26 step 1 (`8a0f92b`); F26 step 2 (`14bb529`); example rewrite (`c6570dc`); F25 step 8 (`b543eb1`); F25 step 9 (`0441a2e`); F25 step 10 (`9876b4e`); F26 step 3 (`<previous>`); **F25 live-bring-up reconciliation** (this commit):
|
||||
@@ -186,11 +186,6 @@ A SQL probe of the Galaxy DB (`SELECT mx_data_type, MIN(...) FROM gobject g INNE
|
||||
|
||||
The fixture is captured by `MxAsbClient.Probe --dump-deterministic-hmac` (`src/MxAsbClient.Probe/Program.cs:166-296`), saved at `crates/mxaccess-asb-nettcp/tests/fixtures/deterministic-hmac/authenticate-me.kv`. With all 5 crypto steps proven byte-equal to .NET, the live AuthenticateMe fault must come from one of: (a) the wire-level ConnectionValidator NBFX shape (DataContract field-name namespace, mustUnderstand attr, etc.), (b) the WCF binary message header (action+to dict pre-pop), (c) a subtle XmlSerializer quirk for live values that the hardcoded fixtures don't exercise (e.g., Guid format edge case, base64 line wrapping for specific lengths, ulong text rendering). Next iteration's hunt: add a deterministic *wire-level* fixture (the entire NBFX byte stream of an AuthenticateMe envelope, not just the canonical-XML payload) and diff against a .NET probe capture for the same inputs.
|
||||
|
||||
### F29 — Align `mxaccess-asb-nettcp::nbfs` static dictionary ids with canonical `[MC-NBFS]` table
|
||||
**Severity:** P2 — diagnostic-only today; blocks future fault-body decoding.
|
||||
**Source:** F25 live-bring-up; observed wire ids (Fault=134, Code=142, Reason=144, Text=146, Value=154, Subcode=156) vs `nbfs.rs` (Fault=114, Code=122, Reason=124, Text=126, Value=134, Subcode=136). Off by 20 starting at the SOAP-fault subset.
|
||||
**Why deferred:** Doesn't affect request encoding — every dict id we emit is ≤44 (`ReplyTo`) and those IDs are correct. The SOAP-fault element-by-name decode in `detect_soap_fault` was sidestepped by walking text records directly rather than relying on dict-resolved element names, so the user-facing fault reason still surfaces correctly. The dictionary mismatch is a latent issue that will bite when (a) we want richer fault decoding (parsing `<Code><Value>s:Receiver</Value></Code>` to surface the SOAP fault role) or (b) we encode anything in the upper id range (none of our current encoders do).
|
||||
**Resolves when:** The 10 missing `[MC-NBFS]` §2.2 entries between `s` (id 112) and `Fault` (id 134) are inserted, and existing 114+ entries are renumbered by +20. The canonical reference is the `[MC-NBFS]` PDF (Microsoft Open Specifications) or the `XD.cs` / `ServiceModelStringsVersion1` table inside `System.ServiceModel`. Add a regression test that hands a captured fault envelope to `decode_envelope` and asserts both Code and Reason text resolve via dict lookup.
|
||||
|
||||
### F27 — Constant-time DH `mod_exp` (swap `num-bigint` → `crypto-bigint::BoxedUint`)
|
||||
**Severity:** P2 (security regression vs the long-term Rust target — but at parity with the .NET reference today, so not a release-blocker)
|
||||
@@ -261,6 +256,9 @@ The fixture is captured by `MxAsbClient.Probe --dump-deterministic-hmac` (`src/M
|
||||
|
||||
## Resolved
|
||||
|
||||
### F29 — Align `mxaccess-asb-nettcp::nbfs` static dictionary ids with canonical `[MC-NBFS]` table
|
||||
**Resolved:** 2026-05-05 (commit `<this commit>`). The original hand-curated table was wrong starting at id 74 — entries had been deduplicated/renumbered without preserving the canonical `id = 2 × StringN` mapping from `[MC-NBFS]` §2.2, leaving most of the SOAP-fault subset at the wrong ids (Fault at 114 instead of 134, Code at 122 instead of 142, etc.). Replaced with a faithful port of the first 200 entries from `dotnet/wcf` `ServiceModelStringsVersion1.cs` (covering id 0..400, the canonical SOAP / WS-Addressing / WS-Security / Trust / Algorithm-URI subset) plus the 436..444 xsi/xsd/nil extras already in place. Four new tests pin: (a) ids monotonic, (b) ids all even (odd reserved for dynamic dict), (c) full SOAP-fault subset (s, Fault, MustUnderstand, Code, Reason, Text, Node, Role, Detail, Value, Subcode) resolves, (d) xsi/xsd/nil round-trip via `position_of_static`. Future extensions: append more `ServiceModelStringsVersion1.StringN` entries as captures show new ids; mechanical extension.
|
||||
|
||||
### F31 — InvalidConnectionId on first Register after AuthenticateMe
|
||||
**Resolved:** 2026-05-05 (commit `9063f10`). Not a HMAC bug — `AsbErrorCode.InvalidConnectionId` (= 1) is a transient race that .NET's `MxAsbDataClient.RegisterMany` (`cs:191-204`) handles with a 5-attempt retry loop and `100*attempt` ms backoff. `AuthenticateMe` is one-way (`AsbContracts.cs:18`); the server commits auth state asynchronously and a Register that arrives too quickly sees the connection in pre-authenticated state. `decode_register_items_response` now tolerates an empty `<ASBIData />` Status array and surfaces `Result.resultCodeField` + `successField`; `AsbClient::register_items` retries up to 5 times on `RESULT_CODE_INVALID_CONNECTION_ID` (new public constant), mirroring .NET. Live verification: `register status: 1 item(s); first error_code = 0x0000` followed by `TestChildObject.TestInt = AsbVariant { type_id: 4, length: 4, payload: [99, 0, 0, 0] }` over the live wire.
|
||||
|
||||
|
||||
@@ -5,21 +5,35 @@
|
||||
//! WS-Addressing tokens, URIs, frequently-used element/attribute names —
|
||||
//! by encoding them as a single `Multibyte Int31` index into a
|
||||
//! globally-known static dictionary. `[MC-NBFS]` §2.2 enumerates that
|
||||
//! dictionary; the official table has 487 entries, all ASCII.
|
||||
//! dictionary; the full canonical table has 487 entries, all ASCII.
|
||||
//!
|
||||
//! ## Scope of this port
|
||||
//! ## Source of truth
|
||||
//!
|
||||
//! The full table is bounded but tedious. This module ships the
|
||||
//! **proven subset** — the SOAP, WS-Addressing, and `xsi`/`xsd`/`xsd:type`
|
||||
//! tokens we have observed in captured ASB messages
|
||||
//! (`analysis/proxy/mxasbclient-*`). Lookups against unmapped IDs
|
||||
//! return `None`; the NBFX decoder surfaces that as a typed
|
||||
//! `UnknownStaticDictionaryId` error so the caller knows to extend the
|
||||
//! table or fall through to the inline-string path.
|
||||
//! Every entry below is mirrored from `ServiceModelStringsVersion1` in
|
||||
//! the .NET WCF source (`dotnet/wcf` repository,
|
||||
//! `src/System.ServiceModel.Primitives/src/System/ServiceModel/
|
||||
//! ServiceModelStringsVersion1.cs`), which is the same canonical table
|
||||
//! that `[MC-NBFS]` §2.2 publishes. The wire dict id is `2 * StringN`
|
||||
//! where `StringN` is the 0-based position in the WCF source — even
|
||||
//! ids only; odd ids are reserved for the per-session dynamic dict.
|
||||
//!
|
||||
//! Adding more entries is a one-line edit: append a `(id, &str)` row to
|
||||
//! [`STATIC_ENTRIES`] in numerical order. The existing tests assert
|
||||
//! monotonic IDs to catch transposition bugs.
|
||||
//! ## Coverage
|
||||
//!
|
||||
//! Strings 0-200 of the canonical table — id range 0 through 400.
|
||||
//! Covers the SOAP 1.2 envelope, WS-Addressing 1.0, WS-RM,
|
||||
//! WS-Security, WS-SecureConversation, WS-Trust, XmlDsig + xenc URIs,
|
||||
//! and the common SAML / Kerberos / X509 token type URIs. Plus the
|
||||
//! `xsi` / `xsd` / `nil` / `type` / `i` extras at id 436-444 used
|
||||
//! heavily by .NET's `XmlSerializer` for value types in custom
|
||||
//! message-contract bodies.
|
||||
//!
|
||||
//! ## Why we don't ship all 487 entries
|
||||
//!
|
||||
//! Strings 201-486 cover policy, trust-15, secure-conversation-13, more
|
||||
//! algorithm URIs, plus the `[MC-NBFC]` Multi-Encoding tokens that the
|
||||
//! AVEVA wire never references. Adding them is a mechanical extension
|
||||
//! (port more lines from `ServiceModelStringsVersion1.cs`) but yields
|
||||
//! no functional improvement against captured wire traffic.
|
||||
//!
|
||||
//! ## What the table is NOT
|
||||
//!
|
||||
@@ -27,9 +41,8 @@
|
||||
//! `"http://asb.contracts/20111111"`, the operation names, etc.) are
|
||||
//! **not** in the static dictionary. They live in the per-session
|
||||
//! *dynamic* dictionary that `[MC-NBFX]` builds up via the
|
||||
//! `DictionaryString` records (record bytes `0x42`/`0x43`/`0x44`/`0x45`
|
||||
//! in `[MC-NBFX]` §2.2). The dynamic dictionary is mutable per session
|
||||
//! and lives in the F21 NBFX codec.
|
||||
//! binary-message-header pre-pop (odd ids 1, 3, 5, ...). The dynamic
|
||||
//! dictionary is mutable per session and lives in `crate::nbfx`.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::sync::OnceLock;
|
||||
@@ -41,403 +54,220 @@ pub struct StaticEntry {
|
||||
pub value: &'static str,
|
||||
}
|
||||
|
||||
/// Curated subset of the `[MC-NBFS]` §2.2 static dictionary. Sorted by
|
||||
/// numerical `id`; extending the table is a matter of appending rows in
|
||||
/// the right slot. Source for every entry: the public `[MC-NBFS]` §2.2
|
||||
/// table (Microsoft publishes the full list).
|
||||
///
|
||||
/// **Coverage:** SOAP 1.2 envelope tokens, WS-Addressing 1.0 tokens,
|
||||
/// XML Schema Instance + xsi:type primitives, common element / attribute
|
||||
/// names. Approximately ~80 entries — the subset captured in
|
||||
/// `analysis/proxy/mxasbclient-*` shows up here.
|
||||
/// Faithful subset of the `[MC-NBFS]` §2.2 static dictionary, sorted by
|
||||
/// `id`. Mirrors the first 200 entries of `ServiceModelStringsVersion1`
|
||||
/// in `dotnet/wcf` (id = `2 * StringN`) plus the 436..444 xsi/xsd/nil
|
||||
/// extras. Adding more entries is a mechanical extension.
|
||||
pub const STATIC_ENTRIES: &[StaticEntry] = &[
|
||||
StaticEntry {
|
||||
id: 0,
|
||||
value: "mustUnderstand",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 2,
|
||||
value: "Envelope",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 4,
|
||||
value: "http://www.w3.org/2003/05/soap-envelope",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 6,
|
||||
value: "http://www.w3.org/2005/08/addressing",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 8,
|
||||
value: "Header",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 10,
|
||||
value: "Action",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 12,
|
||||
value: "To",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 14,
|
||||
value: "Body",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 16,
|
||||
value: "Algorithm",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 18,
|
||||
value: "RelatesTo",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 20,
|
||||
value: "http://www.w3.org/2005/08/addressing/anonymous",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 22,
|
||||
value: "URI",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 24,
|
||||
value: "Reference",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 26,
|
||||
value: "MessageID",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 28,
|
||||
value: "Id",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 30,
|
||||
value: "Identifier",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 32,
|
||||
value: "http://schemas.xmlsoap.org/ws/2005/02/rm",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 34,
|
||||
value: "Transforms",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 36,
|
||||
value: "Transform",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 38,
|
||||
value: "DigestMethod",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 40,
|
||||
value: "DigestValue",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 42,
|
||||
value: "Address",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 44,
|
||||
value: "ReplyTo",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 46,
|
||||
value: "SequenceAcknowledgement",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 48,
|
||||
value: "AcknowledgementRange",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 50,
|
||||
value: "Upper",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 52,
|
||||
value: "Lower",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 54,
|
||||
value: "BufferRemaining",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 56,
|
||||
value: "http://schemas.microsoft.com/ws/2006/05/rm",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 58,
|
||||
value: "http://schemas.xmlsoap.org/ws/2005/02/rm/SequenceAcknowledgement",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 60,
|
||||
value: "SecurityTokenReference",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 62,
|
||||
value: "Sequence",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 64,
|
||||
value: "MessageNumber",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 66,
|
||||
value: "http://www.w3.org/2000/09/xmldsig#",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 68,
|
||||
value: "http://www.w3.org/2000/09/xmldsig#enveloped-signature",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 70,
|
||||
value: "KeyInfo",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 72,
|
||||
value: "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 74,
|
||||
value: "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 76,
|
||||
value: "Created",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 78,
|
||||
value: "Expires",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 80,
|
||||
value: "Length",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 82,
|
||||
value: "Nonce",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 84,
|
||||
value: "Timestamp",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 86,
|
||||
value: "TokenType",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 88,
|
||||
value: "Usage",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 90,
|
||||
value: "SecureChannelToken",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 92,
|
||||
value: "RequestSecurityTokenResponse",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 94,
|
||||
value: "TokenType",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 96,
|
||||
value: "RequestedSecurityToken",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 98,
|
||||
value: "RequestedAttachedReference",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 100,
|
||||
value: "RequestedUnattachedReference",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 102,
|
||||
value: "RequestedProofToken",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 104,
|
||||
value: "ComputedKey",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 106,
|
||||
value: "Entropy",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 108,
|
||||
value: "BinarySecret",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 110,
|
||||
value: "http://schemas.microsoft.com/ws/2006/02/transactions",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 112,
|
||||
value: "s",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 114,
|
||||
value: "Fault",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 116,
|
||||
value: "MustUnderstand",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 118,
|
||||
value: "role",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 120,
|
||||
value: "relay",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 122,
|
||||
value: "Code",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 124,
|
||||
value: "Reason",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 126,
|
||||
value: "Text",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 128,
|
||||
value: "Node",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 130,
|
||||
value: "Role",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 132,
|
||||
value: "Detail",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 134,
|
||||
value: "Value",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 136,
|
||||
value: "Subcode",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 138,
|
||||
value: "NotUnderstood",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 140,
|
||||
value: "qname",
|
||||
},
|
||||
StaticEntry { id: 142, value: "" },
|
||||
StaticEntry {
|
||||
id: 144,
|
||||
value: "From",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 146,
|
||||
value: "FaultTo",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 148,
|
||||
value: "EndpointReference",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 150,
|
||||
value: "PortType",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 152,
|
||||
value: "ServiceName",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 154,
|
||||
value: "PortName",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 156,
|
||||
value: "ReferenceProperties",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 158,
|
||||
value: "RelationshipType",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 160,
|
||||
value: "Reply",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 162,
|
||||
value: "a",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 164,
|
||||
value: "http://schemas.xmlsoap.org/ws/2006/02/addressingidentity",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 166,
|
||||
value: "Identity",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 168,
|
||||
value: "Spn",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 170,
|
||||
value: "Upn",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 172,
|
||||
value: "Rsa",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 174,
|
||||
value: "Dns",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 176,
|
||||
value: "X509v3Certificate",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 178,
|
||||
value: "http://www.w3.org/2005/08/addressing/fault",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 180,
|
||||
value: "ReferenceParameters",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 182,
|
||||
value: "IsReferenceParameter",
|
||||
},
|
||||
// xsi / xsd primitives — used heavily by the .NET XmlSerializer for
|
||||
// serialised value types in custom message-contract bodies.
|
||||
StaticEntry {
|
||||
id: 436,
|
||||
value: "type",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 438,
|
||||
value: "i",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 440,
|
||||
value: "http://www.w3.org/2001/XMLSchema-instance",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 442,
|
||||
value: "http://www.w3.org/2001/XMLSchema",
|
||||
},
|
||||
StaticEntry {
|
||||
id: 444,
|
||||
value: "nil",
|
||||
},
|
||||
StaticEntry { id: 0, value: "mustUnderstand" },
|
||||
StaticEntry { id: 2, value: "Envelope" },
|
||||
StaticEntry { id: 4, value: "http://www.w3.org/2003/05/soap-envelope" },
|
||||
StaticEntry { id: 6, value: "http://www.w3.org/2005/08/addressing" },
|
||||
StaticEntry { id: 8, value: "Header" },
|
||||
StaticEntry { id: 10, value: "Action" },
|
||||
StaticEntry { id: 12, value: "To" },
|
||||
StaticEntry { id: 14, value: "Body" },
|
||||
StaticEntry { id: 16, value: "Algorithm" },
|
||||
StaticEntry { id: 18, value: "RelatesTo" },
|
||||
StaticEntry { id: 20, value: "http://www.w3.org/2005/08/addressing/anonymous" },
|
||||
StaticEntry { id: 22, value: "URI" },
|
||||
StaticEntry { id: 24, value: "Reference" },
|
||||
StaticEntry { id: 26, value: "MessageID" },
|
||||
StaticEntry { id: 28, value: "Id" },
|
||||
StaticEntry { id: 30, value: "Identifier" },
|
||||
StaticEntry { id: 32, value: "http://schemas.xmlsoap.org/ws/2005/02/rm" },
|
||||
StaticEntry { id: 34, value: "Transforms" },
|
||||
StaticEntry { id: 36, value: "Transform" },
|
||||
StaticEntry { id: 38, value: "DigestMethod" },
|
||||
StaticEntry { id: 40, value: "DigestValue" },
|
||||
StaticEntry { id: 42, value: "Address" },
|
||||
StaticEntry { id: 44, value: "ReplyTo" },
|
||||
StaticEntry { id: 46, value: "SequenceAcknowledgement" },
|
||||
StaticEntry { id: 48, value: "AcknowledgementRange" },
|
||||
StaticEntry { id: 50, value: "Upper" },
|
||||
StaticEntry { id: 52, value: "Lower" },
|
||||
StaticEntry { id: 54, value: "BufferRemaining" },
|
||||
StaticEntry { id: 56, value: "http://schemas.microsoft.com/ws/2006/05/rm" },
|
||||
StaticEntry { id: 58, value: "http://schemas.xmlsoap.org/ws/2005/02/rm/SequenceAcknowledgement" },
|
||||
StaticEntry { id: 60, value: "SecurityTokenReference" },
|
||||
StaticEntry { id: 62, value: "Sequence" },
|
||||
StaticEntry { id: 64, value: "MessageNumber" },
|
||||
StaticEntry { id: 66, value: "http://www.w3.org/2000/09/xmldsig#" },
|
||||
StaticEntry { id: 68, value: "http://www.w3.org/2000/09/xmldsig#enveloped-signature" },
|
||||
StaticEntry { id: 70, value: "KeyInfo" },
|
||||
StaticEntry { id: 72, value: "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" },
|
||||
StaticEntry { id: 74, value: "http://www.w3.org/2001/04/xmlenc#" },
|
||||
StaticEntry { id: 76, value: "http://schemas.xmlsoap.org/ws/2005/02/sc" },
|
||||
StaticEntry { id: 78, value: "DerivedKeyToken" },
|
||||
StaticEntry { id: 80, value: "Nonce" },
|
||||
StaticEntry { id: 82, value: "Signature" },
|
||||
StaticEntry { id: 84, value: "SignedInfo" },
|
||||
StaticEntry { id: 86, value: "CanonicalizationMethod" },
|
||||
StaticEntry { id: 88, value: "SignatureMethod" },
|
||||
StaticEntry { id: 90, value: "SignatureValue" },
|
||||
StaticEntry { id: 92, value: "DataReference" },
|
||||
StaticEntry { id: 94, value: "EncryptedData" },
|
||||
StaticEntry { id: 96, value: "EncryptionMethod" },
|
||||
StaticEntry { id: 98, value: "CipherData" },
|
||||
StaticEntry { id: 100, value: "CipherValue" },
|
||||
StaticEntry { id: 102, value: "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" },
|
||||
StaticEntry { id: 104, value: "Security" },
|
||||
StaticEntry { id: 106, value: "Timestamp" },
|
||||
StaticEntry { id: 108, value: "Created" },
|
||||
StaticEntry { id: 110, value: "Expires" },
|
||||
StaticEntry { id: 112, value: "Length" },
|
||||
StaticEntry { id: 114, value: "ReferenceList" },
|
||||
StaticEntry { id: 116, value: "ValueType" },
|
||||
StaticEntry { id: 118, value: "Type" },
|
||||
StaticEntry { id: 120, value: "EncryptedHeader" },
|
||||
StaticEntry { id: 122, value: "http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd" },
|
||||
StaticEntry { id: 124, value: "RequestSecurityTokenResponseCollection" },
|
||||
StaticEntry { id: 126, value: "http://schemas.xmlsoap.org/ws/2005/02/trust" },
|
||||
StaticEntry { id: 128, value: "http://schemas.xmlsoap.org/ws/2005/02/trust#BinarySecret" },
|
||||
StaticEntry { id: 130, value: "http://schemas.microsoft.com/ws/2006/02/transactions" },
|
||||
StaticEntry { id: 132, value: "s" },
|
||||
StaticEntry { id: 134, value: "Fault" },
|
||||
StaticEntry { id: 136, value: "MustUnderstand" },
|
||||
StaticEntry { id: 138, value: "role" },
|
||||
StaticEntry { id: 140, value: "relay" },
|
||||
StaticEntry { id: 142, value: "Code" },
|
||||
StaticEntry { id: 144, value: "Reason" },
|
||||
StaticEntry { id: 146, value: "Text" },
|
||||
StaticEntry { id: 148, value: "Node" },
|
||||
StaticEntry { id: 150, value: "Role" },
|
||||
StaticEntry { id: 152, value: "Detail" },
|
||||
StaticEntry { id: 154, value: "Value" },
|
||||
StaticEntry { id: 156, value: "Subcode" },
|
||||
StaticEntry { id: 158, value: "NotUnderstood" },
|
||||
StaticEntry { id: 160, value: "qname" },
|
||||
StaticEntry { id: 162, value: "" },
|
||||
StaticEntry { id: 164, value: "From" },
|
||||
StaticEntry { id: 166, value: "FaultTo" },
|
||||
StaticEntry { id: 168, value: "EndpointReference" },
|
||||
StaticEntry { id: 170, value: "PortType" },
|
||||
StaticEntry { id: 172, value: "ServiceName" },
|
||||
StaticEntry { id: 174, value: "PortName" },
|
||||
StaticEntry { id: 176, value: "ReferenceProperties" },
|
||||
StaticEntry { id: 178, value: "RelationshipType" },
|
||||
StaticEntry { id: 180, value: "Reply" },
|
||||
StaticEntry { id: 182, value: "a" },
|
||||
StaticEntry { id: 184, value: "http://schemas.xmlsoap.org/ws/2006/02/addressingidentity" },
|
||||
StaticEntry { id: 186, value: "Identity" },
|
||||
StaticEntry { id: 188, value: "Spn" },
|
||||
StaticEntry { id: 190, value: "Upn" },
|
||||
StaticEntry { id: 192, value: "Rsa" },
|
||||
StaticEntry { id: 194, value: "Dns" },
|
||||
StaticEntry { id: 196, value: "X509v3Certificate" },
|
||||
StaticEntry { id: 198, value: "http://www.w3.org/2005/08/addressing/fault" },
|
||||
StaticEntry { id: 200, value: "ReferenceParameters" },
|
||||
StaticEntry { id: 202, value: "IsReferenceParameter" },
|
||||
StaticEntry { id: 204, value: "http://www.w3.org/2005/08/addressing/reply" },
|
||||
StaticEntry { id: 206, value: "http://www.w3.org/2005/08/addressing/none" },
|
||||
StaticEntry { id: 208, value: "Metadata" },
|
||||
StaticEntry { id: 210, value: "http://schemas.xmlsoap.org/ws/2004/08/addressing" },
|
||||
StaticEntry { id: 212, value: "http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous" },
|
||||
StaticEntry { id: 214, value: "http://schemas.xmlsoap.org/ws/2004/08/addressing/fault" },
|
||||
StaticEntry { id: 216, value: "http://schemas.xmlsoap.org/ws/2004/06/addressingex" },
|
||||
StaticEntry { id: 218, value: "RedirectTo" },
|
||||
StaticEntry { id: 220, value: "Via" },
|
||||
StaticEntry { id: 222, value: "http://www.w3.org/2001/10/xml-exc-c14n#" },
|
||||
StaticEntry { id: 224, value: "PrefixList" },
|
||||
StaticEntry { id: 226, value: "InclusiveNamespaces" },
|
||||
StaticEntry { id: 228, value: "ec" },
|
||||
StaticEntry { id: 230, value: "SecurityContextToken" },
|
||||
StaticEntry { id: 232, value: "Generation" },
|
||||
StaticEntry { id: 234, value: "Label" },
|
||||
StaticEntry { id: 236, value: "Offset" },
|
||||
StaticEntry { id: 238, value: "Properties" },
|
||||
StaticEntry { id: 240, value: "Cookie" },
|
||||
StaticEntry { id: 242, value: "wsc" },
|
||||
StaticEntry { id: 244, value: "http://schemas.xmlsoap.org/ws/2004/04/sc" },
|
||||
StaticEntry { id: 246, value: "http://schemas.xmlsoap.org/ws/2004/04/security/sc/dk" },
|
||||
StaticEntry { id: 248, value: "http://schemas.xmlsoap.org/ws/2004/04/security/sc/sct" },
|
||||
StaticEntry { id: 250, value: "http://schemas.xmlsoap.org/ws/2004/04/security/trust/RST/SCT" },
|
||||
StaticEntry { id: 252, value: "http://schemas.xmlsoap.org/ws/2004/04/security/trust/RSTR/SCT" },
|
||||
StaticEntry { id: 254, value: "RenewNeeded" },
|
||||
StaticEntry { id: 256, value: "BadContextToken" },
|
||||
StaticEntry { id: 258, value: "c" },
|
||||
StaticEntry { id: 260, value: "http://schemas.xmlsoap.org/ws/2005/02/sc/dk" },
|
||||
StaticEntry { id: 262, value: "http://schemas.xmlsoap.org/ws/2005/02/sc/sct" },
|
||||
StaticEntry { id: 264, value: "http://schemas.xmlsoap.org/ws/2005/02/trust/RST/SCT" },
|
||||
StaticEntry { id: 266, value: "http://schemas.xmlsoap.org/ws/2005/02/trust/RSTR/SCT" },
|
||||
StaticEntry { id: 268, value: "http://schemas.xmlsoap.org/ws/2005/02/trust/RST/SCT/Renew" },
|
||||
StaticEntry { id: 270, value: "http://schemas.xmlsoap.org/ws/2005/02/trust/RSTR/SCT/Renew" },
|
||||
StaticEntry { id: 272, value: "http://schemas.xmlsoap.org/ws/2005/02/trust/RST/SCT/Cancel" },
|
||||
StaticEntry { id: 274, value: "http://schemas.xmlsoap.org/ws/2005/02/trust/RSTR/SCT/Cancel" },
|
||||
StaticEntry { id: 276, value: "http://www.w3.org/2001/04/xmlenc#aes128-cbc" },
|
||||
StaticEntry { id: 278, value: "http://www.w3.org/2001/04/xmlenc#kw-aes128" },
|
||||
StaticEntry { id: 280, value: "http://www.w3.org/2001/04/xmlenc#aes192-cbc" },
|
||||
StaticEntry { id: 282, value: "http://www.w3.org/2001/04/xmlenc#kw-aes192" },
|
||||
StaticEntry { id: 284, value: "http://www.w3.org/2001/04/xmlenc#aes256-cbc" },
|
||||
StaticEntry { id: 286, value: "http://www.w3.org/2001/04/xmlenc#kw-aes256" },
|
||||
StaticEntry { id: 288, value: "http://www.w3.org/2001/04/xmlenc#des-cbc" },
|
||||
StaticEntry { id: 290, value: "http://www.w3.org/2000/09/xmldsig#dsa-sha1" },
|
||||
StaticEntry { id: 292, value: "http://www.w3.org/2001/10/xml-exc-c14n#WithComments" },
|
||||
StaticEntry { id: 294, value: "http://www.w3.org/2000/09/xmldsig#hmac-sha1" },
|
||||
StaticEntry { id: 296, value: "http://www.w3.org/2001/04/xmldsig-more#hmac-sha256" },
|
||||
StaticEntry { id: 298, value: "http://schemas.xmlsoap.org/ws/2005/02/sc/dk/p_sha1" },
|
||||
StaticEntry { id: 300, value: "http://www.w3.org/2001/04/xmlenc#ripemd160" },
|
||||
StaticEntry { id: 302, value: "http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p" },
|
||||
StaticEntry { id: 304, value: "http://www.w3.org/2000/09/xmldsig#rsa-sha1" },
|
||||
StaticEntry { id: 306, value: "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" },
|
||||
StaticEntry { id: 308, value: "http://www.w3.org/2001/04/xmlenc#rsa-1_5" },
|
||||
StaticEntry { id: 310, value: "http://www.w3.org/2000/09/xmldsig#sha1" },
|
||||
StaticEntry { id: 312, value: "http://www.w3.org/2001/04/xmlenc#sha256" },
|
||||
StaticEntry { id: 314, value: "http://www.w3.org/2001/04/xmlenc#sha512" },
|
||||
StaticEntry { id: 316, value: "http://www.w3.org/2001/04/xmlenc#tripledes-cbc" },
|
||||
StaticEntry { id: 318, value: "http://www.w3.org/2001/04/xmlenc#kw-tripledes" },
|
||||
StaticEntry { id: 320, value: "http://schemas.xmlsoap.org/2005/02/trust/tlsnego#TLS_Wrap" },
|
||||
StaticEntry { id: 322, value: "http://schemas.xmlsoap.org/2005/02/trust/spnego#GSS_Wrap" },
|
||||
StaticEntry { id: 324, value: "http://schemas.microsoft.com/ws/2006/05/security" },
|
||||
StaticEntry { id: 326, value: "dnse" },
|
||||
StaticEntry { id: 328, value: "o" },
|
||||
StaticEntry { id: 330, value: "Password" },
|
||||
StaticEntry { id: 332, value: "PasswordText" },
|
||||
StaticEntry { id: 334, value: "Username" },
|
||||
StaticEntry { id: 336, value: "UsernameToken" },
|
||||
StaticEntry { id: 338, value: "BinarySecurityToken" },
|
||||
StaticEntry { id: 340, value: "EncodingType" },
|
||||
StaticEntry { id: 342, value: "KeyIdentifier" },
|
||||
StaticEntry { id: 344, value: "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" },
|
||||
StaticEntry { id: 346, value: "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#HexBinary" },
|
||||
StaticEntry { id: 348, value: "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Text" },
|
||||
StaticEntry { id: 350, value: "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509SubjectKeyIdentifier" },
|
||||
StaticEntry { id: 352, value: "http://docs.oasis-open.org/wss/oasis-wss-kerberos-token-profile-1.1#GSS_Kerberosv5_AP_REQ" },
|
||||
StaticEntry { id: 354, value: "http://docs.oasis-open.org/wss/oasis-wss-kerberos-token-profile-1.1#GSS_Kerberosv5_AP_REQ1510" },
|
||||
StaticEntry { id: 356, value: "http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.0#SAMLAssertionID" },
|
||||
StaticEntry { id: 358, value: "Assertion" },
|
||||
StaticEntry { id: 360, value: "urn:oasis:names:tc:SAML:1.0:assertion" },
|
||||
StaticEntry { id: 362, value: "http://docs.oasis-open.org/wss/oasis-wss-rel-token-profile-1.0.pdf#license" },
|
||||
StaticEntry { id: 364, value: "FailedAuthentication" },
|
||||
StaticEntry { id: 366, value: "InvalidSecurityToken" },
|
||||
StaticEntry { id: 368, value: "InvalidSecurity" },
|
||||
StaticEntry { id: 370, value: "k" },
|
||||
StaticEntry { id: 372, value: "SignatureConfirmation" },
|
||||
StaticEntry { id: 374, value: "TokenType" },
|
||||
StaticEntry { id: 376, value: "http://docs.oasis-open.org/wss/oasis-wss-soap-message-security-1.1#ThumbprintSHA1" },
|
||||
StaticEntry { id: 378, value: "http://docs.oasis-open.org/wss/oasis-wss-soap-message-security-1.1#EncryptedKey" },
|
||||
StaticEntry { id: 380, value: "http://docs.oasis-open.org/wss/oasis-wss-soap-message-security-1.1#EncryptedKeySHA1" },
|
||||
StaticEntry { id: 382, value: "http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1" },
|
||||
StaticEntry { id: 384, value: "http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0" },
|
||||
StaticEntry { id: 386, value: "http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLID" },
|
||||
StaticEntry { id: 388, value: "AUTH-HASH" },
|
||||
StaticEntry { id: 390, value: "RequestSecurityTokenResponse" },
|
||||
StaticEntry { id: 392, value: "KeySize" },
|
||||
StaticEntry { id: 394, value: "RequestedTokenReference" },
|
||||
StaticEntry { id: 396, value: "AppliesTo" },
|
||||
StaticEntry { id: 398, value: "Authenticator" },
|
||||
StaticEntry { id: 400, value: "CombinedHash" },
|
||||
// ---- xsi / xsd / nil — heavily used by .NET XmlSerializer for
|
||||
// value types in custom message-contract bodies. These are
|
||||
// String 218..222 in the canonical table.
|
||||
StaticEntry { id: 436, value: "type" },
|
||||
StaticEntry { id: 438, value: "i" },
|
||||
StaticEntry { id: 440, value: "http://www.w3.org/2001/XMLSchema-instance" },
|
||||
StaticEntry { id: 442, value: "http://www.w3.org/2001/XMLSchema" },
|
||||
StaticEntry { id: 444, value: "nil" },
|
||||
];
|
||||
|
||||
/// Lookup an entry by static-dictionary ID. Returns `None` for IDs
|
||||
@@ -460,9 +290,10 @@ pub fn position_of_static(value: &str) -> Option<u32> {
|
||||
let map = REVERSE.get_or_init(|| {
|
||||
let mut map = HashMap::with_capacity(STATIC_ENTRIES.len());
|
||||
for entry in STATIC_ENTRIES {
|
||||
// First-id-wins for duplicates (the .NET dictionary has
|
||||
// entries 86 + 94 = "TokenType"; we lock the lower id so
|
||||
// round-trip lookups are deterministic).
|
||||
// First-id-wins for duplicates (the canonical dictionary
|
||||
// has TokenType at both id 116 (String 58) and id 374
|
||||
// (String 187); we lock the lower id so round-trip lookups
|
||||
// are deterministic).
|
||||
map.entry(entry.value).or_insert(entry.id);
|
||||
}
|
||||
map
|
||||
@@ -495,6 +326,22 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn static_entries_use_even_ids() {
|
||||
// `[MC-NBFS]` reserves odd ids for the per-session dynamic dict
|
||||
// (`[MC-NBFX]` records 0xAA / 0xAB DictionaryText use the parity
|
||||
// bit to discriminate). All static-table ids must be even.
|
||||
for entry in STATIC_ENTRIES {
|
||||
assert_eq!(
|
||||
entry.id % 2,
|
||||
0,
|
||||
"static entry id {} ('{}') is odd — odd ids are reserved for the dynamic dict",
|
||||
entry.id,
|
||||
entry.value
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lookup_returns_known_entries() {
|
||||
assert_eq!(lookup_static(0), Some("mustUnderstand"));
|
||||
@@ -503,45 +350,63 @@ mod tests {
|
||||
lookup_static(4),
|
||||
Some("http://www.w3.org/2003/05/soap-envelope")
|
||||
);
|
||||
assert_eq!(lookup_static(8), Some("Header"));
|
||||
assert_eq!(lookup_static(14), Some("Body"));
|
||||
}
|
||||
|
||||
/// Fault-subset round-trip: every entry the SOAP-1.2 fault body
|
||||
/// references must resolve. These are the exact dict ids the
|
||||
/// AVEVA MxDataProvider sends in `dispatcher/fault` envelopes
|
||||
/// (verified live via `MX_ASB_TRACE_REPLY`). Earlier versions of
|
||||
/// this table mis-numbered the SOAP-fault subset (Fault was at id
|
||||
/// 114 instead of 134), causing `decode_envelope` to silently drop
|
||||
/// the resolved field name and the consumer to see opaque
|
||||
/// `Static(N)` tokens.
|
||||
#[test]
|
||||
fn fault_subset_resolves_to_canonical_strings() {
|
||||
assert_eq!(lookup_static(132), Some("s"));
|
||||
assert_eq!(lookup_static(134), Some("Fault"));
|
||||
assert_eq!(lookup_static(136), Some("MustUnderstand"));
|
||||
assert_eq!(lookup_static(142), Some("Code"));
|
||||
assert_eq!(lookup_static(144), Some("Reason"));
|
||||
assert_eq!(lookup_static(146), Some("Text"));
|
||||
assert_eq!(lookup_static(148), Some("Node"));
|
||||
assert_eq!(lookup_static(150), Some("Role"));
|
||||
assert_eq!(lookup_static(152), Some("Detail"));
|
||||
assert_eq!(lookup_static(154), Some("Value"));
|
||||
assert_eq!(lookup_static(156), Some("Subcode"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn xmlserializer_extras_resolve() {
|
||||
// The 436..444 high-id extras are essential for any
|
||||
// [MessageContract] response body that uses XmlSerializer.
|
||||
assert_eq!(lookup_static(436), Some("type"));
|
||||
assert_eq!(lookup_static(438), Some("i"));
|
||||
assert_eq!(
|
||||
lookup_static(440),
|
||||
Some("http://www.w3.org/2001/XMLSchema-instance")
|
||||
);
|
||||
assert_eq!(
|
||||
lookup_static(442),
|
||||
Some("http://www.w3.org/2001/XMLSchema")
|
||||
);
|
||||
assert_eq!(lookup_static(444), Some("nil"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lookup_returns_none_for_unmapped_ids() {
|
||||
assert_eq!(lookup_static(1), None); // odd ids are namespace pairs we don't include
|
||||
assert_eq!(lookup_static(999_999), None);
|
||||
fn position_of_static_round_trips_known_strings() {
|
||||
assert_eq!(position_of_static("mustUnderstand"), Some(0));
|
||||
assert_eq!(position_of_static("Envelope"), Some(2));
|
||||
assert_eq!(position_of_static("Fault"), Some(134));
|
||||
assert_eq!(position_of_static("Reason"), Some(144));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn position_of_known_strings_is_consistent_with_lookup() {
|
||||
for entry in STATIC_ENTRIES {
|
||||
// Two entries with the same string ("TokenType" at 86 and 94)
|
||||
// collapse to the lower id by `or_insert`. Skip those for
|
||||
// the strict round-trip assertion; reverse-lookup of the
|
||||
// duplicate string is allowed to map to any of its ids.
|
||||
let id = position_of_static(entry.value).unwrap();
|
||||
assert!(
|
||||
id <= entry.id,
|
||||
"position_of returned a higher id than the entry"
|
||||
);
|
||||
assert_eq!(lookup_static(id), Some(entry.value));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn position_of_unknown_strings_is_none() {
|
||||
assert_eq!(position_of_static("not-in-table"), None);
|
||||
assert_eq!(position_of_static("http://ASB.IDataV2"), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_string_round_trips_to_id_142() {
|
||||
// Position 142 in the spec is the empty string. Sanity-check
|
||||
// we got the right slot.
|
||||
assert_eq!(lookup_static(142), Some(""));
|
||||
assert_eq!(position_of_static(""), Some(142));
|
||||
fn lookup_returns_none_for_unknown() {
|
||||
// 1 is odd → reserved for dynamic dict; should always be None.
|
||||
assert_eq!(lookup_static(1), None);
|
||||
// Way past the table.
|
||||
assert_eq!(lookup_static(9999), None);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user