hspec-core 2.7.7 → 2.7.8
raw patch · 6 files changed
+162/−65 lines, 6 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ Test.Hspec.Core.Hooks: aroundAll :: (ActionWith a -> IO ()) -> SpecWith a -> Spec
+ Test.Hspec.Core.Hooks: aroundAllWith :: forall a b. (ActionWith a -> ActionWith b) -> SpecWith a -> SpecWith b
Files
- hspec-core.cabal +1/−1
- src/Test/Hspec/Core/Hooks.hs +45/−15
- test/Helper.hs +5/−1
- test/Test/Hspec/Core/HooksSpec.hs +109/−46
- test/Test/Hspec/Core/RunnerSpec.hs +1/−1
- version.yaml +1/−1
hspec-core.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack name: hspec-core-version: 2.7.7+version: 2.7.8 license: MIT license-file: LICENSE copyright: (c) 2011-2021 Simon Hengel,
src/Test/Hspec/Core/Hooks.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE ScopedTypeVariables #-} -- | Stability: provisional module Test.Hspec.Core.Hooks ( before@@ -13,7 +14,9 @@ , around , around_ , aroundWith+, aroundAll , aroundAll_+, aroundAllWith ) where import Prelude ()@@ -105,31 +108,58 @@ item{ itemExample = \params aroundAction -> e params (aroundAction . action) } -- | Wrap an action around the given spec.+aroundAll :: (ActionWith a -> IO ()) -> SpecWith a -> Spec+aroundAll action = aroundAllWith $ \ e () -> action e++-- | Wrap an action around the given spec. aroundAll_ :: (IO () -> IO ()) -> SpecWith a -> SpecWith a aroundAll_ action spec = do- startCleanup <- runIO newEmptyMVar+ allSpecItemsDone <- runIO newEmptyMVar workerRef <- runIO newEmptyMVar let acquire :: IO () acquire = do- acquireDone <- newEmptyMVar+ resource <- newEmptyMVar worker <- async $ do action $ do- signal acquireDone- waitFor startCleanup+ signal resource+ waitFor allSpecItemsDone putMVar workerRef worker unwrapExceptionsFromLinkedThread $ do link worker- waitFor acquireDone- cleanup :: IO ()- cleanup = signal startCleanup >> takeMVar workerRef >>= wait- beforeAll_ acquire $ afterAll_ cleanup spec- where- signal :: MVar () -> IO ()- signal = flip putMVar ()+ waitFor resource+ release :: IO ()+ release = signal allSpecItemsDone >> takeMVar workerRef >>= wait+ beforeAll_ acquire $ afterAll_ release spec - waitFor :: MVar () -> IO ()- waitFor = takeMVar+-- | Wrap an action around the given spec. Changes the arg type inside.+aroundAllWith :: forall a b. (ActionWith a -> ActionWith b) -> SpecWith a -> SpecWith b+aroundAllWith action spec = do+ allSpecItemsDone <- runIO newEmptyMVar+ workerRef <- runIO newEmptyMVar+ let+ acquire :: b -> IO a+ acquire b = do+ resource <- newEmptyMVar+ worker <- async $ do+ flip action b $ \ a -> do+ putMVar resource a+ waitFor allSpecItemsDone+ putMVar workerRef worker+ unwrapExceptionsFromLinkedThread $ do+ link worker+ takeMVar resource+ release :: IO ()+ release = signal allSpecItemsDone >> takeMVar workerRef >>= wait+ beforeAllWith acquire $ afterAll_ release spec - unwrapExceptionsFromLinkedThread :: IO a -> IO a- unwrapExceptionsFromLinkedThread = (`catch` \ (ExceptionInLinkedThread _ e) -> throwIO e)+unwrapExceptionsFromLinkedThread :: IO a -> IO a+unwrapExceptionsFromLinkedThread = (`catch` \ (ExceptionInLinkedThread _ e) -> throwIO e)++type BinarySemaphore = MVar ()++signal :: BinarySemaphore -> IO ()+signal = flip putMVar ()++waitFor :: BinarySemaphore -> IO ()+waitFor = takeMVar
test/Helper.hs view
@@ -18,6 +18,7 @@ , ignoreExitCode , ignoreUserInterrupt , throwException+, throwException_ , withEnvironment , inTempDirectory@@ -73,8 +74,11 @@ instance Eq SomeException where (==) = exceptionEq -throwException :: IO ()+throwException :: IO a throwException = E.throwIO DivideByZero++throwException_ :: IO ()+throwException_ = throwException ignoreExitCode :: IO () -> IO () ignoreExitCode action = action `E.catch` \e -> let _ = e :: ExitCode in return ()
test/Test/Hspec/Core/HooksSpec.hs view
@@ -14,8 +14,8 @@ import qualified Test.Hspec.Core.Hooks as H -runSilent :: H.Spec -> IO ()-runSilent = silence . H.hspec+evalSpec_ :: H.Spec -> IO ()+evalSpec_ = void . evalSpec evalSpec :: H.Spec -> IO [([String], Item)] evalSpec = fmap normalize . (H.specToEvalForest H.defaultConfig >=> runFormatter config)@@ -47,7 +47,7 @@ describe "before" $ do it "runs an action before every spec item" $ do (rec, retrieve) <- mkAppend- runSilent $ H.before (rec "before" >> return "value") $ do+ evalSpec_ $ H.before (rec "before" >> return "value") $ do H.it "foo" $ \value -> do rec (value ++ " foo") H.it "bar" $ \value -> do@@ -57,14 +57,14 @@ context "when used with a QuickCheck property" $ do it "runs action before every check of the property" $ do (rec, retrieve) <- mkAppend- runSilent $ H.before (rec "before" >> return "value") $ do+ evalSpec_ $ H.before (rec "before" >> return "value") $ do H.it "foo" $ \value -> property $ \(_ :: Int) -> rec value retrieve `shouldReturn` (take 200 . cycle) ["before", "value"] describe "before_" $ do it "runs an action before every spec item" $ do (rec, retrieve) <- mkAppend- runSilent $ H.before_ (rec "before") $ do+ evalSpec_ $ H.before_ (rec "before") $ do H.it "foo" $ do rec "foo" H.it "bar" $ do@@ -74,7 +74,7 @@ context "when used multiple times" $ do it "is evaluated outside in" $ do (rec, retrieve) <- mkAppend- runSilent $ H.before_ (rec "outer") $ H.before_ (rec "inner") $ do+ evalSpec_ $ H.before_ (rec "outer") $ H.before_ (rec "inner") $ do H.it "foo" $ do rec "foo" retrieve `shouldReturn` ["outer", "inner", "foo"]@@ -82,14 +82,14 @@ context "when used with a QuickCheck property" $ do it "runs action before every check of the property" $ do (rec, retrieve) <- mkAppend- runSilent $ H.before_ (rec "before") $ do+ evalSpec_ $ H.before_ (rec "before") $ do H.it "foo" $ property $ \(_ :: Int) -> rec "foo" retrieve `shouldReturn` (take 200 . cycle) ["before", "foo"] context "when used multiple times" $ do it "is evaluated outside in" $ do (rec, retrieve) <- mkAppend- runSilent $ H.before_ (rec "outer") $ H.before_ (rec "inner") $ do+ evalSpec_ $ H.before_ (rec "outer") $ H.before_ (rec "inner") $ do H.it "foo" $ property $ \(_ :: Int) -> rec "foo" retrieve `shouldReturn` (take 300 . cycle) ["outer", "inner", "foo"] @@ -98,7 +98,7 @@ (rec, retrieve) <- mkAppend let action :: Int -> IO String action = return . show- runSilent $ H.before (return 23) $ H.beforeWith action $ do+ evalSpec_ $ H.before (return 23) $ H.beforeWith action $ do H.it "foo" $ \value -> rec value retrieve `shouldReturn` ["23"] @@ -114,7 +114,7 @@ (rec, retrieve) <- mkAppend - runSilent $ H.before (return 23) $ H.beforeWith action1 $ H.beforeWith action2 $ H.beforeWith action3 $ do+ evalSpec_ $ H.before (return 23) $ H.beforeWith action1 $ H.beforeWith action2 $ H.beforeWith action3 $ do H.it "foo" $ \value -> rec value retrieve `shouldReturn` ["foo 24"]@@ -122,7 +122,7 @@ describe "beforeAll" $ do it "runs an action before the first spec item" $ do (rec, retrieve) <- mkAppend- runSilent $ H.beforeAll (rec "beforeAll" >> return "value") $ do+ evalSpec_ $ H.beforeAll (rec "beforeAll" >> return "value") $ do H.it "foo" $ \value -> do rec $ "foo " ++ value H.it "bar" $ \value -> do@@ -135,24 +135,27 @@ context "when specified action throws an exception" $ do it "sets subsequent spec items to pending" $ do- result <- silence . H.hspecResult $ H.beforeAll (throwIO (ErrorCall "foo")) $ do+ evalSpec $ H.beforeAll throwException $ do H.it "foo" $ \n -> do n `shouldBe` (23 :: Int) H.it "bar" $ \n -> do n `shouldBe` 23- result `shouldBe` H.Summary {H.summaryExamples = 2, H.summaryFailures = 1}+ `shouldReturn` [+ item ["foo"] divideByZero+ , item ["bar"] (Pending (Just "exception in beforeAll-hook (see previous failure)"))+ ] context "when used with an empty list of examples" $ do it "does not run specified action" $ do (rec, retrieve) <- mkAppend- runSilent $ H.beforeAll (rec "beforeAll" >> return "value") $ do+ evalSpec_ $ H.beforeAll (rec "beforeAll" >> return "value") $ do return () retrieve `shouldReturn` [] describe "beforeAll_" $ do it "runs an action before the first spec item" $ do (rec, retrieve) <- mkAppend- runSilent $ H.beforeAll_ (rec "beforeAll_") $ do+ evalSpec_ $ H.beforeAll_ (rec "beforeAll_") $ do H.it "foo" $ do rec "foo" H.it "bar" $ do@@ -166,7 +169,7 @@ context "when used multiple times" $ do it "is evaluated outside in" $ do (rec, retrieve) <- mkAppend- runSilent $ H.beforeAll_ (rec "outer") $ H.beforeAll_ (rec "inner") $ do+ evalSpec_ $ H.beforeAll_ (rec "outer") $ H.beforeAll_ (rec "inner") $ do H.it "foo" $ do rec "foo" H.it "bar" $ do@@ -183,7 +186,7 @@ (rec, retrieve) <- mkAppend let action :: Int -> IO String action = return . show- runSilent $ H.beforeAll (return 23) $ H.beforeAllWith action $ do+ evalSpec_ $ H.beforeAll (return 23) $ H.beforeAllWith action $ do H.it "foo" $ \value -> rec value retrieve `shouldReturn` ["23"] @@ -199,7 +202,7 @@ (rec, retrieve) <- mkAppend - runSilent $ H.beforeAll (return 23) $+ evalSpec_ $ H.beforeAll (return 23) $ H.beforeAllWith action1 $ H.beforeAllWith action2 $ H.beforeAllWith action3 $ do H.it "foo" $ \value -> rec value @@ -207,7 +210,7 @@ it "runs an action before the first spec item" $ do (rec, retrieve) <- mkAppend- runSilent $ H.beforeAll (return (23 :: Int)) $+ evalSpec_ $ H.beforeAll (return (23 :: Int)) $ H.beforeAllWith (\value -> rec "beforeAllWith" >> return (show value)) $ do H.it "foo" $ \value -> do rec $ "foo " ++ value@@ -221,19 +224,22 @@ context "when specified action throws an exception" $ do it "sets subsequent spec items to pending" $ do- result <- silence . H.hspecResult $- H.beforeAll (return (23 :: Int)) $- H.beforeAllWith (\_ -> throwIO (ErrorCall "foo")) $ do+ evalSpec $ do+ H.beforeAll (return (23 :: Int)) $ do+ H.beforeAllWith (\ _ -> throwException) $ do H.it "foo" $ \n -> do n `shouldBe` (23 :: Int) H.it "bar" $ \n -> do n `shouldBe` 23- result `shouldBe` H.Summary {H.summaryExamples = 2, H.summaryFailures = 1}+ `shouldReturn` [+ item ["foo"] divideByZero+ , item ["bar"] (Pending (Just "exception in beforeAll-hook (see previous failure)"))+ ] context "when used with an empty list of examples" $ do it "does not run specified action" $ do (rec, retrieve) <- mkAppend- runSilent $ H.beforeAll (return (23 :: Int)) $+ evalSpec_ $ H.beforeAll (return (23 :: Int)) $ H.beforeAllWith (\_ -> rec "beforeAllWith" >> return "value") $ do return () retrieve `shouldReturn` []@@ -241,7 +247,7 @@ describe "after" $ do it "runs an action after every spec item" $ do (rec, retrieve) <- mkAppend- runSilent $ H.before (rec "before" >> return "from before") $ H.after rec $ do+ evalSpec_ $ H.before (rec "before" >> return "from before") $ H.after rec $ do H.it "foo" $ \_ -> do rec "foo" H.it "bar" $ \_ -> do@@ -257,16 +263,16 @@ it "guarantees that action is run" $ do (rec, retrieve) <- mkAppend- silence . ignoreExitCode . H.hspec $ H.before (rec "before" >> return "from before") $ H.after rec $ do+ evalSpec_ $ H.before (rec "before" >> return "from before") $ H.after rec $ do H.it "foo" $ \_ -> do- ioError $ userError "foo" :: IO ()+ throwException_ rec "foo" retrieve `shouldReturn` ["before", "from before"] describe "after_" $ do it "runs an action after every spec item" $ do (rec, retrieve) <- mkAppend- runSilent $ H.after_ (rec "after") $ do+ evalSpec_ $ H.after_ (rec "after") $ do H.it "foo" $ do rec "foo" H.it "bar" $ do@@ -280,16 +286,16 @@ it "guarantees that action is run" $ do (rec, retrieve) <- mkAppend- silence . ignoreExitCode $ H.hspec $ H.after_ (rec "after") $ do+ evalSpec_ $ H.after_ (rec "after") $ do H.it "foo" $ do- ioError $ userError "foo" :: IO ()+ throwException_ rec "foo" retrieve `shouldReturn` ["after"] context "when used multiple times" $ do it "is evaluated inside out" $ do (rec, retrieve) <- mkAppend- runSilent $ H.after_ (rec "after outer") $ H.after_ (rec "after inner") $ do+ evalSpec_ $ H.after_ (rec "after outer") $ H.after_ (rec "after inner") $ do H.it "foo" $ do rec "foo" retrieve `shouldReturn` [@@ -301,7 +307,7 @@ describe "afterAll" $ do it "runs an action after the last spec item" $ do (rec, retrieve) <- mkAppend- runSilent $ H.before (rec "before" >> return "from before") $ H.afterAll rec $ do+ evalSpec_ $ H.before (rec "before" >> return "from before") $ H.afterAll rec $ do H.it "foo" $ \_ -> do rec "foo" H.it "bar" $ \_ -> do@@ -333,7 +339,7 @@ describe "afterAll_" $ do it "runs an action after the last spec item" $ do (rec, retrieve) <- mkAppend- runSilent $ H.before_ (rec "before") $ H.afterAll_ (rec "afterAll_") $ do+ evalSpec_ $ H.before_ (rec "before") $ H.afterAll_ (rec "afterAll_") $ do H.it "foo" $ do rec "foo" H.it "bar" $ do@@ -350,7 +356,7 @@ context "when used multiple times" $ do it "is evaluated inside out" $ do (rec, retrieve) <- mkAppend- runSilent $ H.afterAll_ (rec "after outer") $ H.afterAll_ (rec "after inner") $ do+ evalSpec_ $ H.afterAll_ (rec "after outer") $ H.afterAll_ (rec "after inner") $ do H.it "foo" $ do rec "foo" retrieve `shouldReturn` [@@ -362,7 +368,7 @@ context "when used with an empty list of examples" $ do it "does not run specified action" $ do (rec, retrieve) <- mkAppend- runSilent $ H.afterAll_ (rec "afterAll_") $ do+ evalSpec_ $ H.afterAll_ (rec "afterAll_") $ do return () retrieve `shouldReturn` [] @@ -399,7 +405,7 @@ it "wraps every spec item with an action" $ do (rec, retrieve) <- mkAppend let action e = rec "before" >> e "from around" >> rec "after"- runSilent $ H.around action $ do+ evalSpec_ $ H.around action $ do H.it "foo" $ rec . ("foo " ++) H.it "bar" $ rec . ("bar " ++) retrieve `shouldReturn` [@@ -415,7 +421,7 @@ it "wraps every spec item with an action" $ do (rec, retrieve) <- mkAppend let action e = rec "before" >> e >> rec "after"- runSilent $ H.around_ action $ do+ evalSpec_ $ H.around_ action $ do H.it "foo" $ do rec "foo" H.it "bar" $ do@@ -434,7 +440,7 @@ (rec, retrieve) <- mkAppend let actionOuter e = rec "before outer" >> e >> rec "after outer" actionInner e = rec "before inner" >> e >> rec "after inner"- runSilent $ H.around_ actionOuter $ H.around_ actionInner $ do+ evalSpec_ $ H.around_ actionOuter $ H.around_ actionInner $ do H.it "foo" $ do rec "foo" retrieve `shouldReturn` [@@ -447,18 +453,41 @@ describe "aroundWith" $ do it "wraps every spec item with an action" $ do+ mock <- newMock (rec, retrieve) <- mkAppend- let action :: H.ActionWith String -> H.ActionWith Int- action e = e . show- runSilent $ H.before (return 23) $ H.aroundWith action $ do+ let action = (. show)+ evalSpec_ $ H.before (mockAction mock >> mockCounter mock) $ H.aroundWith action $ do H.it "foo" rec- retrieve `shouldReturn` ["23"]+ H.it "bar" rec+ H.it "baz" rec+ retrieve `shouldReturn` [+ "1"+ , "2"+ , "3"+ ]+ mockCounter mock `shouldReturn` 3 + describe "aroundAll" $ do+ it "wraps an action around a spec" $ do+ (rec, retrieve) <- mkAppend+ let action e = rec "before" *> e "from around" <* rec "after"+ evalSpec_ $ H.aroundAll action $ do+ H.it "foo" $ rec . ("foo " ++)+ H.it "bar" $ rec . ("bar " ++)+ H.it "baz" $ rec . ("baz " ++)+ retrieve `shouldReturn` [+ "before"+ , "foo from around"+ , "bar from around"+ , "baz from around"+ , "after"+ ]+ describe "aroundAll_" $ do it "wraps an action around a spec" $ do (rec, retrieve) <- mkAppend let action inner = rec "before" *> inner <* rec "after"- _ <- evalSpec $ H.aroundAll_ action $ do+ evalSpec_ $ H.aroundAll_ action $ do H.it "foo" $ rec "foo" H.it "bar" $ rec "bar" retrieve `shouldReturn` [@@ -474,7 +503,7 @@ action = mockAction mock >> mockCounter mock (rec, retrieve) <- mkAppend- _ <- evalSpec $ H.before action $ H.aroundAll_ id $ do+ evalSpec_ $ H.before action $ H.aroundAll_ id $ do H.it "foo" $ rec . show H.it "bar" $ rec . show H.it "baz" $ rec . show@@ -485,7 +514,7 @@ ] mockCounter mock `shouldReturn` 4 - it "reports exceptions in acquire-part" $ do+ it "reports exceptions on acquire" $ do evalSpec $ do H.aroundAll_ (throwException <*) $ do H.it "foo" True@@ -494,9 +523,43 @@ , item ["afterAll-hook"] (Pending (Just "exception in beforeAll-hook (see previous failure)")) ] - it "reports exceptions in cleanup-part" $ do+ it "reports exceptions on release" $ do evalSpec $ do H.aroundAll_ (<* throwException) $ do+ H.it "foo" True+ `shouldReturn` [+ item ["foo"] Success+ , item ["afterAll-hook"] divideByZero+ ]++ describe "aroundAllWith" $ do+ it "wraps an action around a spec" $ do+ mock <- newMock+ (rec, retrieve) <- mkAppend+ let action = (. show)+ evalSpec_ $ H.before (mockAction mock >> mockCounter mock) $ H.aroundAllWith action $ do+ H.it "foo" rec+ H.it "bar" rec+ H.it "baz" rec+ retrieve `shouldReturn` [+ "1"+ , "1"+ , "1"+ ]+ mockCounter mock `shouldReturn` 4++ it "reports exceptions on acquire" $ do+ evalSpec $ do+ H.aroundAllWith (\ action () -> throwException >>= action) $ do+ H.it "foo" H.pending+ `shouldReturn` [+ item ["foo"] divideByZero+ , item ["afterAll-hook"] (Pending (Just "exception in beforeAll-hook (see previous failure)"))+ ]++ it "reports exceptions on release" $ do+ evalSpec $ do+ H.aroundAllWith (\ action () -> action () <* throwException) $ do H.it "foo" True `shouldReturn` [ item ["foo"] Success
test/Test/Hspec/Core/RunnerSpec.hs view
@@ -540,7 +540,7 @@ it "treats uncaught exceptions as failure" $ do hspecResult_ $ do- H.it "foobar" throwException+ H.it "foobar" throwException_ `shouldReturn` H.Summary 1 1 it "uses the specdoc formatter by default" $ do
version.yaml view
@@ -1,1 +1,1 @@-&version 2.7.7+&version 2.7.8