Getting Started

[Déjà Fu is] A martial art in which the user's limbs move in time as well as space, […] It is best described as "the feeling that you have been kicked in the head this way before"

-- Terry Pratchett, Thief of Time

Déjà Fu is a unit-testing library for concurrent Haskell programs. Tests are deterministic and expressive, making it easy and convenient to test your threaded code.

Available on GitHub, Hackage, and Stackage.

Features:

  • An abstraction over the concurrency functionality in IO
  • Deterministic testing of nondeterministic code
  • Both complete (slower) and incomplete (faster) modes
  • A unit-testing-like approach to writing test cases
  • A property-testing-like approach to comparing stateful operations
  • Testing of potentially nonterminating programs
  • Integration with HUnit and tasty

There are a few different packages under the Déjà Fu umbrella:

VersionSummary
concurrency1.11.0.3Typeclasses, functions, and data types for concurrency and STM.
dejafu2.4.0.6Systematic testing for Haskell concurrency.
hunit-dejafu2.0.0.6Deja Fu support for the HUnit test framework.
tasty-dejafu2.1.0.1Deja Fu support for the Tasty test framework.

See the latest package documentation.

Installation

Install from Hackage globally:

$ cabal install dejafu

Or add it to your cabal file:

build-depends: ...
             , dejafu

Or to your package.yaml:

dependencies:
  ...
  - dejafu

Quick start guide

Déjà Fu supports unit testing, and comes with a helper function called autocheck to look for some common issues. Let's see it in action:

import Control.Concurrent.Classy

myFunction :: MonadConc m => m String
myFunction = do
  var <- newEmptyMVar
  fork (putMVar var "hello")
  fork (putMVar var "world")
  readMVar var

That MonadConc is a typeclass abstraction over concurrency, but we'll get onto that shortly. First, the result of testing:

> autocheck myFunction
[pass] Never Deadlocks
[pass] No Exceptions
[fail] Consistent Result
    "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!

Along with each result, Déjà Fu gives us a representative execution trace in an abbreviated form. Sn means that thread n started executing, and Pn means that thread n pre-empted the previously running thread.

Why Déjà Fu?

Testing concurrent programs is difficult, because in general they are nondeterministic. This leads to people using work-arounds like running their testsuite many thousands of times; or running their testsuite while putting their machine under heavy load.

These approaches are inadequate for a few reasons:

  • How many runs is enough? When you are just hopping to spot a bug by coincidence, how do you know to stop?
  • How do you know if you've fixed a bug you saw previously? Because the scheduler is a black box, you don't know if the previously buggy schedule has been re-run.
  • You won't get that much scheduling variety! Operating systems and language runtimes like to run threads for long periods of time, which reduces the variety you get (and so drives up the number of runs you need).

Déjà Fu addresses these points by offering complete testing. You can run a test case and be guaranteed to find all results with some bounds. These bounds can be configured, or even disabled! The underlying approach used is smarter than merely trying all possible executions, and will in general explore the state-space quickly.

If your test case is just too big for complete testing, there is also a random scheduling mode, which is necessarily incomplete. However, Déjà Fu will tend to produce much more schedule variety than just running your test case in IO the same number of times, and so bugs will tend to crop up sooner. Furthermore, as you get execution traces out, you can be certain that a bug has been fixed by simply following the trace by eye.

Bibliography

These libraries wouldn't be possible without prior research, which I mention in the documentation. Haddock comments get the full citation, whereas in-line comments just get the shortened name:

There are also a few papers on dejafu itself:

Typeclasses

We don't use the regular Control.Concurrent and Control.Exception modules, we use typeclass-generalised ones instead from the concurrency and exceptions packages.

Porting guide

If you want to test some existing code, you'll need to port it to the appropriate typeclass. The typeclass is necessary, because we can't peek inside IO and STM values, so we need to able to plug in an alternative implementation when testing.

Fortunately, this tends to be a fairly mechanical and type-driven process:

  1. Import Control.Concurrent.Classy.* instead of Control.Concurrent.*

  2. Import Control.Monad.Catch instead of Control.Exception

  3. Change your monad type:

    • IO a becomes MonadConc m => m a
    • STM a becomes MonadSTM stm => stm a
  4. Parameterise your state types by the monad:

    • TVar becomes TVar stm
    • MVar becomes MVar m
    • IORef becomes IORef m
  5. Some functions are renamed:

    • forkIO* becomes fork*
    • atomicModifyIORefCAS becomes modifyIORefCAS*
  6. Fix the type errors

If you're lucky enough to be starting a new concurrent Haskell project, you can just program against the MonadConc interface.

What if I really need I/O?

You can use MonadIO and liftIO with MonadConc, for instance if you need to talk to a database (or just use some existing library which needs real I/O).

To test IO-using code, there are some rules you need to follow:

  1. Given the same set of scheduling decisions, your IO code must be deterministic (see below).

  2. As dejafu can't inspect IO values, they should be kept small; otherwise dejafu may miss buggy interleavings.

  3. You absolutely cannot block on the action of another thread inside IO, or the test execution will just deadlock.

Tip

Deterministic IO is only essential if you're using the systematic testing (the default). Nondeterministic IO won't break the random testing, it'll just make things more confusing.

Deriving your own instances

There are MonadConc and MonadSTM instances for many common monad transformers. In the simple case, where you want an instance for a newtype wrapper around a type that has an instance, you may be able to derive it. For example:

{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE UndecidableInstances #-}

data Env = Env

newtype MyMonad m a = MyMonad { runMyMonad :: ReaderT Env m a }
  deriving (Functor, Applicative, Monad)

deriving instance MonadThrow m => MonadThrow (MyMonad m)
deriving instance MonadCatch m => MonadCatch (MyMonad m)
deriving instance MonadMask  m => MonadMask  (MyMonad m)

deriving instance MonadConc m => MonadConc (MyMonad m)

MonadSTM needs a slightly different set of classes:

{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE UndecidableInstances #-}

data Env = Env

newtype MyMonad m a = MyMonad { runMyMonad :: ReaderT Env m a }
  deriving (Functor, Applicative, Monad, Alternative, MonadPlus)

deriving instance MonadThrow m => MonadThrow (MyMonad m)
deriving instance MonadCatch m => MonadCatch (MyMonad m)

deriving instance MonadSTM m => MonadSTM (MyMonad m)

Don't be put off by the use of UndecidableInstances, it's safe here.

Unit Testing

Writing tests with Déjà Fu is a little different to traditional unit testing, as your test case may have multiple results. A "test" is a combination of your code, and a predicate which says something about the set of allowed results.

Most tests will look something like this:

dejafu "Assert the thing holds" myPredicate myAction

The dejafu function comes from Test.DejaFu. Another useful function is dejafuWithSettings (see Advanced Usage).

Actions

An action is just something with the type MonadConc m => m a, or (MonadConc m, MonadIO m) => m a for some a that your chosen predicate can deal with.

For example, some users on Reddit found a couple of apparent bugs in the auto-update package a while ago (thread here). As the package is simple and self-contained, I translated it to the MonadConc abstraction and wrote a couple of tests to replicate the bugs. Here they are:

deadlocks :: MonadConc m => m ()
deadlocks = do
  auto <- mkAutoUpdate defaultUpdateSettings
  auto

nondeterministic :: forall m. MonadConc m => m Int
nondeterministic = do
  var <- newIORef 0
  let settings = (defaultUpdateSettings :: UpdateSettings m ())
        { updateAction = atomicModifyIORef var (\x -> (x+1, x)) }
  auto <- mkAutoUpdate settings
  auto
  auto

These actions action could be tested with autocheck, and the issues would be revealed. The use of ScopedTypeVariables in the second is an unfortunate example of what can happen when everything becomes more polymorphic. But other than that, note how there is no special mention of Déjà Fu in the actions: it's just normal concurrent Haskell, simply written against a different interface.

The modified package is included in the test suite, if you want to see the full code.

Note

The predicates in dejafu-tests are a little confusing, as they're the opposite of what you would normally write! These predicates are checking that the bug is found, not that the code is correct.

If the RTS supports bound threads (the -threaded flag was passed to GHC when linking), then the main thread of an action given to Déjà Fu will be bound, and further bound threads can be forked with the forkOS functions. If not, then attempting to fork a bound thread will raise an error.

Conditions

When a concurrent program of type MonadConc m => m a is executed, it may produce a value of type a, or it may experience a condition such as deadlock.

A condition does not necessarily cause your test to fail. It's important to be aware of what exactly your test is testing, to avoid drawing the wrong conclusions from a passing (or failing) test.

Setup and Teardown

Because dejafu drives the execution of the program under test, there are some tricks available to you which are not possible using normal concurrent Haskell.

If your test does some set-up work which is required for your test to work, but which is not the actual thing you are testing, you can define that as a setup action:

withSetup
  :: Program Basic n x
  -- ^ Setup action
  -> (x -> Program Basic n a)
  -- ^ Main program
  -> Program (WithSetup x) n a

dejafu will save the state at the end of the setup action, and efficiently restore that state in subsequent runs of the same test with a different schedule. This can be much more efficient than dejafu running the setup action normally every single time.

If you want to examine some state you created in your setup action even if your actual test case deadlocks or something, you can define a teardown action:

withSetupAndTeardown
  :: Program Basic n x
  -- ^ Setup action
  -> (x -> Either Condition y -> Program Basic n a)
  -- ^ Teardown action
  -> (x -> Program Basic n y)
  -- ^ Main program
  -> Program (WithSetupAndTeardown x y) n a

The teardown action is always executed.

Finally, if you want to ensure that some invariant holds over some shared state, you can define invariants in the setup action, which are checked atomically during the main action:

-- slightly contrived example
let setup = do
      var <- newEmptyMVar
      registerInvariant $ do
        value <- inspectMVar var
        when (x == Just 1) (throwM Overflow)
      pure var
in withSetup setup $ \var -> do
     fork $ putMVar var 0
     fork $ putMVar var 1
     tryReadMVar var

If the main action violates the invariant, it is terminated with an InvariantFailure condition, and any teardown action is run.

Predicates

There are a few predicates built in, and some helpers to define your own.

abortsNeverchecks that the computation never aborts
abortsAlwayschecks that the computation always aborts
abortsSometimeschecks that the computation aborts at least once

An abort is where the scheduler chooses to terminate execution early. If you see it, it probably means that a test didn't terminate before it hit the execution length limit. Aborts are hidden unless you use explicitly enable them, see (see Advanced Usage).

deadlocksNeverchecks that the computation never deadlocks
deadlocksAlwayschecks that the computation always deadlocks
deadlocksSometimeschecks that the computation deadlocks at least once

Deadlocking is where every thread becomes blocked. This can be, for example, if every thread is trying to read from an MVar that has been emptied.

exceptionsNeverchecks that the main thread is never killed by an exception
exceptionsAlwayschecks that the main thread is always killed by an exception
exceptionsSometimeschecks that the main thread is killed by an exception at least once

An uncaught exception in the main thread kills the process. These can be synchronous (thrown in the main thread) or asynchronous (thrown to it from a different thread).

alwaysSamechecks that the computation is deterministic and always produces a value
alwaysSameOn fis like alwaysSame, but transforms the results with f first
alwaysSameBy fis like alwaysSame, but uses f instead of (==) to compare
notAlwaysSamechecks that the computation is nondeterministic
notAlwaysSameOn fis like notAlwaysSame, but transforms the results with f first
notAlwaysSameBy fis 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!

alwaysTrue pchecks that p is true for every result
somewhereTrue pchecks that p is true for at least one result

These can be used to check custom predicates. For example, you might want all your results to be less than five.

gives xschecks that the set of results is exactly xs (which may include conditions)
gives' xschecks that the set of results is exactly xs (which may not include conditions)

These let you say exactly what you want the results to be. Your test will fail if it has any extra results, or misses a result.

You can check multiple predicates against the same collection of results using the dejafus and dejafusWithSettings functions. These avoid recomputing the results, and so may be faster than multiple dejafu / dejafuWithSettings calls.

Using HUnit and Tasty

By itself, Déjà Fu has no framework in place for named test groups and parallel execution or anything like that. It does one thing and does it well, which is running test cases for concurrent programs. HUnit and tasty integration is provided to get more of the features you'd expect from a testing framework.

The integration is provided by the hunit-dejafu and tasty-dejafu packages.

There's a simple naming convention used: the Test.DejaFu function dejafuFoo is wrapped in the appropriate way and exposed as testDejafuFoo from Test.HUnit.DejaFu and Test.Tasty.DejaFu.

Our example from the start becomes:

testDejafu "Assert the thing holds" myPredicate myAction

The autocheck function is exposed as testAuto.

Refinement Testing

Déjà Fu also supports a form of property-testing where you can check things about the side-effects of stateful operations. For example, we can assert that readMVar is equivalent to sequencing takeMVar and putMVar like so:

prop_mvar_read_take_put =
  sig readMVar `equivalentTo` sig (\v -> takeMVar v >>= putMVar v)

Given the signature function, sig, defined in the next section. If we check this, our property fails!

> check prop_mvar_read_take_put
*** Failure: (seed Just 0)
    left:  [(Nothing,Just 0)]
    right: [(Nothing,Just 0),(Just Deadlock,Just 0)]
False

This is because readMVar is atomic, whereas sequencing takeMVar with putMVar is not, and so another thread can interfere with the MVar in the middle. The check and equivalentTo functions come from Test.DejaFu.Refinement (also re-exported from Test.DejaFu).

Signatures

A signature tells the property-tester something about the state your operation acts upon, it has a few components:

data Sig s o x = Sig
  { initialise ::      x -> ConcIO s
  , observe    :: s -> x -> ConcIO o
  , interfere  :: s -> x -> ConcIO ()
  , expression :: s      -> ConcIO ()
  }
  • s is the state type, it's the thing which your operations mutate. For readMVar, the state is some MVar a.

  • o is the observation type, it's some pure (and comparable) proxy for a snapshot of your mutable state. For MVar a, the observation is probably a Maybe a.

  • x is the seed type, it's some pure value used to construct the initial mutable state. For MVar a, the seed is probably a Maybe a.

  • ConcIO is just one of the instances of MonadConc that Déjà Fu defines for testing purposes. Just write code polymorphic in the monad as usual, and all will work.

The initialise, observe, and expression functions should be self-explanatory, but the interfere one may not be. It's the job of the interfere function to change the state in some way; it's run concurrently with the expression, to simulate the nondeterministic action of other threads.

Here's a concrete example for our MVar example:

sig :: (MVar ConcIO Int -> ConcIO a) -> Sig (MVar ConcIO Int) (Maybe Int) (Maybe Int)
sig e = Sig
{ initialise = maybe newEmptyMVar newMVar
, observe    = \v _ -> tryTakeMVar v
, interfere  = \v s -> tryTakeMVar v >> maybe (pure ()) (\x -> void $ tryPutMVar v (x * 1000)) s
, expression = void . e
}

The observe function should be deterministic, but as it is run after the normal execution ends, it may have side-effects on the state. The interfere function can do just about anything (there are probably some concrete rules for a good function, but I haven't figured them out yet), but a poor one may result in the property-checker being unable to distinguish between atomic and nonatomic expressions.

Properties

A property is a pair of signatures linked by one of three provided functions. These functions are:

FunctionOperatorChecks that...
equivalentTo===... the left and right have exactly the same behaviours
refines=>=... every behaviour of the left is also a behaviour of the right
strictlyRefines->-... left =>= right holds but left === right does not

The signatures can have different state types, as long as the seed and observation types are the same. This lets you compare different implementations of the same idea: for example, comparing a concurrent stack implemented using MVar with one implemented using IORef.

Properties can have parameters, given in the obvious way:

check $ \a b c -> sig1 ... `op` sig2 ...

Under the hood, seed and parameter values are generated using the leancheck package, an enumerative property-based testing library. This means that any types you use will need to have a Listable instance.

You can also think about the three functions in terms of sets of results, where a result is a (Maybe Failure, o) value. A Failure is something like deadlocking, or being killed by an exception; o is the observation type. An observation is always made, even if execution of the expression fails.

FunctionResult-set operation
refinesFor all seed and parameter assignments, subset-or-equal
strictlyRefinesFor at least one seed and parameter assignment, proper subset; for all others, subset-or-equal
equivalentToFor all seed and parameter assignments, equality

Finally, there is an expectFailure function, which inverts the expected result of a property.

The Déjà Fu testsuite has a collection of refinement properties, which may help you get a feel for this sort of testing.

Using HUnit and Tasty

As for unit testing, HUnit and tasty integration is provided for refinement testing in the hunit-dejafu and tasty-dejafu packages.

The testProperty function is used to check properties. Our example from the start becomes:

testProperty "Read is equivalent to Take then Put" prop_mvar_read_take_put

Advanced Usage

Déjà Fu tries to have a sensible set of defaults, but there are some times when the defaults are not suitable. There are a lot of knobs provided to tweak how things work.

Execution settings

The autocheckWithSettings, dejafuWithSettings, and dejafusWithSettings let you provide a Settings value, which controls some of Déjà Fu's behaviour:

dejafuWithSettings mySettings "Assert the thing holds" myPredicate myAction

The available settings are:

  • "Way", how to explore the behaviours of the program under test.

  • Length bound, a cut-off point to terminate an execution even if it's not done yet.

  • Memory model, which affects how non-synchronised operations, such as readIORef and writeIORef behave.

  • Discarding, which allows throwing away uninteresting results, rather than keeping them around in memory.

  • Early exit, which allows exiting as soon as a result matching a predicate is found.

  • Representative traces, keeping only one execution trace for each distinct result.

  • Trace simplification, rewriting execution traces into a simpler form (particularly effective with the random testing).

  • Safe IO, pruning needless schedules when your IO is only used to manage thread-local state.

See the Test.DejaFu.Settings module for more information.

Performance tuning

  • Are you happy to trade space for time?

    Consider computing the results once and running multiple predicates over the output: this is what dejafus / testDejafus / etc does.

  • Can you sacrifice completeness?

    Consider using the random testing functionality. See the *WithSettings functions.

  • Would strictness help?

    Consider using the strict functions in Test.DejaFu.SCT (the ones ending with a ').

  • Do you just want the set of results, and don't care about traces?

    Consider using Test.DejaFu.SCT.resultsSet.

  • Do you know something about the sort of results you care about?

    Consider discarding results you don't care about. See the *WithSettings functions in Test.DejaFu, Test.DejaFu.SCT, and Test.{HUnit,Tasty}.DejaFu.

For example, let's say you want to know if your test case deadlocks, but you don't care about the execution trace, and you are going to sacrifice completeness because your possible state-space is huge. You could do it like this:

dejafuWithSettings
  ( set ldiscard
    -- "efa" == "either failure a", discard everything but deadlocks
    (Just $ \efa -> Just (if either isDeadlock (const False) efa then DiscardTrace else DiscardResultAndTrace))
  . set lway
    -- try 10000 executions with random scheduling
    (randomly (mkStdGen 42) 10000)
  $ defaultSettings
  )
  -- the name of the test
  "Never Deadlocks"
  -- the predicate to check
  deadlocksNever
  -- your test case
  testCase

1.x to 2.x

dejafu-2.0.0.0 is a super-major release which breaks compatibility with dejafu-1.x.

Highlights reel:

  • Test cases are written in terms of a new Program type.
  • The Failure type has been replaced with a Condition type (actually in 1.12).
  • Random testing takes an optional length bound.
  • Atomically-checked invariants over shared mutable state.

See the changelogs for the full details.

The Program type

The ConcT type is now an alias for Program Basic.

A Program Basic has all the instances ConcT did, defined using the ~ instance trick, so this shouldn't be a breaking change:

instance (pty ~ Basic)            => MonadTrans (Program pty)
instance (pty ~ Basic)            => MonadCatch (Program pty n)
instance (pty ~ Basic)            => MonadThrow (Program pty n)
instance (pty ~ Basic)            => MonadMask  (Program pty n)
instance (pty ~ Basic, Monad   n) => MonadConc  (Program pty n)
instance (pty ~ Basic, MonadIO n) => MonadIO    (Program pty n)

The dontCheck function has been removed in favour of withSetup:

do x <- dontCheck setup
   action x

-- becomes

withSetup setup action

The subconcurrency function has been removed in favour of withSetupAndTeardown:

do x <- setup
   y <- subconcurrency (action x)
   teardown x y

-- becomes

withSetupAndTeardown setup teardown action

The dontCheck and subconcurrency functions used to throw runtime errors if nested. This is not possible with withSetup and withSetupAndTeardown due to their types:

withSetup
  :: Program Basic n x
  -- ^ Setup action
  -> (x -> Program Basic n a)
  -- ^ Main program
  -> Program (WithSetup x) n a

withSetupAndTeardown
  :: Program Basic n x
  -- ^ Setup action
  -> (x -> Either Condition y -> Program Basic n a)
  -- ^ Teardown action
  -> (x -> Program Basic n y)
  -- ^ Main program
  -> Program (WithSetupAndTeardown x y) n a

Previously, multiple calls to subconcurrency could be sequenced in the same test case. This is not possible using withSetupAndTeardown. If you rely on this behaviour, please file an issue.

The Condition type

This is a change in dejafu-1.12.0.0, but the alias Failure = Condition is removed in dejafu-2.0.0.0.

  • The STMDeadlock and Deadlock constructors have been merged.
  • Internal errors have been split into the Error type and are raised as exceptions, instead of being returned as conditions.

The name "failure" has been a recurring source of confusion, because an individual execution can "fail" without the predicate as a whole failing. My hope is that the more neutral "condition" will prevent this confusion.

Deprecated functions

All the deprecated special-purpose functions have been removed. Use more general *WithSettings functions instead.

Need help?

  • For general help talk to me in IRC (barrucadu in #haskell) or shoot me an email (mike@barrucadu.co.uk)
  • For bugs, issues, or requests, please file an issue.

0.x to 1.x

dejafu-1.0.0.0 is a super-major release which breaks compatibility with dejafu-0.x quite significantly, but brings with it support for bound threads, and significantly improves memory usage in the general case.

Highlights reel:

  • Most predicates now only need to keep around the failures, rather than all results.
  • Support for bound threads (with concurrency-1.3.0.0).
  • The ST / IO interface duplication is gone, everything is now monadic.
  • Function parameter order is closer to other testing libraries.
  • Much improved API documentation.

See the changelogs for the full details.

ST and IO functions

There is only one set of functions now. Testing bound threads requires being able to fork actual threads, so testing with ST is no longer possible. The ConcST type is gone, there is only ConcIO.

For dejafu change:

  • autocheckIO to autocheck
  • dejafuIO to dejafu
  • dejafusIO to dejafus
  • autocheckWayIO to autocheckWay
  • dejafuWayIO to dejafuWay
  • dejafusWayIO to dejafusWay
  • dejafuDiscardIO to dejafuDiscard
  • runTestM to runTest
  • runTestWayM to runTestWay

If you relied on being able to get a pure result from the ConcST functions, you can no longer do this.

For hunit-dejafu and tasty-dejafu change:

  • testAutoIO to testAuto
  • testDejafuIO to testDejafu
  • testDejafusIO to testDejafus
  • testAutoWayIO to testAutoWay
  • testDejafuWayIO to testDejafuWay
  • testDejafusWayIO to testDejafusWay
  • testDejafuDiscardIO to testDejafuDiscard

Function parameter order

Like HUnit, the monadic action to test is now the last parameter of the testing functions. This makes it convenient to write tests without needing to define the action elsewhere.

For dejafu change:

  • dejafu ma (s, p) to dejafu s p ma
  • dejafus ma ps to dejafus ps ma
  • dejafuWay way mem ma (s, p) to dejafuWay way mem s p ma
  • dejafusWay way mem ma ps to dejafuWay way mem ps ma
  • dejafuDiscard d way mem ma (s, p) to dejafuDiscard d way mem s p ma

For hunit-dejafu and tasty-dejafu change:

  • testDejafu ma s p to testDejafu s p ma
  • testDejafus ma ps to testDejafus ps ma
  • testDejafuWay way mem ma s p to testDejafuWay way mem s p ma
  • testDejafusWay way mem ma ps to testDejafusWay way mem ps ma
  • testDejafuDiscard d way mem ma s p to testDejafuDiscard d way mem s p ma

Predicates

The Predicate a type is now an alias for ProPredicate a a, defined like so:

data ProPredicate a b = ProPredicate
  { pdiscard :: Either Failure a -> Maybe Discard
  -- ^ Selectively discard results before computing the result.
  , peval :: [(Either Failure a, Trace)] -> Result b
  -- ^ Compute the result with the un-discarded results.
  }

If you use the predicate helper functions to construct a predicate, you do not need to change anything (and should get a nice reduction in your resident memory usage). If you supply a function directly, you can recover the old behaviour like so:

old :: ([(Either Failure a, Trace)] -> Result a) -> ProPredicate a a
old p = ProPredicate
  { pdiscard = const Nothing
  , peval = p
  }

The alwaysTrue2 helper function is gone. If you use it, use alwaysSameOn or alwaysSameBy instead.

Need help?

  • For general help talk to me in IRC (barrucadu in #haskell) or shoot me an email (mike@barrucadu.co.uk)
  • For bugs, issues, or requests, please file an issue.

Contributing

Thanks for caring about Déjà Fu!

Ways to contribute

Déjà Fu is a project under active development, there's always something to do. Here's a list of ideas to get you started:

  • Submit bug reports.
  • Submit feature requests.
  • Got a particularly slow test case which you think should be faster? Open an issue for that too.
  • Blog about how and why you use Déjà Fu.
  • Check if any bugs which have been open for a while are still bugs.

If you want to contribute code, you could:

  • Tackle one of the issues tagged "good first issue".
  • Tackle a bigger issue, perhaps one of the roadmap issues!
  • Run code coverage and try to fix a gap in the tests.
  • Profile the test suite and try to improve a slow function.

Roadmap issues are priority issues (in my opinion), so help with those is especially appreciated.

If you have a support question, you can talk to me on IRC (#haskell on freenode) or send an email (mike@barrucadu.co.uk) rather than opening an issue. But maybe your question is a bug report about poor documentation in disguise!

Making the change

  1. Talk to me!

    I don't bite, and chances are I can quickly tell you where you should start. It's better to ask what seems like a stupid question than to waste a lot of time on the wrong approach.

  2. Make the change.

    Figure out what needs to be changed, how to change it, and do it. If you're fixing a bug, make sure to add a minimal reproduction to Cases.Regressions in dejafu-tests.

  3. Document the change.

    All top-level definitions should have a Haddock comment explaining what it does. If you've added or changed a top-level function, consider commenting its arguments too.

    If you've added a top-level definition, or changed one in a backwards-incompatible way, add an @since unreleased Haddock comment to it. This is to help prevent me from missing things when I update the changelog ahead of a release.

  4. Submit a PR.

    GitHub Actions will run some checks, which might prompt further action. You should expect a response from me in a day or two.

Don't worry about your PR being perfect the first time. We'll work through any issues together, to ensure that Déjà Fu gets the best code it can.

Coding style

There isn't really a prescribed style. It's not quite the wild west though; keep these three rules in mind:

  1. Be consistent.
  2. Run stylish-haskell to format import lists.
  3. Use hlint and weeder and fix lints unless you have a good reason not to.

GitHub Actions runs stylish-haskell and hlint on all PRs.

Coverage

hpc can generate a coverage report from the execution of dejafu-tests:

$ stack build --coverage
$ stack exec dejafu-tests
$ stack hpc report --all dejafu-tests.tix

This will print some stats and generate an HTML coverage report:

Generating combined report
 52% expressions used (4052/7693)
 48% boolean coverage (63/129)
      43% guards (46/106), 31 always True, 9 always False, 20 unevaluated
      68% 'if' conditions (11/16), 2 always True, 3 unevaluated
      85% qualifiers (6/7), 1 unevaluated
 61% alternatives used (392/635)
 80% local declarations used (210/261)
 26% top-level declarations used (280/1063)
The combined report is available at /home/barrucadu/projects/dejafu/.stack-work/install/x86_64-linux/nightly-2016-06-20/8.0.1/hpc/combined/custom/hpc_index.html

The highlighted code in the HTML report emphasises branch coverage:

  • Red means a branch was evaluated as always false.
  • Green means a branch was evaluated as always true.
  • Yellow means an expression was never evaluated.

See also the stack coverage documentation.

Performance

GHC can generate performance statistics from the execution of dejafu-tests:

$ stack build --profile
$ stack exec  -- dejafu-tests +RTS -p
$ less dejafu-tests.prof

This prints a detailed breakdown of where memory and time are being spent:

    Mon Mar 20 19:26 2017 Time and Allocation Profiling Report  (Final)

       dejafu-tests +RTS -p -RTS

    total time  =      105.94 secs   (105938 ticks @ 1000 us, 1 processor)
    total alloc = 46,641,766,952 bytes  (excludes profiling overheads)

COST CENTRE                           MODULE                     %time %alloc

findBacktrackSteps.doBacktrack.idxs'  Test.DejaFu.SCT.Internal    21.9   12.0
==                                    Test.DejaFu.Common          12.4    0.0
yieldCount.go                         Test.DejaFu.SCT             12.1    0.0
dependent'                            Test.DejaFu.SCT              5.1    0.0
runThreads.go                         Test.DejaFu.Conc.Internal    2.7    4.1
[...]

Be careful, however! Compiling with profiling can significantly affect the behaviour of a program! Use profiling to get an idea of where the hot spots are, but make sure to confirm with a non-profiled build that things are actually getting faster.

If you compile with -rtsopts you can get some basic stats from a non-profiled build:

$ stack exec -- dejafu-tests +RTS -s

[...]
86,659,658,504 bytes allocated in the heap
13,057,037,448 bytes copied during GC
    13,346,952 bytes maximum residency (4743 sample(s))
       127,824 bytes maximum slop
            37 MB total memory in use (0 MB lost due to fragmentation)

                                   Tot time (elapsed)  Avg pause  Max pause
Gen  0     78860 colls,     0 par   32.659s  32.970s     0.0004s    0.0669s
Gen  1      4743 colls,     0 par    3.043s   3.052s     0.0006s    0.0086s

TASKS: 174069 (174065 bound, 4 peak workers (4 total), using -N1)

SPARKS: 0 (0 converted, 0 overflowed, 0 dud, 0 GC'd, 0 fizzled)

INIT    time    0.001s  (  0.001s elapsed)
MUT     time   98.685s  (101.611s elapsed)
GC      time   35.702s  ( 36.022s elapsed)
EXIT    time    0.001s  (  0.007s elapsed)
Total   time  134.388s  (137.640s elapsed)

Alloc rate    878,145,635 bytes per MUT second

Productivity  73.4% of total user, 73.8% of total elapsed

Heap profiling

GHC can tell you where the memory is going:

$ stack build --profile
$ stack exec  -- dejafu-tests +RTS -hc
$ hp2ps -c dejafu-tests.hp

This will produce a graph of memory usage over time, as a postscript file, broken down by cost-centre which produced the data. There are a few different views:

  • -hm breaks down the graph by module
  • -hd breaks down the graph by closure description
  • -hy breaks down the graph by type

I typically find -hd and -hy most useful. If you're feeling particularly brave, you can try -hr, which is intended to help track down memory leaks caused by unevaluated thunks.

Supported GHC Versions

Déjà Fu supports the latest four GHC releases, at least. For testing purposes, we use Stackage snapshots as a proxy for GHC versions. The currently supported versions are:

GHCStackagebase
9.6Nightly 2021-07-014.18.0.0
9.4LTS 21.04.17.0.0
9.2LTS 20.04.16.0.0
9.0LTS 19.04.15.0.0
8.1,LTS 17.04.14.1.0
8.8LTS 15.04.13.0.0
8.6LTS 14.04.12.0.0
8.4LTS 12.04.11.0.0
8.2LTS 10.04.10.1.0

In practice, we may compile with older versions of GHC, but keeping them working is not a priority.

Adding new GHC releases

When a new version of GHC is released, we need to make some changes for everything to go smoothly. In general, these changes should only cause a patch level version bump.

  1. Bump the upper bound of base and set up any needed conditional compilation
  2. Add the GHC and base versions to the table.
  3. Remove any unsupported versions from the table.
  4. Make a patch release.

A new GHC release won't get a Stackage snapshot for little while. When it does:

  1. Add the snapshot to the GitHub Actions configuration.
  2. Update the resolver in the stack.yaml.
  3. Put the snapshot in the table.

Dropping old GHC releases

When we want to drop an unsupported version of GHC, we need to bump the version bound on base to preclude it. This is a backwards-incompatible change which causes a major version bump.

  1. Remove the dropped GHC version from the GitHub Actions configuration.
  2. Bump the lower bound of base.
  3. Look through the other dependencies. Some may not work with our new lower bound on base, so we should bump those too.
  4. Remove any now-irrelevant conditional compilation (mostly CPP, but there may also be some cabal file bits).
  5. Make whatever change required the bump.
  6. Make a major release.

GHC versions shouldn't be dropped just because we can, but here are some good reasons to do it:

  • We want to bump the lower bounds of a dependency to a version which doesn't support that GHC.
  • We want to add a new dependency which doesn't support that GHC.
  • The conditional compilation needed to keep that GHC working is getting confusing.

Release Process

Warning

If it's early in the year, make sure you put down the right year in the CHANGELOG!

  1. Figure out what the next version number is. See the PVP_ page if unsure.

  2. Update version numbers in the relevant cabal files:

    • Update the version field
    • Update the tag in the source-repository block
  3. Fill in all @since unreleased Haddock comments with the relevant version number.

  4. Update version numbers in the tables in the README page.

  5. Ensure the relevant CHANGELOG files have all the entries they should.

  6. Add the release information to the relevant CHANGELOG files:

    • Change the unreleased title to the version number
    • Add the current date
    • Add the git tag name
    • Add the Hackage URL
    • Add the contributors list
  7. Commit.

  8. Push to GitHub and wait for GitHub Actions to confirm everything is OK. If it's not OK, fix what is broken before continuing.

  9. Merge the PR.

  10. Tag the merge commit. Tags are in the form <package>-<version>, and the message is the changelog entry.

  11. Push tags to GitHub.

When the merge commit successfully builds on master the updated packages will be pushed to Hackage by Concourse.

Pro tips

  • If a release would have a combination of breaking and non-breaking changes, if possible make two releases: the non-breaking ones first, and then a major release with the breaking ones.

    This makes it possible for users who don't want the breaking changes to still benefit from the non-breaking improvements.

  • Before uploading to Hackage, check you have no changes to the files (for example, temporarily changing the GHC options, or adding trace calls, for debugging reasons).

    stack upload will upload the files on the disk, not the files in version control, so your unwanted changes will be published!

Release Notes

This project is versioned according to the PVP, the de facto standard Haskell versioning scheme.

1.11.0.3 (2023-06-17)

Miscellaneous

1.11.0.2 (2021-08-15)

Miscellaneous

  • Remove reference to freenode in README.

1.11.0.1 (2021-03-14)

Fixed

  • (issue #334) Compilation error under GHC 9 due to use of const.

1.11.0.0 (2020-05-14)

Contributors: mitchellwrosen (pull request #319).

Added

  • (issue #316) Control.Monad.Conc.Class.unsafeUnmask.
  • Control.Monad.Conc.Class.interruptible.

1.10.0.0 (2020-05-10)

Added

  • (issue #312) Control.Monad.Conc.Class.getMaskingState.

1.9.0.0 (2020-02-26)

Changed

  • (issue #286) Pulled in changes from stm-2.5.0.0 package:

    • Changed newTBQueue to accept Natural as a size.
    • Changed lengthTBQueue to return a Natural.

1.8.1.0 (2019-11-16)

Added

  • (issue #303) Control.Monad.Conc.Class.newTVarConc, with a default implementation of atomically . newTVar.

1.8.0.0 (2019-10-04)

Added

  • MonadFail instances for Control.Monad.Conc.Class.IsConc and Control.Monad.STM.IsSTM.

Changed

  • Added MonadFail constraints to Control.Concurrent.Classy.QSem.newQSem and Control.Concurrent.Classy.QSemN.newQSemN.

Miscellaneous

  • Fixed a compilation error with GHC 8.8

1.7.0.0 (2019-03-24)

Added

  • The Control.Monad.Conc.Class.supportsBoundThreads function, like rtsSupportsBoundThreads but returns a monadic result.

Deprecated

  • Control.Monad.Conc.Class.rtsSupportsBoundThreads, in favour of supportsBoundThreads.

1.6.2.0 (2018-11-28)

Contributors: gip (pull request #289).

Added

1.6.1.0 (2018-09-23)

Added

  • (issue #286) Copy across additions from the stm package:

    • Control.Concurrent.Classy.STM.TQueue.flushTQueue
    • Control.Concurrent.Classy.STM.TBQueue.flushTBQueue
    • Control.Concurrent.Classy.STM.TBQueue.lengthTBQueue
    • Control.Concurrent.Classy.STM.TVar.stateTVar
  • (issue #287) The Control.Concurrent.Classy.STM.TSem module.

Changed

  • (issue #286) Copy across changes from the stm package:

    • Make definition of readTQueue consistent with readTBQueue
    • Performance improvements to peekTQueue and peekTBQueue.

Miscellaneous

  • The upper bound on stm is <2.6.

1.6.0.0 - IORefs (2018-07-01)

Added

  • Control.Concurrent.Classy.CRef, deprecated *CRef functions and a CRef alias.

Changed

  • (issue #274) CRef is now IORef: all functions, modules, and types have been renamed.

1.5.0.0 - No More 7.10 (2018-03-28)

Added

Changed

  • (issue #132) Control.Monad.Conc.Class.fork, forkOn, forkOS, and forkOSN are top-level definitions.

Miscellaneous

1.4.0.2 (2018-03-11)

Miscellaneous

1.4.0.1 (2018-02-26)

Miscellaneous

1.4.0.0 (2018-01-19)

Changed

  • Control.Monad.Conc.Class.peekTicket' has a more concrete type, to make deriving newtype instances of MonadConc possible:

    • Old: MonadConc m => proxy m -> Ticket m a -> a
    • New: MonadConc m => Proxy m -> Ticket m a -> a

1.3.0.0 - The Bound Thread Release (2017-12-23)

Note: bound threads are only supported if you compile with GHC and link with -threaded.

Added

  • (pull request #145) Bound thread variants of the withAsync functions:

    • Control.Concurrent.Classy.Async.asyncBound
    • Control.Concurrent.Classy.Async.asyncBoundN
    • Control.Concurrent.Classy.Async.withAsyncBound
    • Control.Concurrent.Classy.Async.withAsyncBoundN
  • (pull request #145) Bound thread functions in MonadConc:

    • Control.Monad.Conc.Class.forkOS
    • Control.Monad.Conc.Class.forkOSN
    • Control.Monad.Conc.Class.isCurrentThreadBound
  • (pull request #145) Helper functions for bound threads:

    • Control.Monad.Conc.Class.runInBoundThread
    • Control.Monad.Conc.Class.runInUnboundThread

Changed

  • (pull request #145) Control.Monad.Conc.Class.rtsSupportsBoundThreads is a re-export from Control.Concurrent.

1.2.3.0 (2017-11-30)

Added

  • (issue #148) Named thread variants of the withAsync functions:

    • Control.Concurrent.Classy.Async.withAsyncN
    • Control.Concurrent.Classy.Async.withAsyncOnN
    • Control.Concurrent.Classy.Async.withAsyncWithUnmaskN
    • Control.Concurrent.Classy.Async.withAsyncOnWithUnmaskN

1.2.2.0 (2017-11-05)

Added

  • (issue #144) IsConc and IsSTM wrapper types:

    • Control.Monad.Conc.Class.IsConc (constructor unexported)
    • Control.Monad.Conc.Class.toIsConc
    • Control.Monad.Conc.Class.fromIsConc
    • Control.Monad.STM.Class.IsSTM (constructor unexported)
    • Control.Monad.STM.Class.toIsSTM
    • Control.Monad.STM.Class.fromIsSTM

Changed

  • Control.Monad.Conc.Class.modifyCRefCAS_ for transformer instances delegates to the underlying monad, rather than using the default definition in terms of modifyCRefCAS.

1.2.1.2 (2017-10-14)

Fixed

  • (issue #134) Control.Monad.Conc.Class.forkWithUnmask and forkOnWithUnmask for the IO instance does not infinitely loop (bug introduced in concurrency-1.2.1.1).

1.2.1.1 (2017-10-11)

Changed

  • Named threads for IO are implemented with GHC.Conc.labelThread.

1.2.1.0 (2017-10-02)

Added

  • (pull request #125) Named thread variants of the async functions:

    • Control.Concurrent.Classy.Async.asyncN
    • Control.Concurrent.Classy.Async.asyncOnN
    • Control.Concurrent.Classy.Async.asyncWithUnmaskN
    • Control.Concurrent.Classy.Async.asyncOnWithUnmaskN

1.2.0.0 (2017-09-16)

Changed

  • MonadPlus is a superclass of MonadSTM.
  • Control.Monad.STM.Class.orElse is a top-level alias for mplus.
  • Control.Monad.STM.Class.retry is a top-level alias for mzero.

1.1.2.1 (2017-06-07)

Changed

  • Control.Concurrent.Classy.MVar.isEmptyMVar does not briefly empties the MVar, and does not block.

1.1.2.0 (2017-04-05)

Added

  • Missing functions copied from async:

    • Control.Concurrent.Classy.Async.uninterruptibleCancel
    • Control.Concurrent.Classy.Async.replicateConcurrently
    • Control.Concurrent.Classy.Async.concurrently_
    • Control.Concurrent.Classy.Async.mapConcurrently_
    • Control.Concurrent.Classy.Async.forConcurrently_
    • Control.Concurrent.Classy.Async.replicateConcurrently_
  • Control.Concurrent.Classy.Async.Concurrently has a Semigroup instance when built with base >= 4.9.

  • Control.Concurrent.Classy.Async.Concurrently has a Monoid instance.

  • Control.Monad.Conc.Class re-exports Control.Monad.Catch.mask_ and uninterruptibleMask_.

Changed

  • (pull request #77) To match changes in async, Control.Concurrent.Classy.Async.cancel and withAsync block until the Async is killed.

Miscellaneous

  • Every definition, class, and instance now has a Haddock @since annotation.

1.1.1.0 - The Async Release (2017-03-04)

Added

  • The Control.Concurrent.Classy.Async module.

1.1.0.0 (2017-02-21)

Added

  • Control.Monad.Conc.Class.tryReadMVar

Removed

  • Control.Monad.Conc.Class._concMessage

1.0.0.0 - The Initial Release (2016-09-10)

Added

  • Everything.

Release Notes

This project is versioned according to the PVP, the de facto standard Haskell versioning scheme.

2.4.0.6 (2024-12-11)

Contributors: telser (pull request #417).

Miscellaneous

  • Update documentation link in Test.DejaFu.
  • Fix GHC compatibility warning.
  • The upper bound on containers is <0.8.

2.4.0.5 (2023-06-17)

Miscellaneous

2.4.0.4 (2022-08-22)

Miscellaneous

  • Update doctest examples in Test.DejaFu.
  • The upper bound on leancheck is <2.

2.4.0.3 (2021-08-15)

Miscellaneous

  • Remove reference to freenode in README.

2.4.0.2 (2021-03-14)

Fixed

  • (issue #334) Compilation error under GHC 9 due to use of const.

2.4.0.1 (2020-12-28)

Fixed

  • (issue #331) Initial TVar values from setup actions are now restored for subsequent executions.

2.4.0.0 (2020-07-01)

Added

  • Thread action constructor for STM transactions which throw an exception: Test.DejaFu.Types.ThreadAction ThrownSTM

Changed

  • Test.DejaFu.Types.ThreadAction, Throw, and ThrowTo now include the resultant masking state, and no bool.

Fixed

  • (issue #324) Jumping out of a restored mask into an exception handler now atomically restores the masking state.

2.3.0.1 (2020-06-24)

Miscellaneous

  • The upper bound on random is <1.3.

2.3.0.0 (2020-05-14)

Miscellaneous

2.2.0.0 (2020-05-10)

Added

  • Thread action constructors for the MonadConc getMaskingState function:

    • Test.DejaFu.Types.ThreadAction, GetMaskingState
    • Test.DejaFu.Types.Lookahead, WillGetMaskingState

Miscellaneous

2.1.0.3 (2020-02-29)

Fixed

  • Fixed an internal error message.

2.1.0.2 (2020-02-29)

Miscellaneous

2.1.0.1 (2019-10-04)

Miscellaneous

  • Fixed a compilation error with GHC 8.8
  • The upper version bound on concurrency is <1.9.

2.1.0.0 (2019-03-24)

Added

  • The Test.DejaFu.Types.MonadDejaFu typeclass, containing the primitives needed to run a concurrent program. There are instances for:

    • IO, which is probably the MonadConc instance people used previously, so there is no breaking change there.
    • CatchT (ST t), meaning that concurrent programs can be run without IO once more.
  • Thread action constructors for MonadConc supportsBoundThreads function:

    • Test.DejaFu.Types.ThreadAction, SupportsBoundThreads
    • Test.DejaFu.Types.Lookahead, WillSupportsBoundThreads

Changed

  • Many functions which had a MonadConc constraint now have a MonadDejaFu constraint:

    • In Test.DejaFu

      • autocheck
      • autocheckWay
      • autocheckWithSettings
      • dejafu
      • dejafuWay
      • dejafuWithSettings
      • dejafus
      • dejafusWay
      • dejafusWithSettings
      • runTest
      • runTestWay
      • runTestWithSettings
    • In Test.DejaFu.Conc

      • runConcurrent
      • recordSnapshot
      • runSnapshot
    • In Test.DejaFu.SCT

      • runSCT
      • resultsSet
      • runSCT'
      • resultsSet'
      • runSCTWithSettings
      • resultsSetWithSettings
      • runSCTWithSettings'
      • resultsSetWithSettings'

Miscellaneous

2.0.0.1 (2019-03-14)

Fixed

  • (issue #267) Throwing an asynchronous exception to the current thread interrupts the current thread even if it is masked.

2.0.0.0 (2019-02-12)

Added

  • The Program types and their constructors (re-exported from Test.DejaFu):

    • Test.DejaFu.Conc.Program
    • Test.DejaFu.Conc.Basic
    • Test.DejaFu.Conc.WithSetup
    • Test.DejaFu.Conc.WithSetupAndTeardown
    • Test.DejaFu.Conc.withSetup
    • Test.DejaFu.Conc.withTeardown
    • Test.DejaFu.Conc.withSetupAndTeardown
  • The Invariant type and associated functions (re-exported from Test.DejaFu):

    • Test.DejaFu.Conc.Invariant
    • Test.DejaFu.Conc.registerInvariant
    • Test.DejaFu.Conc.inspectIORef
    • Test.DejaFu.Conc.inspectMVar
    • Test.DejaFu.Conc.inspectTVar
  • New snapshotting functions:

    • Test.DejaFu.Conc.Snapshot
    • Test.DejaFu.Conc.recordSnapshot
    • Test.DejaFu.Conc.runSnapshot
  • Test.DejaFu.Settings.llengthBound, which now applies to all ways of testing.

  • Test.DejaFu.Types.isInvariantFailure (re-exported from Test.DejaFu).

  • Test.DejaFu.runTestWithSettings function.

  • A simplified form of the concurrency state:

    • Test.DejaFu.Types.ConcurrencyState
    • Test.DejaFu.Types.isBuffered
    • Test.DejaFu.Types.numBuffered
    • Test.DejaFu.Types.isFull
    • Test.DejaFu.Types.canInterrupt
    • Test.DejaFu.Types.canInterruptL
    • Test.DejaFu.Types.isMaskedInterruptible
    • Test.DejaFu.Types.isMaskedUninterruptible

Changed

  • Test.DejaFu.Schedule.Scheduler has a ConcurrencyState parameter.

  • Test.DejaFu.alwaysSameBy and Test.DejaFu.notAlwaysSameBy return a representative trace for each unique condition.

  • Functions which took a ConcT now take a Program pty:

    • Test.DejaFu.autocheck
    • Test.DejaFu.autocheckWay
    • Test.DejaFu.autocheckWithSettings
    • Test.DejaFu.dejafu
    • Test.DejaFu.dejafuWay
    • Test.DejaFu.dejafuWithSettings
    • Test.DejaFu.dejafus
    • Test.DejaFu.dejafusWay
    • Test.DejaFu.dejafusWithSettings
    • Test.DejaFu.runTest
    • Test.DejaFu.runTestWay
    • Test.DejaFu.runTestWithSettings
    • Test.DejaFu.Conc.runConcurrent
    • Test.DejaFu.SCT.runSCT
    • Test.DejaFu.SCT.resultsSet
    • Test.DejaFu.SCT.runSCT'
    • Test.DejaFu.SCT.resultsSet'
    • Test.DejaFu.SCT.runSCTWithSettings
    • Test.DejaFu.SCT.resultsSetWithSettings
    • Test.DejaFu.SCT.runSCTWithSettings'
    • Test.DejaFu.SCT.resultsSetWithSettings'
  • Test.DejaFu.Conc.ConcT is an alias for Program Basic.

  • Test.DejaFu.Types.Bounds:

    • Removed boundLength field.
  • Test.DejaFu.Types.Condition:

    • Added InvariantFailure constructor
    • Removed STMDeadlock constructor
  • Test.DejaFu.Types.Error:

    • Removed NestedSubconcurrency, MultithreadedSubconcurrency, and LateDontCheck constructors.
  • Test.DejaFu.Types.Lookahead:

    • Added WillRegisterInvariant constructor
    • Removed WillSubconcurrency, WillStopSubconcurrency, and WillDontCheck constructors
  • Test.DejaFu.Types.ThreadAction:

    • Added RegisterInvariant constructor
    • Removed Subconcurrency, StopSubconcurrency, and DontCheck constructors

Removed

  • The deprecated functions:

    • Test.DejaFu.dejafuDiscard
    • Test.DejaFu.SCT.runSCTDiscard
    • Test.DejaFu.SCT.runSCTDiscard'
    • Test.DejaFu.SCT.resultsSetDiscard
    • Test.DejaFu.SCT.resultsSetDiscard'
    • Test.DejaFu.SCT.sctBound
    • Test.DejaFu.SCT.sctBoundDiscard
    • Test.DejaFu.SCT.sctUniformRandom
    • Test.DejaFu.SCT.sctUniformRandomDiscard
    • Test.DejaFu.SCT.sctWeightedRandom
    • Test.DejaFu.SCT.sctWeightedRandomDiscard
  • The deprecated type Test.DejaFu.Types.Failure

  • Old snapshotting functions:

    • Test.DejaFu.Conc.DCSnapshot
    • Test.DejaFu.Conc.runForDCSnapshot
    • Test.DejaFu.Conc.runWithDCSnapshot
    • Test.DejaFu.Conc.canDCSnapshot
    • Test.DejaFu.Conc.threadsFromDCSnapshot
  • Test.DejaFu.Conc.dontCheck

  • Test.DejaFu.Conc.subconcurrency

  • Test.DejaFu.Settings.defaultLengthBound

  • Test.DejaFu.Types.isIncorrectUsage

1.12.0.0 (2019-01-20)

Added

  • Test.DejaFu.Types.Error for internal errors and misuses, with predicates:

    • Test.DejaFu.Types.isSchedulerError
    • Test.DejaFu.Types.isIncorrectUsage
  • Deprecated Test.DejaFu.Types.Failure type synonym for Condition.

  • The Test.DejaFu.Settings.lshowAborts option, to make SCT functions show Abort conditions.

  • Test.DejaFu.Utils.showCondition

Changed

  • Renamed Test.DejaFu.Types.Failure to Test.DejaFu.Types.Condition.
  • The SCT functions drop Left Abort results by default, restore the old behaviour with Test.DejaFu.Settings.lshowAborts.

Removed

  • Test.DejaFu.Types.isInternalError
  • Test.DejaFu.Types.isIllegalDontCheck
  • Test.DejaFu.Types.isIllegalSubconcurrency
  • Test.DejaFu.Utils.showFail

1.11.0.5 (2019-01-17)

Miscellaneous

1.11.0.4 (2018-12-02)

Contributors: pepeiborra (pull request #290).

Miscellaneous

1.11.0.3 (2018-07-15)

Fixed

  • (issue #275) In trace simplification, only remove a commit if there are no other buffered writes for that same IORef.

1.11.0.2 (2018-07-08)

Miscellaneous

1.11.0.1 (2018-07-02)

Miscellaneous

1.11.0.0 - IORefs (2018-07-01)

Changed

  • (issue #274) CRef is now IORef: all functions, data constructors, and types have been renamed.
  • The lower bound on concurrency is 1.6.

1.10.1.0 (2018-06-17)

Added

  • (issue #224) The Test.DejaFu.Settings.lsafeIO option, for when all lifted IO is thread-safe (such as exclusively managing thread-local state).

1.10.0.0 (2018-06-17)

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)

Added

  • A Test.DejaFu.successful predicate, to check that a computation never fails.

1.9.0.0 (2018-06-10)

Changed

  • (issue #190) Test.DejaFu.Types.Throw and ThrowTo have a Bool parameter, which is True if the exception kills the thread.

1.8.0.0 (2018-06-03)

Changed

  • (issue #258) Length bounding is disabled by default. This is not a breaking API change, but it is a breaking semantics change.

1.7.0.0 (2018-06-03)

Changed

  • (issue #237) Test.DejaFu.SCT.sctWeightedRandom and sctWeightedRandomDiscard no longer take the number of executions to use the same weights for as a parameter.

Removed

  • (issue #237) The deprecated function Test.DejaFu.Settings.swarmy.

1.6.0.0 (2018-05-11)

Removed

  • The deprecated module Test.DejaFu.Defaults.

1.5.1.0 (2018-03-29)

Added

  • (issue #210) Test.DejaFu.Types.Weaken and Strengthen newtype wrappers around discard functions, with Semigroup, Monoid, Contravariant, and Divisible instances corresponding to weakenDiscard and strengthenDiscard.

1.5.0.0 - No More 7.10 (2018-03-28)

Miscellaneous

1.4.0.0 (2018-03-17)

Changed

  • (issue #201) Test.DejaFu.Conc.ConcT r n a drops its r parameter, becoming ConcT n a.
  • (issue #201) All functions drop the MonadConc constraint.

Removed

  • (issue #201) The MonadRef and MonadAtomicRef instances for Test.DejaFu.Conc.ConcT.
  • (issue #198) The Test.DejaFu.Types.Killed thread action, which was unused.

Fixed

  • (issue #250) Add missing dependency for throwTo actions.

1.3.2.0 (2018-03-12)

Added

  • (issue #183) SCT settings for trace simplification:

    • Test.DejaFu.Settings.lequality
    • Test.DejaFu.Settings.lsimplify
  • (pull request #248) Test.DejaFu.Utils.toTIdTrace to extract thread IDs from a trace.

  • (pull request #248) SCT setting to make some recoverable errors fatal: Test.DejaFu.Settings.ldebugFatal

Performance

  • (pull request #248) Prune some unnecessary interleavings of CRef actions in systematic testing when using sequential consistency.

1.3.1.0 (2018-03-11)

Added

  • (pull request #246) Generic instances for:

    • Test.DejaFu.Types.ThreadId
    • Test.DejaFu.Types.CRefId
    • Test.DejaFu.Types.MVarId
    • Test.DejaFu.Types.TVarId
    • Test.DejaFu.Types.Id
    • Test.DejaFu.Types.ThreadAction
    • Test.DejaFu.Types.Lookahead
    • Test.DejaFu.Types.TAction
    • Test.DejaFu.Types.Decision
    • Test.DejaFu.Types.Failure
    • Test.DejaFu.Types.Bounds
    • Test.DejaFu.Types.PreemptionBound
    • Test.DejaFu.Types.FairBound
    • Test.DejaFu.Types.LengthBound
    • Test.DejaFu.Types.Discard
    • Test.DejaFu.Types.MemType
    • Test.DejaFu.Types.MonadFailException
  • (pull request #246) NFData instance for Test.DejaFu.Types.MonadFailException

Fixed

  • (issue #199) Missing cases in the NFData instances for Test.DejaFu.Types.ThreadAction and TAction

1.3.0.3 (2018-03-11)

Miscellaneous

1.3.0.2 (2018-03-11)

Fixed

1.3.0.1 (2018-03-08)

Fixed

1.3.0.0 (2018-03-06)

Deprecated

1.2.0.0 - The Settings Release (2018-03-06)

Contributors: qrilka (pull request #236).

Added

  • (pull request #238) A record-based approach to SCT configuration:

    • Test.DejaFu.Settings (re-exported from Test.Dejafu and Test.DejaFu.SCT)

    • Test.DejaFu.Settings.Settings

    • Test.DejaFu.Settings.defaultSettings

    • Test.DejaFu.Settings.fromWayAndMemType

    • Lenses:

      • Test.DejaFu.Settings.lway
      • Test.DejaFu.Settings.lmemtype
      • Test.DejaFu.Settings.ldiscard
      • Test.DejaFu.Settings.learlyExit
      • Test.DejaFu.Settings.ldebugShow
      • Test.DejaFu.Settings.ldebugPrint
    • Lens helpers:

      • Test.DejaFu.Settings.get
      • Test.DejaFu.Settings.set
    • Runners:

      • Test.DejaFu.SCT.runSCTWithSettings
      • Test.DejaFu.SCT.runSCTWithSettings'
      • Test.DejaFu.SCT.resultsSetWithSettings
      • Test.DejaFu.SCT.resultsSetWithSettings'
  • (pull request #238) Settings-based test functions:

    • Test.DejaFu.autocheckWithSettings
    • Test.DejaFu.dejafuWithSettings
    • Test.DejaFu.dejafusWithSettings
    • Test.DejaFu.runTestWithSettings

Deprecated

  • (pull request #238) SCT function variants:

    • Test.DejaFu.SCT.runSCTDiscard
    • Test.DejaFu.SCT.resultSetDiscard
    • Test.DejaFu.SCT.runSCTDiscard'
    • Test.DejaFu.SCT.resultSetDiscard'
    • Test.DejaFu.SCT.sctBound
    • Test.DejaFu.SCT.sctBoundDiscard
    • Test.DejaFu.SCT.sctUniformRandom
    • Test.DejaFu.SCT.sctUniformRandomDiscard
    • Test.DejaFu.SCT.sctWeightedRandom
    • Test.DejaFu.SCT.sctWeightedRandomDiscard
  • (pull request #238) The Test.DejaFu.Defaults module. Import Test.DejaFu.Settings instead.

  • (pull request #238) Test.DejaFu.dejafuDiscard.

Removed

  • (pull request #238) Test.DejaFu.Defaults.defaultDiscarder, as the discard function is optional.

1.1.0.2 (2018-03-01)

Miscellaneous

  • (pull request #235) The documentation for Test.DejaFu.Conc.dontCheck and subconcurrency clarify that an illegal use does not necessarily cause a failing test.

1.1.0.1 (2018-02-26)

Contributors: qrilka (pull request #229).

Miscellaneous

1.1.0.0 (2018-02-22)

Contributors: qrilka (pull request #228).

Added

  • (pull request #219) The testing-only Test.DejaFu.Conc.dontCheck function, and associated definitions:

    • Test.DejaFu.Types.DontCheck
    • Test.DejaFu.Types.WillDontCheck
    • Test.DejaFu.Types.IllegalDontCheck
    • Test.DejaFu.Types.isIllegalDontCheck
  • (pull request #219) A snapshotting approach based on Test.DejaFu.Conc.dontCheck:

    • Test.DejaFu.Conc.runForDCSnapshot
    • Test.DejaFu.Conc.runWithDCSnapshot
    • Test.DejaFu.Conc.canDCSnapshot
    • Test.DejaFu.Conc.threadsFromDCSnapshot

Changed

  • (pull request #219) SCT functions automatically use the snapshotting mechanism when possible.

1.0.0.2 (2018-02-18)

Contributors: qrilka (pull request #214).

Changed

  • (issue #193) Deterministically assign commit thread IDs.

Fixed

  • (issue #189) Remove an incorrect optimisation in systematic testing for getNumCapabilities and setNumCapabilities.
  • (issue #204) Fix missed interleavings in systematic testing with some uses of STM.
  • (issue #205) Fix forkOS being recorded in an execution trace as if it were a fork.

Miscellaneous

1.0.0.1 (2018-01-19)

Miscellaneous

1.0.0.0 - The API Friendliness Release (2017-12-23)

Added

  • Test.DejaFu.alwaysSameOn and alwaysSameBy predicate helpers.

  • Test.DejaFu.SCT.strengthenDiscard and weakenDiscard functions to combine discard functions.

  • (issue #124) The Test.DejaFu.ProPredicate type, which contains both an old-style Predicate and a discard function. It is also a Profunctor, parameterised by the input and output types.

  • (issue #124) Test.DejaFu.alwaysNothing and somewhereNothing predicate helpers, like alwaysTrue and somewhereTrue, to lift regular functions into a ProPredicate.

  • (issue #137) The Test.DejaFu.Types.Id type.

  • (pull request #145) Thread action and lookahead values for bound threads:

    • Test.DejaFu.Types.ForkOS
    • Test.DejaFu.Types.IsCurrentThreadBound
    • Test.DejaFu.Types.WillForkOS
    • Test.DejaFu.Types.WillIsCurrentThreadBound
  • (issue #155) Test.DejaFu.Types and Test.DejaFu.Utils modules, each containing some of what was in Test.DejaFu.Common.

Changed

  • All testing functions require MonadConc, MonadRef, and MonadIO constraints. Testing with ST is no longer possible.
  • The Test.DejaFu.alwaysSame predicate helper gives the simplest trace leading to each distinct result.
  • The MonadIO Test.DejaFu.Conc.ConcIO instance is now the more general MonadIO n => MonadIO (ConcT r n).
  • (issue #121) The chosen thread is no longer redundantly included in trace lookahead.
  • (issue #123) All testing functions in Test.DejaFu take the action to run as the final parameter.
  • (issue #124) All testing functions in Test.DejaFu have been generalised to take a ProPredicate instead of a Predicate.
  • (issue #124) The Test.DejaFu.Predicate type is an alias for ProPredicate a a.
  • (issue #124) The Test.DejaFu.Result type no longer includes a number of cases checked.
  • (issue #137) The Test.DejaFu.Types.ThreadId, CRefId, MVarId, and TVarId types are now wrappers for an Id.
  • (pull request #145) If built with the threaded runtime, the main thread in a test is executed as a bound thread.
  • (issue #155) The Test.DejaFu.SCT.Discard type is defined in Test.DejaFu.Types, and re-exported from Test.DejaFu.SCT.
  • (issue #155) The Test.DejaFu.Schedule.tidOf and decisionOf functions are defined in Test.DejaFu.Utils, but not re-exported from Test.DejaFu.Schedule.

Removed

  • The IO specific testing functions:

    • Test.DejaFu.autocheckIO
    • Test.DejaFu.dejafuIO
    • Test.DejaFu.dejafusIO
    • Test.DejaFu.autocheckWayIO
    • Test.DejaFu.dejafuWayIO
    • Test.DejaFu.dejafusWayIO
    • Test.DejaFu.dejafuDiscardIO
    • Test.DejaFu.runTestM
    • Test.DejaFu.runTestWayM
  • The Test.DejaFu.Conc.ConcST type alias.

  • The MonadBaseControl IO Test.DejaFu.Conc.ConcIO typeclass instance.

  • The Test.DejaFu.alwaysTrue2 function, which had confusing behaviour.

  • The Test.DejaFu.Common.TTrace type synonym for [TAction].

  • The Test.DejaFu.Common.preEmpCount function.

  • Re-exports of Decision and NonEmpty from Test.DejaFu.Schedule.

  • (issue #155) The Test.DejaFu.Common and Test.DejaFu.STM modules.

Fixed

  • In refinement property testing, a blocking interference function is not reported as a deadlocking execution.

Performance

  • (issue #124) Passing tests should use substantially less memory.
  • (issue #168) Prune some unnecessary interleavings of MVar actions in systematic testing.

Miscellaneous

0.9.1.2 (2017-12-12)

Miscellaneous

0.9.1.1 (2017-12-08)

Fixed

  • (issue #160) Fix an off-by-one issue with nested masks during systematic testing.

0.9.1.0 (2017-11-26)

Added

  • MonadFail instance for Test.DejaFu.Conc.ConcT.
  • MonadFail instance for Test.DejaFu.STM.STMLike.

Changed

  • Pretty-printed traces display a pre-emption following a yield with a little "p".

Fixed

  • Some incorrect Haddock @since comments.

0.9.0.3 (2017-11-06)

Fixed

  • (issue #138) Fix missed interleavings in systematic testing with some relaxed memory programs.

0.9.0.2 (2017-11-02)

Changed

  • A fair bound of 0 prevents yielding or delaying.

Performance

  • Prune some unnecessary interleavings of STM transactions in systematic testing.

0.9.0.1 (2017-10-28)

Fixed

  • (issue #139) Fix double pop of exception handler stack.

0.9.0.0 (2017-10-11)

Added

  • Failure predicates (also exported from Test.DejaFu):

    • Test.DejaFu.Common.isAbort
    • Test.DejaFu.Common.isDeadlock
    • Test.DejaFu.Common.isIllegalSubconcurrency
    • Test.DejaFu.Common.isInternalError
    • Test.DejaFu.Common.isUncaughtException
  • Thread action and lookahead values for threadDelay:

    • Test.DejaFu.Common.ThreadDelay
    • Test.DejaFu.Common.WillThreadDelay

Changed

  • The UncaughtException constructor for Test.DejaFu.Common.Failure now includes the exception value.
  • Uses of threadDelay are no longer reported in the trace as a use of yield.

Removed

  • The Bounded, Enum, and Read instances for Test.DejaFu.Common.Failure.

0.8.0.0 (2017-09-26)

Changed

  • (issue #80) STM traces now include the ID of a newly-created TVar.
  • (issue #106) Schedulers are not given the execution trace so far.
  • (issue #120) Traces only include a single action of lookahead.
  • (issue #122) The Test.DejaFu.Scheduler.Scheduler type is now a newtype, rather than a type synonym.

0.7.3.0 (2017-09-26)

Added

  • The Test.DejaFu.Common.threadNames function.

Fixed

  • (issue #101) Named threads which are only started by a pre-emption are shown in the pretty-printed trace key.
  • (issue #118) Escaping a mask by raising an exception correctly restores the masking state (#118).

0.7.2.0 (2017-09-16)

Added

  • Alternative and MonadPlus instances for Test.DejaFu.STM.STM.

Fixed

  • The Eq and Ord instances for Test.DejaFu.Common.ThreadId, CRefId, MVarId, and TVarId are consistent.

Miscellaneous

0.7.1.3 (2017-09-08)

Fixed

  • (issue #111) Aborted STM transactions are correctly rolled back.

Performance

  • (issue #105) Use a more efficient approach for an internal component of the systematic testing.

0.7.1.2 (2017-08-21)

Fixed

  • (issue #110) Errors thrown with Control.Monad.fail are correctly treated as asynchronous exceptions.

0.7.1.1 (2017-08-16)

Performance

  • (issue #64) Greatly reduce memory usage in systematic testing when discarding traces by using an alternative data structure.

    • Old: O(max trace length * number of executions)
    • New: O(max trace length * number of traces kept)

0.7.1.0 - The Discard Release (2017-08-10)

Added

  • (issue #90) A way to selectively discard results or traces:

    • Type: Test.DejaFu.SCT.Discard
    • Functions: Test.DejaFu.SCT.runSCTDiscard, resultsSetDiscard, sctBoundDiscard, sctUniformRandomDiscard, and sctWeightedRandomDiscard.
  • (issue #90) Discarding variants of the testing functions:

    • Test.DejaFu.dejafuDiscard
    • Test.DejaFu.dejafuDiscardIO
  • (issue #90) Test.DejaFu.Defaults.defaultDiscarder.

Performance

  • (issue #90) The Test.DejaFu.SCT.resultsSet and resultsSet' functions discard traces as they are produced, rather than all at the end.

0.7.0.2 (2017-06-12)

Changed

  • Remove unnecessary typeclass constraints from Test.DejaFu.Refinement.check, check', checkFor, and counterExamples.

Miscellaneous

0.7.0.1 (2017-06-09)

Performance

  • The Test.DejaFu.Refinement.check, check', and checkFor functions no longer need to compute all counterexamples before showing only one.
  • The above and counterExamples are now faster even if there is only a single counterexample in some cases.

0.7.0.0 - The Refinement Release (2017-06-07)

Added

  • The Test.DejaFu.Refinement module, re-exported from Test.DejaFu.

  • The Test.DejaFu.SCT.sctUniformRandom function for SCT via random scheduling.

  • Smart constructors for Test.DejaFu.SCT.Way (also re-exported from Test.DejaFu):

    • Test.DejaFu.SCT.systematically, like the old Systematically.
    • Test.DejaFu.SCT.randomly, like the old Randomly.
    • Test.DejaFu.SCT.uniformly, a new uniform (as opposed to weighted) random scheduler.
    • Test.DejaFu.SCT.swarmy, like the old Randomly but which can use the same weights for multiple executions.

Changed

  • The default* values are defined in Test.DejaFu.Defaults and re-exported from Test.DejaFu.
  • The Test.DejaFu.SCT.sctRandom function is now called sctWeightedRandom and can re-use the same weights for multiple executions.

Removed

  • The Test.DejaFu.SCT.Way type is now abstract, so its constructors are no longer exported:

    • Test.DejaFu.SCT.Systematically
    • Test.DejaFu.SCT.Randomly
  • The Test.DejaFu.SCT.sctPreBound, sctFairBound, and sctLengthBound functions.

Fixed

  • (issue #81) Test.DejaFu.Conc.subconcurrency no longer re-uses IDs.

0.6.0.0 (2017-04-08)

Changed

  • The Test.DejaFu.Conc.Conc n r a type is ConcT r n a, and has a MonadTrans instance.
  • The Test.DejaFu.SCT.Way type is a GADT, and does not expose the type parameter of the random generator.

Removed

  • The NFData instance for Test.DejaFu.SCT.Way.

Miscellaneous

  • Test.DejaFu.Common forms part of the public API.
  • Every definition, class, and instance now has a Haddock @since annotation.

0.5.1.3 (2017-04-05)

Miscellaneous

0.5.1.2 (2017-03-04)

Note: this version was misnumbered! It should have caused a minor

: version bump!

Added

  • MonadRef and MonadAtomicRef instances for Test.DejaFu.Conc.Conc using CRef.

Fixed

  • A long-standing bug where if the main thread is killed with a throwTo, the throwing neither appears in the trace nor correctly terminates the execution.

Miscellaneous

0.5.1.1 (2017-02-25)

Fixed

  • Fix using incorrect correct scheduler state after a subconcurrency action.
  • Fix infinite loop in SCT of subconcurrency.

0.5.1.0 (2017-02-25)

Added

  • NFData instances for:

    • Test.DejaFu.Result
    • Test.DejaFu.Common.ThreadId
    • Test.DejaFu.Common.CRefId
    • Test.DejaFu.Common.MVarId
    • Test.DejaFu.Common.TVarId
    • Test.DejaFu.Common.IdSource
    • Test.DejaFu.Common.ThreadAction
    • Test.DejaFu.Common.Lookahead
    • Test.DejaFu.Common.ActionType
    • Test.DejaFu.Common.TAction
    • Test.DejaFu.Common.Decision
    • Test.DejaFu.Common.Failure
    • Test.DejaFu.Common.MemType
    • Test.DejaFu.SCT.Bounds
    • Test.DejaFu.SCT.PreemptionBound
    • Test.DejaFu.SCT.FairBound
    • Test.DejaFu.SCT.LengthBound
    • Test.DejaFu.SCT.Way
    • Test.DejaFu.STM.Result
  • Eq, Ord, and Show instances for Test.DejaFu.Common.IdSource.

  • Strict variants of Test.DejaFu.SCT.runSCT and resultsSet: runSCT' and resultsSet'.

0.5.0.2 (2017-02-22)

Note: this version was misnumbered! It should have caused a major

: version bump!

Added

  • StopSubconcurrency constructor for Test.DejaFu.Common.ThreadAction.

Changed

  • A Test.DejaFu.Common.StopConcurrency action appears in the execution trace immediately after the end of a Test.DejaFu.Conc.subconcurrency action.

Fixed

  • A Test.DejaFu.Conc.subconcurrency action inherits the number of capabilities from the outer computation.

Miscellaneous

  • Test.DejaFu.SCT compiles with MonoLocalBinds enabled (implied by GADTs and TypeFamilies), which may be relevant to hackers.

0.5.0.1 (2017-02-21)

Fixed

  • readMVar is considered a "release action" for the purposes of fair-bounding.

0.5.0.0 - The Way Release (2017-02-21)

Added

  • Eq instances for Test.DejaFu.Common.ThreadAction and Lookahead.

  • Thread action and lookahead values for tryReadMVar:

    • Test.DejaFu.Common.TryReadMVar
    • Test.DejaFu.Common.WillTryReadMVar
  • The testing-only Test.DejaFu.Conc.subconcurrency function.

  • SCT through weighted random scheduling: Test.DejaFu.SCT.sctRandom.

  • The Test.DejaFu.SCT.Way type, used by the new functions runSCT and resultsSet.

Changed

  • All the functions which took a Test.DejaFu.SCT.Bounds now take a Way instead.

Fixed

  • Some previously-missed CRef action dependencies are no longer missed.

Miscellaneous

  • The version bounds on concurrency are 1.1.0.*.
  • A bunch of things were called "Var" or "Ref", these are now consistently "MVar" and "CRef".
  • Significant performance improvements in both time and space.
  • The dpor package has been merged back into this, as it turned out not to be very generally useful.

0.4.0.0 - The Packaging Release (2016-09-10)

Added

  • The Test.DejaFu.runTestM and runTestM' functions.
  • The Test.DejaFu.Conc.runConcurrent function.
  • The Test.DejaFu.STM.runTransaction function.
  • The Test.DejaFu.Common module.

Changed

  • The Control.* modules have all been split out into a separate concurrency package.
  • The Test.DejaFu.Deterministic module has been renamed to Test.DejaFu.Conc.
  • Many definitions from other modules have been moved to the Test.DejaFu.Common module.
  • The Test.DejaFu.autocheck' function takes the schedule bounds as a parameter.
  • The Test.DejaFu.Conc.Conc type no longer has the STM type as a parameter.
  • The ST specific functions in Test.DejaFu.SCT are polymorphic in the monad.
  • The termination of the main thread in execution traces appears as a single Stop, rather than the previous Lift, Stop.
  • Execution traces printed by the helpful functions in Test.DejaFu include a key of thread names.

Removed

  • The Test.DejaFu.runTestIO and runTestIO' functions: use runTestM and runTestM' instead.
  • The Test.DejaFu.Conc.runConcST and runConcIO functions: use runConcurrent instead.
  • The Test.DejaFu.STM.runTransactionST and runTransactionIO functions: use runTransaction instead.
  • The IO specific functions in Test.DejaFu.SCT.

0.3.2.1 (2016-07-21)

Fixed

  • (issue #55) Fix incorrect detection of deadlocks with some nested STM transactions.

0.3.2.0 (2016-06-06)

Fixed

  • (issue #40) Fix missing executions with daemon threads with uninteresting first actions. This is significantly faster with dpor-0.2.0.0.

Performance

  • When using dpor-0.2.0.0, greatly improve dependency inference of exceptions during systematic testing.
  • Improve dependency inference of STM transactions during systematic testing.

0.3.1.1 (2016-05-26)

Miscellaneous

  • Now supports GHC 8.

0.3.1.0 (2016-05-02)

Fixed

  • Fix inaccurate counting of pre-emptions in an execution trace when relaxed memory commit actions are present.

0.3.0.0 (2016-04-03)

The minimum supported version of GHC is now 7.10.

I didn't write proper release notes, and this is so far back I don't really care to dig through the logs.

0.2.0.0 (2015-12-01)

I didn't write proper release notes, and this is so far back I don't really care to dig through the logs.

0.1.0.0 - The Initial Release (2015-08-27)

Added

  • Everything.

Release Notes

This project is versioned according to the PVP, the de facto standard Haskell versioning scheme.

2.0.0.6 (2022-08-30)

Fixed

  • Remove inaccurate comment about Test.HUnit.DejaFu.testDejafus sharing work.

2.0.0.5 (2021-08-15)

Miscellaneous

  • Remove reference to freenode in README.

2.0.0.4 (2020-07-01)

Miscellaneous

  • The upper bound on dejafu is <2.5

2.0.0.3 (2020-05-10)

Miscellaneous

  • The upper bound on dejafu is <2.4

2.0.0.2 (2020-05-10)

Miscellaneous

  • The upper bound on dejafu is <2.3

2.0.0.1 (2019-03-24)

Miscellaneous

  • The upper bound on dejafu is <2.2

2.0.0.0 (2019-02-12)

Added

  • Re-exports for the Program types and their constructors:

    • Test.HUnit.DejaFu.Program
    • Test.HUnit.DejaFu.Basic
    • Test.HUnit.DejaFu.ConcT
    • Test.HUnit.DejaFu.ConcIO
    • Test.HUnit.DejaFu.WithSetup
    • Test.HUnit.DejaFu.WithSetupAndTeardown
    • Test.HUnit.DejaFu.withSetup
    • Test.HUnit.DejaFu.withTeardown
    • Test.HUnit.DejaFu.withSetupAndTeardown
  • Re-exports for the Invariant type and its functions:

    • Test.HUnit.DejaFu.Invariant
    • Test.HUnit.DejaFu.registerInvariant
    • Test.HUnit.DejaFu.inspectIORef
    • Test.HUnit.DejaFu.inspectMVar
    • Test.HUnit.DejaFu.inspectTVar

Changed

  • Functions which took a ConcIO now take a Program pty IO:

    • Test.HUnit.DejaFu.testAuto
    • Test.HUnit.DejaFu.testAutoWay
    • Test.HUnit.DejaFu.testAutoWithSettings
    • Test.HUnit.DejaFu.testDejafu
    • Test.HUnit.DejaFu.testDejafuWay
    • Test.HUnit.DejaFu.testDejafuWithSettings
    • Test.HUnit.DejaFu.testDejafus
    • Test.HUnit.DejaFu.testDejafusWay
    • Test.HUnit.DejaFu.testDejafusWithSettings

Removed

  • The deprecated functions:

    • Test.HUnit.DejaFu.testDejafuDiscard
    • Test.HUnit.DejaFu.testDejafusDiscard

Miscellaneous

  • The lower bound on dejafu is >=2.0.

1.2.1.0 (2019-01-20)

Added

  • Re-export of the Condition type from dejafu. If using dejafu < 1.12, this is an alias for Failure.

Miscellaneous

  • The upper bound on dejafu is <1.13

1.2.0.6 (2018-07-01)

Miscellaneous

  • The upper bound on dejafu is <1.12.

1.2.0.5 (2018-06-17)

Miscellaneous

  • The upper bound on dejafu is <1.11.

1.2.0.4 (2018-06-10)

Miscellaneous

  • The upper bound on dejafu is <1.10.

1.2.0.3 (2018-06-03)

Miscellaneous

  • The upper bound on dejafu is <1.9.

1.2.0.2 (2018-06-03)

Miscellaneous

  • The upper bound on dejafu is <1.8.

1.2.0.1 (2018-05-11)

Miscellaneous

  • The upper bound on dejafu is <1.7.

1.2.0.0 - No More 7.10 (2018-03-28)

Miscellaneous

  • GHC 7.10 support is dropped. Dependency lower bounds are:

  • The upper bound on dejafu is 1.6.

1.1.0.3 (2018-03-17)

Miscellaneous

1.1.0.2 (2018-03-11)

Miscellaneous

1.1.0.1 (2018-03-06)

Miscellaneous

  • The upper bound on dejafu is <1.4.

1.1.0.0 - The Settings Release (2018-03-06)

Added

  • (pull request #238) Settings-based test functions:

    • Test.HUnit.DejaFu.testAutoWithSettings
    • Test.HUnit.DejaFu.testDejafuWithSettings
    • Test.HUnit.DejaFu.testDejafusWithSettings
  • (pull request #238) Re-export of Test.DejaFu.Settings.

Deprecated

Removed

Miscellaneous

  • The version bounds on dejafu are >=1.2 && <1.3.

1.0.1.2 (2018-02-26)

Miscellaneous

1.0.1.1 (2018-02-22)

Miscellaneous

  • The upper bound on dejafu is <1.2.

1.0.1.0 (2018-02-13)

Added

1.0.0.0 - The API Friendliness Release (2017-12-23)

Added

  • (issue #124) Re-exports of Test.DejaFu.Predicate and ProPredicate.

Changed

  • All testing functions require MonadConc, MonadRef, and MonadIO constraints. Testing with ST is no longer possible.
  • (issue #123) All testing functions take the action to run as the final parameter.
  • (issue #124) All testing functions have been generalised to take a Test.DejaFu.ProPredicate instead of a Predicate.

Removed

  • The Test.DejaFu.Conc.ConcST specific functions.
  • The orphan Testable and Assertable instances for Test.DejaFu.Conc.ConcST t ().

Miscellaneous

  • The version bounds on dejafu are >=1.0 && <1.1.

0.7.1.1 (2017-11-30)

Fixed

  • A missing Haddock @since comments.

0.7.1.0 (2017-11-30)

Added

  • Test.HUnit.DejaFu.testPropertyFor function.

0.7.0.2 (2017-10-11)

Miscellaneous

  • The upper bound on dejafu is <0.10.

0.7.0.1 (2017-09-26)

Miscellaneous

  • The upper bound on dejafu is <0.9.

0.7.0.0 - The Discard Release (2017-08-10)

Added

  • Re-export for Test.DejaFu.SCT.Discard and Test.DejaFu.Defaults.defaultDiscarder.
  • Test.HUnit.DejaFu.testDejafuDiscard and testDejafuDiscardIO functions.

Miscellaneous

  • The lower bound on dejafu is >=0.7.1.

0.6.0.0 - The Refinement Release (2017-06-07)

Added

  • Test.HUnit.DejaFu.testProperty function
  • Re-exports for Test.DejaFu.SCT.systematically, randomly, uniformly, and swarmy.
  • Re-exports for Test.DejaFu.Defaults.defaultWay, defaultMemType, and defaultBounds.

Removed

  • Re-exports of the Test.DejaFu.SCT.Way constructors: Systematically and Randomly.

Miscellaneous

  • The version bounds on dejafu are >=0.7 && <0.8.

0.5.0.0 - The Way Release (2017-04-08)

Changed

  • Due to changes in dejafu, the Way type no longer takes a parameter; it is now a GADT.

Miscellaneous

  • Every definition, class, and instance now has a Haddock @since annotation.
  • The version bounds on dejafu are >=0.6 && <0.7.
  • Remove an unnecessary dependency on random.

0.4.0.1 (2017-03-20)

Miscellaneous

  • The upper bound on HUnit is <1.7.

0.4.0.0 (2017-02-21)

Added

  • Re-export of Test.DejaFu.SCT.Way.

Changed

  • All the functions which took a Test.DejaFu.SCT.Bounds now take a Way.

Miscellaneous

  • The version bounds on dejafu are >=0.5 && <0.6.
  • Dependency on random with bounds >=1.0 && <1.2.

0.3.0.3 (2016-10-22)

Miscellaneous

  • The upper bound on HUnit is <1.6.

0.3.0.2 (2016-09-10)

Miscellaneous

  • The upper bound on dejafu is <0.5.

0.3.0.1 (2016-05-26)

Miscellaneous

  • The lower bound on base is >=4.8.
  • The upper bound on dejafu is <0.4.

0.3.0.0 (2016-04-28)

Added

  • Orphan Assertable and Testable instances for Test.DejaFu.Conc.ConcST t () and ConcIO ().
  • Re-export Test.DejaFu.SCT.Bounds.

Miscellaneous

  • The version bounds on dejafu are >=0.2

0.2.1.0 (2016-04-03)

Note: this was never pushed to Hackage, whoops!

Miscellaneous

  • The version bounds on dejafu are 0.3.*.

0.2.0.0 - The Initial Release (2015-12-01)

Added

  • Everything.

Release Notes

This project is versioned according to the PVP, the de facto standard Haskell versioning scheme.

2.1.0.1 (2023-09-11)

Miscellaneous

  • The upper bound on tasty is <1.6.

2.1.0.0 (2022-08-31)

Changed

  • (issue #361) The following functions take a TestName parameter to name the test group, rather than using "Deja Fu Tests":

    • Test.Tasty.DejaFu.testAuto
    • Test.Tasty.DejaFu.testAutoWay
    • Test.Tasty.DejaFu.testAutoWithSettings
    • Test.Tasty.DejaFu.testDejafus
    • Test.Tasty.DejaFu.testDejafusWay
    • Test.Tasty.DejaFu.testDejafusWithSettings

2.0.0.9 (2022-08-30)

Fixed

  • Remove inaccurate comment about Test.Tasty.DejaFu.testDejafus sharing work.

2.0.0.8 (2021-08-15)

Miscellaneous

  • Remove reference to freenode from README.

2.0.0.7 (2020-12-27)

Miscellaneous

  • The upper bound on tasty is <1.5.

2.0.0.6 (2020-07-01)

Miscellaneous

  • The upper bound on dejafu is <2.5.

2.0.0.5 (2020-06-24)

Miscellaneous

  • The upper bound on random is <1.3.

2.0.0.4 (2020-05-14)

Miscellaneous

  • The upper bound on dejafu is <2.4

2.0.0.3 (2020-05-10)

Miscellaneous

  • The upper bound on dejafu is <2.3

2.0.0.2 (2020-05-10)

Miscellaneous

  • The upper bound on tasty is <1.4

2.0.0.1 (2019-03-24)

Miscellaneous

  • The upper bound on dejafu is <2.2

2.0.0.0 (2019-02-12)

Added

  • Re-exports for the Program types and their constructors:

    • Test.Tasty.DejaFu.Program
    • Test.Tasty.DejaFu.Basic
    • Test.Tasty.DejaFu.ConcT
    • Test.Tasty.DejaFu.ConcIO
    • Test.Tasty.DejaFu.WithSetup
    • Test.Tasty.DejaFu.WithSetupAndTeardown
    • Test.Tasty.DejaFu.withSetup
    • Test.Tasty.DejaFu.withTeardown
    • Test.Tasty.DejaFu.withSetupAndTeardown
  • Re-exports for the Invariant type and its functions:

    • Test.Tasty.DejaFu.Invariant
    • Test.Tasty.DejaFu.registerInvariant
    • Test.Tasty.DejaFu.inspectIORef
    • Test.Tasty.DejaFu.inspectMVar
    • Test.Tasty.DejaFu.inspectTVar

Changed

  • Functions which took a ConcIO now take a Program pty IO:

    • Test.Tasty.DejaFu.testAuto
    • Test.Tasty.DejaFu.testAutoWay
    • Test.Tasty.DejaFu.testAutoWithSettings
    • Test.Tasty.DejaFu.testDejafu
    • Test.Tasty.DejaFu.testDejafuWay
    • Test.Tasty.DejaFu.testDejafuWithSettings
    • Test.Tasty.DejaFu.testDejafus
    • Test.Tasty.DejaFu.testDejafusWay
    • Test.Tasty.DejaFu.testDejafusWithSettings

Removed

  • The deprecated functions:

    • Test.Tasty.DejaFu.testDejafuDiscard
    • Test.Tasty.DejaFu.testDejafusDiscard

Miscellaneous

  • The lower bound on dejafu is >=2.0.

1.2.1.0 (2019-01-20)

Added

  • Re-export of the Condition type from dejafu. If using dejafu < 1.12, this is an alias for Failure.

Miscellaneous

  • The upper bound on dejafu is <1.13

1.2.0.8 (2018-12-02)

Miscellaneous

  • The upper bound on tasty is <1.3.

1.2.0.7 (2018-07-01)

Miscellaneous

  • The upper bound on dejafu is <1.12.

1.2.0.6 (2018-06-17)

Miscellaneous

  • The upper bound on dejafu is <1.11.

1.2.0.5 (2018-06-10)

Miscellaneous

  • The upper bound on dejafu is <1.10.

1.2.0.4 (2018-06-03)

Miscellaneous

  • The upper bound on dejafu is <1.9.

1.2.0.3 (2018-06-03)

Miscellaneous

  • The upper bound on dejafu is <1.8.

1.2.0.2 (2018-05-12)

Miscellaneous

  • The upper bound on tasty is <1.2.

1.2.0.1 (2018-05-11)

Miscellaneous

  • The upper bound on dejafu is <1.7.

1.2.0.0 - No More 7.10 (2018-03-28)

Miscellaneous

  • GHC 7.10 support is dropped. Dependency lower bounds are:

  • The upper bound on dejafu is 1.6.

1.1.0.2 (2018-03-17)

Miscellaneous

  • The upper bound on dejafu is <1.5.

1.1.0.1 (2018-03-06)

Miscellaneous

  • The upper bound on dejafu is <1.4.

1.1.0.0 - The Settings Release (2018-03-06)

Added

  • (pull request #238) Settings-based test functions:

    • Test.Tasty.DejaFu.testAutoWithSettings
    • Test.Tasty.DejaFu.testDejafuWithSettings
    • Test.Tasty.DejaFu.testDejafusWithSettings
  • (pull request #238) Re-export of Test.DejaFu.Settings.

Deprecated

Removed

Miscellaneous

  • The version bounds on dejafu are >=1.2 && <1.3.

1.0.1.1 (2018-02-22)

Miscellaneous

  • The upper bound on dejafu is <1.2.

1.0.1.0 (2018-02-13)

Added

1.0.0.1 (2018-01-09)

Miscellaneous

  • The upper bound on tasty is <1.1.

1.0.0.0 - The API Friendliness Release (2017-12-23)

Added

  • (issue #124) Re-exports of Test.DejaFu.Predicate and ProPredicate.

Changed

  • All testing functions require MonadConc, MonadRef, and MonadIO constraints. Testing with ST is no longer possible.
  • (issue #123) All testing functions take the action to run as the final parameter.
  • (issue #124) All testing functions have been generalised to take a Test.DejaFu.ProPredicate instead of a Predicate.

Removed

  • The Test.DejaFu.Conc.ConcST specific functions.
  • The orphan IsTest instance for Test.DejaFu.Conc.ConcST t (Maybe String).

Miscellaneous

  • The version bounds on dejafu are >=1.0 && <1.1.

0.7.1.1 (2017-11-30)

Fixed

  • A missing Haddock @since comments.

0.7.1.0 (2017-11-30)

Added

  • Test.Tasty.DejaFu.testPropertyFor function.

0.7.0.3 (2017-11-02)

Miscellaneous

  • The upper bound on tasty is <0.13.

0.7.0.2 (2017-10-11)

Miscellaneous

  • The upper bound on dejafu is <0.10.

0.7.0.1 (2017-09-26)

Miscellaneous

  • The upper bound on dejafu is <0.9.

0.7.0.0 - The Discard Release (2017-08-10)

Added

  • Re-export for Test.DejaFu.SCT.Discard and Test.DejaFu.Defaults.defaultDiscarder.
  • Test.Tasty.DejaFu.testDejafuDiscard and testDejafuDiscardIO functions.

Miscellaneous

  • The lower bound on dejafu is >=0.7.1.

0.6.0.0 - The Refinement Release (2017-04-08)

Added

  • Test.Tasty.DejaFu.testProperty function
  • Re-exports for Test.DejaFu.SCT.systematically, randomly, uniformly, and swarmy.
  • Re-exports for Test.DejaFu.Defaults.defaultWay, defaultMemType, and defaultBounds.

Removed

  • Re-exports of the Test.DejaFu.SCT.Way constructors: Systematically and Randomly.

Miscellaneous

  • The version bounds on dejafu are >=0.7 && <0.8.

0.5.0.0 - The Way Release (2017-04-08)

Changed

  • Due to changes in dejafu, the Way type no longer takes a parameter; it is now a GADT.

Miscellaneous

  • Every definition, class, and instance now has a Haddock @since annotation.
  • The version bounds on dejafu are >=0.6 && <0.7.

0.4.0.0 (2017-02-21)

Added

  • Re-export of Test.DejaFu.SCT.Way.

  • Orphan IsOption instance for Test.DejaFu.SCT.Way. Command-line parameters are:

    • "systematically": systematic testing with the default bounds
    • "randomly": 100 executions with a fixed random seed

Changed

  • All the functions which took a Test.DejaFu.SCT.Bounds now take a Way.

Miscellaneous

  • The version bounds on dejafu are >=0.5 && <0.6.
  • Dependency on random with bounds >=1.0 && <1.2.

0.3.0.2 (2016-09-10)

Miscellaneous

  • The upper bound on dejafu is <0.5.

0.3.0.1 (2016-05-26)

Miscellaneous

  • The lower bound on base is >=4.8.
  • The upper bound on dejafu is <0.4.

0.3.0.0 (2016-04-28)

Added

  • Orphan IsTest instances for Test.DejaFu.Conc.ConcST t (Maybe String) and ConcIO (Maybe String).

  • Orphan IsOption instances for Test.DejaFu.SCT.Bounds and MemType. Command-line parameters are:

    • "sc": sequential consistency
    • "tso": total store order
    • "pso": partial store order
  • Re-export Test.DejaFu.SCT.Bounds.

Miscellaneous

  • The version bounds on dejafu are >=0.2

0.1.1.0 (2016-04-03)

Note: this was misnumbered (it should have been 0.2.1.0) and was never pushed to Hackage, whoops!

Miscellaneous

  • The version bounds on dejafu are 0.3.*.

0.2.0.0 - The Initial Release (2015-12-01)

Added

  • Everything.