diff --git a/src/Quasar/Disposable.hs b/src/Quasar/Disposable.hs index 6ecb90a9d2f949a1d9db7cad9e77cc0cf5ae0e9a..03cb56b73a1557fc8b036bb12463b780ea63dba0 100644 --- a/src/Quasar/Disposable.hs +++ b/src/Quasar/Disposable.hs @@ -273,7 +273,8 @@ collectGarbage resourceManager = go >> traceIO "gc: completed" traceIO "gc: change detected" - -- Check entries for completion. Completion will be queried with `entryIsEmpty` during the next STM transaction. + -- Checking entries for completion has to be done in IO. + -- Completion is then queried with `entryIsEmpty` during the following STM transaction. checkEntries =<< atomically (readTVar entriesVar') traceIO "gc: entries checked" diff --git a/test/Quasar/DisposableSpec.hs b/test/Quasar/DisposableSpec.hs index de3982d227ff04a89ef48a53a4c175018ea6eaae..0acc9e08ca3150287a61ed05af032d0f326638f1 100644 --- a/test/Quasar/DisposableSpec.hs +++ b/test/Quasar/DisposableSpec.hs @@ -1,5 +1,6 @@ module Quasar.DisposableSpec (spec) where +import Control.Exception import Control.Concurrent import Control.Monad (void) import Prelude @@ -7,6 +8,11 @@ import Test.Hspec import Quasar.Awaitable import Quasar.Disposable +data TestException = TestException + deriving (Eq, Show) + +instance Exception TestException + spec :: Spec spec = parallel $ do describe "Disposable" $ do @@ -36,6 +42,13 @@ spec = parallel $ do withResourceManager \resourceManager -> do attachDisposable resourceManager noDisposable + it "can attach an disposable" $ do + withResourceManager \resourceManager -> do + avar <- newAsyncVar :: IO (AsyncVar ()) + attachDisposable resourceManager $ alreadyDisposing avar + putAsyncVar_ avar () + pure () :: IO () + it "can dispose an awaitable that is completed asynchronously" $ do avar <- newAsyncVar :: IO (AsyncVar ()) void $ forkIO $ do @@ -44,3 +57,21 @@ spec = parallel $ do withResourceManager \resourceManager -> do attachDisposable resourceManager (alreadyDisposing avar) + + it "can call a trivial dispose action" $ do + withResourceManager \resourceManager -> + attachDisposeAction resourceManager $ pure $ pure () + pure () :: IO () + + it "can call a dispose action" $ do + withResourceManager \resourceManager -> do + avar <- newAsyncVar :: IO (AsyncVar ()) + attachDisposeAction resourceManager $ toAwaitable avar <$ putAsyncVar_ avar () + pure () :: IO () + + it "re-throws an exception from a dispose action" $ do + shouldThrow + do + withResourceManager \resourceManager -> + attachDisposeAction resourceManager $ throwIO $ TestException + \TestException -> True