# SPDX-License-Identifier: MIT
#
# Tests for MIT-SHM extension.

import struct

import pytest

from proto import shm
from xclient import Extension, X11Reply


class TestShmCreateSegment:
    @pytest.mark.swapped_client
    def test_create_segment_reply_sequence_swapped(self, xserver, xclient_swapped):
        """
        ProcShmCreateSegment was missing swaps(&rep.sequenceNumber) and
        swapl(&rep.length) for byte-swapped clients.

        Without the fix the sequence number in the reply is
        byte-reversed.  We send the request and verify that the
        reply's sequence number matches the expected value.

        ShmCreateSegment requires SHM fd-passing (SHM 1.2+) and a
        local connection (Unix socket).  The reply also carries an fd
        via SCM_RIGHTS which our simple recv() silently drops — that's
        fine, we only need to check the header fields.

        Fixed in commit c49c150dcfb7 ("Xext/shm: add missing reply
        byte-swap in ProcShmCreateSegment").
        """
        conn = xclient_swapped

        ext = conn.query_extension(Extension.MIT_SHM)
        if not ext:
            pytest.skip("MIT-SHM extension not available")

        # Query SHM version
        req = shm.QueryVersionRequest(opcode=ext.opcode)
        conn.send_request(req)
        resp = conn.recv_response(timeout=5.0)

        if not isinstance(resp, X11Reply):
            pytest.skip("SHM QueryVersion failed")

        # Check for SHM 1.2+ (fd-passing / CreateSegment support)
        # Reply: type(1) + sharedPixmaps(1) + seq(2) + length(4) +
        #        majorVersion(2) + minorVersion(2) + ...
        if len(resp.data) < 12:
            pytest.skip("SHM QueryVersion reply too short")

        major = struct.unpack_from(">H", resp.data, 8)[0]
        minor = struct.unpack_from(">H", resp.data, 10)[0]
        if major < 1 or (major == 1 and minor < 2):
            pytest.skip(f"SHM {major}.{minor} does not support CreateSegment")

        shmseg_id = conn.alloc_id()
        seq = conn.send_request(
            shm.CreateSegmentRequest(
                opcode=ext.opcode,
                shmseg=shmseg_id,
                size=4096,
                read_only=False,
            )
        )

        # Read the 32-byte reply header.  The fd arrives as
        # ancillary data which plain recv() drops, but the data
        # bytes still arrive on the stream.
        resp = conn.recv_response(timeout=5.0)

        assert xserver.is_alive, "Server crashed"
        assert isinstance(resp, X11Reply), f"Expected reply, got {resp}"

        # Verify the sequence number was swapped correctly.
        reply_seq = struct.unpack_from(">H", resp.data, 2)[0]
        assert reply_seq == (seq & 0xFFFF), (
            f"Reply sequence = {reply_seq:#06x}, "
            f"expected {seq & 0xFFFF:#06x}. "
            f"sequenceNumber not byte-swapped in "
            f"ProcShmCreateSegment reply."
        )
