mirror of
				https://github.com/Textualize/textual.git
				synced 2025-10-17 02:38:12 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			272 lines
		
	
	
		
			7.5 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			272 lines
		
	
	
		
			7.5 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| import pytest
 | |
| from rich.segment import Segment
 | |
| from rich.style import Style as RichStyle
 | |
| from rich.text import Text
 | |
| 
 | |
| from textual._border import render_border_label, render_row
 | |
| from textual.content import Content
 | |
| from textual.style import Style
 | |
| from textual.widget import Widget
 | |
| 
 | |
| 
 | |
| def test_border_render_row():
 | |
|     style = RichStyle.parse("red")
 | |
|     row = (Segment("┏", style), Segment("━", style), Segment("┓", style))
 | |
| 
 | |
|     assert list(render_row(row, 5, False, False, ())) == [
 | |
|         Segment(row[1].text * 5, row[1].style)
 | |
|     ]
 | |
|     assert list(render_row(row, 5, True, False, ())) == [
 | |
|         row[0],
 | |
|         Segment(row[1].text * 4, row[1].style),
 | |
|     ]
 | |
|     assert list(render_row(row, 5, False, True, ())) == [
 | |
|         Segment(row[1].text * 4, row[1].style),
 | |
|         row[2],
 | |
|     ]
 | |
|     assert list(render_row(row, 5, True, True, ())) == [
 | |
|         row[0],
 | |
|         Segment(row[1].text * 3, row[1].style),
 | |
|         row[2],
 | |
|     ]
 | |
| 
 | |
| 
 | |
| def test_border_title_single_line():
 | |
|     """The border_title gets set to a single line even when multiple lines are provided."""
 | |
|     widget = Widget()
 | |
| 
 | |
|     assert widget.border_title is None
 | |
| 
 | |
|     widget.border_title = None
 | |
|     assert widget.border_title is None
 | |
| 
 | |
|     widget.border_title = ""
 | |
|     assert widget.border_title == ""
 | |
| 
 | |
|     widget.border_title = "How is life\ngoing for you?"
 | |
|     assert widget.border_title == "How is life"
 | |
| 
 | |
|     widget.border_title = "How is life\n\rgoing for you?"
 | |
|     assert widget.border_title == "How is life"
 | |
| 
 | |
|     widget.border_title = "Sorry you \r\n have to \n read this."
 | |
|     assert widget.border_title == "Sorry you "
 | |
| 
 | |
|     widget.border_title = "[red]This also \n works with markup \n involved.[/]"
 | |
|     assert widget.border_title == "[red]This also [/red]"
 | |
| 
 | |
|     widget.border_title = Text.from_markup("[bold]Hello World")
 | |
|     assert widget.border_title == "[bold]Hello World[/bold]"
 | |
| 
 | |
| 
 | |
| def test_border_subtitle_single_line():
 | |
|     """The border_subtitle gets set to a single line even when multiple lines are provided."""
 | |
|     widget = Widget()
 | |
| 
 | |
|     widget.border_subtitle = ""
 | |
|     assert widget.border_subtitle == ""
 | |
| 
 | |
|     widget.border_subtitle = "How is life\ngoing for you?"
 | |
|     assert widget.border_subtitle == "How is life"
 | |
| 
 | |
|     widget.border_subtitle = "How is life\n\rgoing for you?"
 | |
|     assert widget.border_subtitle == "How is life"
 | |
| 
 | |
|     widget.border_subtitle = "Sorry you \r\n have to \n read this."
 | |
|     assert widget.border_subtitle == "Sorry you "
 | |
| 
 | |
|     widget.border_subtitle = "[red]This also \n works with markup \n involved.[/]"
 | |
|     assert widget.border_subtitle == "[red]This also [/red]"
 | |
| 
 | |
|     widget.border_subtitle = Text.from_markup("[bold]Hello World")
 | |
|     assert widget.border_subtitle == "[bold]Hello World[/bold]"
 | |
| 
 | |
| 
 | |
| @pytest.mark.parametrize(
 | |
|     ["width", "has_left_corner", "has_right_corner"],
 | |
|     [
 | |
|         (10, True, True),
 | |
|         (10, True, False),
 | |
|         (10, False, False),
 | |
|         (10, False, True),
 | |
|         (1, True, True),
 | |
|         (1, True, False),
 | |
|         (1, False, False),
 | |
|         (1, False, True),
 | |
|     ],
 | |
| )
 | |
| def test_render_border_label_empty_label_skipped(
 | |
|     width: int, has_left_corner: bool, has_right_corner: bool
 | |
| ):
 | |
|     """Test that we get an empty list of segments if there is no label to display."""
 | |
| 
 | |
|     assert [] == list(
 | |
|         render_border_label(
 | |
|             (Content(""), Style()),
 | |
|             True,
 | |
|             "round",
 | |
|             width,
 | |
|             Style(),
 | |
|             Style(),
 | |
|             Style(),
 | |
|             has_left_corner,
 | |
|             has_right_corner,
 | |
|         )
 | |
|     )
 | |
| 
 | |
| 
 | |
| @pytest.mark.parametrize(
 | |
|     ["label", "width", "has_left_corner", "has_right_corner"],
 | |
|     [
 | |
|         ("hey", 2, True, True),
 | |
|         ("hey", 2, True, False),
 | |
|         ("hey", 2, False, True),
 | |
|         ("hey", 3, True, True),
 | |
|         ("hey", 4, True, True),
 | |
|     ],
 | |
| )
 | |
| def test_render_border_label_skipped_if_narrow(
 | |
|     label: str, width: int, has_left_corner: bool, has_right_corner: bool
 | |
| ):
 | |
|     """Test that we skip rendering a label when we do not have space for it.
 | |
| 
 | |
|     In order for us to have enough space for the label, we need to have space for the
 | |
|     corners that we need (none, just one, or both) and we need to be able to have two
 | |
|     blank spaces around the label (one on each side).
 | |
|     If we don't have space for all of these, we skip the label altogether.
 | |
|     """
 | |
| 
 | |
|     assert [] == list(
 | |
|         render_border_label(
 | |
|             (Content.from_markup(label), Style()),
 | |
|             True,
 | |
|             "round",
 | |
|             width,
 | |
|             Style(),
 | |
|             Style(),
 | |
|             Style(),
 | |
|             has_left_corner,
 | |
|             has_right_corner,
 | |
|         )
 | |
|     )
 | |
| 
 | |
| 
 | |
| @pytest.mark.parametrize(
 | |
|     "label",
 | |
|     [
 | |
|         "Why did the scarecrow",
 | |
|         "win a Nobel prize?",
 | |
|         "because it was outstanding",
 | |
|         "in its field.",
 | |
|     ],
 | |
| )
 | |
| def test_render_border_label_wide_plain(label: str):
 | |
|     """Test label rendering in a wide area with no styling."""
 | |
| 
 | |
|     BIG_NUM = 9999
 | |
|     args = (
 | |
|         True,
 | |
|         "round",
 | |
|         BIG_NUM,
 | |
|         Style(),
 | |
|         Style(),
 | |
|         Style(),
 | |
|         True,
 | |
|         True,
 | |
|     )
 | |
|     segments = render_border_label((Content.from_markup(label), Style()), *args)
 | |
|     (segment,) = segments
 | |
| 
 | |
|     assert segment == Segment(f" {label} ", None)
 | |
| 
 | |
| 
 | |
| @pytest.mark.parametrize(
 | |
|     "label",
 | |
|     [
 | |
|         "[b][/]",
 | |
|         "[i b][/]",
 | |
|         "[white on red][/]",
 | |
|         "[blue]",
 | |
|     ],
 | |
| )
 | |
| def test_render_border_empty_text_with_markup(label: str):
 | |
|     """Test label rendering if there is no text but some markup."""
 | |
|     assert [] == list(
 | |
|         render_border_label(
 | |
|             (Content.from_markup(label), Style()),
 | |
|             True,
 | |
|             "round",
 | |
|             999,
 | |
|             Style(),
 | |
|             Style(),
 | |
|             Style(),
 | |
|             True,
 | |
|             True,
 | |
|         )
 | |
|     )
 | |
| 
 | |
| 
 | |
| def test_render_border_label():
 | |
|     """Test label rendering with styling, with and without overflow."""
 | |
| 
 | |
|     label = "[b][on red]What [i]is up[/on red] with you?[/]"
 | |
|     border_style = Style.parse("green on blue")
 | |
| 
 | |
|     # Implicit test on the number of segments returned:
 | |
|     segments = list(
 | |
|         render_border_label(
 | |
|             (Content.from_markup(label), Style.null()),
 | |
|             True,
 | |
|             "round",
 | |
|             9999,
 | |
|             Style(),
 | |
|             Style(),
 | |
|             border_style,
 | |
|             True,
 | |
|             True,
 | |
|         )
 | |
|     )
 | |
| 
 | |
|     for segment in segments:
 | |
|         print("!!", segment)
 | |
| 
 | |
|     blank1, what, is_up, with_you, blank2 = segments
 | |
| 
 | |
|     expected_blank = Segment(" ", border_style.rich_style)
 | |
|     assert blank1 == expected_blank
 | |
|     assert blank2 == expected_blank
 | |
| 
 | |
|     what_style = Style.parse("b on red")
 | |
|     expected_what = Segment("What ", (border_style + what_style).rich_style)
 | |
|     print(what)
 | |
|     print(expected_what)
 | |
|     assert what == expected_what
 | |
| 
 | |
|     is_up_style = Style.parse("b on red i")
 | |
|     expected_is_up = Segment("is up", (border_style + is_up_style).rich_style)
 | |
|     assert is_up == expected_is_up
 | |
| 
 | |
|     with_you_style = Style.parse("b i")
 | |
|     expected_with_you = Segment(
 | |
|         " with you?", (border_style + with_you_style).rich_style
 | |
|     )
 | |
|     assert with_you == expected_with_you
 | |
| 
 | |
|     blank1, what, blank2 = render_border_label(
 | |
|         (Content.from_markup(label), Style()),
 | |
|         True,
 | |
|         "round",
 | |
|         5 + 4,  # 5 where "What…" fits + 2 for the blank spaces + 2 for the corners.
 | |
|         Style(),
 | |
|         Style(),
 | |
|         border_style,
 | |
|         True,  # This corner costs 2 cells.
 | |
|         True,  # This corner costs 2 cells.
 | |
|     )
 | |
| 
 | |
|     assert blank1 == expected_blank
 | |
|     assert blank2 == expected_blank
 | |
| 
 | |
|     expected_what = Segment("What…", (border_style + what_style).rich_style)
 | |
|     assert what == expected_what
 | 
