diff options
Diffstat (limited to 't/chainlint')
152 files changed, 2118 insertions, 0 deletions
diff --git a/t/chainlint/arithmetic-expansion.expect b/t/chainlint/arithmetic-expansion.expect new file mode 100644 index 0000000000..5677e16cad --- /dev/null +++ b/t/chainlint/arithmetic-expansion.expect @@ -0,0 +1,9 @@ +2 ( +3 foo && +4 bar=$((42 + 1)) && +5 baz +6 ) && +7 ( +8 bar=$((42 + 1)) ?!LINT: missing '&&'?! +9 baz +10 ) diff --git a/t/chainlint/arithmetic-expansion.test b/t/chainlint/arithmetic-expansion.test new file mode 100644 index 0000000000..7b4c5c9a41 --- /dev/null +++ b/t/chainlint/arithmetic-expansion.test @@ -0,0 +1,13 @@ +test_expect_success 'arithmetic-expansion' ' +( + foo && +# LINT: closing ")" of $((...)) not misinterpreted as subshell-closing ")" + bar=$((42 + 1)) && + baz +) && +( +# LINT: missing "&&" on $((...)) + bar=$((42 + 1)) + baz +) +' diff --git a/t/chainlint/bash-array.expect b/t/chainlint/bash-array.expect new file mode 100644 index 0000000000..435dc8bdc8 --- /dev/null +++ b/t/chainlint/bash-array.expect @@ -0,0 +1,10 @@ +2 ( +3 foo && +4 bar=(gumbo stumbo wumbo) && +5 baz +6 ) && +7 ( +8 foo && +9 bar=${#bar[@]} && +10 baz +11 ) diff --git a/t/chainlint/bash-array.test b/t/chainlint/bash-array.test new file mode 100644 index 0000000000..4ca977d299 --- /dev/null +++ b/t/chainlint/bash-array.test @@ -0,0 +1,14 @@ +test_expect_success 'bash-array' ' +( + foo && +# LINT: ")" in Bash array assignment not misinterpreted as subshell-closing ")" + bar=(gumbo stumbo wumbo) && + baz +) && +( + foo && +# LINT: Bash array length operator not misinterpreted as comment + bar=${#bar[@]} && + baz +) +' diff --git a/t/chainlint/blank-line-before-esac.expect b/t/chainlint/blank-line-before-esac.expect new file mode 100644 index 0000000000..b88ba919eb --- /dev/null +++ b/t/chainlint/blank-line-before-esac.expect @@ -0,0 +1,18 @@ +2 test_done () { +3 case "$test_failure" in +4 0) +5 test_at_end_hook_ +6 +7 exit 0 ;; +8 +9 *) +10 if test $test_external_has_tap -eq 0 +11 then +12 say_color error "# failed $test_failure among $msg" +13 say "1..$test_count" +14 fi +15 +16 exit 1 ;; +17 +18 esac +19 } diff --git a/t/chainlint/blank-line-before-esac.test b/t/chainlint/blank-line-before-esac.test new file mode 100644 index 0000000000..51f02ea0c5 --- /dev/null +++ b/t/chainlint/blank-line-before-esac.test @@ -0,0 +1,21 @@ +test_expect_success 'blank-line-before-esac' ' +# LINT: blank line before "esac" +test_done () { + case "$test_failure" in + 0) + test_at_end_hook_ + + exit 0 ;; + + *) + if test $test_external_has_tap -eq 0 + then + say_color error "# failed $test_failure among $msg" + say "1..$test_count" + fi + + exit 1 ;; + + esac +} +' diff --git a/t/chainlint/blank-line.expect b/t/chainlint/blank-line.expect new file mode 100644 index 0000000000..6ae39dd174 --- /dev/null +++ b/t/chainlint/blank-line.expect @@ -0,0 +1,8 @@ +2 ( +3 +4 nothing && +5 +6 something +7 +8 +9 ) diff --git a/t/chainlint/blank-line.test b/t/chainlint/blank-line.test new file mode 100644 index 0000000000..6f29a491de --- /dev/null +++ b/t/chainlint/blank-line.test @@ -0,0 +1,12 @@ +test_expect_success 'blank-line' ' +( + + nothing && + + something +# LINT: ignore blank lines since final _statement_ before subshell end is +# LINT: significant to "&&"-check, not final _line_ (which might be blank) + + +) +' diff --git a/t/chainlint/block-comment.expect b/t/chainlint/block-comment.expect new file mode 100644 index 0000000000..7926936c18 --- /dev/null +++ b/t/chainlint/block-comment.expect @@ -0,0 +1,8 @@ +2 ( +3 { +4 # show a +5 echo a && +6 # show b +7 echo b +8 } +9 ) diff --git a/t/chainlint/block-comment.test b/t/chainlint/block-comment.test new file mode 100644 index 0000000000..934ef4113a --- /dev/null +++ b/t/chainlint/block-comment.test @@ -0,0 +1,10 @@ +test_expect_success 'block-comment' ' +( + { + # show a + echo a && + # show b + echo b + } +) +' diff --git a/t/chainlint/block.expect b/t/chainlint/block.expect new file mode 100644 index 0000000000..3d3f854c0d --- /dev/null +++ b/t/chainlint/block.expect @@ -0,0 +1,23 @@ +2 ( +3 foo && +4 { +5 echo a ?!LINT: missing '&&'?! +6 echo b +7 } && +8 bar && +9 { +10 echo c +11 } ?!LINT: missing '&&'?! +12 baz +13 ) && +14 +15 { +16 echo a; ?!LINT: missing '&&'?! echo b +17 } && +18 { echo a; ?!LINT: missing '&&'?! echo b; } && +19 +20 { +21 echo "${var}9" && +22 echo "done" +23 } && +24 finis diff --git a/t/chainlint/block.test b/t/chainlint/block.test new file mode 100644 index 0000000000..a1b6b4dd32 --- /dev/null +++ b/t/chainlint/block.test @@ -0,0 +1,29 @@ +test_expect_success 'block' ' +( +# LINT: missing "&&" after first "echo" + foo && + { + echo a + echo b + } && + bar && +# LINT: missing "&&" at closing "}" + { + echo c + } + baz +) && + +# LINT: ";" not allowed in place of "&&" +{ + echo a; echo b +} && +{ echo a; echo b; } && + +# LINT: "}" inside string not mistaken as end of block +{ + echo "${var}9" && + echo "done" +} && +finis +' diff --git a/t/chainlint/broken-chain.expect b/t/chainlint/broken-chain.expect new file mode 100644 index 0000000000..b7b1ce8509 --- /dev/null +++ b/t/chainlint/broken-chain.expect @@ -0,0 +1,6 @@ +2 ( +3 foo && +4 bar ?!LINT: missing '&&'?! +5 baz && +6 wop +7 ) diff --git a/t/chainlint/broken-chain.test b/t/chainlint/broken-chain.test new file mode 100644 index 0000000000..1966499ef9 --- /dev/null +++ b/t/chainlint/broken-chain.test @@ -0,0 +1,10 @@ +test_expect_success 'broken-chain' ' +( + foo && +# LINT: missing "&&" from "bar" + bar + baz && +# LINT: final statement before closing ")" legitimately lacks "&&" + wop +) +' diff --git a/t/chainlint/case-comment.expect b/t/chainlint/case-comment.expect new file mode 100644 index 0000000000..2442dd5f25 --- /dev/null +++ b/t/chainlint/case-comment.expect @@ -0,0 +1,11 @@ +2 ( +3 case "$x" in +4 # found foo +5 x) foo ;; +6 # found other +7 *) +8 # treat it as bar +9 bar +10 ;; +11 esac +12 ) diff --git a/t/chainlint/case-comment.test b/t/chainlint/case-comment.test new file mode 100644 index 0000000000..3f31ae9010 --- /dev/null +++ b/t/chainlint/case-comment.test @@ -0,0 +1,13 @@ +test_expect_success 'case-comment' ' +( + case "$x" in + # found foo + x) foo ;; + # found other + *) + # treat it as bar + bar + ;; + esac +) +' diff --git a/t/chainlint/case.expect b/t/chainlint/case.expect new file mode 100644 index 0000000000..0a3b09e470 --- /dev/null +++ b/t/chainlint/case.expect @@ -0,0 +1,19 @@ +2 ( +3 case "$x" in +4 x) foo ;; +5 *) bar ;; +6 esac && +7 foobar +8 ) && +9 ( +10 case "$x" in +11 x) foo ;; +12 *) bar ;; +13 esac ?!LINT: missing '&&'?! +14 foobar +15 ) && +16 ( +17 case "$x" in 1) true;; esac && +18 case "$y" in 2) false;; esac ?!LINT: missing '&&'?! +19 foobar +20 ) diff --git a/t/chainlint/case.test b/t/chainlint/case.test new file mode 100644 index 0000000000..bea21fee4f --- /dev/null +++ b/t/chainlint/case.test @@ -0,0 +1,25 @@ +test_expect_success 'case' ' +( +# LINT: "...)" arms in "case" not misinterpreted as subshell-closing ")" + case "$x" in + x) foo ;; + *) bar ;; + esac && + foobar +) && +( +# LINT: missing "&&" on "esac" + case "$x" in + x) foo ;; + *) bar ;; + esac + foobar +) && +( +# LINT: "...)" arm in one-liner "case" not misinterpreted as closing ")" + case "$x" in 1) true;; esac && +# LINT: same but missing "&&" + case "$y" in 2) false;; esac + foobar +) +' diff --git a/t/chainlint/chain-break-background.expect b/t/chainlint/chain-break-background.expect new file mode 100644 index 0000000000..d06deadae7 --- /dev/null +++ b/t/chainlint/chain-break-background.expect @@ -0,0 +1,9 @@ +2 JGIT_DAEMON_PID= && +3 git init --bare empty.git && +4 >empty.git/git-daemon-export-ok && +5 mkfifo jgit_daemon_output && +6 { +7 jgit daemon --port="$JGIT_DAEMON_PORT" . >jgit_daemon_output & +8 JGIT_DAEMON_PID=$! +9 } && +10 test_expect_code 2 git ls-remote --exit-code git://localhost:$JGIT_DAEMON_PORT/empty.git diff --git a/t/chainlint/chain-break-background.test b/t/chainlint/chain-break-background.test new file mode 100644 index 0000000000..c68e1b04d5 --- /dev/null +++ b/t/chainlint/chain-break-background.test @@ -0,0 +1,12 @@ +test_expect_success 'chain-break-background' ' +JGIT_DAEMON_PID= && +git init --bare empty.git && +>empty.git/git-daemon-export-ok && +mkfifo jgit_daemon_output && +{ +# LINT: exit status of "&" is always 0 so &&-chaining immaterial + jgit daemon --port="$JGIT_DAEMON_PORT" . >jgit_daemon_output & + JGIT_DAEMON_PID=$! +} && +test_expect_code 2 git ls-remote --exit-code git://localhost:$JGIT_DAEMON_PORT/empty.git +' diff --git a/t/chainlint/chain-break-continue.expect b/t/chainlint/chain-break-continue.expect new file mode 100644 index 0000000000..4bb60aae25 --- /dev/null +++ b/t/chainlint/chain-break-continue.expect @@ -0,0 +1,12 @@ +2 git ls-tree --name-only -r refs/notes/many_notes | +3 while read path +4 do +5 test "$path" = "foobar/non-note.txt" && continue +6 test "$path" = "deadbeef" && continue +7 test "$path" = "de/adbeef" && continue +8 +9 if test $(expr length "$path") -ne $hexsz +10 then +11 return 1 +12 fi +13 done diff --git a/t/chainlint/chain-break-continue.test b/t/chainlint/chain-break-continue.test new file mode 100644 index 0000000000..de8119b204 --- /dev/null +++ b/t/chainlint/chain-break-continue.test @@ -0,0 +1,15 @@ +test_expect_success 'chain-break-continue' ' +git ls-tree --name-only -r refs/notes/many_notes | +while read path +do +# LINT: broken &&-chain okay if explicit "continue" + test "$path" = "foobar/non-note.txt" && continue + test "$path" = "deadbeef" && continue + test "$path" = "de/adbeef" && continue + + if test $(expr length "$path") -ne $hexsz + then + return 1 + fi +done +' diff --git a/t/chainlint/chain-break-false.expect b/t/chainlint/chain-break-false.expect new file mode 100644 index 0000000000..f6a0a301e9 --- /dev/null +++ b/t/chainlint/chain-break-false.expect @@ -0,0 +1,9 @@ +2 if condition not satisified +3 then +4 echo it did not work... +5 echo failed! +6 false +7 else +8 echo it went okay ?!LINT: missing '&&'?! +9 congratulate user +10 fi diff --git a/t/chainlint/chain-break-false.test b/t/chainlint/chain-break-false.test new file mode 100644 index 0000000000..f78ad911fc --- /dev/null +++ b/t/chainlint/chain-break-false.test @@ -0,0 +1,12 @@ +test_expect_success 'chain-break-false' ' +# LINT: broken &&-chain okay if explicit "false" signals failure +if condition not satisified +then + echo it did not work... + echo failed! + false +else + echo it went okay + congratulate user +fi +' diff --git a/t/chainlint/chain-break-return-exit.expect b/t/chainlint/chain-break-return-exit.expect new file mode 100644 index 0000000000..ba0ec51aa0 --- /dev/null +++ b/t/chainlint/chain-break-return-exit.expect @@ -0,0 +1,19 @@ +2 case "$(git ls-files)" in +3 one) echo pass one ;; +4 *) echo bad one; return 1 ;; +5 esac && +6 ( +7 case "$(git ls-files)" in +8 two) echo pass two ;; +9 *) echo bad two; exit 1 ;; +10 esac +11 ) && +12 case "$(git ls-files)" in +13 dir/two"$LF"one) echo pass both ;; +14 *) echo bad; return 1 ;; +15 esac && +16 +17 for i in 1 2 3 4 ; do +18 git checkout main -b $i || return $? +19 test_commit $i $i $i tag$i || return $? +20 done diff --git a/t/chainlint/chain-break-return-exit.test b/t/chainlint/chain-break-return-exit.test new file mode 100644 index 0000000000..b6f519bb4d --- /dev/null +++ b/t/chainlint/chain-break-return-exit.test @@ -0,0 +1,25 @@ +test_expect_success 'chain-break-return-exit' ' +case "$(git ls-files)" in +one) echo pass one ;; +# LINT: broken &&-chain okay if explicit "return 1" signals failuire +*) echo bad one; return 1 ;; +esac && +( + case "$(git ls-files)" in + two) echo pass two ;; +# LINT: broken &&-chain okay if explicit "exit 1" signals failuire + *) echo bad two; exit 1 ;; + esac +) && +case "$(git ls-files)" in +dir/two"$LF"one) echo pass both ;; +# LINT: broken &&-chain okay if explicit "return 1" signals failuire +*) echo bad; return 1 ;; +esac && + +for i in 1 2 3 4 ; do +# LINT: broken &&-chain okay if explicit "return $?" signals failure + git checkout main -b $i || return $? + test_commit $i $i $i tag$i || return $? +done +' diff --git a/t/chainlint/chain-break-status.expect b/t/chainlint/chain-break-status.expect new file mode 100644 index 0000000000..23c0caa7d8 --- /dev/null +++ b/t/chainlint/chain-break-status.expect @@ -0,0 +1,9 @@ +2 OUT=$( ((large_git; echo $? 1>&3) | :) 3>&1 ) && +3 test_match_signal 13 "$OUT" && +4 +5 { test-tool sigchain >actual; ret=$?; } && +6 { +7 test_match_signal 15 "$ret" || +8 test "$ret" = 3 +9 } && +10 test_cmp expect actual diff --git a/t/chainlint/chain-break-status.test b/t/chainlint/chain-break-status.test new file mode 100644 index 0000000000..d9fee190d9 --- /dev/null +++ b/t/chainlint/chain-break-status.test @@ -0,0 +1,13 @@ +test_expect_success 'chain-break-status' ' +# LINT: broken &&-chain okay if next command handles "$?" explicitly +OUT=$( ((large_git; echo $? 1>&3) | :) 3>&1 ) && +test_match_signal 13 "$OUT" && + +# LINT: broken &&-chain okay if next command handles "$?" explicitly +{ test-tool sigchain >actual; ret=$?; } && +{ + test_match_signal 15 "$ret" || + test "$ret" = 3 +} && +test_cmp expect actual +' diff --git a/t/chainlint/chained-block.expect b/t/chainlint/chained-block.expect new file mode 100644 index 0000000000..f2501bba90 --- /dev/null +++ b/t/chainlint/chained-block.expect @@ -0,0 +1,9 @@ +2 echo nobody home && { +3 test the doohicky ?!LINT: missing '&&'?! +4 right now +5 } && +6 +7 GIT_EXTERNAL_DIFF=echo git diff | { +8 read path oldfile oldhex oldmode newfile newhex newmode && +9 test "z$oh" = "z$oldhex" +10 } diff --git a/t/chainlint/chained-block.test b/t/chainlint/chained-block.test new file mode 100644 index 0000000000..71ef1d0b7f --- /dev/null +++ b/t/chainlint/chained-block.test @@ -0,0 +1,13 @@ +test_expect_success 'chained-block' ' +# LINT: start of block chained to preceding command +echo nobody home && { + test the doohicky + right now +} && + +# LINT: preceding command pipes to block on same line +GIT_EXTERNAL_DIFF=echo git diff | { + read path oldfile oldhex oldmode newfile newhex newmode && + test "z$oh" = "z$oldhex" +} +' diff --git a/t/chainlint/chained-subshell.expect b/t/chainlint/chained-subshell.expect new file mode 100644 index 0000000000..93fb1a6578 --- /dev/null +++ b/t/chainlint/chained-subshell.expect @@ -0,0 +1,10 @@ +2 mkdir sub && ( +3 cd sub && +4 foo the bar ?!LINT: missing '&&'?! +5 nuff said +6 ) && +7 +8 cut "-d " -f actual | (read s1 s2 s3 && +9 test -f $s1 ?!LINT: missing '&&'?! +10 test $(cat $s2) = tree2path1 && +11 test $(cat $s3) = tree3path1) diff --git a/t/chainlint/chained-subshell.test b/t/chainlint/chained-subshell.test new file mode 100644 index 0000000000..1f11f65398 --- /dev/null +++ b/t/chainlint/chained-subshell.test @@ -0,0 +1,15 @@ +test_expect_success 'chained-subshell' ' +# LINT: start of subshell chained to preceding command +mkdir sub && ( + cd sub && + foo the bar + nuff said +) && + +# LINT: preceding command pipes to subshell on same line +cut "-d " -f actual | (read s1 s2 s3 && +test -f $s1 +test $(cat $s2) = tree2path1 && +# LINT: closing subshell ")" correctly detected on same line as "$(...)" +test $(cat $s3) = tree3path1) +' diff --git a/t/chainlint/close-nested-and-parent-together.expect b/t/chainlint/close-nested-and-parent-together.expect new file mode 100644 index 0000000000..4167e54a59 --- /dev/null +++ b/t/chainlint/close-nested-and-parent-together.expect @@ -0,0 +1,3 @@ +2 (cd foo && +3 (bar && +4 baz)) diff --git a/t/chainlint/close-nested-and-parent-together.test b/t/chainlint/close-nested-and-parent-together.test new file mode 100644 index 0000000000..56b28b186b --- /dev/null +++ b/t/chainlint/close-nested-and-parent-together.test @@ -0,0 +1,5 @@ +test_expect_success 'close-nested-and-parent-together' ' +(cd foo && + (bar && + baz)) +' diff --git a/t/chainlint/close-subshell.expect b/t/chainlint/close-subshell.expect new file mode 100644 index 0000000000..a272cfe72e --- /dev/null +++ b/t/chainlint/close-subshell.expect @@ -0,0 +1,26 @@ +2 ( +3 foo +4 ) && +5 ( +6 bar +7 ) >out && +8 ( +9 baz +10 ) 2>err && +11 ( +12 boo +13 ) <input && +14 ( +15 bip +16 ) | wuzzle && +17 ( +18 bop +19 ) | fazz \ +20 fozz && +21 ( +22 bup +23 ) | +24 fuzzle && +25 ( +26 yop +27 ) diff --git a/t/chainlint/close-subshell.test b/t/chainlint/close-subshell.test new file mode 100644 index 0000000000..b99f80569d --- /dev/null +++ b/t/chainlint/close-subshell.test @@ -0,0 +1,29 @@ +test_expect_success 'close-subshell' ' +# LINT: closing ")" with various decorations ("&&", ">", "|", etc.) +( + foo +) && +( + bar +) >out && +( + baz +) 2>err && +( + boo +) <input && +( + bip +) | wuzzle && +( + bop +) | fazz \ + fozz && +( + bup +) | +fuzzle && +( + yop +) +' diff --git a/t/chainlint/command-substitution-subsubshell.expect b/t/chainlint/command-substitution-subsubshell.expect new file mode 100644 index 0000000000..f2a9312dc8 --- /dev/null +++ b/t/chainlint/command-substitution-subsubshell.expect @@ -0,0 +1,2 @@ +2 OUT=$( ((large_git 1>&3) | :) 3>&1 ) && +3 test_match_signal 13 "$OUT" diff --git a/t/chainlint/command-substitution-subsubshell.test b/t/chainlint/command-substitution-subsubshell.test new file mode 100644 index 0000000000..4ea772d60a --- /dev/null +++ b/t/chainlint/command-substitution-subsubshell.test @@ -0,0 +1,5 @@ +test_expect_success 'command-substitution-subsubshell' ' +# LINT: subshell nested in subshell nested in command substitution +OUT=$( ((large_git 1>&3) | :) 3>&1 ) && +test_match_signal 13 "$OUT" +' diff --git a/t/chainlint/command-substitution.expect b/t/chainlint/command-substitution.expect new file mode 100644 index 0000000000..73809fd585 --- /dev/null +++ b/t/chainlint/command-substitution.expect @@ -0,0 +1,9 @@ +2 ( +3 foo && +4 bar=$(gobble) && +5 baz +6 ) && +7 ( +8 bar=$(gobble blocks) ?!LINT: missing '&&'?! +9 baz +10 ) diff --git a/t/chainlint/command-substitution.test b/t/chainlint/command-substitution.test new file mode 100644 index 0000000000..494d671e80 --- /dev/null +++ b/t/chainlint/command-substitution.test @@ -0,0 +1,13 @@ +test_expect_success 'command-substitution' ' +( + foo && +# LINT: closing ")" of $(...) not misinterpreted as subshell-closing ")" + bar=$(gobble) && + baz +) && +( +# LINT: missing "&&" on $(...) + bar=$(gobble blocks) + baz +) +' diff --git a/t/chainlint/comment.expect b/t/chainlint/comment.expect new file mode 100644 index 0000000000..584098d6ba --- /dev/null +++ b/t/chainlint/comment.expect @@ -0,0 +1,8 @@ +2 ( +3 # comment 1 +4 nothing && +5 # comment 2 +6 something +7 # comment 3 +8 # comment 4 +9 ) diff --git a/t/chainlint/comment.test b/t/chainlint/comment.test new file mode 100644 index 0000000000..c488beac0d --- /dev/null +++ b/t/chainlint/comment.test @@ -0,0 +1,13 @@ +test_expect_success 'comment' ' +( +# LINT: swallow comment lines + # comment 1 + nothing && + # comment 2 + something +# LINT: swallow comment lines since final _statement_ before subshell end is +# LINT: significant to "&&"-check, not final _line_ (which might be comment) + # comment 3 + # comment 4 +) +' diff --git a/t/chainlint/complex-if-in-cuddled-loop.expect b/t/chainlint/complex-if-in-cuddled-loop.expect new file mode 100644 index 0000000000..e66bb2d5d0 --- /dev/null +++ b/t/chainlint/complex-if-in-cuddled-loop.expect @@ -0,0 +1,9 @@ +2 (for i in a b c; do +3 if test "$(echo $(waffle bat))" = "eleventeen" && +4 test "$x" = "$y"; then +5 : +6 else +7 echo >file +8 fi ?!LINT: missing '|| exit 1'?! +9 done) && +10 test ! -f file diff --git a/t/chainlint/complex-if-in-cuddled-loop.test b/t/chainlint/complex-if-in-cuddled-loop.test new file mode 100644 index 0000000000..f98ae4c42d --- /dev/null +++ b/t/chainlint/complex-if-in-cuddled-loop.test @@ -0,0 +1,13 @@ +test_expect_success 'complex-if-in-cuddled-loop' ' +# LINT: "for" loop cuddled with "(" and ")" and nested "if" with complex +# LINT: multi-line condition; indented with spaces, not tabs +(for i in a b c; do + if test "$(echo $(waffle bat))" = "eleventeen" && + test "$x" = "$y"; then + : + else + echo >file + fi + done) && +test ! -f file +' diff --git a/t/chainlint/cuddled-if-then-else.expect b/t/chainlint/cuddled-if-then-else.expect new file mode 100644 index 0000000000..72da8794cb --- /dev/null +++ b/t/chainlint/cuddled-if-then-else.expect @@ -0,0 +1,6 @@ +2 (if test -z ""; then +3 echo empty +4 else +5 echo bizzy +6 fi) && +7 echo foobar diff --git a/t/chainlint/cuddled-if-then-else.test b/t/chainlint/cuddled-if-then-else.test new file mode 100644 index 0000000000..b1b42e1aac --- /dev/null +++ b/t/chainlint/cuddled-if-then-else.test @@ -0,0 +1,9 @@ +test_expect_success 'cuddled-if-then-else' ' +# LINT: "if" cuddled with "(" and ")"; indented with spaces, not tabs +(if test -z ""; then + echo empty + else + echo bizzy + fi) && +echo foobar +' diff --git a/t/chainlint/cuddled-loop.expect b/t/chainlint/cuddled-loop.expect new file mode 100644 index 0000000000..c38585c756 --- /dev/null +++ b/t/chainlint/cuddled-loop.expect @@ -0,0 +1,4 @@ +2 ( while read x +3 do foobar bop || exit 1 +4 done <file ) && +5 outside subshell diff --git a/t/chainlint/cuddled-loop.test b/t/chainlint/cuddled-loop.test new file mode 100644 index 0000000000..6fccb6ac22 --- /dev/null +++ b/t/chainlint/cuddled-loop.test @@ -0,0 +1,9 @@ +test_expect_success 'cuddled-loop' ' +# LINT: "while" loop cuddled with "(" and ")", with embedded (allowed) +# LINT: "|| exit {n}" to exit loop early, and using redirection "<" to feed +# LINT: loop; indented with spaces, not tabs +( while read x + do foobar bop || exit 1 + done <file ) && +outside subshell +' diff --git a/t/chainlint/cuddled.expect b/t/chainlint/cuddled.expect new file mode 100644 index 0000000000..1864b3fc8b --- /dev/null +++ b/t/chainlint/cuddled.expect @@ -0,0 +1,17 @@ +2 (cd foo && +3 bar +4 ) && +5 +6 (cd foo ?!LINT: missing '&&'?! +7 bar +8 ) && +9 +10 ( +11 cd foo && +12 bar) && +13 +14 (cd foo && +15 bar) && +16 +17 (cd foo ?!LINT: missing '&&'?! +18 bar) diff --git a/t/chainlint/cuddled.test b/t/chainlint/cuddled.test new file mode 100644 index 0000000000..5a6ef7a4a6 --- /dev/null +++ b/t/chainlint/cuddled.test @@ -0,0 +1,24 @@ +test_expect_success 'cuddled' ' +# LINT: first subshell statement cuddled with opening "(" +(cd foo && + bar +) && + +# LINT: same with missing "&&" +(cd foo + bar +) && + +# LINT: closing ")" cuddled with final subshell statement +( + cd foo && + bar) && + +# LINT: "(" and ")" cuddled with first and final subshell statements +(cd foo && + bar) && + +# LINT: same with missing "&&" +(cd foo + bar) +' diff --git a/t/chainlint/double-here-doc.expect b/t/chainlint/double-here-doc.expect new file mode 100644 index 0000000000..48c04ecd58 --- /dev/null +++ b/t/chainlint/double-here-doc.expect @@ -0,0 +1,12 @@ +2 run_sub_test_lib_test_err run-inv-range-start \ +3 "--run invalid range start" \ +4 --run="a-5" <<-\EOF && +5 test_expect_success "passing test #1" "true" +6 test_done +7 EOF +8 check_sub_test_lib_test_err run-inv-range-start \ +9 <<-\EOF_OUT 3<<-EOF_ERR +10 > FATAL: Unexpected exit with code 1 +11 EOF_OUT +12 > error: --run: invalid non-numeric in range start: ${SQ}a-5${SQ} +13 EOF_ERR diff --git a/t/chainlint/double-here-doc.test b/t/chainlint/double-here-doc.test new file mode 100644 index 0000000000..1b69b7a651 --- /dev/null +++ b/t/chainlint/double-here-doc.test @@ -0,0 +1,14 @@ +test_expect_success 'double-here-doc' ' +run_sub_test_lib_test_err run-inv-range-start \ + "--run invalid range start" \ + --run="a-5" <<-\EOF && +test_expect_success "passing test #1" "true" +test_done +EOF +check_sub_test_lib_test_err run-inv-range-start \ + <<-\EOF_OUT 3<<-EOF_ERR +> FATAL: Unexpected exit with code 1 +EOF_OUT +> error: --run: invalid non-numeric in range start: ${SQ}a-5${SQ} +EOF_ERR +' diff --git a/t/chainlint/dqstring-line-splice.expect b/t/chainlint/dqstring-line-splice.expect new file mode 100644 index 0000000000..2ca1c92cd6 --- /dev/null +++ b/t/chainlint/dqstring-line-splice.expect @@ -0,0 +1,5 @@ +2 +3 echo 'fatal: reword option of --fixup is mutually exclusive with' '--patch/--interactive/--all/--include/--only' >expect && +4 test_must_fail git commit --fixup=reword:HEAD~ $1 2>actual && +5 test_cmp expect actual +6 diff --git a/t/chainlint/dqstring-line-splice.test b/t/chainlint/dqstring-line-splice.test new file mode 100644 index 0000000000..f6aa637be8 --- /dev/null +++ b/t/chainlint/dqstring-line-splice.test @@ -0,0 +1,9 @@ +test_expect_success 'dqstring-line-splice' ' +# LINT: line-splice within DQ-string +'" +echo 'fatal: reword option of --fixup is mutually exclusive with'\ + '--patch/--interactive/--all/--include/--only' >expect && +test_must_fail git commit --fixup=reword:HEAD~ $1 2>actual && +test_cmp expect actual +"' +' diff --git a/t/chainlint/dqstring-no-interpolate.expect b/t/chainlint/dqstring-no-interpolate.expect new file mode 100644 index 0000000000..c9f75849c5 --- /dev/null +++ b/t/chainlint/dqstring-no-interpolate.expect @@ -0,0 +1,12 @@ +2 grep "^ ! [rejected][ ]*$BRANCH -> $BRANCH (non-fast-forward)$" out && +3 +4 grep "^\.git$" output.txt && +5 +6 +7 ( +8 cd client$version && +9 GIT_TEST_PROTOCOL_VERSION=$version git fetch-pack --no-progress .. $(cat ../input) +10 ) >output && +11 cut -d ' ' -f 2 <output | sort >actual && +12 test_cmp expect actual +13 diff --git a/t/chainlint/dqstring-no-interpolate.test b/t/chainlint/dqstring-no-interpolate.test new file mode 100644 index 0000000000..7ae079b558 --- /dev/null +++ b/t/chainlint/dqstring-no-interpolate.test @@ -0,0 +1,17 @@ +test_expect_success 'dqstring-no-interpolate' ' +# LINT: regex dollar-sign eol anchor in double-quoted string not special +grep "^ ! \[rejected\][ ]*$BRANCH -> $BRANCH (non-fast-forward)$" out && + +# LINT: escaped "$" not mistaken for variable expansion +grep "^\\.git\$" output.txt && + +'" +( + cd client$version && +# LINT: escaped dollar-sign in double-quoted test body + GIT_TEST_PROTOCOL_VERSION=$version git fetch-pack --no-progress .. \$(cat ../input) +) >output && + cut -d ' ' -f 2 <output | sort >actual && + test_cmp expect actual +"' +' diff --git a/t/chainlint/empty-here-doc.expect b/t/chainlint/empty-here-doc.expect new file mode 100644 index 0000000000..54b33f823a --- /dev/null +++ b/t/chainlint/empty-here-doc.expect @@ -0,0 +1,4 @@ +2 git ls-tree $tree path >current && +3 cat >expected <<\EOF && +4 EOF +5 test_output diff --git a/t/chainlint/empty-here-doc.test b/t/chainlint/empty-here-doc.test new file mode 100644 index 0000000000..8b7ab6eb5f --- /dev/null +++ b/t/chainlint/empty-here-doc.test @@ -0,0 +1,7 @@ +test_expect_success 'empty-here-doc' ' +git ls-tree $tree path >current && +# LINT: empty here-doc +cat >expected <<\EOF && +EOF +test_output +' diff --git a/t/chainlint/exclamation.expect b/t/chainlint/exclamation.expect new file mode 100644 index 0000000000..078744b61b --- /dev/null +++ b/t/chainlint/exclamation.expect @@ -0,0 +1,4 @@ +2 if ! condition; then echo nope; else yep; fi && +3 test_prerequisite !MINGW && +4 mail uucp!address && +5 echo !whatever! diff --git a/t/chainlint/exclamation.test b/t/chainlint/exclamation.test new file mode 100644 index 0000000000..796de21b7c --- /dev/null +++ b/t/chainlint/exclamation.test @@ -0,0 +1,10 @@ +test_expect_success 'exclamation' ' +# LINT: "! word" is two tokens +if ! condition; then echo nope; else yep; fi && +# LINT: "!word" is single token, not two tokens "!" and "word" +test_prerequisite !MINGW && +# LINT: "word!word" is single token, not three tokens "word", "!", and "word" +mail uucp!address && +# LINT: "!word!" is single token, not three tokens "!", "word", and "!" +echo !whatever! +' diff --git a/t/chainlint/exit-loop.expect b/t/chainlint/exit-loop.expect new file mode 100644 index 0000000000..407278094c --- /dev/null +++ b/t/chainlint/exit-loop.expect @@ -0,0 +1,24 @@ +2 ( +3 for i in a b c +4 do +5 foo || exit 1 +6 bar && +7 baz +8 done +9 ) && +10 ( +11 while true +12 do +13 foo || exit 1 +14 bar && +15 baz +16 done +17 ) && +18 ( +19 i=0 && +20 while test $i -lt 10 +21 do +22 echo $i || exit +23 i=$(($i + 1)) +24 done +25 ) diff --git a/t/chainlint/exit-loop.test b/t/chainlint/exit-loop.test new file mode 100644 index 0000000000..7e8b68b465 --- /dev/null +++ b/t/chainlint/exit-loop.test @@ -0,0 +1,29 @@ +test_expect_success 'exit-loop' ' +( + for i in a b c + do +# LINT: "|| exit {n}" valid for-loop escape in subshell; no "&&" needed + foo || exit 1 + bar && + baz + done +) && +( + while true + do +# LINT: "|| exit {n}" valid while-loop escape in subshell; no "&&" needed + foo || exit 1 + bar && + baz + done +) && +( + i=0 && + while test $i -lt 10 + do +# LINT: "|| exit" (sans exit code) valid escape in subshell; no "&&" needed + echo $i || exit + i=$(($i + 1)) + done +) +' diff --git a/t/chainlint/exit-subshell.expect b/t/chainlint/exit-subshell.expect new file mode 100644 index 0000000000..793db12453 --- /dev/null +++ b/t/chainlint/exit-subshell.expect @@ -0,0 +1,5 @@ +2 ( +3 foo || exit 1 +4 bar && +5 baz +6 ) diff --git a/t/chainlint/exit-subshell.test b/t/chainlint/exit-subshell.test new file mode 100644 index 0000000000..05dff55cd7 --- /dev/null +++ b/t/chainlint/exit-subshell.test @@ -0,0 +1,8 @@ +test_expect_success 'exit-subshell' ' +( +# LINT: "|| exit {n}" valid subshell escape without hurting &&-chain + foo || exit 1 + bar && + baz +) +' diff --git a/t/chainlint/for-loop-abbreviated.expect b/t/chainlint/for-loop-abbreviated.expect new file mode 100644 index 0000000000..5574831976 --- /dev/null +++ b/t/chainlint/for-loop-abbreviated.expect @@ -0,0 +1,5 @@ +2 for it +3 do +4 path=$(expr "$it" : ([^:]*)) && +5 git update-index --add "$path" || exit +6 done diff --git a/t/chainlint/for-loop-abbreviated.test b/t/chainlint/for-loop-abbreviated.test new file mode 100644 index 0000000000..1dd14f2a44 --- /dev/null +++ b/t/chainlint/for-loop-abbreviated.test @@ -0,0 +1,8 @@ +test_expect_success 'for-loop-abbreviated' ' +# LINT: for-loop lacking optional "in [word...]" before "do" +for it +do + path=$(expr "$it" : '\([^:]*\)') && + git update-index --add "$path" || exit +done +' diff --git a/t/chainlint/for-loop.expect b/t/chainlint/for-loop.expect new file mode 100644 index 0000000000..5029eacce3 --- /dev/null +++ b/t/chainlint/for-loop.expect @@ -0,0 +1,14 @@ +2 ( +3 for i in a b c +4 do +5 echo $i ?!LINT: missing '&&'?! +6 cat <<-\EOF ?!LINT: missing '|| exit 1'?! +7 bar +8 EOF +9 done ?!LINT: missing '&&'?! +10 +11 for i in a b c; do +12 echo $i && +13 cat $i ?!LINT: missing '|| exit 1'?! +14 done +15 ) diff --git a/t/chainlint/for-loop.test b/t/chainlint/for-loop.test new file mode 100644 index 0000000000..6f2489eb19 --- /dev/null +++ b/t/chainlint/for-loop.test @@ -0,0 +1,21 @@ +test_expect_success 'for-loop' ' +( +# LINT: "for", "do", "done" do not need "&&" + for i in a b c + do +# LINT: missing "&&" on "echo" + echo $i +# LINT: last statement of while does not need "&&" + cat <<-\EOF + bar + EOF +# LINT: missing "&&" on "done" + done + +# LINT: "do" on same line as "for" + for i in a b c; do + echo $i && + cat $i + done +) +' diff --git a/t/chainlint/function.expect b/t/chainlint/function.expect new file mode 100644 index 0000000000..9e46a3554a --- /dev/null +++ b/t/chainlint/function.expect @@ -0,0 +1,11 @@ +2 sha1_file() { +3 echo "$*" | sed "s#..#.git/objects/&/#" +4 } && +5 +6 remove_object() { +7 file=$(sha1_file "$*") && +8 test -e "$file" ?!LINT: missing '&&'?! +9 rm -f "$file" +10 } ?!LINT: missing '&&'?! +11 +12 sha1_file arg && remove_object arg diff --git a/t/chainlint/function.test b/t/chainlint/function.test new file mode 100644 index 0000000000..763fcf3f87 --- /dev/null +++ b/t/chainlint/function.test @@ -0,0 +1,15 @@ +test_expect_success 'function' ' +# LINT: "()" in function definition not mistaken for subshell +sha1_file() { + echo "$*" | sed "s#..#.git/objects/&/#" +} && + +# LINT: broken &&-chain in function and after function +remove_object() { + file=$(sha1_file "$*") && + test -e "$file" + rm -f "$file" +} + +sha1_file arg && remove_object arg +' diff --git a/t/chainlint/here-doc-body-indent.expect b/t/chainlint/here-doc-body-indent.expect new file mode 100644 index 0000000000..4306faee86 --- /dev/null +++ b/t/chainlint/here-doc-body-indent.expect @@ -0,0 +1,2 @@ +2 echo "we should find this" ?!LINT: missing '&&'?! +3 echo "even though our heredoc has its indent stripped" diff --git a/t/chainlint/here-doc-body-indent.test b/t/chainlint/here-doc-body-indent.test new file mode 100644 index 0000000000..39ff970ef3 --- /dev/null +++ b/t/chainlint/here-doc-body-indent.test @@ -0,0 +1,4 @@ +test_expect_success 'here-doc-body-indent' - <<-\EOT + echo "we should find this" + echo "even though our heredoc has its indent stripped" +EOT diff --git a/t/chainlint/here-doc-body-pathological.expect b/t/chainlint/here-doc-body-pathological.expect new file mode 100644 index 0000000000..2f8ea03a47 --- /dev/null +++ b/t/chainlint/here-doc-body-pathological.expect @@ -0,0 +1,7 @@ +2 echo "outer here-doc does not allow indented end-tag" ?!LINT: missing '&&'?! +3 cat >file <<-\EOF && +4 but this inner here-doc +5 does allow indented EOF +6 EOF +7 echo "missing chain after" ?!LINT: missing '&&'?! +8 echo "but this line is OK because it's the end" diff --git a/t/chainlint/here-doc-body-pathological.test b/t/chainlint/here-doc-body-pathological.test new file mode 100644 index 0000000000..7d2daa44f9 --- /dev/null +++ b/t/chainlint/here-doc-body-pathological.test @@ -0,0 +1,9 @@ +test_expect_success 'here-doc-body-pathological' - <<\EOF + echo "outer here-doc does not allow indented end-tag" + cat >file <<-\EOF && + but this inner here-doc + does allow indented EOF + EOF + echo "missing chain after" + echo "but this line is OK because it's the end" +EOF diff --git a/t/chainlint/here-doc-body.expect b/t/chainlint/here-doc-body.expect new file mode 100644 index 0000000000..df8d79bc0a --- /dev/null +++ b/t/chainlint/here-doc-body.expect @@ -0,0 +1,7 @@ +2 echo "missing chain before" ?!LINT: missing '&&'?! +3 cat >file <<-\EOF && +4 inside inner here-doc +5 these are not shell commands +6 EOF +7 echo "missing chain after" ?!LINT: missing '&&'?! +8 echo "but this line is OK because it's the end" diff --git a/t/chainlint/here-doc-body.test b/t/chainlint/here-doc-body.test new file mode 100644 index 0000000000..989ac2f4e1 --- /dev/null +++ b/t/chainlint/here-doc-body.test @@ -0,0 +1,9 @@ +test_expect_success 'here-doc-body' - <<\EOT + echo "missing chain before" + cat >file <<-\EOF && + inside inner here-doc + these are not shell commands + EOF + echo "missing chain after" + echo "but this line is OK because it's the end" +EOT diff --git a/t/chainlint/here-doc-close-subshell.expect b/t/chainlint/here-doc-close-subshell.expect new file mode 100644 index 0000000000..965813f463 --- /dev/null +++ b/t/chainlint/here-doc-close-subshell.expect @@ -0,0 +1,4 @@ +2 ( +3 cat <<-\INPUT) +4 fizz +5 INPUT diff --git a/t/chainlint/here-doc-close-subshell.test b/t/chainlint/here-doc-close-subshell.test new file mode 100644 index 0000000000..2458f3323b --- /dev/null +++ b/t/chainlint/here-doc-close-subshell.test @@ -0,0 +1,7 @@ +test_expect_success 'here-doc-close-subshell' ' +( +# LINT: line contains here-doc and closes nested subshell + cat <<-\INPUT) + fizz + INPUT +' diff --git a/t/chainlint/here-doc-double.expect b/t/chainlint/here-doc-double.expect new file mode 100644 index 0000000000..e5e981889f --- /dev/null +++ b/t/chainlint/here-doc-double.expect @@ -0,0 +1,2 @@ +8 echo "actual test commands" ?!LINT: missing '&&'?! +9 echo "that should be checked" diff --git a/t/chainlint/here-doc-double.test b/t/chainlint/here-doc-double.test new file mode 100644 index 0000000000..777389f0d9 --- /dev/null +++ b/t/chainlint/here-doc-double.test @@ -0,0 +1,10 @@ +# This is obviously a ridiculous thing to do, but we should be able +# to handle two here-docs on the same line, and attribute them +# correctly. +test_expect_success "$(cat <<END_OF_PREREQS)" 'here-doc-double' - <<\EOT +SOME +PREREQS +END_OF_PREREQS + echo "actual test commands" + echo "that should be checked" +EOT diff --git a/t/chainlint/here-doc-indent-operator.expect b/t/chainlint/here-doc-indent-operator.expect new file mode 100644 index 0000000000..ec0e61505b --- /dev/null +++ b/t/chainlint/here-doc-indent-operator.expect @@ -0,0 +1,11 @@ +2 cat >expect <<- EOF && +3 header: 43475048 1 $(test_oid oid_version) $NUM_CHUNKS 0 +4 num_commits: $1 +5 chunks: oid_fanout oid_lookup commit_metadata generation_data bloom_indexes bloom_data +6 EOF +7 +8 cat >expect << -EOF ?!LINT: missing '&&'?! +9 this is not indented +10 -EOF +11 +12 cleanup diff --git a/t/chainlint/here-doc-indent-operator.test b/t/chainlint/here-doc-indent-operator.test new file mode 100644 index 0000000000..a2656f47c1 --- /dev/null +++ b/t/chainlint/here-doc-indent-operator.test @@ -0,0 +1,15 @@ +test_expect_success 'here-doc-indent-operator' ' +# LINT: whitespace between operator "<<-" and tag legal +cat >expect <<- EOF && +header: 43475048 1 $(test_oid oid_version) $NUM_CHUNKS 0 +num_commits: $1 +chunks: oid_fanout oid_lookup commit_metadata generation_data bloom_indexes bloom_data +EOF + +# LINT: not an indented here-doc; just a plain here-doc with tag named "-EOF" +cat >expect << -EOF +this is not indented +-EOF + +cleanup +' diff --git a/t/chainlint/here-doc-multi-line-command-subst.expect b/t/chainlint/here-doc-multi-line-command-subst.expect new file mode 100644 index 0000000000..8128f15b92 --- /dev/null +++ b/t/chainlint/here-doc-multi-line-command-subst.expect @@ -0,0 +1,8 @@ +2 ( +3 x=$(bobble <<-\END && +4 fossil +5 vegetable +6 END +7 wiffle) ?!LINT: missing '&&'?! +8 echo $x +9 ) diff --git a/t/chainlint/here-doc-multi-line-command-subst.test b/t/chainlint/here-doc-multi-line-command-subst.test new file mode 100644 index 0000000000..8710a8c483 --- /dev/null +++ b/t/chainlint/here-doc-multi-line-command-subst.test @@ -0,0 +1,11 @@ +test_expect_success 'here-doc-multi-line-command-subst' ' +( +# LINT: line contains here-doc and opens multi-line $(...) + x=$(bobble <<-\END && + fossil + vegetable + END + wiffle) + echo $x +) +' diff --git a/t/chainlint/here-doc-multi-line-string.expect b/t/chainlint/here-doc-multi-line-string.expect new file mode 100644 index 0000000000..a03a04ff3d --- /dev/null +++ b/t/chainlint/here-doc-multi-line-string.expect @@ -0,0 +1,7 @@ +2 ( +3 cat <<-\TXT && echo "multi-line +4 string" ?!LINT: missing '&&'?! +5 fizzle +6 TXT +7 bap +8 ) diff --git a/t/chainlint/here-doc-multi-line-string.test b/t/chainlint/here-doc-multi-line-string.test new file mode 100644 index 0000000000..2f496002fd --- /dev/null +++ b/t/chainlint/here-doc-multi-line-string.test @@ -0,0 +1,10 @@ +test_expect_success 'here-doc-multi-line-string' ' +( +# LINT: line contains here-doc and opens multi-line string + cat <<-\TXT && echo "multi-line + string" + fizzle + TXT + bap +) +' diff --git a/t/chainlint/here-doc.expect b/t/chainlint/here-doc.expect new file mode 100644 index 0000000000..2c382dd8eb --- /dev/null +++ b/t/chainlint/here-doc.expect @@ -0,0 +1,25 @@ +2 boodle wobba \ +3 gorgo snoot \ +4 wafta snurb <<EOF && +5 quoth the raven, +6 nevermore... +7 EOF +8 +9 cat <<-Arbitrary_Tag_42 >foo && +10 snoz +11 boz +12 woz +13 Arbitrary_Tag_42 +14 +15 cat <<"zump" >boo && +16 snoz +17 boz +18 woz +19 zump +20 +21 horticulture <<\EOF +22 gomez +23 morticia +24 wednesday +25 pugsly +26 EOF diff --git a/t/chainlint/here-doc.test b/t/chainlint/here-doc.test new file mode 100644 index 0000000000..c91b695319 --- /dev/null +++ b/t/chainlint/here-doc.test @@ -0,0 +1,32 @@ +test_expect_success 'here-doc' ' +# LINT: stitch together incomplete \-ending lines +# LINT: swallow here-doc to avoid false positives in content +boodle wobba \ + gorgo snoot \ + wafta snurb <<EOF && +quoth the raven, +nevermore... +EOF + +# LINT: swallow here-doc with arbitrary tag +cat <<-Arbitrary_Tag_42 >foo && +snoz +boz +woz +Arbitrary_Tag_42 + +# LINT: swallow "quoted" here-doc +cat <<"zump" >boo && +snoz +boz +woz +zump + +# LINT: swallow here-doc (EOF is last line of test) +horticulture <<\EOF +gomez +morticia +wednesday +pugsly +EOF +' diff --git a/t/chainlint/if-condition-split.expect b/t/chainlint/if-condition-split.expect new file mode 100644 index 0000000000..6d2a03dfdb --- /dev/null +++ b/t/chainlint/if-condition-split.expect @@ -0,0 +1,7 @@ +2 if bob && +3 marcia || +4 kevin +5 then +6 echo "nomads" ?!LINT: missing '&&'?! +7 echo "for sure" +8 fi diff --git a/t/chainlint/if-condition-split.test b/t/chainlint/if-condition-split.test new file mode 100644 index 0000000000..9a3b3ed04a --- /dev/null +++ b/t/chainlint/if-condition-split.test @@ -0,0 +1,10 @@ +test_expect_success 'if-condition-split' ' +# LINT: "if" condition split across multiple lines at "&&" or "||" +if bob && + marcia || + kevin +then + echo "nomads" + echo "for sure" +fi +' diff --git a/t/chainlint/if-in-loop.expect b/t/chainlint/if-in-loop.expect new file mode 100644 index 0000000000..7e3ba740de --- /dev/null +++ b/t/chainlint/if-in-loop.expect @@ -0,0 +1,12 @@ +2 ( +3 for i in a b c +4 do +5 if false +6 then +7 echo "err" +8 exit 1 +9 fi ?!LINT: missing '&&'?! +10 foo +11 done ?!LINT: missing '&&'?! +12 bar +13 ) diff --git a/t/chainlint/if-in-loop.test b/t/chainlint/if-in-loop.test new file mode 100644 index 0000000000..5be9d1cfa5 --- /dev/null +++ b/t/chainlint/if-in-loop.test @@ -0,0 +1,17 @@ +test_expect_success 'if-in-loop' ' +( + for i in a b c + do + if false + then +# LINT: missing "&&" on "echo" okay since "exit 1" signals error explicitly + echo "err" + exit 1 +# LINT: missing "&&" on "fi" + fi + foo +# LINT: missing "&&" on "done" + done + bar +) +' diff --git a/t/chainlint/if-then-else.expect b/t/chainlint/if-then-else.expect new file mode 100644 index 0000000000..924caa2e4e --- /dev/null +++ b/t/chainlint/if-then-else.expect @@ -0,0 +1,22 @@ +2 ( +3 if test -n "" +4 then +5 echo very ?!LINT: missing '&&'?! +6 echo empty +7 elif test -z "" +8 then +9 echo foo +10 else +11 echo foo && +12 cat <<-\EOF +13 bar +14 EOF +15 fi ?!LINT: missing '&&'?! +16 echo poodle +17 ) && +18 ( +19 if test -n ""; then +20 echo very && +21 echo empty +22 fi +23 ) diff --git a/t/chainlint/if-then-else.test b/t/chainlint/if-then-else.test new file mode 100644 index 0000000000..6582a7f440 --- /dev/null +++ b/t/chainlint/if-then-else.test @@ -0,0 +1,31 @@ +test_expect_success 'if-then-else' ' +( +# LINT: "if", "then", "elif", "else", "fi" do not need "&&" + if test -n "" + then +# LINT: missing "&&" on "echo" + echo very +# LINT: last statement before "elif" does not need "&&" + echo empty + elif test -z "" + then +# LINT: last statement before "else" does not need "&&" + echo foo + else + echo foo && +# LINT: last statement before "fi" does not need "&&" + cat <<-\EOF + bar + EOF +# LINT: missing "&&" on "fi" + fi + echo poodle +) && +( +# LINT: "then" on same line as "if" + if test -n ""; then + echo very && + echo empty + fi +) +' diff --git a/t/chainlint/incomplete-line.expect b/t/chainlint/incomplete-line.expect new file mode 100644 index 0000000000..b15e00b901 --- /dev/null +++ b/t/chainlint/incomplete-line.expect @@ -0,0 +1,10 @@ +2 line 1 \ +3 line 2 \ +4 line 3 \ +5 line 4 && +6 ( +7 line 5 \ +8 line 6 \ +9 line 7 \ +10 line 8 +11 ) diff --git a/t/chainlint/incomplete-line.test b/t/chainlint/incomplete-line.test new file mode 100644 index 0000000000..74a93021eb --- /dev/null +++ b/t/chainlint/incomplete-line.test @@ -0,0 +1,14 @@ +test_expect_success 'incomplete-line' ' +# LINT: stitch together all incomplete \-ending lines +line 1 \ +line 2 \ +line 3 \ +line 4 && +( +# LINT: stitch together all incomplete \-ending lines (subshell) + line 5 \ + line 6 \ + line 7 \ + line 8 +) +' diff --git a/t/chainlint/inline-comment.expect b/t/chainlint/inline-comment.expect new file mode 100644 index 0000000000..4b4080124e --- /dev/null +++ b/t/chainlint/inline-comment.expect @@ -0,0 +1,8 @@ +2 ( +3 foobar && # comment 1 +4 barfoo ?!LINT: missing '&&'?! # wrong position for && +5 flibble "not a # comment" +6 ) && +7 +8 (cd foo && +9 flibble "not a # comment") diff --git a/t/chainlint/inline-comment.test b/t/chainlint/inline-comment.test new file mode 100644 index 0000000000..4fbbf1058a --- /dev/null +++ b/t/chainlint/inline-comment.test @@ -0,0 +1,14 @@ +test_expect_success 'inline-comment' ' +( +# LINT: swallow inline comment (leaving command intact) + foobar && # comment 1 +# LINT: mispositioned "&&" (correctly) swallowed with comment + barfoo # wrong position for && +# LINT: "#" in string not misinterpreted as comment + flibble "not a # comment" +) && + +# LINT: "#" in string in cuddled subshell not misinterpreted as comment +(cd foo && + flibble "not a # comment") +' diff --git a/t/chainlint/loop-detect-failure.expect b/t/chainlint/loop-detect-failure.expect new file mode 100644 index 0000000000..7d846b878d --- /dev/null +++ b/t/chainlint/loop-detect-failure.expect @@ -0,0 +1,15 @@ +2 git init r1 && +3 for n in 1 2 3 4 5 +4 do +5 echo "This is file: $n" > r1/file.$n && +6 git -C r1 add file.$n && +7 git -C r1 commit -m "$n" || return 1 +8 done && +9 +10 git init r2 && +11 for n in 1000 10000 +12 do +13 printf "%"$n"s" X > r2/large.$n && +14 git -C r2 add large.$n && +15 git -C r2 commit -m "$n" ?!LINT: missing '|| return 1'?! +16 done diff --git a/t/chainlint/loop-detect-failure.test b/t/chainlint/loop-detect-failure.test new file mode 100644 index 0000000000..44673aa394 --- /dev/null +++ b/t/chainlint/loop-detect-failure.test @@ -0,0 +1,19 @@ +test_expect_success 'loop-detect-failure' ' +git init r1 && +# LINT: loop handles failure explicitly with "|| return 1" +for n in 1 2 3 4 5 +do + echo "This is file: $n" > r1/file.$n && + git -C r1 add file.$n && + git -C r1 commit -m "$n" || return 1 +done && + +git init r2 && +# LINT: loop fails to handle failure explicitly with "|| return 1" +for n in 1000 10000 +do + printf "%"$n"s" X > r2/large.$n && + git -C r2 add large.$n && + git -C r2 commit -m "$n" +done +' diff --git a/t/chainlint/loop-detect-status.expect b/t/chainlint/loop-detect-status.expect new file mode 100644 index 0000000000..0f180b08de --- /dev/null +++ b/t/chainlint/loop-detect-status.expect @@ -0,0 +1,18 @@ +2 (while test $i -le $blobcount +3 do +4 printf "Generating blob $i/$blobcount\r" >&2 && +5 printf "blob\nmark :$i\ndata $blobsize\n" && +6 #test-tool genrandom $i $blobsize && +7 printf "%-${blobsize}s" $i && +8 echo "M 100644 :$i $i" >> commit && +9 i=$(($i+1)) || +10 echo $? > exit-status +11 done && +12 echo "commit refs/heads/main" && +13 echo "author A U Thor <author@email.com> 123456789 +0000" && +14 echo "committer C O Mitter <committer@email.com> 123456789 +0000" && +15 echo "data 5" && +16 echo ">2gb" && +17 cat commit) | +18 git fast-import --big-file-threshold=2 && +19 test ! -f exit-status diff --git a/t/chainlint/loop-detect-status.test b/t/chainlint/loop-detect-status.test new file mode 100644 index 0000000000..8b639be073 --- /dev/null +++ b/t/chainlint/loop-detect-status.test @@ -0,0 +1,21 @@ +test_expect_success 'loop-detect-status' ' +# LINT: "$?" handled explicitly within loop body +(while test $i -le $blobcount + do + printf "Generating blob $i/$blobcount\r" >&2 && + printf "blob\nmark :$i\ndata $blobsize\n" && + #test-tool genrandom $i $blobsize && + printf "%-${blobsize}s" $i && + echo "M 100644 :$i $i" >> commit && + i=$(($i+1)) || + echo $? > exit-status + done && + echo "commit refs/heads/main" && + echo "author A U Thor <author@email.com> 123456789 +0000" && + echo "committer C O Mitter <committer@email.com> 123456789 +0000" && + echo "data 5" && + echo ">2gb" && + cat commit) | +git fast-import --big-file-threshold=2 && +test ! -f exit-status +' diff --git a/t/chainlint/loop-in-if.expect b/t/chainlint/loop-in-if.expect new file mode 100644 index 0000000000..32e076ad1b --- /dev/null +++ b/t/chainlint/loop-in-if.expect @@ -0,0 +1,12 @@ +2 ( +3 if true +4 then +5 while true +6 do +7 echo "pop" ?!LINT: missing '&&'?! +8 echo "glup" ?!LINT: missing '|| exit 1'?! +9 done ?!LINT: missing '&&'?! +10 foo +11 fi ?!LINT: missing '&&'?! +12 bar +13 ) diff --git a/t/chainlint/loop-in-if.test b/t/chainlint/loop-in-if.test new file mode 100644 index 0000000000..b0d0d393cf --- /dev/null +++ b/t/chainlint/loop-in-if.test @@ -0,0 +1,17 @@ +test_expect_success 'loop-in-if' ' +( + if true + then + while true + do +# LINT: missing "&&" on "echo" + echo "pop" + echo "glup" +# LINT: missing "&&" on "done" + done + foo +# LINT: missing "&&" on "fi" + fi + bar +) +' diff --git a/t/chainlint/loop-upstream-pipe.expect b/t/chainlint/loop-upstream-pipe.expect new file mode 100644 index 0000000000..bef82479ca --- /dev/null +++ b/t/chainlint/loop-upstream-pipe.expect @@ -0,0 +1,10 @@ +2 ( +3 git rev-list --objects --no-object-names base..loose | +4 while read oid +5 do +6 path="$objdir/$(test_oid_to_path "$oid")" && +7 printf "%s %d\n" "$oid" "$(test-tool chmtime --get "$path")" || +8 echo "object list generation failed for $oid" +9 done | +10 sort -k1 +11 ) >expect && diff --git a/t/chainlint/loop-upstream-pipe.test b/t/chainlint/loop-upstream-pipe.test new file mode 100644 index 0000000000..8415a4db27 --- /dev/null +++ b/t/chainlint/loop-upstream-pipe.test @@ -0,0 +1,13 @@ +test_expect_success 'loop-upstream-pipe' ' +( + git rev-list --objects --no-object-names base..loose | + while read oid + do +# LINT: "|| echo" signals failure in loop upstream of a pipe + path="$objdir/$(test_oid_to_path "$oid")" && + printf "%s %d\n" "$oid" "$(test-tool chmtime --get "$path")" || + echo "object list generation failed for $oid" + done | + sort -k1 +) >expect && +' diff --git a/t/chainlint/multi-line-nested-command-substitution.expect b/t/chainlint/multi-line-nested-command-substitution.expect new file mode 100644 index 0000000000..ad27e43e05 --- /dev/null +++ b/t/chainlint/multi-line-nested-command-substitution.expect @@ -0,0 +1,18 @@ +2 ( +3 foo && +4 x=$( +5 echo bar | +6 cat +7 ) && +8 echo ok +9 ) | +10 sort && +11 ( +12 bar && +13 x=$(echo bar | +14 cat +15 ) && +16 y=$(echo baz | +17 fip) && +18 echo fail +19 ) diff --git a/t/chainlint/multi-line-nested-command-substitution.test b/t/chainlint/multi-line-nested-command-substitution.test new file mode 100644 index 0000000000..e811c63f2b --- /dev/null +++ b/t/chainlint/multi-line-nested-command-substitution.test @@ -0,0 +1,20 @@ +test_expect_success 'multi-line-nested-command-substitution' ' +( + foo && + x=$( + echo bar | + cat + ) && + echo ok +) | +sort && +( + bar && + x=$(echo bar | + cat + ) && + y=$(echo baz | + fip) && + echo fail +) +' diff --git a/t/chainlint/multi-line-string.expect b/t/chainlint/multi-line-string.expect new file mode 100644 index 0000000000..9d33297525 --- /dev/null +++ b/t/chainlint/multi-line-string.expect @@ -0,0 +1,14 @@ +2 ( +3 x="line 1 +4 line 2 +5 line 3" && +6 y="line 1 +7 line2" ?!LINT: missing '&&'?! +8 foobar +9 ) && +10 ( +11 echo "xyz" "abc +12 def +13 ghi" && +14 barfoo +15 ) diff --git a/t/chainlint/multi-line-string.test b/t/chainlint/multi-line-string.test new file mode 100644 index 0000000000..7b5048d2ea --- /dev/null +++ b/t/chainlint/multi-line-string.test @@ -0,0 +1,17 @@ +test_expect_success 'multi-line-string' ' +( + x="line 1 + line 2 + line 3" && +# LINT: missing "&&" on assignment + y="line 1 + line2" + foobar +) && +( + echo "xyz" "abc + def + ghi" && + barfoo +) +' diff --git a/t/chainlint/negated-one-liner.expect b/t/chainlint/negated-one-liner.expect new file mode 100644 index 0000000000..0a6f3c29b2 --- /dev/null +++ b/t/chainlint/negated-one-liner.expect @@ -0,0 +1,5 @@ +2 ! (foo && bar) && +3 ! (foo && bar) >baz && +4 +5 ! (foo; ?!LINT: missing '&&'?! bar) && +6 ! (foo; ?!LINT: missing '&&'?! bar) >baz diff --git a/t/chainlint/negated-one-liner.test b/t/chainlint/negated-one-liner.test new file mode 100644 index 0000000000..30f4cc5a9b --- /dev/null +++ b/t/chainlint/negated-one-liner.test @@ -0,0 +1,9 @@ +test_expect_success 'negated-one-liner' ' +# LINT: top-level one-liner subshell +! (foo && bar) && +! (foo && bar) >baz && + +# LINT: top-level one-liner subshell missing internal "&&" +! (foo; bar) && +! (foo; bar) >baz +' diff --git a/t/chainlint/nested-cuddled-subshell.expect b/t/chainlint/nested-cuddled-subshell.expect new file mode 100644 index 0000000000..fec2c74274 --- /dev/null +++ b/t/chainlint/nested-cuddled-subshell.expect @@ -0,0 +1,25 @@ +2 ( +3 (cd foo && +4 bar +5 ) && +6 +7 (cd foo && +8 bar +9 ) ?!LINT: missing '&&'?! +10 +11 ( +12 cd foo && +13 bar) && +14 +15 ( +16 cd foo && +17 bar) ?!LINT: missing '&&'?! +18 +19 (cd foo && +20 bar) && +21 +22 (cd foo && +23 bar) ?!LINT: missing '&&'?! +24 +25 foobar +26 ) diff --git a/t/chainlint/nested-cuddled-subshell.test b/t/chainlint/nested-cuddled-subshell.test new file mode 100644 index 0000000000..31e92d3be4 --- /dev/null +++ b/t/chainlint/nested-cuddled-subshell.test @@ -0,0 +1,33 @@ +test_expect_success 'nested-cuddled-subshell' ' +( +# LINT: opening "(" cuddled with first nested subshell statement + (cd foo && + bar + ) && + +# LINT: same but "&&" missing + (cd foo && + bar + ) + +# LINT: closing ")" cuddled with final nested subshell statement + ( + cd foo && + bar) && + +# LINT: same but "&&" missing + ( + cd foo && + bar) + +# LINT: "(" and ")" cuddled with first and final subshell statements + (cd foo && + bar) && + +# LINT: same but "&&" missing + (cd foo && + bar) + + foobar +) +' diff --git a/t/chainlint/nested-here-doc.expect b/t/chainlint/nested-here-doc.expect new file mode 100644 index 0000000000..571f4c9514 --- /dev/null +++ b/t/chainlint/nested-here-doc.expect @@ -0,0 +1,30 @@ +2 cat <<ARBITRARY >foop && +3 naddle +4 fub <<EOF +5 nozzle +6 noodle +7 EOF +8 formp +9 ARBITRARY +10 +11 ( +12 cat <<-\INPUT_END && +13 fish are mice +14 but geese go slow +15 data <<EOF +16 perl is lerp +17 and nothing else +18 EOF +19 toink +20 INPUT_END +21 +22 cat <<-\EOT ?!LINT: missing '&&'?! +23 text goes here +24 data <<EOF +25 data goes here +26 EOF +27 more test here +28 EOT +29 +30 foobar +31 ) diff --git a/t/chainlint/nested-here-doc.test b/t/chainlint/nested-here-doc.test new file mode 100644 index 0000000000..9505c47a34 --- /dev/null +++ b/t/chainlint/nested-here-doc.test @@ -0,0 +1,35 @@ +test_expect_success 'nested-here-doc' ' +# LINT: inner "EOF" not misintrepreted as closing ARBITRARY here-doc +cat <<ARBITRARY >foop && +naddle +fub <<EOF + nozzle + noodle +EOF +formp +ARBITRARY + +( +# LINT: inner "EOF" not misintrepreted as closing INPUT_END here-doc + cat <<-\INPUT_END && + fish are mice + but geese go slow + data <<EOF + perl is lerp + and nothing else + EOF + toink + INPUT_END + +# LINT: same but missing "&&" + cat <<-\EOT + text goes here + data <<EOF + data goes here + EOF + more test here + EOT + + foobar +) +' diff --git a/t/chainlint/nested-loop-detect-failure.expect b/t/chainlint/nested-loop-detect-failure.expect new file mode 100644 index 0000000000..b4aaa621a2 --- /dev/null +++ b/t/chainlint/nested-loop-detect-failure.expect @@ -0,0 +1,31 @@ +2 for i in 0 1 2 3 4 5 6 7 8 9; +3 do +4 for j in 0 1 2 3 4 5 6 7 8 9; +5 do +6 echo "$i$j" >"path$i$j" ?!LINT: missing '|| return 1'?! +7 done ?!LINT: missing '|| return 1'?! +8 done && +9 +10 for i in 0 1 2 3 4 5 6 7 8 9; +11 do +12 for j in 0 1 2 3 4 5 6 7 8 9; +13 do +14 echo "$i$j" >"path$i$j" || return 1 +15 done +16 done && +17 +18 for i in 0 1 2 3 4 5 6 7 8 9; +19 do +20 for j in 0 1 2 3 4 5 6 7 8 9; +21 do +22 echo "$i$j" >"path$i$j" ?!LINT: missing '|| return 1'?! +23 done || return 1 +24 done && +25 +26 for i in 0 1 2 3 4 5 6 7 8 9; +27 do +28 for j in 0 1 2 3 4 5 6 7 8 9; +29 do +30 echo "$i$j" >"path$i$j" || return 1 +31 done || return 1 +32 done diff --git a/t/chainlint/nested-loop-detect-failure.test b/t/chainlint/nested-loop-detect-failure.test new file mode 100644 index 0000000000..3d4b657412 --- /dev/null +++ b/t/chainlint/nested-loop-detect-failure.test @@ -0,0 +1,37 @@ +test_expect_success 'nested-loop-detect-failure' ' +# LINT: neither loop handles failure explicitly with "|| return 1" +for i in 0 1 2 3 4 5 6 7 8 9; +do + for j in 0 1 2 3 4 5 6 7 8 9; + do + echo "$i$j" >"path$i$j" + done +done && + +# LINT: inner loop handles failure explicitly with "|| return 1" +for i in 0 1 2 3 4 5 6 7 8 9; +do + for j in 0 1 2 3 4 5 6 7 8 9; + do + echo "$i$j" >"path$i$j" || return 1 + done +done && + +# LINT: outer loop handles failure explicitly with "|| return 1" +for i in 0 1 2 3 4 5 6 7 8 9; +do + for j in 0 1 2 3 4 5 6 7 8 9; + do + echo "$i$j" >"path$i$j" + done || return 1 +done && + +# LINT: inner & outer loops handles failure explicitly with "|| return 1" +for i in 0 1 2 3 4 5 6 7 8 9; +do + for j in 0 1 2 3 4 5 6 7 8 9; + do + echo "$i$j" >"path$i$j" || return 1 + done || return 1 +done +' diff --git a/t/chainlint/nested-subshell-comment.expect b/t/chainlint/nested-subshell-comment.expect new file mode 100644 index 0000000000..078c6f275f --- /dev/null +++ b/t/chainlint/nested-subshell-comment.expect @@ -0,0 +1,11 @@ +2 ( +3 foo && +4 ( +5 bar && +6 # bottles wobble while fiddles gobble +7 # minor numbers of cows (or do they?) +8 baz && +9 snaff +10 ) ?!LINT: missing '&&'?! +11 fuzzy +12 ) diff --git a/t/chainlint/nested-subshell-comment.test b/t/chainlint/nested-subshell-comment.test new file mode 100644 index 0000000000..b430580ce0 --- /dev/null +++ b/t/chainlint/nested-subshell-comment.test @@ -0,0 +1,15 @@ +test_expect_success 'nested-subshell-comment' ' +( + foo && + ( + bar && +# LINT: ")" in comment in nested subshell not misinterpreted as closing ")" + # bottles wobble while fiddles gobble + # minor numbers of cows (or do they?) + baz && + snaff +# LINT: missing "&&" on ")" + ) + fuzzy +) +' diff --git a/t/chainlint/nested-subshell.expect b/t/chainlint/nested-subshell.expect new file mode 100644 index 0000000000..a8d85d5d5b --- /dev/null +++ b/t/chainlint/nested-subshell.expect @@ -0,0 +1,13 @@ +2 ( +3 cd foo && +4 ( +5 echo a && +6 echo b +7 ) >file && +8 +9 cd foo && +10 ( +11 echo a ?!LINT: missing '&&'?! +12 echo b +13 ) >file +14 ) diff --git a/t/chainlint/nested-subshell.test b/t/chainlint/nested-subshell.test new file mode 100644 index 0000000000..c31da34b73 --- /dev/null +++ b/t/chainlint/nested-subshell.test @@ -0,0 +1,15 @@ +test_expect_success 'nested-subshell' ' +( + cd foo && + ( + echo a && + echo b + ) >file && + + cd foo && + ( + echo a + echo b + ) >file +) +' diff --git a/t/chainlint/not-heredoc.expect b/t/chainlint/not-heredoc.expect new file mode 100644 index 0000000000..5d51705a7a --- /dev/null +++ b/t/chainlint/not-heredoc.expect @@ -0,0 +1,14 @@ +2 echo "<<<<<<< ours" && +3 echo ourside && +4 echo "=======" && +5 echo theirside && +6 echo ">>>>>>> theirs" && +7 +8 ( +9 echo "<<<<<<< ours" && +10 echo ourside && +11 echo "=======" && +12 echo theirside && +13 echo ">>>>>>> theirs" ?!LINT: missing '&&'?! +14 poodle +15 ) >merged diff --git a/t/chainlint/not-heredoc.test b/t/chainlint/not-heredoc.test new file mode 100644 index 0000000000..09711e45e0 --- /dev/null +++ b/t/chainlint/not-heredoc.test @@ -0,0 +1,18 @@ +test_expect_success 'not-heredoc' ' +# LINT: "<< ours" inside string is not here-doc +echo "<<<<<<< ours" && +echo ourside && +echo "=======" && +echo theirside && +echo ">>>>>>> theirs" && + +( +# LINT: "<< ours" inside string is not here-doc + echo "<<<<<<< ours" && + echo ourside && + echo "=======" && + echo theirside && + echo ">>>>>>> theirs" + poodle +) >merged +' diff --git a/t/chainlint/one-liner-for-loop.expect b/t/chainlint/one-liner-for-loop.expect new file mode 100644 index 0000000000..e1fcbd3639 --- /dev/null +++ b/t/chainlint/one-liner-for-loop.expect @@ -0,0 +1,9 @@ +2 git init dir-rename-and-content && +3 ( +4 cd dir-rename-and-content && +5 test_write_lines 1 2 3 4 5 >foo && +6 mkdir olddir && +7 for i in a b c; do echo $i >olddir/$i; ?!LINT: missing '|| exit 1'?! done ?!LINT: missing '&&'?! +8 git add foo olddir && +9 git commit -m "original" && +10 ) diff --git a/t/chainlint/one-liner-for-loop.test b/t/chainlint/one-liner-for-loop.test new file mode 100644 index 0000000000..00afd7ef76 --- /dev/null +++ b/t/chainlint/one-liner-for-loop.test @@ -0,0 +1,12 @@ +test_expect_success 'one-liner-for-loop' ' +git init dir-rename-and-content && +( + cd dir-rename-and-content && + test_write_lines 1 2 3 4 5 >foo && + mkdir olddir && +# LINT: one-liner for-loop missing "|| exit"; also broken &&-chain + for i in a b c; do echo $i >olddir/$i; done + git add foo olddir && + git commit -m "original" && +) +' diff --git a/t/chainlint/one-liner.expect b/t/chainlint/one-liner.expect new file mode 100644 index 0000000000..5deeb05070 --- /dev/null +++ b/t/chainlint/one-liner.expect @@ -0,0 +1,9 @@ +2 (foo && bar) && +3 (foo && bar) | +4 (foo && bar) >baz && +5 +6 (foo; ?!LINT: missing '&&'?! bar) && +7 (foo; ?!LINT: missing '&&'?! bar) | +8 (foo; ?!LINT: missing '&&'?! bar) >baz && +9 +10 (foo "bar; baz") diff --git a/t/chainlint/one-liner.test b/t/chainlint/one-liner.test new file mode 100644 index 0000000000..6e42ee1b5e --- /dev/null +++ b/t/chainlint/one-liner.test @@ -0,0 +1,14 @@ +test_expect_success 'one-liner' ' +# LINT: top-level one-liner subshell +(foo && bar) && +(foo && bar) | +(foo && bar) >baz && + +# LINT: top-level one-liner subshell missing internal "&&" and broken &&-chain +(foo; bar) && +(foo; bar) | +(foo; bar) >baz && + +# LINT: ";" in string not misinterpreted as broken &&-chain +(foo "bar; baz") +' diff --git a/t/chainlint/p4-filespec.expect b/t/chainlint/p4-filespec.expect new file mode 100644 index 0000000000..cff3e4e3d1 --- /dev/null +++ b/t/chainlint/p4-filespec.expect @@ -0,0 +1,4 @@ +2 ( +3 p4 print -1 //depot/fiddle#42 >file && +4 foobar +5 ) diff --git a/t/chainlint/p4-filespec.test b/t/chainlint/p4-filespec.test new file mode 100644 index 0000000000..8ba6b911dc --- /dev/null +++ b/t/chainlint/p4-filespec.test @@ -0,0 +1,7 @@ +test_expect_success 'p4-filespec' ' +( +# LINT: Perforce revspec in filespec not misinterpreted as in-line comment + p4 print -1 //depot/fiddle#42 >file && + foobar +) +' diff --git a/t/chainlint/pipe.expect b/t/chainlint/pipe.expect new file mode 100644 index 0000000000..d947c76584 --- /dev/null +++ b/t/chainlint/pipe.expect @@ -0,0 +1,10 @@ +2 ( +3 foo | +4 bar | +5 baz && +6 +7 fish | +8 cow ?!LINT: missing '&&'?! +9 +10 sunder +11 ) diff --git a/t/chainlint/pipe.test b/t/chainlint/pipe.test new file mode 100644 index 0000000000..1af81c243b --- /dev/null +++ b/t/chainlint/pipe.test @@ -0,0 +1,14 @@ +test_expect_success 'pipe' ' +( +# LINT: no "&&" needed on line ending with "|" + foo | + bar | + baz && + +# LINT: final line of pipe sequence ("cow") lacking "&&" + fish | + cow + + sunder +) +' diff --git a/t/chainlint/return-loop.expect b/t/chainlint/return-loop.expect new file mode 100644 index 0000000000..da8f9abea3 --- /dev/null +++ b/t/chainlint/return-loop.expect @@ -0,0 +1,5 @@ +2 while test $i -lt $((num - 5)) +3 do +4 git notes add -m "notes for commit$i" HEAD~$i || return 1 +5 i=$((i + 1)) +6 done diff --git a/t/chainlint/return-loop.test b/t/chainlint/return-loop.test new file mode 100644 index 0000000000..ea76c3593a --- /dev/null +++ b/t/chainlint/return-loop.test @@ -0,0 +1,8 @@ +test_expect_success 'return-loop' ' +while test $i -lt $((num - 5)) +do +# LINT: "|| return {n}" valid loop escape outside subshell; no "&&" needed + git notes add -m "notes for commit$i" HEAD~$i || return 1 + i=$((i + 1)) +done +' diff --git a/t/chainlint/semicolon.expect b/t/chainlint/semicolon.expect new file mode 100644 index 0000000000..2b499fbe70 --- /dev/null +++ b/t/chainlint/semicolon.expect @@ -0,0 +1,19 @@ +2 ( +3 cat foo ; ?!LINT: missing '&&'?! echo bar ?!LINT: missing '&&'?! +4 cat foo ; ?!LINT: missing '&&'?! echo bar +5 ) && +6 ( +7 cat foo ; ?!LINT: missing '&&'?! echo bar && +8 cat foo ; ?!LINT: missing '&&'?! echo bar +9 ) && +10 ( +11 echo "foo; bar" && +12 cat foo; ?!LINT: missing '&&'?! echo bar +13 ) && +14 ( +15 foo; +16 ) && +17 (cd foo && +18 for i in a b c; do +19 echo; ?!LINT: missing '|| exit 1'?! +20 done) diff --git a/t/chainlint/semicolon.test b/t/chainlint/semicolon.test new file mode 100644 index 0000000000..fc0ba1b539 --- /dev/null +++ b/t/chainlint/semicolon.test @@ -0,0 +1,27 @@ +test_expect_success 'semicolon' ' +( +# LINT: missing internal "&&" and ending "&&" + cat foo ; echo bar +# LINT: final statement before ")" only missing internal "&&" + cat foo ; echo bar +) && +( +# LINT: missing internal "&&" + cat foo ; echo bar && + cat foo ; echo bar +) && +( +# LINT: not fooled by semicolon in string + echo "foo; bar" && + cat foo; echo bar +) && +( +# LINT: semicolon unnecessary but legitimate + foo; +) && +(cd foo && + for i in a b c; do +# LINT: semicolon unnecessary but legitimate + echo; + done) +' diff --git a/t/chainlint/sqstring-in-sqstring.expect b/t/chainlint/sqstring-in-sqstring.expect new file mode 100644 index 0000000000..ba5d3c3a6d --- /dev/null +++ b/t/chainlint/sqstring-in-sqstring.expect @@ -0,0 +1,4 @@ +2 perl -e ' +3 defined($_ = -s $_) or die for @ARGV; +4 exit 1 if $ARGV[0] <= $ARGV[1]; +5 ' test-2-$packname_2.pack test-3-$packname_3.pack diff --git a/t/chainlint/sqstring-in-sqstring.test b/t/chainlint/sqstring-in-sqstring.test new file mode 100644 index 0000000000..24169724a5 --- /dev/null +++ b/t/chainlint/sqstring-in-sqstring.test @@ -0,0 +1,7 @@ +test_expect_success 'sqstring-in-sqstring' ' +# LINT: SQ-string Perl code fragment within SQ-string +perl -e '\'' + defined($_ = -s $_) or die for @ARGV; + exit 1 if $ARGV[0] <= $ARGV[1]; +'\'' test-2-$packname_2.pack test-3-$packname_3.pack +' diff --git a/t/chainlint/subshell-here-doc.expect b/t/chainlint/subshell-here-doc.expect new file mode 100644 index 0000000000..e450caf948 --- /dev/null +++ b/t/chainlint/subshell-here-doc.expect @@ -0,0 +1,30 @@ +2 ( +3 echo wobba \ +4 gorgo snoot \ +5 wafta snurb <<-EOF && +6 quoth the raven, +7 nevermore... +8 EOF +9 +10 cat <<EOF >bip ?!LINT: missing '&&'?! +11 fish fly high +12 EOF +13 +14 echo <<-\EOF >bop +15 gomez +16 morticia +17 wednesday +18 pugsly +19 EOF +20 ) && +21 ( +22 cat <<-\ARBITRARY >bup && +23 glink +24 FIZZ +25 ARBITRARY +26 cat <<-"ARBITRARY3" >bup3 && +27 glink +28 FIZZ +29 ARBITRARY3 +30 meep +31 ) diff --git a/t/chainlint/subshell-here-doc.test b/t/chainlint/subshell-here-doc.test new file mode 100644 index 0000000000..4a38f47f01 --- /dev/null +++ b/t/chainlint/subshell-here-doc.test @@ -0,0 +1,37 @@ +test_expect_success 'subshell-here-doc' ' +( +# LINT: stitch together incomplete \-ending lines +# LINT: swallow here-doc to avoid false positives in content + echo wobba \ + gorgo snoot \ + wafta snurb <<-EOF && + quoth the raven, + nevermore... + EOF + +# LINT: missing "&&" on "cat" + cat <<EOF >bip + fish fly high +EOF + +# LINT: swallow here-doc (EOF is last line of subshell) + echo <<-\EOF >bop + gomez + morticia + wednesday + pugsly + EOF +) && +( +# LINT: swallow here-doc with arbitrary tag + cat <<-\ARBITRARY >bup && + glink + FIZZ + ARBITRARY + cat <<-"ARBITRARY3" >bup3 && + glink + FIZZ + ARBITRARY3 + meep +) +' diff --git a/t/chainlint/subshell-one-liner.expect b/t/chainlint/subshell-one-liner.expect new file mode 100644 index 0000000000..265d996a21 --- /dev/null +++ b/t/chainlint/subshell-one-liner.expect @@ -0,0 +1,19 @@ +2 ( +3 (foo && bar) && +4 (foo && bar) | +5 (foo && bar) >baz && +6 +7 (foo; ?!LINT: missing '&&'?! bar) && +8 (foo; ?!LINT: missing '&&'?! bar) | +9 (foo; ?!LINT: missing '&&'?! bar) >baz && +10 +11 (foo || exit 1) && +12 (foo || exit 1) | +13 (foo || exit 1) >baz && +14 +15 (foo && bar) ?!LINT: missing '&&'?! +16 +17 (foo && bar; ?!LINT: missing '&&'?! baz) ?!LINT: missing '&&'?! +18 +19 foobar +20 ) diff --git a/t/chainlint/subshell-one-liner.test b/t/chainlint/subshell-one-liner.test new file mode 100644 index 0000000000..dac536afcc --- /dev/null +++ b/t/chainlint/subshell-one-liner.test @@ -0,0 +1,26 @@ +test_expect_success 'subshell-one-liner' ' +( +# LINT: nested one-liner subshell + (foo && bar) && + (foo && bar) | + (foo && bar) >baz && + +# LINT: nested one-liner subshell missing internal "&&" + (foo; bar) && + (foo; bar) | + (foo; bar) >baz && + +# LINT: nested one-liner subshell with "|| exit" + (foo || exit 1) && + (foo || exit 1) | + (foo || exit 1) >baz && + +# LINT: nested one-liner subshell lacking ending "&&" + (foo && bar) + +# LINT: nested one-liner subshell missing internal "&&" and lacking ending "&&" + (foo && bar; baz) + + foobar +) +' diff --git a/t/chainlint/t7900-subtree.expect b/t/chainlint/t7900-subtree.expect new file mode 100644 index 0000000000..9e60338bcf --- /dev/null +++ b/t/chainlint/t7900-subtree.expect @@ -0,0 +1,22 @@ +2 ( +3 chks="sub1 +4 sub2 +5 sub3 +6 sub4" && +7 chks_sub=$(cat <<TXT | sed "s,^,sub dir/," +8 $chks +9 TXT +10 ) && +11 chkms="main-sub1 +12 main-sub2 +13 main-sub3 +14 main-sub4" && +15 chkms_sub=$(cat <<TXT | sed "s,^,sub dir/," +16 $chkms +17 TXT +18 ) && +19 +20 subfiles=$(git ls-files) && +21 check_equal "$subfiles" "$chkms +22 $chks" +23 ) diff --git a/t/chainlint/t7900-subtree.test b/t/chainlint/t7900-subtree.test new file mode 100644 index 0000000000..1f4f03300f --- /dev/null +++ b/t/chainlint/t7900-subtree.test @@ -0,0 +1,24 @@ +test_expect_success 't7900-subtree' ' +( + chks="sub1 +sub2 +sub3 +sub4" && + chks_sub=$(cat <<TXT | sed "s,^,sub dir/," +$chks +TXT +) && + chkms="main-sub1 +main-sub2 +main-sub3 +main-sub4" && + chkms_sub=$(cat <<TXT | sed "s,^,sub dir/," +$chkms +TXT +) && + + subfiles=$(git ls-files) && + check_equal "$subfiles" "$chkms +$chks" +) +' diff --git a/t/chainlint/token-pasting.expect b/t/chainlint/token-pasting.expect new file mode 100644 index 0000000000..387189b6de --- /dev/null +++ b/t/chainlint/token-pasting.expect @@ -0,0 +1,27 @@ +2 git config filter.rot13.smudge ./rot13.sh && +3 git config filter.rot13.clean ./rot13.sh && +4 +5 { +6 echo "*.t filter=rot13" ?!LINT: missing '&&'?! +7 echo "*.i ident" +8 } >.gitattributes && +9 +10 { +11 echo a b c d e f g h i j k l m ?!LINT: missing '&&'?! +12 echo n o p q r s t u v w x y z ?!LINT: missing '&&'?! +13 echo '$Id$' +14 } >test && +15 cat test >test.t && +16 cat test >test.o && +17 cat test >test.i && +18 git add test test.t test.i && +19 rm -f test test.t test.i && +20 git checkout -- test test.t test.i && +21 +22 echo "content-test2" >test2.o && +23 echo "content-test3 - filename with special characters" >"test3 'sq',$x=.o" ?!LINT: missing '&&'?! +24 +25 downstream_url_for_sed=$( +26 printf "%sn" "$downstream_url" | +27 sed -e 's/\/\\/g' -e 's/[[/.*^$]/\&/g' +28 ) diff --git a/t/chainlint/token-pasting.test b/t/chainlint/token-pasting.test new file mode 100644 index 0000000000..590914b733 --- /dev/null +++ b/t/chainlint/token-pasting.test @@ -0,0 +1,34 @@ +test_expect_success 'token-pasting' ' +# LINT: single token; composite of multiple strings +git config filter.rot13.smudge ./rot13.sh && +git config filter.rot13.clean ./rot13.sh && + +{ + echo "*.t filter=rot13" + echo "*.i ident" +} >.gitattributes && + +{ + echo a b c d e f g h i j k l m + echo n o p q r s t u v w x y z +# LINT: exit/enter string context and escaped-quote outside of string + echo '\''$Id$'\'' +} >test && +cat test >test.t && +cat test >test.o && +cat test >test.i && +git add test test.t test.i && +rm -f test test.t test.i && +git checkout -- test test.t test.i && + +echo "content-test2" >test2.o && +# LINT: exit/enter string context and escaped-quote outside of string +echo "content-test3 - filename with special characters" >"test3 '\''sq'\'',\$x=.o" + +# LINT: single token; composite of multiple strings +downstream_url_for_sed=$( + printf "%s\n" "$downstream_url" | +# LINT: exit/enter string context; "&" inside string not command terminator + sed -e '\''s/\\/\\\\/g'\'' -e '\''s/[[/.*^$]/\\&/g'\'' +) +' diff --git a/t/chainlint/unclosed-here-doc-indent.expect b/t/chainlint/unclosed-here-doc-indent.expect new file mode 100644 index 0000000000..156906c85a --- /dev/null +++ b/t/chainlint/unclosed-here-doc-indent.expect @@ -0,0 +1,4 @@ +2 command_which_is_run && +3 cat >expect <<-\EOF ?!LINT: unclosed heredoc?! && +4 we forget to end the here-doc +5 command_which_is_gobbled diff --git a/t/chainlint/unclosed-here-doc-indent.test b/t/chainlint/unclosed-here-doc-indent.test new file mode 100644 index 0000000000..7ac9d0f7d7 --- /dev/null +++ b/t/chainlint/unclosed-here-doc-indent.test @@ -0,0 +1,6 @@ +test_expect_success 'unclosed-here-doc-indent' ' +command_which_is_run && +cat >expect <<-\EOF && +we forget to end the here-doc +command_which_is_gobbled +' diff --git a/t/chainlint/unclosed-here-doc.expect b/t/chainlint/unclosed-here-doc.expect new file mode 100644 index 0000000000..752c608862 --- /dev/null +++ b/t/chainlint/unclosed-here-doc.expect @@ -0,0 +1,7 @@ +2 command_which_is_run && +3 cat >expect <<\EOF ?!LINT: unclosed heredoc?! && +4 we try to end the here-doc below, +5 but the indentation throws us off +6 since the operator is not "<<-". +7 EOF +8 command_which_is_gobbled diff --git a/t/chainlint/unclosed-here-doc.test b/t/chainlint/unclosed-here-doc.test new file mode 100644 index 0000000000..68e78f06f3 --- /dev/null +++ b/t/chainlint/unclosed-here-doc.test @@ -0,0 +1,9 @@ +test_expect_success 'unclosed-here-doc' ' +command_which_is_run && +cat >expect <<\EOF && + we try to end the here-doc below, + but the indentation throws us off + since the operator is not "<<-". + EOF +command_which_is_gobbled +' diff --git a/t/chainlint/while-loop.expect b/t/chainlint/while-loop.expect new file mode 100644 index 0000000000..2ba5582165 --- /dev/null +++ b/t/chainlint/while-loop.expect @@ -0,0 +1,14 @@ +2 ( +3 while true +4 do +5 echo foo ?!LINT: missing '&&'?! +6 cat <<-\EOF ?!LINT: missing '|| exit 1'?! +7 bar +8 EOF +9 done ?!LINT: missing '&&'?! +10 +11 while true; do +12 echo foo && +13 cat bar ?!LINT: missing '|| exit 1'?! +14 done +15 ) diff --git a/t/chainlint/while-loop.test b/t/chainlint/while-loop.test new file mode 100644 index 0000000000..33a201906a --- /dev/null +++ b/t/chainlint/while-loop.test @@ -0,0 +1,21 @@ +test_expect_success 'while-loop' ' +( +# LINT: "while", "do", "done" do not need "&&" + while true + do +# LINT: missing "&&" on "echo" + echo foo +# LINT: last statement of while does not need "&&" + cat <<-\EOF + bar + EOF +# LINT: missing "&&" on "done" + done + +# LINT: "do" on same line as "while" + while true; do + echo foo && + cat bar + done +) +' |