Back to Repositories

Testing Rich Console Rule Component Implementation in Textualize/rich

A comprehensive test suite for Rich’s Rule component that validates horizontal line rendering with various configurations and text alignments in terminal output. The tests ensure proper handling of different character sets, text styles, and edge cases.

Test Coverage Overview

The test suite provides extensive coverage of Rule component functionality:
  • Basic rule rendering with and without text
  • Text alignment options (left, center, right)
  • Custom character sets for rule lines
  • CJK character support
  • Edge cases with limited width and long text
  • Error handling for invalid configurations

Implementation Analysis

The testing approach uses pytest’s parametrize feature for systematic validation of different scenarios. Tests verify console output against expected string patterns, including ANSI escape sequences for styling. Mock Console objects with StringIO capture actual output for comparison.

Implementation includes both positive test cases for expected behavior and negative test cases for error conditions.

Technical Details

  • Testing Framework: pytest
  • Key Dependencies: io.StringIO for output capture
  • Mock Objects: Console with controlled width and environment
  • Test Utilities: pytest.raises for exception testing
  • Configuration: Various console widths and display settings

Best Practices Demonstrated

The test suite exemplifies several testing best practices:
  • Isolated test cases with clear assertions
  • Parametrized tests for multiple scenarios
  • Comprehensive edge case coverage
  • Consistent error validation
  • Mock objects for controlled testing environment
  • Clear test naming conventions

textualize/rich

tests/test_rule.py

            
import io

import pytest

from rich.console import Console
from rich.rule import Rule
from rich.text import Text


def test_rule():
    console = Console(
        width=16,
        file=io.StringIO(),
        force_terminal=True,
        legacy_windows=False,
        _environ={},
    )
    console.print(Rule())
    console.print(Rule("foo"))
    console.rule(Text("foo", style="bold"))
    console.rule("foobarbazeggfoobarbazegg")
    expected = "\x1b[92m────────────────\x1b[0m
"
    expected += "\x1b[92m───── \x1b[0mfoo\x1b[92m ──────\x1b[0m
"
    expected += "\x1b[92m───── \x1b[0m\x1b[1mfoo\x1b[0m\x1b[92m ──────\x1b[0m
"
    expected += "\x1b[92m─ \x1b[0mfoobarbazeg…\x1b[92m ─\x1b[0m
"

    result = console.file.getvalue()
    assert result == expected


def test_rule_error():
    console = Console(width=16, file=io.StringIO(), legacy_windows=False, _environ={})
    with pytest.raises(ValueError):
        console.rule("foo", align="foo")


def test_rule_align():
    console = Console(width=16, file=io.StringIO(), legacy_windows=False, _environ={})
    console.rule("foo")
    console.rule("foo", align="left")
    console.rule("foo", align="center")
    console.rule("foo", align="right")
    console.rule()
    result = console.file.getvalue()
    print(repr(result))
    expected = "───── foo ──────
foo ────────────
───── foo ──────
──────────── foo
────────────────
"
    assert result == expected


def test_rule_cjk():
    console = Console(
        width=16,
        file=io.StringIO(),
        force_terminal=True,
        color_system=None,
        legacy_windows=False,
        _environ={},
    )
    console.rule("欢迎!")
    expected = "──── 欢迎! ────
"
    assert console.file.getvalue() == expected


@pytest.mark.parametrize(
    "align,outcome",
    [
        ("center", "───
"),
        ("left", "… ─
"),
        ("right", "─ …
"),
    ],
)
def test_rule_not_enough_space_for_title_text(align, outcome):
    console = Console(width=3, file=io.StringIO(), record=True)
    console.rule("Hello!", align=align)
    assert console.file.getvalue() == outcome


def test_rule_center_aligned_title_not_enough_space_for_rule():
    console = Console(width=4, file=io.StringIO(), record=True)
    console.rule("ABCD")
    assert console.file.getvalue() == "────
"


@pytest.mark.parametrize("align", ["left", "right"])
def test_rule_side_aligned_not_enough_space_for_rule(align):
    console = Console(width=2, file=io.StringIO(), record=True)
    console.rule("ABCD", align=align)
    assert console.file.getvalue() == "──
"


@pytest.mark.parametrize(
    "align,outcome",
    [
        ("center", "─ … ─
"),
        ("left", "AB… ─
"),
        ("right", "─ AB…
"),
    ],
)
def test_rule_just_enough_width_available_for_title(align, outcome):
    console = Console(width=5, file=io.StringIO(), record=True)
    console.rule("ABCD", align=align)
    assert console.file.getvalue() == outcome


def test_characters():
    console = Console(
        width=16,
        file=io.StringIO(),
        force_terminal=True,
        color_system=None,
        legacy_windows=False,
        _environ={},
    )
    console.rule(characters="+*")
    console.rule("foo", characters="+*")
    console.print(Rule(characters=".,"))
    expected = "+*+*+*+*+*+*+*+*
"
    expected += "+*+*+ foo +*+*+*
"
    expected += ".,.,.,.,.,.,.,.,
"
    assert console.file.getvalue() == expected


def test_repr():
    rule = Rule("foo")
    assert isinstance(repr(rule), str)


def test_error():
    with pytest.raises(ValueError):
        Rule(characters="")