hunit-dejafu (empty) → 0.2.0.0
raw patch · 4 files changed
+252/−0 lines, 4 filesdep +HUnitdep +basedep +dejafusetup-changed
Dependencies added: HUnit, base, dejafu
Files
- LICENSE +20/−0
- Setup.hs +2/−0
- Test/HUnit/DejaFu.hs +189/−0
- hunit-dejafu.cabal +41/−0
+ LICENSE view
@@ -0,0 +1,20 @@+Copyright (c) 2015, Michael Walker <mike@barrucadu.co.uk>++Permission is hereby granted, free of charge, to any person obtaining+a copy of this software and associated documentation files (the+"Software"), to deal in the Software without restriction, including+without limitation the rights to use, copy, modify, merge, publish,+distribute, sublicense, and/or sell copies of the Software, and to+permit persons to whom the Software is furnished to do so, subject to+the following conditions:++The above copyright notice and this permission notice shall be+included in all copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ Test/HUnit/DejaFu.hs view
@@ -0,0 +1,189 @@+{-# LANGUAGE RankNTypes #-}++-- | This module allows using Deja Fu predicates with HUnit to test+-- the behaviour of concurrent systems.+module Test.HUnit.DejaFu+ ( -- * Testing+ testAuto+ , testDejafu+ , testDejafus+ , testAutoIO+ , testDejafuIO+ , testDejafusIO++ -- * Testing under Alternative Memory Models+ , MemType(..)+ , testAuto'+ , testAutoIO'+ , testDejafu'+ , testDejafus'+ , testDejafuIO'+ , testDejafusIO'+ ) where++import Test.DejaFu+import Test.DejaFu.Deterministic (ConcST, ConcIO, showFail, showTrace)+import Test.DejaFu.SCT (sctBound, sctBoundIO)+import Test.HUnit (Test(..), assertString)++--------------------------------------------------------------------------------+-- Automated testing++-- | Automatically test a computation. In particular, look for+-- deadlocks, uncaught exceptions, and multiple return values.+-- +-- This uses the 'Conc' monad for testing, which is an instance of+-- 'MonadConc'. If you need to test something which also uses+-- 'MonadIO', use 'testAutoIO'.+testAuto :: (Eq a, Show a)+ => (forall t. ConcST t a)+ -- ^ The computation to test+ -> Test+testAuto = testAuto' defaultMemType++-- | Variant of 'testAuto' which tests a computation under a given+-- memory model.+testAuto' :: (Eq a, Show a)+ => MemType+ -- ^ The memory model to use for non-synchronised @CRef@ operations.+ -> (forall t. ConcST t a)+ -- ^ The computation to test+ -> Test+testAuto' memtype conc = testDejafus' memtype defaultBounds conc autocheckCases++-- | Variant of 'testAuto' for computations which do 'IO'.+testAutoIO :: (Eq a, Show a) => ConcIO a -> Test+testAutoIO = testAutoIO' defaultMemType++-- | Variant of 'testAuto'' for computations which do 'IO'.+testAutoIO' :: (Eq a, Show a) => MemType -> ConcIO a -> Test+testAutoIO' memtype concio = testDejafusIO' memtype defaultBounds concio autocheckCases++-- | Predicates for the various autocheck functions.+autocheckCases :: Eq a => [(String, Predicate a)]+autocheckCases =+ [("Never Deadlocks", representative deadlocksNever)+ , ("No Exceptions", representative exceptionsNever)+ , ("Consistent Result", alwaysSame)+ ]++--------------------------------------------------------------------------------+-- Manual testing++-- | Check that a predicate holds.+testDejafu :: Show a+ => (forall t. ConcST t a)+ -- ^ The computation to test+ -> String+ -- ^ The name of the test.+ -> Predicate a+ -- ^ The predicate to check+ -> Test+testDejafu = testDejafu' defaultMemType defaultBounds++-- | Variant of 'testDejafu' which takes a memory model and+-- pre-emption bound.+testDejafu' :: Show a+ => MemType+ -- ^ The memory model to use for non-synchronised @CRef@ operations.+ -> Bounds+ -- ^ The schedule bound.+ -> (forall t. ConcST t a)+ -- ^ The computation to test+ -> String+ -- ^ The name of the test.+ -> Predicate a+ -- ^ The predicate to check+ -> Test+testDejafu' memtype cb conc name p = testDejafus' memtype cb conc [(name, p)]++-- | Variant of 'testDejafu' which takes a collection of predicates to+-- test. This will share work between the predicates, rather than+-- running the concurrent computation many times for each predicate.+testDejafus :: Show a+ => (forall t. ConcST t a)+ -- ^ The computation to test+ -> [(String, Predicate a)]+ -- ^ The list of predicates (with names) to check+ -> Test+testDejafus = testDejafus' defaultMemType defaultBounds++-- | Variant of 'testDejafus' which takes a memory model and pre-emption+-- bound.+testDejafus' :: Show a+ => MemType+ -- ^ The memory model to use for non-synchronised @CRef@ operations.+ -> Bounds+ -- ^ The schedule bounds+ -> (forall t. ConcST t a)+ -- ^ The computation to test+ -> [(String, Predicate a)]+ -- ^ The list of predicates (with names) to check+ -> Test+testDejafus' = test++-- | Variant of 'testDejafu' for computations which do 'IO'.+testDejafuIO :: Show a => ConcIO a -> String -> Predicate a -> Test+testDejafuIO = testDejafuIO' defaultMemType defaultBounds++-- | Variant of 'testDejafu'' for computations which do 'IO'.+testDejafuIO' :: Show a => MemType -> Bounds -> ConcIO a -> String -> Predicate a -> Test+testDejafuIO' memtype cb concio name p = testDejafusIO' memtype cb concio [(name, p)]++-- | Variant of 'testDejafus' for computations which do 'IO'.+testDejafusIO :: Show a => ConcIO a -> [(String, Predicate a)] -> Test+testDejafusIO = testDejafusIO' defaultMemType defaultBounds++-- | Variant of 'dejafus'' for computations which do 'IO'.+testDejafusIO' :: Show a => MemType -> Bounds -> ConcIO a -> [(String, Predicate a)] -> Test+testDejafusIO' = testio++--------------------------------------------------------------------------------+-- HUnit integration++-- | Produce a HUnit 'Test' from a Deja Fu test.+test :: Show a => MemType -> Bounds -> (forall t. ConcST t a) -> [(String, Predicate a)] -> Test+test memtype cb conc tests = case map toTest tests of+ [t] -> t+ ts -> TestList ts++ where+ toTest (name, p) = TestLabel name . TestCase $+ assertString . showErr $ p traces++ traces = sctBound memtype cb conc++-- | Produce a HUnit 'Test' from an IO-using Deja Fu test.+testio :: Show a => MemType -> Bounds -> ConcIO a -> [(String, Predicate a)] -> Test+testio memtype cb concio tests = case map toTest tests of+ [t] -> t+ ts -> TestList ts++ where+ toTest (name, p) = TestLabel name . TestCase $ do+ -- Sharing of traces probably not possible (without something+ -- really unsafe) here, as 'test' doesn't allow side-effects+ -- (eg, constructing an 'MVar' to share the traces after one+ -- test computed them).+ traces <- sctBoundIO memtype cb concio+ assertString . showErr $ p traces++-- | Convert a test result into an error message on failure (empty+-- string on success).+showErr :: Show a => Result a -> String+showErr res+ | _pass res = ""+ | otherwise = "Failed after " ++ show (_casesChecked res) ++ " cases:\n" ++ msg ++ unlines failures ++ rest where++ msg = if null (_failureMsg res) then "" else _failureMsg res ++ "\n"++ failures = map (\(r, t) -> "\t" ++ either showFail show r ++ " " ++ showTrace t) . take 5 $ _failures res++ rest = if moreThan (_failures res) 5 then "\n\t..." else ""++-- | Check if a list has more than some number of elements.+moreThan :: [a] -> Int -> Bool+moreThan [] n = n < 0+moreThan _ 0 = True+moreThan (_:xs) n = moreThan xs (n-1)+
+ hunit-dejafu.cabal view
@@ -0,0 +1,41 @@+-- Initial hunit-dejafu.cabal generated by cabal init. For further +-- documentation, see http://haskell.org/cabal/users-guide/++name: hunit-dejafu+version: 0.2.0.0+synopsis: Deja Fu support for the HUnit test framework.++description:+ Integration between the <https://hackage.haskell.org/package/dejafu dejafu>+ library for concurrency testing and+ <https://hackage.haskell.org/package/HUnit HUnit>. This lets you+ easily incorporate concurrency testing into your existing test+ suites.+ .+ See the <https://github.com/barrucadu/dejafu README> for more+ details.++homepage: https://github.com/barrucadu/dejafu+license: MIT+license-file: LICENSE+author: Michael Walker+maintainer: mike@barrucadu.co.uk+-- copyright: +category: Testing+build-type: Simple+-- extra-source-files: +cabal-version: >=1.10++source-repository head+ type: git+ location: https://github.com/barrucadu/dejafu.git++library+ exposed-modules: Test.HUnit.DejaFu+ -- other-modules: + -- other-extensions: + build-depends: base >=4.5 && <5+ , dejafu == 0.2.*+ , HUnit+ -- hs-source-dirs: + default-language: Haskell2010