Merge branch 'es/chain-lint-in-subshell'
Look for broken "&&" chains that are hidden in subshell, many of which have been found and corrected. * es/chain-lint-in-subshell: t/chainlint.sed: drop extra spaces from regex character class t/chainlint: add chainlint "specialized" test cases t/chainlint: add chainlint "complex" test cases t/chainlint: add chainlint "cuddled" test cases t/chainlint: add chainlint "loop" and "conditional" test cases t/chainlint: add chainlint "nested subshell" test cases t/chainlint: add chainlint "one-liner" test cases t/chainlint: add chainlint "whitespace" test cases t/chainlint: add chainlint "basic" test cases t/Makefile: add machinery to check correctness of chainlint.sed t/test-lib: teach --chain-lint to detect broken &&-chains in subshells
This commit is contained in:
		
							
								
								
									
										1
									
								
								t/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								t/.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -1,3 +1,4 @@ | ||||
| /trash directory* | ||||
| /test-results | ||||
| /.prove | ||||
| /chainlinttmp | ||||
|  | ||||
							
								
								
									
										25
									
								
								t/Makefile
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								t/Makefile
									
									
									
									
									
								
							| @ -18,8 +18,10 @@ TEST_LINT ?= test-lint | ||||
|  | ||||
| ifdef TEST_OUTPUT_DIRECTORY | ||||
| TEST_RESULTS_DIRECTORY = $(TEST_OUTPUT_DIRECTORY)/test-results | ||||
| CHAINLINTTMP = $(TEST_OUTPUT_DIRECTORY)/chainlinttmp | ||||
| else | ||||
| TEST_RESULTS_DIRECTORY = test-results | ||||
| CHAINLINTTMP = chainlinttmp | ||||
| endif | ||||
|  | ||||
| # Shell quote; | ||||
| @ -27,14 +29,17 @@ SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH)) | ||||
| TEST_SHELL_PATH_SQ = $(subst ','\'',$(TEST_SHELL_PATH)) | ||||
| PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH)) | ||||
| TEST_RESULTS_DIRECTORY_SQ = $(subst ','\'',$(TEST_RESULTS_DIRECTORY)) | ||||
| CHAINLINTTMP_SQ = $(subst ','\'',$(CHAINLINTTMP)) | ||||
|  | ||||
| T = $(sort $(wildcard t[0-9][0-9][0-9][0-9]-*.sh)) | ||||
| TGITWEB = $(sort $(wildcard t95[0-9][0-9]-*.sh)) | ||||
| THELPERS = $(sort $(filter-out $(T),$(wildcard *.sh))) | ||||
| CHAINLINTTESTS = $(sort $(patsubst chainlint/%.test,%,$(wildcard chainlint/*.test))) | ||||
| CHAINLINT = sed -f chainlint.sed | ||||
|  | ||||
| all: $(DEFAULT_TEST_TARGET) | ||||
|  | ||||
| test: pre-clean $(TEST_LINT) | ||||
| test: pre-clean check-chainlint $(TEST_LINT) | ||||
| 	$(MAKE) aggregate-results-and-cleanup | ||||
|  | ||||
| failed: | ||||
| @ -43,7 +48,7 @@ failed: | ||||
| 		sed -n 's/\.counts$$/.sh/p') && \ | ||||
| 	test -z "$$failed" || $(MAKE) $$failed | ||||
|  | ||||
| prove: pre-clean $(TEST_LINT) | ||||
| prove: pre-clean check-chainlint $(TEST_LINT) | ||||
| 	@echo "*** prove ***"; $(PROVE) --exec '$(TEST_SHELL_PATH_SQ)' $(GIT_PROVE_OPTS) $(T) :: $(GIT_TEST_OPTS) | ||||
| 	$(MAKE) clean-except-prove-cache | ||||
|  | ||||
| @ -53,13 +58,25 @@ $(T): | ||||
| pre-clean: | ||||
| 	$(RM) -r '$(TEST_RESULTS_DIRECTORY_SQ)' | ||||
|  | ||||
| clean-except-prove-cache: | ||||
| clean-except-prove-cache: clean-chainlint | ||||
| 	$(RM) -r 'trash directory'.* '$(TEST_RESULTS_DIRECTORY_SQ)' | ||||
| 	$(RM) -r valgrind/bin | ||||
|  | ||||
| clean: clean-except-prove-cache | ||||
| 	$(RM) .prove | ||||
|  | ||||
| clean-chainlint: | ||||
| 	$(RM) -r '$(CHAINLINTTMP_SQ)' | ||||
|  | ||||
| check-chainlint: | ||||
| 	@mkdir -p '$(CHAINLINTTMP_SQ)' && \ | ||||
| 	err=0 && \ | ||||
| 	for i in $(CHAINLINTTESTS); do \ | ||||
| 		$(CHAINLINT) <chainlint/$$i.test | \ | ||||
| 		sed -e '/^# LINT: /d' >'$(CHAINLINTTMP_SQ)'/$$i.actual && \ | ||||
| 		diff -u chainlint/$$i.expect '$(CHAINLINTTMP_SQ)'/$$i.actual || err=1; \ | ||||
| 	done && exit $$err | ||||
|  | ||||
| test-lint: test-lint-duplicates test-lint-executable test-lint-shell-syntax \ | ||||
| 	test-lint-filenames | ||||
|  | ||||
| @ -102,4 +119,4 @@ valgrind: | ||||
| perf: | ||||
| 	$(MAKE) -C perf/ all | ||||
|  | ||||
| .PHONY: pre-clean $(T) aggregate-results clean valgrind perf | ||||
| .PHONY: pre-clean $(T) aggregate-results clean valgrind perf check-chainlint clean-chainlint | ||||
|  | ||||
							
								
								
									
										346
									
								
								t/chainlint.sed
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										346
									
								
								t/chainlint.sed
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,346 @@ | ||||
| #------------------------------------------------------------------------------ | ||||
| # Detect broken &&-chains in tests. | ||||
| # | ||||
| # At present, only &&-chains in subshells are examined by this linter; | ||||
| # top-level &&-chains are instead checked directly by the test framework. Like | ||||
| # the top-level &&-chain linter, the subshell linter (intentionally) does not | ||||
| # check &&-chains within {...} blocks. | ||||
| # | ||||
| # Checking for &&-chain breakage is done line-by-line by pure textual | ||||
| # inspection. | ||||
| # | ||||
| # Incomplete lines (those ending with "\") are stitched together with following | ||||
| # lines to simplify processing, particularly of "one-liner" statements. | ||||
| # Top-level here-docs are swallowed to avoid false positives within the | ||||
| # here-doc body, although the statement to which the here-doc is attached is | ||||
| # retained. | ||||
| # | ||||
| # Heuristics are used to detect end-of-subshell when the closing ")" is cuddled | ||||
| # with the final subshell statement on the same line: | ||||
| # | ||||
| #    (cd foo && | ||||
| #        bar) | ||||
| # | ||||
| # in order to avoid misinterpreting the ")" in constructs such as "x=$(...)" | ||||
| # and "case $x in *)" as ending the subshell. | ||||
| # | ||||
| # Lines missing a final "&&" are flagged with "?!AMP?!", and lines which chain | ||||
| # commands with ";" internally rather than "&&" are flagged "?!SEMI?!". A line | ||||
| # may be flagged for both violations. | ||||
| # | ||||
| # Detection of a missing &&-link in a multi-line subshell is complicated by the | ||||
| # fact that the last statement before the closing ")" must not end with "&&". | ||||
| # Since processing is line-by-line, it is not known whether a missing "&&" is | ||||
| # legitimate or not until the _next_ line is seen. To accommodate this, within | ||||
| # multi-line subshells, each line is stored in sed's "hold" area until after | ||||
| # the next line is seen and processed. If the next line is a stand-alone ")", | ||||
| # then a missing "&&" on the previous line is legitimate; otherwise a missing | ||||
| # "&&" is a break in the &&-chain. | ||||
| # | ||||
| #    ( | ||||
| #         cd foo && | ||||
| #         bar | ||||
| #    ) | ||||
| # | ||||
| # In practical terms, when "bar" is encountered, it is flagged with "?!AMP?!", | ||||
| # but when the stand-alone ")" line is seen which closes the subshell, the | ||||
| # "?!AMP?!" violation is removed from the "bar" line (retrieved from the "hold" | ||||
| # area) since the final statement of a subshell must not end with "&&". The | ||||
| # final line of a subshell may still break the &&-chain by using ";" internally | ||||
| # to chain commands together rather than "&&", so "?!SEMI?!" is never removed | ||||
| # from a line (even though "?!AMP?!" might be). | ||||
| # | ||||
| # Care is taken to recognize the last _statement_ of a multi-line subshell, not | ||||
| # necessarily the last textual _line_ within the subshell, since &&-chaining | ||||
| # applies to statements, not to lines. Consequently, blank lines, comment | ||||
| # lines, and here-docs are swallowed (but not the command to which the here-doc | ||||
| # is attached), leaving the last statement in the "hold" area, not the last | ||||
| # line, thus simplifying &&-link checking. | ||||
| # | ||||
| # The final statement before "done" in for- and while-loops, and before "elif", | ||||
| # "else", and "fi" in if-then-else likewise must not end with "&&", thus | ||||
| # receives similar treatment. | ||||
| # | ||||
| # To facilitate regression testing (and manual debugging), a ">" annotation is | ||||
| # applied to the line containing ")" which closes a subshell, ">>" to a line | ||||
| # closing a nested subshell, and ">>>" to a line closing both at once. This | ||||
| # makes it easy to detect whether the heuristics correctly identify | ||||
| # end-of-subshell. | ||||
| #------------------------------------------------------------------------------ | ||||
|  | ||||
| # incomplete line -- slurp up next line | ||||
| :squash | ||||
| /\\$/ { | ||||
| 	N | ||||
| 	s/\\\n// | ||||
| 	bsquash | ||||
| } | ||||
|  | ||||
| # here-doc -- swallow it to avoid false hits within its body (but keep the | ||||
| # command to which it was attached) | ||||
| /<<[ 	]*[-\\]*EOF[ 	]*/ { | ||||
| 	s/[ 	]*<<[ 	]*[-\\]*EOF// | ||||
| 	h | ||||
| 	:hereslurp | ||||
| 	N | ||||
| 	s/.*\n// | ||||
| 	/^[ 	]*EOF[ 	]*$/!bhereslurp | ||||
| 	x | ||||
| } | ||||
|  | ||||
| # one-liner "(...) &&" | ||||
| /^[ 	]*!*[ 	]*(..*)[ 	]*&&[ 	]*$/boneline | ||||
|  | ||||
| # same as above but without trailing "&&" | ||||
| /^[ 	]*!*[ 	]*(..*)[ 	]*$/boneline | ||||
|  | ||||
| # one-liner "(...) >x" (or "2>x" or "<x" or "|x" or "&" | ||||
| /^[ 	]*!*[ 	]*(..*)[ 	]*[0-9]*[<>|&]/boneline | ||||
|  | ||||
| # multi-line "(...\n...)" | ||||
| /^[ 	]*(/bsubshell | ||||
|  | ||||
| # innocuous line -- print it and advance to next line | ||||
| b | ||||
|  | ||||
| # found one-liner "(...)" -- mark suspect if it uses ";" internally rather than | ||||
| # "&&" (but not ";" in a string) | ||||
| :oneline | ||||
| /;/{ | ||||
| 	/"[^"]*;[^"]*"/!s/^/?!SEMI?!/ | ||||
| } | ||||
| b | ||||
|  | ||||
| :subshell | ||||
| # bare "(" line? | ||||
| /^[ 	]*([	]*$/ { | ||||
| 	# stash for later printing | ||||
| 	h | ||||
| 	bnextline | ||||
| } | ||||
| # "(..." line -- split off and stash "(", then process "..." as its own line | ||||
| x | ||||
| s/.*/(/ | ||||
| x | ||||
| s/(// | ||||
| bslurp | ||||
|  | ||||
| :nextline | ||||
| N | ||||
| s/.*\n// | ||||
|  | ||||
| :slurp | ||||
| # incomplete line "...\" | ||||
| /\\$/bincomplete | ||||
| # multi-line quoted string "...\n..." | ||||
| /^[^"]*"[^"]*$/bdqstring | ||||
| # multi-line quoted string '...\n...' (but not contraction in string "it's so") | ||||
| /^[^']*'[^']*$/{ | ||||
| 	/"[^'"]*'[^'"]*"/!bsqstring | ||||
| } | ||||
| # here-doc -- swallow it | ||||
| /<<[ 	]*[-\\]*EOF/bheredoc | ||||
| /<<[ 	]*[-\\]*EOT/bheredoc | ||||
| /<<[ 	]*[-\\]*INPUT_END/bheredoc | ||||
| # comment or empty line -- discard since final non-comment, non-empty line | ||||
| # before closing ")", "done", "elsif", "else", or "fi" will need to be | ||||
| # re-visited to drop "suspect" marking since final line of those constructs | ||||
| # legitimately lacks "&&", so "suspect" mark must be removed | ||||
| /^[ 	]*#/bnextline | ||||
| /^[ 	]*$/bnextline | ||||
| # in-line comment -- strip it (but not "#" in a string, Bash ${#...} array | ||||
| # length, or Perforce "//depot/path#42" revision in filespec) | ||||
| /[ 	]#/{ | ||||
| 	/"[^"]*#[^"]*"/!s/[ 	]#.*$// | ||||
| } | ||||
| # one-liner "case ... esac" | ||||
| /^[ 	]*case[ 	]*..*esac/bcheckchain | ||||
| # multi-line "case ... esac" | ||||
| /^[ 	]*case[ 	]..*[ 	]in/bcase | ||||
| # multi-line "for ... done" or "while ... done" | ||||
| /^[ 	]*for[ 	]..*[ 	]in/bcontinue | ||||
| /^[ 	]*while[ 	]/bcontinue | ||||
| /^[ 	]*do[ 	]/bcontinue | ||||
| /^[ 	]*do[ 	]*$/bcontinue | ||||
| /;[ 	]*do/bcontinue | ||||
| /^[ 	]*done[ 	]*&&[ 	]*$/bdone | ||||
| /^[ 	]*done[ 	]*$/bdone | ||||
| /^[ 	]*done[ 	]*[<>|]/bdone | ||||
| /^[ 	]*done[ 	]*)/bdone | ||||
| /||[ 	]*exit[ 	]/bcontinue | ||||
| /||[ 	]*exit[ 	]*$/bcontinue | ||||
| # multi-line "if...elsif...else...fi" | ||||
| /^[ 	]*if[ 	]/bcontinue | ||||
| /^[ 	]*then[ 	]/bcontinue | ||||
| /^[ 	]*then[ 	]*$/bcontinue | ||||
| /;[ 	]*then/bcontinue | ||||
| /^[ 	]*elif[ 	]/belse | ||||
| /^[ 	]*elif[ 	]*$/belse | ||||
| /^[ 	]*else[ 	]/belse | ||||
| /^[ 	]*else[ 	]*$/belse | ||||
| /^[ 	]*fi[ 	]*&&[ 	]*$/bdone | ||||
| /^[ 	]*fi[ 	]*$/bdone | ||||
| /^[ 	]*fi[ 	]*[<>|]/bdone | ||||
| /^[ 	]*fi[ 	]*)/bdone | ||||
| # nested one-liner "(...) &&" | ||||
| /^[ 	]*(.*)[ 	]*&&[ 	]*$/bcheckchain | ||||
| # nested one-liner "(...)" | ||||
| /^[ 	]*(.*)[ 	]*$/bcheckchain | ||||
| # nested one-liner "(...) >x" (or "2>x" or "<x" or "|x") | ||||
| /^[ 	]*(.*)[ 	]*[0-9]*[<>|]/bcheckchain | ||||
| # nested multi-line "(...\n...)" | ||||
| /^[ 	]*(/bnest | ||||
| # multi-line "{...\n...}" | ||||
| /^[ 	]*{/bblock | ||||
| # closing ")" on own line -- exit subshell | ||||
| /^[ 	]*)/bclosesolo | ||||
| # "$((...))" -- arithmetic expansion; not closing ")" | ||||
| /\$(([^)][^)]*))[^)]*$/bcheckchain | ||||
| # "$(...)" -- command substitution; not closing ")" | ||||
| /\$([^)][^)]*)[^)]*$/bcheckchain | ||||
| # multi-line "$(...\n...)" -- command substitution; treat as nested subshell | ||||
| /\$([ 	]*$/bnest | ||||
| # "=(...)" -- Bash array assignment; not closing ")" | ||||
| /=(/bcheckchain | ||||
| # closing "...) &&" | ||||
| /)[ 	]*&&[ 	]*$/bclose | ||||
| # closing "...)" | ||||
| /)[ 	]*$/bclose | ||||
| # closing "...) >x" (or "2>x" or "<x" or "|x") | ||||
| /)[ 	]*[<>|]/bclose | ||||
| :checkchain | ||||
| # mark suspect if line uses ";" internally rather than "&&" (but not ";" in a | ||||
| # string and not ";;" in one-liner "case...esac") | ||||
| /;/{ | ||||
| 	/;;/!{ | ||||
| 		/"[^"]*;[^"]*"/!s/^/?!SEMI?!/ | ||||
| 	} | ||||
| } | ||||
| # line ends with pipe "...|" -- valid; not missing "&&" | ||||
| /|[ 	]*$/bcontinue | ||||
| # missing end-of-line "&&" -- mark suspect | ||||
| /&&[ 	]*$/!s/^/?!AMP?!/ | ||||
| :continue | ||||
| # retrieve and print previous line | ||||
| x | ||||
| n | ||||
| bslurp | ||||
|  | ||||
| # found incomplete line "...\" -- slurp up next line | ||||
| :incomplete | ||||
| N | ||||
| s/\\\n// | ||||
| bslurp | ||||
|  | ||||
| # found multi-line double-quoted string "...\n..." -- slurp until end of string | ||||
| :dqstring | ||||
| s/"//g | ||||
| N | ||||
| s/\n// | ||||
| /"/!bdqstring | ||||
| bcheckchain | ||||
|  | ||||
| # found multi-line single-quoted string '...\n...' -- slurp until end of string | ||||
| :sqstring | ||||
| s/'//g | ||||
| N | ||||
| s/\n// | ||||
| /'/!bsqstring | ||||
| bcheckchain | ||||
|  | ||||
| # found here-doc -- swallow it to avoid false hits within its body (but keep | ||||
| # the command to which it was attached); take care to handle here-docs nested | ||||
| # within here-docs by only recognizing closing tag matching outer here-doc | ||||
| # opening tag | ||||
| :heredoc | ||||
| /EOF/{ s/[ 	]*<<[ 	]*[-\\]*EOF//; s/^/EOF/; } | ||||
| /EOT/{ s/[ 	]*<<[ 	]*[-\\]*EOT//; s/^/EOT/; } | ||||
| /INPUT_END/{ s/[ 	]*<<[ 	]*[-\\]*INPUT_END//; s/^/INPUT_END/; } | ||||
| :hereslurpsub | ||||
| N | ||||
| /^EOF.*\n[ 	]*EOF[ 	]*$/bhereclose | ||||
| /^EOT.*\n[ 	]*EOT[ 	]*$/bhereclose | ||||
| /^INPUT_END.*\n[ 	]*INPUT_END[ 	]*$/bhereclose | ||||
| bhereslurpsub | ||||
| :hereclose | ||||
| s/^EOF// | ||||
| s/^EOT// | ||||
| s/^INPUT_END// | ||||
| s/\n.*$// | ||||
| bcheckchain | ||||
|  | ||||
| # found "case ... in" -- pass through untouched | ||||
| :case | ||||
| x | ||||
| n | ||||
| /^[ 	]*esac/bslurp | ||||
| bcase | ||||
|  | ||||
| # found "else" or "elif" -- drop "suspect" from final line before "else" since | ||||
| # that line legitimately lacks "&&" | ||||
| :else | ||||
| x | ||||
| s/?!AMP?!// | ||||
| x | ||||
| bcontinue | ||||
|  | ||||
| # found "done" closing for-loop or while-loop, or "fi" closing if-then -- drop | ||||
| # "suspect" from final contained line since that line legitimately lacks "&&" | ||||
| :done | ||||
| x | ||||
| s/?!AMP?!// | ||||
| x | ||||
| # is 'done' or 'fi' cuddled with ")" to close subshell? | ||||
| /done.*)/bclose | ||||
| /fi.*)/bclose | ||||
| bcheckchain | ||||
|  | ||||
| # found nested multi-line "(...\n...)" -- pass through untouched | ||||
| :nest | ||||
| x | ||||
| :nestslurp | ||||
| n | ||||
| # closing ")" on own line -- stop nested slurp | ||||
| /^[ 	]*)/bnestclose | ||||
| # comment -- not closing ")" if in comment | ||||
| /^[ 	]*#/bnestcontinue | ||||
| # "$((...))" -- arithmetic expansion; not closing ")" | ||||
| /\$(([^)][^)]*))[^)]*$/bnestcontinue | ||||
| # "$(...)" -- command substitution; not closing ")" | ||||
| /\$([^)][^)]*)[^)]*$/bnestcontinue | ||||
| # closing "...)" -- stop nested slurp | ||||
| /)/bnestclose | ||||
| :nestcontinue | ||||
| x | ||||
| bnestslurp | ||||
| :nestclose | ||||
| s/^/>>/ | ||||
| # is it "))" which closes nested and parent subshells? | ||||
| /)[ 	]*)/bslurp | ||||
| bcheckchain | ||||
|  | ||||
| # found multi-line "{...\n...}" block -- pass through untouched | ||||
| :block | ||||
| x | ||||
| n | ||||
| # closing "}" -- stop block slurp | ||||
| /}/bcheckchain | ||||
| bblock | ||||
|  | ||||
| # found closing ")" on own line -- drop "suspect" from final line of subshell | ||||
| # since that line legitimately lacks "&&" and exit subshell loop | ||||
| :closesolo | ||||
| x | ||||
| s/?!AMP?!// | ||||
| p | ||||
| x | ||||
| s/^/>/ | ||||
| b | ||||
|  | ||||
| # found closing "...)" -- exit subshell loop | ||||
| :close | ||||
| x | ||||
| p | ||||
| x | ||||
| s/^/>/ | ||||
| b | ||||
							
								
								
									
										9
									
								
								t/chainlint/arithmetic-expansion.expect
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								t/chainlint/arithmetic-expansion.expect
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | ||||
| ( | ||||
| 	foo && | ||||
| 	bar=$((42 + 1)) && | ||||
| 	baz | ||||
| >) && | ||||
| ( | ||||
| ?!AMP?!	bar=$((42 + 1)) | ||||
| 	baz | ||||
| >) | ||||
							
								
								
									
										11
									
								
								t/chainlint/arithmetic-expansion.test
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								t/chainlint/arithmetic-expansion.test
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,11 @@ | ||||
| ( | ||||
| 	foo && | ||||
| # LINT: closing ")" of $((...)) not misinterpreted as subshell-closing ")" | ||||
| 	bar=$((42 + 1)) && | ||||
| 	baz | ||||
| ) && | ||||
| ( | ||||
| # LINT: missing "&&" on $((...)) | ||||
| 	bar=$((42 + 1)) | ||||
| 	baz | ||||
| ) | ||||
							
								
								
									
										10
									
								
								t/chainlint/bash-array.expect
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								t/chainlint/bash-array.expect
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | ||||
| ( | ||||
| 	foo && | ||||
| 	bar=(gumbo stumbo wumbo) && | ||||
| 	baz | ||||
| >) && | ||||
| ( | ||||
| 	foo && | ||||
| 	bar=${#bar[@]} && | ||||
| 	baz | ||||
| >) | ||||
							
								
								
									
										12
									
								
								t/chainlint/bash-array.test
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								t/chainlint/bash-array.test
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | ||||
| ( | ||||
| 	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 | ||||
| ) | ||||
							
								
								
									
										4
									
								
								t/chainlint/blank-line.expect
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								t/chainlint/blank-line.expect
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,4 @@ | ||||
| ( | ||||
| 	nothing && | ||||
| 	something | ||||
| >) | ||||
							
								
								
									
										10
									
								
								t/chainlint/blank-line.test
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								t/chainlint/blank-line.test
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | ||||
| ( | ||||
|  | ||||
| 	nothing && | ||||
|  | ||||
| 	something | ||||
| # LINT: swallow blank lines since final _statement_ before subshell end is | ||||
| # LINT: significant to "&&"-check, not final _line_ (which might be blank) | ||||
|  | ||||
|  | ||||
| ) | ||||
							
								
								
									
										12
									
								
								t/chainlint/block.expect
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								t/chainlint/block.expect
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | ||||
| ( | ||||
| 	foo && | ||||
| 	{ | ||||
| 		echo a | ||||
| 		echo b | ||||
| 	} && | ||||
| 	bar && | ||||
| 	{ | ||||
| 		echo c | ||||
| ?!AMP?!	} | ||||
| 	baz | ||||
| >) | ||||
							
								
								
									
										15
									
								
								t/chainlint/block.test
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								t/chainlint/block.test
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | ||||
| ( | ||||
| # LINT: missing "&&" in block not currently detected (for consistency with | ||||
| # LINT: --chain-lint at top level and to provide escape hatch if needed) | ||||
| 	foo && | ||||
| 	{ | ||||
| 		echo a | ||||
| 		echo b | ||||
| 	} && | ||||
| 	bar && | ||||
| # LINT: missing "&&" at closing "}" | ||||
| 	{ | ||||
| 		echo c | ||||
| 	} | ||||
| 	baz | ||||
| ) | ||||
							
								
								
									
										6
									
								
								t/chainlint/broken-chain.expect
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								t/chainlint/broken-chain.expect
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | ||||
| ( | ||||
| 	foo && | ||||
| ?!AMP?!	bar | ||||
| 	baz && | ||||
| 	wop | ||||
| >) | ||||
							
								
								
									
										8
									
								
								t/chainlint/broken-chain.test
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								t/chainlint/broken-chain.test
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | ||||
| ( | ||||
| 	foo && | ||||
| # LINT: missing "&&" from 'bar' | ||||
| 	bar | ||||
| 	baz && | ||||
| # LINT: final statement before closing ")" legitimately lacks "&&" | ||||
| 	wop | ||||
| ) | ||||
							
								
								
									
										19
									
								
								t/chainlint/case.expect
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								t/chainlint/case.expect
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,19 @@ | ||||
| ( | ||||
| 	case "$x" in | ||||
| 	x) foo ;; | ||||
| 	*) bar ;; | ||||
| 	esac && | ||||
| 	foobar | ||||
| >) && | ||||
| ( | ||||
| 	case "$x" in | ||||
| 	x) foo ;; | ||||
| 	*) bar ;; | ||||
| ?!AMP?!	esac | ||||
| 	foobar | ||||
| >) && | ||||
| ( | ||||
| 	case "$x" in 1) true;; esac && | ||||
| ?!AMP?!	case "$y" in 2) false;; esac | ||||
| 	foobar | ||||
| >) | ||||
							
								
								
									
										23
									
								
								t/chainlint/case.test
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								t/chainlint/case.test
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,23 @@ | ||||
| ( | ||||
| # 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 | ||||
| ) | ||||
							
								
								
									
										4
									
								
								t/chainlint/close-nested-and-parent-together.expect
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								t/chainlint/close-nested-and-parent-together.expect
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,4 @@ | ||||
| ( | ||||
| cd foo && | ||||
| 	(bar && | ||||
| >>>		baz)) | ||||
							
								
								
									
										3
									
								
								t/chainlint/close-nested-and-parent-together.test
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								t/chainlint/close-nested-and-parent-together.test
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | ||||
| (cd foo && | ||||
| 	(bar && | ||||
| 		baz)) | ||||
							
								
								
									
										25
									
								
								t/chainlint/close-subshell.expect
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								t/chainlint/close-subshell.expect
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,25 @@ | ||||
| ( | ||||
| 	foo | ||||
| >) && | ||||
| ( | ||||
| 	bar | ||||
| >) >out && | ||||
| ( | ||||
| 	baz | ||||
| >) 2>err && | ||||
| ( | ||||
| 	boo | ||||
| >) <input && | ||||
| ( | ||||
| 	bip | ||||
| >) | wuzzle && | ||||
| ( | ||||
| 	bop | ||||
| >) | fazz 	fozz && | ||||
| ( | ||||
| 	bup | ||||
| >) | | ||||
| fuzzle && | ||||
| ( | ||||
| 	yop | ||||
| >) | ||||
							
								
								
									
										27
									
								
								t/chainlint/close-subshell.test
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								t/chainlint/close-subshell.test
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,27 @@ | ||||
| # LINT: closing ")" with various decorations ("&&", ">", "|", etc.) | ||||
| ( | ||||
| 	foo | ||||
| ) && | ||||
| ( | ||||
| 	bar | ||||
| ) >out && | ||||
| ( | ||||
| 	baz | ||||
| ) 2>err && | ||||
| ( | ||||
| 	boo | ||||
| ) <input && | ||||
| ( | ||||
| 	bip | ||||
| ) | wuzzle && | ||||
| ( | ||||
| 	bop | ||||
| ) | fazz \ | ||||
| 	fozz && | ||||
| ( | ||||
| 	bup | ||||
| ) | | ||||
| fuzzle && | ||||
| ( | ||||
| 	yop | ||||
| ) | ||||
							
								
								
									
										9
									
								
								t/chainlint/command-substitution.expect
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								t/chainlint/command-substitution.expect
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | ||||
| ( | ||||
| 	foo && | ||||
| 	bar=$(gobble) && | ||||
| 	baz | ||||
| >) && | ||||
| ( | ||||
| ?!AMP?!	bar=$(gobble blocks) | ||||
| 	baz | ||||
| >) | ||||
							
								
								
									
										11
									
								
								t/chainlint/command-substitution.test
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								t/chainlint/command-substitution.test
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,11 @@ | ||||
| ( | ||||
| 	foo && | ||||
| # LINT: closing ")" of $(...) not misinterpreted as subshell-closing ")" | ||||
| 	bar=$(gobble) && | ||||
| 	baz | ||||
| ) && | ||||
| ( | ||||
| # LINT: missing "&&" on $(...) | ||||
| 	bar=$(gobble blocks) | ||||
| 	baz | ||||
| ) | ||||
							
								
								
									
										4
									
								
								t/chainlint/comment.expect
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								t/chainlint/comment.expect
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,4 @@ | ||||
| ( | ||||
| 	nothing && | ||||
| 	something | ||||
| >) | ||||
							
								
								
									
										11
									
								
								t/chainlint/comment.test
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								t/chainlint/comment.test
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,11 @@ | ||||
| ( | ||||
| # 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 | ||||
| ) | ||||
							
								
								
									
										10
									
								
								t/chainlint/complex-if-in-cuddled-loop.expect
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								t/chainlint/complex-if-in-cuddled-loop.expect
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | ||||
| ( | ||||
| 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 | ||||
							
								
								
									
										11
									
								
								t/chainlint/complex-if-in-cuddled-loop.test
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								t/chainlint/complex-if-in-cuddled-loop.test
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,11 @@ | ||||
| # 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 | ||||
							
								
								
									
										7
									
								
								t/chainlint/cuddled-if-then-else.expect
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								t/chainlint/cuddled-if-then-else.expect
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | ||||
| ( | ||||
| if test -z ""; then | ||||
|     echo empty | ||||
|  else | ||||
|     echo bizzy | ||||
| > fi) && | ||||
| echo foobar | ||||
							
								
								
									
										7
									
								
								t/chainlint/cuddled-if-then-else.test
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								t/chainlint/cuddled-if-then-else.test
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | ||||
| # LINT: 'if' cuddled with "(" and ")"; indented with spaces, not tabs | ||||
| (if test -z ""; then | ||||
|     echo empty | ||||
|  else | ||||
|     echo bizzy | ||||
|  fi) && | ||||
| echo foobar | ||||
							
								
								
									
										5
									
								
								t/chainlint/cuddled-loop.expect
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								t/chainlint/cuddled-loop.expect
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | ||||
| ( | ||||
|  while read x | ||||
|   do foobar bop || exit 1 | ||||
| >  done <file ) && | ||||
| outside subshell | ||||
							
								
								
									
										7
									
								
								t/chainlint/cuddled-loop.test
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								t/chainlint/cuddled-loop.test
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | ||||
| # 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 | ||||
							
								
								
									
										21
									
								
								t/chainlint/cuddled.expect
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								t/chainlint/cuddled.expect
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,21 @@ | ||||
| ( | ||||
| cd foo && | ||||
| 	bar | ||||
| >) && | ||||
|  | ||||
| ( | ||||
| ?!AMP?!cd foo | ||||
| 	bar | ||||
| >) && | ||||
|  | ||||
| ( | ||||
| 	cd foo && | ||||
| >	bar) && | ||||
|  | ||||
| ( | ||||
| cd foo && | ||||
| >	bar) && | ||||
|  | ||||
| ( | ||||
| ?!AMP?!cd foo | ||||
| >	bar) | ||||
							
								
								
									
										23
									
								
								t/chainlint/cuddled.test
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								t/chainlint/cuddled.test
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,23 @@ | ||||
| # LINT: first subshell statement cuddled with opening "("; for implementation | ||||
| # LINT: simplicity, "(..." is split into two lines, "(" and "..." | ||||
| (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) | ||||
							
								
								
									
										24
									
								
								t/chainlint/exit-loop.expect
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								t/chainlint/exit-loop.expect
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,24 @@ | ||||
| ( | ||||
| 	for i in a b c | ||||
| 	do | ||||
| 		foo || exit 1 | ||||
| 		bar && | ||||
| 		baz | ||||
| 	done | ||||
| >) && | ||||
| ( | ||||
| 	while true | ||||
| 	do | ||||
| 		foo || exit 1 | ||||
| 		bar && | ||||
| 		baz | ||||
| 	done | ||||
| >) && | ||||
| ( | ||||
| 	i=0 && | ||||
| 	while test $i -lt 10 | ||||
| 	do | ||||
| 		echo $i || exit | ||||
| 		i=$(($i + 1)) | ||||
| 	done | ||||
| >) | ||||
							
								
								
									
										27
									
								
								t/chainlint/exit-loop.test
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								t/chainlint/exit-loop.test
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,27 @@ | ||||
| ( | ||||
| 	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 | ||||
| ) | ||||
							
								
								
									
										5
									
								
								t/chainlint/exit-subshell.expect
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								t/chainlint/exit-subshell.expect
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | ||||
| ( | ||||
| 	foo || exit 1 | ||||
| 	bar && | ||||
| 	baz | ||||
| >) | ||||
							
								
								
									
										6
									
								
								t/chainlint/exit-subshell.test
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								t/chainlint/exit-subshell.test
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | ||||
| ( | ||||
| # LINT: "|| exit {n}" valid subshell escape without hurting &&-chain | ||||
| 	foo || exit 1 | ||||
| 	bar && | ||||
| 	baz | ||||
| ) | ||||
							
								
								
									
										11
									
								
								t/chainlint/for-loop.expect
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								t/chainlint/for-loop.expect
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,11 @@ | ||||
| ( | ||||
| 	for i in a b c | ||||
| 	do | ||||
| ?!AMP?!		echo $i | ||||
| 		cat | ||||
| ?!AMP?!	done | ||||
| 	for i in a b c; do | ||||
| 		echo $i && | ||||
| 		cat $i | ||||
| 	done | ||||
| >) | ||||
							
								
								
									
										19
									
								
								t/chainlint/for-loop.test
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								t/chainlint/for-loop.test
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,19 @@ | ||||
| ( | ||||
| # 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 | ||||
| ) | ||||
							
								
								
									
										3
									
								
								t/chainlint/here-doc.expect
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								t/chainlint/here-doc.expect
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | ||||
| boodle wobba        gorgo snoot        wafta snurb && | ||||
|  | ||||
| horticulture | ||||
							
								
								
									
										16
									
								
								t/chainlint/here-doc.test
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								t/chainlint/here-doc.test
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,16 @@ | ||||
| # 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 (EOF is last line of test) | ||||
| horticulture <<\EOF | ||||
| gomez | ||||
| morticia | ||||
| wednesday | ||||
| pugsly | ||||
| EOF | ||||
							
								
								
									
										12
									
								
								t/chainlint/if-in-loop.expect
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								t/chainlint/if-in-loop.expect
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | ||||
| ( | ||||
| 	for i in a b c | ||||
| 	do | ||||
| 		if false | ||||
| 		then | ||||
| ?!AMP?!			echo "err" | ||||
| 			exit 1 | ||||
| ?!AMP?!		fi | ||||
| 		foo | ||||
| ?!AMP?!	done | ||||
| 	bar | ||||
| >) | ||||
							
								
								
									
										15
									
								
								t/chainlint/if-in-loop.test
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								t/chainlint/if-in-loop.test
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | ||||
| ( | ||||
| 	for i in a b c | ||||
| 	do | ||||
| 		if false | ||||
| 		then | ||||
| # LINT: missing "&&" on 'echo' | ||||
| 			echo "err" | ||||
| 			exit 1 | ||||
| # LINT: missing "&&" on 'fi' | ||||
| 		fi | ||||
| 		foo | ||||
| # LINT: missing "&&" on 'done' | ||||
| 	done | ||||
| 	bar | ||||
| ) | ||||
							
								
								
									
										19
									
								
								t/chainlint/if-then-else.expect
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								t/chainlint/if-then-else.expect
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,19 @@ | ||||
| ( | ||||
| 	if test -n "" | ||||
| 	then | ||||
| ?!AMP?!		echo very | ||||
| 		echo empty | ||||
| 	elif test -z "" | ||||
| 		echo foo | ||||
| 	else | ||||
| 		echo foo && | ||||
| 		cat | ||||
| ?!AMP?!	fi | ||||
| 	echo poodle | ||||
| >) && | ||||
| ( | ||||
| 	if test -n ""; then | ||||
| 		echo very && | ||||
| ?!AMP?!		echo empty | ||||
| 	if | ||||
| >) | ||||
							
								
								
									
										28
									
								
								t/chainlint/if-then-else.test
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								t/chainlint/if-then-else.test
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,28 @@ | ||||
| ( | ||||
| # 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 "" | ||||
| # 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 | ||||
| 	if | ||||
| ) | ||||
							
								
								
									
										4
									
								
								t/chainlint/incomplete-line.expect
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								t/chainlint/incomplete-line.expect
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,4 @@ | ||||
| line 1 line 2 line 3 line 4 && | ||||
| ( | ||||
| 	line 5 	line 6 	line 7 	line 8 | ||||
| >) | ||||
							
								
								
									
										12
									
								
								t/chainlint/incomplete-line.test
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								t/chainlint/incomplete-line.test
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | ||||
| # 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 | ||||
| ) | ||||
							
								
								
									
										9
									
								
								t/chainlint/inline-comment.expect
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								t/chainlint/inline-comment.expect
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | ||||
| ( | ||||
| 	foobar && | ||||
| ?!AMP?!	barfoo | ||||
| 	flibble "not a # comment" | ||||
| >) && | ||||
|  | ||||
| ( | ||||
| cd foo && | ||||
| >	flibble "not a # comment") | ||||
							
								
								
									
										12
									
								
								t/chainlint/inline-comment.test
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								t/chainlint/inline-comment.test
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | ||||
| ( | ||||
| # 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") | ||||
							
								
								
									
										12
									
								
								t/chainlint/loop-in-if.expect
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								t/chainlint/loop-in-if.expect
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | ||||
| ( | ||||
| 	if true | ||||
| 	then | ||||
| 		while true | ||||
| 		do | ||||
| ?!AMP?!			echo "pop" | ||||
| 			echo "glup" | ||||
| ?!AMP?!		done | ||||
| 		foo | ||||
| ?!AMP?!	fi | ||||
| 	bar | ||||
| >) | ||||
							
								
								
									
										15
									
								
								t/chainlint/loop-in-if.test
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								t/chainlint/loop-in-if.test
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | ||||
| ( | ||||
| 	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 | ||||
| ) | ||||
| @ -0,0 +1,9 @@ | ||||
| ( | ||||
| 	foo && | ||||
| 	x=$( | ||||
| 		echo bar | | ||||
| 		cat | ||||
| >>	) && | ||||
| 	echo ok | ||||
| >) | | ||||
| sort | ||||
							
								
								
									
										9
									
								
								t/chainlint/multi-line-nested-command-substitution.test
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								t/chainlint/multi-line-nested-command-substitution.test
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | ||||
| ( | ||||
| 	foo && | ||||
| 	x=$( | ||||
| 		echo bar | | ||||
| 		cat | ||||
| 	) && | ||||
| 	echo ok | ||||
| ) | | ||||
| sort | ||||
							
								
								
									
										9
									
								
								t/chainlint/multi-line-string.expect
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								t/chainlint/multi-line-string.expect
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | ||||
| ( | ||||
| 	x=line 1		line 2		line 3" && | ||||
| ?!AMP?!	y=line 1		line2' | ||||
| 	foobar | ||||
| >) && | ||||
| ( | ||||
| 	echo "there's nothing to see here" && | ||||
| 	exit | ||||
| >) | ||||
							
								
								
									
										15
									
								
								t/chainlint/multi-line-string.test
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								t/chainlint/multi-line-string.test
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | ||||
| ( | ||||
| 	x="line 1 | ||||
| 		line 2 | ||||
| 		line 3" && | ||||
| # LINT: missing "&&" on assignment | ||||
| 	y='line 1 | ||||
| 		line2' | ||||
| 	foobar | ||||
| ) && | ||||
| ( | ||||
| # LINT: apostrophe (in a contraction) within string not misinterpreted as | ||||
| # LINT: starting multi-line single-quoted string | ||||
| 	echo "there's nothing to see here" && | ||||
| 	exit | ||||
| ) | ||||
							
								
								
									
										5
									
								
								t/chainlint/negated-one-liner.expect
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								t/chainlint/negated-one-liner.expect
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | ||||
| ! (foo && bar) && | ||||
| ! (foo && bar) >baz && | ||||
|  | ||||
| ?!SEMI?!! (foo; bar) && | ||||
| ?!SEMI?!! (foo; bar) >baz | ||||
							
								
								
									
										7
									
								
								t/chainlint/negated-one-liner.test
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								t/chainlint/negated-one-liner.test
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | ||||
| # LINT: top-level one-liner subshell | ||||
| ! (foo && bar) && | ||||
| ! (foo && bar) >baz && | ||||
|  | ||||
| # LINT: top-level one-liner subshell missing internal "&&" | ||||
| ! (foo; bar) && | ||||
| ! (foo; bar) >baz | ||||
							
								
								
									
										19
									
								
								t/chainlint/nested-cuddled-subshell.expect
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								t/chainlint/nested-cuddled-subshell.expect
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,19 @@ | ||||
| ( | ||||
| 	(cd foo && | ||||
| 		bar | ||||
| >>	) && | ||||
| 	(cd foo && | ||||
| 		bar | ||||
| ?!AMP?!>>	) | ||||
| 	( | ||||
| 		cd foo && | ||||
| >>		bar) && | ||||
| 	( | ||||
| 		cd foo && | ||||
| ?!AMP?!>>		bar) | ||||
| 	(cd foo && | ||||
| >>		bar) && | ||||
| 	(cd foo && | ||||
| ?!AMP?!>>		bar) | ||||
| 	foobar | ||||
| >) | ||||
							
								
								
									
										31
									
								
								t/chainlint/nested-cuddled-subshell.test
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								t/chainlint/nested-cuddled-subshell.test
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,31 @@ | ||||
| ( | ||||
| # 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 | ||||
| ) | ||||
							
								
								
									
										5
									
								
								t/chainlint/nested-here-doc.expect
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								t/chainlint/nested-here-doc.expect
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | ||||
| ( | ||||
| 	cat && | ||||
| ?!AMP?!	cat | ||||
| 	foobar | ||||
| >) | ||||
							
								
								
									
										23
									
								
								t/chainlint/nested-here-doc.test
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								t/chainlint/nested-here-doc.test
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,23 @@ | ||||
| ( | ||||
| # 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 | ||||
| ) | ||||
							
								
								
									
										11
									
								
								t/chainlint/nested-subshell-comment.expect
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								t/chainlint/nested-subshell-comment.expect
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,11 @@ | ||||
| ( | ||||
| 	foo && | ||||
| 	( | ||||
| 		bar && | ||||
| 		# bottles wobble while fiddles gobble | ||||
| 		# minor numbers of cows (or do they?) | ||||
| 		baz && | ||||
| 		snaff | ||||
| ?!AMP?!>>	) | ||||
| 	fuzzy | ||||
| >) | ||||
							
								
								
									
										13
									
								
								t/chainlint/nested-subshell-comment.test
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								t/chainlint/nested-subshell-comment.test
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,13 @@ | ||||
| ( | ||||
| 	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 | ||||
| ) | ||||
							
								
								
									
										12
									
								
								t/chainlint/nested-subshell.expect
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								t/chainlint/nested-subshell.expect
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | ||||
| ( | ||||
| 	cd foo && | ||||
| 	( | ||||
| 		echo a && | ||||
| 		echo b | ||||
| >>	) >file && | ||||
| 	cd foo && | ||||
| 	( | ||||
| 		echo a | ||||
| 		echo b | ||||
| >>	) >file | ||||
| >) | ||||
							
								
								
									
										14
									
								
								t/chainlint/nested-subshell.test
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								t/chainlint/nested-subshell.test
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,14 @@ | ||||
| ( | ||||
| 	cd foo && | ||||
| 	( | ||||
| 		echo a && | ||||
| 		echo b | ||||
| 	) >file && | ||||
|  | ||||
| 	cd foo && | ||||
| 	( | ||||
| # LINT: nested multi-line subshell not presently checked for missing "&&" | ||||
| 		echo a | ||||
| 		echo b | ||||
| 	) >file | ||||
| ) | ||||
							
								
								
									
										9
									
								
								t/chainlint/one-liner.expect
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								t/chainlint/one-liner.expect
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | ||||
| (foo && bar) && | ||||
| (foo && bar) | | ||||
| (foo && bar) >baz && | ||||
|  | ||||
| ?!SEMI?!(foo; bar) && | ||||
| ?!SEMI?!(foo; bar) | | ||||
| ?!SEMI?!(foo; bar) >baz | ||||
|  | ||||
| (foo "bar; baz") | ||||
							
								
								
									
										12
									
								
								t/chainlint/one-liner.test
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								t/chainlint/one-liner.test
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | ||||
| # LINT: top-level one-liner subshell | ||||
| (foo && bar) && | ||||
| (foo && bar) | | ||||
| (foo && bar) >baz && | ||||
|  | ||||
| # LINT: top-level one-liner subshell missing internal "&&" | ||||
| (foo; bar) && | ||||
| (foo; bar) | | ||||
| (foo; bar) >baz | ||||
|  | ||||
| # LINT: ";" in string not misinterpreted as broken &&-chain | ||||
| (foo "bar; baz") | ||||
							
								
								
									
										4
									
								
								t/chainlint/p4-filespec.expect
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								t/chainlint/p4-filespec.expect
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,4 @@ | ||||
| ( | ||||
| 	p4 print -1 //depot/fiddle#42 >file && | ||||
| 	foobar | ||||
| >) | ||||
							
								
								
									
										5
									
								
								t/chainlint/p4-filespec.test
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								t/chainlint/p4-filespec.test
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | ||||
| ( | ||||
| # LINT: Perforce revspec in filespec not misinterpreted as in-line comment | ||||
| 	p4 print -1 //depot/fiddle#42 >file && | ||||
| 	foobar | ||||
| ) | ||||
							
								
								
									
										8
									
								
								t/chainlint/pipe.expect
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								t/chainlint/pipe.expect
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | ||||
| ( | ||||
| 	foo | | ||||
| 	bar | | ||||
| 	baz && | ||||
| 	fish | | ||||
| ?!AMP?!	cow | ||||
| 	sunder | ||||
| >) | ||||
							
								
								
									
										12
									
								
								t/chainlint/pipe.test
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								t/chainlint/pipe.test
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | ||||
| ( | ||||
| # LINT: no "&&" needed on line ending with "|" | ||||
| 	foo | | ||||
| 	bar | | ||||
| 	baz && | ||||
|  | ||||
| # LINT: final line of pipe sequence ('cow') lacking "&&" | ||||
| 	fish | | ||||
| 	cow | ||||
|  | ||||
| 	sunder | ||||
| ) | ||||
							
								
								
									
										20
									
								
								t/chainlint/semicolon.expect
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								t/chainlint/semicolon.expect
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,20 @@ | ||||
| ( | ||||
| ?!AMP?!?!SEMI?!	cat foo ; echo bar | ||||
| ?!SEMI?!	cat foo ; echo bar | ||||
| >) && | ||||
| ( | ||||
| ?!SEMI?!	cat foo ; echo bar && | ||||
| ?!SEMI?!	cat foo ; echo bar | ||||
| >) && | ||||
| ( | ||||
| 	echo "foo; bar" && | ||||
| ?!SEMI?!	cat foo; echo bar | ||||
| >) && | ||||
| ( | ||||
| ?!SEMI?!	foo; | ||||
| >) && | ||||
| ( | ||||
| cd foo && | ||||
| 	for i in a b c; do | ||||
| ?!SEMI?!		echo; | ||||
| >	done) | ||||
							
								
								
									
										25
									
								
								t/chainlint/semicolon.test
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								t/chainlint/semicolon.test
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,25 @@ | ||||
| ( | ||||
| # 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: unnecessary terminating semicolon | ||||
| 	foo; | ||||
| ) && | ||||
| (cd foo && | ||||
| 	for i in a b c; do | ||||
| # LINT: unnecessary terminating semicolon | ||||
| 		echo; | ||||
| 	done) | ||||
							
								
								
									
										5
									
								
								t/chainlint/subshell-here-doc.expect
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								t/chainlint/subshell-here-doc.expect
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | ||||
| ( | ||||
| 	echo wobba 	       gorgo snoot 	       wafta snurb && | ||||
| ?!AMP?!	cat >bip | ||||
| 	echo >bop | ||||
| >) | ||||
							
								
								
									
										23
									
								
								t/chainlint/subshell-here-doc.test
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								t/chainlint/subshell-here-doc.test
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,23 @@ | ||||
| ( | ||||
| # 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 | ||||
| ) | ||||
							
								
								
									
										14
									
								
								t/chainlint/subshell-one-liner.expect
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								t/chainlint/subshell-one-liner.expect
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,14 @@ | ||||
| ( | ||||
| 	(foo && bar) && | ||||
| 	(foo && bar) | | ||||
| 	(foo && bar) >baz && | ||||
| ?!SEMI?!	(foo; bar) && | ||||
| ?!SEMI?!	(foo; bar) | | ||||
| ?!SEMI?!	(foo; bar) >baz && | ||||
| 	(foo || exit 1) && | ||||
| 	(foo || exit 1) | | ||||
| 	(foo || exit 1) >baz && | ||||
| ?!AMP?!	(foo && bar) | ||||
| ?!AMP?!?!SEMI?!	(foo && bar; baz) | ||||
| 	foobar | ||||
| >) | ||||
							
								
								
									
										24
									
								
								t/chainlint/subshell-one-liner.test
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								t/chainlint/subshell-one-liner.test
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,24 @@ | ||||
| ( | ||||
| # 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 | ||||
| ) | ||||
							
								
								
									
										11
									
								
								t/chainlint/while-loop.expect
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								t/chainlint/while-loop.expect
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,11 @@ | ||||
| ( | ||||
| 	while true | ||||
| 	do | ||||
| ?!AMP?!		echo foo | ||||
| 		cat | ||||
| ?!AMP?!	done | ||||
| 	while true; do | ||||
| 		echo foo && | ||||
| 		cat bar | ||||
| 	done | ||||
| >) | ||||
							
								
								
									
										19
									
								
								t/chainlint/while-loop.test
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								t/chainlint/while-loop.test
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,19 @@ | ||||
| ( | ||||
| # 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 | ||||
| ) | ||||
| @ -675,7 +675,8 @@ test_run_ () { | ||||
| 		trace= | ||||
| 		# 117 is magic because it is unlikely to match the exit | ||||
| 		# code of other programs | ||||
| 		if test "OK-117" != "$(test_eval_ "(exit 117) && $1${LF}${LF}echo OK-\$?" 3>&1)" | ||||
| 		if $(printf '%s\n' "$1" | sed -f "$GIT_BUILD_DIR/t/chainlint.sed" | grep -q '?![A-Z][A-Z]*?!') || | ||||
| 			test "OK-117" != "$(test_eval_ "(exit 117) && $1${LF}${LF}echo OK-\$?" 3>&1)" | ||||
| 		then | ||||
| 			error "bug in the test script: broken &&-chain or run-away HERE-DOC: $1" | ||||
| 		fi | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	 Junio C Hamano
					Junio C Hamano