7a2760b85f
Add 16 BDD scenarios covering: - PlainElementRenderer.render_element dispatch for all 9 element types - _BaseElementRenderer.serialize() via PlainElementRenderer - ColorElementRenderer.render_element dispatch for all element types - TableElementRenderer can_render (True/False) and render_element dispatch - RichElementRenderer.render_element dispatch + can_render True path - JsonElementRenderer.render_element dispatch (all render_* return "") - YamlElementRenderer.render_element dispatch (all render_* return "") - RendererRegistry.resolve() unknown format fallback to plain - RendererRegistry.resolve() ValueError when no plain fallback registered Raises cli/output/registry.py coverage from 60.9% to pass the 96.5% overall threshold. ISSUES CLOSED: #917
223 lines
9.3 KiB
Gherkin
223 lines
9.3 KiB
Gherkin
Feature: Output Rendering Framework — Registry, Renderer, and Capabilities
|
|
|
|
# ================================================================
|
|
# RendererRegistry
|
|
# ================================================================
|
|
|
|
Scenario: RendererRegistry registers and resolves built-in formats
|
|
Given the default renderer registry
|
|
Then the registry has format "plain" registered
|
|
And the registry has format "color" registered
|
|
And the registry has format "table" registered
|
|
And the registry has format "rich" registered
|
|
And the registry has format "json" registered
|
|
And the registry has format "yaml" registered
|
|
|
|
Scenario: RendererRegistry available_formats returns sorted list
|
|
Given the default renderer registry
|
|
Then the available formats are "color,json,plain,rich,table,yaml"
|
|
|
|
Scenario: RendererRegistry is_registered returns False for unknown
|
|
Given the default renderer registry
|
|
Then the registry does not have format "csv" registered
|
|
|
|
Scenario: RendererRegistry resolves plain format
|
|
Given the default renderer registry
|
|
When I resolve format "plain" from the registry
|
|
Then the resolved renderer format name is "plain"
|
|
|
|
Scenario: RendererRegistry resolves json format
|
|
Given the default renderer registry
|
|
When I resolve format "json" from the registry
|
|
Then the resolved renderer format name is "json"
|
|
|
|
Scenario: RendererRegistry resolve falls back from rich to plain on non-TTY
|
|
Given the default renderer registry
|
|
And a non-TTY terminal environment
|
|
When I resolve format "rich" from the registry with terminal caps
|
|
Then the resolved renderer format name is "plain"
|
|
|
|
Scenario: RendererRegistry supports custom format registration
|
|
Given a new empty renderer registry
|
|
When I register a custom "csv" format in the registry
|
|
Then the registry has format "csv" registered
|
|
|
|
# ================================================================
|
|
# ElementRenderer protocol
|
|
# ================================================================
|
|
|
|
Scenario: PlainElementRenderer renders panel element
|
|
Given a PlainElementRenderer
|
|
When I render a panel with title "Test" through the renderer
|
|
Then the renderer output contains "Test"
|
|
|
|
Scenario: PlainElementRenderer can_render always returns True
|
|
Given a PlainElementRenderer
|
|
Then the renderer can_render returns True for any terminal
|
|
|
|
Scenario: ColorElementRenderer can_render requires ANSI
|
|
Given a ColorElementRenderer
|
|
Then the renderer can_render returns False without ANSI
|
|
|
|
Scenario: RichElementRenderer can_render requires cursor movement
|
|
Given a RichElementRenderer
|
|
Then the renderer can_render returns False without cursor movement
|
|
|
|
Scenario: JsonElementRenderer serializes output
|
|
Given a JsonElementRenderer
|
|
When I serialize a StructuredOutput through the renderer
|
|
Then the serialized output is valid JSON
|
|
|
|
Scenario: YamlElementRenderer serializes output with sorted keys
|
|
Given a YamlElementRenderer
|
|
When I serialize a StructuredOutput through the renderer
|
|
Then the serialized output is valid YAML
|
|
And the serialized output has sorted keys
|
|
|
|
# ================================================================
|
|
# TerminalCapabilities extended fields
|
|
# ================================================================
|
|
|
|
Scenario: TerminalCapabilities has all 11 spec fields
|
|
When I create a full TerminalCapabilities
|
|
Then the capabilities has width 120
|
|
And the capabilities has height 40
|
|
And the capabilities has supports_256_color True
|
|
And the capabilities has supports_truecolor True
|
|
And the capabilities has supports_unicode True
|
|
And the capabilities has supports_alternate_screen True
|
|
And the capabilities has no_color False
|
|
And the capabilities has term_program "iTerm2"
|
|
|
|
Scenario: TerminalCapabilities backward-compatible aliases work
|
|
When I create a full TerminalCapabilities
|
|
Then the capabilities supports_cursor property matches supports_cursor_movement
|
|
And the capabilities term property matches term_program
|
|
|
|
# ================================================================
|
|
# ColumnDef.type serialisation
|
|
# ================================================================
|
|
|
|
Scenario: ColumnDef serialises type field as "type" in JSON
|
|
Given an OutputSession with format "json" using JsonMaterializer
|
|
When I create a table with ColumnDef objects "Name,Status"
|
|
And I add a dict row with Name "Name" and Status "Alice"
|
|
And I close the table handle
|
|
And the session is closed
|
|
Then the json output is valid JSON
|
|
And the json output ColumnDef uses type key not col_type
|
|
|
|
Scenario: ColumnDef accepts type alias in constructor
|
|
When I create a ColumnDef with type alias "integer"
|
|
Then the ColumnDef col_type is "integer"
|
|
|
|
# ================================================================
|
|
# YAML sorted keys
|
|
# ================================================================
|
|
|
|
Scenario: YAML output uses sorted keys
|
|
Given an OutputSession with format "yaml" using YamlMaterializer
|
|
When I create a panel handle with title "Sort Test"
|
|
And I set entry "Zebra" to "last"
|
|
And I set entry "Alpha" to "first"
|
|
And I close the panel handle
|
|
And the session is closed
|
|
Then the yaml output is valid YAML
|
|
|
|
# ================================================================
|
|
# Progress omitted from JSON output
|
|
# ================================================================
|
|
|
|
Scenario: JSON output omits progress elements
|
|
Given an OutputSession with format "json" using JsonMaterializer
|
|
When I create a progress handle labelled "Building" with total 100
|
|
And I set progress to 50 of 100
|
|
And I close the progress handle
|
|
And I create a panel handle with title "Info"
|
|
And I set entry "Name" to "test"
|
|
And I close the panel handle
|
|
And the session is closed
|
|
Then the json output is valid JSON
|
|
And the json output does not contain element type "progress"
|
|
And the json output contains element type "panel"
|
|
|
|
# ================================================================
|
|
# MaterializationStrategy.bind() method
|
|
# ================================================================
|
|
|
|
Scenario: PlainMaterializer has bind method
|
|
Given a PlainMaterializer instance
|
|
When I call bind on the materializer
|
|
Then no error is raised
|
|
|
|
Scenario: JsonMaterializer has bind method
|
|
Given a JsonMaterializer instance
|
|
When I call bind on the json materializer
|
|
Then no error is raised
|
|
|
|
# ================================================================
|
|
# Render dispatch — concrete renderer methods coverage
|
|
# ================================================================
|
|
|
|
Scenario: PlainElementRenderer dispatches all element types via render_element
|
|
Given a PlainElementRenderer
|
|
When I call render_element with each element type
|
|
Then no render dispatch error occurred
|
|
|
|
Scenario: PlainElementRenderer serialize assembles rendered text
|
|
Given a PlainElementRenderer
|
|
When I call base serialize with a text element
|
|
Then the base serialized output is a string
|
|
|
|
Scenario: ColorElementRenderer dispatches all element types via render_element
|
|
Given a ColorElementRenderer
|
|
When I call render_element with each element type
|
|
Then no render dispatch error occurred
|
|
|
|
Scenario: ColorElementRenderer can_render returns True when ANSI is supported
|
|
Given a ColorElementRenderer
|
|
Then color renderer can_render is True with ANSI support
|
|
|
|
Scenario: TableElementRenderer can_render checks is_tty flag
|
|
Given a TableElementRenderer
|
|
Then table renderer can_render is True on a TTY terminal
|
|
And table renderer can_render is False on a non-TTY terminal
|
|
|
|
Scenario: TableElementRenderer dispatches all element types via render_element
|
|
Given a TableElementRenderer
|
|
When I call render_element with each element type
|
|
Then no render dispatch error occurred
|
|
|
|
Scenario: RichElementRenderer dispatches all element types via render_element
|
|
Given a RichElementRenderer
|
|
When I call render_element with each element type
|
|
Then no render dispatch error occurred
|
|
|
|
Scenario: RichElementRenderer can_render returns True with cursor movement
|
|
Given a RichElementRenderer
|
|
Then rich renderer can_render is True with cursor movement
|
|
|
|
Scenario: JsonElementRenderer dispatches all element types returning empty strings
|
|
Given a JsonElementRenderer
|
|
When I call render_element with each element type
|
|
Then no render dispatch error occurred
|
|
|
|
Scenario: YamlElementRenderer dispatches all element types returning empty strings
|
|
Given a YamlElementRenderer
|
|
When I call render_element with each element type
|
|
Then no render dispatch error occurred
|
|
|
|
# ================================================================
|
|
# RendererRegistry edge-case paths
|
|
# ================================================================
|
|
|
|
Scenario: RendererRegistry resolve unknown format falls back to plain
|
|
Given the default renderer registry
|
|
When I resolve format "unregistered_format" from the registry
|
|
Then the resolved renderer format name is "plain"
|
|
|
|
Scenario: RendererRegistry resolve raises ValueError when no plain fallback exists
|
|
Given a registry with no plain and a non-renderable format
|
|
When I try to resolve the non-renderable format
|
|
Then a ValueError is raised from resolve
|