Feature: LSP StdioTransport coverage
  As a developer maintaining the LSP transport layer
  I need thorough tests for StdioTransport
  So that all error paths and normal flows are exercised

  # ── start() error paths ─────────────────────────────────────────

  Scenario: ltcov start raises RuntimeError when already alive
    Given ltcov I create a StdioTransport for command "cat"
    And ltcov the transport has a running mock process
    When ltcov I try to start the transport
    Then ltcov the error should be a RuntimeError with message "already started"

  Scenario: ltcov start raises LspError on FileNotFoundError
    Given ltcov I create a StdioTransport for command "nonexistent_binary_xyz"
    And ltcov Popen is mocked to raise FileNotFoundError
    When ltcov I try to start the transport
    Then ltcov the error should be an LspError with message "not found"

  Scenario: ltcov start raises LspError on OSError
    Given ltcov I create a StdioTransport for command "bad_command"
    And ltcov Popen is mocked to raise OSError with "Permission denied"
    When ltcov I try to start the transport
    Then ltcov the error should be an LspError with message "Failed to start"

  # ── stop() paths ────────────────────────────────────────────────

  Scenario: ltcov stop returns None when not started
    Given ltcov I create a StdioTransport for command "echo"
    When ltcov I stop the transport
    Then ltcov the stop result should be None

  Scenario: ltcov stop returns exit code when process already exited
    Given ltcov I create a StdioTransport for command "echo"
    And ltcov the transport has a mock process that already exited with code 0
    When ltcov I stop the transport
    Then ltcov the stop result should be 0
    And ltcov the internal process should be None

  Scenario: ltcov stop returns exit code when process already exited with error
    Given ltcov I create a StdioTransport for command "echo"
    And ltcov the transport has a mock process that already exited with code 1
    When ltcov I stop the transport
    Then ltcov the stop result should be 1

  Scenario: ltcov stop force kills on timeout
    Given ltcov I create a StdioTransport for command "sleep"
    And ltcov the transport has a mock process that ignores terminate
    When ltcov I stop the transport with timeout 0.1
    Then ltcov the mock process should have been killed
    And ltcov the stop result should be an integer

  # ── send_message() paths ────────────────────────────────────────

  Scenario: ltcov send_message raises RuntimeError when not started
    Given ltcov I create a StdioTransport for command "echo"
    When ltcov I try to send a message
    Then ltcov the error should be a RuntimeError with message "not started"

  Scenario: ltcov send_message raises RuntimeError when stdin is None
    Given ltcov I create a StdioTransport for command "echo"
    And ltcov the transport has a mock process with no stdin
    When ltcov I try to send a message
    Then ltcov the error should be a RuntimeError with message "not started"

  Scenario: ltcov send_message writes Content-Length framed JSON-RPC
    Given ltcov I create a StdioTransport for command "echo"
    And ltcov the transport has a mock process with writable stdin
    When ltcov I send the message {"jsonrpc":"2.0","method":"initialize","id":1}
    Then ltcov the written bytes should contain "Content-Length:"
    And ltcov the written bytes should contain "initialize"

  Scenario: ltcov send_message raises BrokenPipeError on dead process
    Given ltcov I create a StdioTransport for command "echo"
    And ltcov the transport has a mock process with broken stdin
    When ltcov I try to send a message
    Then ltcov the error should be a BrokenPipeError

  # ── read_message() paths ────────────────────────────────────────

  Scenario: ltcov read_message raises RuntimeError when not started
    Given ltcov I create a StdioTransport for command "echo"
    When ltcov I try to read a message
    Then ltcov the error should be a RuntimeError with message "not started"

  Scenario: ltcov read_message raises RuntimeError when stdout is None
    Given ltcov I create a StdioTransport for command "echo"
    And ltcov the transport has a mock process with no stdout
    When ltcov I try to read a message
    Then ltcov the error should be a RuntimeError with message "not started"

  Scenario: ltcov read_message returns None on select timeout
    Given ltcov I create a StdioTransport for command "echo"
    And ltcov the transport has a mock process with empty stdout
    And ltcov select is mocked to return not ready
    When ltcov I read a message with timeout 1.0
    Then ltcov the read result should be None

  Scenario: ltcov read_message returns None on EOF
    Given ltcov I create a StdioTransport for command "echo"
    And ltcov the transport has a mock process with stdout that returns EOF
    When ltcov I read a message with timeout 1.0
    Then ltcov the read result should be None

  Scenario: ltcov read_message uses default timeout when None
    Given ltcov I create a StdioTransport for command "echo"
    And ltcov the transport has a mock process with stdout that returns EOF
    When ltcov I read a message with default timeout
    Then ltcov the read result should be None

  Scenario: ltcov read_message parses valid Content-Length message
    Given ltcov I create a StdioTransport for command "echo"
    And ltcov the transport has a mock process with a valid JSON-RPC response
    When ltcov I read a message with timeout 5.0
    Then ltcov the read result should have key "jsonrpc" with value "2.0"

  Scenario: ltcov read_message returns None on invalid content-length value
    Given ltcov I create a StdioTransport for command "echo"
    And ltcov the transport has a mock process with invalid content-length header
    When ltcov I read a message with timeout 5.0
    Then ltcov the read result should be None

  Scenario: ltcov read_message returns None when no content-length header
    Given ltcov I create a StdioTransport for command "echo"
    And ltcov the transport has a mock process with no content-length header
    When ltcov I read a message with timeout 5.0
    Then ltcov the read result should be None

  Scenario: ltcov read_message raises ValueError on oversized message
    Given ltcov I create a StdioTransport for command "echo"
    And ltcov the transport has a mock process with oversized content-length
    When ltcov I try to read a message
    Then ltcov the error should be a ValueError with message "too large"

  Scenario: ltcov read_message returns None on body select timeout
    Given ltcov I create a StdioTransport for command "echo"
    And ltcov the transport has a mock process with headers but body times out
    When ltcov I read a message with timeout 5.0
    Then ltcov the read result should be None

  Scenario: ltcov read_message returns None on truncated body
    Given ltcov I create a StdioTransport for command "echo"
    And ltcov the transport has a mock process with truncated body
    When ltcov I read a message with timeout 5.0
    Then ltcov the read result should be None

  Scenario: ltcov read_message returns None on invalid JSON body
    Given ltcov I create a StdioTransport for command "echo"
    And ltcov the transport has a mock process with invalid JSON body
    When ltcov I read a message with timeout 5.0
    Then ltcov the read result should be None
