{-# LANGUAGE GeneralizedNewtypeDeriving, PatternGuards, DeriveDataTypeable #-} -- | Golden test management module Test.Tasty.Golden.Manage ( -- * Command line helpers defaultMain , defaultMainWithRunner , goldenManagerParser -- * Programmatic API , acceptGoldenTests ) where import Test.Tasty hiding (defaultMainWithRunner, defaultMain) import Test.Tasty.Runners hiding (defaultMainWithRunner) import Test.Tasty.Options import Test.Tasty.Golden.Internal import Data.Maybe import Data.Typeable import Control.Monad.Cont import Text.Printf import Options.Applicative import System.Exit -- | Parse possible management commands. Fail (as a parser) if no -- management commands are given. goldenManagerParser :: Parser (OptionSet -> TestTree -> IO ()) goldenManagerParser = flag' acceptGoldenTests ( long "accept" <> help "Accept current results of golden tests" ) -- | Parse the command line arguments and run the tests using the provided -- runner. -- -- If any golden test management commands are specified, execute them -- instead. -- -- Note: this is a replacement for "Test.Tasty"'s 'defaultMainWithRunner' -- and has a name conflict with it. You'll need to use @hiding@ or -- a similar means to resolve this. defaultMainWithRunner :: Runner -> TestTree -> IO () defaultMainWithRunner runner testTree = do let runTests opts = execRunner runner opts testTree >>= \ok -> if ok then exitSuccess else exitFailure optsParser = treeOptionParser testTree -- partially apply goldenManagerParser to testTree mgmntParser :: Parser (OptionSet -> IO ()) mgmntParser = (\mgr opts -> mgr opts testTree) <$> goldenManagerParser parser = (mgmntParser <|> pure runTests) <*> optsParser join $ execParser $ info (helper <*> parser) ( fullDesc <> header "Mmm... tasty test suite (with golden test management capabilities)" ) -- | Parse the command line arguments and run the tests using the standard -- console runner. -- -- If any golden test management commands are specified, execute them -- instead. -- -- Note: this is a replacement for "Test.Tasty"'s 'defaultMain' -- and has a name conflict with it. You'll need to use @hiding@ or -- a similar means to resolve this. defaultMain :: TestTree -> IO () defaultMain = defaultMainWithRunner runUI -- | Get the list of all golden tests in a given test tree getGoldenTests :: OptionSet -> TestTree -> [(TestName, Golden)] getGoldenTests = foldTestTree (\_ name t -> fmap ((,) name) $ maybeToList $ cast t) (const id) -- | «Accept» a golden test, i.e. reset the golden value to the currently -- produced value acceptGoldenTest :: Golden -> IO () acceptGoldenTest (Golden _ getTested _ update) = vgRun $ liftIO . update =<< getTested -- | Accept all golden tests in the test tree acceptGoldenTests :: OptionSet -> TestTree -> IO () acceptGoldenTests opts tests = do let gs = getGoldenTests opts tests forM_ gs $ \(n,g) -> do acceptGoldenTest g printf "Accepted %s\n" n