tasty-coverage (empty) → 0.1.0.0
raw patch · 5 files changed
+177/−0 lines, 5 filesdep +basedep +filepathdep +hpc
Dependencies added: base, filepath, hpc, tasty
Files
- CHANGELOG.md +5/−0
- LICENSE +28/−0
- README.md +32/−0
- src/Test/Tasty/CoverageReporter.hs +73/−0
- tasty-coverage.cabal +39/−0
+ CHANGELOG.md view
@@ -0,0 +1,5 @@+# Revision history for tasty-test++## 0.1.0.0 -- 2023-08-07++* Release of first version on Hackage
+ LICENSE view
@@ -0,0 +1,28 @@+BSD 3-Clause License++Copyright (c) 2023, David Binder++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++1. Redistributions of source code must retain the above copyright notice, this+ list of conditions and the following disclaimer.++2. Redistributions in binary form must reproduce the above copyright notice,+ this list of conditions and the following disclaimer in the documentation+ and/or other materials provided with the distribution.++3. Neither the name of the copyright holder nor the names of its+ contributors may be used to endorse or promote products derived from+ this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.md view
@@ -0,0 +1,32 @@+# tasty-coverage++A [tasty](https://hackage.haskell.org/package/tasty) ingredient which allows to generate per-test coverage data.++If the GHC compiler is passed the `-fhpc` flag, then the generated code is instrumented in order to also emit information about the executed parts of the sourcecode at runtime.+This coverage information is written to a file with the suffix `.tix`.+For testsuites it is sometimes more useful to have the coverage information for each test individually.+This information can be collected using the methods from the `Trace.Hpc.Reflect` module from the [hpc](https://hackage.haskell.org/package/hpc) library.+The `tasty-coverage` package provides a simple ingredient for the [tasty](https://hackage.haskell.org/package/tasty) testsuite driver which allows to run the testsuite with the `--report-coverage` option.+When this option is passed, one `.tix` file is generated for each individual test.+Passing tests have the file suffix `PASSED.tix`, whereas failing tests have the suffix `FAILED.tix`.++```console+> cabal run tasty-coverage-test -- --help+Mmm... tasty test suite++Usage: tasty-coverage-test [-p|--pattern PATTERN] [-t|--timeout DURATION] + [--report-coverage]++Available options:+ -h,--help Show this help text+ -p,--pattern PATTERN Select only tests which satisfy a pattern or awk+ expression+ -t,--timeout DURATION Timeout for individual tests (suffixes: ms,s,m,h;+ default: s)+ --report-coverage Generate per-test coverage data++> cabal run tasty-coverage-test -- --report-coverage+Wrote coverage file: tix/UnitTests.testOne.PASSED.tix+Wrote coverage file: tix/UnitTests.testTwo.PASSED.tix+Wrote coverage file: tix/UnitTests.testThree.FAILED.tix+```
+ src/Test/Tasty/CoverageReporter.hs view
@@ -0,0 +1,73 @@+{-# LANGUAGE InstanceSigs #-}+module Test.Tasty.CoverageReporter (coverageReporter) where++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 )+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)++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)+++tixDir :: FilePath+tixDir = "tix"++-- | 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))++++-- | 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 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+ }++tixFilePath :: TestName -> Result -> FilePath+tixFilePath tn Result { resultOutcome = Success } = tixDir </> tn <.> "PASSED" <.> ".tix"+tixFilePath tn Result { resultOutcome = Failure _ } = tixDir </> tn <.> "FAILED" <.> ".tix"++coverageReporter :: Ingredient+coverageReporter = TestManager coverageOptions coverageRunner++coverageOptions :: [OptionDescription]+coverageOptions = [Option (Proxy :: Proxy ReportCoverage)]++coverageRunner :: OptionSet -> TestTree -> Maybe (IO Bool)+coverageRunner opts tree = case lookupOption opts of+ MkReportCoverage False -> Nothing+ MkReportCoverage True -> Just $ do+ testNames opts tree+ pure True++
+ tasty-coverage.cabal view
@@ -0,0 +1,39 @@+cabal-version: 3.0+name: tasty-coverage+version: 0.1.0.0+license: BSD-3-Clause+license-file: LICENSE+copyright: David Binder, 2023+maintainer: david.binder@uni-tuebingen.de+author: David Binder+tested-with: ghc ==9.2.7 || ==9.4.5 || ==9.6.2+homepage: https://github.com/BinderDavid/tasty-coverage+bug-reports: https://github.com/BinderDavid/tasty-coverage/issues+synopsis:+ Ingredient for tasty which generates per-test coverage reports++description:+ An ingredient for the tasty testing framework which allows to generate per-test coverage reports.+ For every test "foo" a file "foo.PASSED.tix" or "foo.FAILED.tix" is generated, depending on whether the test passed or failed. ++category: Testing+build-type: Simple+extra-doc-files:+ CHANGELOG.md+ README.md++source-repository head+ type: git+ location: git@github.com:BinderDavid/tasty-coverage.git++library+ exposed-modules: Test.Tasty.CoverageReporter+ hs-source-dirs: src+ default-language: Haskell2010+ ghc-options: -Wall+ build-depends:+ base >=4.16 && <4.20,+ tasty ^>=1.4,+ hpc >=0.6 && <0.8,+ filepath >=1.3.8 && <1.4.100+