-- |
-- Module      : Test.FitSpec.Main
-- Copyright   : (c) 2015-2017 Rudy Matela
-- License     : 3-Clause BSD  (see the file LICENSE)
-- Maintainer  : Rudy Matela <rudy@matela.com.br>
--
-- Exports "main" functions for FitSpec.
-- They work exactly by 'report' and 'reportWith' but can be customized by
-- command line arguments.
--
-- > main = mainWith args { ... } functions properties
{-# Language DeriveDataTypeable, StandaloneDeriving #-}
module Test.FitSpec.Main
  ( mainWith
  , defaultMain
  , getArgs
  , getArgsWith
  , module Test.FitSpec.Report -- deprecated export, remove later
  )
where

import Test.FitSpec.Report
import System.Console.CmdArgs hiding (args)
import qualified System.Console.CmdArgs as CA (args)
import Control.Monad (liftM)
import Test.FitSpec.Mutable
import Test.FitSpec.ShowMutable

deriving instance Data ShowMutantAs
deriving instance Data Args
deriving instance Typeable ShowMutantAs
deriving instance Typeable Args

annotate :: Args -> Args
annotate as = Args
  { nMutants     = nMutants     as  &= name "m"
      &= help "(starting) number of function mutations"
  , nTests       = nTests       as  &= name "n"
      &= help "(starting) number of test values (each prop.)"
  , timeout      = timeout      as  &= name "t" &= name "s"
      &= help "timeout in seconds, 0 for just T*M"
  , names        = names        as
      &= ignore
  , rows         = rows         as
      &= help "how many rows of results to show"
  , verbose      = verbose      as
      &= help "activate verbose output"
  , showMutantAs = showMutantAs as  &= name "a"
      &= help "how to show mutants (tuple / nestedtuple / definition / bindings)"
      &= typ  "type"
  , extra        = extra        as  &= CA.args
      &= typ "extra arguments"
  } &= summary "FitSpec"
    &= program "program"
    &= help "Refine property-sets for functional testing"

getArgsWith :: Args -> IO Args
getArgsWith = cmdArgs . annotate

getArgs :: IO Args
getArgs = getArgsWith args

-- | Same as 'reportWith', but allow overriding of configuration via command
--   line arguments.
mainWith :: (Mutable a, ShowMutable a)
         => Args
         -> a -> (a -> [Property]) -> IO ()
mainWith as f ps = do
  as' <- getArgsWith as
  reportWith as' f ps

-- | Same as 'report', but allow configuration via command line arguments.
defaultMain :: (Mutable a, ShowMutable a)
            => a -> (a -> [Property]) -> IO ()
defaultMain = mainWith args