on 2158366 help sign in
helix/helix-tui/tests/widgets_table.rs
717 lines 31 kB history raw
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// };
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();
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// };
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// );
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// );
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// );
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// }
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();
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// };
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// );
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// );
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// }
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();
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// };
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// );
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// );
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// );
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// }
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();
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// };
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// );
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// );
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// );
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// }
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();
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// };
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// );
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// );
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// );
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// }
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// };
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// );
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// );
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// );
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// }
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();
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// }
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();
709// let expected = Buffer::with_lines(vec![
710// "│Head1 Head2 Head3 │",
711// "│ │",
712// "│ │",
713// "│ │",
714// ]);
716// terminal.backend().assert_buffer(&expected);
717// }