"""G6 — Cluster L regression pins for adversarial inspect attrs.

Pin two wave-2 fixes through a Python wire round-trip:

**G2 (commit `e9ea7e9`).** Pre-fix, sysfs attribute values
containing `"` or `\\` were spliced into inspect JSON without
escaping. The SDK's `json.loads` crashed on the malformed
bytes. The fix extracted `hrb-code/src/json_escape.zig` with
12 Zig-side test pins; this Python pin exercises the SAME
discipline through the wire by inspecting a URN with
deliberately adversarial attrs (`"a-quote` + `\\a-slash`).
Pre-fix this raised `JSONDecodeError`; post-fix `json.loads`
returns a dict with the original characters intact.

**G8 (commit `aee8750`).** Pre-fix, the USB-inspect attribute
buffer was 64 bytes — descriptors with longer serials (USB
spec allows up to 255 UTF-16 chars) were silently truncated.
The fix bumped the buffer to 256 + this pin proves a
200-character value round-trips through the inspect emit path
without truncation. (The buffer change shipped in
`LinuxUsbBackend`; the wire-emit path (`server.zig`) doesn't
have the same buffer constraint but THIS test pins the broker-
wide end-to-end "long-value attr survives inspect" invariant
regardless of which backend.)

Both pins use the `hw:/test/edge_attrs` URN — a synthetic
fixture seeded in `server.zig` against the fake worker (see
the `_g6_edge_attrs` block there). Production-safe: the
`hw:/test/` worker is already the synthetic-fixture scope.
"""

from __future__ import annotations

from typing import TYPE_CHECKING

import pytest

from tests.contract.conftest import rt

if TYPE_CHECKING:
    import socket

pytestmark = pytest.mark.contract


_URN = "hw:/test/edge_attrs"


def test_g2_double_quote_in_attr_survives_json_loads(
    raw_broker: socket.socket,
) -> None:
    """The G2 regression pin (Python integration half). Inspect
    a URN whose attr value contains `"`; assert the response
    parses + the value round-trips byte-equivalent. Pre-fix
    `json.loads` raised JSONDecodeError on the malformed bytes."""
    resp = rt(raw_broker, {"op": "inspect", "urn": _URN})
    assert resp.get("ok") is True, f"setup: inspect failed: {resp!r}"
    # The wire shape (post-G2 / per the inspect formatter):
    # the attrs dict is inside the `resource` wrap (or top-level —
    # check whichever surface). Find the json_dquote key.
    attrs = resp.get("resource", {}).get("attrs") or resp.get("attrs")
    assert attrs is not None, f"no attrs in response: {resp!r}"
    assert attrs.get("json_dquote") == 'has"a-quote', (
        f'G2 regression: value with `"` did not round-trip. Got: {attrs.get("json_dquote")!r}'
    )


def test_g2_backslash_in_attr_survives_json_loads(
    raw_broker: socket.socket,
) -> None:
    """Same as above but for `\\`. Two different shapes of the
    escape vulnerability — pre-G2 either could crash the client."""
    resp = rt(raw_broker, {"op": "inspect", "urn": _URN})
    assert resp.get("ok") is True
    attrs = resp.get("resource", {}).get("attrs") or resp.get("attrs")
    assert attrs.get("json_bslash") == "has\\a-slash", (
        f"G2 regression: value with `\\\\` did not round-trip. Got: {attrs.get('json_bslash')!r}"
    )


def test_g8_long_value_attr_survives_inspect_emit(
    raw_broker: socket.socket,
) -> None:
    """G8 regression pin (broker-wide, not USB-specific). The
    fixture seeds a 213-character attr value
    (`F4GS9PWWJCM7-` + 200 `X`s). Pre-G8 the LinuxUsbBackend's
    `s_buf` was 64 bytes and silently truncated; this test pins
    the end-to-end "long value round-trips through inspect"
    invariant at the wire level."""
    resp = rt(raw_broker, {"op": "inspect", "urn": _URN})
    attrs = resp.get("resource", {}).get("attrs") or resp.get("attrs")
    value = attrs.get("long_serial")
    expected = "F4GS9PWWJCM7-" + "X" * 200
    assert value == expected, (
        f"G8 regression: long attr value truncated or mangled. "
        f"Got len={len(value or '')}, expected {len(expected)}. "
        f"Got: {value!r}"
    )


def test_existing_test_urns_still_have_no_per_slot_attrs(
    raw_broker: socket.socket,
) -> None:
    """Contrapositive — the FakeBackend extension (`addWithAttrs`)
    MUST NOT change the inspect shape for slots seeded via the
    plain `add()`. `hw:/test/dev0` has no per-slot attrs;
    inspecting it should return only the synthetic markers
    (`backend` + `synthetic`)."""
    resp = rt(raw_broker, {"op": "inspect", "urn": "hw:/test/dev0"})
    attrs = resp.get("resource", {}).get("attrs") or resp.get("attrs")
    assert attrs == {"backend": "mgf-hrb-fake", "synthetic": "true"}, (
        f"FakeBackend extension regressed the basic-add inspect shape. Got: {attrs!r}"
    )
