forked from HAL9000/cleveragents-core
4874f2ad6f
ISSUES CLOSED: #175
222 lines
6.6 KiB
Python
222 lines
6.6 KiB
Python
"""Step definitions for validation_pipeline_stream_coverage.feature.
|
|
|
|
Exercises the _ThreadLocalStream helper methods that lack coverage:
|
|
- encoding property (line 58)
|
|
- writable() method (line 61)
|
|
- readable() method (line 64)
|
|
- flush() with active buffer (line 75)
|
|
- isatty() method (line 79)
|
|
|
|
All tests use a simple mock original stream — no real I/O needed.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import Any
|
|
|
|
from behave import given, then, when
|
|
from behave.runner import Context
|
|
|
|
from cleveragents.application.services.validation_pipeline import (
|
|
_ThreadLocalStream,
|
|
)
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Mock original stream
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class _MockOriginalStream:
|
|
"""Configurable mock that mimics a real stdout/stderr."""
|
|
|
|
def __init__(self) -> None:
|
|
self.encoding: str = "utf-8"
|
|
self._has_encoding: bool = True
|
|
self._isatty_return: bool = False
|
|
self._written: list[str] = []
|
|
self._flushed: bool = False
|
|
|
|
def write(self, s: str) -> int:
|
|
self._written.append(s)
|
|
return len(s)
|
|
|
|
def flush(self) -> None:
|
|
self._flushed = True
|
|
|
|
def isatty(self) -> bool:
|
|
return self._isatty_return
|
|
|
|
|
|
class _NoEncodingStream:
|
|
"""Mock stream without an encoding attribute."""
|
|
|
|
def write(self, s: str) -> int:
|
|
return len(s)
|
|
|
|
def flush(self) -> None:
|
|
pass
|
|
|
|
def isatty(self) -> bool:
|
|
return False
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Background
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
@given("a thread-local stream wrapping a mock original stream")
|
|
def step_given_tl_stream(context: Context) -> None:
|
|
context.tls_original = _MockOriginalStream()
|
|
context.tls_stream = _ThreadLocalStream(context.tls_original)
|
|
context.tls_result: Any = None
|
|
context.tls_captured: str = ""
|
|
context.tls_error: Exception | None = None
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Given steps
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
@given('the original stream has encoding "{enc}"')
|
|
def step_given_encoding(context: Context, enc: str) -> None:
|
|
context.tls_original.encoding = enc
|
|
|
|
|
|
@given("the original stream has no encoding attribute")
|
|
def step_given_no_encoding(context: Context) -> None:
|
|
context.tls_stream = _ThreadLocalStream(_NoEncodingStream())
|
|
|
|
|
|
@given("the original stream isatty returns True")
|
|
def step_given_isatty_true(context: Context) -> None:
|
|
context.tls_original._isatty_return = True
|
|
|
|
|
|
@given("the original stream isatty returns False")
|
|
def step_given_isatty_false(context: Context) -> None:
|
|
context.tls_original._isatty_return = False
|
|
|
|
|
|
@given("capture is started on the thread-local stream")
|
|
def step_given_capture_started(context: Context) -> None:
|
|
context.tls_stream.start_capture()
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# When steps
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
@when("I read the thread-local stream encoding")
|
|
def step_when_read_encoding(context: Context) -> None:
|
|
context.tls_result = context.tls_stream.encoding
|
|
|
|
|
|
@when("I check if the thread-local stream is writable")
|
|
def step_when_check_writable(context: Context) -> None:
|
|
context.tls_result = context.tls_stream.writable()
|
|
|
|
|
|
@when("I check if the thread-local stream is readable")
|
|
def step_when_check_readable(context: Context) -> None:
|
|
context.tls_result = context.tls_stream.readable()
|
|
|
|
|
|
@when("I flush the thread-local stream")
|
|
def step_when_flush(context: Context) -> None:
|
|
try:
|
|
context.tls_stream.flush()
|
|
context.tls_error = None
|
|
except Exception as exc:
|
|
context.tls_error = exc
|
|
|
|
|
|
@when("I check if the thread-local stream isatty")
|
|
def step_when_check_isatty(context: Context) -> None:
|
|
context.tls_result = context.tls_stream.isatty()
|
|
|
|
|
|
@when('I write "{text}" to the thread-local stream')
|
|
def step_when_write(context: Context, text: str) -> None:
|
|
context.tls_stream.write(text)
|
|
|
|
|
|
@when("capture is stopped on the thread-local stream")
|
|
def step_when_stop_capture(context: Context) -> None:
|
|
context.tls_captured = context.tls_stream.stop_capture()
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Then steps
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
@then('the encoding should be "{enc}"')
|
|
def step_then_encoding(context: Context, enc: str) -> None:
|
|
assert context.tls_result == enc, (
|
|
f"Expected encoding '{enc}', got '{context.tls_result}'"
|
|
)
|
|
|
|
|
|
@then("writable should return True")
|
|
def step_then_writable_true(context: Context) -> None:
|
|
assert context.tls_result is True, (
|
|
f"Expected writable()=True, got {context.tls_result}"
|
|
)
|
|
|
|
|
|
@then("readable should return False")
|
|
def step_then_readable_false(context: Context) -> None:
|
|
assert context.tls_result is False, (
|
|
f"Expected readable()=False, got {context.tls_result}"
|
|
)
|
|
|
|
|
|
@then("the flush should succeed without error")
|
|
def step_then_flush_ok(context: Context) -> None:
|
|
assert context.tls_error is None, f"Expected no error, got {context.tls_error}"
|
|
|
|
|
|
@then("the original stream flush should be called")
|
|
def step_then_original_flushed(context: Context) -> None:
|
|
assert context.tls_original._flushed, (
|
|
"Expected original stream flush() to be called"
|
|
)
|
|
|
|
|
|
@then("isatty should return True")
|
|
def step_then_isatty_true(context: Context) -> None:
|
|
assert context.tls_result is True, (
|
|
f"Expected isatty()=True, got {context.tls_result}"
|
|
)
|
|
|
|
|
|
@then("isatty should return False")
|
|
def step_then_isatty_false(context: Context) -> None:
|
|
assert context.tls_result is False, (
|
|
f"Expected isatty()=False, got {context.tls_result}"
|
|
)
|
|
|
|
|
|
@then('the original stream should have received "{text}"')
|
|
def step_then_original_received(context: Context, text: str) -> None:
|
|
assert text in context.tls_original._written, (
|
|
f"Expected '{text}' in original writes, got {context.tls_original._written}"
|
|
)
|
|
|
|
|
|
@then('the captured text should be "{text}"')
|
|
def step_then_captured_text(context: Context, text: str) -> None:
|
|
assert context.tls_captured == text, (
|
|
f"Expected captured text '{text}', got '{context.tls_captured}'"
|
|
)
|
|
|
|
|
|
@then("the captured text should be empty")
|
|
def step_then_captured_text_empty(context: Context) -> None:
|
|
assert context.tls_captured == "", (
|
|
f"Expected empty captured text, got '{context.tls_captured}'"
|
|
)
|