@@ -34,6 +34,29 @@ def styles_of(frame: ToolbarFrame, row: int = 0) -> list[str]:
3434
3535
3636class TestShape :
37+ @pytest .mark .parametrize (
38+ ("content" , "width" , "height" , "expected" ),
39+ [
40+ ("\n STATUS" , 8 , 1 , [" …" ]),
41+ ("STATUS\n next" , 8 , 1 , ["STATUS …" ]),
42+ ("abcd" , 4 , 1 , ["abcd" ]),
43+ ("abcde" , 4 , 1 , ["abc…" ]),
44+ ("abcdef\n xy" , 4 , 2 , ["abc…" , "xy " ]),
45+ ("a\n b\n c\n d" , 4 , 3 , ["a " , "b " , "c …" ]),
46+ ("abc\n " , 4 , 1 , ["abc…" ]),
47+ ("广" , 1 , 1 , ["…" ]),
48+ ("a广x" , 3 , 1 , ["a …" ]),
49+ ("e\u0301 abc" , 3 , 1 , ["e\u0301 a…" ]),
50+ ("abx\u0301 " , 3 , 1 , ["abx\u0301 " ]),
51+ ("abcde\u0301 \n z" , 4 , 2 , ["abc…" , "z " ]),
52+ ("\t X\n y" , 4 , 2 , [" …" , "y " ]),
53+ ],
54+ )
55+ def test_truncation_is_visible_and_does_not_wrap (self , content , width , height , expected ) -> None :
56+ frame = ToolbarFrame .build (content , width = width , height = height )
57+ assert [text_of (frame , row ) for row in range (height )] == expected
58+ assert all (len (row ) == width for row in frame .rows )
59+
3760 def test_a_frame_is_always_exactly_its_declared_size (self ) -> None :
3861 frame = ToolbarFrame .build ("hi" , width = 10 , height = 2 )
3962 assert len (frame .rows ) == 2
@@ -45,16 +68,16 @@ def test_short_content_is_padded_with_default_style_spaces(self) -> None:
4568 assert text_of (frame ) == "hi "
4669 assert styles_of (frame ) == ["class:toolbar" ] * 5
4770
48- def test_content_wider_than_the_terminal_wraps (self ) -> None :
71+ def test_content_wider_than_the_terminal_is_clipped (self ) -> None :
4972 frame = ToolbarFrame .build ("abcdef" , width = 3 , height = 2 )
50- assert text_of (frame , 0 ) == "abc "
51- assert text_of (frame , 1 ) == "def "
73+ assert text_of (frame , 0 ) == "ab… "
74+ assert text_of (frame , 1 ) == " "
5275
5376 def test_content_taller_than_the_band_is_truncated (self ) -> None :
5477 """Growing past the band is a geometry transition, never a write outside it."""
5578 frame = ToolbarFrame .build ("one\n two\n three" , width = 10 , height = 2 )
5679 assert text_of (frame , 0 ) == "one "
57- assert text_of (frame , 1 ) == "two "
80+ assert text_of (frame , 1 ) == "two … "
5881
5982 def test_an_explicit_newline_starts_a_row (self ) -> None :
6083 frame = ToolbarFrame .build ("a\n b" , width = 3 , height = 2 )
@@ -105,10 +128,10 @@ def test_a_wide_character_occupies_two_cells(self) -> None:
105128 def test_a_wide_character_is_never_split_at_the_right_edge (self ) -> None :
106129 """Half a wide character at the edge is what wraps a row into the one below it."""
107130 frame = ToolbarFrame .build ("a广" , width = 2 , height = 2 )
108- assert text_of (frame , 0 ) == "a "
109- assert frame . rows [ 1 ][ 0 ]. char == "广 "
131+ assert text_of (frame , 0 ) == "a… "
132+ assert text_of ( frame , 1 ) == " "
110133
111- def test_the_pad_before_a_wrapped_wide_character_uses_the_default_style (self ) -> None :
134+ def test_the_truncation_indicator_uses_the_default_style (self ) -> None :
112135 frame = ToolbarFrame .build ([("bold" , "a广" )], width = 2 , height = 2 , default_style = "base" )
113136 assert styles_of (frame , 0 ) == ["bold" , "base" ]
114137
@@ -137,8 +160,8 @@ class TestMeasurement:
137160 def test_a_short_toolbar_is_one_row (self ) -> None :
138161 assert measure_toolbar_height ("hi" , width = 10 ) == 1
139162
140- def test_wrapping_is_counted (self ) -> None :
141- assert measure_toolbar_height ("abcdef" , width = 3 ) == 2
163+ def test_horizontal_overflow_does_not_add_rows (self ) -> None :
164+ assert measure_toolbar_height ("abcdef" , width = 3 ) == 1
142165
143166 def test_newlines_are_counted (self ) -> None :
144167 assert measure_toolbar_height ("a\n b\n c" , width = 10 ) == 3
@@ -148,10 +171,10 @@ def test_empty_content_still_measures_one_row(self) -> None:
148171 assert measure_toolbar_height ("" , width = 10 ) == 1
149172
150173 def test_measurement_matches_the_frame_it_would_build (self ) -> None :
151- content = [("bold" , "wide 广 content that wraps around " )]
174+ content = [("bold" , "wide 广 content that is clipped \n last row " )]
152175 height = measure_toolbar_height (content , width = 12 )
153176 frame = ToolbarFrame .build (content , width = 12 , height = height )
154- # Nothing was truncated: the last row is where the content ended .
177+ # Horizontal clipping does not move content onto the last logical line .
155178 assert measure_toolbar_height (content , width = 12 ) == len (frame .rows )
156179 assert text_of (frame , height - 1 ).strip () != ""
157180
@@ -181,12 +204,12 @@ def test_a_frame_reports_its_own_size(self) -> None:
181204 def test_an_empty_frame_reports_zero_width (self ) -> None :
182205 assert ToolbarFrame (rows = ()).width == 0
183206
184- def test_a_tab_wraps_when_it_reaches_the_edge (self ) -> None :
185- """The expansion is cells, so it wraps like any other run of them ."""
207+ def test_a_tab_is_clipped_when_it_reaches_the_edge (self ) -> None :
208+ """Tab expansion cannot spill into the next reserved row ."""
186209 frame = ToolbarFrame .build ("a\t b" , width = 4 , height = 3 )
187- assert text_of (frame , 0 ) == "a "
210+ assert text_of (frame , 0 ) == "a … "
188211 assert text_of (frame , 1 ) == " "
189- assert text_of (frame , 2 ) == "b "
212+ assert text_of (frame , 2 ) == " "
190213
191214 def test_a_combining_mark_after_a_wide_character_joins_that_character (self ) -> None :
192215 """Attaching it to the continuation cell instead shifts every later column."""
0 commit comments