packages feed

dejafu 0.9.0.0 → 0.9.0.1

raw patch · 8 files changed

+95/−40 lines, 8 filesdep −mtlPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies removed: mtl

API changes (from Hackage documentation)

- Test.DejaFu.SCT.Internal: err :: String -> String -> a
+ Test.DejaFu.Common: efromJust :: String -> Maybe a -> a
+ Test.DejaFu.Common: efromList :: String -> [a] -> NonEmpty a
+ Test.DejaFu.Common: ehead :: String -> [a] -> a
+ Test.DejaFu.Common: eidx :: String -> [a] -> Int -> a
+ Test.DejaFu.Common: etail :: String -> [a] -> [a]
+ Test.DejaFu.Common: fatal :: String -> String -> a

Files

CHANGELOG.markdown view
@@ -7,6 +7,24 @@ *de facto* standard Haskell versioning scheme.  +0.9.0.1+-------++- **Date**    2017-10-28+- **Git tag** [dejafu-0.9.0.1][]+- **Hackage** https://hackage.haskell.org/package/dejafu-0.9.0.1++### Miscellaneous++- Fixed an issue where tests with exception handlers would sometimes skip over nested handlers or+  try to take the tail of an empty list (#139 and #141).++[dejafu-0.9.0.1]: https://github.com/barrucadu/dejafu/releases/tag/dejafu-0.9.0.1+++---------------------------------------------------------------------------------------------------++ 0.9.0.0 ------- 
Test/DejaFu/Common.hs view
@@ -66,17 +66,24 @@   -- * Miscellaneous   , MonadFailException(..)   , runRefCont+  , ehead+  , etail+  , eidx+  , efromJust+  , efromList+  , fatal   ) where -import           Control.DeepSeq   (NFData(..))-import           Control.Exception (Exception(..), MaskingState(..),-                                    SomeException, displayException)-import           Control.Monad.Ref (MonadRef(..))-import           Data.Function     (on)-import           Data.List         (intercalate)-import           Data.Maybe        (fromMaybe, mapMaybe)-import           Data.Set          (Set)-import qualified Data.Set          as S+import           Control.DeepSeq    (NFData(..))+import           Control.Exception  (Exception(..), MaskingState(..),+                                     SomeException, displayException)+import           Control.Monad.Ref  (MonadRef(..))+import           Data.Function      (on)+import           Data.List          (intercalate)+import           Data.List.NonEmpty (NonEmpty(..))+import           Data.Maybe         (fromMaybe, mapMaybe)+import           Data.Set           (Set)+import qualified Data.Set           as S  ------------------------------------------------------------------------------- -- Identifiers@@ -982,6 +989,42 @@   ref <- newRef Nothing   let c = k (act . writeRef ref . f)   pure (c, ref)++-- | 'head' but with a better error message if it fails.  Use this+-- only where it shouldn't fail!+ehead :: String -> [a] -> a+ehead _ (x:_) = x+ehead src _ = fatal src "head: empty list"++-- | 'tail' but with a better error message if it fails.  Use this+-- only where it shouldn't fail!+etail :: String -> [a] -> [a]+etail _ (_:xs) = xs+etail src _ = fatal src "tail: empty list"++-- | '(!!)' but with a better error message if it fails.  Use this+-- only where it shouldn't fail!+eidx :: String -> [a] -> Int -> a+eidx src xs i+  | i < length xs = xs !! i+  | otherwise = fatal src "(!!): index too large"++-- | 'fromJust' but with a better error message if it fails.  Use this+-- only where it shouldn't fail!+efromJust :: String -> Maybe a -> a+efromJust _ (Just x) = x+efromJust src _ = fatal src "fromJust: Nothing"++-- | 'fromList' but with a better error message if it fails.  Use this+-- only where it shouldn't fail!+efromList :: String -> [a] -> NonEmpty a+efromList _ (x:xs) = x:|xs+efromList src _ = fatal src "fromList: empty list"++-- | 'error' but saying where it came from+fatal :: String -> String -> a+fatal src msg = error ("(dejafu: " ++ src ++ ") " ++ msg)+  ------------------------------------------------------------------------------- -- Utilities
Test/DejaFu/Conc/Internal.hs view
@@ -21,9 +21,8 @@                                                       writeRef) import           Data.Functor                        (void) import           Data.List                           (sortOn)-import           Data.List.NonEmpty                  (fromList) import qualified Data.Map.Strict                     as M-import           Data.Maybe                          (fromJust, isJust)+import           Data.Maybe                          (isJust) import           Data.Monoid                         ((<>)) import           Data.Sequence                       (Seq, (<|)) import qualified Data.Sequence                       as Seq@@ -64,7 +63,7 @@                     }   (finalCtx, trace, finalAction) <- runThreads sched memtype ref ctx   out <- readRef ref-  pure (fromJust out, finalCtx, trace, finalAction)+  pure (efromJust "runConcurrency" out, finalCtx, trace, finalAction)  -- | The context a collection of threads are running in. data Context n r g = Context@@ -97,7 +96,7 @@              Nothing -> die sofar prior InternalError ctx'            Nothing -> die sofar prior Abort ctx'     where-      (choice, g')  = scheduleThread sched prior (fromList runnable') (cSchedState ctx)+      (choice, g')  = scheduleThread sched prior (efromList "runThreads" runnable') (cSchedState ctx)       runnable'     = [(t, lookahead (_continuation a)) | (t, a) <- sortOn fst $ M.assocs runnable]       runnable      = M.filter (not . isBlocked) threadsc       threadsc      = addCommitThreads (cWriteBuf ctx) threads@@ -290,7 +289,7 @@       wb' <- case memtype of         -- shouldn't ever get here         SequentialConsistency ->-          error "Attempting to commit under SequentialConsistency"+          fatal "stepThread.ACommit" "Attempting to commit under SequentialConsistency"         -- commit using the thread id.         TotalStoreOrder -> commitWrite (cWriteBuf ctx) (t, Nothing)         -- commit using the cref id.@@ -337,8 +336,8 @@      -- run a subcomputation in an exception-catching context.     ACatching h ma c ->-      let a        = runCont ma      (APopCatching . c)-          e exc    = runCont (h exc) (APopCatching . c)+      let a        = runCont ma (APopCatching . c)+          e exc    = runCont (h exc) c           threads' = goto a tid (catching e tid (cThreads ctx))       in simple threads' Catching @@ -351,7 +350,7 @@     -- a function to run a computation with the current masking state.     AMasking m ma c ->       let a = runCont (ma umask) (AResetMask False False m' . c)-          m' = _masking . fromJust $ M.lookup tid (cThreads ctx)+          m' = _masking . efromJust "stepThread.AMasking" $ M.lookup tid (cThreads ctx)           umask mb = resetMask True m' >> mb >>= \b -> resetMask False m >> pure b           resetMask typ ms = cont $ \k -> AResetMask typ True ms $ k ()           threads' = goto a tid (mask m tid (cThreads ctx))
Test/DejaFu/Conc/Internal/Memory.hs view
@@ -26,7 +26,7 @@ import           Control.Monad.Ref                   (MonadRef, readRef,                                                       writeRef) import           Data.Map.Strict                     (Map)-import           Data.Maybe                          (fromJust, maybeToList)+import           Data.Maybe                          (maybeToList) import           Data.Monoid                         ((<>)) import           Data.Sequence                       (Seq, ViewL(..), singleton,                                                       viewl, (><))@@ -160,7 +160,7 @@ -- | Read from a @MVar@, blocking if empty. readFromMVar :: MonadRef r n => MVar r a -> (a -> Action n r)             -> ThreadId -> Threads n r -> n (Bool, Threads n r, [ThreadId])-readFromMVar cvar c = seeMVar NonEmptying Blocking cvar (c . fromJust)+readFromMVar cvar c = seeMVar NonEmptying Blocking cvar (c . efromJust "readFromMVar")  -- | Try to read from a @MVar@, not blocking if empty. tryReadFromMVar :: MonadRef r n => MVar r a -> (Maybe a -> Action n r)@@ -170,7 +170,7 @@ -- | Take from a @MVar@, blocking if empty. takeFromMVar :: MonadRef r n => MVar r a -> (a -> Action n r)              -> ThreadId -> Threads n r -> n (Bool, Threads n r, [ThreadId])-takeFromMVar cvar c = seeMVar Emptying Blocking cvar (c . fromJust)+takeFromMVar cvar c = seeMVar Emptying Blocking cvar (c . efromJust "takeFromMVar")  -- | Try to take from a @MVar@, not blocking if empty. tryTakeFromMVar :: MonadRef r n => MVar r a -> (Maybe a -> Action n r)
Test/DejaFu/Conc/Internal/Threading.hs view
@@ -92,7 +92,7 @@  -- | Remove the most recent exception handler. uncatching :: ThreadId -> Threads n r -> Threads n r-uncatching = M.adjust $ \thread -> thread { _handlers = tail $ _handlers thread }+uncatching = M.adjust $ \thread -> thread { _handlers = etail "uncatching" (_handlers thread) }  -- | Raise an exception in a thread. except :: (MaskingState -> Action n r) -> [Handler n r] -> ThreadId -> Threads n r -> Threads n r
Test/DejaFu/SCT/Internal.hs view
@@ -22,7 +22,7 @@ import           Data.List.NonEmpty   (toList) import           Data.Map.Strict      (Map) import qualified Data.Map.Strict      as M-import           Data.Maybe           (fromJust, fromMaybe, isJust, isNothing,+import           Data.Maybe           (fromMaybe, isJust, isNothing,                                        listToMaybe) import           Data.Sequence        (Seq, (|>)) import qualified Data.Sequence        as Sq@@ -157,7 +157,7 @@     in case dporNext dpor of          Just (t, child)            | t == tid'      -> dpor { dporNext = Just (tid', grow state' tid' rest child) }-           | hasTodos child -> err "incorporateTrace" "replacing child with todos!"+           | hasTodos child -> fatal "incorporateTrace" "replacing child with todos!"          _ ->            let taken = M.insert tid' a (dporTaken dpor)                sleep = dporSleep dpor `M.union` dporTaken dpor@@ -166,7 +166,7 @@                    , dporNext  = Just (tid', subtree state' tid' sleep trc)                    , dporDone  = S.insert tid' (dporDone dpor)                    }-  grow _ _ [] _ = err "incorporateTrace" "trace exhausted without reading a to-do point!"+  grow _ _ [] _ = fatal "incorporateTrace" "trace exhausted without reading a to-do point!"    -- check if there are to-do points in a tree   hasTodos dpor = not (M.null (dporTodo dpor)) || (case dporNext dpor of Just (_, dpor') -> hasTodos dpor'; _ -> False)@@ -193,7 +193,7 @@           ((d', _, a'):_) -> M.singleton (tidOf tid d') a'           [] -> M.empty         }-  subtree _ _ _ [] = err "incorporateTrace" "subtree suffix empty!"+  subtree _ _ _ [] = fatal "incorporateTrace" "subtree suffix empty!"  -- | Produce a list of new backtracking points from an execution -- trace. These are then used to inform new \"to-do\" points in the@@ -251,7 +251,7 @@   -- backtracking points.   doBacktrack killsEarly allThreads enabledThreads bs =     let tagged = reverse $ zip [0..] bs-        idxs   = [ (head is, False, u)+        idxs   = [ (ehead "doBacktrack.idxs" is, False, u)                  | (u, n) <- enabledThreads                  , v <- S.toList allThreads                  , u /= v@@ -301,9 +301,9 @@    child = case dporNext dpor of     Just (t, d)-      | t /= tid -> err "incorporateBacktrackSteps" "incorporating wrong trace!"+      | t /= tid -> fatal "incorporateBacktrackSteps" "incorporating wrong trace!"       | otherwise -> incorporateBacktrackSteps bs d-    Nothing -> err "incorporateBacktrackSteps" "child is missing!"+    Nothing -> fatal "incorporateBacktrackSteps" "child is missing!" incorporateBacktrackSteps [] dpor = dpor  -------------------------------------------------------------------------------@@ -416,7 +416,7 @@         ((i',c',t'):is') -> go i' bs (i'-i0-1) c' t' is'         [] -> bs   go i0 (b:bs) i c tid is = b : go i0 bs (i-1) c tid is-  go _ [] _ _ _ _ = err "backtrackAt" "ran out of schedule whilst backtracking!"+  go _ [] _ _ _ _ = fatal "backtrackAt" "ran out of schedule whilst backtracking!"    -- Backtrack to a single thread   backtrackTo tid c = M.insert tid c . bcktBacktracks@@ -495,7 +495,7 @@     decision = decisionOf (fst <$> prior) (S.fromList tids)      -- Get the action of a thread-    action t = fromJust $ lookup t threads'+    action t = efromJust "dporSched.action" (lookup t threads')      -- The runnable thread IDs     tids = map fst threads'@@ -812,7 +812,3 @@ killsDaemons :: ThreadId -> Lookahead -> Bool killsDaemons t WillStop = t == initialThread killsDaemons _ _ = False---- | Internal errors.-err :: String -> String -> a-err func msg = error (func ++ ": (internal error) " ++ msg)
Test/DejaFu/Schedule.hs view
@@ -98,7 +98,7 @@   go _ threads g =     let threads' = map fst (toList threads)         (choice, g') = randomR (0, length threads' - 1) g-    in (Just $ threads' !! choice, g')+    in (Just $ eidx "randomSched" threads' choice, g')  -- | A round-robin scheduler which, at every step, schedules the -- thread with the next 'ThreadId'.
dejafu.cabal view
@@ -2,7 +2,7 @@ -- documentation, see http://haskell.org/cabal/users-guide/  name:                dejafu-version:             0.9.0.0+version:             0.9.0.1 synopsis:            Systematic testing for Haskell concurrency.  description:@@ -37,7 +37,7 @@ source-repository this   type:     git   location: https://github.com/barrucadu/dejafu.git-  tag:      dejafu-0.9.0.0+  tag:      dejafu-0.9.0.1  library   exposed-modules:     Test.DejaFu@@ -64,13 +64,12 @@                      , deepseq           >=1.1 && <2                      , exceptions        >=0.7 && <0.9                      , leancheck         >=0.6 && <0.7-                     , mtl               >=2.2 && <2.3                      , random            >=1.0 && <1.2                      , ref-fd            >=0.4 && <0.5-                     -- remove semigroups dep when GHC 8.4 is out-                     , semigroups        >=0.16 && <0.19                      , transformers      >=0.4  && <0.6                      , transformers-base >=0.4  && <0.5   -- hs-source-dirs:         default-language:    Haskell2010   ghc-options:         -Wall+  if impl(ghc < 8.0.1)+    build-depends: semigroups >=0.16 && <0.19