tasty-discover 3.0.2 → 4.0.0
raw patch · 11 files changed
+314/−158 lines, 11 filesdep +Globdep +hedgehogdep +tasty-hedgehogPVP ok
version bump matches the API change (PVP)
Dependencies added: Glob, hedgehog, tasty-hedgehog
API changes (from Hackage documentation)
- Test.Tasty.Discover: addSuffixes :: [String] -> [String]
- Test.Tasty.Discover: extractTests :: FilePath -> String -> [Test]
- Test.Tasty.Discover: filesBySuffix :: FilePath -> [String] -> IO [FilePath]
- Test.Tasty.Discover: ingredientImport :: String -> String
- Test.Tasty.Discover: ingredients :: [String] -> String
- Test.Tasty.Discover: isHidden :: FilePath -> Bool
- Test.Tasty.Discover: isIgnored :: [FilePath] -> String -> Bool
- Test.Tasty.Discover: showImports :: [String] -> String
- Test.Tasty.Discover: showModuleTree :: ModuleTree -> [String]
- Test.Tasty.Discover: testFileSuffixes :: Config -> [String]
+ Test.Tasty.Config: [ignores] :: Config -> Maybe GlobPattern
+ Test.Tasty.Config: [modules] :: Config -> Maybe GlobPattern
+ Test.Tasty.Config: type GlobPattern = String
- Test.Tasty.Config: Config :: Maybe String -> Maybe String -> [FilePath] -> [Ingredient] -> Bool -> Bool -> Bool -> Config
+ Test.Tasty.Config: Config :: Maybe GlobPattern -> Maybe String -> Maybe String -> Maybe GlobPattern -> [FilePath] -> [Ingredient] -> Bool -> Bool -> Bool -> Config
Files
- CHANGELOG.md +14/−0
- README.md +90/−31
- executable/Main.hs +1/−0
- library/Test/Tasty/Config.hs +69/−21
- library/Test/Tasty/Discover.hs +39/−41
- library/Test/Tasty/Generator.hs +48/−31
- tasty-discover.cabal +10/−3
- test/ConfigTest.hs +33/−30
- test/DiscoverTest.hs +9/−0
- test/Driver.hs +1/−0
- test/Tasty.hs +0/−1
CHANGELOG.md view
@@ -8,6 +8,20 @@ [Keep a Changelog]: http://keepachangelog.com/ [Semantic Versioning]: http://semver.org/ +# 4.0.0 [2017-09-01]++## Changed+- Deprecated `--[no-]module-suffix` for `--modules` (see pull request [#117]).+- Deprecated `--ignore-module` for `--ignores` (see pull request [#117]).++## Added+- `tasty-hedgehog` is now a supported test library.++## Removed+- `unit_` prefixes have been removed.++[#117]: https://github.com/lwm/tasty-discover/pull/117+ # 3.0.2 [2017-06-05] ### Fixed
README.md view
@@ -11,24 +11,73 @@ # Getting Started -5 steps to tasty test discovery satori:- - Create a `Tasty.hs` in the `hs-source-dirs` of your test suite.- - Set your test suite `main-is` to the `Tasty.hs`.- - Create test modules in files with suffix `*Test.hs` or `*Spec.hs`.- - Write your tests with the following prefixes:- - `prop_`: [QuickCheck](http://hackage.haskell.org/package/tasty-quickcheck) properties.- - `scprop_`: [SmallCheck](http://hackage.haskell.org/package/tasty-smallcheck) properties.- - `unit_`: [HUnit](http://hackage.haskell.org/package/tasty-hunit) test cases.- - `spec_`: [Hspec](http://hackage.haskell.org/package/tasty-hspec) specifications.- - `test_`: [Tasty](http://hackage.haskell.org/package/tasty) TestTrees.+There's 4 simple steps: -# Examples+ 1. [Create a test driver file in the test directory](#create-test-driver-file)+ 2. [Mark the driver file as the `main-is` in the test suite](#configure-cabal-test-suite)+ 3. [Mark tests with the correct prefixes](#write-tests)+ 4. [Customise test discovery as needed](#customise-discovery) +Check out the [example project](#example-project) to get moving quickly.++## Create Test Driver File++You can name this file anything you want but it must contain the correct+preprocessor definition for tasty-discover to run and also, to detect the+configuration. It should be in the top level of the test directory.++For example (in `test/Driver.hs`):++```+{-# OPTIONS_GHC -F -pgmF tasty-discover #-}+```++## Configure Cabal Test Suite++In order for Cabal/Stack to know where the tests are, you'll need to configure+the main-is option of your test-suite to point to that file. In the following+example, the test driver file is called Driver.hs:++```+test-suite test+ main-is: Driver.hs+ hs-source-dirs: tests+ build-depends: base+```++If you use [hpack], that might look like:++[hpack]: https://github.com/sol/hpack++``` yaml+tests:+ test:+ main: "Driver.hs"+ source-dirs: "test"+ dependencies:+ - "base"+```++# Write Tests++Create test modules and correctly prefix the tests with the name that+corresponds to the testing library you wish to run the test with:++ - **prop_**: [QuickCheck](http://hackage.haskell.org/package/tasty-quickcheck) properties.+ - **scprop_**: [SmallCheck](http://hackage.haskell.org/package/tasty-smallcheck) properties.+ - **hprop_**: [Hedgehog](http://hackage.haskell.org/package/tasty-hedgehog) properties.+ - **unit_**: [HUnit](http://hackage.haskell.org/package/tasty-hunit) test cases.+ - **spec_**: [Hspec](http://hackage.haskell.org/package/tasty-hspec) specifications.+ - **test_**: [Tasty](http://hackage.haskell.org/package/tasty) TestTrees.++Here's an example test module:+ ``` haskell {-# LANGUAGE ScopedTypeVariables #-} module ExampleTest where +import Data.List import Test.Tasty import Test.Tasty.HUnit import Test.Tasty.Hspec@@ -70,43 +119,53 @@ pure $ map (\s -> testCase s $ pure ()) inputs ``` -# Configuration--Pass configuration options within your `Tasty.hs` like so:+# Customise Discovery -``` haskell-{-#- OPTIONS_GHC -F -pgmF tasty-discover- -optF <OPTION>- -optF <OPTION>- -- etc.-#-}-```+You configure tasty-discover by passing options to the test driver file. ## No Arguments+ Example: `{-# OPTIONS_GHC -F -pgmF tasty-discover -optF --debug #-}` - - `--no-module-suffix`: Collect all test modules, regardless of module suffix.- - `--debug`: Output the contents of the generated module while testing.- - `--tree-display`: Display the test output results hierarchically.+ - **--debug**: Output the contents of the generated module while testing.+ - **--tree-display**: Display the test output results hierarchically. ## With Arguments-Example: `{-# OPTIONS_GHC -F -pgmF tasty-discover -optF --module-suffix=FooBar #-}` - - `--module-suffix`: Which test module suffix you wish to have discovered.- - `--generated-module`: The name of the generated test module.- - `--ignore-module`: Which test modules to ignore from discovery.- - `--ingredient`: Tasty ingredients to add to your test runner.+Example: `{-# OPTIONS_GHC -F -pgmF tasty-discover -optF --modules="*CustomTest.hs" #-}` + - **--modules**: Which test modules to discover (with glob pattern).+ - **--ignores**: Which test modules to ignore (with glob pattern).+ - **--generated-module**: The name of the generated test module.+ - **--ingredient**: Tasty ingredients to add to your test runner.++# Example Project++See the [testing for this package] for a fully configured example.++[testing for this package]: https://github.com/lwm/tasty-discover/tree/master/test+ # Change Log-See the [change log] for the latest changes. +Please see the [CHANGELOG.md] for the latest changes.++[CHANGELOG.md]: https://github.com/lwm/tasty-discover/blob/master/CHANGELOG.md++# Deprecation Policy++If a breaking change is implemented, you'll see a major version increase, an+entry in the [change log] and a compile time error with a deprecation warning+and clear instructions on how to upgrade. Please do complain if we're doing+this too much.+ [change log]: https://github.com/lwm/tasty-discover/blob/master/CHANGELOG.md # Contributing+ All contributions welcome! # Acknowledgements+ Thanks to [hspec-discover] and [tasty-auto] for making this possible. [hspec-discover]: https://hspec.github.io/hspec-discover.html
executable/Main.hs view
@@ -1,4 +1,5 @@ -- | Main executable module.+ module Main where import Control.Monad (when)
library/Test/Tasty/Config.hs view
@@ -1,7 +1,17 @@--- Configuration options module.-module Test.Tasty.Config- ( Config(..)+-- | The test driver configuration options module.+--+-- Anything that can be passed as an argument to the test driver+-- definition exists as a field in the 'Config' type.++module Test.Tasty.Config (+ -- * Configuration Options+ Config (..)+ , GlobPattern++ -- * Configuration Parser , parseConfig++ -- * Configuration Defaults , defaultConfig ) where @@ -10,32 +20,64 @@ ArgOrder (Permute), OptDescr (Option), getOpt) +-- | A tasty ingredient. type Ingredient = String +-- | A glob pattern.+type GlobPattern = String++-- | The discovery and runner configuration. data Config = Config- { moduleSuffix :: Maybe String- , generatedModuleName :: Maybe String- , ignoredModules :: [FilePath]- , tastyIngredients :: [Ingredient]- , noModuleSuffix :: Bool- , debug :: Bool- , treeDisplay :: Bool+ { modules :: Maybe GlobPattern -- ^ Glob pattern for matching modules during test discovery.+ , moduleSuffix :: Maybe String -- ^ <<<DEPRECATED>>>: Module suffix.+ , generatedModuleName :: Maybe String -- ^ Name of the generated main module.+ , ignores :: Maybe GlobPattern -- ^ Glob pattern for ignoring modules during test discovery.+ , ignoredModules :: [FilePath] -- ^ <<<DEPRECATED>>>: Ignored modules by full name.+ , tastyIngredients :: [Ingredient] -- ^ Tasty ingredients to use.+ , noModuleSuffix :: Bool -- ^ <<<DEPRECATED>>>: suffix and look in all modules.+ , debug :: Bool -- ^ Debug the generated module.+ , treeDisplay :: Bool -- ^ Tree display for the test results table. } deriving (Show) -- | The default configuration defaultConfig :: Config-defaultConfig = Config Nothing Nothing [] [] False False False+defaultConfig = Config Nothing Nothing Nothing Nothing [] [] False False False +-- | Deprecation message for old `--[no-]module-suffix` option.+moduleSuffixDeprecationMessage :: String+moduleSuffixDeprecationMessage =+ error $ concat+ [ "\n\n"+ , "----------------------------------------------------------\n"+ , "DEPRECATION NOTICE: `--[no-]module-suffix` is deprecated.\n"+ , "The default behaviour now discovers all test module suffixes.\n"+ , "Please use the `--modules='<glob-pattern>'` option to specify.\n"+ , "----------------------------------------------------------\n"+ ]++-- | Deprecation message for old `--ignore-module` option.+ignoreModuleDeprecationMessage :: String+ignoreModuleDeprecationMessage =+ error $ concat+ [ "\n\n"+ , "----------------------------------------------------------\n"+ , "DEPRECATION NOTICE: `--ignore-module` is deprecated.\n"+ , "Please use the `--ignores='<glob-pattern>'` option instead.\n"+ , "----------------------------------------------------------\n"+ ]+ -- | Configuration options parser. parseConfig :: String -> [String] -> Either String Config parseConfig prog args = case getOpt Permute options args of (opts, [], []) ->- let config = foldl (flip id) defaultConfig opts- errorMsg = "You cannot combine '--no-module-suffix' and '--module-suffix'\n"- in- if noModuleSuffix config && isJust (moduleSuffix config)- then formatError errorMsg- else Right config+ let config = foldl (flip id) defaultConfig opts in+ if noModuleSuffix config || isJust (moduleSuffix config) then+ error moduleSuffixDeprecationMessage+ else+ if not $ null (ignoredModules config) then+ error ignoreModuleDeprecationMessage+ else+ Right config (_, _, err:_) -> formatError err (_, arg:_, _) -> formatError ("unexpected argument `" ++ arg ++ "`\n") where@@ -44,21 +86,27 @@ -- | All configuration options. options :: [OptDescr (Config -> Config)] options = [- Option [] ["module-suffix"]+ Option [] ["modules"]+ (ReqArg (\s c -> c {modules = Just s}) "GLOB-PATTERN")+ "Specify desired modules with a glob pattern (white-list)"+ , Option [] ["module-suffix"] (ReqArg (\s c -> c {moduleSuffix = Just s}) "SUFFIX")- "Specify desired test module suffix"+ "<<<DEPRECATED>>>: Specify desired test module suffix" , Option [] ["generated-module"] (ReqArg (\s c -> c {generatedModuleName = Just s}) "MODULE") "Qualified generated module name"+ , Option [] ["ignores"]+ (ReqArg (\s c -> c {ignores = Just s}) "GLOB-PATTERN")+ "Specify desired modules to ignore with a glob pattern (black-list)" , Option [] ["ignore-module"] (ReqArg (\s c -> c {ignoredModules = s : ignoredModules c}) "FILE")- "Ignore a test module"+ "<<<DEPRECATED>>>: Ignore a test module" , Option [] ["ingredient"] (ReqArg (\s c -> c {tastyIngredients = s : tastyIngredients c}) "INGREDIENT") "Qualified tasty ingredient name" , Option [] ["no-module-suffix"] (NoArg $ \c -> c {noModuleSuffix = True})- "Ignore test module suffix and import them all"+ "<<<DEPRECATED>>>: Ignore test module suffix and import them all" , Option [] ["debug"] (NoArg $ \c -> c {debug = True}) "Debug output of generated test module"
library/Test/Tasty/Discover.hs view
@@ -1,16 +1,28 @@ -- | Automatic test discovery and runner for the tasty framework.-module Test.Tasty.Discover where +module Test.Tasty.Discover (+ -- * Main Test Generator+ generateTestDriver++ -- * For Testing Purposes Only+ , ModuleTree (..)+ , findTests+ , mkModuleTree+ , showTests+ ) where+ import Data.List (dropWhileEnd, intercalate, isPrefixOf,- isSuffixOf, nub)+ nub) import qualified Data.Map.Strict as M-import Data.Traversable (for)-import System.Directory (doesDirectoryExist, getDirectoryContents)-import System.FilePath (takeDirectory, (</>))-import Test.Tasty.Config (Config (..))+import Data.Maybe (fromMaybe)+import System.FilePath (takeDirectory, takeFileName, (</>))+import System.FilePath.Glob (compile, globDir1, match)+import Test.Tasty.Config (Config (..), GlobPattern) import Test.Tasty.Generator (Generator (..), Test (..), generators, getGenerators, mkTest, showSetup) +-- | Main function generator, along with all the boilerplate which+-- which will run the discovered tests. generateTestDriver :: Config -> String -> [String] -> FilePath -> [Test] -> String generateTestDriver config modname is src tests = let generators' = getGenerators tests@@ -40,38 +52,29 @@ ] ] -addSuffixes :: [String] -> [String]-addSuffixes modules = (++) <$> modules <*> [".lhs", ".hs"]--isHidden :: FilePath -> Bool-isHidden filename = head filename /= '.'--filesBySuffix :: FilePath -> [String] -> IO [FilePath]-filesBySuffix dir suffixes = do- entries <- filter isHidden <$> getDirectoryContents dir- fmap concat $ for entries $ \entry -> do- let dir' = dir </> entry- dirExists <- doesDirectoryExist dir'- if dirExists then- map (entry </>) <$> filesBySuffix dir' suffixes- else if any (`isSuffixOf` entry) suffixes then- pure [entry]- else- pure []+-- | Match files by specified glob pattern.+filesByModuleGlob :: FilePath -> Maybe GlobPattern -> IO [String]+filesByModuleGlob directory globPattern = do+ (fmap takeFileName) <$> globDir1 pattern directory+ where pattern = compile (fromMaybe "*.hs*" globPattern) -isIgnored :: [FilePath] -> String -> Bool-isIgnored ignores filename = filename `notElem` addSuffixes ignores+-- | Filter and remove files by specified glob pattern.+ignoreByModuleGlob :: [FilePath] -> Maybe GlobPattern -> [FilePath]+ignoreByModuleGlob directories ignoreGlob = filter (not . match pattern) directories+ where pattern = compile (fromMaybe "" ignoreGlob) +-- | Discover the tests modules. findTests :: FilePath -> Config -> IO [Test] findTests src config = do- let dir = takeDirectory src- suffixes = testFileSuffixes config- ignores = ignoredModules config- files <- filter (isIgnored ignores) <$> filesBySuffix dir suffixes- concat <$> traverse (extract dir) files+ let directory = takeDirectory src+ allModules <- filesByModuleGlob directory (modules config)+ let filtered = ignoreByModuleGlob allModules (ignores config)+ concat <$> traverse (extract directory) filtered where- extract dir file = extractTests file <$> readFile (dir </> file)+ extract directory file = do+ extractTests file <$> readFile (directory </> file) +-- | Extract the test names from discovered modules. extractTests :: FilePath -> String -> [Test] extractTests file = mkTestDeDuped . isKnownPrefix . parseTest where@@ -80,24 +83,19 @@ checkPrefix g = (`isPrefixOf` g) . generatorPrefix parseTest = map fst . concatMap lex . lines -testFileSuffixes :: Config -> [String]-testFileSuffixes config = if noModuleSuffix config- then [""]- else addSuffixes suffixes- where- suffixes = case moduleSuffix config of- Just suffix' -> [suffix']- Nothing -> ["Spec", "Test"]-+-- | Show the imports. showImports :: [String] -> String showImports mods = unlines $ nub $ map (\m -> "import qualified " ++ m ++ "\n") mods +-- | Retrieve the ingredient name. ingredientImport :: String -> String ingredientImport = init . dropWhileEnd (/= '.') +-- | Ingredients to be included. ingredients :: [String] -> String ingredients is = concat $ map (++":") is ++ ["T.defaultIngredients"] +-- | Show the tests. showTests :: Config -> [Test] -> [String] -> [String] showTests config tests testNumVars = if treeDisplay config then showModuleTree $ mkModuleTree tests testNumVars
library/Test/Tasty/Generator.hs view
@@ -1,11 +1,26 @@+-- | The test generator boilerplate module.+--+-- Any test that is supported (HUnit, HSpec, etc.) provides here, a+-- generator type with all the context necessary for outputting the+-- necessary boilerplate for the generated main function that will+-- run all the tests.+ module Test.Tasty.Generator- ( Generator(..)+ (+ -- * Types+ Generator (..)+ , Test (..)++ -- * Generators , generators- , showSetup , getGenerator , getGenerators- , Test(..)- , mkTest,++ -- * Boilerplate Formatter+ , showSetup++ -- * Type Constructor+ , mkTest ) where import Data.Function (on)@@ -13,33 +28,40 @@ import Data.Maybe (fromJust) import System.FilePath (dropExtension, pathSeparator) +-- | The test type. data Test = Test- { testModule :: String- , testFunction :: String+ { testModule :: String -- ^ Module name.+ , testFunction :: String -- ^ Function name. } deriving (Eq, Show) +-- | 'Test' constructor. mkTest :: FilePath -> String -> Test mkTest = Test . chooser pathSeparator '.' . dropExtension where chooser c1 c2 = map $ \c3 -> if c3 == c1 then c2 else c3 +-- | The generator type. data Generator = Generator- { generatorPrefix :: String- , generatorImport :: String- , generatorClass :: String- , generatorSetup :: Test -> String+ { generatorPrefix :: String -- ^ Generator prefix.+ , generatorImport :: String -- ^ Module import path.+ , generatorClass :: String -- ^ Generator class.+ , generatorSetup :: Test -> String -- ^ Generator setup. } +-- | Module import qualifier. qualifyFunction :: Test -> String qualifyFunction t = testModule t ++ "." ++ testFunction t +-- | Function namer. name :: Test -> String name = chooser '_' ' ' . tail . dropWhile (/= '_') . testFunction where chooser c1 c2 = map $ \c3 -> if c3 == c1 then c2 else c3 +-- | Generator retriever (single). getGenerator :: Test -> Generator getGenerator t = fromJust $ getPrefix generators where getPrefix = find ((`isPrefixOf` testFunction t) . generatorPrefix) +-- | Generator retriever (many). getGenerators :: [Test] -> [Generator] getGenerators = map head .@@ -47,19 +69,31 @@ sortOn generatorPrefix . map getGenerator +-- | Boilerplate formatter. showSetup :: Test -> String -> String showSetup t var = " " ++ var ++ " <- " ++ setup ++ "\n" where setup = generatorSetup (getGenerator t) t +-- | All types of tests supported for boilerplate generation. generators :: [Generator] generators = [ quickCheckPropertyGenerator- , hunitTestCaseGeneratorDeprecated+ , hedgehogPropertyGenerator , hunitTestCaseGenerator , hspecTestCaseGenerator , tastyTestGroupGenerator ] +-- | Quickcheck group generator prefix.+hedgehogPropertyGenerator :: Generator+hedgehogPropertyGenerator = Generator+ { generatorPrefix = "hprop_"+ , generatorImport = "import qualified Test.Tasty.Hedgehog as H\n"+ , generatorClass = ""+ , generatorSetup = \t -> "pure $ H.testProperty \"" ++ name t ++ "\" " ++ qualifyFunction t+ }++-- | Quickcheck group generator prefix. quickCheckPropertyGenerator :: Generator quickCheckPropertyGenerator = Generator { generatorPrefix = "prop_"@@ -68,26 +102,7 @@ , generatorSetup = \t -> "pure $ QC.testProperty \"" ++ name t ++ "\" " ++ qualifyFunction t } -deprecationMessage :: String-deprecationMessage =- error $ concat- [ "\n\n"- , "----------------------------------------------------------\n"- , "DEPRECATION NOTICE: The `case_` prefix is deprecated.\n"- , "Please use the `unit_` prefix instead.\n"- , "Please see https://github.com/lwm/tasty-discover/issues/95.\n"- , "----------------------------------------------------------\n"- ]---- DEPRECATED: Use `unit_` instead (below)-hunitTestCaseGeneratorDeprecated :: Generator-hunitTestCaseGeneratorDeprecated = Generator- { generatorPrefix = "case_"- , generatorImport = deprecationMessage- , generatorClass = deprecationMessage- , generatorSetup = const deprecationMessage- }-+-- | HUnit generator prefix. hunitTestCaseGenerator :: Generator hunitTestCaseGenerator = Generator { generatorPrefix = "unit_"@@ -101,6 +116,7 @@ , generatorSetup = \t -> "testCase \"" ++ name t ++ "\" " ++ qualifyFunction t } +-- | Hspec generator prefix. hspecTestCaseGenerator :: Generator hspecTestCaseGenerator = Generator { generatorPrefix = "spec_"@@ -109,6 +125,7 @@ , generatorSetup = \t -> "HS.testSpec \"" ++ name t ++ "\" " ++ qualifyFunction t } +-- | Tasty group generator prefix. tastyTestGroupGenerator :: Generator tastyTestGroupGenerator = Generator { generatorPrefix = "test_"
tasty-discover.cabal view
@@ -1,9 +1,9 @@--- This file has been generated from package.yaml by hpack version 0.17.0.+-- This file has been generated from package.yaml by hpack version 0.18.1. -- -- see: https://github.com/sol/hpack name: tasty-discover-version: 3.0.2+version: 4.0.0 synopsis: Test discovery for the tasty framework. description: Automatic test discovery and runner for the tasty framework. Prefix your test case names and tasty-discover will discover, collect and run them. All popular test libraries are covered. Configure once and then just write your tests. Avoid forgetting to add test modules to your Cabal/Hpack files. Tasty ingredients are included along with various configuration options for different use cases. Please see the `README.md` below for how to get started.@@ -36,10 +36,13 @@ , containers >= 0.4 && < 1.0 , directory >= 1.1 && < 2.0 , filepath >= 1.3 && < 2.0+ , Glob >= 0.8 && < 1.0 exposed-modules: Test.Tasty.Config Test.Tasty.Discover Test.Tasty.Generator+ other-modules:+ Paths_tasty_discover default-language: Haskell2010 executable tasty-discover@@ -50,12 +53,13 @@ , containers >= 0.4 && < 1.0 , directory >= 1.1 && < 2.0 , filepath >= 1.3 && < 2.0+ , Glob >= 0.8 && < 1.0 , tasty-discover default-language: Haskell2010 test-suite test type: exitcode-stdio-1.0- main-is: Tasty.hs+ main-is: Driver.hs hs-source-dirs: test ghc-options: -Wall@@ -64,6 +68,7 @@ , containers >= 0.4 && < 1.0 , directory >= 1.1 && < 2.0 , filepath >= 1.3 && < 2.0+ , Glob >= 0.8 && < 1.0 , base , tasty , tasty-discover@@ -71,6 +76,8 @@ , tasty-hunit , tasty-quickcheck , tasty-smallcheck+ , tasty-hedgehog+ , hedgehog other-modules: ConfigTest DiscoverTest
test/ConfigTest.hs view
@@ -1,4 +1,5 @@ {-# OPTIONS_GHC -fno-warn-orphans #-}+ module ConfigTest where import Data.List (isInfixOf)@@ -8,50 +9,52 @@ generateTestDriver, mkModuleTree, showTests) import Test.Tasty.Generator (Test (..), mkTest)+import Test.Tasty.Hspec import Test.Tasty.HUnit import Test.Tasty.QuickCheck -unit_noModuleSuffixEmptyList :: IO ()-unit_noModuleSuffixEmptyList = do- actual <- findTests "test/SubMod/" (defaultConfig { moduleSuffix = Just "DoesntExist"})- actual @?= []--unit_differentGeneratedModule :: Assertion-unit_differentGeneratedModule = assertBool "" ("FunkyModuleName" `isInfixOf` generatedModule)- where generatedModule = generateTestDriver defaultConfig "FunkyModuleName" [] "test/" []--unit_ignoreAModule :: IO ()-unit_ignoreAModule = do- actual <- findTests "test/SubMod/" (defaultConfig { ignoredModules = ["PropTest"] })- actual @?= []+spec_modules :: Spec+spec_modules =+ describe "Test discovery" $+ it "Discovers tests" $ do+ let expectedTest = mkTest "PropTest" "prop_additionAssociative"+ config = defaultConfig { modules = Just "*Test.hs" }+ discoveredTests <- findTests "test/SubMod/" config+ discoveredTests `shouldBe` [expectedTest] -unit_noModuleSuffix :: IO ()-unit_noModuleSuffix = do- actual1 <- findTests "test/SubMod/" defaultConfig- actual1 @?= [mkTest "PropTest" "prop_additionAssociative"]+spec_ignores :: Spec+spec_ignores =+ describe "Module ignore configuration" $+ it "Ignores tests in modules with the specified suffix" $ do+ let ignoreModuleConfig = defaultConfig { ignores = Just "*.hs" }+ discoveredTests <- findTests "test/SubMod/" ignoreModuleConfig+ discoveredTests `shouldBe` [] - actual2 <- findTests "test/SubMod/" (defaultConfig { noModuleSuffix = True })- let expected = [ mkTest "FooBaz" "prop_additionCommutative"- , mkTest "FooBaz" "prop_multiplationDistributiveOverAddition"- , mkTest "PropTest" "prop_additionAssociative" ]- assertBool "" $ all (`elem` expected) actual2+spec_badModuleGlob :: Spec+spec_badModuleGlob =+ describe "Module suffix configuration" $+ it "Filters discovered tests by specified suffix" $ do+ let badGlobConfig = defaultConfig { modules = Just "DoesntExist*.hs" }+ discoveredTests <- findTests "test/SubMod/" badGlobConfig+ discoveredTests `shouldBe` [] -unit_noModuleSuffixRecurseDirs :: IO ()-unit_noModuleSuffixRecurseDirs = do- tests <- findTests "test/" (defaultConfig { noModuleSuffix = True })- assertBool "" $ elem (mkTest "SubMod/FooBaz" "prop_additionCommutative") tests+spec_customModuleName :: Spec+spec_customModuleName =+ describe "Module name configuration" $+ it "Creates a generated main function with the specified name" $ do+ let generatedModule = generateTestDriver defaultConfig "FunkyModuleName" [] "test/" []+ "FunkyModuleName" `shouldSatisfy` (`isInfixOf` generatedModule) unit_noTreeDisplayDefault :: IO () unit_noTreeDisplayDefault = do- let config = defaultConfig { noModuleSuffix = True }- tests <- findTests "test/SubMod/" config+ tests <- findTests "test/SubMod/" defaultConfig let testNumVars = map (('t' :) . show) [(0::Int)..]- trees = showTests config tests testNumVars+ trees = showTests defaultConfig tests testNumVars length trees @?= 3 unit_treeDisplay :: IO () unit_treeDisplay = do- let config = defaultConfig { noModuleSuffix = True, treeDisplay = True }+ let config = defaultConfig { treeDisplay = True } tests <- findTests "test/SubMod/" config let testNumVars = map (('t' :) . show) [(0::Int)..] trees = showTests config tests testNumVars
test/DiscoverTest.hs view
@@ -3,6 +3,9 @@ module DiscoverTest where import Data.List+import qualified Hedgehog as H+import qualified Hedgehog.Gen as Gen+import qualified Hedgehog.Range as Range import Test.Tasty import Test.Tasty.Hspec import Test.Tasty.HUnit@@ -41,3 +44,9 @@ test_generateTrees = do inputs <- pure ["First input", "Second input"] pure $ map (\s -> testCase s $ pure ()) inputs++{-# ANN hprop_reverse "HLint: ignore Avoid reverse" #-}+hprop_reverse :: H.Property+hprop_reverse = H.property $ do+ xs <- H.forAll $ Gen.list (Range.linear 0 100) Gen.alpha+ reverse (reverse xs) H.=== xs
+ test/Driver.hs view
@@ -0,0 +1,1 @@+{-# OPTIONS_GHC -F -pgmF tasty-discover #-}
− test/Tasty.hs
@@ -1,1 +0,0 @@-{-# OPTIONS_GHC -F -pgmF tasty-discover #-}