Merge pull request #270 from barrucadu/259-failures

Highlight failures in tests
This commit is contained in:
Michael Walker 2018-06-17 11:41:10 +01:00 committed by GitHub
commit 6966c377b6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 249 additions and 80 deletions

View File

@ -9,6 +9,12 @@
# Record patterns are just ugly.
- ignore: {name: Use record patterns}
# Don't prefer TupleSections
- ignore: {name: Use tuple-section}
# Inapplicable
- ignore: {name: Use readTVarIO, within: Control.Monad.Conc.Class}
# GHC treats infix $ specially wrt type checking, so that things like
# "runST $ do ..." work even though they're impredicative.
# Unfortunately, this means that HLint's "avoid lambda" warning for

View File

@ -45,10 +45,10 @@ There are a few different packages under the Déjà Fu umbrella:
| | Version | Summary |
| - | ------- | ------- |
| [concurrency][h:conc] | 1.5.0.0 | Typeclasses, functions, and data types for concurrency and STM. |
| [dejafu][h:dejafu] | 1.9.1.0 | Systematic testing for Haskell concurrency. |
| [hunit-dejafu][h:hunit] | 1.2.0.4 | Deja Fu support for the HUnit test framework. |
| [tasty-dejafu][h:tasty] | 1.2.0.5 | Deja Fu support for the Tasty test framework. |
| [concurrency][h:conc] | 1.5.0.0 | Typeclasses, functions, and data types for concurrency and STM. |
| [dejafu][h:dejafu] | 1.10.0.0 | Systematic testing for Haskell concurrency. |
| [hunit-dejafu][h:hunit] | 1.2.0.5 | Deja Fu support for the HUnit test framework. |
| [tasty-dejafu][h:tasty] | 1.2.0.6 | Deja Fu support for the Tasty test framework. |
Each package has its own README and CHANGELOG in its subdirectory.

View File

@ -18,6 +18,7 @@ cabal-version: >=1.10
library
exposed-modules: Unit
, Unit.Predicates
, Unit.Properties
, Integration

View File

@ -42,7 +42,7 @@ concFilter = unsafeRunFind $ [0..5] @! const True
-- | Check that two lists of results are equal, modulo order.
checkResultLists :: Ord a => Predicate [a]
checkResultLists = alwaysSameOn (fmap sort)
checkResultLists = alwaysSameOn sort
-------------------------------------------------------------------------------

View File

@ -178,7 +178,7 @@ stmTests = toTestList
[ djfuT "Transactions are atomic" (gives' [0,2]) $ do
x <- atomically $ newTVarInt 0
_ <- fork . atomically $ writeTVar x 1 >> writeTVar x 2
atomically $ readTVar x
readTVarConc x
, djfuT "'retry' is the left identity of 'orElse'" (gives' [()]) $ do
x <- atomically $ newTVar Nothing

View File

@ -45,7 +45,7 @@ tests = toTestList
writeTVar v 2
writeTVar v 3
retry
atomically $ readTVar v
readTVarConc v
, djfu "https://github.com/barrucadu/dejafu/issues/118" exceptionsAlways $
catchSomeException

View File

@ -139,7 +139,7 @@ stmTests = toTestList
, djfu "When a TVar is updated, its new value is visible in a later transaction" (gives' [True]) $ do
ctv <- atomically $ newTVarInt 5
(5==) <$> atomically (readTVar ctv)
(5==) <$> readTVarConc ctv
, djfu "Aborting a transaction blocks the thread" (gives [Left STMDeadlock])
(atomically retry :: MonadConc m => m ()) -- avoid an ambiguous type
@ -147,14 +147,14 @@ stmTests = toTestList
, djfu "Aborting a transaction can be caught and recovered from" (gives' [True]) $ do
ctv <- atomically $ newTVarInt 5
atomically $ orElse retry (writeTVar ctv 6)
(6==) <$> atomically (readTVar ctv)
(6==) <$> readTVarConc ctv
, djfu "An exception thrown in a transaction can be caught" (gives' [True]) $ do
ctv <- atomically $ newTVarInt 5
atomically $ catchArithException
(throwSTM Overflow)
(\_ -> writeTVar ctv 6)
(6==) <$> atomically (readTVar ctv)
(6==) <$> readTVarConc ctv
, djfu "Nested exception handlers in transactions work" (gives' [True]) $ do
ctv <- atomically $ newTVarInt 5
@ -163,7 +163,7 @@ stmTests = toTestList
(throwSTM Overflow)
(\_ -> writeTVar ctv 0))
(\_ -> writeTVar ctv 6)
(6==) <$> atomically (readTVar ctv)
(6==) <$> readTVarConc ctv
, djfu "MonadSTM is a MonadFail" (alwaysFailsWith isUncaughtException)
(atomically $ fail "hello world" :: MonadConc m => m ()) -- avoid an ambiguous type

View File

@ -11,14 +11,16 @@ import Test.Tasty.Hedgehog (HedgehogDiscardLimit(..),
import Test.Tasty.Options (IsOption(..), OptionDescription(..))
import Text.Read (readMaybe)
import qualified Unit.Properties as P
import qualified Unit.Predicates as PE
import qualified Unit.Properties as PO
import Common
-- | Run all the unit tests.
tests :: [TestTree]
tests = map applyHedgehogOptions
[ testGroup "Properties" P.tests
[ testGroup "Predicates" PE.tests
, testGroup "Properties" PO.tests
]
-- | Tasty options

View File

@ -0,0 +1,78 @@
module Unit.Predicates where
import qualified Test.DejaFu as D
import Test.Tasty.HUnit
import Common
tests :: [TestTree]
tests =
[ testGroup "alwaysSameBy" alwaysSameBy
, testGroup "notAlwaysSameBy" notAlwaysSameBy
, testGroup "alwaysNothing" alwaysNothing
, testGroup "somewhereNothing" somewhereNothing
, testGroup "gives" gives
]
-------------------------------------------------------------------------------
alwaysSameBy :: [TestTree]
alwaysSameBy = toTestList
[ passes "Equal successes" (D.alwaysSameBy (==)) [Right 1, Right 1, Right 1]
, fails "Unequal successes" (D.alwaysSameBy (==)) [Right 1, Right 2, Right 3]
, fails "Equal failures" (D.alwaysSameBy (==)) [Left D.Deadlock, Left D.Deadlock, Left D.Deadlock]
, fails "Unequal failures" (D.alwaysSameBy (==)) [Left D.Deadlock, Left D.STMDeadlock, Left D.Abort]
, fails "Mixed failures and successes" (D.alwaysSameBy (==)) [Left D.Deadlock, Right 1, Right 1]
]
-------------------------------------------------------------------------------
notAlwaysSameBy :: [TestTree]
notAlwaysSameBy = toTestList
[ fails "Equal successes" (D.notAlwaysSameBy (==)) [Right 1, Right 1, Right 1]
, passes "Unequal successes" (D.notAlwaysSameBy (==)) [Right 1, Right 2, Right 3]
, fails "Equal failures" (D.notAlwaysSameBy (==)) [Left D.Deadlock, Left D.Deadlock, Left D.Deadlock]
, fails "Unequal failures" (D.notAlwaysSameBy (==)) [Left D.Deadlock, Left D.STMDeadlock, Left D.Abort]
, fails "Mixed failures and successes" (D.notAlwaysSameBy (==)) [Left D.Deadlock, Right 1, Right 1]
]
-------------------------------------------------------------------------------
alwaysNothing :: [TestTree]
alwaysNothing = toTestList
[ passes "Always" (D.alwaysNothing (const Nothing)) [Right 1, Right 2, Left D.Deadlock]
, fails "Somewhere" (D.alwaysNothing (either (Just . Left) (const Nothing))) [Right 1, Right 2, Left D.Deadlock]
, fails "Never" (D.alwaysNothing Just) [Right 1, Right 2, Left D.Deadlock]
]
-------------------------------------------------------------------------------
somewhereNothing :: [TestTree]
somewhereNothing = toTestList
[ passes "Always" (D.somewhereNothing (const Nothing)) [Right 1, Right 2, Left D.Deadlock]
, passes "Somewhere" (D.somewhereNothing (either (Just . Left) (const Nothing))) [Right 1, Right 2, Left D.Deadlock]
, fails "Never" (D.somewhereNothing Just) [Right 1, Right 2, Left D.Deadlock]
]
-------------------------------------------------------------------------------
gives :: [TestTree]
gives = toTestList
[ passes "Exact match" (D.gives [Right 1, Right 2]) [Right 1, Right 2]
, fails "Extra results" (D.gives [Right 1, Right 2]) [Right 1, Right 2, Right 3]
, fails "Missing results" (D.gives [Right 1, Right 2]) [Right 1]
]
-------------------------------------------------------------------------------
-- | Check a predicate passes
passes :: String -> D.Predicate Int -> [Either D.Failure Int] -> TestTree
passes = checkPredicate D._pass
-- | Check a predicate fails
fails :: String -> D.Predicate Int -> [Either D.Failure Int] -> TestTree
fails = checkPredicate (not . D._pass)
-- | Check a predicate
checkPredicate :: (D.Result Int -> Bool) -> String -> D.Predicate Int -> [Either D.Failure Int] -> TestTree
checkPredicate f msg p = testCase msg . assertBool "" . f . D.peval p . map (\efa -> (efa, []))

View File

@ -7,6 +7,30 @@ standard Haskell versioning scheme.
.. _PVP: https://pvp.haskell.org/
1.10.0.0 (2018-06-17)
---------------------
* Git: :tag:`dejafu-1.10.0.0`
* Hackage: :hackage:`dejafu-1.10.0.0`
Added
~~~~~
* The ``Test.DejaFu.notAlwaysSameOn`` and ``notAlwaysSameBy``
predicates, generalising ``notAlwaysSame``.
Changed
~~~~~~~
* ``Test.DejaFu.autocheck`` and related functions use the
``successful`` predicate, rather than looking specifically for
deadlocks and uncaught exceptions.
* (:issue:`259`) The ``Test.DejaFu.alwaysSame``, ``alwaysSameOn``,
``alwaysSameBy``, and ``notAlwaysSame`` predicates fail if the
computation under test fails.
1.9.1.0 (2018-06-10)
--------------------

View File

@ -1,4 +1,3 @@
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE TupleSections #-}
{- |
@ -7,7 +6,7 @@ Copyright : (c) 2015--2018 Michael Walker
License : MIT
Maintainer : Michael Walker <mike@barrucadu.co.uk>
Stability : experimental
Portability : LambdaCase, MultiParamTypeClasses, TupleSections
Portability : TupleSections
dejafu is a library for unit-testing concurrent Haskell programs,
written using the [concurrency](https://hackage.haskell.org/package/concurrency)
@ -27,17 +26,15 @@ let example = do
We can test it with dejafu like so:
>>> autocheck example
[pass] Never Deadlocks
[pass] No Exceptions
[fail] Consistent Result
[pass] Successful
[fail] Deterministic
"hello" S0----S1--S0--
<BLANKLINE>
"world" S0----S2--S0--
False
The 'autocheck' function takes a concurrent program to test and looks
for some common unwanted behaviours: deadlocks, uncaught exceptions in
the main thread, and nondeterminism. Here we see the program is
for concurrency errors and nondeterminism. Here we see the program is
nondeterministic, dejafu gives us all the distinct results it found
and, for each, a summarised execution trace leading to that result:
@ -177,6 +174,8 @@ usage.
, representative
, alwaysSameOn
, alwaysSameBy
, notAlwaysSameOn
, notAlwaysSameBy
, alwaysTrue
, somewhereTrue
, alwaysNothing
@ -272,14 +271,16 @@ import Control.DeepSeq (NFData(..))
import Control.Monad (unless, when)
import Control.Monad.Conc.Class (MonadConc)
import Control.Monad.IO.Class (MonadIO(..))
import Data.Either (isLeft)
import Data.Function (on)
import Data.List (intercalate, intersperse)
import Data.List (intercalate, intersperse, partition)
import Data.Maybe (catMaybes, isJust, isNothing,
mapMaybe)
import Data.Profunctor (Profunctor(..))
import System.Environment (lookupEnv)
import Test.DejaFu.Conc
import Test.DejaFu.Internal
import Test.DejaFu.Refinement
import Test.DejaFu.SCT
import Test.DejaFu.Settings
@ -314,13 +315,12 @@ let relaxed = do
-- | Automatically test a computation.
--
-- In particular, look for deadlocks, uncaught exceptions, and
-- multiple return values. Returns @True@ if all tests pass
-- In particular, concurrency errors and nondeterminism. Returns
-- @True@ if all tests pass
--
-- >>> autocheck example
-- [pass] Never Deadlocks
-- [pass] No Exceptions
-- [fail] Consistent Result
-- [pass] Successful
-- [fail] Deterministic
-- "hello" S0----S1--S0--
-- <BLANKLINE>
-- "world" S0----S2--S0--
@ -337,9 +337,8 @@ autocheck = autocheckWithSettings defaultSettings
-- memory model.
--
-- >>> autocheckWay defaultWay defaultMemType relaxed
-- [pass] Never Deadlocks
-- [pass] No Exceptions
-- [fail] Consistent Result
-- [pass] Successful
-- [fail] Deterministic
-- (False,True) S0---------S1----S0--S2----S0--
-- <BLANKLINE>
-- (False,False) S0---------S1--P2----S1--S0---
@ -350,9 +349,8 @@ autocheck = autocheckWithSettings defaultSettings
-- False
--
-- >>> autocheckWay defaultWay SequentialConsistency relaxed
-- [pass] Never Deadlocks
-- [pass] No Exceptions
-- [fail] Consistent Result
-- [pass] Successful
-- [fail] Deterministic
-- (False,True) S0---------S1----S0--S2----S0--
-- <BLANKLINE>
-- (True,True) S0---------S1-P2----S1---S0---
@ -374,9 +372,8 @@ autocheckWay way = autocheckWithSettings . fromWayAndMemType way
-- | Variant of 'autocheck' which takes a settings record.
--
-- >>> autocheckWithSettings (fromWayAndMemType defaultWay defaultMemType) relaxed
-- [pass] Never Deadlocks
-- [pass] No Exceptions
-- [fail] Consistent Result
-- [pass] Successful
-- [fail] Deterministic
-- (False,True) S0---------S1----S0--S2----S0--
-- <BLANKLINE>
-- (False,False) S0---------S1--P2----S1--S0---
@ -387,9 +384,8 @@ autocheckWay way = autocheckWithSettings . fromWayAndMemType way
-- False
--
-- >>> autocheckWithSettings (fromWayAndMemType defaultWay SequentialConsistency) relaxed
-- [pass] Never Deadlocks
-- [pass] No Exceptions
-- [fail] Consistent Result
-- [pass] Successful
-- [fail] Deterministic
-- (False,True) S0---------S1----S0--S2----S0--
-- <BLANKLINE>
-- (True,True) S0---------S1-P2----S1---S0---
@ -405,9 +401,8 @@ autocheckWithSettings :: (MonadConc n, MonadIO n, Eq a, Show a)
-- ^ The computation to test.
-> n Bool
autocheckWithSettings settings = dejafusWithSettings settings
[ ("Never Deadlocks", representative deadlocksNever)
, ("No Exceptions", representative exceptionsNever)
, ("Consistent Result", alwaysSame) -- already representative
[ ("Successful", representative successful)
, ("Deterministic", alwaysSame) -- already representative
]
-- | Check a predicate and print the result to stdout, return 'True'
@ -830,54 +825,86 @@ exceptionsAlways = alwaysTrue $ either isUncaughtException (const False)
exceptionsSometimes :: Predicate a
exceptionsSometimes = somewhereTrue $ either isUncaughtException (const False)
-- | Check that the result of a computation is always the same. In
-- particular this means either: (a) it always fails in the same way,
-- or (b) it never fails and the values returned are all equal.
-- | Check that a computation always gives the same, successful,
-- result.
--
-- > alwaysSame = alwaysSameBy (==)
--
-- @since 1.0.0.0
-- @since 1.10.0.0
alwaysSame :: Eq a => Predicate a
alwaysSame = alwaysSameBy (==)
-- | Check that the result of a computation is always the same by
-- comparing the result of a function on every result.
-- | Check that a computation always gives the same (according to the
-- provided function), successful, result.
--
-- > alwaysSameOn = alwaysSameBy ((==) `on` f)
--
-- @since 1.0.0.0
alwaysSameOn :: Eq b => (Either Failure a -> b) -> Predicate a
-- @since 1.10.0.0
alwaysSameOn :: Eq b => (a -> b) -> Predicate a
alwaysSameOn f = alwaysSameBy ((==) `on` f)
-- | Check that the result of a computation is always the same, using
-- some transformation on results.
--
-- @since 1.0.0.0
alwaysSameBy :: (Either Failure a -> Either Failure a -> Bool) -> Predicate a
-- @since 1.10.0.0
alwaysSameBy :: (a -> a -> Bool) -> Predicate a
alwaysSameBy f = ProPredicate
{ pdiscard = const Nothing
, peval = \xs -> case simplestsBy f xs of
[] -> defaultPass
[_] -> defaultPass
xs' -> defaultFail xs'
, peval = \xs ->
let (failures, successes) = partition (isLeft . fst) xs
simpleSuccesses = simplestsBy (f `on` efromRight) successes
in case (failures, simpleSuccesses) of
([], []) -> defaultPass
([], [_]) -> defaultPass
(_, _) -> defaultFail (failures ++ simpleSuccesses)
}
-- | Check that the result of a computation is not always the same.
-- | Check that a computation never fails, and gives multiple distinct
-- successful results.
--
-- @since 1.0.0.0
-- > notAlwaysSame = notAlwaysSameBy (==)
--
-- @since 1.10.0.0
notAlwaysSame :: Eq a => Predicate a
notAlwaysSame = ProPredicate
notAlwaysSame = notAlwaysSameBy (==)
-- | Check that a computation never fails, and gives multiple distinct
-- (according to the provided function) successful results.
--
-- > notAlwaysSameOn = notAlwaysSameBy ((==) `on` f)
--
-- @since 1.10.0.0
notAlwaysSameOn :: Eq b => (a -> b) -> Predicate a
notAlwaysSameOn f = notAlwaysSameBy ((==) `on` f)
-- | Check that a computation never fails, and gives multiple distinct
-- successful results, by applying a transformation on results.
--
-- This inverts the condition, so (eg) @notAlwaysSameBy (==)@ will
-- pass if there are unequal results.
--
-- @since 1.10.0.0
notAlwaysSameBy :: (a -> a -> Bool) -> Predicate a
notAlwaysSameBy f = ProPredicate
{ pdiscard = const Nothing
, peval = \case
[x] -> defaultFail [x]
xs -> go xs (defaultFail [])
, peval = \xs ->
let (failures, successes) = partition (isLeft . fst) xs
in case successes of
[x] -> defaultFail (x : failures)
_ ->
let res = go successes (defaultFail [])
in case failures of
[] -> res
_ -> res { _failures = failures ++ _failures res, _pass = False }
}
where
y1 .*. y2 = not (on f (efromRight . fst) y1 y2)
go [y1,y2] res
| fst y1 /= fst y2 = res { _pass = True }
| y1 .*. y2 = res { _pass = True }
| otherwise = res { _failures = y1 : y2 : _failures res }
go (y1:y2:ys) res
| fst y1 /= fst y2 = go (y2:ys) res { _pass = True }
| y1 .*. y2 = go (y2:ys) res { _pass = True }
| otherwise = go (y2:ys) res { _failures = y1 : y2 : _failures res }
go _ res = res

View File

@ -351,6 +351,12 @@ efromList :: HasCallStack => [a] -> NonEmpty a
efromList (x:xs) = x:|xs
efromList _ = withFrozenCallStack $ fatal "fromList: empty list"
-- | 'fromRight' but with a better error message if it fails. Use
-- this only where it shouldn't fail!
efromRight :: HasCallStack => Either a b -> b
efromRight (Right b) = b
efromRight _ = withFrozenCallStack $ fatal "fromRight: Left"
-- | 'M.adjust' but which errors if the key is not present. Use this
-- only where it shouldn't fail!
eadjust :: (Ord k, Show k, HasCallStack) => (v -> v) -> k -> M.Map k v -> M.Map k v

View File

@ -2,7 +2,7 @@
-- documentation, see http://haskell.org/cabal/users-guide/
name: dejafu
version: 1.9.1.0
version: 1.10.0.0
synopsis: A library for unit-testing concurrent programs.
description:
@ -33,7 +33,7 @@ source-repository head
source-repository this
type: git
location: https://github.com/barrucadu/dejafu.git
tag: dejafu-1.9.1.0
tag: dejafu-1.10.0.0
library
exposed-modules: Test.DejaFu

View File

@ -27,10 +27,10 @@ There are a few different packages under the Déjà Fu umbrella:
.. csv-table::
:header: "Package", "Version", "Summary"
":hackage:`concurrency`", "1.5.0.0", "Typeclasses, functions, and data types for concurrency and STM"
":hackage:`dejafu`", "1.9.1.0", "Systematic testing for Haskell concurrency"
":hackage:`hunit-dejafu`", "1.2.0.4", "Déjà Fu support for the HUnit test framework"
":hackage:`tasty-dejafu`", "1.2.0.5", "Déjà Fu support for the tasty test framework"
":hackage:`concurrency`", "1.5.0.0", "Typeclasses, functions, and data types for concurrency and STM"
":hackage:`dejafu`", "1.10.0.0", "Systematic testing for Haskell concurrency"
":hackage:`hunit-dejafu`", "1.2.0.5", "Déjà Fu support for the HUnit test framework"
":hackage:`tasty-dejafu`", "1.2.0.6", "Déjà Fu support for the tasty test framework"
Installation
@ -82,16 +82,15 @@ we'll get onto that shortly. First, the result of testing:
.. code-block:: none
> autocheck myFunction
[pass] Never Deadlocks
[pass] No Exceptions
[fail] Consistent Result
[pass] Successful
[fail] Deterministic
"hello" S0----S1--S0--
"world" S0----S2--S0--
False
There are no deadlocks or uncaught exceptions, which is good; but the
program is (as you probably spotted) nondeterministic!
There are no concurrency errors, which is good; but the program is (as
you probably spotted) nondeterministic!
Along with each result, Déjà Fu gives us a representative execution
trace in an abbreviated form. ``Sn`` means that thread ``n`` started

View File

@ -116,6 +116,8 @@ to it from a different thread).
``alwaysSameOn f``,"is like ``alwaysSame``, but transforms the results with ``f`` first"
``alwaysSameBy f``,"is like ``alwaysSame``, but uses ``f`` instead of ``(==)`` to compare"
``notAlwaysSame``,"checks that the computation is nondeterministic"
``notAlwaysSameOn f``,"is like ``notAlwaysSame``, but transforms the results with ``f`` first"
``notAlwaysSameBy f``,"is like ``notAlwaysSame``, but uses ``f`` instead of ``(==)`` to compare"
Checking for **determinism** will also find nondeterministic failures:
deadlocking (for instance) is still a result of a test!

View File

@ -7,6 +7,18 @@ standard Haskell versioning scheme.
.. _PVP: https://pvp.haskell.org/
1.2.0.5 (2018-06-17)
--------------------
* Git: :tag:`hunit-dejafu-1.2.0.5`
* Hackage: :hackage:`hunit-dejafu-1.2.0.5`
Miscellaneous
~~~~~~~~~~~~~
* The upper bound on :hackage:`dejafu` is <1.11.
1.2.0.4 (2018-06-10)
--------------------

View File

@ -2,7 +2,7 @@
-- documentation, see http://haskell.org/cabal/users-guide/
name: hunit-dejafu
version: 1.2.0.4
version: 1.2.0.5
synopsis: Deja Fu support for the HUnit test framework.
description:
@ -30,7 +30,7 @@ source-repository head
source-repository this
type: git
location: https://github.com/barrucadu/dejafu.git
tag: hunit-dejafu-1.2.0.4
tag: hunit-dejafu-1.2.0.5
library
exposed-modules: Test.HUnit.DejaFu
@ -38,7 +38,7 @@ library
-- other-extensions:
build-depends: base >=4.9 && <5
, exceptions >=0.7 && <0.11
, dejafu >=1.5 && <1.10
, dejafu >=1.5 && <1.11
, HUnit >=1.3.1 && <1.7
-- hs-source-dirs:
default-language: Haskell2010

View File

@ -7,6 +7,18 @@ standard Haskell versioning scheme.
.. _PVP: https://pvp.haskell.org/
1.2.0.6 (2018-06-17)
--------------------
* Git: :tag:`tasty-dejafu-1.2.0.6`
* Hackage: :hackage:`tasty-dejafu-1.2.0.6`
Miscellaneous
~~~~~~~~~~~~~
* The upper bound on :hackage:`dejafu` is <1.11.
1.2.0.5 (2018-06-10)
--------------------

View File

@ -2,7 +2,7 @@
-- documentation, see http://haskell.org/cabal/users-guide/
name: tasty-dejafu
version: 1.2.0.5
version: 1.2.0.6
synopsis: Deja Fu support for the Tasty test framework.
description:
@ -30,14 +30,14 @@ source-repository head
source-repository this
type: git
location: https://github.com/barrucadu/dejafu.git
tag: tasty-dejafu-1.2.0.5
tag: tasty-dejafu-1.2.0.6
library
exposed-modules: Test.Tasty.DejaFu
-- other-modules:
-- other-extensions:
build-depends: base >=4.9 && <5
, dejafu >=1.5 && <1.10
, dejafu >=1.5 && <1.11
, random >=1.0 && <1.2
, tagged >=0.8 && <0.9
, tasty >=0.10 && <1.2