Blame tests/test.hs

Packit 3fa651
{-# LANGUAGE StandaloneDeriving         #-}
Packit 3fa651
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
Packit 3fa651
{-# LANGUAGE TemplateHaskell            #-}
Packit 3fa651
{-# OPTIONS_GHC -fno-warn-orphans       #-}
Packit 3fa651
module Main where
Packit 3fa651
Packit 3fa651
import qualified Examples.Hello as Hello
Packit 3fa651
import qualified Examples.Commands as Commands
Packit 3fa651
import qualified Examples.Cabal as Cabal
Packit 3fa651
import qualified Examples.Alternatives as Alternatives
Packit 3fa651
import qualified Examples.Formatting as Formatting
Packit 3fa651
Packit 3fa651
import           Control.Applicative
Packit 3fa651
import           Control.Monad
Packit 3fa651
import           Data.ByteString (ByteString)
Packit 3fa651
import           Data.List hiding (group)
Packit 3fa651
import           Data.Semigroup hiding (option)
Packit 3fa651
import           Data.String
Packit 3fa651
Packit 3fa651
import           System.Exit
Packit 3fa651
import           Test.QuickCheck hiding (Success, Failure)
Packit 3fa651
import           Test.QuickCheck.Property
Packit 3fa651
Packit 3fa651
import           Options.Applicative
Packit 3fa651
import           Options.Applicative.Types
Packit 3fa651
import           Options.Applicative.Help.Pretty (Doc, SimpleDoc(..))
Packit 3fa651
import qualified Options.Applicative.Help.Pretty as Doc
Packit 3fa651
import           Options.Applicative.Help.Chunk
Packit 3fa651
import           Options.Applicative.Help.Levenshtein
Packit 3fa651
Packit 3fa651
import           Prelude
Packit 3fa651
Packit 3fa651
run :: ParserInfo a -> [String] -> ParserResult a
Packit 3fa651
run = execParserPure defaultPrefs
Packit 3fa651
Packit 3fa651
assertError :: Show a => ParserResult a
Packit 3fa651
            -> (ParserFailure ParserHelp -> Property) -> Property
Packit 3fa651
assertError x f = case x of
Packit 3fa651
  Success r -> counterexample ("expected failure, got success: " ++ show r) failed
Packit 3fa651
  Failure e -> f e
Packit 3fa651
  CompletionInvoked _ -> counterexample "expected failure, got completion" failed
Packit 3fa651
Packit 3fa651
assertResult :: ParserResult a -> (a -> Property) -> Property
Packit 3fa651
assertResult x f = case x of
Packit 3fa651
  Success r -> f r
Packit 3fa651
  Failure e -> do
Packit 3fa651
    let (msg, _) = renderFailure e "test"
Packit 3fa651
    counterexample ("unexpected parse error\n" ++ msg) failed
Packit 3fa651
  CompletionInvoked _ -> counterexample "expected result, got completion" failed
Packit 3fa651
Packit 3fa651
assertHasLine :: String -> String -> Property
Packit 3fa651
assertHasLine l s = counterexample ("expected line:\n\t" ++ l ++ "\nnot found")
Packit 3fa651
                  $ l `elem` lines s
Packit 3fa651
Packit 3fa651
checkHelpTextWith :: Show a => ExitCode -> ParserPrefs -> String
Packit 3fa651
                  -> ParserInfo a -> [String] -> Property
Packit 3fa651
checkHelpTextWith ecode pprefs name p args = ioProperty $ do
Packit 3fa651
  let result = execParserPure pprefs p args
Packit 3fa651
  expected <- readFile $ "tests/" ++ name ++ ".err.txt"
Packit 3fa651
  return $ assertError result $ \failure ->
Packit 3fa651
    let (msg, code) = renderFailure failure name
Packit 3fa651
    in  (expected === msg ++ "\n") .&&. (ecode === code)
Packit 3fa651
Packit 3fa651
checkHelpText :: Show a => String -> ParserInfo a -> [String] -> Property
Packit 3fa651
checkHelpText = checkHelpTextWith ExitSuccess defaultPrefs
Packit 3fa651
Packit 3fa651
prop_hello :: Property
Packit 3fa651
prop_hello = once $
Packit 3fa651
  checkHelpText "hello" Hello.opts ["--help"]
Packit 3fa651
Packit 3fa651
prop_modes :: Property
Packit 3fa651
prop_modes = once $
Packit 3fa651
  checkHelpText "commands" Commands.opts ["--help"]
Packit 3fa651
Packit 3fa651
prop_cmd_header :: Property
Packit 3fa651
prop_cmd_header = once $
Packit 3fa651
  let i  = info (helper <*> Commands.sample) (header "foo")
Packit 3fa651
      r1 = checkHelpTextWith (ExitFailure 1) defaultPrefs
Packit 3fa651
                    "commands_header" i ["-zello"]
Packit 3fa651
      r2 = checkHelpTextWith (ExitFailure 1) (prefs showHelpOnError)
Packit 3fa651
                    "commands_header_full" i ["-zello"]
Packit 3fa651
  in  (r1 .&&. r2)
Packit 3fa651
Packit 3fa651
prop_cabal_conf :: Property
Packit 3fa651
prop_cabal_conf = once $
Packit 3fa651
  checkHelpText "cabal" Cabal.pinfo ["configure", "--help"]
Packit 3fa651
Packit 3fa651
prop_args :: Property
Packit 3fa651
prop_args = once $
Packit 3fa651
  let result = run Commands.opts ["hello", "foo", "bar"]
Packit 3fa651
  in  assertResult result ((===) (Commands.Hello ["foo", "bar"]))
Packit 3fa651
Packit 3fa651
prop_args_opts :: Property
Packit 3fa651
prop_args_opts = once $
Packit 3fa651
  let result = run Commands.opts ["hello", "foo", "--bar"]
Packit 3fa651
  in  assertError result (\_ -> property succeeded)
Packit 3fa651
Packit 3fa651
prop_args_ddash :: Property
Packit 3fa651
prop_args_ddash = once $
Packit 3fa651
  let result = run Commands.opts ["hello", "foo", "--", "--bar", "--", "baz"]
Packit 3fa651
  in  assertResult result ((===) (Commands.Hello ["foo", "--bar", "--", "baz"]))
Packit 3fa651
Packit 3fa651
prop_alts :: Property
Packit 3fa651
prop_alts = once $
Packit 3fa651
  let result = run Alternatives.opts ["-b", "-a", "-b", "-a", "-a", "-b"]
Packit 3fa651
  in  assertResult result $ \xs ->
Packit 3fa651
    let a = Alternatives.A
Packit 3fa651
        b = Alternatives.B
Packit 3fa651
    in  [b, a, b, a, a, b] === xs
Packit 3fa651
Packit 3fa651
prop_show_default :: Property
Packit 3fa651
prop_show_default = once $
Packit 3fa651
  let p = option auto
Packit 3fa651
          ( short 'n'
Packit 3fa651
          <> help "set count"
Packit 3fa651
          <> value (0 :: Int)
Packit 3fa651
          <> showDefault )
Packit 3fa651
      i = info (p <**> helper) idm
Packit 3fa651
      result = run i ["--help"]
Packit 3fa651
  in  assertError result $ \failure ->
Packit 3fa651
    let (msg, _) = renderFailure failure "test"
Packit 3fa651
    in  assertHasLine
Packit 3fa651
        "  -n ARG                   set count (default: 0)"
Packit 3fa651
        msg
Packit 3fa651
Packit 3fa651
prop_alt_cont :: Property
Packit 3fa651
prop_alt_cont = once $
Packit 3fa651
  let p = Alternatives.a <|> Alternatives.b
Packit 3fa651
      i = info p idm
Packit 3fa651
      result = run i ["-a", "-b"]
Packit 3fa651
  in  assertError result (\_ -> property succeeded)
Packit 3fa651
Packit 3fa651
prop_alt_help :: Property
Packit 3fa651
prop_alt_help = once $
Packit 3fa651
  let p :: Parser (Maybe (Either String String))
Packit 3fa651
      p = p1 <|> p2 <|> p3
Packit 3fa651
      p1 = (Just . Left)
Packit 3fa651
        <$> strOption ( long "virtual-machine"
Packit 3fa651
                     <> metavar "VM"
Packit 3fa651
                     <> help "Virtual machine name" )
Packit 3fa651
      p2 = (Just . Right)
Packit 3fa651
        <$> strOption ( long "cloud-service"
Packit 3fa651
                     <> metavar "CS"
Packit 3fa651
                     <> help "Cloud service name" )
Packit 3fa651
      p3 = flag' Nothing ( long "dry-run" )
Packit 3fa651
      i = info (p <**> helper) idm
Packit 3fa651
  in checkHelpText "alt" i ["--help"]
Packit 3fa651
Packit 3fa651
prop_nested_commands :: Property
Packit 3fa651
prop_nested_commands = once $
Packit 3fa651
  let p3 :: Parser String
Packit 3fa651
      p3 = strOption (short 'a' <> metavar "A")
Packit 3fa651
      p2 = subparser (command "b" (info p3 idm))
Packit 3fa651
      p1 = subparser (command "c" (info p2 idm))
Packit 3fa651
      i = info (p1 <**> helper) idm
Packit 3fa651
  in checkHelpTextWith (ExitFailure 1) defaultPrefs "nested" i ["c", "b"]
Packit 3fa651
Packit 3fa651
prop_drops_back_contexts :: Property
Packit 3fa651
prop_drops_back_contexts = once $
Packit 3fa651
  let p3 :: Parser String
Packit 3fa651
      p3 = strOption (short 'a' <> metavar "A")
Packit 3fa651
      p2 = subparser (command "b" (info p3 idm)  <> metavar "B")
Packit 3fa651
      p1 = subparser (command "c" (info p3 idm)  <> metavar "C")
Packit 3fa651
      p0 = (,) <$> p2 <*> p1
Packit 3fa651
      i = info (p0 <**> helper) idm
Packit 3fa651
  in checkHelpTextWith (ExitFailure 1) defaultPrefs "dropback" i ["b", "-aA"]
Packit 3fa651
Packit 3fa651
prop_context_carry :: Property
Packit 3fa651
prop_context_carry = once $
Packit 3fa651
  let p3 :: Parser String
Packit 3fa651
      p3 = strOption (short 'a' <> metavar "A")
Packit 3fa651
      p2 = subparser (command "b" (info p3 idm)  <> metavar "B")
Packit 3fa651
      p1 = subparser (command "c" (info p3 idm)  <> metavar "C")
Packit 3fa651
      p0 = (,) <$> p2 <*> p1
Packit 3fa651
      i = info (p0 <**> helper) idm
Packit 3fa651
  in checkHelpTextWith (ExitFailure 1) defaultPrefs "carry" i ["b", "-aA", "c"]
Packit 3fa651
Packit 3fa651
prop_help_on_empty :: Property
Packit 3fa651
prop_help_on_empty = once $
Packit 3fa651
  let p3 :: Parser String
Packit 3fa651
      p3 = strOption (short 'a' <> metavar "A")
Packit 3fa651
      p2 = subparser (command "b" (info p3 idm)  <> metavar "B")
Packit 3fa651
      p1 = subparser (command "c" (info p3 idm)  <> metavar "C")
Packit 3fa651
      p0 = (,) <$> p2 <*> p1
Packit 3fa651
      i = info (p0 <**> helper) idm
Packit 3fa651
  in checkHelpTextWith (ExitFailure 1) (prefs showHelpOnEmpty) "helponempty" i []
Packit 3fa651
Packit 3fa651
prop_help_on_empty_sub :: Property
Packit 3fa651
prop_help_on_empty_sub = once $
Packit 3fa651
  let p3 :: Parser String
Packit 3fa651
      p3 = strOption (short 'a' <> metavar "A" <> help "both commands require this")
Packit 3fa651
      p2 = subparser (command "b" (info p3 idm)  <> metavar "B")
Packit 3fa651
      p1 = subparser (command "c" (info p3 idm)  <> metavar "C")
Packit 3fa651
      p0 = (,) <$> p2 <*> p1
Packit 3fa651
      i = info (p0 <**> helper) idm
Packit 3fa651
  in checkHelpTextWith (ExitFailure 1) (prefs showHelpOnEmpty) "helponemptysub" i ["b", "-aA", "c"]
Packit 3fa651
Packit 3fa651
prop_many_args :: Property
Packit 3fa651
prop_many_args = forAll (choose (0,2000)) $ \nargs ->
Packit 3fa651
  let p :: Parser [String]
Packit 3fa651
      p = many (argument str idm)
Packit 3fa651
      i = info p idm
Packit 3fa651
      result = run i (replicate nargs "foo")
Packit 3fa651
  in  assertResult result (\xs -> nargs === length xs)
Packit 3fa651
Packit 3fa651
prop_disambiguate :: Property
Packit 3fa651
prop_disambiguate = once $
Packit 3fa651
  let p =   flag' (1 :: Int) (long "foo")
Packit 3fa651
        <|> flag' 2 (long "bar")
Packit 3fa651
        <|> flag' 3 (long "baz")
Packit 3fa651
      i = info p idm
Packit 3fa651
      result = execParserPure (prefs disambiguate) i ["--f"]
Packit 3fa651
  in  assertResult result ((===) 1)
Packit 3fa651
Packit 3fa651
prop_ambiguous :: Property
Packit 3fa651
prop_ambiguous = once $
Packit 3fa651
  let p =   flag' (1 :: Int) (long "foo")
Packit 3fa651
        <|> flag' 2 (long "bar")
Packit 3fa651
        <|> flag' 3 (long "baz")
Packit 3fa651
      i = info p idm
Packit 3fa651
      result = execParserPure (prefs disambiguate) i ["--ba"]
Packit 3fa651
  in  assertError result (\_ -> property succeeded)
Packit 3fa651
Packit 3fa651
prop_completion :: Property
Packit 3fa651
prop_completion = once . ioProperty $
Packit 3fa651
  let p = (,)
Packit 3fa651
        <$> strOption (long "foo" <> value "")
Packit 3fa651
        <*> strOption (long "bar" <> value "")
Packit 3fa651
      i = info p idm
Packit 3fa651
      result = run i ["--bash-completion-index", "0"]
Packit 3fa651
  in case result of
Packit 3fa651
    CompletionInvoked (CompletionResult err) -> do
Packit 3fa651
      completions <- lines <$> err "test"
Packit 3fa651
      return $ ["--foo", "--bar"] === completions
Packit 3fa651
    Failure _   -> return $ counterexample "unexpected failure" failed
Packit 3fa651
    Success val -> return $ counterexample ("unexpected result " ++ show val) failed
Packit 3fa651
Packit 3fa651
prop_completion_opt_after_double_dash :: Property
Packit 3fa651
prop_completion_opt_after_double_dash = once . ioProperty $
Packit 3fa651
  let p = (,)
Packit 3fa651
        <$> strOption (long "foo" <> value "")
Packit 3fa651
        <*> argument readerAsk (completeWith ["bar"])
Packit 3fa651
      i = info p idm
Packit 3fa651
      result = run i ["--bash-completion-index", "2"
Packit 3fa651
                    , "--bash-completion-word", "test"
Packit 3fa651
                    , "--bash-completion-word", "--"]
Packit 3fa651
  in case result of
Packit 3fa651
    CompletionInvoked (CompletionResult err) -> do
Packit 3fa651
      completions <- lines <$> err "test"
Packit 3fa651
      return $ ["bar"] === completions
Packit 3fa651
    Failure _   -> return $ counterexample "unexpected failure" failed
Packit 3fa651
    Success val -> return $ counterexample ("unexpected result " ++ show val) failed
Packit 3fa651
Packit 3fa651
prop_completion_only_reachable :: Property
Packit 3fa651
prop_completion_only_reachable = once . ioProperty $
Packit 3fa651
  let p :: Parser (String,String)
Packit 3fa651
      p = (,)
Packit 3fa651
        <$> strArgument (completeWith ["reachable"])
Packit 3fa651
        <*> strArgument (completeWith ["unreachable"])
Packit 3fa651
      i = info p idm
Packit 3fa651
      result = run i ["--bash-completion-index", "0"]
Packit 3fa651
  in case result of
Packit 3fa651
    CompletionInvoked (CompletionResult err) -> do
Packit 3fa651
      completions <- lines <$> err "test"
Packit 3fa651
      return $ ["reachable"] === completions
Packit 3fa651
    Failure _   -> return $ counterexample "unexpected failure" failed
Packit 3fa651
    Success val -> return $ counterexample ("unexpected result " ++ show val) failed
Packit 3fa651
Packit 3fa651
prop_completion_only_reachable_deep :: Property
Packit 3fa651
prop_completion_only_reachable_deep = once . ioProperty $
Packit 3fa651
  let p :: Parser (String,String)
Packit 3fa651
      p = (,)
Packit 3fa651
        <$> strArgument (completeWith ["seen"])
Packit 3fa651
        <*> strArgument (completeWith ["now-reachable"])
Packit 3fa651
      i = info p idm
Packit 3fa651
      result = run i [ "--bash-completion-index", "2"
Packit 3fa651
                     , "--bash-completion-word", "test-prog"
Packit 3fa651
                     , "--bash-completion-word", "seen" ]
Packit 3fa651
  in case result of
Packit 3fa651
    CompletionInvoked (CompletionResult err) -> do
Packit 3fa651
      completions <- lines <$> err "test"
Packit 3fa651
      return $ ["now-reachable"] === completions
Packit 3fa651
    Failure _   -> return $ counterexample "unexpected failure" failed
Packit 3fa651
    Success val -> return $ counterexample ("unexpected result " ++ show val) failed
Packit 3fa651
Packit 3fa651
prop_completion_multi :: Property
Packit 3fa651
prop_completion_multi = once . ioProperty $
Packit 3fa651
  let p :: Parser [String]
Packit 3fa651
      p = many (strArgument (completeWith ["reachable"]))
Packit 3fa651
      i = info p idm
Packit 3fa651
      result = run i [ "--bash-completion-index", "3"
Packit 3fa651
                     , "--bash-completion-word", "test-prog"
Packit 3fa651
                     , "--bash-completion-word", "nope" ]
Packit 3fa651
  in case result of
Packit 3fa651
    CompletionInvoked (CompletionResult err) -> do
Packit 3fa651
      completions <- lines <$> err "test"
Packit 3fa651
      return $ ["reachable"] === completions
Packit 3fa651
    Failure _   -> return $ counterexample "unexpected failure" failed
Packit 3fa651
    Success val -> return $ counterexample ("unexpected result " ++ show val) failed
Packit 3fa651
Packit 3fa651
prop_completion_rich :: Property
Packit 3fa651
prop_completion_rich = once . ioProperty $
Packit 3fa651
  let p = (,)
Packit 3fa651
        <$> option readerAsk (long "foo" <> help "Fo?")
Packit 3fa651
        <*> option readerAsk (long "bar" <> help "Ba?")
Packit 3fa651
      i = info p idm
Packit 3fa651
      result = run i ["--bash-completion-enriched", "--bash-completion-index", "0"]
Packit 3fa651
  in case result of
Packit 3fa651
    CompletionInvoked (CompletionResult err) -> do
Packit 3fa651
      completions <- lines <$> err "test"
Packit 3fa651
      return $ ["--foo\tFo?", "--bar\tBa?"] === completions
Packit 3fa651
    Failure _   -> return $ counterexample "unexpected failure" failed
Packit 3fa651
    Success val -> return $ counterexample ("unexpected result " ++ show val) failed
Packit 3fa651
Packit 3fa651
prop_completion_rich_lengths :: Property
Packit 3fa651
prop_completion_rich_lengths = once . ioProperty $
Packit 3fa651
  let p = (,)
Packit 3fa651
        <$> option readerAsk (long "foo" <> help "Foo hide this")
Packit 3fa651
        <*> option readerAsk (long "bar" <> help "Bar hide this")
Packit 3fa651
      i = info p idm
Packit 3fa651
      result = run i [ "--bash-completion-enriched"
Packit 3fa651
                     , "--bash-completion-index=0"
Packit 3fa651
                     , "--bash-completion-option-desc-length=3"
Packit 3fa651
                     , "--bash-completion-command-desc-length=30"]
Packit 3fa651
  in case result of
Packit 3fa651
    CompletionInvoked (CompletionResult err) -> do
Packit 3fa651
      completions <- lines <$> err "test"
Packit 3fa651
      return $ ["--foo\tFoo...", "--bar\tBar..."] === completions
Packit 3fa651
    Failure _   -> return $ counterexample "unexpected failure" failed
Packit 3fa651
    Success val -> return $ counterexample ("unexpected result " ++ show val) failed
Packit 3fa651
Packit 3fa651
prop_bind_usage :: Property
Packit 3fa651
prop_bind_usage = once $
Packit 3fa651
  let p :: Parser [String]
Packit 3fa651
      p = many (argument str (metavar "ARGS..."))
Packit 3fa651
      i = info (p <**> helper) briefDesc
Packit 3fa651
      result = run i ["--help"]
Packit 3fa651
  in assertError result $ \failure ->
Packit 3fa651
    let text = head . lines . fst $ renderFailure failure "test"
Packit 3fa651
    in  "Usage: test [ARGS...]" === text
Packit 3fa651
Packit 3fa651
prop_issue_19 :: Property
Packit 3fa651
prop_issue_19 = once $
Packit 3fa651
  let p = option (fmap Just str)
Packit 3fa651
        ( short 'x'
Packit 3fa651
       <> value Nothing )
Packit 3fa651
      i = info (p <**> helper) idm
Packit 3fa651
      result = run i ["-x", "foo"]
Packit 3fa651
  in  assertResult result (Just "foo" ===)
Packit 3fa651
Packit 3fa651
prop_arguments1_none :: Property
Packit 3fa651
prop_arguments1_none =
Packit 3fa651
  let p :: Parser [String]
Packit 3fa651
      p = some (argument str idm)
Packit 3fa651
      i = info (p <**> helper) idm
Packit 3fa651
      result = run i []
Packit 3fa651
  in assertError result $ \_ -> property succeeded
Packit 3fa651
Packit 3fa651
prop_arguments1_some :: Property
Packit 3fa651
prop_arguments1_some = once $
Packit 3fa651
  let p :: Parser [String]
Packit 3fa651
      p = some (argument str idm)
Packit 3fa651
      i = info (p <**> helper) idm
Packit 3fa651
      result = run i ["foo", "--", "bar", "baz"]
Packit 3fa651
  in  assertResult result (["foo", "bar", "baz"] ===)
Packit 3fa651
Packit 3fa651
prop_arguments_switch :: Property
Packit 3fa651
prop_arguments_switch = once $
Packit 3fa651
  let p :: Parser [String]
Packit 3fa651
      p =  switch (short 'x')
Packit 3fa651
        *> many (argument str idm)
Packit 3fa651
      i = info p idm
Packit 3fa651
      result = run i ["--", "-x"]
Packit 3fa651
  in assertResult result $ \args -> ["-x"] === args
Packit 3fa651
Packit 3fa651
prop_issue_35 :: Property
Packit 3fa651
prop_issue_35 = once $
Packit 3fa651
  let p =  flag' True (short 't' <> hidden)
Packit 3fa651
       <|> flag' False (short 'f')
Packit 3fa651
      i = info p idm
Packit 3fa651
      result = run i []
Packit 3fa651
  in assertError result $ \failure ->
Packit 3fa651
    let text = lines . fst $ renderFailure failure "test"
Packit 3fa651
    in  ["Missing: -f", "", "Usage: test -f"] === text
Packit 3fa651
Packit 3fa651
prop_backtracking :: Property
Packit 3fa651
prop_backtracking = once $
Packit 3fa651
  let p2 = switch (short 'a')
Packit 3fa651
      p1 = (,)
Packit 3fa651
        <$> subparser (command "c" (info p2 idm))
Packit 3fa651
        <*> switch (short 'b')
Packit 3fa651
      i = info (p1 <**> helper) idm
Packit 3fa651
      result = execParserPure (prefs noBacktrack) i ["c", "-b"]
Packit 3fa651
  in assertError result $ \_ -> property succeeded
Packit 3fa651
Packit 3fa651
prop_error_context :: Property
Packit 3fa651
prop_error_context = once $
Packit 3fa651
  let p = pk <$> option auto (long "port")
Packit 3fa651
             <*> option auto (long "key")
Packit 3fa651
      i = info p idm
Packit 3fa651
      result = run i ["--port", "foo", "--key", "291"]
Packit 3fa651
  in assertError result $ \failure ->
Packit 3fa651
      let (msg, _) = renderFailure failure "test"
Packit 3fa651
          errMsg   = head $ lines msg
Packit 3fa651
      in  conjoin [ counterexample "no context in error message (option)" ("port" `isInfixOf` errMsg)
Packit 3fa651
                  , counterexample "no context in error message (value)"  ("foo" `isInfixOf` errMsg)]
Packit 3fa651
  where
Packit 3fa651
    pk :: Int -> Int -> (Int, Int)
Packit 3fa651
    pk = (,)
Packit 3fa651
Packit 3fa651
condr :: (Int -> Bool) -> ReadM Int
Packit 3fa651
condr f = do
Packit 3fa651
  x <- auto
Packit 3fa651
  guard (f x)
Packit 3fa651
  return x
Packit 3fa651
Packit 3fa651
prop_arg_order_1 :: Property
Packit 3fa651
prop_arg_order_1 = once $
Packit 3fa651
  let p = (,)
Packit 3fa651
          <$> argument (condr even) idm
Packit 3fa651
          <*> argument (condr odd) idm
Packit 3fa651
      i = info p idm
Packit 3fa651
      result = run i ["3", "6"]
Packit 3fa651
  in assertError result $ \_ -> property succeeded
Packit 3fa651
Packit 3fa651
prop_arg_order_2 :: Property
Packit 3fa651
prop_arg_order_2 = once $
Packit 3fa651
  let p = (,,)
Packit 3fa651
        <$> argument (condr even) idm
Packit 3fa651
        <*> option (condr even) (short 'a')
Packit 3fa651
        <*> option (condr odd) (short 'b')
Packit 3fa651
      i = info p idm
Packit 3fa651
      result = run i ["2", "-b", "3", "-a", "6"]
Packit 3fa651
  in assertResult result ((===) (2, 6, 3))
Packit 3fa651
Packit 3fa651
prop_arg_order_3 :: Property
Packit 3fa651
prop_arg_order_3 = once $
Packit 3fa651
  let p = (,)
Packit 3fa651
          <$> (  argument (condr even) idm
Packit 3fa651
             <|> option auto (short 'n') )
Packit 3fa651
          <*> argument (condr odd) idm
Packit 3fa651
      i = info p idm
Packit 3fa651
      result = run i ["-n", "3", "5"]
Packit 3fa651
  in assertResult result ((===) (3, 5))
Packit 3fa651
Packit 3fa651
prop_unix_style :: Int -> Int -> Property
Packit 3fa651
prop_unix_style j k =
Packit 3fa651
  let p = (,)
Packit 3fa651
          <$> flag' j (short 'x')
Packit 3fa651
          <*> flag' k (short 'c')
Packit 3fa651
      i = info p idm
Packit 3fa651
      result = run i ["-xc"]
Packit 3fa651
  in assertResult result ((===) (j,k))
Packit 3fa651
Packit 3fa651
prop_unix_with_options :: Property
Packit 3fa651
prop_unix_with_options = once $
Packit 3fa651
  let p = (,)
Packit 3fa651
          <$> flag' (1 :: Int) (short 'x')
Packit 3fa651
          <*> strOption (short 'a')
Packit 3fa651
      i = info p idm
Packit 3fa651
      result = run i ["-xac"]
Packit 3fa651
  in assertResult result ((===) (1, "c"))
Packit 3fa651
Packit 3fa651
prop_count_flags :: Property
Packit 3fa651
prop_count_flags = once $
Packit 3fa651
  let p = length <$> many (flag' () (short 't'))
Packit 3fa651
      i = info p idm
Packit 3fa651
      result = run i ["-ttt"]
Packit 3fa651
  in assertResult result ((===) 3)
Packit 3fa651
Packit 3fa651
prop_issue_47 :: Property
Packit 3fa651
prop_issue_47 = once $
Packit 3fa651
  let p = option r (long "test" <> value 9) :: Parser Int
Packit 3fa651
      r = readerError "error message"
Packit 3fa651
      result = run (info p idm) ["--test", "x"]
Packit 3fa651
  in assertError result $ \failure ->
Packit 3fa651
    let text = head . lines . fst $ renderFailure failure "test"
Packit 3fa651
    in  counterexample "no error message" ("error message" `isInfixOf` text)
Packit 3fa651
Packit 3fa651
prop_long_help :: Property
Packit 3fa651
prop_long_help = once $
Packit 3fa651
  let p = Formatting.opts <**> helper
Packit 3fa651
      i = info p
Packit 3fa651
        ( progDesc (concat
Packit 3fa651
            [ "This is a very long program description. "
Packit 3fa651
            , "This text should be automatically wrapped "
Packit 3fa651
            , "to fit the size of the terminal" ]) )
Packit 3fa651
  in checkHelpTextWith ExitSuccess (prefs (columns 50)) "formatting" i ["--help"]
Packit 3fa651
Packit 3fa651
prop_issue_50 :: Property
Packit 3fa651
prop_issue_50 = once $
Packit 3fa651
  let p = argument str (metavar "INPUT")
Packit 3fa651
          <* switch (long "version")
Packit 3fa651
      result = run (info p idm) ["--version", "test"]
Packit 3fa651
  in assertResult result $ \r -> "test" === r
Packit 3fa651
Packit 3fa651
prop_intersperse_1 :: Property
Packit 3fa651
prop_intersperse_1 = once $
Packit 3fa651
  let p = many (argument str (metavar "ARGS"))
Packit 3fa651
          <* switch (short 'x')
Packit 3fa651
      result = run (info p noIntersperse)
Packit 3fa651
                 ["a", "-x", "b"]
Packit 3fa651
  in assertResult result $ \args -> ["a", "-x", "b"] === args
Packit 3fa651
Packit 3fa651
prop_intersperse_2 :: Property
Packit 3fa651
prop_intersperse_2 = once $
Packit 3fa651
  let p = subparser
Packit 3fa651
          (  command "run"
Packit 3fa651
             ( info (many (argument str (metavar "OPTIONS")))
Packit 3fa651
                    noIntersperse )
Packit 3fa651
          <> command "test"
Packit 3fa651
             ( info (many (argument str (metavar "ARGS")))
Packit 3fa651
                    idm ) )
Packit 3fa651
      i = info p idm
Packit 3fa651
      result1 = run i ["run", "foo", "-x"]
Packit 3fa651
      result2 = run i ["test", "bar", "-x"]
Packit 3fa651
  in conjoin [ assertResult result1 $ \args -> ["foo", "-x"] === args
Packit 3fa651
             , assertError result2 $ \_ -> property succeeded ]
Packit 3fa651
Packit 3fa651
prop_intersperse_3 :: Property
Packit 3fa651
prop_intersperse_3 = once $
Packit 3fa651
  let p = (,,) <$> switch ( long "foo" )
Packit 3fa651
               <*> strArgument ( metavar "FILE" )
Packit 3fa651
               <*> many ( strArgument ( metavar "ARGS..." ) )
Packit 3fa651
      i = info p noIntersperse
Packit 3fa651
      result = run i ["--foo", "myfile", "-a", "-b", "-c"]
Packit 3fa651
  in assertResult result $ \(b,f,as) ->
Packit 3fa651
     conjoin [ ["-a", "-b", "-c"] === as
Packit 3fa651
             , True               === b
Packit 3fa651
             , "myfile"           === f ]
Packit 3fa651
Packit 3fa651
prop_forward_options :: Property
Packit 3fa651
prop_forward_options = once $
Packit 3fa651
  let p = (,) <$> switch ( long "foo" )
Packit 3fa651
              <*> many ( strArgument ( metavar "ARGS..." ) )
Packit 3fa651
      i = info p forwardOptions
Packit 3fa651
      result = run i ["--fo", "--foo", "myfile"]
Packit 3fa651
  in assertResult result $ \(b,a) ->
Packit 3fa651
     conjoin [ True               === b
Packit 3fa651
             , ["--fo", "myfile"] === a ]
Packit 3fa651
Packit 3fa651
prop_issue_52 :: Property
Packit 3fa651
prop_issue_52 = once $
Packit 3fa651
  let p = subparser
Packit 3fa651
        ( metavar "FOO"
Packit 3fa651
        <> command "run" (info (pure "foo") idm) )
Packit 3fa651
      i = info p idm
Packit 3fa651
  in assertError (run i []) $ \failure -> do
Packit 3fa651
    let text = lines . fst $ renderFailure failure "test"
Packit 3fa651
    ["Missing: FOO", "", "Usage: test FOO"] === text
Packit 3fa651
Packit 3fa651
prop_multiple_subparsers :: Property
Packit 3fa651
prop_multiple_subparsers = once $
Packit 3fa651
  let p1 = subparser
Packit 3fa651
        (command "add" (info (pure ())
Packit 3fa651
             ( progDesc "Add a file to the repository" )))
Packit 3fa651
      p2 = subparser
Packit 3fa651
        (command "commit" (info (pure ())
Packit 3fa651
             ( progDesc "Record changes to the repository" )))
Packit 3fa651
      i = info (p1 *> p2 <**> helper) idm
Packit 3fa651
  in checkHelpText "subparsers" i ["--help"]
Packit 3fa651
Packit 3fa651
prop_argument_error :: Property
Packit 3fa651
prop_argument_error = once $
Packit 3fa651
  let r = (auto >>= \x -> x <$ guard (x == 42))
Packit 3fa651
        <|> (str >>= \x -> readerError (x ++ " /= 42"))
Packit 3fa651
      p1 = argument r idm :: Parser Int
Packit 3fa651
      i = info (p1 *> p1) idm
Packit 3fa651
  in assertError (run i ["3", "4"]) $ \failure ->
Packit 3fa651
    let text = head . lines . fst $ renderFailure failure "test"
Packit 3fa651
    in  "3 /= 42" === text
Packit 3fa651
Packit 3fa651
prop_reader_error_mplus :: Property
Packit 3fa651
prop_reader_error_mplus = once $
Packit 3fa651
  let r = (auto >>= \x -> x <$ guard (x == 42))
Packit 3fa651
        <|> (str >>= \x -> readerError (x ++ " /= 42"))
Packit 3fa651
      p1 = argument r idm :: Parser Int
Packit 3fa651
      i = info p1 idm
Packit 3fa651
  in assertError (run i ["foo"]) $ \failure ->
Packit 3fa651
    let text = head . lines . fst $ renderFailure failure "test"
Packit 3fa651
    in  "foo /= 42" === text
Packit 3fa651
Packit 3fa651
prop_missing_flags_described :: Property
Packit 3fa651
prop_missing_flags_described = once $
Packit 3fa651
  let p :: Parser (String, String, Maybe String)
Packit 3fa651
      p = (,,)
Packit 3fa651
       <$> option str (short 'a')
Packit 3fa651
       <*> option str (short 'b')
Packit 3fa651
       <*> optional (option str (short 'c'))
Packit 3fa651
      i = info p idm
Packit 3fa651
  in assertError (run i ["-b", "3"]) $ \failure ->
Packit 3fa651
    let text = head . lines . fst $ renderFailure failure "test"
Packit 3fa651
    in  "Missing: -a ARG" === text
Packit 3fa651
Packit 3fa651
prop_many_missing_flags_described :: Property
Packit 3fa651
prop_many_missing_flags_described = once $
Packit 3fa651
  let p :: Parser (String, String)
Packit 3fa651
      p = (,)
Packit 3fa651
        <$> option str (short 'a')
Packit 3fa651
        <*> option str (short 'b')
Packit 3fa651
      i = info p idm
Packit 3fa651
  in assertError (run i []) $ \failure ->
Packit 3fa651
    let text = head . lines . fst $ renderFailure failure "test"
Packit 3fa651
    in  "Missing: -a ARG -b ARG" === text
Packit 3fa651
Packit 3fa651
prop_alt_missing_flags_described :: Property
Packit 3fa651
prop_alt_missing_flags_described = once $
Packit 3fa651
  let p :: Parser String
Packit 3fa651
      p = option str (short 'a') <|> option str (short 'b')
Packit 3fa651
      i = info p idm
Packit 3fa651
  in assertError (run i []) $ \failure ->
Packit 3fa651
    let text = head . lines . fst $ renderFailure failure "test"
Packit 3fa651
    in  "Missing: (-a ARG | -b ARG)" === text
Packit 3fa651
Packit 3fa651
prop_missing_option_parameter_err :: Property
Packit 3fa651
prop_missing_option_parameter_err = once $
Packit 3fa651
  let p :: Parser String
Packit 3fa651
      p = option str (short 'a')
Packit 3fa651
      i = info p idm
Packit 3fa651
  in assertError (run i ["-a"]) $ \failure ->
Packit 3fa651
    let text = head . lines . fst $ renderFailure failure "test"
Packit 3fa651
    in  "The option `-a` expects an argument." === text
Packit 3fa651
Packit 3fa651
prop_many_pairs_success :: Property
Packit 3fa651
prop_many_pairs_success = once $
Packit 3fa651
  let p :: Parser [(String, String)]
Packit 3fa651
      p = many $ (,) <$> argument str idm <*> argument str idm
Packit 3fa651
      i = info p idm
Packit 3fa651
      nargs = 10000
Packit 3fa651
      result = run i (replicate nargs "foo")
Packit 3fa651
  in assertResult result $ \xs -> nargs `div` 2 === length xs
Packit 3fa651
Packit 3fa651
prop_many_pairs_failure :: Property
Packit 3fa651
prop_many_pairs_failure = once $
Packit 3fa651
  let p :: Parser [(String, String)]
Packit 3fa651
      p = many $ (,) <$> argument str idm <*> argument str idm
Packit 3fa651
      i = info p idm
Packit 3fa651
      nargs = 9999
Packit 3fa651
      result = run i (replicate nargs "foo")
Packit 3fa651
  in assertError result $ \_ -> property succeeded
Packit 3fa651
Packit 3fa651
prop_many_pairs_lazy_progress :: Property
Packit 3fa651
prop_many_pairs_lazy_progress = once $
Packit 3fa651
  let p :: Parser [(Maybe String, String)]
Packit 3fa651
      p = many $ (,) <$> optional (option str (short 'a')) <*> argument str idm
Packit 3fa651
      i = info p idm
Packit 3fa651
      result = run i ["foo", "-abar", "baz"]
Packit 3fa651
  in assertResult result $ \xs -> [(Just "bar", "foo"), (Nothing, "baz")] === xs
Packit 3fa651
Packit 3fa651
prop_suggest :: Property
Packit 3fa651
prop_suggest = once $
Packit 3fa651
  let p2 = subparser (command "reachable"   (info (pure ()) idm))
Packit 3fa651
      p1 = subparser (command "unreachable" (info (pure ()) idm))
Packit 3fa651
      p  = (,) <$> p2 <*> p1
Packit 3fa651
      i  = info p idm
Packit 3fa651
      result = run i ["ureachable"]
Packit 3fa651
  in assertError result $ \failure ->
Packit 3fa651
    let (msg, _)  = renderFailure failure "prog"
Packit 3fa651
    in  counterexample msg
Packit 3fa651
       $  isInfixOf "Did you mean this?\n    reachable" msg
Packit 3fa651
      .&. not (isInfixOf "unreachable" msg)
Packit 3fa651
Packit 3fa651
prop_bytestring_reader :: Property
Packit 3fa651
prop_bytestring_reader = once $
Packit 3fa651
  let t = "testValue"
Packit 3fa651
      p :: Parser ByteString
Packit 3fa651
      p = argument str idm
Packit 3fa651
      i = info p idm
Packit 3fa651
      result = run i ["testValue"]
Packit 3fa651
  in assertResult result $ \xs -> fromString t === xs
Packit 3fa651
Packit 3fa651
---
Packit 3fa651
Packit 3fa651
deriving instance Arbitrary a => Arbitrary (Chunk a)
Packit 3fa651
deriving instance Eq SimpleDoc
Packit 3fa651
deriving instance Show SimpleDoc
Packit 3fa651
Packit 3fa651
equalDocs :: Float -> Int -> Doc -> Doc -> Property
Packit 3fa651
equalDocs f w d1 d2 = Doc.renderPretty f w d1
Packit 3fa651
                  === Doc.renderPretty f w d2
Packit 3fa651
Packit 3fa651
prop_listToChunk_1 :: [String] -> Property
Packit 3fa651
prop_listToChunk_1 xs = isEmpty (listToChunk xs) === null xs
Packit 3fa651
Packit 3fa651
prop_listToChunk_2 :: [String] -> Property
Packit 3fa651
prop_listToChunk_2 xs = listToChunk xs === mconcat (fmap pure xs)
Packit 3fa651
Packit 3fa651
prop_extractChunk_1 :: String -> Property
Packit 3fa651
prop_extractChunk_1 x = extractChunk (pure x) === x
Packit 3fa651
Packit 3fa651
prop_extractChunk_2 :: Chunk String -> Property
Packit 3fa651
prop_extractChunk_2 x = extractChunk (fmap pure x) === x
Packit 3fa651
Packit 3fa651
prop_stringChunk_1 :: Positive Float -> Positive Int -> String -> Property
Packit 3fa651
prop_stringChunk_1 (Positive f) (Positive w) s =
Packit 3fa651
  equalDocs f w (extractChunk (stringChunk s))
Packit 3fa651
                (Doc.string s)
Packit 3fa651
Packit 3fa651
prop_stringChunk_2 :: String -> Property
Packit 3fa651
prop_stringChunk_2 s = isEmpty (stringChunk s) === null s
Packit 3fa651
Packit 3fa651
prop_paragraph :: String -> Property
Packit 3fa651
prop_paragraph s = isEmpty (paragraph s) === null (words s)
Packit 3fa651
Packit 3fa651
---
Packit 3fa651
Packit 3fa651
--
Packit 3fa651
-- From
Packit 3fa651
-- https://en.wikipedia.org/wiki/Damerau%E2%80%93Levenshtein_distance
Packit 3fa651
--
Packit 3fa651
-- In information theory and computer science, the Damerau–Levenshtein
Packit 3fa651
-- distance is a distance (string metric) between two strings, i.e.,
Packit 3fa651
-- finite sequence of symbols, given by counting the minimum number
Packit 3fa651
-- of operations needed to transform one string into the other, where
Packit 3fa651
-- an operation is defined as an insertion, deletion, or substitution
Packit 3fa651
-- of a single character, or a transposition of two adjacent characters.
Packit 3fa651
--
Packit 3fa651
prop_edit_distance_gezero :: String -> String -> Bool
Packit 3fa651
prop_edit_distance_gezero a b = editDistance a b >= 0
Packit 3fa651
Packit 3fa651
prop_edit_insertion :: [Char] -> Char -> [Char] -> Property
Packit 3fa651
prop_edit_insertion as i bs =
Packit 3fa651
  editDistance (as ++ bs) (as ++ [i] ++ bs) === 1
Packit 3fa651
Packit 3fa651
prop_edit_symmetric :: [Char] -> [Char] -> Property
Packit 3fa651
prop_edit_symmetric as bs =
Packit 3fa651
  editDistance as bs === editDistance bs as
Packit 3fa651
Packit 3fa651
prop_edit_substitution :: [Char] -> [Char] -> Char -> Char -> Property
Packit 3fa651
prop_edit_substitution as bs a b = a /= b ==>
Packit 3fa651
  editDistance (as ++ [a] ++ bs) (as ++ [b] ++ bs) === 1
Packit 3fa651
Packit 3fa651
prop_edit_transposition :: [Char] -> [Char] -> Char -> Char -> Property
Packit 3fa651
prop_edit_transposition as bs a b = a /= b ==>
Packit 3fa651
  editDistance (as ++ [a] ++ [b] ++ bs) (as ++ [b] ++ [a] ++ bs) === 1
Packit 3fa651
Packit 3fa651
---
Packit 3fa651
Packit 3fa651
return []
Packit 3fa651
main :: IO ()
Packit 3fa651
main = do
Packit 3fa651
  result <- $(quickCheckAll)
Packit 3fa651
  unless result exitFailure