iris-0.1.0.0: test/Test/Iris/Cli.hs
module Test.Iris.Cli (cliSpec, cliSpecParserConflicts) where
import Options.Applicative (getParseResult)
import Test.Hspec (Expectation, Spec, describe, expectationFailure, it, shouldBe, shouldReturn)
import Iris (CliEnvSettings (..))
import Iris.Cli (VersionSettings (versionSettingsMkDesc))
import Iris.Cli.Colour (ColourOption (..))
import Iris.Cli.Interactive (InteractiveMode (..), handleInteractiveMode)
import Iris.Cli.Internal
import Iris.Cli.ParserInfo (cmdParserInfo)
import Iris.Cli.Version (defaultVersionSettings)
import Iris.Settings (defaultCliEnvSettings)
import Test.Iris.Common (checkCI)
import qualified Options.Applicative as Opt
import qualified Paths_iris as Autogen
expectedHelpText :: String
expectedHelpText =
"Simple CLI program\n\
\\n\
\Usage: <iris-test> [--no-input] [--colour | --no-colour]\n\
\\n\
\ CLI tool build with iris - a Haskell CLI framework\n\
\\n\
\Available options:\n\
\ -h,--help Show this help text\n\
\ --no-input Enter the terminal in non-interactive mode\n\
\ --colour Always output colours\n\
\ --no-colour Never output colours"
expectedHelpTextWithVersion :: String
expectedHelpTextWithVersion =
"Simple CLI program\n\
\\n\
\Usage: <iris-test> [--version] [--numeric-version] [--no-input] \n\
\ [--colour | --no-colour]\n\
\\n\
\ CLI tool build with iris - a Haskell CLI framework\n\
\\n\
\Available options:\n\
\ -h,--help Show this help text\n\
\ --version Show application version\n\
\ --numeric-version Show only numeric application version\n\
\ --no-input Enter the terminal in non-interactive mode\n\
\ --colour Always output colours\n\
\ --no-colour Never output colours"
expectedNumericVersion :: String
expectedNumericVersion = "0.1.0.0"
cliSpec :: Spec
cliSpec = describe "Cli Options" $ do
let parserPrefs = Opt.defaultPrefs
it "help without version environment" $ do
let parserInfo = cmdParserInfo defaultCliEnvSettings
let result = Opt.execParserPure parserPrefs parserInfo ["--help"]
parseResultHandlerFailure result expectedHelpText
it "help with version environment" $ do
let cliEnvSettings = defaultCliEnvSettings{cliEnvSettingsVersionSettings = Just (defaultVersionSettings Autogen.version)}
let parserInfo = cmdParserInfo cliEnvSettings
let result = Opt.execParserPure parserPrefs parserInfo ["--help"]
parseResultHandlerFailure result expectedHelpTextWithVersion
it "--numeric-version returns correct version" $ do
let cliEnvSettings = defaultCliEnvSettings{cliEnvSettingsVersionSettings = Just (defaultVersionSettings Autogen.version)}
let parserInfo = cmdParserInfo cliEnvSettings
let result = Opt.execParserPure parserPrefs parserInfo ["--numeric-version"]
parseResultHandlerFailure result expectedNumericVersion
it "CI interactivity check" $ do
handleInteractiveMode NonInteractive `shouldReturn` NonInteractive
isCi <- checkCI
if isCi
then handleInteractiveMode Interactive `shouldReturn` NonInteractive
else handleInteractiveMode Interactive `shouldReturn` Interactive
it "Handles colour mode" $ do
let parserInfo = cmdParserInfo defaultCliEnvSettings
let coloption args = getParseResult $ cmdColourOption <$> Opt.execParserPure parserPrefs parserInfo args
coloption ["--colour"] `shouldBe` pure Always
coloption ["--no-colour"] `shouldBe` pure Never
coloption [] `shouldBe` pure Auto
it "--version returns correct version text" $ do
let expectedVersionMkDescription = ("Version " ++)
let cliEnvSettings = defaultCliEnvSettings{cliEnvSettingsVersionSettings = Just $ (defaultVersionSettings Autogen.version){versionSettingsMkDesc = expectedVersionMkDescription}}
let parserInfo = cmdParserInfo cliEnvSettings
let expectedVersion = expectedVersionMkDescription expectedNumericVersion
let result = Opt.execParserPure parserPrefs parserInfo ["--version"]
parseResultHandlerFailure result expectedVersion
newtype UserDefinedParser a = UserDefinedParser {noInteractive :: a}
userDefinedNoInputOption :: Opt.Parser (UserDefinedParser String)
userDefinedNoInputOption =
UserDefinedParser
<$> Opt.strOption (Opt.long "no-input")
userDefinedNoInputSwitch :: Opt.Parser (UserDefinedParser Bool)
userDefinedNoInputSwitch =
UserDefinedParser
<$> Opt.switch (Opt.long "no-input")
userDefinedNoInputOnCommand :: Opt.Parser (UserDefinedParser Bool)
userDefinedNoInputOnCommand =
Opt.subparser
( Opt.command
"test-command"
(Opt.info userDefinedNoInputSwitch Opt.fullDesc)
)
customParserSettings :: Opt.Parser (UserDefinedParser a) -> CliEnvSettings (UserDefinedParser a) ()
customParserSettings parser =
CliEnvSettings
{ cliEnvSettingsCmdParser = parser
, cliEnvSettingsAppEnv = ()
, cliEnvSettingsHeaderDesc = "Simple CLI program"
, cliEnvSettingsProgDesc = "CLI tool build with iris - a Haskell CLI framework"
, cliEnvSettingsVersionSettings = Nothing
, cliEnvSettingsAppName = Nothing
}
argValue :: String
argValue = "someValue"
expectedErrorTextUserDefinedNoInputArg :: String
expectedErrorTextUserDefinedNoInputArg =
"Invalid argument `"
<> argValue
<> "'\n\
\\n\
\Usage: <iris-test> [--no-input] --no-input ARG [--colour | --no-colour]\n\
\\n\
\ CLI tool build with iris - a Haskell CLI framework"
expectedErrorTextUserDefinedNoInputNoArg :: String
expectedErrorTextUserDefinedNoInputNoArg =
"Missing: --no-input ARG\n\
\\n\
\Usage: <iris-test> [--no-input] --no-input ARG [--colour | --no-colour]\n\
\\n\
\ CLI tool build with iris - a Haskell CLI framework"
cliSpecParserConflicts :: Spec
cliSpecParserConflicts = describe "Cli Parser Conflicts" $ do
let parserPrefs = Opt.defaultPrefs
it "--no-input=someValue defined by user - arg provided" $ do
let parserInfo = cmdParserInfo $ customParserSettings userDefinedNoInputOption
let result = Opt.execParserPure parserPrefs parserInfo ["--no-input", argValue]
parseResultHandlerFailure result expectedErrorTextUserDefinedNoInputArg
it "--no-input=someValue defined by user - no arg provided" $ do
let parserInfo = cmdParserInfo $ customParserSettings userDefinedNoInputOption
let result = Opt.execParserPure parserPrefs parserInfo ["--no-input"]
parseResultHandlerFailure result expectedErrorTextUserDefinedNoInputNoArg
it "--no-input=someValue defined by user - not provided at all" $ do
let parserInfo = cmdParserInfo $ customParserSettings userDefinedNoInputOption
let result = Opt.execParserPure parserPrefs parserInfo []
parseResultHandlerFailure result expectedErrorTextUserDefinedNoInputNoArg
it "--no-input switch defined by user - provided" $ do
let parserInfo = cmdParserInfo $ customParserSettings userDefinedNoInputSwitch
let result = Opt.execParserPure parserPrefs parserInfo ["--no-input"]
parseResultHandlerSuccess result ["NonInteractive", "False"]
it "--no-input switch defined by user - not provided" $ do
let parserInfo = cmdParserInfo $ customParserSettings userDefinedNoInputSwitch
let result = Opt.execParserPure parserPrefs parserInfo []
parseResultHandlerSuccess result ["Interactive", "False"]
it "--no-input switch with command defined by user - user provided" $ do
let parserInfo = cmdParserInfo $ customParserSettings userDefinedNoInputOnCommand
let result = Opt.execParserPure parserPrefs parserInfo ["test-command", "--no-input"]
parseResultHandlerSuccess result ["Interactive", "True"]
it "--no-input switch with command defined by user - internal provided" $ do
let parserInfo = cmdParserInfo $ customParserSettings userDefinedNoInputOnCommand
let result = Opt.execParserPure parserPrefs parserInfo ["--no-input", "test-command"]
parseResultHandlerSuccess result ["NonInteractive", "False"]
parseResultHandlerSuccess :: Show b => Opt.ParserResult (Cmd (UserDefinedParser b)) -> [String] -> Expectation
parseResultHandlerSuccess parseResult expected =
case parseResult of
Opt.Failure _ -> expectationFailure "Expected 'Success' but got 'Failure' "
Opt.Success a -> do
let internalNoInput = show $ cmdInteractiveMode a
let userDefinedNoInput = show . noInteractive . cmdCmd $ a
shouldBe [internalNoInput, userDefinedNoInput] expected
Opt.CompletionInvoked completionResult -> expectationFailure $ "Expected 'Success' but got: " <> show completionResult
parseResultHandlerFailure :: Opt.ParserResult a -> String -> Expectation
parseResultHandlerFailure parseResult expected =
case parseResult of
-- The help functionality is baked into optparse-applicative and presents itself as a ParserFailure.
Opt.Failure (Opt.ParserFailure getFailure) -> do
let (helpText, _exitCode, _int) = getFailure "<iris-test>"
show helpText `shouldBe` expected
Opt.Success _ -> expectationFailure "Expected 'Failure' but got 'Success' "
Opt.CompletionInvoked completionResult -> expectationFailure $ "Expected 'Failure' but got: " <> show completionResult