Skip to content

Commit

Permalink
[#59] add tests for catching global and local parser conflicts (#88)
Browse files Browse the repository at this point in the history
Resolves #59

Co-authored-by: zetkez <[email protected]>
  • Loading branch information
zetkez and zetkez authored Oct 13, 2022
1 parent 4701eda commit bb4f1b1
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 22 deletions.
3 changes: 2 additions & 1 deletion test/Test/Iris.hs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ module Test.Iris (irisSpec) where
import Test.Hspec (Spec, describe)

import Test.Iris.Tool (toolSpec)
import Test.Iris.Cli (cliSpec)
import Test.Iris.Cli (cliSpec, cliSpecParserConflicts)

irisSpec :: Spec
irisSpec = describe "Iris" $ do
toolSpec
cliSpec
cliSpecParserConflicts
131 changes: 110 additions & 21 deletions test/Test/Iris/Cli.hs
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
{-# LANGUAGE ScopedTypeVariables #-}
module Test.Iris.Cli (cliSpec) where
module Test.Iris.Cli (cliSpec, cliSpecParserConflicts) where

import Test.Hspec (Spec, describe, it, shouldBe, expectationFailure, shouldReturn)
import Test.Hspec (Expectation, Spec, describe, expectationFailure, it, shouldBe, shouldReturn)

import Iris.Cli (VersionSettings (versionSettingsMkDesc))
import Iris.Cli.Interactive (InteractiveMode (..), handleInteractiveMode)
import Iris.Cli.Internal
import Iris.Cli.ParserInfo (cmdParserInfo)
import Iris.Settings (defaultCliEnvSettings, cliEnvSettingsVersionSettings)
import Iris.Cli.Version (defaultVersionSettings)
import Iris.Settings (CliEnvSettings (..), defaultCliEnvSettings)
import qualified Options.Applicative as Opt
import qualified Paths_iris as Autogen
import Iris.Cli (VersionSettings(versionSettingsMkDesc))
import Iris.Cli.Interactive (handleInteractiveMode, InteractiveMode (..))
import System.Environment (lookupEnv)


Expand Down Expand Up @@ -51,17 +52,17 @@ cliSpec = describe "Cli Options" $ do
it "help without version environment" $ do
let parserInfo = cmdParserInfo defaultCliEnvSettings
let result = Opt.execParserPure parserPrefs parserInfo ["--help"]
parseResultHandler result expectedHelpText
parseResultHandlerFailure result expectedHelpText
it "help with version environment" $ do
let cliEnvSettings = defaultCliEnvSettings { cliEnvSettingsVersionSettings = Just (defaultVersionSettings Autogen.version)}
let parserInfo= cmdParserInfo cliEnvSettings
let parserInfo = cmdParserInfo cliEnvSettings
let result = Opt.execParserPure parserPrefs parserInfo ["--help"]
parseResultHandler result expectedHelpTextWithVersion
parseResultHandlerFailure result expectedHelpTextWithVersion
it "--numeric-version returns correct version" $ do
let cliEnvSettings = defaultCliEnvSettings { cliEnvSettingsVersionSettings = Just (defaultVersionSettings Autogen.version)}
let parserInfo= cmdParserInfo cliEnvSettings
let parserInfo = cmdParserInfo cliEnvSettings
let result = Opt.execParserPure parserPrefs parserInfo ["--numeric-version"]
parseResultHandler result expectedNumericVersion
parseResultHandlerFailure result expectedNumericVersion
it "CI interactivity check" $ do
handleInteractiveMode NonInteractive `shouldReturn` NonInteractive
isCi <- checkCI
Expand All @@ -70,16 +71,104 @@ cliSpec = describe "Cli Options" $ do
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 parserInfo = cmdParserInfo cliEnvSettings
let expectedVersion = expectedVersionMkDescription expectedNumericVersion
let result = Opt.execParserPure parserPrefs parserInfo ["--version"]
parseResultHandler result expectedVersion
where
parseResultHandler 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
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
, cliEnvSettingsRequiredTools = []
}

argValue :: String
argValue = "someValue"

expectedErrorTextUserDefinedNoInputArg :: String
expectedErrorTextUserDefinedNoInputArg =
"Invalid argument `" <> argValue <> "'\n\
\\n\
\Usage: <iris-test> [--no-input] --no-input ARG\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\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

0 comments on commit bb4f1b1

Please sign in to comment.