{-
    Copyright 2012-2022 Vidar Holen

    This file is part of ShellCheck.
    https://www.shellcheck.net

    ShellCheck is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    ShellCheck is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.
-}
{-# LANGUAGE TemplateHaskell #-}
module ShellCheck.Checker (checkScript, ShellCheck.Checker.runTests) where

import ShellCheck.Analyzer
import ShellCheck.ASTLib
import ShellCheck.Interface
import ShellCheck.Parser

import Debug.Trace -- DO NOT SUBMIT
import Data.Either
import Data.Functor
import Data.List
import Data.Maybe
import Data.Ord
import Control.Monad.Identity
import qualified Data.Map as Map
import qualified System.IO
import Prelude hiding (readFile)
import Control.Monad

import Test.QuickCheck.All

tokenToPosition :: Map Id (Position, Position) -> TokenComment -> PositionedComment
tokenToPosition Map Id (Position, Position)
startMap TokenComment
t = PositionedComment -> Maybe PositionedComment -> PositionedComment
forall a. a -> Maybe a -> a
fromMaybe PositionedComment
forall {a}. a
fail (Maybe PositionedComment -> PositionedComment)
-> Maybe PositionedComment -> PositionedComment
forall a b. (a -> b) -> a -> b
$ do
    (Position, Position)
span <- Id -> Map Id (Position, Position) -> Maybe (Position, Position)
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup (TokenComment -> Id
tcId TokenComment
t) Map Id (Position, Position)
startMap
    PositionedComment -> Maybe PositionedComment
forall a. a -> Maybe a
forall (m :: * -> *) a. Monad m => a -> m a
return (PositionedComment -> Maybe PositionedComment)
-> PositionedComment -> Maybe PositionedComment
forall a b. (a -> b) -> a -> b
$ PositionedComment
newPositionedComment {
        pcStartPos = fst span,
        pcEndPos = snd span,
        pcComment = tcComment t,
        pcFix = tcFix t
    }
  where
    fail :: a
fail = [Char] -> a
forall a. HasCallStack => [Char] -> a
error [Char]
"Internal shellcheck error: id doesn't exist. Please report!"

shellFromFilename :: [Char] -> Maybe Shell
shellFromFilename [Char]
filename = [Shell] -> Maybe Shell
forall a. [a] -> Maybe a
listToMaybe [Shell]
candidates
  where
    shellExtensions :: [([Char], Shell)]
shellExtensions = [([Char]
".ksh", Shell
Ksh)
                      ,([Char]
".bash", Shell
Bash)
                      ,([Char]
".bats", Shell
Bash)
                      ,([Char]
".dash", Shell
Dash)]
                      -- The `.sh` is too generic to determine the shell:
                      -- We fallback to Bash in this case and emit SC2148 if there is no shebang
    candidates :: [Shell]
candidates =
        [Shell
sh | ([Char]
ext,Shell
sh) <- [([Char], Shell)]
shellExtensions, [Char]
ext [Char] -> [Char] -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isSuffixOf` [Char]
filename]

checkScript :: Monad m => SystemInterface m -> CheckSpec -> m CheckResult
checkScript :: forall (m :: * -> *).
Monad m =>
SystemInterface m -> CheckSpec -> m CheckResult
checkScript SystemInterface m
sys CheckSpec
spec = do
    [PositionedComment]
results <- [Char] -> m [PositionedComment]
checkScript (CheckSpec -> [Char]
csScript CheckSpec
spec)
    CheckResult -> m CheckResult
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return CheckResult
emptyCheckResult {
        crFilename = csFilename spec,
        crComments = results
    }
  where
    checkScript :: [Char] -> m [PositionedComment]
checkScript [Char]
contents = do
        ParseResult
result <- SystemInterface m -> ParseSpec -> m ParseResult
forall (m :: * -> *).
Monad m =>
SystemInterface m -> ParseSpec -> m ParseResult
parseScript SystemInterface m
sys ParseSpec
newParseSpec {
            psFilename = csFilename spec,
            psScript = contents,
            psCheckSourced = csCheckSourced spec,
            psIgnoreRC = csIgnoreRC spec,
            psShellTypeOverride = csShellTypeOverride spec
        }
        let parseMessages :: [PositionedComment]
parseMessages = ParseResult -> [PositionedComment]
prComments ParseResult
result
        let tokenPositions :: Map Id (Position, Position)
tokenPositions = ParseResult -> Map Id (Position, Position)
prTokenPositions ParseResult
result
        let analysisSpec :: Token -> AnalysisSpec
analysisSpec Token
root =
                AnalysisSpec
as {
                    asScript = root,
                    asShellType = csShellTypeOverride spec,
                    asFallbackShell = shellFromFilename $ csFilename spec,
                    asCheckSourced = csCheckSourced spec,
                    asExecutionMode = Executed,
                    asTokenPositions = tokenPositions,
                    asExtendedAnalysis = csExtendedAnalysis spec,
                    asOptionalChecks = getEnableDirectives root ++ csOptionalChecks spec
                } where as :: AnalysisSpec
as = Token -> AnalysisSpec
newAnalysisSpec Token
root
        let analysisMessages :: [TokenComment]
analysisMessages =
                [TokenComment]
-> (Token -> [TokenComment]) -> Maybe Token -> [TokenComment]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe []
                    (AnalysisResult -> [TokenComment]
arComments (AnalysisResult -> [TokenComment])
-> (Token -> AnalysisResult) -> Token -> [TokenComment]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. AnalysisSpec -> AnalysisResult
analyzeScript (AnalysisSpec -> AnalysisResult)
-> (Token -> AnalysisSpec) -> Token -> AnalysisResult
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Token -> AnalysisSpec
analysisSpec)
                        (Maybe Token -> [TokenComment]) -> Maybe Token -> [TokenComment]
forall a b. (a -> b) -> a -> b
$ ParseResult -> Maybe Token
prRoot ParseResult
result
        let translator :: TokenComment -> PositionedComment
translator = Map Id (Position, Position) -> TokenComment -> PositionedComment
tokenToPosition Map Id (Position, Position)
tokenPositions
        [PositionedComment] -> m [PositionedComment]
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return ([PositionedComment] -> m [PositionedComment])
-> ([PositionedComment] -> [PositionedComment])
-> [PositionedComment]
-> m [PositionedComment]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [PositionedComment] -> [PositionedComment]
forall a. Eq a => [a] -> [a]
nub ([PositionedComment] -> [PositionedComment])
-> ([PositionedComment] -> [PositionedComment])
-> [PositionedComment]
-> [PositionedComment]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [PositionedComment] -> [PositionedComment]
sortMessages ([PositionedComment] -> [PositionedComment])
-> ([PositionedComment] -> [PositionedComment])
-> [PositionedComment]
-> [PositionedComment]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (PositionedComment -> Bool)
-> [PositionedComment] -> [PositionedComment]
forall a. (a -> Bool) -> [a] -> [a]
filter PositionedComment -> Bool
shouldInclude ([PositionedComment] -> m [PositionedComment])
-> [PositionedComment] -> m [PositionedComment]
forall a b. (a -> b) -> a -> b
$
            ([PositionedComment]
parseMessages [PositionedComment] -> [PositionedComment] -> [PositionedComment]
forall a. [a] -> [a] -> [a]
++ (TokenComment -> PositionedComment)
-> [TokenComment] -> [PositionedComment]
forall a b. (a -> b) -> [a] -> [b]
map TokenComment -> PositionedComment
translator [TokenComment]
analysisMessages)

    shouldInclude :: PositionedComment -> Bool
shouldInclude PositionedComment
pc =
            Severity
severity Severity -> Severity -> Bool
forall a. Ord a => a -> a -> Bool
<= CheckSpec -> Severity
csMinSeverity CheckSpec
spec Bool -> Bool -> Bool
&&
            case CheckSpec -> Maybe [Code]
csIncludedWarnings CheckSpec
spec of
                Maybe [Code]
Nothing -> Code
code Code -> [Code] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` CheckSpec -> [Code]
csExcludedWarnings CheckSpec
spec
                Just [Code]
includedWarnings -> Code
code Code -> [Code] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Code]
includedWarnings
        where
            code :: Code
code     = Comment -> Code
cCode (PositionedComment -> Comment
pcComment PositionedComment
pc)
            severity :: Severity
severity = Comment -> Severity
cSeverity (PositionedComment -> Comment
pcComment PositionedComment
pc)

    sortMessages :: [PositionedComment] -> [PositionedComment]
sortMessages = (PositionedComment -> ([Char], Code, Code, Severity, Code, [Char]))
-> [PositionedComment] -> [PositionedComment]
forall b a. Ord b => (a -> b) -> [a] -> [a]
sortOn PositionedComment -> ([Char], Code, Code, Severity, Code, [Char])
order
    order :: PositionedComment -> ([Char], Code, Code, Severity, Code, [Char])
order PositionedComment
pc =
        let pos :: Position
pos = PositionedComment -> Position
pcStartPos PositionedComment
pc
            comment :: Comment
comment = PositionedComment -> Comment
pcComment PositionedComment
pc in
        (Position -> [Char]
posFile Position
pos,
         Position -> Code
posLine Position
pos,
         Position -> Code
posColumn Position
pos,
         Comment -> Severity
cSeverity Comment
comment,
         Comment -> Code
cCode Comment
comment,
         Comment -> [Char]
cMessage Comment
comment)
    getPosition :: PositionedComment -> Position
getPosition = PositionedComment -> Position
pcStartPos


getErrors :: SystemInterface Identity -> CheckSpec -> [Code]
getErrors SystemInterface Identity
sys CheckSpec
spec =
    [Code] -> [Code]
forall a. Ord a => [a] -> [a]
sort ([Code] -> [Code])
-> (CheckResult -> [Code]) -> CheckResult -> [Code]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (PositionedComment -> Code) -> [PositionedComment] -> [Code]
forall a b. (a -> b) -> [a] -> [b]
map PositionedComment -> Code
getCode ([PositionedComment] -> [Code])
-> (CheckResult -> [PositionedComment]) -> CheckResult -> [Code]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CheckResult -> [PositionedComment]
crComments (CheckResult -> [Code]) -> CheckResult -> [Code]
forall a b. (a -> b) -> a -> b
$
        Identity CheckResult -> CheckResult
forall a. Identity a -> a
runIdentity (SystemInterface Identity -> CheckSpec -> Identity CheckResult
forall (m :: * -> *).
Monad m =>
SystemInterface m -> CheckSpec -> m CheckResult
checkScript SystemInterface Identity
sys CheckSpec
spec)
  where
    getCode :: PositionedComment -> Code
getCode = Comment -> Code
cCode (Comment -> Code)
-> (PositionedComment -> Comment) -> PositionedComment -> Code
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PositionedComment -> Comment
pcComment

check :: [Char] -> [Code]
check = [([Char], [Char])] -> [Char] -> [Code]
checkWithIncludes []

checkWithSpec :: [([Char], [Char])] -> CheckSpec -> [Code]
checkWithSpec [([Char], [Char])]
includes =
    SystemInterface Identity -> CheckSpec -> [Code]
getErrors ([([Char], [Char])] -> SystemInterface Identity
mockedSystemInterface [([Char], [Char])]
includes)

checkWithIncludes :: [([Char], [Char])] -> [Char] -> [Code]
checkWithIncludes [([Char], [Char])]
includes [Char]
src =
    [([Char], [Char])] -> CheckSpec -> [Code]
checkWithSpec [([Char], [Char])]
includes CheckSpec
emptyCheckSpec {
        csScript = src,
        csExcludedWarnings = [2148]
    }

checkRecursive :: [([Char], [Char])] -> [Char] -> [Code]
checkRecursive [([Char], [Char])]
includes [Char]
src =
    [([Char], [Char])] -> CheckSpec -> [Code]
checkWithSpec [([Char], [Char])]
includes CheckSpec
emptyCheckSpec {
        csScript = src,
        csExcludedWarnings = [2148],
        csCheckSourced = True
    }

checkOptionIncludes :: Maybe [Code] -> [Char] -> [Code]
checkOptionIncludes Maybe [Code]
includes [Char]
src =
    [([Char], [Char])] -> CheckSpec -> [Code]
checkWithSpec [] CheckSpec
emptyCheckSpec {
        csScript = src,
        csIncludedWarnings = includes,
        csCheckSourced = True
    }

checkWithRc :: [Char] -> CheckSpec -> [Code]
checkWithRc [Char]
rc = SystemInterface Identity -> CheckSpec -> [Code]
getErrors
    ([Char] -> SystemInterface Identity -> SystemInterface Identity
forall {m :: * -> *}.
Monad m =>
[Char] -> SystemInterface m -> SystemInterface m
mockRcFile [Char]
rc (SystemInterface Identity -> SystemInterface Identity)
-> SystemInterface Identity -> SystemInterface Identity
forall a b. (a -> b) -> a -> b
$ [([Char], [Char])] -> SystemInterface Identity
mockedSystemInterface [])

checkWithIncludesAndSourcePath :: [([Char], [Char])]
-> ([Char] -> Maybe Bool -> [[Char]] -> [Char] -> Identity [Char])
-> CheckSpec
-> [Code]
checkWithIncludesAndSourcePath [([Char], [Char])]
includes [Char] -> Maybe Bool -> [[Char]] -> [Char] -> Identity [Char]
mapper = SystemInterface Identity -> CheckSpec -> [Code]
getErrors
    ([([Char], [Char])] -> SystemInterface Identity
mockedSystemInterface [([Char], [Char])]
includes) {
        siFindSource = mapper
    }

checkWithRcIncludesAndSourcePath :: [Char]
-> [([Char], [Char])]
-> ([Char] -> Maybe Bool -> [[Char]] -> [Char] -> Identity [Char])
-> CheckSpec
-> [Code]
checkWithRcIncludesAndSourcePath [Char]
rc [([Char], [Char])]
includes [Char] -> Maybe Bool -> [[Char]] -> [Char] -> Identity [Char]
mapper = SystemInterface Identity -> CheckSpec -> [Code]
getErrors
    ([Char] -> SystemInterface Identity -> SystemInterface Identity
forall {m :: * -> *}.
Monad m =>
[Char] -> SystemInterface m -> SystemInterface m
mockRcFile [Char]
rc (SystemInterface Identity -> SystemInterface Identity)
-> SystemInterface Identity -> SystemInterface Identity
forall a b. (a -> b) -> a -> b
$ [([Char], [Char])] -> SystemInterface Identity
mockedSystemInterface [([Char], [Char])]
includes) {
        siFindSource = mapper
    }

prop_findsParseIssue :: Bool
prop_findsParseIssue = [Char] -> [Code]
check [Char]
"echo \"$12\"" [Code] -> [Code] -> Bool
forall a. Eq a => a -> a -> Bool
== [Code
1037]

prop_commentDisablesParseIssue1 :: Bool
prop_commentDisablesParseIssue1 =
    [Code] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([Code] -> Bool) -> [Code] -> Bool
forall a b. (a -> b) -> a -> b
$ [Char] -> [Code]
check [Char]
"#shellcheck disable=SC1037\necho \"$12\""
prop_commentDisablesParseIssue2 :: Bool
prop_commentDisablesParseIssue2 =
    [Code] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([Code] -> Bool) -> [Code] -> Bool
forall a b. (a -> b) -> a -> b
$ [Char] -> [Code]
check [Char]
"#shellcheck disable=SC1037\n#lol\necho \"$12\""

prop_findsAnalysisIssue :: Bool
prop_findsAnalysisIssue =
    [Char] -> [Code]
check [Char]
"echo $1" [Code] -> [Code] -> Bool
forall a. Eq a => a -> a -> Bool
== [Code
2086]
prop_commentDisablesAnalysisIssue1 :: Bool
prop_commentDisablesAnalysisIssue1 =
    [Code] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([Code] -> Bool) -> [Code] -> Bool
forall a b. (a -> b) -> a -> b
$ [Char] -> [Code]
check [Char]
"#shellcheck disable=SC2086\necho $1"
prop_commentDisablesAnalysisIssue2 :: Bool
prop_commentDisablesAnalysisIssue2 =
    [Code] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([Code] -> Bool) -> [Code] -> Bool
forall a b. (a -> b) -> a -> b
$ [Char] -> [Code]
check [Char]
"#shellcheck disable=SC2086\n#lol\necho $1"

prop_optionDisablesIssue1 :: Bool
prop_optionDisablesIssue1 =
    [Code] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([Code] -> Bool) -> [Code] -> Bool
forall a b. (a -> b) -> a -> b
$ SystemInterface Identity -> CheckSpec -> [Code]
getErrors
                ([([Char], [Char])] -> SystemInterface Identity
mockedSystemInterface [])
                CheckSpec
emptyCheckSpec {
                    csScript = "echo $1",
                    csExcludedWarnings = [2148, 2086]
                }

prop_optionDisablesIssue2 :: Bool
prop_optionDisablesIssue2 =
    [Code] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([Code] -> Bool) -> [Code] -> Bool
forall a b. (a -> b) -> a -> b
$ SystemInterface Identity -> CheckSpec -> [Code]
getErrors
                ([([Char], [Char])] -> SystemInterface Identity
mockedSystemInterface [])
                CheckSpec
emptyCheckSpec {
                    csScript = "echo \"$10\"",
                    csExcludedWarnings = [2148, 1037]
                }

prop_wontParseBadShell :: Bool
prop_wontParseBadShell =
    [Code
1071] [Code] -> [Code] -> Bool
forall a. Eq a => a -> a -> Bool
== [Char] -> [Code]
check [Char]
"#!/usr/bin/python\ntrue $1\n"

prop_optionDisablesBadShebang :: Bool
prop_optionDisablesBadShebang =
    [Code] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([Code] -> Bool) -> [Code] -> Bool
forall a b. (a -> b) -> a -> b
$ SystemInterface Identity -> CheckSpec -> [Code]
getErrors
                ([([Char], [Char])] -> SystemInterface Identity
mockedSystemInterface [])
                CheckSpec
emptyCheckSpec {
                    csScript = "#!/usr/bin/python\ntrue\n",
                    csShellTypeOverride = Just Sh
                }

prop_annotationDisablesBadShebang :: Bool
prop_annotationDisablesBadShebang =
    [Code] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([Code] -> Bool) -> [Code] -> Bool
forall a b. (a -> b) -> a -> b
$ [Char] -> [Code]
check [Char]
"#!/usr/bin/python\n# shellcheck shell=sh\ntrue\n"


prop_canParseDevNull :: Bool
prop_canParseDevNull =
    [Code] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([Code] -> Bool) -> [Code] -> Bool
forall a b. (a -> b) -> a -> b
$ [Char] -> [Code]
check [Char]
"source /dev/null"

prop_failsWhenNotSourcing :: Bool
prop_failsWhenNotSourcing =
    [Code
1091, Code
2154] [Code] -> [Code] -> Bool
forall a. Eq a => a -> a -> Bool
== [Char] -> [Code]
check [Char]
"source lol; echo \"$bar\""

prop_worksWhenSourcing :: Bool
prop_worksWhenSourcing =
    [Code] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([Code] -> Bool) -> [Code] -> Bool
forall a b. (a -> b) -> a -> b
$ [([Char], [Char])] -> [Char] -> [Code]
checkWithIncludes [([Char]
"lib", [Char]
"bar=1")] [Char]
"source lib; echo \"$bar\""

prop_worksWhenSourcingWithDashDash :: Bool
prop_worksWhenSourcingWithDashDash =
    [Code] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([Code] -> Bool) -> [Code] -> Bool
forall a b. (a -> b) -> a -> b
$ [([Char], [Char])] -> [Char] -> [Code]
checkWithIncludes [([Char]
"lib", [Char]
"bar=1")] [Char]
"source -- lib; echo \"$bar\""

prop_worksWhenDotting :: Bool
prop_worksWhenDotting =
    [Code] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([Code] -> Bool) -> [Code] -> Bool
forall a b. (a -> b) -> a -> b
$ [([Char], [Char])] -> [Char] -> [Code]
checkWithIncludes [([Char]
"lib", [Char]
"bar=1")] [Char]
". lib; echo \"$bar\""

-- FIXME: This should really be giving [1093], "recursively sourced"
prop_noInfiniteSourcing :: Bool
prop_noInfiniteSourcing =
    [Code] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([Code] -> Bool) -> [Code] -> Bool
forall a b. (a -> b) -> a -> b
$ [([Char], [Char])] -> [Char] -> [Code]
checkWithIncludes  [([Char]
"lib", [Char]
"source lib")] [Char]
"source lib"

prop_canSourceBadSyntax :: Bool
prop_canSourceBadSyntax =
    [Code
1094, Code
2086] [Code] -> [Code] -> Bool
forall a. Eq a => a -> a -> Bool
== [([Char], [Char])] -> [Char] -> [Code]
checkWithIncludes [([Char]
"lib", [Char]
"for f; do")] [Char]
"source lib; echo $1"

prop_cantSourceDynamic :: Bool
prop_cantSourceDynamic =
    [Code
1090] [Code] -> [Code] -> Bool
forall a. Eq a => a -> a -> Bool
== [([Char], [Char])] -> [Char] -> [Code]
checkWithIncludes [([Char]
"lib", [Char]
"")] [Char]
". \"$1\""

prop_cantSourceDynamic2 :: Bool
prop_cantSourceDynamic2 =
    [Code
1090] [Code] -> [Code] -> Bool
forall a. Eq a => a -> a -> Bool
== [([Char], [Char])] -> [Char] -> [Code]
checkWithIncludes [([Char]
"lib", [Char]
"")] [Char]
"source ~/foo"

prop_canStripPrefixAndSource :: Bool
prop_canStripPrefixAndSource =
    [Code] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([Code] -> Bool) -> [Code] -> Bool
forall a b. (a -> b) -> a -> b
$ [([Char], [Char])] -> [Char] -> [Code]
checkWithIncludes [([Char]
"./lib", [Char]
"")] [Char]
"source \"$MYDIR/lib\""

prop_canStripPrefixAndSource2 :: Bool
prop_canStripPrefixAndSource2 =
    [Code] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([Code] -> Bool) -> [Code] -> Bool
forall a b. (a -> b) -> a -> b
$ [([Char], [Char])] -> [Char] -> [Code]
checkWithIncludes [([Char]
"./utils.sh", [Char]
"")] [Char]
"source \"$(dirname \"${BASH_SOURCE[0]}\")/utils.sh\""

prop_canSourceDynamicWhenRedirected :: Bool
prop_canSourceDynamicWhenRedirected =
    [Code] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([Code] -> Bool) -> [Code] -> Bool
forall a b. (a -> b) -> a -> b
$ [([Char], [Char])] -> [Char] -> [Code]
checkWithIncludes [([Char]
"lib", [Char]
"")] [Char]
"#shellcheck source=lib\n. \"$1\""

prop_canRedirectWithSpaces :: Bool
prop_canRedirectWithSpaces =
    [Code] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([Code] -> Bool) -> [Code] -> Bool
forall a b. (a -> b) -> a -> b
$ [([Char], [Char])] -> [Char] -> [Code]
checkWithIncludes [([Char]
"my file", [Char]
"")] [Char]
"#shellcheck source=\"my file\"\n. \"$1\""

prop_recursiveAnalysis :: Bool
prop_recursiveAnalysis =
    [Code
2086] [Code] -> [Code] -> Bool
forall a. Eq a => a -> a -> Bool
== [([Char], [Char])] -> [Char] -> [Code]
checkRecursive [([Char]
"lib", [Char]
"echo $1")] [Char]
"source lib"

prop_recursiveParsing :: Bool
prop_recursiveParsing =
    [Code
1037] [Code] -> [Code] -> Bool
forall a. Eq a => a -> a -> Bool
== [([Char], [Char])] -> [Char] -> [Code]
checkRecursive [([Char]
"lib", [Char]
"echo \"$10\"")] [Char]
"source lib"

prop_nonRecursiveAnalysis :: Bool
prop_nonRecursiveAnalysis =
    [Code] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([Code] -> Bool) -> [Code] -> Bool
forall a b. (a -> b) -> a -> b
$ [([Char], [Char])] -> [Char] -> [Code]
checkWithIncludes [([Char]
"lib", [Char]
"echo $1")] [Char]
"source lib"

prop_nonRecursiveParsing :: Bool
prop_nonRecursiveParsing =
    [Code] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([Code] -> Bool) -> [Code] -> Bool
forall a b. (a -> b) -> a -> b
$ [([Char], [Char])] -> [Char] -> [Code]
checkWithIncludes [([Char]
"lib", [Char]
"echo \"$10\"")] [Char]
"source lib"

prop_sourceDirectiveDoesntFollowFile :: Bool
prop_sourceDirectiveDoesntFollowFile =
    [Code] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([Code] -> Bool) -> [Code] -> Bool
forall a b. (a -> b) -> a -> b
$ [([Char], [Char])] -> [Char] -> [Code]
checkWithIncludes
                [([Char]
"foo", [Char]
"source bar"), ([Char]
"bar", [Char]
"baz=3")]
                [Char]
"#shellcheck source=foo\n. \"$1\"; echo \"$baz\""

prop_filewideAnnotationBase :: Bool
prop_filewideAnnotationBase = [Code
2086] [Code] -> [Code] -> Bool
forall a. Eq a => a -> a -> Bool
== [Char] -> [Code]
check [Char]
"#!/bin/sh\necho $1"
prop_filewideAnnotation1 :: Bool
prop_filewideAnnotation1 = [Code] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([Code] -> Bool) -> [Code] -> Bool
forall a b. (a -> b) -> a -> b
$
    [Char] -> [Code]
check [Char]
"#!/bin/sh\n# shellcheck disable=2086\necho $1"
prop_filewideAnnotation2 :: Bool
prop_filewideAnnotation2 = [Code] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([Code] -> Bool) -> [Code] -> Bool
forall a b. (a -> b) -> a -> b
$
    [Char] -> [Code]
check [Char]
"#!/bin/sh\n# shellcheck disable=2086\ntrue\necho $1"
prop_filewideAnnotation3 :: Bool
prop_filewideAnnotation3 = [Code] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([Code] -> Bool) -> [Code] -> Bool
forall a b. (a -> b) -> a -> b
$
    [Char] -> [Code]
check [Char]
"#!/bin/sh\n#unrelated\n# shellcheck disable=2086\ntrue\necho $1"
prop_filewideAnnotation4 :: Bool
prop_filewideAnnotation4 = [Code] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([Code] -> Bool) -> [Code] -> Bool
forall a b. (a -> b) -> a -> b
$
    [Char] -> [Code]
check [Char]
"#!/bin/sh\n# shellcheck disable=2086\n#unrelated\ntrue\necho $1"
prop_filewideAnnotation5 :: Bool
prop_filewideAnnotation5 = [Code] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([Code] -> Bool) -> [Code] -> Bool
forall a b. (a -> b) -> a -> b
$
    [Char] -> [Code]
check [Char]
"#!/bin/sh\n\n\n\n#shellcheck disable=2086\ntrue\necho $1"
prop_filewideAnnotation6 :: Bool
prop_filewideAnnotation6 = [Code] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([Code] -> Bool) -> [Code] -> Bool
forall a b. (a -> b) -> a -> b
$
    [Char] -> [Code]
check [Char]
"#shellcheck shell=sh\n#unrelated\n#shellcheck disable=2086\ntrue\necho $1"
prop_filewideAnnotation7 :: Bool
prop_filewideAnnotation7 = [Code] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([Code] -> Bool) -> [Code] -> Bool
forall a b. (a -> b) -> a -> b
$
    [Char] -> [Code]
check [Char]
"#!/bin/sh\n# shellcheck disable=2086\n#unrelated\ntrue\necho $1"

prop_filewideAnnotationBase2 :: Bool
prop_filewideAnnotationBase2 = [Code
2086, Code
2181] [Code] -> [Code] -> Bool
forall a. Eq a => a -> a -> Bool
== [Char] -> [Code]
check [Char]
"true\n[ $? == 0 ] && echo $1"
prop_filewideAnnotation8 :: Bool
prop_filewideAnnotation8 = [Code] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([Code] -> Bool) -> [Code] -> Bool
forall a b. (a -> b) -> a -> b
$
    [Char] -> [Code]
check [Char]
"# Disable $? warning\n#shellcheck disable=SC2181\n# Disable quoting warning\n#shellcheck disable=2086\ntrue\n[ $? == 0 ] && echo $1"

prop_sourcePartOfOriginalScript :: Bool
prop_sourcePartOfOriginalScript = -- #1181: -x disabled posix warning for 'source'
    Code
3046 Code -> [Code] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [([Char], [Char])] -> [Char] -> [Code]
checkWithIncludes [([Char]
"./saywhat.sh", [Char]
"echo foo")] [Char]
"#!/bin/sh\nsource ./saywhat.sh"

prop_spinBug1413 :: Bool
prop_spinBug1413 = [Code] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([Code] -> Bool) -> [Code] -> Bool
forall a b. (a -> b) -> a -> b
$ [Char] -> [Code]
check [Char]
"fun() {\n# shellcheck disable=SC2188\n> /dev/null\n}\n"

prop_deducesTypeFromExtension :: Bool
prop_deducesTypeFromExtension = [Code] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Code]
result
  where
    result :: [Code]
result = [([Char], [Char])] -> CheckSpec -> [Code]
checkWithSpec [] CheckSpec
emptyCheckSpec {
        csFilename = "file.ksh",
        csScript = "(( 3.14 ))"
    }

prop_deducesTypeFromExtension2 :: Bool
prop_deducesTypeFromExtension2 = [Code]
result [Code] -> [Code] -> Bool
forall a. Eq a => a -> a -> Bool
== [Code
2079]
  where
    result :: [Code]
result = [([Char], [Char])] -> CheckSpec -> [Code]
checkWithSpec [] CheckSpec
emptyCheckSpec {
        csFilename = "file.bash",
        csScript = "(( 3.14 ))"
    }

prop_canDisableShebangWarning :: Bool
prop_canDisableShebangWarning = [Code] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([Code] -> Bool) -> [Code] -> Bool
forall a b. (a -> b) -> a -> b
$ [Code]
result
  where
    result :: [Code]
result = [([Char], [Char])] -> CheckSpec -> [Code]
checkWithSpec [] CheckSpec
emptyCheckSpec {
        csFilename = "file.sh",
        csScript = "#shellcheck disable=SC2148\nfoo"
    }

prop_canDisableAllWarnings :: Bool
prop_canDisableAllWarnings = [Code]
result [Code] -> [Code] -> Bool
forall a. Eq a => a -> a -> Bool
== [Code
2086]
  where
    result :: [Code]
result = [([Char], [Char])] -> CheckSpec -> [Code]
checkWithSpec [] CheckSpec
emptyCheckSpec {
        csFilename = "file.sh",
        csScript = "#!/bin/sh\necho $1\n#shellcheck disable=all\necho `echo $1`"
    }

prop_canDisableParseErrors :: Bool
prop_canDisableParseErrors = [Code] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([Code] -> Bool) -> [Code] -> Bool
forall a b. (a -> b) -> a -> b
$ [Code]
result
  where
    result :: [Code]
result = [([Char], [Char])] -> CheckSpec -> [Code]
checkWithSpec [] CheckSpec
emptyCheckSpec {
        csFilename = "file.sh",
        csScript = "#shellcheck disable=SC1073,SC1072,SC2148\n()"
    }

prop_shExtensionDoesntMatter :: Bool
prop_shExtensionDoesntMatter = [Code]
result [Code] -> [Code] -> Bool
forall a. Eq a => a -> a -> Bool
== [Code
2148]
  where
    result :: [Code]
result = [([Char], [Char])] -> CheckSpec -> [Code]
checkWithSpec [] CheckSpec
emptyCheckSpec {
        csFilename = "file.sh",
        csScript = "echo 'hello world'"
    }

prop_sourcedFileUsesOriginalShellExtension :: Bool
prop_sourcedFileUsesOriginalShellExtension = [Code]
result [Code] -> [Code] -> Bool
forall a. Eq a => a -> a -> Bool
== [Code
2079]
  where
    result :: [Code]
result = [([Char], [Char])] -> CheckSpec -> [Code]
checkWithSpec [([Char]
"file.ksh", [Char]
"(( 3.14 ))")] CheckSpec
emptyCheckSpec {
        csFilename = "file.bash",
        csScript = "source file.ksh",
        csCheckSourced = True
    }

prop_canEnableOptionalsWithSpec :: Bool
prop_canEnableOptionalsWithSpec = [Code]
result [Code] -> [Code] -> Bool
forall a. Eq a => a -> a -> Bool
== [Code
2244]
  where
    result :: [Code]
result = [([Char], [Char])] -> CheckSpec -> [Code]
checkWithSpec [] CheckSpec
emptyCheckSpec {
        csFilename = "file.sh",
        csScript = "#!/bin/sh\n[ \"$1\" ]",
        csOptionalChecks = ["avoid-nullary-conditions"]
    }

prop_optionIncludes1 :: Bool
prop_optionIncludes1 =
    -- expect 2086, but not included, so nothing reported
    [Code] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([Code] -> Bool) -> [Code] -> Bool
forall a b. (a -> b) -> a -> b
$ Maybe [Code] -> [Char] -> [Code]
checkOptionIncludes ([Code] -> Maybe [Code]
forall a. a -> Maybe a
Just [Code
2080]) [Char]
"#!/bin/sh\n var='a b'\n echo $var"

prop_optionIncludes2 :: Bool
prop_optionIncludes2 =
    -- expect 2086, included, so it is reported
    [Code
2086] [Code] -> [Code] -> Bool
forall a. Eq a => a -> a -> Bool
== Maybe [Code] -> [Char] -> [Code]
checkOptionIncludes ([Code] -> Maybe [Code]
forall a. a -> Maybe a
Just [Code
2086]) [Char]
"#!/bin/sh\n var='a b'\n echo $var"

prop_optionIncludes3 :: Bool
prop_optionIncludes3 =
    -- expect 2086, no inclusions provided, so it is reported
    [Code
2086] [Code] -> [Code] -> Bool
forall a. Eq a => a -> a -> Bool
== Maybe [Code] -> [Char] -> [Code]
checkOptionIncludes Maybe [Code]
forall a. Maybe a
Nothing [Char]
"#!/bin/sh\n var='a b'\n echo $var"

prop_optionIncludes4 :: Bool
prop_optionIncludes4 =
    -- expect 2086 & 2154, only 2154 included, so only that's reported
    [Code
2154] [Code] -> [Code] -> Bool
forall a. Eq a => a -> a -> Bool
== Maybe [Code] -> [Char] -> [Code]
checkOptionIncludes ([Code] -> Maybe [Code]
forall a. a -> Maybe a
Just [Code
2154]) [Char]
"#!/bin/sh\n var='a b'\n echo $var\n echo $bar"


prop_readsRcFile :: Bool
prop_readsRcFile = [Code] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Code]
result
  where
    result :: [Code]
result = [Char] -> CheckSpec -> [Code]
checkWithRc [Char]
"disable=2086" CheckSpec
emptyCheckSpec {
        csScript = "#!/bin/sh\necho $1",
        csIgnoreRC = False
    }

prop_canUseNoRC :: Bool
prop_canUseNoRC = [Code]
result [Code] -> [Code] -> Bool
forall a. Eq a => a -> a -> Bool
== [Code
2086]
  where
    result :: [Code]
result = [Char] -> CheckSpec -> [Code]
checkWithRc [Char]
"disable=2086" CheckSpec
emptyCheckSpec {
        csScript = "#!/bin/sh\necho $1",
        csIgnoreRC = True
    }

prop_NoRCWontLookAtFile :: Bool
prop_NoRCWontLookAtFile = [Code]
result [Code] -> [Code] -> Bool
forall a. Eq a => a -> a -> Bool
== [Code
2086]
  where
    result :: [Code]
result = [Char] -> CheckSpec -> [Code]
checkWithRc ([Char] -> [Char]
forall a. HasCallStack => [Char] -> a
error [Char]
"Fail") CheckSpec
emptyCheckSpec {
        csScript = "#!/bin/sh\necho $1",
        csIgnoreRC = True
    }

prop_brokenRcGetsWarning :: Bool
prop_brokenRcGetsWarning = [Code]
result [Code] -> [Code] -> Bool
forall a. Eq a => a -> a -> Bool
== [Code
1134, Code
2086]
  where
    result :: [Code]
result = [Char] -> CheckSpec -> [Code]
checkWithRc [Char]
"rofl" CheckSpec
emptyCheckSpec {
        csScript = "#!/bin/sh\necho $1",
        csIgnoreRC = False
    }

prop_canEnableOptionalsWithRc :: Bool
prop_canEnableOptionalsWithRc = [Code]
result [Code] -> [Code] -> Bool
forall a. Eq a => a -> a -> Bool
== [Code
2244]
  where
    result :: [Code]
result = [Char] -> CheckSpec -> [Code]
checkWithRc [Char]
"enable=avoid-nullary-conditions" CheckSpec
emptyCheckSpec {
        csScript = "#!/bin/sh\n[ \"$1\" ]"
    }

prop_sourcePathRedirectsName :: Bool
prop_sourcePathRedirectsName = [Code]
result [Code] -> [Code] -> Bool
forall a. Eq a => a -> a -> Bool
== [Code
2086]
  where
    f :: [Char] -> p -> p -> [Char] -> m [Char]
f [Char]
"dir/myscript" p
_ p
_ [Char]
"lib" = [Char] -> m [Char]
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return [Char]
"foo/lib"
    result :: [Code]
result = [([Char], [Char])]
-> ([Char] -> Maybe Bool -> [[Char]] -> [Char] -> Identity [Char])
-> CheckSpec
-> [Code]
checkWithIncludesAndSourcePath [([Char]
"foo/lib", [Char]
"echo $1")] [Char] -> Maybe Bool -> [[Char]] -> [Char] -> Identity [Char]
forall {m :: * -> *} {p} {p}.
Monad m =>
[Char] -> p -> p -> [Char] -> m [Char]
f CheckSpec
emptyCheckSpec {
        csScript = "#!/bin/bash\nsource lib",
        csFilename = "dir/myscript",
        csCheckSourced = True
    }

prop_sourcePathAddsAnnotation :: Bool
prop_sourcePathAddsAnnotation = [Code]
result [Code] -> [Code] -> Bool
forall a. Eq a => a -> a -> Bool
== [Code
2086]
  where
    f :: [Char] -> p -> [[Char]] -> [Char] -> m [Char]
f [Char]
"dir/myscript" p
_ [[Char]
"mypath"] [Char]
"lib" = [Char] -> m [Char]
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return [Char]
"foo/lib"
    result :: [Code]
result = [([Char], [Char])]
-> ([Char] -> Maybe Bool -> [[Char]] -> [Char] -> Identity [Char])
-> CheckSpec
-> [Code]
checkWithIncludesAndSourcePath [([Char]
"foo/lib", [Char]
"echo $1")] [Char] -> Maybe Bool -> [[Char]] -> [Char] -> Identity [Char]
forall {m :: * -> *} {p}.
Monad m =>
[Char] -> p -> [[Char]] -> [Char] -> m [Char]
f CheckSpec
emptyCheckSpec {
        csScript = "#!/bin/bash\n# shellcheck source-path=mypath\nsource lib",
        csFilename = "dir/myscript",
        csCheckSourced = True
    }

prop_sourcePathWorksWithSpaces :: Bool
prop_sourcePathWorksWithSpaces = [Code]
result [Code] -> [Code] -> Bool
forall a. Eq a => a -> a -> Bool
== [Code
2086]
  where
    f :: [Char] -> p -> [[Char]] -> [Char] -> m [Char]
f [Char]
"dir/myscript" p
_ [[Char]
"my path"] [Char]
"lib" = [Char] -> m [Char]
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return [Char]
"foo/lib"
    result :: [Code]
result = [([Char], [Char])]
-> ([Char] -> Maybe Bool -> [[Char]] -> [Char] -> Identity [Char])
-> CheckSpec
-> [Code]
checkWithIncludesAndSourcePath [([Char]
"foo/lib", [Char]
"echo $1")] [Char] -> Maybe Bool -> [[Char]] -> [Char] -> Identity [Char]
forall {m :: * -> *} {p}.
Monad m =>
[Char] -> p -> [[Char]] -> [Char] -> m [Char]
f CheckSpec
emptyCheckSpec {
        csScript = "#!/bin/bash\n# shellcheck source-path='my path'\nsource lib",
        csFilename = "dir/myscript",
        csCheckSourced = True
    }

prop_sourcePathRedirectsDirective :: Bool
prop_sourcePathRedirectsDirective = [Code]
result [Code] -> [Code] -> Bool
forall a. Eq a => a -> a -> Bool
== [Code
2086]
  where
    f :: [Char] -> p -> p -> [Char] -> m [Char]
f [Char]
"dir/myscript" p
_ p
_ [Char]
"lib" = [Char] -> m [Char]
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return [Char]
"foo/lib"
    f [Char]
_ p
_ p
_ [Char]
_ = [Char] -> m [Char]
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return [Char]
"/dev/null"
    result :: [Code]
result = [([Char], [Char])]
-> ([Char] -> Maybe Bool -> [[Char]] -> [Char] -> Identity [Char])
-> CheckSpec
-> [Code]
checkWithIncludesAndSourcePath [([Char]
"foo/lib", [Char]
"echo $1")] [Char] -> Maybe Bool -> [[Char]] -> [Char] -> Identity [Char]
forall {m :: * -> *} {p} {p}.
Monad m =>
[Char] -> p -> p -> [Char] -> m [Char]
f CheckSpec
emptyCheckSpec {
        csScript = "#!/bin/bash\n# shellcheck source=lib\nsource kittens",
        csFilename = "dir/myscript",
        csCheckSourced = True
    }

prop_rcCanAllowExternalSources :: Bool
prop_rcCanAllowExternalSources = [Code]
result [Code] -> [Code] -> Bool
forall a. Eq a => a -> a -> Bool
== [Code
2086]
  where
    f :: [Char] -> Maybe Bool -> d -> [Char] -> m [Char]
f [Char]
"dir/myscript" (Just Bool
True) d
_ [Char]
"mylib" = [Char] -> m [Char]
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return [Char]
"resolved/mylib"
    f [Char]
a Maybe Bool
b d
c [Char]
d = [Char] -> m [Char]
forall a. HasCallStack => [Char] -> a
error ([Char] -> m [Char]) -> [Char] -> m [Char]
forall a b. (a -> b) -> a -> b
$ ([Char], [Char], Maybe Bool, d, [Char]) -> [Char]
forall a. Show a => a -> [Char]
show ([Char]
"Unexpected", [Char]
a, Maybe Bool
b, d
c, [Char]
d)
    result :: [Code]
result = [Char]
-> [([Char], [Char])]
-> ([Char] -> Maybe Bool -> [[Char]] -> [Char] -> Identity [Char])
-> CheckSpec
-> [Code]
checkWithRcIncludesAndSourcePath [Char]
"external-sources=true" [([Char]
"resolved/mylib", [Char]
"echo $1")] [Char] -> Maybe Bool -> [[Char]] -> [Char] -> Identity [Char]
forall {m :: * -> *} {d}.
(Monad m, Show d) =>
[Char] -> Maybe Bool -> d -> [Char] -> m [Char]
f CheckSpec
emptyCheckSpec {
        csScript = "#!/bin/bash\nsource mylib",
        csFilename = "dir/myscript",
        csCheckSourced = True
    }

prop_rcCanDenyExternalSources :: Bool
prop_rcCanDenyExternalSources = [Code]
result [Code] -> [Code] -> Bool
forall a. Eq a => a -> a -> Bool
== [Code
2086]
  where
    f :: [Char] -> Maybe Bool -> d -> [Char] -> m [Char]
f [Char]
"dir/myscript" (Just Bool
False) d
_ [Char]
"mylib" = [Char] -> m [Char]
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return [Char]
"resolved/mylib"
    f [Char]
a Maybe Bool
b d
c [Char]
d = [Char] -> m [Char]
forall a. HasCallStack => [Char] -> a
error ([Char] -> m [Char]) -> [Char] -> m [Char]
forall a b. (a -> b) -> a -> b
$ ([Char], [Char], Maybe Bool, d, [Char]) -> [Char]
forall a. Show a => a -> [Char]
show ([Char]
"Unexpected", [Char]
a, Maybe Bool
b, d
c, [Char]
d)
    result :: [Code]
result = [Char]
-> [([Char], [Char])]
-> ([Char] -> Maybe Bool -> [[Char]] -> [Char] -> Identity [Char])
-> CheckSpec
-> [Code]
checkWithRcIncludesAndSourcePath [Char]
"external-sources=false" [([Char]
"resolved/mylib", [Char]
"echo $1")] [Char] -> Maybe Bool -> [[Char]] -> [Char] -> Identity [Char]
forall {m :: * -> *} {d}.
(Monad m, Show d) =>
[Char] -> Maybe Bool -> d -> [Char] -> m [Char]
f CheckSpec
emptyCheckSpec {
        csScript = "#!/bin/bash\nsource mylib",
        csFilename = "dir/myscript",
        csCheckSourced = True
    }

prop_rcCanLeaveExternalSourcesUnspecified :: Bool
prop_rcCanLeaveExternalSourcesUnspecified = [Code]
result [Code] -> [Code] -> Bool
forall a. Eq a => a -> a -> Bool
== [Code
2086]
  where
    f :: [Char] -> Maybe a -> d -> [Char] -> m [Char]
f [Char]
"dir/myscript" Maybe a
Nothing d
_ [Char]
"mylib" = [Char] -> m [Char]
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return [Char]
"resolved/mylib"
    f [Char]
a Maybe a
b d
c [Char]
d = [Char] -> m [Char]
forall a. HasCallStack => [Char] -> a
error ([Char] -> m [Char]) -> [Char] -> m [Char]
forall a b. (a -> b) -> a -> b
$ ([Char], [Char], Maybe a, d, [Char]) -> [Char]
forall a. Show a => a -> [Char]
show ([Char]
"Unexpected", [Char]
a, Maybe a
b, d
c, [Char]
d)
    result :: [Code]
result = [Char]
-> [([Char], [Char])]
-> ([Char] -> Maybe Bool -> [[Char]] -> [Char] -> Identity [Char])
-> CheckSpec
-> [Code]
checkWithRcIncludesAndSourcePath [Char]
"" [([Char]
"resolved/mylib", [Char]
"echo $1")] [Char] -> Maybe Bool -> [[Char]] -> [Char] -> Identity [Char]
forall {m :: * -> *} {a} {d}.
(Monad m, Show a, Show d) =>
[Char] -> Maybe a -> d -> [Char] -> m [Char]
f CheckSpec
emptyCheckSpec {
        csScript = "#!/bin/bash\nsource mylib",
        csFilename = "dir/myscript",
        csCheckSourced = True
    }

prop_fileCanDisableExternalSources :: Bool
prop_fileCanDisableExternalSources = [Code]
result [Code] -> [Code] -> Bool
forall a. Eq a => a -> a -> Bool
== [Code
2006, Code
2086]
  where
    f :: [Char] -> Maybe Bool -> d -> [Char] -> m [Char]
f [Char]
"dir/myscript" (Just Bool
True) d
_ [Char]
"withExternal" = [Char] -> m [Char]
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return [Char]
"withExternal"
    f [Char]
"dir/myscript" (Just Bool
False) d
_ [Char]
"withoutExternal" = [Char] -> m [Char]
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return [Char]
"withoutExternal"
    f [Char]
a Maybe Bool
b d
c [Char]
d = [Char] -> m [Char]
forall a. HasCallStack => [Char] -> a
error ([Char] -> m [Char]) -> [Char] -> m [Char]
forall a b. (a -> b) -> a -> b
$ ([Char], [Char], Maybe Bool, d, [Char]) -> [Char]
forall a. Show a => a -> [Char]
show ([Char]
"Unexpected", [Char]
a, Maybe Bool
b, d
c, [Char]
d)
    result :: [Code]
result = [Char]
-> [([Char], [Char])]
-> ([Char] -> Maybe Bool -> [[Char]] -> [Char] -> Identity [Char])
-> CheckSpec
-> [Code]
checkWithRcIncludesAndSourcePath [Char]
"external-sources=true" [([Char]
"withExternal", [Char]
"echo $1"), ([Char]
"withoutExternal", [Char]
"_=`foo`")] [Char] -> Maybe Bool -> [[Char]] -> [Char] -> Identity [Char]
forall {m :: * -> *} {d}.
(Monad m, Show d) =>
[Char] -> Maybe Bool -> d -> [Char] -> m [Char]
f CheckSpec
emptyCheckSpec {
        csScript = "#!/bin/bash\ntrue\nsource withExternal\n# shellcheck external-sources=false\nsource withoutExternal",
        csFilename = "dir/myscript",
        csCheckSourced = True
    }

prop_fileCannotEnableExternalSources :: Bool
prop_fileCannotEnableExternalSources = [Code]
result [Code] -> [Code] -> Bool
forall a. Eq a => a -> a -> Bool
== [Code
1144]
  where
    f :: [Char] -> Maybe a -> d -> [Char] -> m [Char]
f [Char]
"dir/myscript" Maybe a
Nothing d
_ [Char]
"foo" = [Char] -> m [Char]
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return [Char]
"foo"
    f [Char]
a Maybe a
b d
c [Char]
d = [Char] -> m [Char]
forall a. HasCallStack => [Char] -> a
error ([Char] -> m [Char]) -> [Char] -> m [Char]
forall a b. (a -> b) -> a -> b
$ ([Char], [Char], Maybe a, d, [Char]) -> [Char]
forall a. Show a => a -> [Char]
show ([Char]
"Unexpected", [Char]
a, Maybe a
b, d
c, [Char]
d)
    result :: [Code]
result = [Char]
-> [([Char], [Char])]
-> ([Char] -> Maybe Bool -> [[Char]] -> [Char] -> Identity [Char])
-> CheckSpec
-> [Code]
checkWithRcIncludesAndSourcePath [Char]
"" [([Char]
"foo", [Char]
"true")] [Char] -> Maybe Bool -> [[Char]] -> [Char] -> Identity [Char]
forall {m :: * -> *} {a} {d}.
(Monad m, Show a, Show d) =>
[Char] -> Maybe a -> d -> [Char] -> m [Char]
f CheckSpec
emptyCheckSpec {
        csScript = "#!/bin/bash\n# shellcheck external-sources=true\nsource foo",
        csFilename = "dir/myscript",
        csCheckSourced = True
    }

prop_fileCannotEnableExternalSources2 :: Bool
prop_fileCannotEnableExternalSources2 = [Code]
result [Code] -> [Code] -> Bool
forall a. Eq a => a -> a -> Bool
== [Code
1144]
  where
    f :: [Char] -> Maybe Bool -> d -> [Char] -> m [Char]
f [Char]
"dir/myscript" (Just Bool
False) d
_ [Char]
"foo" = [Char] -> m [Char]
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return [Char]
"foo"
    f [Char]
a Maybe Bool
b d
c [Char]
d = [Char] -> m [Char]
forall a. HasCallStack => [Char] -> a
error ([Char] -> m [Char]) -> [Char] -> m [Char]
forall a b. (a -> b) -> a -> b
$ ([Char], [Char], Maybe Bool, d, [Char]) -> [Char]
forall a. Show a => a -> [Char]
show ([Char]
"Unexpected", [Char]
a, Maybe Bool
b, d
c, [Char]
d)
    result :: [Code]
result = [Char]
-> [([Char], [Char])]
-> ([Char] -> Maybe Bool -> [[Char]] -> [Char] -> Identity [Char])
-> CheckSpec
-> [Code]
checkWithRcIncludesAndSourcePath [Char]
"external-sources=false" [([Char]
"foo", [Char]
"true")] [Char] -> Maybe Bool -> [[Char]] -> [Char] -> Identity [Char]
forall {m :: * -> *} {d}.
(Monad m, Show d) =>
[Char] -> Maybe Bool -> d -> [Char] -> m [Char]
f CheckSpec
emptyCheckSpec {
        csScript = "#!/bin/bash\n# shellcheck external-sources=true\nsource foo",
        csFilename = "dir/myscript",
        csCheckSourced = True
    }

prop_rcCanSuppressEarlyProblems1 :: Bool
prop_rcCanSuppressEarlyProblems1 = [Code] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Code]
result
  where
    result :: [Code]
result = [Char] -> CheckSpec -> [Code]
checkWithRc [Char]
"disable=1071" CheckSpec
emptyCheckSpec {
        csScript = "#!/bin/zsh\necho $1"
    }

prop_rcCanSuppressEarlyProblems2 :: Bool
prop_rcCanSuppressEarlyProblems2 = [Code] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Code]
result
  where
    result :: [Code]
result = [Char] -> CheckSpec -> [Code]
checkWithRc [Char]
"disable=1104" CheckSpec
emptyCheckSpec {
        csScript = "!/bin/bash\necho 'hello world'"
    }

prop_sourceWithHereDocWorks :: Bool
prop_sourceWithHereDocWorks = [Code] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Code]
result
  where
    result :: [Code]
result = [([Char], [Char])] -> [Char] -> [Code]
checkWithIncludes [([Char]
"bar", [Char]
"true\n")] [Char]
"source bar << eof\nlol\neof"

prop_hereDocsAreParsedWithoutTrailingLinefeed :: Bool
prop_hereDocsAreParsedWithoutTrailingLinefeed = Code
1044 Code -> [Code] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Code]
result
  where
    result :: [Code]
result = [Char] -> [Code]
check [Char]
"cat << eof"

prop_hereDocsWillHaveParsedIndices :: Bool
prop_hereDocsWillHaveParsedIndices = [Code] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Code]
result
  where
    result :: [Code]
result = [Char] -> [Code]
check [Char]
"#!/bin/bash\nmy_array=(a b)\ncat <<EOF >> ./test\n $(( 1 + my_array[1] ))\nEOF"

prop_rcCanSuppressDfa :: Bool
prop_rcCanSuppressDfa = [Code] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Code]
result
  where
    result :: [Code]
result = [Char] -> CheckSpec -> [Code]
checkWithRc [Char]
"extended-analysis=false" CheckSpec
emptyCheckSpec {
        csScript = "#!/bin/sh\nexit; foo;"
    }

prop_fileCanSuppressDfa :: Bool
prop_fileCanSuppressDfa = [Code] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([Code] -> Bool) -> [Code] -> Bool
forall a b. (a -> b) -> a -> b
$ [Code] -> [Code]
forall a. Show a => a -> a
traceShowId [Code]
result
  where
    result :: [Code]
result = [Char] -> CheckSpec -> [Code]
checkWithRc [Char]
"" CheckSpec
emptyCheckSpec {
        csScript = "#!/bin/sh\n# shellcheck extended-analysis=false\nexit; foo;"
    }

prop_fileWinsWhenSuppressingDfa1 :: Bool
prop_fileWinsWhenSuppressingDfa1 = [Code] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Code]
result
  where
    result :: [Code]
result = [Char] -> CheckSpec -> [Code]
checkWithRc [Char]
"extended-analysis=true" CheckSpec
emptyCheckSpec {
        csScript = "#!/bin/sh\n# shellcheck extended-analysis=false\nexit; foo;"
    }

prop_fileWinsWhenSuppressingDfa2 :: Bool
prop_fileWinsWhenSuppressingDfa2 = [Code]
result [Code] -> [Code] -> Bool
forall a. Eq a => a -> a -> Bool
== [Code
2317]
  where
    result :: [Code]
result = [Char] -> CheckSpec -> [Code]
checkWithRc [Char]
"extended-analysis=false" CheckSpec
emptyCheckSpec {
        csScript = "#!/bin/sh\n# shellcheck extended-analysis=true\nexit; foo;"
    }

prop_flagWinsWhenSuppressingDfa1 :: Bool
prop_flagWinsWhenSuppressingDfa1 = [Code]
result [Code] -> [Code] -> Bool
forall a. Eq a => a -> a -> Bool
== [Code
2317]
  where
    result :: [Code]
result = [Char] -> CheckSpec -> [Code]
checkWithRc [Char]
"extended-analysis=false" CheckSpec
emptyCheckSpec {
        csScript = "#!/bin/sh\n# shellcheck extended-analysis=false\nexit; foo;",
        csExtendedAnalysis = Just True
    }

prop_flagWinsWhenSuppressingDfa2 :: Bool
prop_flagWinsWhenSuppressingDfa2 = [Code] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Code]
result
  where
    result :: [Code]
result = [Char] -> CheckSpec -> [Code]
checkWithRc [Char]
"extended-analysis=true" CheckSpec
emptyCheckSpec {
        csScript = "#!/bin/sh\n# shellcheck extended-analysis=true\nexit; foo;",
        csExtendedAnalysis = Just False
    }

return []
runTests :: IO Bool
runTests = $Bool
[Char]
[([Char], Property)]
Bool -> Property
[([Char], Property)] -> (Property -> IO Result) -> IO Bool
Property -> IO Result
forall prop. Testable prop => prop -> IO Result
forall prop. Testable prop => prop -> Property
prop_findsParseIssue :: Bool
prop_commentDisablesParseIssue1 :: Bool
prop_commentDisablesParseIssue2 :: Bool
prop_findsAnalysisIssue :: Bool
prop_commentDisablesAnalysisIssue1 :: Bool
prop_commentDisablesAnalysisIssue2 :: Bool
prop_optionDisablesIssue1 :: Bool
prop_optionDisablesIssue2 :: Bool
prop_wontParseBadShell :: Bool
prop_optionDisablesBadShebang :: Bool
prop_annotationDisablesBadShebang :: Bool
prop_canParseDevNull :: Bool
prop_failsWhenNotSourcing :: Bool
prop_worksWhenSourcing :: Bool
prop_worksWhenSourcingWithDashDash :: Bool
prop_worksWhenDotting :: Bool
prop_noInfiniteSourcing :: Bool
prop_canSourceBadSyntax :: Bool
prop_cantSourceDynamic :: Bool
prop_cantSourceDynamic2 :: Bool
prop_canStripPrefixAndSource :: Bool
prop_canStripPrefixAndSource2 :: Bool
prop_canSourceDynamicWhenRedirected :: Bool
prop_canRedirectWithSpaces :: Bool
prop_recursiveAnalysis :: Bool
prop_recursiveParsing :: Bool
prop_nonRecursiveAnalysis :: Bool
prop_nonRecursiveParsing :: Bool
prop_sourceDirectiveDoesntFollowFile :: Bool
prop_filewideAnnotationBase :: Bool
prop_filewideAnnotation1 :: Bool
prop_filewideAnnotation2 :: Bool
prop_filewideAnnotation3 :: Bool
prop_filewideAnnotation4 :: Bool
prop_filewideAnnotation5 :: Bool
prop_filewideAnnotation6 :: Bool
prop_filewideAnnotation7 :: Bool
prop_filewideAnnotationBase2 :: Bool
prop_filewideAnnotation8 :: Bool
prop_sourcePartOfOriginalScript :: Bool
prop_spinBug1413 :: Bool
prop_deducesTypeFromExtension :: Bool
prop_deducesTypeFromExtension2 :: Bool
prop_canDisableShebangWarning :: Bool
prop_canDisableAllWarnings :: Bool
prop_canDisableParseErrors :: Bool
prop_shExtensionDoesntMatter :: Bool
prop_sourcedFileUsesOriginalShellExtension :: Bool
prop_canEnableOptionalsWithSpec :: Bool
prop_optionIncludes1 :: Bool
prop_optionIncludes2 :: Bool
prop_optionIncludes3 :: Bool
prop_optionIncludes4 :: Bool
prop_readsRcFile :: Bool
prop_canUseNoRC :: Bool
prop_NoRCWontLookAtFile :: Bool
prop_brokenRcGetsWarning :: Bool
prop_canEnableOptionalsWithRc :: Bool
prop_sourcePathRedirectsName :: Bool
prop_sourcePathAddsAnnotation :: Bool
prop_sourcePathWorksWithSpaces :: Bool
prop_sourcePathRedirectsDirective :: Bool
prop_rcCanAllowExternalSources :: Bool
prop_rcCanDenyExternalSources :: Bool
prop_rcCanLeaveExternalSourcesUnspecified :: Bool
prop_fileCanDisableExternalSources :: Bool
prop_fileCannotEnableExternalSources :: Bool
prop_fileCannotEnableExternalSources2 :: Bool
prop_rcCanSuppressEarlyProblems1 :: Bool
prop_rcCanSuppressEarlyProblems2 :: Bool
prop_sourceWithHereDocWorks :: Bool
prop_hereDocsAreParsedWithoutTrailingLinefeed :: Bool
prop_hereDocsWillHaveParsedIndices :: Bool
prop_rcCanSuppressDfa :: Bool
prop_fileCanSuppressDfa :: Bool
prop_fileWinsWhenSuppressingDfa1 :: Bool
prop_fileWinsWhenSuppressingDfa2 :: Bool
prop_flagWinsWhenSuppressingDfa1 :: Bool
prop_flagWinsWhenSuppressingDfa2 :: Bool
property :: forall prop. Testable prop => prop -> Property
quickCheckResult :: forall prop. Testable prop => prop -> IO Result
runQuickCheckAll :: [([Char], Property)] -> (Property -> IO Result) -> IO Bool
quickCheckAll