on 02cd68d help sign in
bat/tests/integration_tests.rs
751 lines 16 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 alias_pager_disable() {
410 bat()
411 .env("PAGER", "echo other-pager")
412 .arg("-P")
413 .arg("test.txt")
414 .assert()
415 .success()
416 .stdout(predicate::eq("hello world\n").normalize());
419#[test]
420fn alias_pager_disable_long_overrides_short() {
421 bat()
422 .env("PAGER", "echo pager-output")
423 .arg("-P")
424 .arg("--paging=always")
425 .arg("test.txt")
426 .assert()
427 .success()
428 .stdout(predicate::eq("pager-output\n").normalize());
431#[test]
432fn config_location_test() {
433 bat_with_config()
434 .env("BAT_CONFIG_PATH", "bat.conf")
435 .arg("--config-file")
436 .assert()
437 .success()
438 .stdout("bat.conf\n");
441#[test]
442fn config_read_arguments_from_file() {
443 bat_with_config()
444 .env("BAT_CONFIG_PATH", "bat.conf")
445 .arg("test.txt")
446 .assert()
447 .success()
448 .stdout(predicate::eq("dummy-pager-from-config\n").normalize());
451#[test]
452fn utf16() {
453 // The output will be converted to UTF-8 with a leading UTF-8 BOM
454 bat()
455 .arg("--plain")
456 .arg("--decorations=always")
457 .arg("test_UTF-16LE.txt")
458 .assert()
459 .success()
460 .stdout(std::str::from_utf8(b"\xEF\xBB\xBFhello world\n").unwrap());
463#[test]
464fn can_print_file_named_cache() {
465 bat_with_config()
466 .arg("cache")
467 .assert()
468 .success()
469 .stdout("test\n")
470 .stderr("");
473#[test]
474fn can_print_file_named_cache_with_additional_argument() {
475 bat_with_config()
476 .arg("cache")
477 .arg("test.txt")
478 .assert()
479 .success()
480 .stdout("test\nhello world\n")
481 .stderr("");
484#[test]
485fn can_print_file_starting_with_cache() {
486 bat_with_config()
487 .arg("cache.c")
488 .assert()
489 .success()
490 .stdout("test\n")
491 .stderr("");
494#[test]
495fn does_not_print_unwanted_file_named_cache() {
496 bat_with_config().arg("cach").assert().failure();
499#[test]
500fn unicode_wrap() {
501 bat_with_config()
502 .arg("unicode-wrap.txt")
503 .arg("--style=numbers,snip")
504 .arg("--decorations=always")
505 .arg("--terminal-width=40")
506 .assert()
507 .success()
508 .stdout(
509 " 1 ビタミンA ビタミンD ビタミンE ビ
510 タミンK ビタミンB1 ビタミンB2 ナ
511 イアシン パントテン酸 ビタミンB6
512 ビタミンB12 葉酸 ビオチン ビタ
513 ミンC
514 2
515 3 고양이 고양이 고양이 고양이 고양이
516 고양이 고양이 고양이 고양이 고양이
517 고양이 고양이 고양이 고양이 고양이
518 고양이 고양이 고양이 고양이 고양이
519 고양이 고양이 고양이 고양이 고양이
520 고양이 고양이 고양이 고양이 고양이
521 고양이 고양이 고양이 고양이 고양이
522 고양이 고양이 고양이 고양이 고양이
523 고양이
524 4
525 5 1 บวก 2 บวก 3 บวก 4 บวก 5 บวก 6 บวก
526 7 บวก 8 บวก 9 บวก 10 บวก 11 บวก 12
527 บวก 13 บวก 14 บวก 15 บวก 16 บวก 17
528 บวก 18 บวก 19 บวก 20
529 6
530 7 Бельгия Болгария Чехия Дания Герман
531 ия Эстония Ирландия Греция Испания
532 Франция Хорватия Италия Кипр Латвия
533 Литва Люксембург Венгрия Мальта Ни
534 дерланды Австрия Польша Португалия
535 Румыния Словения Словакия Финляндия
536 Швеция Великобритания
537",
538 );
541#[test]
542fn snip() {
543 bat()
544 .arg("multiline.txt")
545 .arg("--style=numbers,snip")
546 .arg("--decorations=always")
547 .arg("--line-range=1:2")
548 .arg("--line-range=4:")
549 .arg("--terminal-width=80")
550 .assert()
551 .success()
552 .stdout(
553 " 1 line 1
554 2 line 2
555 ...─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ 8< ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
556 4 line 4
557",
558 );
561#[test]
562fn empty_file_leads_to_empty_output_with_grid_enabled() {
563 bat()
564 .arg("empty.txt")
565 .arg("--style=grid")
566 .arg("--decorations=always")
567 .arg("--terminal-width=80")
568 .assert()
569 .success()
570 .stdout("");
573#[test]
574fn filename_basic() {
575 bat()
576 .arg("test.txt")
577 .arg("--decorations=always")
578 .arg("--style=header")
579 .arg("-r=0:0")
580 .arg("--file-name=foo")
581 .assert()
582 .success()
583 .stdout("File: foo\n")
584 .stderr("");
587#[test]
588fn filename_binary() {
589 bat()
590 .arg("test.binary")
591 .arg("--decorations=always")
592 .arg("--style=header")
593 .arg("-r=0:0")
594 .arg("--file-name=foo")
595 .assert()
596 .success()
597 .stdout("File: foo <BINARY>\n")
598 .stderr("");
601#[test]
602fn filename_stdin() {
603 bat()
604 .arg("--decorations=always")
605 .arg("--style=header")
606 .arg("-r=0:0")
607 .arg("-")
608 .write_stdin("stdin\n")
609 .arg("--file-name=foo")
610 .assert()
611 .success()
612 .stdout("File: foo\n")
613 .stderr("");
616#[test]
617fn filename_stdin_binary() {
618 let vec = vec![0; 1];
619 bat_with_config()
620 .arg("--decorations=always")
621 .arg("--style=header")
622 .write_stdin(vec)
623 .arg("--file-name=foo")
624 .assert()
625 .success()
626 .stdout("File: foo <BINARY>\n")
627 .stderr("");
630#[test]
631fn filename_multiple_ok() {
632 bat()
633 .arg("--decorations=always")
634 .arg("--style=header")
635 .arg("-r=0:0")
636 .arg("test.txt")
637 .arg("--file-name=foo")
638 .arg("single-line.txt")
639 .arg("--file-name=bar")
640 .assert()
641 .success()
642 .stdout("File: foo\n\nFile: bar\n")
643 .stderr("");
646#[test]
647fn filename_multiple_err() {
648 bat()
649 .arg("--decorations=always")
650 .arg("--style=header")
651 .arg("-r=0:0")
652 .arg("test.txt")
653 .arg("--file-name=foo")
654 .arg("single-line.txt")
655 .assert()
656 .failure();
659#[test]
660fn header_padding() {
661 bat()
662 .arg("--decorations=always")
663 .arg("--style=header")
664 .arg("test.txt")
665 .arg("single-line.txt")
666 .assert()
667 .stdout("File: test.txt\nhello world\n\nFile: single-line.txt\nSingle Line\n")
668 .stderr("");
671#[cfg(target_os = "linux")]
672#[test]
673fn file_with_invalid_utf8_filename() {
674 use std::ffi::OsStr;
675 use std::fs::File;
676 use std::io::Write;
677 use std::os::unix::ffi::OsStrExt;
679 use tempdir::TempDir;
681 let tmp_dir = TempDir::new("bat_test").expect("can create temporary directory");
682 let file_path = tmp_dir
683 .path()
684 .join(OsStr::from_bytes(b"test-invalid-utf8-\xC3(.rs"));
685 {
686 let mut file = File::create(&file_path).expect("can create temporary file");
687 writeln!(file, "dummy content").expect("can write to file");
688 }
690 bat()
691 .arg(file_path.as_os_str())
692 .assert()
693 .success()
694 .stdout("dummy content\n");
697#[test]
698fn do_not_panic_regression_tests() {
699 for filename in &[
700 "issue_28.md",
701 "issue_190.md",
702 "issue_314.hs",
703 "issue_914.rb",
704 "issue_915.vue",
705 ] {
706 bat()
707 .arg("--color=always")
708 .arg(&format!("regression_tests/{}", filename))
709 .assert()
710 .success();
711 }
714#[test]
715fn do_not_detect_different_syntax_for_stdin_and_files() {
716 let file = "regression_tests/issue_985.js";
718 let cmd_for_file = bat()
719 .arg("--color=always")
720 .arg("--map-syntax=*.js:Markdown")
721 .arg(&format!("--file-name={}", file))
722 .arg("--style=plain")
723 .arg(file)
724 .assert()
725 .success();
727 let cmd_for_stdin = bat()
728 .arg("--color=always")
729 .arg("--map-syntax=*.js:Markdown")
730 .arg("--style=plain")
731 .arg(&format!("--file-name={}", file))
732 .pipe_stdin(Path::new(EXAMPLES_DIR).join(file))
733 .unwrap()
734 .assert()
735 .success();
737 assert_eq!(
738 from_utf8(&cmd_for_file.get_output().stdout).expect("output is valid utf-8"),
739 from_utf8(&cmd_for_stdin.get_output().stdout).expect("output is valid utf-8")
740 );
743#[test]
744fn show_all_mode() {
745 bat()
746 .arg("--show-all")
747 .arg("nonprintable.txt")
748 .assert()
749 .stdout("hello·world␊\n├──┤␍␀␇␈␛")
750 .stderr("");