on 3d07dec help sign in
bat/tests/integration_tests.rs
853 lines 20 kB history raw
1use assert_cmd::Command;
2use predicates::{prelude::predicate, str::PredicateStrExt};
3use std::path::Path;
4use std::str::from_utf8;
6const EXAMPLES_DIR: &str = "tests/examples";
8fn bat_with_config() -> Command {
9 let mut cmd = Command::cargo_bin("bat").unwrap();
10 cmd.current_dir("tests/examples");
11 cmd.env_remove("PAGER");
12 cmd.env_remove("BAT_PAGER");
13 cmd.env_remove("BAT_CONFIG_PATH");
14 cmd.env_remove("BAT_STYLE");
15 cmd.env_remove("BAT_THEME");
16 cmd.env_remove("BAT_TABS");
17 cmd
20fn bat() -> Command {
21 let mut cmd = bat_with_config();
22 cmd.arg("--no-config");
23 cmd
26#[test]
27fn basic() {
28 bat()
29 .arg("test.txt")
30 .assert()
31 .success()
32 .stdout("hello world\n")
33 .stderr("");
36#[test]
37fn stdin() {
38 bat()
39 .write_stdin("foo\nbar\n")
40 .assert()
41 .success()
42 .stdout("foo\nbar\n");
45#[test]
46fn concatenate() {
47 bat()
48 .arg("test.txt")
49 .arg("test.txt")
50 .assert()
51 .success()
52 .stdout("hello world\nhello world\n");
55#[test]
56fn concatenate_stdin() {
57 bat()
58 .arg("test.txt")
59 .arg("-")
60 .arg("test.txt")
61 .write_stdin("stdin\n")
62 .assert()
63 .success()
64 .stdout("hello world\nstdin\nhello world\n");
67#[test]
68fn concatenate_empty_first() {
69 bat()
70 .arg("empty.txt")
71 .arg("test.txt")
72 .assert()
73 .success()
74 .stdout("hello world\n");
77#[test]
78fn concatenate_empty_last() {
79 bat()
80 .arg("test.txt")
81 .arg("empty.txt")
82 .assert()
83 .success()
84 .stdout("hello world\n");
87#[test]
88fn concatenate_empty_both() {
89 bat()
90 .arg("empty.txt")
91 .arg("empty.txt")
92 .assert()
93 .success()
94 .stdout("");
97#[test]
98fn concatenate_empty_between() {
99 bat()
100 .arg("test.txt")
101 .arg("empty.txt")
102 .arg("test.txt")
103 .assert()
104 .success()
105 .stdout("hello world\nhello world\n");
108#[test]
109fn concatenate_empty_first_and_last() {
110 bat()
111 .arg("empty.txt")
112 .arg("test.txt")
113 .arg("empty.txt")
114 .assert()
115 .success()
116 .stdout("hello world\n");
119#[test]
120fn concatenate_single_line() {
121 bat()
122 .arg("single-line.txt")
123 .arg("single-line.txt")
124 .assert()
125 .success()
126 .stdout("Single LineSingle Line");
129#[test]
130fn concatenate_single_line_empty() {
131 bat()
132 .arg("single-line.txt")
133 .arg("empty.txt")
134 .arg("single-line.txt")
135 .assert()
136 .success()
137 .stdout("Single LineSingle Line");
140#[test]
141fn line_numbers() {
142 bat()
143 .arg("multiline.txt")
144 .arg("--style=numbers")
145 .arg("--decorations=always")
146 .assert()
147 .success()
148 .stdout(" 1 line 1\n 2 line 2\n 3 line 3\n 4 line 4\n");
151#[test]
152fn line_range_2_3() {
153 bat()
154 .arg("multiline.txt")
155 .arg("--line-range=2:3")
156 .assert()
157 .success()
158 .stdout("line 2\nline 3\n");
161#[test]
162fn line_range_first_two() {
163 bat()
164 .arg("multiline.txt")
165 .arg("--line-range=:2")
166 .assert()
167 .success()
168 .stdout("line 1\nline 2\n");
171#[test]
172fn line_range_last_3() {
173 bat()
174 .arg("multiline.txt")
175 .arg("--line-range=2:")
176 .assert()
177 .success()
178 .stdout("line 2\nline 3\nline 4\n");
181#[test]
182fn line_range_multiple() {
183 bat()
184 .arg("multiline.txt")
185 .arg("--line-range=1:2")
186 .arg("--line-range=4:4")
187 .assert()
188 .success()
189 .stdout("line 1\nline 2\nline 4\n");
192#[test]
193fn tabs_numbers() {
194 bat()
195 .arg("tabs.txt")
196 .arg("--tabs=4")
197 .arg("--style=numbers")
198 .arg("--decorations=always")
199 .assert()
200 .success()
201 .stdout(
202 " 1 1 2 3 4
203 2 1 ?
204 3 22 ?
205 4 333 ?
206 5 4444 ?
207 6 55555 ?
208 7 666666 ?
209 8 7777777 ?
210 9 88888888 ?
211",
212 );
215#[test]
216fn tabs_passthrough_wrapped() {
217 bat()
218 .arg("tabs.txt")
219 .arg("--tabs=0")
220 .arg("--style=plain")
221 .arg("--decorations=always")
222 .assert()
223 .success()
224 .stdout(
225 " 1 2 3 4
2261 ?
22722 ?
228333 ?
2294444 ?
23055555 ?
231666666 ?
2327777777 ?
23388888888 ?
234",
235 );
238#[test]
239fn tabs_4_wrapped() {
240 bat()
241 .arg("tabs.txt")
242 .arg("--tabs=4")
243 .arg("--style=plain")
244 .arg("--decorations=always")
245 .assert()
246 .success()
247 .stdout(
248 " 1 2 3 4
2491 ?
25022 ?
251333 ?
2524444 ?
25355555 ?
254666666 ?
2557777777 ?
25688888888 ?
257",
258 );
261#[test]
262fn tabs_8_wrapped() {
263 bat()
264 .arg("tabs.txt")
265 .arg("--tabs=8")
266 .arg("--style=plain")
267 .arg("--decorations=always")
268 .assert()
269 .success()
270 .stdout(
271 " 1 2 3 4
2721 ?
27322 ?
274333 ?
2754444 ?
27655555 ?
277666666 ?
2787777777 ?
27988888888 ?
280",
281 );
284#[test]
285fn tabs_passthrough() {
286 bat()
287 .arg("tabs.txt")
288 .arg("--tabs=0")
289 .arg("--style=plain")
290 .arg("--decorations=always")
291 .assert()
292 .success()
293 .stdout(
294 " 1 2 3 4
2951 ?
29622 ?
297333 ?
2984444 ?
29955555 ?
300666666 ?
3017777777 ?
30288888888 ?
303",
304 );
307#[test]
308fn tabs_4() {
309 bat()
310 .arg("tabs.txt")
311 .arg("--tabs=4")
312 .arg("--style=plain")
313 .arg("--decorations=always")
314 .assert()
315 .success()
316 .stdout(
317 " 1 2 3 4
3181 ?
31922 ?
320333 ?
3214444 ?
32255555 ?
323666666 ?
3247777777 ?
32588888888 ?
326",
327 );
330#[test]
331fn tabs_8() {
332 bat()
333 .arg("tabs.txt")
334 .arg("--tabs=8")
335 .arg("--style=plain")
336 .arg("--decorations=always")
337 .assert()
338 .success()
339 .stdout(
340 " 1 2 3 4
3411 ?
34222 ?
343333 ?
3444444 ?
34555555 ?
346666666 ?
3477777777 ?
34888888888 ?
349",
350 );
353#[test]
354fn fail_non_existing() {
355 bat().arg("non-existing-file").assert().failure();
358#[test]
359fn fail_directory() {
360 bat().arg("sub_directory").assert().failure();
363#[test]
364fn do_not_exit_directory() {
365 bat()
366 .arg("sub_directory")
367 .arg("test.txt")
368 .assert()
369 .stdout("hello world\n")
370 .failure();
373#[test]
374fn pager_basic() {
375 bat()
376 .env("PAGER", "echo pager-output")
377 .arg("--paging=always")
378 .arg("test.txt")
379 .assert()
380 .success()
381 .stdout(predicate::eq("pager-output\n").normalize());
384#[test]
385fn pager_overwrite() {
386 bat()
387 .env("PAGER", "echo other-pager")
388 .env("BAT_PAGER", "echo pager-output")
389 .arg("--paging=always")
390 .arg("test.txt")
391 .assert()
392 .success()
393 .stdout(predicate::eq("pager-output\n").normalize());
396#[test]
397fn pager_disable() {
398 bat()
399 .env("PAGER", "echo other-pager")
400 .env("BAT_PAGER", "")
401 .arg("--paging=always")
402 .arg("test.txt")
403 .assert()
404 .success()
405 .stdout(predicate::eq("hello world\n").normalize());
408#[test]
409fn pager_value_bat() {
410 bat()
411 .arg("--pager=bat")
412 .arg("--paging=always")
413 .arg("test.txt")
414 .assert()
415 .failure();
418#[test]
419fn alias_pager_disable() {
420 bat()
421 .env("PAGER", "echo other-pager")
422 .arg("-P")
423 .arg("test.txt")
424 .assert()
425 .success()
426 .stdout(predicate::eq("hello world\n").normalize());
429#[test]
430fn alias_pager_disable_long_overrides_short() {
431 bat()
432 .env("PAGER", "echo pager-output")
433 .arg("-P")
434 .arg("--paging=always")
435 .arg("test.txt")
436 .assert()
437 .success()
438 .stdout(predicate::eq("pager-output\n").normalize());
441#[test]
442fn config_location_test() {
443 bat_with_config()
444 .env("BAT_CONFIG_PATH", "bat.conf")
445 .arg("--config-file")
446 .assert()
447 .success()
448 .stdout("bat.conf\n");
451#[test]
452fn config_read_arguments_from_file() {
453 bat_with_config()
454 .env("BAT_CONFIG_PATH", "bat.conf")
455 .arg("test.txt")
456 .assert()
457 .success()
458 .stdout(predicate::eq("dummy-pager-from-config\n").normalize());
461#[test]
462fn utf16() {
463 // The output will be converted to UTF-8 with a leading UTF-8 BOM
464 bat()
465 .arg("--plain")
466 .arg("--decorations=always")
467 .arg("test_UTF-16LE.txt")
468 .assert()
469 .success()
470 .stdout(std::str::from_utf8(b"\xEF\xBB\xBFhello world\n").unwrap());
473#[test]
474fn can_print_file_named_cache() {
475 bat_with_config()
476 .arg("cache")
477 .assert()
478 .success()
479 .stdout("test\n")
480 .stderr("");
483#[test]
484fn can_print_file_named_cache_with_additional_argument() {
485 bat_with_config()
486 .arg("cache")
487 .arg("test.txt")
488 .assert()
489 .success()
490 .stdout("test\nhello world\n")
491 .stderr("");
494#[test]
495fn can_print_file_starting_with_cache() {
496 bat_with_config()
497 .arg("cache.c")
498 .assert()
499 .success()
500 .stdout("test\n")
501 .stderr("");
504#[test]
505fn does_not_print_unwanted_file_named_cache() {
506 bat_with_config().arg("cach").assert().failure();
509#[test]
510fn unicode_wrap() {
511 bat_with_config()
512 .arg("unicode-wrap.txt")
513 .arg("--style=numbers,snip")
514 .arg("--decorations=always")
515 .arg("--terminal-width=40")
516 .assert()
517 .success()
518 .stdout(
519 " 1 ビタミンA ビタミンD ビタミンE ビ
520 タミンK ビタミンB1 ビタミンB2 ナ
521 イアシン パントテン酸 ビタミンB6
522 ビタミンB12 葉酸 ビオチン ビタ
523 ミンC
524 2
525 3 고양이 고양이 고양이 고양이 고양이
526 고양이 고양이 고양이 고양이 고양이
527 고양이 고양이 고양이 고양이 고양이
528 고양이 고양이 고양이 고양이 고양이
529 고양이 고양이 고양이 고양이 고양이
530 고양이 고양이 고양이 고양이 고양이
531 고양이 고양이 고양이 고양이 고양이
532 고양이 고양이 고양이 고양이 고양이
533 고양이
534 4
535 5 1 บวก 2 บวก 3 บวก 4 บวก 5 บวก 6 บวก
536 7 บวก 8 บวก 9 บวก 10 บวก 11 บวก 12
537 บวก 13 บวก 14 บวก 15 บวก 16 บวก 17
538 บวก 18 บวก 19 บวก 20
539 6
540 7 Бельгия Болгария Чехия Дания Герман
541 ия Эстония Ирландия Греция Испания
542 Франция Хорватия Италия Кипр Латвия
543 Литва Люксембург Венгрия Мальта Ни
544 дерланды Австрия Польша Португалия
545 Румыния Словения Словакия Финляндия
546 Швеция Великобритания
547",
548 );
551#[test]
552fn snip() {
553 bat()
554 .arg("multiline.txt")
555 .arg("--style=numbers,snip")
556 .arg("--decorations=always")
557 .arg("--line-range=1:2")
558 .arg("--line-range=4:")
559 .arg("--terminal-width=80")
560 .assert()
561 .success()
562 .stdout(
563 " 1 line 1
564 2 line 2
565 ...─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ 8< ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
566 4 line 4
567",
568 );
571#[test]
572fn empty_file_leads_to_empty_output_with_grid_enabled() {
573 bat()
574 .arg("empty.txt")
575 .arg("--style=grid")
576 .arg("--decorations=always")
577 .arg("--terminal-width=80")
578 .assert()
579 .success()
580 .stdout("");
583#[test]
584fn empty_file_leads_to_empty_output_with_rule_enabled() {
585 bat()
586 .arg("empty.txt")
587 .arg("--style=rule")
588 .arg("--decorations=always")
589 .arg("--terminal-width=80")
590 .assert()
591 .success()
592 .stdout("");
595#[test]
596fn filename_basic() {
597 bat()
598 .arg("test.txt")
599 .arg("--decorations=always")
600 .arg("--style=header")
601 .arg("-r=0:0")
602 .arg("--file-name=foo")
603 .assert()
604 .success()
605 .stdout("File: foo\n")
606 .stderr("");
609#[test]
610fn filename_binary() {
611 bat()
612 .arg("test.binary")
613 .arg("--decorations=always")
614 .arg("--style=header")
615 .arg("-r=0:0")
616 .arg("--file-name=foo")
617 .assert()
618 .success()
619 .stdout("File: foo <BINARY>\n")
620 .stderr("");
623#[test]
624fn filename_stdin() {
625 bat()
626 .arg("--decorations=always")
627 .arg("--style=header")
628 .arg("-r=0:0")
629 .arg("-")
630 .write_stdin("stdin\n")
631 .arg("--file-name=foo")
632 .assert()
633 .success()
634 .stdout("File: foo\n")
635 .stderr("");
638#[test]
639fn filename_stdin_binary() {
640 let vec = vec![0; 1];
641 bat_with_config()
642 .arg("--decorations=always")
643 .arg("--style=header")
644 .write_stdin(vec)
645 .arg("--file-name=foo")
646 .assert()
647 .success()
648 .stdout("File: foo <BINARY>\n")
649 .stderr("");
652#[test]
653fn filename_multiple_ok() {
654 bat()
655 .arg("--decorations=always")
656 .arg("--style=header")
657 .arg("-r=0:0")
658 .arg("test.txt")
659 .arg("--file-name=foo")
660 .arg("single-line.txt")
661 .arg("--file-name=bar")
662 .assert()
663 .success()
664 .stdout("File: foo\n\nFile: bar\n")
665 .stderr("");
668#[test]
669fn filename_multiple_err() {
670 bat()
671 .arg("--decorations=always")
672 .arg("--style=header")
673 .arg("-r=0:0")
674 .arg("test.txt")
675 .arg("--file-name=foo")
676 .arg("single-line.txt")
677 .assert()
678 .failure();
681#[test]
682fn header_padding() {
683 bat()
684 .arg("--decorations=always")
685 .arg("--style=header")
686 .arg("test.txt")
687 .arg("single-line.txt")
688 .assert()
689 .stdout("File: test.txt\nhello world\n\nFile: single-line.txt\nSingle Line\n")
690 .stderr("");
693#[test]
694fn header_padding_rule() {
695 bat()
696 .arg("--decorations=always")
697 .arg("--style=header,rule")
698 .arg("--terminal-width=80")
699 .arg("test.txt")
700 .arg("single-line.txt")
701 .assert()
702 .stdout(
703 "File: test.txt
704hello world
705────────────────────────────────────────────────────────────────────────────────
706File: single-line.txt
707Single Line
708",
709 )
710 .stderr("");
713#[test]
714fn grid_overrides_rule() {
715 bat()
716 .arg("--decorations=always")
717 .arg("--style=grid,rule")
718 .arg("--terminal-width=80")
719 .arg("test.txt")
720 .arg("single-line.txt")
721 .assert()
722 .stdout(
723 "\
724────────────────────────────────────────────────────────────────────────────────
725hello world
726────────────────────────────────────────────────────────────────────────────────
727────────────────────────────────────────────────────────────────────────────────
728Single Line
729────────────────────────────────────────────────────────────────────────────────
730",
731 )
732 .stderr("\x1b[33m[bat warning]\x1b[0m: Style 'rule' is a subset of style 'grid', 'rule' will not be visible.\n");
735#[cfg(target_os = "linux")]
736#[test]
737fn file_with_invalid_utf8_filename() {
738 use std::ffi::OsStr;
739 use std::fs::File;
740 use std::io::Write;
741 use std::os::unix::ffi::OsStrExt;
743 use tempdir::TempDir;
745 let tmp_dir = TempDir::new("bat_test").expect("can create temporary directory");
746 let file_path = tmp_dir
747 .path()
748 .join(OsStr::from_bytes(b"test-invalid-utf8-\xC3(.rs"));
749 {
750 let mut file = File::create(&file_path).expect("can create temporary file");
751 writeln!(file, "dummy content").expect("can write to file");
752 }
754 bat()
755 .arg(file_path.as_os_str())
756 .assert()
757 .success()
758 .stdout("dummy content\n");
761#[test]
762fn do_not_panic_regression_tests() {
763 for filename in &[
764 "issue_28.md",
765 "issue_190.md",
766 "issue_314.hs",
767 "issue_914.rb",
768 "issue_915.vue",
769 ] {
770 bat()
771 .arg("--color=always")
772 .arg(&format!("regression_tests/{}", filename))
773 .assert()
774 .success();
775 }
778#[test]
779fn do_not_detect_different_syntax_for_stdin_and_files() {
780 let file = "regression_tests/issue_985.js";
782 let cmd_for_file = bat()
783 .arg("--color=always")
784 .arg("--map-syntax=*.js:Markdown")
785 .arg(&format!("--file-name={}", file))
786 .arg("--style=plain")
787 .arg(file)
788 .assert()
789 .success();
791 let cmd_for_stdin = bat()
792 .arg("--color=always")
793 .arg("--map-syntax=*.js:Markdown")
794 .arg("--style=plain")
795 .arg(&format!("--file-name={}", file))
796 .pipe_stdin(Path::new(EXAMPLES_DIR).join(file))
797 .unwrap()
798 .assert()
799 .success();
801 assert_eq!(
802 from_utf8(&cmd_for_file.get_output().stdout).expect("output is valid utf-8"),
803 from_utf8(&cmd_for_stdin.get_output().stdout).expect("output is valid utf-8")
804 );
807#[test]
808fn show_all_mode() {
809 bat()
810 .arg("--show-all")
811 .arg("nonprintable.txt")
812 .assert()
813 .stdout("hello·world␊\n├──┤␍␀␇␈␛")
814 .stderr("");
817#[test]
818fn plain_mode_does_not_add_nonexisting_newline() {
819 bat()
820 .arg("--paging=never")
821 .arg("--color=never")
822 .arg("--decorations=always")
823 .arg("--style=plain")
824 .arg("single-line.txt")
825 .assert()
826 .success()
827 .stdout("Single Line");
830// Regression test for https://github.com/sharkdp/bat/issues/299
831#[test]
832fn grid_for_file_without_newline() {
833 bat()
834 .arg("--paging=never")
835 .arg("--color=never")
836 .arg("--terminal-width=80")
837 .arg("--wrap=never")
838 .arg("--decorations=always")
839 .arg("--style=full")
840 .arg("single-line.txt")
841 .assert()
842 .success()
843 .stdout(
844 "\
845───────┬────────────────────────────────────────────────────────────────────────
846 │ File: single-line.txt
847───────┼────────────────────────────────────────────────────────────────────────
848 1 │ Single Line
849───────┴────────────────────────────────────────────────────────────────────────
850",
851 )
852 .stderr("");