@@ -1,717 +1,717 @@
1−use helix_tui::{
2− backend::TestBackend,
3− buffer::Buffer,
4− layout::Constraint,
5− style::{Color, Modifier, Style},
6− text::{Span, Spans},
7− widgets::{Block, Borders, Cell, Row, Table, TableState},
8− Terminal,
9−};
10−
11−#[test]
12−fn widgets_table_column_spacing_can_be_changed() {
13− let test_case = |column_spacing, expected| {
14− let backend = TestBackend::new(30, 10);
15− let mut terminal = Terminal::new(backend).unwrap();
16−
17− terminal
18− .draw(|f| {
19− let size = f.size();
20− let table = Table::new(vec![
21− Row::new(vec!["Row11", "Row12", "Row13"]),
22− Row::new(vec!["Row21", "Row22", "Row23"]),
23− Row::new(vec!["Row31", "Row32", "Row33"]),
24− Row::new(vec!["Row41", "Row42", "Row43"]),
25− ])
26− .header(Row::new(vec!["Head1", "Head2", "Head3"]).bottom_margin(1))
27− .block(Block::default().borders(Borders::ALL))
28− .widths(&[
29− Constraint::Length(5),
30− Constraint::Length(5),
31− Constraint::Length(5),
32− ])
33− .column_spacing(column_spacing);
34− f.render_widget(table, size);
35− })
36− .unwrap();
37− terminal.backend().assert_buffer(&expected);
38− };
39−
40− // no space between columns
41− test_case(
42− 0,
43− Buffer::with_lines(vec![
44− "┌────────────────────────────┐",
45− "│Head1Head2Head3 │",
46− "│ │",
47− "│Row11Row12Row13 │",
48− "│Row21Row22Row23 │",
49− "│Row31Row32Row33 │",
50− "│Row41Row42Row43 │",
51− "│ │",
52− "│ │",
53− "└────────────────────────────┘",
54− ]),
55− );
56−
57− // one space between columns
58− test_case(
59− 1,
60− Buffer::with_lines(vec![
61− "┌────────────────────────────┐",
62− "│Head1 Head2 Head3 │",
63− "│ │",
64− "│Row11 Row12 Row13 │",
65− "│Row21 Row22 Row23 │",
66− "│Row31 Row32 Row33 │",
67− "│Row41 Row42 Row43 │",
68− "│ │",
69− "│ │",
70− "└────────────────────────────┘",
71− ]),
72− );
73−
74− // enough space to just not hide the third column
75− test_case(
76− 6,
77− Buffer::with_lines(vec![
78− "┌────────────────────────────┐",
79− "│Head1 Head2 Head3 │",
80− "│ │",
81− "│Row11 Row12 Row13 │",
82− "│Row21 Row22 Row23 │",
83− "│Row31 Row32 Row33 │",
84− "│Row41 Row42 Row43 │",
85− "│ │",
86− "│ │",
87− "└────────────────────────────┘",
88− ]),
89− );
90−
91− // enough space to hide part of the third column
92− test_case(
93− 7,
94− Buffer::with_lines(vec![
95− "┌────────────────────────────┐",
96− "│Head1 Head2 Head│",
97− "│ │",
98− "│Row11 Row12 Row1│",
99− "│Row21 Row22 Row2│",
100− "│Row31 Row32 Row3│",
101− "│Row41 Row42 Row4│",
102− "│ │",
103− "│ │",
104− "└────────────────────────────┘",
105− ]),
106− );
107−}
108−
109−#[test]
110−fn widgets_table_columns_widths_can_use_fixed_length_constraints() {
111− let test_case = |widths, expected| {
112− let backend = TestBackend::new(30, 10);
113− let mut terminal = Terminal::new(backend).unwrap();
114−
115− terminal
116− .draw(|f| {
117− let size = f.size();
118− let table = Table::new(vec![
119− Row::new(vec!["Row11", "Row12", "Row13"]),
120− Row::new(vec!["Row21", "Row22", "Row23"]),
121− Row::new(vec!["Row31", "Row32", "Row33"]),
122− Row::new(vec!["Row41", "Row42", "Row43"]),
123− ])
124− .header(Row::new(vec!["Head1", "Head2", "Head3"]).bottom_margin(1))
125− .block(Block::default().borders(Borders::ALL))
126− .widths(widths);
127− f.render_widget(table, size);
128− })
129− .unwrap();
130− terminal.backend().assert_buffer(&expected);
131− };
132−
133− // columns of zero width show nothing
134− test_case(
135− &[
136− Constraint::Length(0),
137− Constraint::Length(0),
138− Constraint::Length(0),
139− ],
140− Buffer::with_lines(vec![
141− "┌────────────────────────────┐",
142− "│ │",
143− "│ │",
144− "│ │",
145− "│ │",
146− "│ │",
147− "│ │",
148− "│ │",
149− "│ │",
150− "└────────────────────────────┘",
151− ]),
152− );
153−
154− // columns of 1 width trim
155− test_case(
156− &[
157− Constraint::Length(1),
158− Constraint::Length(1),
159− Constraint::Length(1),
160− ],
161− Buffer::with_lines(vec![
162− "┌────────────────────────────┐",
163− "│H H H │",
164− "│ │",
165− "│R R R │",
166− "│R R R │",
167− "│R R R │",
168− "│R R R │",
169− "│ │",
170− "│ │",
171− "└────────────────────────────┘",
172− ]),
173− );
174−
175− // columns of large width just before pushing a column off
176− test_case(
177− &[
178− Constraint::Length(8),
179− Constraint::Length(8),
180− Constraint::Length(8),
181− ],
182− Buffer::with_lines(vec![
183− "┌────────────────────────────┐",
184− "│Head1 Head2 Head3 │",
185− "│ │",
186− "│Row11 Row12 Row13 │",
187− "│Row21 Row22 Row23 │",
188− "│Row31 Row32 Row33 │",
189− "│Row41 Row42 Row43 │",
190− "│ │",
191− "│ │",
192− "└────────────────────────────┘",
193− ]),
194− );
195−}
196−
197−#[test]
198−fn widgets_table_columns_widths_can_use_percentage_constraints() {
199− let test_case = |widths, expected| {
200− let backend = TestBackend::new(30, 10);
201− let mut terminal = Terminal::new(backend).unwrap();
202−
203− terminal
204− .draw(|f| {
205− let size = f.size();
206− let table = Table::new(vec![
207− Row::new(vec!["Row11", "Row12", "Row13"]),
208− Row::new(vec!["Row21", "Row22", "Row23"]),
209− Row::new(vec!["Row31", "Row32", "Row33"]),
210− Row::new(vec!["Row41", "Row42", "Row43"]),
211− ])
212− .header(Row::new(vec!["Head1", "Head2", "Head3"]).bottom_margin(1))
213− .block(Block::default().borders(Borders::ALL))
214− .widths(widths)
215− .column_spacing(0);
216− f.render_widget(table, size);
217− })
218− .unwrap();
219− terminal.backend().assert_buffer(&expected);
220− };
221−
222− // columns of zero width show nothing
223− test_case(
224− &[
225− Constraint::Percentage(0),
226− Constraint::Percentage(0),
227− Constraint::Percentage(0),
228− ],
229− Buffer::with_lines(vec![
230− "┌────────────────────────────┐",
231− "│ │",
232− "│ │",
233− "│ │",
234− "│ │",
235− "│ │",
236− "│ │",
237− "│ │",
238− "│ │",
239− "└────────────────────────────┘",
240− ]),
241− );
242−
243− // columns of not enough width trims the data
244− test_case(
245− &[
246− Constraint::Percentage(11),
247− Constraint::Percentage(11),
248− Constraint::Percentage(11),
249− ],
250− Buffer::with_lines(vec![
251− "┌────────────────────────────┐",
252− "│HeaHeaHea │",
253− "│ │",
254− "│RowRowRow │",
255− "│RowRowRow │",
256− "│RowRowRow │",
257− "│RowRowRow │",
258− "│ │",
259− "│ │",
260− "└────────────────────────────┘",
261− ]),
262− );
263−
264− // columns of large width just before pushing a column off
265− test_case(
266− &[
267− Constraint::Percentage(33),
268− Constraint::Percentage(33),
269− Constraint::Percentage(33),
270− ],
271− Buffer::with_lines(vec![
272− "┌────────────────────────────┐",
273− "│Head1 Head2 Head3 │",
274− "│ │",
275− "│Row11 Row12 Row13 │",
276− "│Row21 Row22 Row23 │",
277− "│Row31 Row32 Row33 │",
278− "│Row41 Row42 Row43 │",
279− "│ │",
280− "│ │",
281− "└────────────────────────────┘",
282− ]),
283− );
284−
285− // percentages summing to 100 should give equal widths
286− test_case(
287− &[Constraint::Percentage(50), Constraint::Percentage(50)],
288− Buffer::with_lines(vec![
289− "┌────────────────────────────┐",
290− "│Head1 Head2 │",
291− "│ │",
292− "│Row11 Row12 │",
293− "│Row21 Row22 │",
294− "│Row31 Row32 │",
295− "│Row41 Row42 │",
296− "│ │",
297− "│ │",
298− "└────────────────────────────┘",
299− ]),
300− );
301−}
302−
303−#[test]
304−fn widgets_table_columns_widths_can_use_mixed_constraints() {
305− let test_case = |widths, expected| {
306− let backend = TestBackend::new(30, 10);
307− let mut terminal = Terminal::new(backend).unwrap();
308−
309− terminal
310− .draw(|f| {
311− let size = f.size();
312− let table = Table::new(vec![
313− Row::new(vec!["Row11", "Row12", "Row13"]),
314− Row::new(vec!["Row21", "Row22", "Row23"]),
315− Row::new(vec!["Row31", "Row32", "Row33"]),
316− Row::new(vec!["Row41", "Row42", "Row43"]),
317− ])
318− .header(Row::new(vec!["Head1", "Head2", "Head3"]).bottom_margin(1))
319− .block(Block::default().borders(Borders::ALL))
320− .widths(widths);
321− f.render_widget(table, size);
322− })
323− .unwrap();
324− terminal.backend().assert_buffer(&expected);
325− };
326−
327− // columns of zero width show nothing
328− test_case(
329− &[
330− Constraint::Percentage(0),
331− Constraint::Length(0),
332− Constraint::Percentage(0),
333− ],
334− Buffer::with_lines(vec![
335− "┌────────────────────────────┐",
336− "│ │",
337− "│ │",
338− "│ │",
339− "│ │",
340− "│ │",
341− "│ │",
342− "│ │",
343− "│ │",
344− "└────────────────────────────┘",
345− ]),
346− );
347−
348− // columns of not enough width trims the data
349− test_case(
350− &[
351− Constraint::Percentage(11),
352− Constraint::Length(20),
353− Constraint::Percentage(11),
354− ],
355− Buffer::with_lines(vec![
356− "┌────────────────────────────┐",
357− "│Hea Head2 Hea│",
358− "│ │",
359− "│Row Row12 Row│",
360− "│Row Row22 Row│",
361− "│Row Row32 Row│",
362− "│Row Row42 Row│",
363− "│ │",
364− "│ │",
365− "└────────────────────────────┘",
366− ]),
367− );
368−
369− // columns of large width just before pushing a column off
370− test_case(
371− &[
372− Constraint::Percentage(33),
373− Constraint::Length(10),
374− Constraint::Percentage(33),
375− ],
376− Buffer::with_lines(vec![
377− "┌────────────────────────────┐",
378− "│Head1 Head2 Head3 │",
379− "│ │",
380− "│Row11 Row12 Row13 │",
381− "│Row21 Row22 Row23 │",
382− "│Row31 Row32 Row33 │",
383− "│Row41 Row42 Row43 │",
384− "│ │",
385− "│ │",
386− "└────────────────────────────┘",
387− ]),
388− );
389−
390− // columns of large size (>100% total) hide the last column
391− test_case(
392− &[
393− Constraint::Percentage(60),
394− Constraint::Length(10),
395− Constraint::Percentage(60),
396− ],
397− Buffer::with_lines(vec![
398− "┌────────────────────────────┐",
399− "│Head1 Head2 │",
400− "│ │",
401− "│Row11 Row12 │",
402− "│Row21 Row22 │",
403− "│Row31 Row32 │",
404− "│Row41 Row42 │",
405− "│ │",
406− "│ │",
407− "└────────────────────────────┘",
408− ]),
409− );
410−}
411−
412−#[test]
413−fn widgets_table_columns_widths_can_use_ratio_constraints() {
414− let test_case = |widths, expected| {
415− let backend = TestBackend::new(30, 10);
416− let mut terminal = Terminal::new(backend).unwrap();
417−
418− terminal
419− .draw(|f| {
420− let size = f.size();
421− let table = Table::new(vec![
422− Row::new(vec!["Row11", "Row12", "Row13"]),
423− Row::new(vec!["Row21", "Row22", "Row23"]),
424− Row::new(vec!["Row31", "Row32", "Row33"]),
425− Row::new(vec!["Row41", "Row42", "Row43"]),
426− ])
427− .header(Row::new(vec!["Head1", "Head2", "Head3"]).bottom_margin(1))
428− .block(Block::default().borders(Borders::ALL))
429− .widths(widths)
430− .column_spacing(0);
431− f.render_widget(table, size);
432− })
433− .unwrap();
434− terminal.backend().assert_buffer(&expected);
435− };
436−
437− // columns of zero width show nothing
438− test_case(
439− &[
440− Constraint::Ratio(0, 1),
441− Constraint::Ratio(0, 1),
442− Constraint::Ratio(0, 1),
443− ],
444− Buffer::with_lines(vec![
445− "┌────────────────────────────┐",
446− "│ │",
447− "│ │",
448− "│ │",
449− "│ │",
450− "│ │",
451− "│ │",
452− "│ │",
453− "│ │",
454− "└────────────────────────────┘",
455− ]),
456− );
457−
458− // columns of not enough width trims the data
459− test_case(
460− &[
461− Constraint::Ratio(1, 9),
462− Constraint::Ratio(1, 9),
463− Constraint::Ratio(1, 9),
464− ],
465− Buffer::with_lines(vec![
466− "┌────────────────────────────┐",
467− "│HeaHeaHea │",
468− "│ │",
469− "│RowRowRow │",
470− "│RowRowRow │",
471− "│RowRowRow │",
472− "│RowRowRow │",
473− "│ │",
474− "│ │",
475− "└────────────────────────────┘",
476− ]),
477− );
478−
479− // columns of large width just before pushing a column off
480− test_case(
481− &[
482− Constraint::Ratio(1, 3),
483− Constraint::Ratio(1, 3),
484− Constraint::Ratio(1, 3),
485− ],
486− Buffer::with_lines(vec![
487− "┌────────────────────────────┐",
488− "│Head1 Head2 Head3 │",
489− "│ │",
490− "│Row11 Row12 Row13 │",
491− "│Row21 Row22 Row23 │",
492− "│Row31 Row32 Row33 │",
493− "│Row41 Row42 Row43 │",
494− "│ │",
495− "│ │",
496− "└────────────────────────────┘",
497− ]),
498− );
499−
500− // percentages summing to 100 should give equal widths
501− test_case(
502− &[Constraint::Ratio(1, 2), Constraint::Ratio(1, 2)],
503− Buffer::with_lines(vec![
504− "┌────────────────────────────┐",
505− "│Head1 Head2 │",
506− "│ │",
507− "│Row11 Row12 │",
508− "│Row21 Row22 │",
509− "│Row31 Row32 │",
510− "│Row41 Row42 │",
511− "│ │",
512− "│ │",
513− "└────────────────────────────┘",
514− ]),
515− );
516−}
517−
518−#[test]
519−fn widgets_table_can_have_rows_with_multi_lines() {
520− let test_case = |state: &mut TableState, expected: Buffer| {
521− let backend = TestBackend::new(30, 8);
522− let mut terminal = Terminal::new(backend).unwrap();
523− terminal
524− .draw(|f| {
525− let size = f.size();
526− let table = Table::new(vec![
527− Row::new(vec!["Row11", "Row12", "Row13"]),
528− Row::new(vec!["Row21", "Row22", "Row23"]).height(2),
529− Row::new(vec!["Row31", "Row32", "Row33"]),
530− Row::new(vec!["Row41", "Row42", "Row43"]).height(2),
531− ])
532− .header(Row::new(vec!["Head1", "Head2", "Head3"]).bottom_margin(1))
533− .block(Block::default().borders(Borders::ALL))
534− .highlight_symbol(">> ")
535− .widths(&[
536− Constraint::Length(5),
537− Constraint::Length(5),
538− Constraint::Length(5),
539− ])
540− .column_spacing(1);
541− f.render_stateful_widget(table, size, state);
542− })
543− .unwrap();
544− terminal.backend().assert_buffer(&expected);
545− };
546−
547− let mut state = TableState::default();
548− // no selection
549− test_case(
550− &mut state,
551− Buffer::with_lines(vec![
552− "┌────────────────────────────┐",
553− "│Head1 Head2 Head3 │",
554− "│ │",
555− "│Row11 Row12 Row13 │",
556− "│Row21 Row22 Row23 │",
557− "│ │",
558− "│Row31 Row32 Row33 │",
559− "└────────────────────────────┘",
560− ]),
561− );
562−
563− // select first
564− state.select(Some(0));
565− test_case(
566− &mut state,
567− Buffer::with_lines(vec![
568− "┌────────────────────────────┐",
569− "│ Head1 Head2 Head3 │",
570− "│ │",
571− "│>> Row11 Row12 Row13 │",
572− "│ Row21 Row22 Row23 │",
573− "│ │",
574− "│ Row31 Row32 Row33 │",
575− "└────────────────────────────┘",
576− ]),
577− );
578−
579− // select second (we don't show partially the 4th row)
580− state.select(Some(1));
581− test_case(
582− &mut state,
583− Buffer::with_lines(vec![
584− "┌────────────────────────────┐",
585− "│ Head1 Head2 Head3 │",
586− "│ │",
587− "│ Row11 Row12 Row13 │",
588− "│>> Row21 Row22 Row23 │",
589− "│ │",
590− "│ Row31 Row32 Row33 │",
591− "└────────────────────────────┘",
592− ]),
593− );
594−
595− // select 4th (we don't show partially the 1st row)
596− state.select(Some(3));
597− test_case(
598− &mut state,
599− Buffer::with_lines(vec![
600− "┌────────────────────────────┐",
601− "│ Head1 Head2 Head3 │",
602− "│ │",
603− "│ Row31 Row32 Row33 │",
604− "│>> Row41 Row42 Row43 │",
605− "│ │",
606− "│ │",
607− "└────────────────────────────┘",
608− ]),
609− );
610−}
611−
612−#[test]
613−fn widgets_table_can_have_elements_styled_individually() {
614− let backend = TestBackend::new(30, 4);
615− let mut terminal = Terminal::new(backend).unwrap();
616− let mut state = TableState::default();
617− state.select(Some(0));
618− terminal
619− .draw(|f| {
620− let size = f.size();
621− let table = Table::new(vec![
622− Row::new(vec!["Row11", "Row12", "Row13"]).style(Style::default().fg(Color::Green)),
623− Row::new(vec![
624− Cell::from("Row21"),
625− Cell::from("Row22").style(Style::default().fg(Color::Yellow)),
626− Cell::from(Spans::from(vec![
627− Span::raw("Row"),
628− Span::styled("23", Style::default().fg(Color::Blue)),
629− ]))
630− .style(Style::default().fg(Color::Red)),
631− ])
632− .style(Style::default().fg(Color::LightGreen)),
633− ])
634− .header(Row::new(vec!["Head1", "Head2", "Head3"]).bottom_margin(1))
635− .block(Block::default().borders(Borders::LEFT | Borders::RIGHT))
636− .highlight_symbol(">> ")
637− .highlight_style(Style::default().add_modifier(Modifier::BOLD))
638− .widths(&[
639− Constraint::Length(6),
640− Constraint::Length(6),
641− Constraint::Length(6),
642− ])
643− .column_spacing(1);
644− f.render_stateful_widget(table, size, &mut state);
645− })
646− .unwrap();
647−
648− let mut expected = Buffer::with_lines(vec![
649− "│ Head1 Head2 Head3 │",
650− "│ │",
651− "│>> Row11 Row12 Row13 │",
652− "│ Row21 Row22 Row23 │",
653− ]);
654− // First row = row color + highlight style
655− for col in 1..=28 {
656− expected.get_mut(col, 2).set_style(
657− Style::default()
658− .fg(Color::Green)
659− .add_modifier(Modifier::BOLD),
660− );
661− }
662− // Second row:
663− // 1. row color
664− for col in 1..=28 {
665− expected
666− .get_mut(col, 3)
667− .set_style(Style::default().fg(Color::LightGreen));
668− }
669− // 2. cell color
670− for col in 11..=16 {
671− expected
672− .get_mut(col, 3)
673− .set_style(Style::default().fg(Color::Yellow));
674− }
675− for col in 18..=23 {
676− expected
677− .get_mut(col, 3)
678− .set_style(Style::default().fg(Color::Red));
679− }
680− // 3. text color
681− for col in 21..=22 {
682− expected
683− .get_mut(col, 3)
684− .set_style(Style::default().fg(Color::Blue));
685− }
686− terminal.backend().assert_buffer(&expected);
687−}
688−
689−#[test]
690−fn widgets_table_should_render_even_if_empty() {
691− let backend = TestBackend::new(30, 4);
692− let mut terminal = Terminal::new(backend).unwrap();
693− terminal
694− .draw(|f| {
695− let size = f.size();
696− let table = Table::new(vec![])
697− .header(Row::new(vec!["Head1", "Head2", "Head3"]))
698− .block(Block::default().borders(Borders::LEFT | Borders::RIGHT))
699− .widths(&[
700− Constraint::Length(6),
701− Constraint::Length(6),
702− Constraint::Length(6),
703− ])
704− .column_spacing(1);
705− f.render_widget(table, size);
706− })
707− .unwrap();
708−
709− let expected = Buffer::with_lines(vec![
710− "│Head1 Head2 Head3 │",
711− "│ │",
712− "│ │",
713− "│ │",
714− ]);
715−
716− terminal.backend().assert_buffer(&expected);
717−}
1+// use helix_tui::{
2+// backend::TestBackend,
3+// buffer::Buffer,
4+// layout::Constraint,
5+// style::{Color, Modifier, Style},
6+// text::{Span, Spans},
7+// widgets::{Block, Borders, Cell, Row, Table, TableState},
8+// Terminal,
9+// };
10+
11+// #[test]
12+// fn widgets_table_column_spacing_can_be_changed() {
13+// let test_case = |column_spacing, expected| {
14+// let backend = TestBackend::new(30, 10);
15+// let mut terminal = Terminal::new(backend).unwrap();
16+
17+// terminal
18+// .draw(|f| {
19+// let size = f.size();
20+// let table = Table::new(vec![
21+// Row::new(vec!["Row11", "Row12", "Row13"]),
22+// Row::new(vec!["Row21", "Row22", "Row23"]),
23+// Row::new(vec!["Row31", "Row32", "Row33"]),
24+// Row::new(vec!["Row41", "Row42", "Row43"]),
25+// ])
26+// .header(Row::new(vec!["Head1", "Head2", "Head3"]).bottom_margin(1))
27+// .block(Block::default().borders(Borders::ALL))
28+// .widths(&[
29+// Constraint::Length(5),
30+// Constraint::Length(5),
31+// Constraint::Length(5),
32+// ])
33+// .column_spacing(column_spacing);
34+// f.render_widget(table, size);
35+// })
36+// .unwrap();
37+// terminal.backend().assert_buffer(&expected);
38+// };
39+
40+// // no space between columns
41+// test_case(
42+// 0,
43+// Buffer::with_lines(vec![
44+// "┌────────────────────────────┐",
45+// "│Head1Head2Head3 │",
46+// "│ │",
47+// "│Row11Row12Row13 │",
48+// "│Row21Row22Row23 │",
49+// "│Row31Row32Row33 │",
50+// "│Row41Row42Row43 │",
51+// "│ │",
52+// "│ │",
53+// "└────────────────────────────┘",
54+// ]),
55+// );
56+
57+// // one space between columns
58+// test_case(
59+// 1,
60+// Buffer::with_lines(vec![
61+// "┌────────────────────────────┐",
62+// "│Head1 Head2 Head3 │",
63+// "│ │",
64+// "│Row11 Row12 Row13 │",
65+// "│Row21 Row22 Row23 │",
66+// "│Row31 Row32 Row33 │",
67+// "│Row41 Row42 Row43 │",
68+// "│ │",
69+// "│ │",
70+// "└────────────────────────────┘",
71+// ]),
72+// );
73+
74+// // enough space to just not hide the third column
75+// test_case(
76+// 6,
77+// Buffer::with_lines(vec![
78+// "┌────────────────────────────┐",
79+// "│Head1 Head2 Head3 │",
80+// "│ │",
81+// "│Row11 Row12 Row13 │",
82+// "│Row21 Row22 Row23 │",
83+// "│Row31 Row32 Row33 │",
84+// "│Row41 Row42 Row43 │",
85+// "│ │",
86+// "│ │",
87+// "└────────────────────────────┘",
88+// ]),
89+// );
90+
91+// // enough space to hide part of the third column
92+// test_case(
93+// 7,
94+// Buffer::with_lines(vec![
95+// "┌────────────────────────────┐",
96+// "│Head1 Head2 Head│",
97+// "│ │",
98+// "│Row11 Row12 Row1│",
99+// "│Row21 Row22 Row2│",
100+// "│Row31 Row32 Row3│",
101+// "│Row41 Row42 Row4│",
102+// "│ │",
103+// "│ │",
104+// "└────────────────────────────┘",
105+// ]),
106+// );
107+// }
108+
109+// #[test]
110+// fn widgets_table_columns_widths_can_use_fixed_length_constraints() {
111+// let test_case = |widths, expected| {
112+// let backend = TestBackend::new(30, 10);
113+// let mut terminal = Terminal::new(backend).unwrap();
114+
115+// terminal
116+// .draw(|f| {
117+// let size = f.size();
118+// let table = Table::new(vec![
119+// Row::new(vec!["Row11", "Row12", "Row13"]),
120+// Row::new(vec!["Row21", "Row22", "Row23"]),
121+// Row::new(vec!["Row31", "Row32", "Row33"]),
122+// Row::new(vec!["Row41", "Row42", "Row43"]),
123+// ])
124+// .header(Row::new(vec!["Head1", "Head2", "Head3"]).bottom_margin(1))
125+// .block(Block::default().borders(Borders::ALL))
126+// .widths(widths);
127+// f.render_widget(table, size);
128+// })
129+// .unwrap();
130+// terminal.backend().assert_buffer(&expected);
131+// };
132+
133+// // columns of zero width show nothing
134+// test_case(
135+// &[
136+// Constraint::Length(0),
137+// Constraint::Length(0),
138+// Constraint::Length(0),
139+// ],
140+// Buffer::with_lines(vec![
141+// "┌────────────────────────────┐",
142+// "│ │",
143+// "│ │",
144+// "│ │",
145+// "│ │",
146+// "│ │",
147+// "│ │",
148+// "│ │",
149+// "│ │",
150+// "└────────────────────────────┘",
151+// ]),
152+// );
153+
154+// // columns of 1 width trim
155+// test_case(
156+// &[
157+// Constraint::Length(1),
158+// Constraint::Length(1),
159+// Constraint::Length(1),
160+// ],
161+// Buffer::with_lines(vec![
162+// "┌────────────────────────────┐",
163+// "│H H H │",
164+// "│ │",
165+// "│R R R │",
166+// "│R R R │",
167+// "│R R R │",
168+// "│R R R │",
169+// "│ │",
170+// "│ │",
171+// "└────────────────────────────┘",
172+// ]),
173+// );
174+
175+// // columns of large width just before pushing a column off
176+// test_case(
177+// &[
178+// Constraint::Length(8),
179+// Constraint::Length(8),
180+// Constraint::Length(8),
181+// ],
182+// Buffer::with_lines(vec![
183+// "┌────────────────────────────┐",
184+// "│Head1 Head2 Head3 │",
185+// "│ │",
186+// "│Row11 Row12 Row13 │",
187+// "│Row21 Row22 Row23 │",
188+// "│Row31 Row32 Row33 │",
189+// "│Row41 Row42 Row43 │",
190+// "│ │",
191+// "│ │",
192+// "└────────────────────────────┘",
193+// ]),
194+// );
195+// }
196+
197+// #[test]
198+// fn widgets_table_columns_widths_can_use_percentage_constraints() {
199+// let test_case = |widths, expected| {
200+// let backend = TestBackend::new(30, 10);
201+// let mut terminal = Terminal::new(backend).unwrap();
202+
203+// terminal
204+// .draw(|f| {
205+// let size = f.size();
206+// let table = Table::new(vec![
207+// Row::new(vec!["Row11", "Row12", "Row13"]),
208+// Row::new(vec!["Row21", "Row22", "Row23"]),
209+// Row::new(vec!["Row31", "Row32", "Row33"]),
210+// Row::new(vec!["Row41", "Row42", "Row43"]),
211+// ])
212+// .header(Row::new(vec!["Head1", "Head2", "Head3"]).bottom_margin(1))
213+// .block(Block::default().borders(Borders::ALL))
214+// .widths(widths)
215+// .column_spacing(0);
216+// f.render_widget(table, size);
217+// })
218+// .unwrap();
219+// terminal.backend().assert_buffer(&expected);
220+// };
221+
222+// // columns of zero width show nothing
223+// test_case(
224+// &[
225+// Constraint::Percentage(0),
226+// Constraint::Percentage(0),
227+// Constraint::Percentage(0),
228+// ],
229+// Buffer::with_lines(vec![
230+// "┌────────────────────────────┐",
231+// "│ │",
232+// "│ │",
233+// "│ │",
234+// "│ │",
235+// "│ │",
236+// "│ │",
237+// "│ │",
238+// "│ │",
239+// "└────────────────────────────┘",
240+// ]),
241+// );
242+
243+// // columns of not enough width trims the data
244+// test_case(
245+// &[
246+// Constraint::Percentage(11),
247+// Constraint::Percentage(11),
248+// Constraint::Percentage(11),
249+// ],
250+// Buffer::with_lines(vec![
251+// "┌────────────────────────────┐",
252+// "│HeaHeaHea │",
253+// "│ │",
254+// "│RowRowRow │",
255+// "│RowRowRow │",
256+// "│RowRowRow │",
257+// "│RowRowRow │",
258+// "│ │",
259+// "│ │",
260+// "└────────────────────────────┘",
261+// ]),
262+// );
263+
264+// // columns of large width just before pushing a column off
265+// test_case(
266+// &[
267+// Constraint::Percentage(33),
268+// Constraint::Percentage(33),
269+// Constraint::Percentage(33),
270+// ],
271+// Buffer::with_lines(vec![
272+// "┌────────────────────────────┐",
273+// "│Head1 Head2 Head3 │",
274+// "│ │",
275+// "│Row11 Row12 Row13 │",
276+// "│Row21 Row22 Row23 │",
277+// "│Row31 Row32 Row33 │",
278+// "│Row41 Row42 Row43 │",
279+// "│ │",
280+// "│ │",
281+// "└────────────────────────────┘",
282+// ]),
283+// );
284+
285+// // percentages summing to 100 should give equal widths
286+// test_case(
287+// &[Constraint::Percentage(50), Constraint::Percentage(50)],
288+// Buffer::with_lines(vec![
289+// "┌────────────────────────────┐",
290+// "│Head1 Head2 │",
291+// "│ │",
292+// "│Row11 Row12 │",
293+// "│Row21 Row22 │",
294+// "│Row31 Row32 │",
295+// "│Row41 Row42 │",
296+// "│ │",
297+// "│ │",
298+// "└────────────────────────────┘",
299+// ]),
300+// );
301+// }
302+
303+// #[test]
304+// fn widgets_table_columns_widths_can_use_mixed_constraints() {
305+// let test_case = |widths, expected| {
306+// let backend = TestBackend::new(30, 10);
307+// let mut terminal = Terminal::new(backend).unwrap();
308+
309+// terminal
310+// .draw(|f| {
311+// let size = f.size();
312+// let table = Table::new(vec![
313+// Row::new(vec!["Row11", "Row12", "Row13"]),
314+// Row::new(vec!["Row21", "Row22", "Row23"]),
315+// Row::new(vec!["Row31", "Row32", "Row33"]),
316+// Row::new(vec!["Row41", "Row42", "Row43"]),
317+// ])
318+// .header(Row::new(vec!["Head1", "Head2", "Head3"]).bottom_margin(1))
319+// .block(Block::default().borders(Borders::ALL))
320+// .widths(widths);
321+// f.render_widget(table, size);
322+// })
323+// .unwrap();
324+// terminal.backend().assert_buffer(&expected);
325+// };
326+
327+// // columns of zero width show nothing
328+// test_case(
329+// &[
330+// Constraint::Percentage(0),
331+// Constraint::Length(0),
332+// Constraint::Percentage(0),
333+// ],
334+// Buffer::with_lines(vec![
335+// "┌────────────────────────────┐",
336+// "│ │",
337+// "│ │",
338+// "│ │",
339+// "│ │",
340+// "│ │",
341+// "│ │",
342+// "│ │",
343+// "│ │",
344+// "└────────────────────────────┘",
345+// ]),
346+// );
347+
348+// // columns of not enough width trims the data
349+// test_case(
350+// &[
351+// Constraint::Percentage(11),
352+// Constraint::Length(20),
353+// Constraint::Percentage(11),
354+// ],
355+// Buffer::with_lines(vec![
356+// "┌────────────────────────────┐",
357+// "│Hea Head2 Hea│",
358+// "│ │",
359+// "│Row Row12 Row│",
360+// "│Row Row22 Row│",
361+// "│Row Row32 Row│",
362+// "│Row Row42 Row│",
363+// "│ │",
364+// "│ │",
365+// "└────────────────────────────┘",
366+// ]),
367+// );
368+
369+// // columns of large width just before pushing a column off
370+// test_case(
371+// &[
372+// Constraint::Percentage(33),
373+// Constraint::Length(10),
374+// Constraint::Percentage(33),
375+// ],
376+// Buffer::with_lines(vec![
377+// "┌────────────────────────────┐",
378+// "│Head1 Head2 Head3 │",
379+// "│ │",
380+// "│Row11 Row12 Row13 │",
381+// "│Row21 Row22 Row23 │",
382+// "│Row31 Row32 Row33 │",
383+// "│Row41 Row42 Row43 │",
384+// "│ │",
385+// "│ │",
386+// "└────────────────────────────┘",
387+// ]),
388+// );
389+
390+// // columns of large size (>100% total) hide the last column
391+// test_case(
392+// &[
393+// Constraint::Percentage(60),
394+// Constraint::Length(10),
395+// Constraint::Percentage(60),
396+// ],
397+// Buffer::with_lines(vec![
398+// "┌────────────────────────────┐",
399+// "│Head1 Head2 │",
400+// "│ │",
401+// "│Row11 Row12 │",
402+// "│Row21 Row22 │",
403+// "│Row31 Row32 │",
404+// "│Row41 Row42 │",
405+// "│ │",
406+// "│ │",
407+// "└────────────────────────────┘",
408+// ]),
409+// );
410+// }
411+
412+// #[test]
413+// fn widgets_table_columns_widths_can_use_ratio_constraints() {
414+// let test_case = |widths, expected| {
415+// let backend = TestBackend::new(30, 10);
416+// let mut terminal = Terminal::new(backend).unwrap();
417+
418+// terminal
419+// .draw(|f| {
420+// let size = f.size();
421+// let table = Table::new(vec![
422+// Row::new(vec!["Row11", "Row12", "Row13"]),
423+// Row::new(vec!["Row21", "Row22", "Row23"]),
424+// Row::new(vec!["Row31", "Row32", "Row33"]),
425+// Row::new(vec!["Row41", "Row42", "Row43"]),
426+// ])
427+// .header(Row::new(vec!["Head1", "Head2", "Head3"]).bottom_margin(1))
428+// .block(Block::default().borders(Borders::ALL))
429+// .widths(widths)
430+// .column_spacing(0);
431+// f.render_widget(table, size);
432+// })
433+// .unwrap();
434+// terminal.backend().assert_buffer(&expected);
435+// };
436+
437+// // columns of zero width show nothing
438+// test_case(
439+// &[
440+// Constraint::Ratio(0, 1),
441+// Constraint::Ratio(0, 1),
442+// Constraint::Ratio(0, 1),
443+// ],
444+// Buffer::with_lines(vec![
445+// "┌────────────────────────────┐",
446+// "│ │",
447+// "│ │",
448+// "│ │",
449+// "│ │",
450+// "│ │",
451+// "│ │",
452+// "│ │",
453+// "│ │",
454+// "└────────────────────────────┘",
455+// ]),
456+// );
457+
458+// // columns of not enough width trims the data
459+// test_case(
460+// &[
461+// Constraint::Ratio(1, 9),
462+// Constraint::Ratio(1, 9),
463+// Constraint::Ratio(1, 9),
464+// ],
465+// Buffer::with_lines(vec![
466+// "┌────────────────────────────┐",
467+// "│HeaHeaHea │",
468+// "│ │",
469+// "│RowRowRow │",
470+// "│RowRowRow │",
471+// "│RowRowRow │",
472+// "│RowRowRow │",
473+// "│ │",
474+// "│ │",
475+// "└────────────────────────────┘",
476+// ]),
477+// );
478+
479+// // columns of large width just before pushing a column off
480+// test_case(
481+// &[
482+// Constraint::Ratio(1, 3),
483+// Constraint::Ratio(1, 3),
484+// Constraint::Ratio(1, 3),
485+// ],
486+// Buffer::with_lines(vec![
487+// "┌────────────────────────────┐",
488+// "│Head1 Head2 Head3 │",
489+// "│ │",
490+// "│Row11 Row12 Row13 │",
491+// "│Row21 Row22 Row23 │",
492+// "│Row31 Row32 Row33 │",
493+// "│Row41 Row42 Row43 │",
494+// "│ │",
495+// "│ │",
496+// "└────────────────────────────┘",
497+// ]),
498+// );
499+
500+// // percentages summing to 100 should give equal widths
501+// test_case(
502+// &[Constraint::Ratio(1, 2), Constraint::Ratio(1, 2)],
503+// Buffer::with_lines(vec![
504+// "┌────────────────────────────┐",
505+// "│Head1 Head2 │",
506+// "│ │",
507+// "│Row11 Row12 │",
508+// "│Row21 Row22 │",
509+// "│Row31 Row32 │",
510+// "│Row41 Row42 │",
511+// "│ │",
512+// "│ │",
513+// "└────────────────────────────┘",
514+// ]),
515+// );
516+// }
517+
518+// #[test]
519+// fn widgets_table_can_have_rows_with_multi_lines() {
520+// let test_case = |state: &mut TableState, expected: Buffer| {
521+// let backend = TestBackend::new(30, 8);
522+// let mut terminal = Terminal::new(backend).unwrap();
523+// terminal
524+// .draw(|f| {
525+// let size = f.size();
526+// let table = Table::new(vec![
527+// Row::new(vec!["Row11", "Row12", "Row13"]),
528+// Row::new(vec!["Row21", "Row22", "Row23"]).height(2),
529+// Row::new(vec!["Row31", "Row32", "Row33"]),
530+// Row::new(vec!["Row41", "Row42", "Row43"]).height(2),
531+// ])
532+// .header(Row::new(vec!["Head1", "Head2", "Head3"]).bottom_margin(1))
533+// .block(Block::default().borders(Borders::ALL))
534+// .highlight_symbol(">> ")
535+// .widths(&[
536+// Constraint::Length(5),
537+// Constraint::Length(5),
538+// Constraint::Length(5),
539+// ])
540+// .column_spacing(1);
541+// f.render_stateful_widget(table, size, state);
542+// })
543+// .unwrap();
544+// terminal.backend().assert_buffer(&expected);
545+// };
546+
547+// let mut state = TableState::default();
548+// // no selection
549+// test_case(
550+// &mut state,
551+// Buffer::with_lines(vec![
552+// "┌────────────────────────────┐",
553+// "│Head1 Head2 Head3 │",
554+// "│ │",
555+// "│Row11 Row12 Row13 │",
556+// "│Row21 Row22 Row23 │",
557+// "│ │",
558+// "│Row31 Row32 Row33 │",
559+// "└────────────────────────────┘",
560+// ]),
561+// );
562+
563+// // select first
564+// state.select(Some(0));
565+// test_case(
566+// &mut state,
567+// Buffer::with_lines(vec![
568+// "┌────────────────────────────┐",
569+// "│ Head1 Head2 Head3 │",
570+// "│ │",
571+// "│>> Row11 Row12 Row13 │",
572+// "│ Row21 Row22 Row23 │",
573+// "│ │",
574+// "│ Row31 Row32 Row33 │",
575+// "└────────────────────────────┘",
576+// ]),
577+// );
578+
579+// // select second (we don't show partially the 4th row)
580+// state.select(Some(1));
581+// test_case(
582+// &mut state,
583+// Buffer::with_lines(vec![
584+// "┌────────────────────────────┐",
585+// "│ Head1 Head2 Head3 │",
586+// "│ │",
587+// "│ Row11 Row12 Row13 │",
588+// "│>> Row21 Row22 Row23 │",
589+// "│ │",
590+// "│ Row31 Row32 Row33 │",
591+// "└────────────────────────────┘",
592+// ]),
593+// );
594+
595+// // select 4th (we don't show partially the 1st row)
596+// state.select(Some(3));
597+// test_case(
598+// &mut state,
599+// Buffer::with_lines(vec![
600+// "┌────────────────────────────┐",
601+// "│ Head1 Head2 Head3 │",
602+// "│ │",
603+// "│ Row31 Row32 Row33 │",
604+// "│>> Row41 Row42 Row43 │",
605+// "│ │",
606+// "│ │",
607+// "└────────────────────────────┘",
608+// ]),
609+// );
610+// }
611+
612+// #[test]
613+// fn widgets_table_can_have_elements_styled_individually() {
614+// let backend = TestBackend::new(30, 4);
615+// let mut terminal = Terminal::new(backend).unwrap();
616+// let mut state = TableState::default();
617+// state.select(Some(0));
618+// terminal
619+// .draw(|f| {
620+// let size = f.size();
621+// let table = Table::new(vec![
622+// Row::new(vec!["Row11", "Row12", "Row13"]).style(Style::default().fg(Color::Green)),
623+// Row::new(vec![
624+// Cell::from("Row21"),
625+// Cell::from("Row22").style(Style::default().fg(Color::Yellow)),
626+// Cell::from(Spans::from(vec![
627+// Span::raw("Row"),
628+// Span::styled("23", Style::default().fg(Color::Blue)),
629+// ]))
630+// .style(Style::default().fg(Color::Red)),
631+// ])
632+// .style(Style::default().fg(Color::LightGreen)),
633+// ])
634+// .header(Row::new(vec!["Head1", "Head2", "Head3"]).bottom_margin(1))
635+// .block(Block::default().borders(Borders::LEFT | Borders::RIGHT))
636+// .highlight_symbol(">> ")
637+// .highlight_style(Style::default().add_modifier(Modifier::BOLD))
638+// .widths(&[
639+// Constraint::Length(6),
640+// Constraint::Length(6),
641+// Constraint::Length(6),
642+// ])
643+// .column_spacing(1);
644+// f.render_stateful_widget(table, size, &mut state);
645+// })
646+// .unwrap();
647+
648+// let mut expected = Buffer::with_lines(vec![
649+// "│ Head1 Head2 Head3 │",
650+// "│ │",
651+// "│>> Row11 Row12 Row13 │",
652+// "│ Row21 Row22 Row23 │",
653+// ]);
654+// // First row = row color + highlight style
655+// for col in 1..=28 {
656+// expected.get_mut(col, 2).set_style(
657+// Style::default()
658+// .fg(Color::Green)
659+// .add_modifier(Modifier::BOLD),
660+// );
661+// }
662+// // Second row:
663+// // 1. row color
664+// for col in 1..=28 {
665+// expected
666+// .get_mut(col, 3)
667+// .set_style(Style::default().fg(Color::LightGreen));
668+// }
669+// // 2. cell color
670+// for col in 11..=16 {
671+// expected
672+// .get_mut(col, 3)
673+// .set_style(Style::default().fg(Color::Yellow));
674+// }
675+// for col in 18..=23 {
676+// expected
677+// .get_mut(col, 3)
678+// .set_style(Style::default().fg(Color::Red));
679+// }
680+// // 3. text color
681+// for col in 21..=22 {
682+// expected
683+// .get_mut(col, 3)
684+// .set_style(Style::default().fg(Color::Blue));
685+// }
686+// terminal.backend().assert_buffer(&expected);
687+// }
688+
689+// #[test]
690+// fn widgets_table_should_render_even_if_empty() {
691+// let backend = TestBackend::new(30, 4);
692+// let mut terminal = Terminal::new(backend).unwrap();
693+// terminal
694+// .draw(|f| {
695+// let size = f.size();
696+// let table = Table::new(vec![])
697+// .header(Row::new(vec!["Head1", "Head2", "Head3"]))
698+// .block(Block::default().borders(Borders::LEFT | Borders::RIGHT))
699+// .widths(&[
700+// Constraint::Length(6),
701+// Constraint::Length(6),
702+// Constraint::Length(6),
703+// ])
704+// .column_spacing(1);
705+// f.render_widget(table, size);
706+// })
707+// .unwrap();
708+
709+// let expected = Buffer::with_lines(vec![
710+// "│Head1 Head2 Head3 │",
711+// "│ │",
712+// "│ │",
713+// "│ │",
714+// ]);
715+
716+// terminal.backend().assert_buffer(&expected);
717+// }