summaryrefslogtreecommitdiffstats
path: root/tests/bfs
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@tavianator.com>2022-10-19 10:29:05 -0400
committerTavian Barnes <tavianator@tavianator.com>2022-10-19 11:50:03 -0400
commit3b387d81e63893ed3fe3b45e3721fbcfb1c5dde0 (patch)
tree513c32eda43d92a8ed977f394492ba198bba1f3b /tests/bfs
parente5972621ffa8864b18d3e303ac714fdbe231be74 (diff)
downloadbfs-3b387d81e63893ed3fe3b45e3721fbcfb1c5dde0.tar.xz
tests: Split test cases into separate files
Diffstat (limited to 'tests/bfs')
-rw-r--r--tests/bfs/D_all.out19
-rw-r--r--tests/bfs/D_all.sh1
-rw-r--r--tests/bfs/D_multi.out19
-rw-r--r--tests/bfs/D_multi.sh1
-rw-r--r--tests/bfs/L_capable.out2
-rw-r--r--tests/bfs/L_capable.sh12
-rw-r--r--tests/bfs/L_unique.out1
-rw-r--r--tests/bfs/L_unique.sh1
-rw-r--r--tests/bfs/L_unique_depth.out3
-rw-r--r--tests/bfs/L_unique_depth.sh1
-rw-r--r--tests/bfs/L_unique_loops.out3
-rw-r--r--tests/bfs/L_unique_loops.sh1
-rw-r--r--tests/bfs/O0.out19
-rw-r--r--tests/bfs/O0.sh1
-rw-r--r--tests/bfs/O1.out19
-rw-r--r--tests/bfs/O1.sh1
-rw-r--r--tests/bfs/O2.out19
-rw-r--r--tests/bfs/O2.sh1
-rw-r--r--tests/bfs/O3.out19
-rw-r--r--tests/bfs/O3.sh1
-rw-r--r--tests/bfs/Ofast.out19
-rw-r--r--tests/bfs/Ofast.sh1
-rw-r--r--tests/bfs/S_bfs.out19
-rw-r--r--tests/bfs/S_bfs.sh2
-rw-r--r--tests/bfs/S_dfs.out19
-rw-r--r--tests/bfs/S_dfs.sh2
-rw-r--r--tests/bfs/S_ids.out19
-rw-r--r--tests/bfs/S_ids.sh2
-rw-r--r--tests/bfs/and_incomplete.sh1
-rw-r--r--tests/bfs/capable.out1
-rw-r--r--tests/bfs/capable.sh12
-rw-r--r--tests/bfs/color.out20
-rw-r--r--tests/bfs/color.sh1
-rw-r--r--tests/bfs/color_L.out20
-rw-r--r--tests/bfs/color_L.sh1
-rw-r--r--tests/bfs/color_L_ln_target.out20
-rw-r--r--tests/bfs/color_L_ln_target.sh1
-rw-r--r--tests/bfs/color_L_no_stat.out20
-rw-r--r--tests/bfs/color_L_no_stat.sh1
-rw-r--r--tests/bfs/color_escapes.out20
-rw-r--r--tests/bfs/color_escapes.sh1
-rw-r--r--tests/bfs/color_ext.out20
-rw-r--r--tests/bfs/color_ext.sh1
-rw-r--r--tests/bfs/color_ext0.out20
-rw-r--r--tests/bfs/color_ext0.sh1
-rw-r--r--tests/bfs/color_ext_override.out20
-rw-r--r--tests/bfs/color_ext_override.sh1
-rw-r--r--tests/bfs/color_ext_underride.out20
-rw-r--r--tests/bfs/color_ext_underride.sh1
-rw-r--r--tests/bfs/color_ln_target.out20
-rw-r--r--tests/bfs/color_ln_target.sh1
-rw-r--r--tests/bfs/color_ls.out12
-rw-r--r--tests/bfs/color_ls.sh15
-rw-r--r--tests/bfs/color_mh.out20
-rw-r--r--tests/bfs/color_mh.sh1
-rw-r--r--tests/bfs/color_mh0.out20
-rw-r--r--tests/bfs/color_mh0.sh1
-rw-r--r--tests/bfs/color_mi.out20
-rw-r--r--tests/bfs/color_mi.sh1
-rw-r--r--tests/bfs/color_missing_colon.out20
-rw-r--r--tests/bfs/color_missing_colon.sh1
-rw-r--r--tests/bfs/color_no_stat.out20
-rw-r--r--tests/bfs/color_no_stat.sh1
-rw-r--r--tests/bfs/color_nul.outbin0 -> 20 bytes
-rw-r--r--tests/bfs/color_nul.sh2
-rw-r--r--tests/bfs/color_or.out20
-rw-r--r--tests/bfs/color_or.sh1
-rw-r--r--tests/bfs/color_or0_mi.out20
-rw-r--r--tests/bfs/color_or0_mi.sh1
-rw-r--r--tests/bfs/color_or0_mi0.out20
-rw-r--r--tests/bfs/color_or0_mi0.sh1
-rw-r--r--tests/bfs/color_or_mi.out20
-rw-r--r--tests/bfs/color_or_mi.sh1
-rw-r--r--tests/bfs/color_or_mi0.out20
-rw-r--r--tests/bfs/color_or_mi0.sh1
-rw-r--r--tests/bfs/color_rs_lc_rc_ec.out20
-rw-r--r--tests/bfs/color_rs_lc_rc_ec.sh1
-rw-r--r--tests/bfs/color_st0_tw0_ow.out20
-rw-r--r--tests/bfs/color_st0_tw0_ow.sh1
-rw-r--r--tests/bfs/color_st0_tw0_ow0.out20
-rw-r--r--tests/bfs/color_st0_tw0_ow0.sh1
-rw-r--r--tests/bfs/color_st0_tw_ow.out20
-rw-r--r--tests/bfs/color_st0_tw_ow.sh1
-rw-r--r--tests/bfs/color_st0_tw_ow0.out20
-rw-r--r--tests/bfs/color_st0_tw_ow0.sh1
-rw-r--r--tests/bfs/color_st_tw0_ow.out20
-rw-r--r--tests/bfs/color_st_tw0_ow.sh1
-rw-r--r--tests/bfs/color_st_tw0_ow0.out20
-rw-r--r--tests/bfs/color_st_tw0_ow0.sh1
-rw-r--r--tests/bfs/color_st_tw_ow0.out20
-rw-r--r--tests/bfs/color_st_tw_ow0.sh1
-rw-r--r--tests/bfs/color_star.out20
-rw-r--r--tests/bfs/color_star.sh2
-rw-r--r--tests/bfs/color_su0_sg.out20
-rw-r--r--tests/bfs/color_su0_sg.sh1
-rw-r--r--tests/bfs/color_su0_sg0.out20
-rw-r--r--tests/bfs/color_su0_sg0.sh1
-rw-r--r--tests/bfs/color_su_sg0.out20
-rw-r--r--tests/bfs/color_su_sg0.sh1
-rw-r--r--tests/bfs/comma_incomplete.sh1
-rw-r--r--tests/bfs/data_flow_hidden.out19
-rw-r--r--tests/bfs/data_flow_hidden.sh1
-rw-r--r--tests/bfs/deep_strict.out16
-rw-r--r--tests/bfs/deep_strict.sh5
-rw-r--r--tests/bfs/exclude_depth.out13
-rw-r--r--tests/bfs/exclude_depth.sh1
-rw-r--r--tests/bfs/exclude_exclude.sh1
-rw-r--r--tests/bfs/exclude_mindepth.out0
-rw-r--r--tests/bfs/exclude_mindepth.sh1
-rw-r--r--tests/bfs/exclude_name.out13
-rw-r--r--tests/bfs/exclude_name.sh1
-rw-r--r--tests/bfs/exclude_print.sh1
-rw-r--r--tests/bfs/exec_flush_fprint.out1
-rw-r--r--tests/bfs/exec_flush_fprint.sh3
-rw-r--r--tests/bfs/exec_flush_fprint_fail.sh2
-rw-r--r--tests/bfs/execdir_plus.out11
-rw-r--r--tests/bfs/execdir_plus.sh7
-rw-r--r--tests/bfs/execdir_plus_nonexistent.out19
-rw-r--r--tests/bfs/execdir_plus_nonexistent.sh5
-rw-r--r--tests/bfs/expr_flag_path.out2
-rw-r--r--tests/bfs/expr_flag_path.sh1
-rw-r--r--tests/bfs/expr_path_flag.out2
-rw-r--r--tests/bfs/expr_path_flag.sh1
-rw-r--r--tests/bfs/flag_expr_path.out2
-rw-r--r--tests/bfs/flag_expr_path.sh1
-rw-r--r--tests/bfs/fprint_duplicate_stdout.out38
-rw-r--r--tests/bfs/fprint_duplicate_stdout.sh3
-rw-r--r--tests/bfs/fprint_error_stderr.sh2
-rw-r--r--tests/bfs/fprint_error_stdout.sh2
-rw-r--r--tests/bfs/help.sh6
-rw-r--r--tests/bfs/hidden.out1
-rw-r--r--tests/bfs/hidden.sh1
-rw-r--r--tests/bfs/hidden_root.out5
-rw-r--r--tests/bfs/hidden_root.sh2
-rw-r--r--tests/bfs/links_empty.sh1
-rw-r--r--tests/bfs/links_invalid.sh1
-rw-r--r--tests/bfs/links_negative.sh1
-rw-r--r--tests/bfs/links_noarg.sh1
-rw-r--r--tests/bfs/newerma_nonexistent.sh1
-rw-r--r--tests/bfs/newermq.sh1
-rw-r--r--tests/bfs/newermt_invalid.sh1
-rw-r--r--tests/bfs/newerqm.sh1
-rw-r--r--tests/bfs/nohidden.out21
-rw-r--r--tests/bfs/nohidden.sh1
-rw-r--r--tests/bfs/nohidden_depth.out21
-rw-r--r--tests/bfs/nohidden_depth.sh1
-rw-r--r--tests/bfs/nowarn.sh2
-rw-r--r--tests/bfs/ok_plus_semicolon.out19
-rw-r--r--tests/bfs/ok_plus_semicolon.sh8
-rw-r--r--tests/bfs/okdir_plus_semicolon.out19
-rw-r--r--tests/bfs/okdir_plus_semicolon.sh1
-rw-r--r--tests/bfs/or_incomplete.sh1
-rw-r--r--tests/bfs/path_expr_flag.out2
-rw-r--r--tests/bfs/path_expr_flag.sh1
-rw-r--r--tests/bfs/path_flag_expr.out2
-rw-r--r--tests/bfs/path_flag_expr.sh1
-rw-r--r--tests/bfs/perm_leading_plus_symbolic.out0
-rw-r--r--tests/bfs/perm_leading_plus_symbolic.sh1
-rw-r--r--tests/bfs/perm_symbolic_double_comma.sh1
-rw-r--r--tests/bfs/perm_symbolic_missing_action.sh1
-rw-r--r--tests/bfs/perm_symbolic_trailing_comma.sh1
-rw-r--r--tests/bfs/printf_color.out20
-rw-r--r--tests/bfs/printf_color.sh1
-rw-r--r--tests/bfs/printf_duplicate_flag.sh1
-rw-r--r--tests/bfs/printf_everything.sh9
-rw-r--r--tests/bfs/printf_incomplete_escape.sh1
-rw-r--r--tests/bfs/printf_incomplete_format.sh1
-rw-r--r--tests/bfs/printf_invalid_escape.sh1
-rw-r--r--tests/bfs/printf_invalid_format.sh1
-rw-r--r--tests/bfs/printf_must_be_numeric.sh1
-rw-r--r--tests/bfs/printf_w.out0
-rw-r--r--tests/bfs/printf_w.sh2
-rw-r--r--tests/bfs/stderr_fails_loudly.sh2
-rw-r--r--tests/bfs/stderr_fails_silently.out19
-rw-r--r--tests/bfs/stderr_fails_silently.sh2
-rw-r--r--tests/bfs/type_multi.out7
-rw-r--r--tests/bfs/type_multi.sh1
-rw-r--r--tests/bfs/typo.sh1
-rw-r--r--tests/bfs/unexpected_operator.sh1
-rw-r--r--tests/bfs/unique.out2
-rw-r--r--tests/bfs/unique.sh1
-rw-r--r--tests/bfs/unique_depth.out19
-rw-r--r--tests/bfs/unique_depth.sh1
-rw-r--r--tests/bfs/version.sh1
-rw-r--r--tests/bfs/warn.sh2
-rw-r--r--tests/bfs/xtype_depth.sh2
-rw-r--r--tests/bfs/xtype_multi.out10
-rw-r--r--tests/bfs/xtype_multi.sh1
-rw-r--r--tests/bfs/xtype_reorder.out0
-rw-r--r--tests/bfs/xtype_reorder.sh4
190 files changed, 1359 insertions, 0 deletions
diff --git a/tests/bfs/D_all.out b/tests/bfs/D_all.out
new file mode 100644
index 0000000..a7ccfe4
--- /dev/null
+++ b/tests/bfs/D_all.out
@@ -0,0 +1,19 @@
+basic
+basic/a
+basic/b
+basic/c
+basic/c/d
+basic/e
+basic/e/f
+basic/g
+basic/g/h
+basic/i
+basic/j
+basic/j/foo
+basic/k
+basic/k/foo
+basic/k/foo/bar
+basic/l
+basic/l/foo
+basic/l/foo/bar
+basic/l/foo/bar/baz
diff --git a/tests/bfs/D_all.sh b/tests/bfs/D_all.sh
new file mode 100644
index 0000000..170698a
--- /dev/null
+++ b/tests/bfs/D_all.sh
@@ -0,0 +1 @@
+bfs_diff -D all basic
diff --git a/tests/bfs/D_multi.out b/tests/bfs/D_multi.out
new file mode 100644
index 0000000..a7ccfe4
--- /dev/null
+++ b/tests/bfs/D_multi.out
@@ -0,0 +1,19 @@
+basic
+basic/a
+basic/b
+basic/c
+basic/c/d
+basic/e
+basic/e/f
+basic/g
+basic/g/h
+basic/i
+basic/j
+basic/j/foo
+basic/k
+basic/k/foo
+basic/k/foo/bar
+basic/l
+basic/l/foo
+basic/l/foo/bar
+basic/l/foo/bar/baz
diff --git a/tests/bfs/D_multi.sh b/tests/bfs/D_multi.sh
new file mode 100644
index 0000000..08a8ca6
--- /dev/null
+++ b/tests/bfs/D_multi.sh
@@ -0,0 +1 @@
+bfs_diff -D opt,tree,unknown basic
diff --git a/tests/bfs/L_capable.out b/tests/bfs/L_capable.out
new file mode 100644
index 0000000..e5ba3c7
--- /dev/null
+++ b/tests/bfs/L_capable.out
@@ -0,0 +1,2 @@
+scratch/capable
+scratch/link
diff --git a/tests/bfs/L_capable.sh b/tests/bfs/L_capable.sh
new file mode 100644
index 0000000..e1806b7
--- /dev/null
+++ b/tests/bfs/L_capable.sh
@@ -0,0 +1,12 @@
+skip_unless test "$SUDO"
+skip_unless test "$UNAME" = "Linux"
+
+rm -rf scratch/*
+
+skip_unless invoke_bfs scratch -quit -capable
+
+$TOUCH scratch/{normal,capable}
+sudo setcap all+ep scratch/capable
+ln -s capable scratch/link
+
+bfs_diff -L scratch -capable
diff --git a/tests/bfs/L_unique.out b/tests/bfs/L_unique.out
new file mode 100644
index 0000000..c94c48e
--- /dev/null
+++ b/tests/bfs/L_unique.out
@@ -0,0 +1 @@
+links/file
diff --git a/tests/bfs/L_unique.sh b/tests/bfs/L_unique.sh
new file mode 100644
index 0000000..c804526
--- /dev/null
+++ b/tests/bfs/L_unique.sh
@@ -0,0 +1 @@
+bfs_diff -L links/{file,symlink,hardlink} -unique
diff --git a/tests/bfs/L_unique_depth.out b/tests/bfs/L_unique_depth.out
new file mode 100644
index 0000000..dad0a98
--- /dev/null
+++ b/tests/bfs/L_unique_depth.out
@@ -0,0 +1,3 @@
+loops/deeply/nested
+loops/deeply/nested/dir
+loops/deeply/nested/loop
diff --git a/tests/bfs/L_unique_depth.sh b/tests/bfs/L_unique_depth.sh
new file mode 100644
index 0000000..fb9aca1
--- /dev/null
+++ b/tests/bfs/L_unique_depth.sh
@@ -0,0 +1 @@
+bfs_diff -L loops/deeply/nested -unique -depth
diff --git a/tests/bfs/L_unique_loops.out b/tests/bfs/L_unique_loops.out
new file mode 100644
index 0000000..dad0a98
--- /dev/null
+++ b/tests/bfs/L_unique_loops.out
@@ -0,0 +1,3 @@
+loops/deeply/nested
+loops/deeply/nested/dir
+loops/deeply/nested/loop
diff --git a/tests/bfs/L_unique_loops.sh b/tests/bfs/L_unique_loops.sh
new file mode 100644
index 0000000..2bdd94e
--- /dev/null
+++ b/tests/bfs/L_unique_loops.sh
@@ -0,0 +1 @@
+bfs_diff -L loops/deeply/nested -unique
diff --git a/tests/bfs/O0.out b/tests/bfs/O0.out
new file mode 100644
index 0000000..a7ccfe4
--- /dev/null
+++ b/tests/bfs/O0.out
@@ -0,0 +1,19 @@
+basic
+basic/a
+basic/b
+basic/c
+basic/c/d
+basic/e
+basic/e/f
+basic/g
+basic/g/h
+basic/i
+basic/j
+basic/j/foo
+basic/k
+basic/k/foo
+basic/k/foo/bar
+basic/l
+basic/l/foo
+basic/l/foo/bar
+basic/l/foo/bar/baz
diff --git a/tests/bfs/O0.sh b/tests/bfs/O0.sh
new file mode 100644
index 0000000..0f92d71
--- /dev/null
+++ b/tests/bfs/O0.sh
@@ -0,0 +1 @@
+bfs_diff -O0 basic -not \( -type f -not -type f \)
diff --git a/tests/bfs/O1.out b/tests/bfs/O1.out
new file mode 100644
index 0000000..a7ccfe4
--- /dev/null
+++ b/tests/bfs/O1.out
@@ -0,0 +1,19 @@
+basic
+basic/a
+basic/b
+basic/c
+basic/c/d
+basic/e
+basic/e/f
+basic/g
+basic/g/h
+basic/i
+basic/j
+basic/j/foo
+basic/k
+basic/k/foo
+basic/k/foo/bar
+basic/l
+basic/l/foo
+basic/l/foo/bar
+basic/l/foo/bar/baz
diff --git a/tests/bfs/O1.sh b/tests/bfs/O1.sh
new file mode 100644
index 0000000..924b410
--- /dev/null
+++ b/tests/bfs/O1.sh
@@ -0,0 +1 @@
+bfs_diff -O1 basic -not \( -type f -not -type f \)
diff --git a/tests/bfs/O2.out b/tests/bfs/O2.out
new file mode 100644
index 0000000..a7ccfe4
--- /dev/null
+++ b/tests/bfs/O2.out
@@ -0,0 +1,19 @@
+basic
+basic/a
+basic/b
+basic/c
+basic/c/d
+basic/e
+basic/e/f
+basic/g
+basic/g/h
+basic/i
+basic/j
+basic/j/foo
+basic/k
+basic/k/foo
+basic/k/foo/bar
+basic/l
+basic/l/foo
+basic/l/foo/bar
+basic/l/foo/bar/baz
diff --git a/tests/bfs/O2.sh b/tests/bfs/O2.sh
new file mode 100644
index 0000000..9382456
--- /dev/null
+++ b/tests/bfs/O2.sh
@@ -0,0 +1 @@
+bfs_diff -O2 basic -not \( -type f -not -type f \)
diff --git a/tests/bfs/O3.out b/tests/bfs/O3.out
new file mode 100644
index 0000000..a7ccfe4
--- /dev/null
+++ b/tests/bfs/O3.out
@@ -0,0 +1,19 @@
+basic
+basic/a
+basic/b
+basic/c
+basic/c/d
+basic/e
+basic/e/f
+basic/g
+basic/g/h
+basic/i
+basic/j
+basic/j/foo
+basic/k
+basic/k/foo
+basic/k/foo/bar
+basic/l
+basic/l/foo
+basic/l/foo/bar
+basic/l/foo/bar/baz
diff --git a/tests/bfs/O3.sh b/tests/bfs/O3.sh
new file mode 100644
index 0000000..5bdf2bc
--- /dev/null
+++ b/tests/bfs/O3.sh
@@ -0,0 +1 @@
+bfs_diff -O3 basic -not \( -type f -not -type f \)
diff --git a/tests/bfs/Ofast.out b/tests/bfs/Ofast.out
new file mode 100644
index 0000000..a7ccfe4
--- /dev/null
+++ b/tests/bfs/Ofast.out
@@ -0,0 +1,19 @@
+basic
+basic/a
+basic/b
+basic/c
+basic/c/d
+basic/e
+basic/e/f
+basic/g
+basic/g/h
+basic/i
+basic/j
+basic/j/foo
+basic/k
+basic/k/foo
+basic/k/foo/bar
+basic/l
+basic/l/foo
+basic/l/foo/bar
+basic/l/foo/bar/baz
diff --git a/tests/bfs/Ofast.sh b/tests/bfs/Ofast.sh
new file mode 100644
index 0000000..87c1d8d
--- /dev/null
+++ b/tests/bfs/Ofast.sh
@@ -0,0 +1 @@
+bfs_diff -Ofast basic -not \( -xtype f -not -xtype f \)
diff --git a/tests/bfs/S_bfs.out b/tests/bfs/S_bfs.out
new file mode 100644
index 0000000..bb3cd8d
--- /dev/null
+++ b/tests/bfs/S_bfs.out
@@ -0,0 +1,19 @@
+basic
+basic/a
+basic/b
+basic/c
+basic/e
+basic/g
+basic/i
+basic/j
+basic/k
+basic/l
+basic/c/d
+basic/e/f
+basic/g/h
+basic/j/foo
+basic/k/foo
+basic/l/foo
+basic/k/foo/bar
+basic/l/foo/bar
+basic/l/foo/bar/baz
diff --git a/tests/bfs/S_bfs.sh b/tests/bfs/S_bfs.sh
new file mode 100644
index 0000000..76976de
--- /dev/null
+++ b/tests/bfs/S_bfs.sh
@@ -0,0 +1,2 @@
+invoke_bfs -S bfs -s basic >"$OUT"
+diff_output
diff --git a/tests/bfs/S_dfs.out b/tests/bfs/S_dfs.out
new file mode 100644
index 0000000..a7ccfe4
--- /dev/null
+++ b/tests/bfs/S_dfs.out
@@ -0,0 +1,19 @@
+basic
+basic/a
+basic/b
+basic/c
+basic/c/d
+basic/e
+basic/e/f
+basic/g
+basic/g/h
+basic/i
+basic/j
+basic/j/foo
+basic/k
+basic/k/foo
+basic/k/foo/bar
+basic/l
+basic/l/foo
+basic/l/foo/bar
+basic/l/foo/bar/baz
diff --git a/tests/bfs/S_dfs.sh b/tests/bfs/S_dfs.sh
new file mode 100644
index 0000000..7dd7a46
--- /dev/null
+++ b/tests/bfs/S_dfs.sh
@@ -0,0 +1,2 @@
+invoke_bfs -S dfs -s basic >"$OUT"
+diff_output
diff --git a/tests/bfs/S_ids.out b/tests/bfs/S_ids.out
new file mode 100644
index 0000000..bb3cd8d
--- /dev/null
+++ b/tests/bfs/S_ids.out
@@ -0,0 +1,19 @@
+basic
+basic/a
+basic/b
+basic/c
+basic/e
+basic/g
+basic/i
+basic/j
+basic/k
+basic/l
+basic/c/d
+basic/e/f
+basic/g/h
+basic/j/foo
+basic/k/foo
+basic/l/foo
+basic/k/foo/bar
+basic/l/foo/bar
+basic/l/foo/bar/baz
diff --git a/tests/bfs/S_ids.sh b/tests/bfs/S_ids.sh
new file mode 100644
index 0000000..3995cf0
--- /dev/null
+++ b/tests/bfs/S_ids.sh
@@ -0,0 +1,2 @@
+invoke_bfs -S ids -s basic >"$OUT"
+diff_output
diff --git a/tests/bfs/and_incomplete.sh b/tests/bfs/and_incomplete.sh
new file mode 100644
index 0000000..f7bc2c3
--- /dev/null
+++ b/tests/bfs/and_incomplete.sh
@@ -0,0 +1 @@
+fail invoke_bfs -print -a
diff --git a/tests/bfs/capable.out b/tests/bfs/capable.out
new file mode 100644
index 0000000..78b5bd9
--- /dev/null
+++ b/tests/bfs/capable.out
@@ -0,0 +1 @@
+scratch/capable
diff --git a/tests/bfs/capable.sh b/tests/bfs/capable.sh
new file mode 100644
index 0000000..964f37f
--- /dev/null
+++ b/tests/bfs/capable.sh
@@ -0,0 +1,12 @@
+skip_unless test "$SUDO"
+skip_unless test "$UNAME" = "Linux"
+
+rm -rf scratch/*
+
+skip_unless invoke_bfs scratch -quit -capable
+
+$TOUCH scratch/{normal,capable}
+sudo setcap all+ep scratch/capable
+ln -s capable scratch/link
+
+bfs_diff scratch -capable
diff --git a/tests/bfs/color.out b/tests/bfs/color.out
new file mode 100644
index 0000000..77fc8a8
--- /dev/null
+++ b/tests/bfs/color.out
@@ -0,0 +1,20 @@
+rainbow
+rainbow/exec.sh
+rainbow/socket
+rainbow/broken
+rainbow/chardev_link
+rainbow/link.txt
+rainbow/sticky_ow
+rainbow/sgid
+rainbow/pipe
+rainbow/ow
+rainbow/sugid
+rainbow/suid
+rainbow/sticky
+rainbow/file.dat
+rainbow/file.txt
+rainbow/mh1
+rainbow/mh2
+rainbow/star.gz
+rainbow/star.tar
+rainbow/star.tar.gz
diff --git a/tests/bfs/color.sh b/tests/bfs/color.sh
new file mode 100644
index 0000000..23f05a3
--- /dev/null
+++ b/tests/bfs/color.sh
@@ -0,0 +1 @@
+bfs_diff rainbow -color
diff --git a/tests/bfs/color_L.out b/tests/bfs/color_L.out
new file mode 100644
index 0000000..b60dd4a
--- /dev/null
+++ b/tests/bfs/color_L.out
@@ -0,0 +1,20 @@
+rainbow
+rainbow/exec.sh
+rainbow/chardev_link
+rainbow/socket
+rainbow/broken
+rainbow/sticky_ow
+rainbow/sgid
+rainbow/pipe
+rainbow/ow
+rainbow/sugid
+rainbow/suid
+rainbow/sticky
+rainbow/file.dat
+rainbow/file.txt
+rainbow/link.txt
+rainbow/mh1
+rainbow/mh2
+rainbow/star.gz
+rainbow/star.tar
+rainbow/star.tar.gz
diff --git a/tests/bfs/color_L.sh b/tests/bfs/color_L.sh
new file mode 100644
index 0000000..823db62
--- /dev/null
+++ b/tests/bfs/color_L.sh
@@ -0,0 +1 @@
+bfs_diff -L rainbow -color
diff --git a/tests/bfs/color_L_ln_target.out b/tests/bfs/color_L_ln_target.out
new file mode 100644
index 0000000..cd4ec5e
--- /dev/null
+++ b/tests/bfs/color_L_ln_target.out
@@ -0,0 +1,20 @@
+rainbow
+rainbow/broken
+rainbow/exec.sh
+rainbow/chardev_link
+rainbow/socket
+rainbow/sticky_ow
+rainbow/sgid
+rainbow/pipe
+rainbow/ow
+rainbow/sugid
+rainbow/suid
+rainbow/sticky
+rainbow/file.dat
+rainbow/file.txt
+rainbow/link.txt
+rainbow/mh1
+rainbow/mh2
+rainbow/star.gz
+rainbow/star.tar
+rainbow/star.tar.gz
diff --git a/tests/bfs/color_L_ln_target.sh b/tests/bfs/color_L_ln_target.sh
new file mode 100644
index 0000000..cc5991d
--- /dev/null
+++ b/tests/bfs/color_L_ln_target.sh
@@ -0,0 +1 @@
+LS_COLORS="ln=target:or=01;31:mi=01;33:" bfs_diff -L rainbow -color
diff --git a/tests/bfs/color_L_no_stat.out b/tests/bfs/color_L_no_stat.out
new file mode 100644
index 0000000..c0bb1be
--- /dev/null
+++ b/tests/bfs/color_L_no_stat.out
@@ -0,0 +1,20 @@
+rainbow
+rainbow/chardev_link
+rainbow/ow
+rainbow/sticky
+rainbow/sticky_ow
+rainbow/socket
+rainbow/broken
+rainbow/file.txt
+rainbow/link.txt
+rainbow/pipe
+rainbow/exec.sh
+rainbow/file.dat
+rainbow/mh1
+rainbow/mh2
+rainbow/sgid
+rainbow/star.gz
+rainbow/star.tar
+rainbow/star.tar.gz
+rainbow/sugid
+rainbow/suid
diff --git a/tests/bfs/color_L_no_stat.sh b/tests/bfs/color_L_no_stat.sh
new file mode 100644
index 0000000..0a2caf0
--- /dev/null
+++ b/tests/bfs/color_L_no_stat.sh
@@ -0,0 +1 @@
+LS_COLORS="mh=0:ex=0:sg=0:su=0:st=0:ow=0:tw=0:*.txt=01:" bfs_diff -L rainbow -color
diff --git a/tests/bfs/color_escapes.out b/tests/bfs/color_escapes.out
new file mode 100644
index 0000000..b71e138
--- /dev/null
+++ b/tests/bfs/color_escapes.out
@@ -0,0 +1,20 @@
+:rainbow
+:rainbow/:exec.sh
+:rainbow/:socket
+:rainbow/:broken
+:rainbow/:chardev_link
+:rainbow/:link.txt
+:rainbow/:sticky_ow
+:rainbow/:sgid
+:rainbow/:pipe
+:rainbow/:ow
+:rainbow/:sugid
+:rainbow/:suid
+:rainbow/:sticky
+:rainbow/file.dat
+:rainbow/file.txt
+:rainbow/mh1
+:rainbow/mh2
+:rainbow/star.gz
+:rainbow/star.tar
+:rainbow/star.tar.gz
diff --git a/tests/bfs/color_escapes.sh b/tests/bfs/color_escapes.sh
new file mode 100644
index 0000000..eb5817f
--- /dev/null
+++ b/tests/bfs/color_escapes.sh
@@ -0,0 +1 @@
+LS_COLORS="lc=\e[:rc=\155\::ec=^[\x5B\x6d:" bfs_diff rainbow -color
diff --git a/tests/bfs/color_ext.out b/tests/bfs/color_ext.out
new file mode 100644
index 0000000..cf26e73
--- /dev/null
+++ b/tests/bfs/color_ext.out
@@ -0,0 +1,20 @@
+rainbow
+rainbow/exec.sh
+rainbow/socket
+rainbow/broken
+rainbow/chardev_link
+rainbow/link.txt
+rainbow/file.txt
+rainbow/sticky_ow
+rainbow/sgid
+rainbow/pipe
+rainbow/ow
+rainbow/sugid
+rainbow/suid
+rainbow/sticky
+rainbow/file.dat
+rainbow/mh1
+rainbow/mh2
+rainbow/star.gz
+rainbow/star.tar
+rainbow/star.tar.gz
diff --git a/tests/bfs/color_ext.sh b/tests/bfs/color_ext.sh
new file mode 100644
index 0000000..c9f6d46
--- /dev/null
+++ b/tests/bfs/color_ext.sh
@@ -0,0 +1 @@
+LS_COLORS="*.txt=01:" bfs_diff rainbow -color
diff --git a/tests/bfs/color_ext0.out b/tests/bfs/color_ext0.out
new file mode 100644
index 0000000..e764a6b
--- /dev/null
+++ b/tests/bfs/color_ext0.out
@@ -0,0 +1,20 @@
+rainbow
+rainbow/file.txt
+rainbow/exec.sh
+rainbow/socket
+rainbow/broken
+rainbow/chardev_link
+rainbow/link.txt
+rainbow/sticky_ow
+rainbow/sgid
+rainbow/pipe
+rainbow/ow
+rainbow/sugid
+rainbow/suid
+rainbow/sticky
+rainbow/file.dat
+rainbow/mh1
+rainbow/mh2
+rainbow/star.gz
+rainbow/star.tar
+rainbow/star.tar.gz
diff --git a/tests/bfs/color_ext0.sh b/tests/bfs/color_ext0.sh
new file mode 100644
index 0000000..371a9c5
--- /dev/null
+++ b/tests/bfs/color_ext0.sh
@@ -0,0 +1 @@
+LS_COLORS="*.txt=00:" bfs_diff rainbow -color
diff --git a/tests/bfs/color_ext_override.out b/tests/bfs/color_ext_override.out
new file mode 100644
index 0000000..1377b65
--- /dev/null
+++ b/tests/bfs/color_ext_override.out
@@ -0,0 +1,20 @@
+rainbow
+rainbow/exec.sh
+rainbow/star.tar
+rainbow/star.gz
+rainbow/star.tar.gz
+rainbow/socket
+rainbow/broken
+rainbow/chardev_link
+rainbow/link.txt
+rainbow/sticky_ow
+rainbow/sgid
+rainbow/pipe
+rainbow/ow
+rainbow/sugid
+rainbow/suid
+rainbow/sticky
+rainbow/file.dat
+rainbow/file.txt
+rainbow/mh1
+rainbow/mh2
diff --git a/tests/bfs/color_ext_override.sh b/tests/bfs/color_ext_override.sh
new file mode 100644
index 0000000..ac4c7fb
--- /dev/null
+++ b/tests/bfs/color_ext_override.sh
@@ -0,0 +1 @@
+LS_COLORS="*.tar.gz=01;31:*.TAR=01;32:*.gz=01;33:" bfs_diff rainbow -color
diff --git a/tests/bfs/color_ext_underride.out b/tests/bfs/color_ext_underride.out
new file mode 100644
index 0000000..787248a
--- /dev/null
+++ b/tests/bfs/color_ext_underride.out
@@ -0,0 +1,20 @@
+rainbow
+rainbow/star.tar.gz
+rainbow/exec.sh
+rainbow/star.tar
+rainbow/star.gz
+rainbow/socket
+rainbow/broken
+rainbow/chardev_link
+rainbow/link.txt
+rainbow/sticky_ow
+rainbow/sgid
+rainbow/pipe
+rainbow/ow
+rainbow/sugid
+rainbow/suid
+rainbow/sticky
+rainbow/file.dat
+rainbow/file.txt
+rainbow/mh1
+rainbow/mh2
diff --git a/tests/bfs/color_ext_underride.sh b/tests/bfs/color_ext_underride.sh
new file mode 100644
index 0000000..fb12e01
--- /dev/null
+++ b/tests/bfs/color_ext_underride.sh
@@ -0,0 +1 @@
+LS_COLORS="*.gz=01;33:*.TAR=01;32:*.tar.gz=01;31:" bfs_diff rainbow -color
diff --git a/tests/bfs/color_ln_target.out b/tests/bfs/color_ln_target.out
new file mode 100644
index 0000000..cd4ec5e
--- /dev/null
+++ b/tests/bfs/color_ln_target.out
@@ -0,0 +1,20 @@
+rainbow
+rainbow/broken
+rainbow/exec.sh
+rainbow/chardev_link
+rainbow/socket
+rainbow/sticky_ow
+rainbow/sgid
+rainbow/pipe
+rainbow/ow
+rainbow/sugid
+rainbow/suid
+rainbow/sticky
+rainbow/file.dat
+rainbow/file.txt
+rainbow/link.txt
+rainbow/mh1
+rainbow/mh2
+rainbow/star.gz
+rainbow/star.tar
+rainbow/star.tar.gz
diff --git a/tests/bfs/color_ln_target.sh b/tests/bfs/color_ln_target.sh
new file mode 100644
index 0000000..707d25e
--- /dev/null
+++ b/tests/bfs/color_ln_target.sh
@@ -0,0 +1 @@
+LS_COLORS="ln=target:or=01;31:mi=01;33:" bfs_diff rainbow -color
diff --git a/tests/bfs/color_ls.out b/tests/bfs/color_ls.out
new file mode 100644
index 0000000..b08d894
--- /dev/null
+++ b/tests/bfs/color_ls.out
@@ -0,0 +1,12 @@
+scratch/foo/bar
+scratch/foo/bar
+/__bfs__/nowhere
+/__bfs__/nowhere
+foo/bar/baz/qux
+foo/bar/baz/qux
+foo/bar/nowhere
+foo/bar/nowhere
+foo/bar/nowhere/nothing
+foo/bar/nowhere/nothing
+foo/bar/baz
+foo/bar/baz
diff --git a/tests/bfs/color_ls.sh b/tests/bfs/color_ls.sh
new file mode 100644
index 0000000..79e1db2
--- /dev/null
+++ b/tests/bfs/color_ls.sh
@@ -0,0 +1,15 @@
+rm -rf scratch/*
+touchp scratch/foo/bar/baz
+ln -s foo/bar/baz scratch/link
+ln -s foo/bar/nowhere scratch/broken
+ln -s foo/bar/nowhere/nothing scratch/nested
+ln -s foo/bar/baz/qux scratch/notdir
+ln -s scratch/foo/bar scratch/relative
+mkdir scratch/__bfs__
+ln -s /__bfs__/nowhere scratch/absolute
+
+LS_COLORS="or=01;31:" invoke_bfs scratch/{,link,broken,nested,notdir,relative,absolute} -color -type l -ls \
+ | sed 's/.* -> //' \
+ | sort >"$OUT"
+
+diff_output
diff --git a/tests/bfs/color_mh.out b/tests/bfs/color_mh.out
new file mode 100644
index 0000000..757a6a1
--- /dev/null
+++ b/tests/bfs/color_mh.out
@@ -0,0 +1,20 @@
+rainbow
+rainbow/exec.sh
+rainbow/socket
+rainbow/broken
+rainbow/chardev_link
+rainbow/link.txt
+rainbow/mh1
+rainbow/mh2
+rainbow/sticky_ow
+rainbow/sgid
+rainbow/pipe
+rainbow/ow
+rainbow/sugid
+rainbow/suid
+rainbow/sticky
+rainbow/file.dat
+rainbow/file.txt
+rainbow/star.gz
+rainbow/star.tar
+rainbow/star.tar.gz
diff --git a/tests/bfs/color_mh.sh b/tests/bfs/color_mh.sh
new file mode 100644
index 0000000..aff1845
--- /dev/null
+++ b/tests/bfs/color_mh.sh
@@ -0,0 +1 @@
+LS_COLORS="mh=01:" bfs_diff rainbow -color
diff --git a/tests/bfs/color_mh0.out b/tests/bfs/color_mh0.out
new file mode 100644
index 0000000..77fc8a8
--- /dev/null
+++ b/tests/bfs/color_mh0.out
@@ -0,0 +1,20 @@
+rainbow
+rainbow/exec.sh
+rainbow/socket
+rainbow/broken
+rainbow/chardev_link
+rainbow/link.txt
+rainbow/sticky_ow
+rainbow/sgid
+rainbow/pipe
+rainbow/ow
+rainbow/sugid
+rainbow/suid
+rainbow/sticky
+rainbow/file.dat
+rainbow/file.txt
+rainbow/mh1
+rainbow/mh2
+rainbow/star.gz
+rainbow/star.tar
+rainbow/star.tar.gz
diff --git a/tests/bfs/color_mh0.sh b/tests/bfs/color_mh0.sh
new file mode 100644
index 0000000..7de880d
--- /dev/null
+++ b/tests/bfs/color_mh0.sh
@@ -0,0 +1 @@
+LS_COLORS="mh=00:" bfs_diff rainbow -color
diff --git a/tests/bfs/color_mi.out b/tests/bfs/color_mi.out
new file mode 100644
index 0000000..77fc8a8
--- /dev/null
+++ b/tests/bfs/color_mi.out
@@ -0,0 +1,20 @@
+rainbow
+rainbow/exec.sh
+rainbow/socket
+rainbow/broken
+rainbow/chardev_link
+rainbow/link.txt
+rainbow/sticky_ow
+rainbow/sgid
+rainbow/pipe
+rainbow/ow
+rainbow/sugid
+rainbow/suid
+rainbow/sticky
+rainbow/file.dat
+rainbow/file.txt
+rainbow/mh1
+rainbow/mh2
+rainbow/star.gz
+rainbow/star.tar
+rainbow/star.tar.gz
diff --git a/tests/bfs/color_mi.sh b/tests/bfs/color_mi.sh
new file mode 100644
index 0000000..06dd8c6
--- /dev/null
+++ b/tests/bfs/color_mi.sh
@@ -0,0 +1 @@
+LS_COLORS="mi=01:" bfs_diff rainbow -color
diff --git a/tests/bfs/color_missing_colon.out b/tests/bfs/color_missing_colon.out
new file mode 100644
index 0000000..cf26e73
--- /dev/null
+++ b/tests/bfs/color_missing_colon.out
@@ -0,0 +1,20 @@
+rainbow
+rainbow/exec.sh
+rainbow/socket
+rainbow/broken
+rainbow/chardev_link
+rainbow/link.txt
+rainbow/file.txt
+rainbow/sticky_ow
+rainbow/sgid
+rainbow/pipe
+rainbow/ow
+rainbow/sugid
+rainbow/suid
+rainbow/sticky
+rainbow/file.dat
+rainbow/mh1
+rainbow/mh2
+rainbow/star.gz
+rainbow/star.tar
+rainbow/star.tar.gz
diff --git a/tests/bfs/color_missing_colon.sh b/tests/bfs/color_missing_colon.sh
new file mode 100644
index 0000000..afa3763
--- /dev/null
+++ b/tests/bfs/color_missing_colon.sh
@@ -0,0 +1 @@
+LS_COLORS="*.txt=01" bfs_diff rainbow -color
diff --git a/tests/bfs/color_no_stat.out b/tests/bfs/color_no_stat.out
new file mode 100644
index 0000000..1fc5324
--- /dev/null
+++ b/tests/bfs/color_no_stat.out
@@ -0,0 +1,20 @@
+rainbow
+rainbow/ow
+rainbow/sticky
+rainbow/sticky_ow
+rainbow/socket
+rainbow/broken
+rainbow/chardev_link
+rainbow/link.txt
+rainbow/file.txt
+rainbow/pipe
+rainbow/exec.sh
+rainbow/file.dat
+rainbow/mh1
+rainbow/mh2
+rainbow/sgid
+rainbow/star.gz
+rainbow/star.tar
+rainbow/star.tar.gz
+rainbow/sugid
+rainbow/suid
diff --git a/tests/bfs/color_no_stat.sh b/tests/bfs/color_no_stat.sh
new file mode 100644
index 0000000..0bc2520
--- /dev/null
+++ b/tests/bfs/color_no_stat.sh
@@ -0,0 +1 @@
+LS_COLORS="mh=0:ex=0:sg=0:su=0:st=0:ow=0:tw=0:*.txt=01:" bfs_diff rainbow -color
diff --git a/tests/bfs/color_nul.out b/tests/bfs/color_nul.out
new file mode 100644
index 0000000..c328f82
--- /dev/null
+++ b/tests/bfs/color_nul.out
Binary files differ
diff --git a/tests/bfs/color_nul.sh b/tests/bfs/color_nul.sh
new file mode 100644
index 0000000..4979569
--- /dev/null
+++ b/tests/bfs/color_nul.sh
@@ -0,0 +1,2 @@
+LS_COLORS="ec=\33[m\0:" invoke_bfs rainbow -color -maxdepth 0 >"$OUT"
+diff_output
diff --git a/tests/bfs/color_or.out b/tests/bfs/color_or.out
new file mode 100644
index 0000000..9e1fe5c
--- /dev/null
+++ b/tests/bfs/color_or.out
@@ -0,0 +1,20 @@
+rainbow
+rainbow/exec.sh
+rainbow/socket
+rainbow/chardev_link
+rainbow/link.txt
+rainbow/broken
+rainbow/sticky_ow
+rainbow/sgid
+rainbow/pipe
+rainbow/ow
+rainbow/sugid
+rainbow/suid
+rainbow/sticky
+rainbow/file.dat
+rainbow/file.txt
+rainbow/mh1
+rainbow/mh2
+rainbow/star.gz
+rainbow/star.tar
+rainbow/star.tar.gz
diff --git a/tests/bfs/color_or.sh b/tests/bfs/color_or.sh
new file mode 100644
index 0000000..bccb400
--- /dev/null
+++ b/tests/bfs/color_or.sh
@@ -0,0 +1 @@
+LS_COLORS="or=01:" bfs_diff rainbow -color
diff --git a/tests/bfs/color_or0_mi.out b/tests/bfs/color_or0_mi.out
new file mode 100644
index 0000000..77fc8a8
--- /dev/null
+++ b/tests/bfs/color_or0_mi.out
@@ -0,0 +1,20 @@
+rainbow
+rainbow/exec.sh
+rainbow/socket
+rainbow/broken
+rainbow/chardev_link
+rainbow/link.txt
+rainbow/sticky_ow
+rainbow/sgid
+rainbow/pipe
+rainbow/ow
+rainbow/sugid
+rainbow/suid
+rainbow/sticky
+rainbow/file.dat
+rainbow/file.txt
+rainbow/mh1
+rainbow/mh2
+rainbow/star.gz
+rainbow/star.tar
+rainbow/star.tar.gz
diff --git a/tests/bfs/color_or0_mi.sh b/tests/bfs/color_or0_mi.sh
new file mode 100644
index 0000000..a362cf1
--- /dev/null
+++ b/tests/bfs/color_or0_mi.sh
@@ -0,0 +1 @@
+LS_COLORS="or=00:mi=01;33:" bfs_diff rainbow -color
diff --git a/tests/bfs/color_or0_mi0.out b/tests/bfs/color_or0_mi0.out
new file mode 100644
index 0000000..77fc8a8
--- /dev/null
+++ b/tests/bfs/color_or0_mi0.out
@@ -0,0 +1,20 @@
+rainbow
+rainbow/exec.sh
+rainbow/socket
+rainbow/broken
+rainbow/chardev_link
+rainbow/link.txt
+rainbow/sticky_ow
+rainbow/sgid
+rainbow/pipe
+rainbow/ow
+rainbow/sugid
+rainbow/suid
+rainbow/sticky
+rainbow/file.dat
+rainbow/file.txt
+rainbow/mh1
+rainbow/mh2
+rainbow/star.gz
+rainbow/star.tar
+rainbow/star.tar.gz
diff --git a/tests/bfs/color_or0_mi0.sh b/tests/bfs/color_or0_mi0.sh
new file mode 100644
index 0000000..d7c00f6
--- /dev/null
+++ b/tests/bfs/color_or0_mi0.sh
@@ -0,0 +1 @@
+LS_COLORS="or=00:mi=00:" bfs_diff rainbow -color
diff --git a/tests/bfs/color_or_mi.out b/tests/bfs/color_or_mi.out
new file mode 100644
index 0000000..5667f56
--- /dev/null
+++ b/tests/bfs/color_or_mi.out
@@ -0,0 +1,20 @@
+rainbow
+rainbow/broken
+rainbow/exec.sh
+rainbow/socket
+rainbow/chardev_link
+rainbow/link.txt
+rainbow/sticky_ow
+rainbow/sgid
+rainbow/pipe
+rainbow/ow
+rainbow/sugid
+rainbow/suid
+rainbow/sticky
+rainbow/file.dat
+rainbow/file.txt
+rainbow/mh1
+rainbow/mh2
+rainbow/star.gz
+rainbow/star.tar
+rainbow/star.tar.gz
diff --git a/tests/bfs/color_or_mi.sh b/tests/bfs/color_or_mi.sh
new file mode 100644
index 0000000..467ce6b
--- /dev/null
+++ b/tests/bfs/color_or_mi.sh
@@ -0,0 +1 @@
+LS_COLORS="or=01;31:mi=01;33:" bfs_diff rainbow -color
diff --git a/tests/bfs/color_or_mi0.out b/tests/bfs/color_or_mi0.out
new file mode 100644
index 0000000..5667f56
--- /dev/null
+++ b/tests/bfs/color_or_mi0.out
@@ -0,0 +1,20 @@
+rainbow
+rainbow/broken
+rainbow/exec.sh
+rainbow/socket
+rainbow/chardev_link
+rainbow/link.txt
+rainbow/sticky_ow
+rainbow/sgid
+rainbow/pipe
+rainbow/ow
+rainbow/sugid
+rainbow/suid
+rainbow/sticky
+rainbow/file.dat
+rainbow/file.txt
+rainbow/mh1
+rainbow/mh2
+rainbow/star.gz
+rainbow/star.tar
+rainbow/star.tar.gz
diff --git a/tests/bfs/color_or_mi0.sh b/tests/bfs/color_or_mi0.sh
new file mode 100644
index 0000000..a9c36bf
--- /dev/null
+++ b/tests/bfs/color_or_mi0.sh
@@ -0,0 +1 @@
+LS_COLORS="or=01;31:mi=00:" bfs_diff rainbow -color
diff --git a/tests/bfs/color_rs_lc_rc_ec.out b/tests/bfs/color_rs_lc_rc_ec.out
new file mode 100644
index 0000000..d39bbe7
--- /dev/null
+++ b/tests/bfs/color_rs_lc_rc_ec.out
@@ -0,0 +1,20 @@
+LC01;34RCrainbow/ECLC01;32RCexec.shEC
+LC01;34RCrainbow/ECLC01;35RCsocketEC
+LC01;34RCrainbow/ECLC01;36RCbrokenEC
+LC01;34RCrainbow/ECLC01;36RCchardev_linkEC
+LC01;34RCrainbow/ECLC01;36RClink.txtEC
+LC01;34RCrainbow/ECLC30;42RCsticky_owEC
+LC01;34RCrainbow/ECLC30;43RCsgidEC
+LC01;34RCrainbow/ECLC33RCpipeEC
+LC01;34RCrainbow/ECLC34;42RCowEC
+LC01;34RCrainbow/ECLC37;41RCsugidEC
+LC01;34RCrainbow/ECLC37;41RCsuidEC
+LC01;34RCrainbow/ECLC37;44RCstickyEC
+LC01;34RCrainbow/ECfile.dat
+LC01;34RCrainbow/ECfile.txt
+LC01;34RCrainbow/ECmh1
+LC01;34RCrainbow/ECmh2
+LC01;34RCrainbow/ECstar.gz
+LC01;34RCrainbow/ECstar.tar
+LC01;34RCrainbow/ECstar.tar.gz
+LC01;34RCrainbowEC
diff --git a/tests/bfs/color_rs_lc_rc_ec.sh b/tests/bfs/color_rs_lc_rc_ec.sh
new file mode 100644
index 0000000..467b2da
--- /dev/null
+++ b/tests/bfs/color_rs_lc_rc_ec.sh
@@ -0,0 +1 @@
+LS_COLORS="rs=RS:lc=LC:rc=RC:ec=EC:" bfs_diff rainbow -color
diff --git a/tests/bfs/color_st0_tw0_ow.out b/tests/bfs/color_st0_tw0_ow.out
new file mode 100644
index 0000000..9a47ef2
--- /dev/null
+++ b/tests/bfs/color_st0_tw0_ow.out
@@ -0,0 +1,20 @@
+rainbow
+rainbow/exec.sh
+rainbow/sticky
+rainbow/socket
+rainbow/broken
+rainbow/chardev_link
+rainbow/link.txt
+rainbow/sgid
+rainbow/pipe
+rainbow/ow
+rainbow/sticky_ow
+rainbow/sugid
+rainbow/suid
+rainbow/file.dat
+rainbow/file.txt
+rainbow/mh1
+rainbow/mh2
+rainbow/star.gz
+rainbow/star.tar
+rainbow/star.tar.gz
diff --git a/tests/bfs/color_st0_tw0_ow.sh b/tests/bfs/color_st0_tw0_ow.sh
new file mode 100644
index 0000000..8e2b8e3
--- /dev/null
+++ b/tests/bfs/color_st0_tw0_ow.sh
@@ -0,0 +1 @@
+LS_COLORS="st=00:tw=00:ow=34;42:" bfs_diff rainbow -color
diff --git a/tests/bfs/color_st0_tw0_ow0.out b/tests/bfs/color_st0_tw0_ow0.out
new file mode 100644
index 0000000..2b86fe4
--- /dev/null
+++ b/tests/bfs/color_st0_tw0_ow0.out
@@ -0,0 +1,20 @@
+rainbow
+rainbow/exec.sh
+rainbow/ow
+rainbow/sticky
+rainbow/sticky_ow
+rainbow/socket
+rainbow/broken
+rainbow/chardev_link
+rainbow/link.txt
+rainbow/sgid
+rainbow/pipe
+rainbow/sugid
+rainbow/suid
+rainbow/file.dat
+rainbow/file.txt
+rainbow/mh1
+rainbow/mh2
+rainbow/star.gz
+rainbow/star.tar
+rainbow/star.tar.gz
diff --git a/tests/bfs/color_st0_tw0_ow0.sh b/tests/bfs/color_st0_tw0_ow0.sh
new file mode 100644
index 0000000..c5d5fe7
--- /dev/null
+++ b/tests/bfs/color_st0_tw0_ow0.sh
@@ -0,0 +1 @@
+LS_COLORS="st=00:tw=00:ow=00:" bfs_diff rainbow -color
diff --git a/tests/bfs/color_st0_tw_ow.out b/tests/bfs/color_st0_tw_ow.out
new file mode 100644
index 0000000..42549a1
--- /dev/null
+++ b/tests/bfs/color_st0_tw_ow.out
@@ -0,0 +1,20 @@
+rainbow
+rainbow/exec.sh
+rainbow/sticky
+rainbow/socket
+rainbow/broken
+rainbow/chardev_link
+rainbow/link.txt
+rainbow/sgid
+rainbow/pipe
+rainbow/ow
+rainbow/sugid
+rainbow/suid
+rainbow/sticky_ow
+rainbow/file.dat
+rainbow/file.txt
+rainbow/mh1
+rainbow/mh2
+rainbow/star.gz
+rainbow/star.tar
+rainbow/star.tar.gz
diff --git a/tests/bfs/color_st0_tw_ow.sh b/tests/bfs/color_st0_tw_ow.sh
new file mode 100644
index 0000000..8fd9605
--- /dev/null
+++ b/tests/bfs/color_st0_tw_ow.sh
@@ -0,0 +1 @@
+LS_COLORS="st=00:tw=40;32:ow=34;42:" bfs_diff rainbow -color
diff --git a/tests/bfs/color_st0_tw_ow0.out b/tests/bfs/color_st0_tw_ow0.out
new file mode 100644
index 0000000..535b8ae
--- /dev/null
+++ b/tests/bfs/color_st0_tw_ow0.out
@@ -0,0 +1,20 @@
+rainbow
+rainbow/exec.sh
+rainbow/ow
+rainbow/sticky
+rainbow/socket
+rainbow/broken
+rainbow/chardev_link
+rainbow/link.txt
+rainbow/sgid
+rainbow/pipe
+rainbow/sugid
+rainbow/suid
+rainbow/sticky_ow
+rainbow/file.dat
+rainbow/file.txt
+rainbow/mh1
+rainbow/mh2
+rainbow/star.gz
+rainbow/star.tar
+rainbow/star.tar.gz
diff --git a/tests/bfs/color_st0_tw_ow0.sh b/tests/bfs/color_st0_tw_ow0.sh
new file mode 100644
index 0000000..68c63dc
--- /dev/null
+++ b/tests/bfs/color_st0_tw_ow0.sh
@@ -0,0 +1 @@
+LS_COLORS="st=00:tw=40;32:ow=00:" bfs_diff rainbow -color
diff --git a/tests/bfs/color_st_tw0_ow.out b/tests/bfs/color_st_tw0_ow.out
new file mode 100644
index 0000000..c9a86f4
--- /dev/null
+++ b/tests/bfs/color_st_tw0_ow.out
@@ -0,0 +1,20 @@
+rainbow
+rainbow/exec.sh
+rainbow/socket
+rainbow/broken
+rainbow/chardev_link
+rainbow/link.txt
+rainbow/sgid
+rainbow/pipe
+rainbow/ow
+rainbow/sticky_ow
+rainbow/sugid
+rainbow/suid
+rainbow/sticky
+rainbow/file.dat
+rainbow/file.txt
+rainbow/mh1
+rainbow/mh2
+rainbow/star.gz
+rainbow/star.tar
+rainbow/star.tar.gz
diff --git a/tests/bfs/color_st_tw0_ow.sh b/tests/bfs/color_st_tw0_ow.sh
new file mode 100644
index 0000000..be16251
--- /dev/null
+++ b/tests/bfs/color_st_tw0_ow.sh
@@ -0,0 +1 @@
+LS_COLORS="st=37;44:tw=00:ow=34;42:" bfs_diff rainbow -color
diff --git a/tests/bfs/color_st_tw0_ow0.out b/tests/bfs/color_st_tw0_ow0.out
new file mode 100644
index 0000000..2d94f3a
--- /dev/null
+++ b/tests/bfs/color_st_tw0_ow0.out
@@ -0,0 +1,20 @@
+rainbow
+rainbow/exec.sh
+rainbow/ow
+rainbow/socket
+rainbow/broken
+rainbow/chardev_link
+rainbow/link.txt
+rainbow/sgid
+rainbow/pipe
+rainbow/sugid
+rainbow/suid
+rainbow/sticky
+rainbow/sticky_ow
+rainbow/file.dat
+rainbow/file.txt
+rainbow/mh1
+rainbow/mh2
+rainbow/star.gz
+rainbow/star.tar
+rainbow/star.tar.gz
diff --git a/tests/bfs/color_st_tw0_ow0.sh b/tests/bfs/color_st_tw0_ow0.sh
new file mode 100644
index 0000000..f869e7c
--- /dev/null
+++ b/tests/bfs/color_st_tw0_ow0.sh
@@ -0,0 +1 @@
+LS_COLORS="st=37;44:tw=00:ow=00:" bfs_diff rainbow -color
diff --git a/tests/bfs/color_st_tw_ow0.out b/tests/bfs/color_st_tw_ow0.out
new file mode 100644
index 0000000..317ef90
--- /dev/null
+++ b/tests/bfs/color_st_tw_ow0.out
@@ -0,0 +1,20 @@
+rainbow
+rainbow/exec.sh
+rainbow/ow
+rainbow/socket
+rainbow/broken
+rainbow/chardev_link
+rainbow/link.txt
+rainbow/sgid
+rainbow/pipe
+rainbow/sugid
+rainbow/suid
+rainbow/sticky
+rainbow/sticky_ow
+rainbow/file.dat
+rainbow/file.txt
+rainbow/mh1
+rainbow/mh2
+rainbow/star.gz
+rainbow/star.tar
+rainbow/star.tar.gz
diff --git a/tests/bfs/color_st_tw_ow0.sh b/tests/bfs/color_st_tw_ow0.sh
new file mode 100644
index 0000000..99a17a6
--- /dev/null
+++ b/tests/bfs/color_st_tw_ow0.sh
@@ -0,0 +1 @@
+LS_COLORS="st=37;44:tw=40;32:ow=00:" bfs_diff rainbow -color
diff --git a/tests/bfs/color_star.out b/tests/bfs/color_star.out
new file mode 100644
index 0000000..77fc8a8
--- /dev/null
+++ b/tests/bfs/color_star.out
@@ -0,0 +1,20 @@
+rainbow
+rainbow/exec.sh
+rainbow/socket
+rainbow/broken
+rainbow/chardev_link
+rainbow/link.txt
+rainbow/sticky_ow
+rainbow/sgid
+rainbow/pipe
+rainbow/ow
+rainbow/sugid
+rainbow/suid
+rainbow/sticky
+rainbow/file.dat
+rainbow/file.txt
+rainbow/mh1
+rainbow/mh2
+rainbow/star.gz
+rainbow/star.tar
+rainbow/star.tar.gz
diff --git a/tests/bfs/color_star.sh b/tests/bfs/color_star.sh
new file mode 100644
index 0000000..3ada4fd
--- /dev/null
+++ b/tests/bfs/color_star.sh
@@ -0,0 +1,2 @@
+# Regression test: don't segfault on LS_COLORS="*"
+LS_COLORS="*" bfs_diff rainbow -color
diff --git a/tests/bfs/color_su0_sg.out b/tests/bfs/color_su0_sg.out
new file mode 100644
index 0000000..8b8c8b8
--- /dev/null
+++ b/tests/bfs/color_su0_sg.out
@@ -0,0 +1,20 @@
+rainbow
+rainbow/exec.sh
+rainbow/socket
+rainbow/broken
+rainbow/chardev_link
+rainbow/link.txt
+rainbow/sticky_ow
+rainbow/sgid
+rainbow/sugid
+rainbow/pipe
+rainbow/ow
+rainbow/sticky
+rainbow/file.dat
+rainbow/file.txt
+rainbow/mh1
+rainbow/mh2
+rainbow/star.gz
+rainbow/star.tar
+rainbow/star.tar.gz
+rainbow/suid
diff --git a/tests/bfs/color_su0_sg.sh b/tests/bfs/color_su0_sg.sh
new file mode 100644
index 0000000..f5f57b4
--- /dev/null
+++ b/tests/bfs/color_su0_sg.sh
@@ -0,0 +1 @@
+LS_COLORS="su=00:sg=30;43:" bfs_diff rainbow -color
diff --git a/tests/bfs/color_su0_sg0.out b/tests/bfs/color_su0_sg0.out
new file mode 100644
index 0000000..0cd5f9a
--- /dev/null
+++ b/tests/bfs/color_su0_sg0.out
@@ -0,0 +1,20 @@
+rainbow
+rainbow/exec.sh
+rainbow/socket
+rainbow/broken
+rainbow/chardev_link
+rainbow/link.txt
+rainbow/sticky_ow
+rainbow/pipe
+rainbow/ow
+rainbow/sticky
+rainbow/file.dat
+rainbow/file.txt
+rainbow/mh1
+rainbow/mh2
+rainbow/sgid
+rainbow/star.gz
+rainbow/star.tar
+rainbow/star.tar.gz
+rainbow/sugid
+rainbow/suid
diff --git a/tests/bfs/color_su0_sg0.sh b/tests/bfs/color_su0_sg0.sh
new file mode 100644
index 0000000..0198383
--- /dev/null
+++ b/tests/bfs/color_su0_sg0.sh
@@ -0,0 +1 @@
+LS_COLORS="su=00:sg=00:" bfs_diff rainbow -color
diff --git a/tests/bfs/color_su_sg0.out b/tests/bfs/color_su_sg0.out
new file mode 100644
index 0000000..a9e8c5d
--- /dev/null
+++ b/tests/bfs/color_su_sg0.out
@@ -0,0 +1,20 @@
+rainbow
+rainbow/exec.sh
+rainbow/socket
+rainbow/broken
+rainbow/chardev_link
+rainbow/link.txt
+rainbow/sticky_ow
+rainbow/pipe
+rainbow/ow
+rainbow/sugid
+rainbow/suid
+rainbow/sticky
+rainbow/file.dat
+rainbow/file.txt
+rainbow/mh1
+rainbow/mh2
+rainbow/sgid
+rainbow/star.gz
+rainbow/star.tar
+rainbow/star.tar.gz
diff --git a/tests/bfs/color_su_sg0.sh b/tests/bfs/color_su_sg0.sh
new file mode 100644
index 0000000..8dc6984
--- /dev/null
+++ b/tests/bfs/color_su_sg0.sh
@@ -0,0 +1 @@
+LS_COLORS="su=37;41:sg=00:" bfs_diff rainbow -color
diff --git a/tests/bfs/comma_incomplete.sh b/tests/bfs/comma_incomplete.sh
new file mode 100644
index 0000000..07cf505
--- /dev/null
+++ b/tests/bfs/comma_incomplete.sh
@@ -0,0 +1 @@
+fail invoke_bfs -print ,
diff --git a/tests/bfs/data_flow_hidden.out b/tests/bfs/data_flow_hidden.out
new file mode 100644
index 0000000..a7ccfe4
--- /dev/null
+++ b/tests/bfs/data_flow_hidden.out
@@ -0,0 +1,19 @@
+basic
+basic/a
+basic/b
+basic/c
+basic/c/d
+basic/e
+basic/e/f
+basic/g
+basic/g/h
+basic/i
+basic/j
+basic/j/foo
+basic/k
+basic/k/foo
+basic/k/foo/bar
+basic/l
+basic/l/foo
+basic/l/foo/bar
+basic/l/foo/bar/baz
diff --git a/tests/bfs/data_flow_hidden.sh b/tests/bfs/data_flow_hidden.sh
new file mode 100644
index 0000000..6afaab2
--- /dev/null
+++ b/tests/bfs/data_flow_hidden.sh
@@ -0,0 +1 @@
+bfs_diff basic \( -hidden -not -hidden \) -o \( -hidden -o -not -hidden \)
diff --git a/tests/bfs/deep_strict.out b/tests/bfs/deep_strict.out
new file mode 100644
index 0000000..c385fce
--- /dev/null
+++ b/tests/bfs/deep_strict.out
@@ -0,0 +1,16 @@
+deep/0/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE (4358)
+deep/1/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE (4358)
+deep/2/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE (4358)
+deep/3/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE (4358)
+deep/4/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE (4358)
+deep/5/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE (4358)
+deep/6/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE (4358)
+deep/7/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE (4358)
+deep/8/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE (4358)
+deep/9/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE (4358)
+deep/A/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE (4358)
+deep/B/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE (4358)
+deep/C/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE (4358)
+deep/D/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE (4358)
+deep/E/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE (4358)
+deep/F/.../0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE (4358)
diff --git a/tests/bfs/deep_strict.sh b/tests/bfs/deep_strict.sh
new file mode 100644
index 0000000..e057310
--- /dev/null
+++ b/tests/bfs/deep_strict.sh
@@ -0,0 +1,5 @@
+closefrom 4
+
+# Not even enough fds to keep the root open
+ulimit -n 7
+bfs_diff deep -type f -exec bash -c 'echo "${1:0:6}/.../${1##*/} (${#1})"' bash {} \;
diff --git a/tests/bfs/exclude_depth.out b/tests/bfs/exclude_depth.out
new file mode 100644
index 0000000..59e3c42
--- /dev/null
+++ b/tests/bfs/exclude_depth.out
@@ -0,0 +1,13 @@
+basic
+basic/a
+basic/b
+basic/c
+basic/c/d
+basic/e
+basic/e/f
+basic/g
+basic/g/h
+basic/i
+basic/j
+basic/k
+basic/l
diff --git a/tests/bfs/exclude_depth.sh b/tests/bfs/exclude_depth.sh
new file mode 100644
index 0000000..437b4dd
--- /dev/null
+++ b/tests/bfs/exclude_depth.sh
@@ -0,0 +1 @@
+bfs_diff basic -depth -exclude -name foo
diff --git a/tests/bfs/exclude_exclude.sh b/tests/bfs/exclude_exclude.sh
new file mode 100644
index 0000000..c687623
--- /dev/null
+++ b/tests/bfs/exclude_exclude.sh
@@ -0,0 +1 @@
+fail invoke_bfs basic -exclude -exclude -name foo
diff --git a/tests/bfs/exclude_mindepth.out b/tests/bfs/exclude_mindepth.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/bfs/exclude_mindepth.out
diff --git a/tests/bfs/exclude_mindepth.sh b/tests/bfs/exclude_mindepth.sh
new file mode 100644
index 0000000..c8f70f9
--- /dev/null
+++ b/tests/bfs/exclude_mindepth.sh
@@ -0,0 +1 @@
+bfs_diff basic -mindepth 3 -exclude -name foo
diff --git a/tests/bfs/exclude_name.out b/tests/bfs/exclude_name.out
new file mode 100644
index 0000000..59e3c42
--- /dev/null
+++ b/tests/bfs/exclude_name.out
@@ -0,0 +1,13 @@
+basic
+basic/a
+basic/b
+basic/c
+basic/c/d
+basic/e
+basic/e/f
+basic/g
+basic/g/h
+basic/i
+basic/j
+basic/k
+basic/l
diff --git a/tests/bfs/exclude_name.sh b/tests/bfs/exclude_name.sh
new file mode 100644
index 0000000..7cf9f33
--- /dev/null
+++ b/tests/bfs/exclude_name.sh
@@ -0,0 +1 @@
+bfs_diff basic -exclude -name foo
diff --git a/tests/bfs/exclude_print.sh b/tests/bfs/exclude_print.sh
new file mode 100644
index 0000000..52ff0fd
--- /dev/null
+++ b/tests/bfs/exclude_print.sh
@@ -0,0 +1 @@
+fail invoke_bfs basic -exclude -print
diff --git a/tests/bfs/exec_flush_fprint.out b/tests/bfs/exec_flush_fprint.out
new file mode 100644
index 0000000..511198f
--- /dev/null
+++ b/tests/bfs/exec_flush_fprint.out
@@ -0,0 +1 @@
+basic/a
diff --git a/tests/bfs/exec_flush_fprint.sh b/tests/bfs/exec_flush_fprint.sh
new file mode 100644
index 0000000..9756b6a
--- /dev/null
+++ b/tests/bfs/exec_flush_fprint.sh
@@ -0,0 +1,3 @@
+# Even non-stdstreams should be flushed
+rm -rf scratch/*
+bfs_diff basic/a -fprint scratch/foo -exec cat scratch/foo \;
diff --git a/tests/bfs/exec_flush_fprint_fail.sh b/tests/bfs/exec_flush_fprint_fail.sh
new file mode 100644
index 0000000..5da944a
--- /dev/null
+++ b/tests/bfs/exec_flush_fprint_fail.sh
@@ -0,0 +1,2 @@
+skip_unless test -e /dev/full
+fail invoke_bfs basic/a -fprint /dev/full -exec true \;
diff --git a/tests/bfs/execdir_plus.out b/tests/bfs/execdir_plus.out
new file mode 100644
index 0000000..8866a8f
--- /dev/null
+++ b/tests/bfs/execdir_plus.out
@@ -0,0 +1,11 @@
+./a ./b ./c ./e ./g ./i ./j ./k ./l
+./bar
+./bar
+./basic
+./baz
+./d
+./f
+./foo
+./foo
+./foo
+./h
diff --git a/tests/bfs/execdir_plus.sh b/tests/bfs/execdir_plus.sh
new file mode 100644
index 0000000..9ae7764
--- /dev/null
+++ b/tests/bfs/execdir_plus.sh
@@ -0,0 +1,7 @@
+tree=$(invoke_bfs -D tree 2>&1 -quit)
+
+if [[ "$tree" == *"-S dfs"* ]]; then
+ skip
+fi
+
+bfs_diff basic -execdir "$TESTS/sort-args.sh" {} +
diff --git a/tests/bfs/execdir_plus_nonexistent.out b/tests/bfs/execdir_plus_nonexistent.out
new file mode 100644
index 0000000..a7ccfe4
--- /dev/null
+++ b/tests/bfs/execdir_plus_nonexistent.out
@@ -0,0 +1,19 @@
+basic
+basic/a
+basic/b
+basic/c
+basic/c/d
+basic/e
+basic/e/f
+basic/g
+basic/g/h
+basic/i
+basic/j
+basic/j/foo
+basic/k
+basic/k/foo
+basic/k/foo/bar
+basic/l
+basic/l/foo
+basic/l/foo/bar
+basic/l/foo/bar/baz
diff --git a/tests/bfs/execdir_plus_nonexistent.sh b/tests/bfs/execdir_plus_nonexistent.sh
new file mode 100644
index 0000000..8436953
--- /dev/null
+++ b/tests/bfs/execdir_plus_nonexistent.sh
@@ -0,0 +1,5 @@
+stderr=$(invoke_bfs basic -execdir "$TESTS/nonexistent" {} + 2>&1 >/dev/null)
+[ -n "$stderr" ] || return 1
+
+bfs_diff basic -execdir "$TESTS/nonexistent" {} + -print
+(($? == EX_BFS))
diff --git a/tests/bfs/expr_flag_path.out b/tests/bfs/expr_flag_path.out
new file mode 100644
index 0000000..e67f10b
--- /dev/null
+++ b/tests/bfs/expr_flag_path.out
@@ -0,0 +1,2 @@
+links/skip/broken
+links/skip/link
diff --git a/tests/bfs/expr_flag_path.sh b/tests/bfs/expr_flag_path.sh
new file mode 100644
index 0000000..bb89d92
--- /dev/null
+++ b/tests/bfs/expr_flag_path.sh
@@ -0,0 +1 @@
+bfs_diff -type l -H links/skip
diff --git a/tests/bfs/expr_path_flag.out b/tests/bfs/expr_path_flag.out
new file mode 100644
index 0000000..e67f10b
--- /dev/null
+++ b/tests/bfs/expr_path_flag.out
@@ -0,0 +1,2 @@
+links/skip/broken
+links/skip/link
diff --git a/tests/bfs/expr_path_flag.sh b/tests/bfs/expr_path_flag.sh
new file mode 100644
index 0000000..818e5d1
--- /dev/null
+++ b/tests/bfs/expr_path_flag.sh
@@ -0,0 +1 @@
+bfs_diff -type l links/skip -H
diff --git a/tests/bfs/flag_expr_path.out b/tests/bfs/flag_expr_path.out
new file mode 100644
index 0000000..e67f10b
--- /dev/null
+++ b/tests/bfs/flag_expr_path.out
@@ -0,0 +1,2 @@
+links/skip/broken
+links/skip/link
diff --git a/tests/bfs/flag_expr_path.sh b/tests/bfs/flag_expr_path.sh
new file mode 100644
index 0000000..a414e10
--- /dev/null
+++ b/tests/bfs/flag_expr_path.sh
@@ -0,0 +1 @@
+bfs_diff -H -type l links/skip
diff --git a/tests/bfs/fprint_duplicate_stdout.out b/tests/bfs/fprint_duplicate_stdout.out
new file mode 100644
index 0000000..6c21751
--- /dev/null
+++ b/tests/bfs/fprint_duplicate_stdout.out
@@ -0,0 +1,38 @@
+basic
+basic
+basic/a
+basic/a
+basic/b
+basic/b
+basic/c
+basic/c
+basic/c/d
+basic/c/d
+basic/e
+basic/e
+basic/e/f
+basic/e/f
+basic/g
+basic/g
+basic/g/h
+basic/g/h
+basic/i
+basic/i
+basic/j
+basic/j
+basic/j/foo
+basic/j/foo
+basic/k
+basic/k
+basic/k/foo
+basic/k/foo
+basic/k/foo/bar
+basic/k/foo/bar
+basic/l
+basic/l
+basic/l/foo
+basic/l/foo
+basic/l/foo/bar
+basic/l/foo/bar
+basic/l/foo/bar/baz
+basic/l/foo/bar/baz
diff --git a/tests/bfs/fprint_duplicate_stdout.sh b/tests/bfs/fprint_duplicate_stdout.sh
new file mode 100644
index 0000000..4e95e30
--- /dev/null
+++ b/tests/bfs/fprint_duplicate_stdout.sh
@@ -0,0 +1,3 @@
+invoke_bfs basic -fprint "$OUT" -print >"$OUT"
+sort_output
+diff_output
diff --git a/tests/bfs/fprint_error_stderr.sh b/tests/bfs/fprint_error_stderr.sh
new file mode 100644
index 0000000..427808f
--- /dev/null
+++ b/tests/bfs/fprint_error_stderr.sh
@@ -0,0 +1,2 @@
+skip_unless test -e /dev/full
+fail invoke_bfs basic -maxdepth 0 -fprint /dev/full 2>/dev/full
diff --git a/tests/bfs/fprint_error_stdout.sh b/tests/bfs/fprint_error_stdout.sh
new file mode 100644
index 0000000..fbdc1d0
--- /dev/null
+++ b/tests/bfs/fprint_error_stdout.sh
@@ -0,0 +1,2 @@
+skip_unless test -e /dev/full
+fail invoke_bfs basic -maxdepth 0 -fprint /dev/full >/dev/full
diff --git a/tests/bfs/help.sh b/tests/bfs/help.sh
new file mode 100644
index 0000000..5e5c684
--- /dev/null
+++ b/tests/bfs/help.sh
@@ -0,0 +1,6 @@
+invoke_bfs -help | grep -E '\{...?\}' && return 1
+invoke_bfs -D help | grep -E '\{...?\}' && return 1
+invoke_bfs -S help | grep -E '\{...?\}' && return 1
+invoke_bfs -regextype help | grep -E '\{...?\}' && return 1
+
+return 0
diff --git a/tests/bfs/hidden.out b/tests/bfs/hidden.out
new file mode 100644
index 0000000..e65ede9
--- /dev/null
+++ b/tests/bfs/hidden.out
@@ -0,0 +1 @@
+weirdnames/...
diff --git a/tests/bfs/hidden.sh b/tests/bfs/hidden.sh
new file mode 100644
index 0000000..b0413c5
--- /dev/null
+++ b/tests/bfs/hidden.sh
@@ -0,0 +1 @@
+bfs_diff weirdnames -hidden
diff --git a/tests/bfs/hidden_root.out b/tests/bfs/hidden_root.out
new file mode 100644
index 0000000..8c1371b
--- /dev/null
+++ b/tests/bfs/hidden_root.out
@@ -0,0 +1,5 @@
+...
+.../../...
+./...
+./...
+././...
diff --git a/tests/bfs/hidden_root.sh b/tests/bfs/hidden_root.sh
new file mode 100644
index 0000000..905c5b5
--- /dev/null
+++ b/tests/bfs/hidden_root.sh
@@ -0,0 +1,2 @@
+cd weirdnames
+bfs_diff . ./. ... ./... .../.. -hidden
diff --git a/tests/bfs/links_empty.sh b/tests/bfs/links_empty.sh
new file mode 100644
index 0000000..34c7c25
--- /dev/null
+++ b/tests/bfs/links_empty.sh
@@ -0,0 +1 @@
+fail invoke_bfs links -links ''
diff --git a/tests/bfs/links_invalid.sh b/tests/bfs/links_invalid.sh
new file mode 100644
index 0000000..ff69fa6
--- /dev/null
+++ b/tests/bfs/links_invalid.sh
@@ -0,0 +1 @@
+fail invoke_bfs links -links ASDF
diff --git a/tests/bfs/links_negative.sh b/tests/bfs/links_negative.sh
new file mode 100644
index 0000000..b5d9c58
--- /dev/null
+++ b/tests/bfs/links_negative.sh
@@ -0,0 +1 @@
+fail invoke_bfs links -links +-1
diff --git a/tests/bfs/links_noarg.sh b/tests/bfs/links_noarg.sh
new file mode 100644
index 0000000..5dede5f
--- /dev/null
+++ b/tests/bfs/links_noarg.sh
@@ -0,0 +1 @@
+fail invoke_bfs links -links
diff --git a/tests/bfs/newerma_nonexistent.sh b/tests/bfs/newerma_nonexistent.sh
new file mode 100644
index 0000000..7f3695f
--- /dev/null
+++ b/tests/bfs/newerma_nonexistent.sh
@@ -0,0 +1 @@
+fail invoke_bfs times -newerma basic/nonexistent
diff --git a/tests/bfs/newermq.sh b/tests/bfs/newermq.sh
new file mode 100644
index 0000000..2a22586
--- /dev/null
+++ b/tests/bfs/newermq.sh
@@ -0,0 +1 @@
+fail invoke_bfs times -newermq times/a
diff --git a/tests/bfs/newermt_invalid.sh b/tests/bfs/newermt_invalid.sh
new file mode 100644
index 0000000..61d2485
--- /dev/null
+++ b/tests/bfs/newermt_invalid.sh
@@ -0,0 +1 @@
+fail invoke_bfs times -newermt not_a_date_time
diff --git a/tests/bfs/newerqm.sh b/tests/bfs/newerqm.sh
new file mode 100644
index 0000000..da84350
--- /dev/null
+++ b/tests/bfs/newerqm.sh
@@ -0,0 +1 @@
+fail invoke_bfs times -newerqm times/a
diff --git a/tests/bfs/nohidden.out b/tests/bfs/nohidden.out
new file mode 100644
index 0000000..d3ec901
--- /dev/null
+++ b/tests/bfs/nohidden.out
@@ -0,0 +1,21 @@
+weirdnames
+weirdnames/
+weirdnames/ /j
+weirdnames/!
+weirdnames/!-
+weirdnames/!-/e
+weirdnames/!/d
+weirdnames/(
+weirdnames/(-
+weirdnames/(-/c
+weirdnames/(/b
+weirdnames/)
+weirdnames/)/g
+weirdnames/,
+weirdnames/,/f
+weirdnames/-
+weirdnames/-/a
+weirdnames/[
+weirdnames/[/k
+weirdnames/\
+weirdnames/\/i
diff --git a/tests/bfs/nohidden.sh b/tests/bfs/nohidden.sh
new file mode 100644
index 0000000..e3a3e4a
--- /dev/null
+++ b/tests/bfs/nohidden.sh
@@ -0,0 +1 @@
+bfs_diff weirdnames -nohidden
diff --git a/tests/bfs/nohidden_depth.out b/tests/bfs/nohidden_depth.out
new file mode 100644
index 0000000..d3ec901
--- /dev/null
+++ b/tests/bfs/nohidden_depth.out
@@ -0,0 +1,21 @@
+weirdnames
+weirdnames/
+weirdnames/ /j
+weirdnames/!
+weirdnames/!-
+weirdnames/!-/e
+weirdnames/!/d
+weirdnames/(
+weirdnames/(-
+weirdnames/(-/c
+weirdnames/(/b
+weirdnames/)
+weirdnames/)/g
+weirdnames/,
+weirdnames/,/f
+weirdnames/-
+weirdnames/-/a
+weirdnames/[
+weirdnames/[/k
+weirdnames/\
+weirdnames/\/i
diff --git a/tests/bfs/nohidden_depth.sh b/tests/bfs/nohidden_depth.sh
new file mode 100644
index 0000000..9fd7017
--- /dev/null
+++ b/tests/bfs/nohidden_depth.sh
@@ -0,0 +1 @@
+bfs_diff weirdnames -depth -nohidden
diff --git a/tests/bfs/nowarn.sh b/tests/bfs/nowarn.sh
new file mode 100644
index 0000000..d9f9ab3
--- /dev/null
+++ b/tests/bfs/nowarn.sh
@@ -0,0 +1,2 @@
+stderr=$(invoke_bfs basic -nowarn -depth -prune 2>&1 >/dev/null)
+[ -z "$stderr" ]
diff --git a/tests/bfs/ok_plus_semicolon.out b/tests/bfs/ok_plus_semicolon.out
new file mode 100644
index 0000000..2a3e14f
--- /dev/null
+++ b/tests/bfs/ok_plus_semicolon.out
@@ -0,0 +1,19 @@
+basic +
+basic/a +
+basic/b +
+basic/c +
+basic/c/d +
+basic/e +
+basic/e/f +
+basic/g +
+basic/g/h +
+basic/i +
+basic/j +
+basic/j/foo +
+basic/k +
+basic/k/foo +
+basic/k/foo/bar +
+basic/l +
+basic/l/foo +
+basic/l/foo/bar +
+basic/l/foo/bar/baz +
diff --git a/tests/bfs/ok_plus_semicolon.sh b/tests/bfs/ok_plus_semicolon.sh
new file mode 100644
index 0000000..57d6103
--- /dev/null
+++ b/tests/bfs/ok_plus_semicolon.sh
@@ -0,0 +1,8 @@
+# The -ok primary shall be equivalent to -exec, except that the use of a
+# <plus-sign> to punctuate the end of the primary expression need not be
+# supported, ...
+#
+# bfs chooses not to support it, for compatibility with most other find
+# implementations.
+
+yes | bfs_diff basic -ok echo {} + \;
diff --git a/tests/bfs/okdir_plus_semicolon.out b/tests/bfs/okdir_plus_semicolon.out
new file mode 100644
index 0000000..1909d27
--- /dev/null
+++ b/tests/bfs/okdir_plus_semicolon.out
@@ -0,0 +1,19 @@
+./a +
+./b +
+./bar +
+./bar +
+./basic +
+./baz +
+./c +
+./d +
+./e +
+./f +
+./foo +
+./foo +
+./foo +
+./g +
+./h +
+./i +
+./j +
+./k +
+./l +
diff --git a/tests/bfs/okdir_plus_semicolon.sh b/tests/bfs/okdir_plus_semicolon.sh
new file mode 100644
index 0000000..d316bd7
--- /dev/null
+++ b/tests/bfs/okdir_plus_semicolon.sh
@@ -0,0 +1 @@
+yes | bfs_diff basic -okdir echo {} + \;
diff --git a/tests/bfs/or_incomplete.sh b/tests/bfs/or_incomplete.sh
new file mode 100644
index 0000000..c941b95
--- /dev/null
+++ b/tests/bfs/or_incomplete.sh
@@ -0,0 +1 @@
+fail invoke_bfs -print -o
diff --git a/tests/bfs/path_expr_flag.out b/tests/bfs/path_expr_flag.out
new file mode 100644
index 0000000..e67f10b
--- /dev/null
+++ b/tests/bfs/path_expr_flag.out
@@ -0,0 +1,2 @@
+links/skip/broken
+links/skip/link
diff --git a/tests/bfs/path_expr_flag.sh b/tests/bfs/path_expr_flag.sh
new file mode 100644
index 0000000..7cfa1cd
--- /dev/null
+++ b/tests/bfs/path_expr_flag.sh
@@ -0,0 +1 @@
+bfs_diff links/skip -type l -H
diff --git a/tests/bfs/path_flag_expr.out b/tests/bfs/path_flag_expr.out
new file mode 100644
index 0000000..e67f10b
--- /dev/null
+++ b/tests/bfs/path_flag_expr.out
@@ -0,0 +1,2 @@
+links/skip/broken
+links/skip/link
diff --git a/tests/bfs/path_flag_expr.sh b/tests/bfs/path_flag_expr.sh
new file mode 100644
index 0000000..ca00c8c
--- /dev/null
+++ b/tests/bfs/path_flag_expr.sh
@@ -0,0 +1 @@
+bfs_diff links/skip -H -type l
diff --git a/tests/bfs/perm_leading_plus_symbolic.out b/tests/bfs/perm_leading_plus_symbolic.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/bfs/perm_leading_plus_symbolic.out
diff --git a/tests/bfs/perm_leading_plus_symbolic.sh b/tests/bfs/perm_leading_plus_symbolic.sh
new file mode 100644
index 0000000..4202ac1
--- /dev/null
+++ b/tests/bfs/perm_leading_plus_symbolic.sh
@@ -0,0 +1 @@
+bfs_diff perms -perm +rwx
diff --git a/tests/bfs/perm_symbolic_double_comma.sh b/tests/bfs/perm_symbolic_double_comma.sh
new file mode 100644
index 0000000..66db0ac
--- /dev/null
+++ b/tests/bfs/perm_symbolic_double_comma.sh
@@ -0,0 +1 @@
+fail invoke_bfs perms -perm a+r,,u+w
diff --git a/tests/bfs/perm_symbolic_missing_action.sh b/tests/bfs/perm_symbolic_missing_action.sh
new file mode 100644
index 0000000..3b18721
--- /dev/null
+++ b/tests/bfs/perm_symbolic_missing_action.sh
@@ -0,0 +1 @@
+fail invoke_bfs perms -perm a
diff --git a/tests/bfs/perm_symbolic_trailing_comma.sh b/tests/bfs/perm_symbolic_trailing_comma.sh
new file mode 100644
index 0000000..c52ebe6
--- /dev/null
+++ b/tests/bfs/perm_symbolic_trailing_comma.sh
@@ -0,0 +1 @@
+fail invoke_bfs perms -perm a+r,
diff --git a/tests/bfs/printf_color.out b/tests/bfs/printf_color.out
new file mode 100644
index 0000000..d9cd1a4
--- /dev/null
+++ b/tests/bfs/printf_color.out
@@ -0,0 +1,20 @@
+. . rainbow ./rainbow rainbow
+. ./rainbow exec.sh ./rainbow/exec.sh rainbow/exec.sh
+. ./rainbow socket ./rainbow/socket rainbow/socket
+. ./rainbow broken ./rainbow/broken rainbow/broken nowhere
+. ./rainbow chardev_link ./rainbow/chardev_link rainbow/chardev_link /dev/null
+. ./rainbow link.txt ./rainbow/link.txt rainbow/link.txt file.txt
+. ./rainbow sticky_ow ./rainbow/sticky_ow rainbow/sticky_ow
+. ./rainbow sgid ./rainbow/sgid rainbow/sgid
+. ./rainbow pipe ./rainbow/pipe rainbow/pipe
+. ./rainbow ow ./rainbow/ow rainbow/ow
+. ./rainbow sugid ./rainbow/sugid rainbow/sugid
+. ./rainbow suid ./rainbow/suid rainbow/suid
+. ./rainbow sticky ./rainbow/sticky rainbow/sticky
+. ./rainbow file.dat ./rainbow/file.dat rainbow/file.dat
+. ./rainbow file.txt ./rainbow/file.txt rainbow/file.txt
+. ./rainbow mh1 ./rainbow/mh1 rainbow/mh1
+. ./rainbow mh2 ./rainbow/mh2 rainbow/mh2
+. ./rainbow star.gz ./rainbow/star.gz rainbow/star.gz
+. ./rainbow star.tar ./rainbow/star.tar rainbow/star.tar
+. ./rainbow star.tar.gz ./rainbow/star.tar.gz rainbow/star.tar.gz
diff --git a/tests/bfs/printf_color.sh b/tests/bfs/printf_color.sh
new file mode 100644
index 0000000..7bb38c2
--- /dev/null
+++ b/tests/bfs/printf_color.sh
@@ -0,0 +1 @@
+bfs_diff -color -path './rainbow*' -printf '%H %h %f %p %P %l\n'
diff --git a/tests/bfs/printf_duplicate_flag.sh b/tests/bfs/printf_duplicate_flag.sh
new file mode 100644
index 0000000..77650d0
--- /dev/null
+++ b/tests/bfs/printf_duplicate_flag.sh
@@ -0,0 +1 @@
+fail invoke_bfs basic -printf '%--p'
diff --git a/tests/bfs/printf_everything.sh b/tests/bfs/printf_everything.sh
new file mode 100644
index 0000000..58996ab
--- /dev/null
+++ b/tests/bfs/printf_everything.sh
@@ -0,0 +1,9 @@
+everything=(%{a,b,c,d,D,f,F,g,G,h,H,i,k,l,m,M,n,p,P,s,S,t,u,U,y,Y})
+everything+=(%{A,C,T}{%,+,@,a,A,b,B,c,C,d,D,e,F,g,G,h,H,I,j,k,l,m,M,n,p,r,R,s,S,t,T,u,U,V,w,W,x,X,y,Y,z,Z})
+
+# Check if we have birth times
+if ! fail invoke_bfs basic -printf '%w' -quit >/dev/null; then
+ everything+=(%w %{B,W}{%,+,@,a,A,b,B,c,C,d,D,e,F,g,G,h,H,I,j,k,l,m,M,n,p,r,R,s,S,t,T,u,U,V,w,W,x,X,y,Y,z,Z})
+fi
+
+invoke_bfs rainbow -printf "${everything[*]}\n" >/dev/null
diff --git a/tests/bfs/printf_incomplete_escape.sh b/tests/bfs/printf_incomplete_escape.sh
new file mode 100644
index 0000000..144add5
--- /dev/null
+++ b/tests/bfs/printf_incomplete_escape.sh
@@ -0,0 +1 @@
+fail invoke_bfs basic -printf '\'
diff --git a/tests/bfs/printf_incomplete_format.sh b/tests/bfs/printf_incomplete_format.sh
new file mode 100644
index 0000000..347a0f4
--- /dev/null
+++ b/tests/bfs/printf_incomplete_format.sh
@@ -0,0 +1 @@
+fail invoke_bfs basic -printf '%'
diff --git a/tests/bfs/printf_invalid_escape.sh b/tests/bfs/printf_invalid_escape.sh
new file mode 100644
index 0000000..ce12233
--- /dev/null
+++ b/tests/bfs/printf_invalid_escape.sh
@@ -0,0 +1 @@
+fail invoke_bfs basic -printf '\!'
diff --git a/tests/bfs/printf_invalid_format.sh b/tests/bfs/printf_invalid_format.sh
new file mode 100644
index 0000000..1717615
--- /dev/null
+++ b/tests/bfs/printf_invalid_format.sh
@@ -0,0 +1 @@
+fail invoke_bfs basic -printf '%!'
diff --git a/tests/bfs/printf_must_be_numeric.sh b/tests/bfs/printf_must_be_numeric.sh
new file mode 100644
index 0000000..eabb3d6
--- /dev/null
+++ b/tests/bfs/printf_must_be_numeric.sh
@@ -0,0 +1 @@
+fail invoke_bfs basic -printf '%+p'
diff --git a/tests/bfs/printf_w.out b/tests/bfs/printf_w.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/bfs/printf_w.out
diff --git a/tests/bfs/printf_w.sh b/tests/bfs/printf_w.sh
new file mode 100644
index 0000000..3b27ee7
--- /dev/null
+++ b/tests/bfs/printf_w.sh
@@ -0,0 +1,2 @@
+# Birth times may not be supported, so just check that %w/%W/%B can be parsed
+bfs_diff times -false -printf '%w %WY %BY\n'
diff --git a/tests/bfs/stderr_fails_loudly.sh b/tests/bfs/stderr_fails_loudly.sh
new file mode 100644
index 0000000..d8b3861
--- /dev/null
+++ b/tests/bfs/stderr_fails_loudly.sh
@@ -0,0 +1,2 @@
+skip_unless test -e /dev/full
+fail invoke_bfs -D all basic -false -fprint /dev/full 2>/dev/full
diff --git a/tests/bfs/stderr_fails_silently.out b/tests/bfs/stderr_fails_silently.out
new file mode 100644
index 0000000..a7ccfe4
--- /dev/null
+++ b/tests/bfs/stderr_fails_silently.out
@@ -0,0 +1,19 @@
+basic
+basic/a
+basic/b
+basic/c
+basic/c/d
+basic/e
+basic/e/f
+basic/g
+basic/g/h
+basic/i
+basic/j
+basic/j/foo
+basic/k
+basic/k/foo
+basic/k/foo/bar
+basic/l
+basic/l/foo
+basic/l/foo/bar
+basic/l/foo/bar/baz
diff --git a/tests/bfs/stderr_fails_silently.sh b/tests/bfs/stderr_fails_silently.sh
new file mode 100644
index 0000000..731cb02
--- /dev/null
+++ b/tests/bfs/stderr_fails_silently.sh
@@ -0,0 +1,2 @@
+skip_unless test -e /dev/full
+bfs_diff -D all basic 2>/dev/full
diff --git a/tests/bfs/type_multi.out b/tests/bfs/type_multi.out
new file mode 100644
index 0000000..3cae08a
--- /dev/null
+++ b/tests/bfs/type_multi.out
@@ -0,0 +1,7 @@
+links
+links/deeply
+links/deeply/nested
+links/deeply/nested/dir
+links/deeply/nested/file
+links/file
+links/hardlink
diff --git a/tests/bfs/type_multi.sh b/tests/bfs/type_multi.sh
new file mode 100644
index 0000000..59992c7
--- /dev/null
+++ b/tests/bfs/type_multi.sh
@@ -0,0 +1 @@
+bfs_diff links -type f,d,c
diff --git a/tests/bfs/typo.sh b/tests/bfs/typo.sh
new file mode 100644
index 0000000..459e9fe
--- /dev/null
+++ b/tests/bfs/typo.sh
@@ -0,0 +1 @@
+invoke_bfs -dikkiq 2>&1 | grep follow >/dev/null
diff --git a/tests/bfs/unexpected_operator.sh b/tests/bfs/unexpected_operator.sh
new file mode 100644
index 0000000..b3658f6
--- /dev/null
+++ b/tests/bfs/unexpected_operator.sh
@@ -0,0 +1 @@
+fail invoke_bfs \! -o -print
diff --git a/tests/bfs/unique.out b/tests/bfs/unique.out
new file mode 100644
index 0000000..289cbde
--- /dev/null
+++ b/tests/bfs/unique.out
@@ -0,0 +1,2 @@
+links/file
+links/symlink
diff --git a/tests/bfs/unique.sh b/tests/bfs/unique.sh
new file mode 100644
index 0000000..ea8adfd
--- /dev/null
+++ b/tests/bfs/unique.sh
@@ -0,0 +1 @@
+bfs_diff links/{file,symlink,hardlink} -unique
diff --git a/tests/bfs/unique_depth.out b/tests/bfs/unique_depth.out
new file mode 100644
index 0000000..a7ccfe4
--- /dev/null
+++ b/tests/bfs/unique_depth.out
@@ -0,0 +1,19 @@
+basic
+basic/a
+basic/b
+basic/c
+basic/c/d
+basic/e
+basic/e/f
+basic/g
+basic/g/h
+basic/i
+basic/j
+basic/j/foo
+basic/k
+basic/k/foo
+basic/k/foo/bar
+basic/l
+basic/l/foo
+basic/l/foo/bar
+basic/l/foo/bar/baz
diff --git a/tests/bfs/unique_depth.sh b/tests/bfs/unique_depth.sh
new file mode 100644
index 0000000..c1d9716
--- /dev/null
+++ b/tests/bfs/unique_depth.sh
@@ -0,0 +1 @@
+bfs_diff basic -unique -depth
diff --git a/tests/bfs/version.sh b/tests/bfs/version.sh
new file mode 100644
index 0000000..e0417ca
--- /dev/null
+++ b/tests/bfs/version.sh
@@ -0,0 +1 @@
+invoke_bfs -version >/dev/null
diff --git a/tests/bfs/warn.sh b/tests/bfs/warn.sh
new file mode 100644
index 0000000..0f613c8
--- /dev/null
+++ b/tests/bfs/warn.sh
@@ -0,0 +1,2 @@
+stderr=$(invoke_bfs basic -warn -depth -prune 2>&1 >/dev/null)
+[ -n "$stderr" ]
diff --git a/tests/bfs/xtype_depth.sh b/tests/bfs/xtype_depth.sh
new file mode 100644
index 0000000..cd478af
--- /dev/null
+++ b/tests/bfs/xtype_depth.sh
@@ -0,0 +1,2 @@
+# Make sure -xtype is considered side-effecting for facts_when_impure
+fail invoke_bfs loops -xtype l -depth 100
diff --git a/tests/bfs/xtype_multi.out b/tests/bfs/xtype_multi.out
new file mode 100644
index 0000000..558e89c
--- /dev/null
+++ b/tests/bfs/xtype_multi.out
@@ -0,0 +1,10 @@
+links
+links/deeply
+links/deeply/nested
+links/deeply/nested/dir
+links/deeply/nested/file
+links/deeply/nested/link
+links/file
+links/hardlink
+links/skip
+links/symlink
diff --git a/tests/bfs/xtype_multi.sh b/tests/bfs/xtype_multi.sh
new file mode 100644
index 0000000..ed20955
--- /dev/null
+++ b/tests/bfs/xtype_multi.sh
@@ -0,0 +1 @@
+bfs_diff links -xtype f,d,c
diff --git a/tests/bfs/xtype_reorder.out b/tests/bfs/xtype_reorder.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/bfs/xtype_reorder.out
diff --git a/tests/bfs/xtype_reorder.sh b/tests/bfs/xtype_reorder.sh
new file mode 100644
index 0000000..8d75d7d
--- /dev/null
+++ b/tests/bfs/xtype_reorder.sh
@@ -0,0 +1,4 @@
+# Make sure -xtype is not reordered in front of anything -- if -xtype runs
+# before -links 100, it will report an ELOOP error
+bfs_diff loops -links 100 -xtype l
+invoke_bfs loops -links 100 -xtype l