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