packages feed

tasty-coverage 0.1.1.0 → 0.1.2.0

raw patch · 4 files changed

+129/−49 lines, 4 filesdep ~tastyPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: tasty

API changes (from Hackage documentation)

+ Test.Tasty.CoverageReporter: instance Test.Tasty.Options.IsOption Test.Tasty.CoverageReporter.TixDir

Files

CHANGELOG.md view
@@ -1,5 +1,10 @@ # Revision history for tasty-test +## 0.1.2.0 -- 2023-09-10++* Add compatibility with Tasty 1.5+* Add `--tix-dir` flag for specifying directory for tix files.+ ## 0.1.1.0 -- 2023-09-07  * Be more specific with the file suffixes which are computed from the test outcome. Previously only "PASSED" and "FAILED" were used. We now also use "EXCEPTION", "TIMEOUT" and "SKIPPED".
+ CONTRIBUTING.md view
@@ -0,0 +1,33 @@+Thanks for contributing to `tasty-coverage`. Issues, feature requests and pull requests are always welcome :)++# Code style++The code must be formatted using the `fourmolu` code formatter. See install instructions on their [website](https://github.com/fourmolu/fourmolu).+The following command should work:++```console+> fourmolu --mode inplace $(git ls-files '*.hs')+```++# Keeping a changelog++Any nontrivial change must be recorded in the CHANGELOG.md before the pull-request is merged.+We follow the [keepachangelog.com](https://keepachangelog.com/en/1.1.0/) standard.+Before a new version is released on Hackage, the changes are collected in the `Unreleased` section of the changelog.++# Releasing to Hackage++There is one difficulty which prevents us from releasing the package "as-is" to Hackage.+The testsuite requires the `tasty-coverage-example` to be compiled with the `-fhpc` option, since we test that during execution+the correct .tix files are generated. But hard-coding the `-fhpc` flag in the cabal file is an error according to `cabal check`+and Hackage won't let us upload the package. Therefore, the `create-sdist.sh` script removes the testsuite section from the cabal+file before `cabal sdist` is invoked.++# Release checklist++- Bump the version in the cabal file.+- Create a [git tag](https://git-scm.com/book/en/v2/Git-Basics-Tagging) for the new version and push it.+  Use `git tag -a x.x.x.x -m "Version x.x.x.x"` and then `git push origin x.x.x.x`+- Replace the `Unreleased` part of the `CHANGELOG.md` with the current date and the new version.+- Create a candidate on Hackage and check that everything is correct before releasing.+
src/Test/Tasty/CoverageReporter.hs view
@@ -1,30 +1,43 @@-{-# LANGUAGE InstanceSigs, NamedFieldPuns #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE InstanceSigs #-}+{-# LANGUAGE NamedFieldPuns #-}++-- |+-- Module         : Test.Tasty.CoverageReporter+-- Description    : Ingredient for producing per-test coverage reports+--+-- This module provides an ingredient for the tasty framework which allows+-- to generate one coverage file per individual test. module Test.Tasty.CoverageReporter (coverageReporter) where +import Control.Monad (forM_)+import Data.Bifunctor (first)+import Data.Foldable (fold)+import Data.List.NonEmpty (NonEmpty)+import qualified Data.List.NonEmpty as NE+import Data.Typeable+import System.FilePath ((<.>), (</>)) import Test.Tasty import Test.Tasty.Ingredients import Test.Tasty.Options-import Test.Tasty.Runners import Test.Tasty.Providers-import Data.Typeable-import Trace.Hpc.Reflect ( clearTix, examineTix )-import Trace.Hpc.Tix ( writeTix, Tix(..), TixModule(..) )-import System.FilePath ( (<.>), (</>) )-import Control.Monad (forM_)-import qualified Data.List.NonEmpty as NE-import Data.List.NonEmpty ( NonEmpty )-import Data.Foldable (fold)-import Data.Bifunctor (first)+import Test.Tasty.Runners+import Trace.Hpc.Reflect (clearTix, examineTix)+import Trace.Hpc.Tix (Tix (..), TixModule (..), writeTix) +-------------------------------------------------------------------------------+-- Options+-------------------------------------------------------------------------------+ newtype ReportCoverage = MkReportCoverage Bool   deriving (Eq, Ord, Typeable)  instance IsOption ReportCoverage where-    defaultValue  = MkReportCoverage False-    parseValue = fmap MkReportCoverage . safeReadBool-    optionName = pure "report-coverage"-    optionHelp = pure "Generate per-test coverage data"-    optionCLParser = mkFlagCLParser mempty (MkReportCoverage True)+  defaultValue = MkReportCoverage False+  parseValue = fmap MkReportCoverage . safeReadBool+  optionName = pure "report-coverage"+  optionHelp = pure "Generate per-test coverage data"+  optionCLParser = mkFlagCLParser mempty (MkReportCoverage True)  newtype RemoveTixHash = MkRemoveTixHash Bool   deriving (Eq, Ord, Typeable)@@ -36,41 +49,61 @@   optionHelp = pure "Remove hash from tix file (used for golden tests)"   optionCLParser = mkFlagCLParser mempty (MkRemoveTixHash True) -coverageOptions :: [OptionDescription]-coverageOptions = [ Option (Proxy :: Proxy ReportCoverage)-                  , Option (Proxy :: Proxy RemoveTixHash)-                  ]+newtype TixDir = MkTixDir FilePath +instance IsOption TixDir where+  defaultValue = MkTixDir "tix"+  parseValue str = Just (MkTixDir str)+  optionName = pure "tix-dir"+  optionHelp = pure "Specify directory for generated tix files"+  showDefaultValue (MkTixDir dir) = Just dir -tixDir :: FilePath-tixDir = "tix"+coverageOptions :: [OptionDescription]+coverageOptions =+  [ Option (Proxy :: Proxy ReportCoverage),+    Option (Proxy :: Proxy RemoveTixHash),+    Option (Proxy :: Proxy TixDir)+  ] +-------------------------------------------------------------------------------+-- coverageReporter Ingredient+-------------------------------------------------------------------------------+ -- | Obtain the list of all tests in the suite testNames :: OptionSet -> TestTree -> IO ()-testNames  os tree = forM_ (foldTestTree coverageFold os tree) $ \(s,f) -> f (fold (NE.intersperse "." s))+testNames os tree = forM_ (foldTestTree coverageFold os tree) $ \(s, f) -> f (fold (NE.intersperse "." s)) +type FoldResult = [(NonEmpty TestName, String -> IO ())] +#if MIN_VERSION_tasty(1,5,0)+groupFold :: OptionSet -> TestName -> [FoldResult] -> FoldResult+groupFold _ groupName acc = fmap (first (NE.cons groupName)) (concat acc)+#else+groupFold :: OptionSet -> TestName -> FoldResult -> FoldResult+groupFold _ groupName acc = fmap (first (NE.cons groupName)) acc+#endif  -- | Collect all tests and-coverageFold :: TreeFold [(NonEmpty TestName, String -> IO ())]-coverageFold = trivialFold-       { foldSingle = \opts name test -> do-          let f n = do-                -- Collect the coverage data for exactly this test.-                clearTix-                result <- run opts test (\_ -> pure ())-                tix <- examineTix-                let filepath = tixFilePath n result-                writeTix filepath (removeHash opts tix)-                putStrLn ("Wrote coverage file: " <> filepath)-          pure (NE.singleton name, f),-          -- Append the name of the testgroup to the list of TestNames-          foldGroup = \_ groupName acc -> fmap (first (NE.cons groupName)) acc-        }+coverageFold :: TreeFold FoldResult+coverageFold =+  trivialFold+    { foldSingle = \opts name test -> do+        let f n = do+              -- Collect the coverage data for exactly this test.+              clearTix+              result <- run opts test (\_ -> pure ())+              tix <- examineTix+              let filepath = tixFilePath opts n result+              writeTix filepath (removeHash opts tix)+              putStrLn ("Wrote coverage file: " <> filepath)+        pure (NE.singleton name, f),+      -- Append the name of the testgroup to the list of TestNames+      foldGroup = groupFold+    } -tixFilePath :: TestName -> Result -> FilePath-tixFilePath tn Result { resultOutcome }  =-  tixDir </> generateValidFilepath tn <.> outcomeSuffix resultOutcome <.> ".tix"+tixFilePath :: OptionSet -> TestName -> Result -> FilePath+tixFilePath opts tn Result {resultOutcome} = case lookupOption opts of+  MkTixDir tixDir -> tixDir </> generateValidFilepath tn <.> outcomeSuffix resultOutcome <.> ".tix"  -- | We want to compute the file suffix that we use to distinguish -- tix files for failing and succeeding tests.@@ -81,10 +114,15 @@ outcomeSuffix (Failure (TestTimedOut _)) = "TIMEOUT" outcomeSuffix (Failure TestDepFailed) = "SKIPPED" +-- | This ingredient implements its own test-runner which can be executed with+-- the @--report-coverage@ command line option.+-- The testrunner executes the tests sequentially and emits one coverage file+-- per executed test.+--+-- @since 0.1.0.0 coverageReporter :: Ingredient coverageReporter = TestManager coverageOptions coverageRunner - coverageRunner :: OptionSet -> TestTree -> Maybe (IO Bool) coverageRunner opts tree = case lookupOption opts of   MkReportCoverage False -> Nothing@@ -101,8 +139,8 @@   where     -- Include both Windows and Posix, so that generated .tix files     -- are consistent among systems.-    pathSeparators = ['\\','/']-  +    pathSeparators = ['\\', '/']+ removeHash :: OptionSet -> Tix -> Tix removeHash opts (Tix txs) = case lookupOption opts of   MkRemoveTixHash False -> Tix txs@@ -110,4 +148,3 @@  removeHashModule :: TixModule -> TixModule removeHashModule (TixModule name _hash i is) = TixModule name 0 i is-
tasty-coverage.cabal view
@@ -1,6 +1,6 @@ cabal-version:   3.0 name:            tasty-coverage-version:         0.1.1.0+version:         0.1.2.0 license:         BSD-3-Clause license-file:    LICENSE copyright:       David Binder, 2023@@ -20,21 +20,26 @@ build-type:      Simple extra-doc-files:     CHANGELOG.md+    CONTRIBUTING.md     README.md  source-repository head     type:     git     location: git@github.com:BinderDavid/tasty-coverage.git +common deps+    build-depends:+        base >=4.16 && <4.20,+        tasty >= 1.4 && < 1.6+ library+    import:           deps     exposed-modules:  Test.Tasty.CoverageReporter     hs-source-dirs:   src     default-language: Haskell2010     ghc-options:      -Wall     build-depends:-        base >=4.16 && <4.20,         filepath >=1.3.8 && <=1.5,-        tasty ^>=1.4,         hpc >=0.6 && <0.8,-        +