context-0.2.0.0: test-suite/Test/Context/ConcurrentSpec.hs
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE TypeApplications #-}
module Test.Context.ConcurrentSpec
( spec
) where
import Prelude
import Test.Hspec
import qualified Context
import qualified Control.Monad as Monad
data Thing = Thing
{ stuff :: Int
} deriving stock (Eq, Show)
spec :: Spec
spec = do
describe "forkIO" do
describe "mineMay" do
it "empty stores" do
threadDone <- Context.newEmptyMVar
Context.withEmptyStore @IO @Thing \store1 -> do
Context.withEmptyStore @IO @Char \store2 -> do
Monad.void $ Context.forkIO do
Context.mineMay store1 `shouldReturn` Nothing
Context.mineMay store2 `shouldReturn` Nothing
Context.putMVar threadDone ()
Context.takeMVar threadDone
it "initially-empty stores with registered context" do
threadDone <- Context.newEmptyMVar
Context.withEmptyStore \store1 -> do
Context.use store1 Thing { stuff = 1 } do
Context.withEmptyStore \store2 -> do
Context.use store2 'a' do
Monad.void $ Context.forkIO do
Context.mineMay store1 `shouldReturn` Just Thing { stuff = 1 }
Context.mineMay store2 `shouldReturn` Just 'a'
Context.putMVar threadDone ()
Context.takeMVar threadDone
it "initially-empty stores with nested contexts" do
threadDone <- Context.newEmptyMVar
Context.withEmptyStore \store1 -> do
Context.use store1 Thing { stuff = 1 } do
Context.use store1 Thing { stuff = 2 } do
Context.withEmptyStore \store2 -> do
Context.use store2 'a' do
Context.use store2 'b' do
Monad.void $ Context.forkIO do
Context.mineMay store1 `shouldReturn` Just Thing { stuff = 2 }
Context.mineMay store2 `shouldReturn` Just 'b'
Context.putMVar threadDone ()
Context.takeMVar threadDone
it "non-empty stores" do
threadDone <- Context.newEmptyMVar
Context.withNonEmptyStore Thing { stuff = 1 } \store1 -> do
Context.withNonEmptyStore 'a' \store2 -> do
Monad.void $ Context.forkIO do
Context.mineMay store1 `shouldReturn` Just Thing { stuff = 1 }
Context.mineMay store2 `shouldReturn` Just 'a'
Context.putMVar threadDone ()
Context.takeMVar threadDone
describe "forkFinally" do
describe "mineMay" do
it "empty stores" do
threadDone <- Context.newEmptyMVar
Context.withEmptyStore @IO @Thing \store1 -> do
Context.withEmptyStore @IO @Char \store2 -> do
let checkStores = do
Context.mineMay store1 `shouldReturn` Nothing
Context.mineMay store2 `shouldReturn` Nothing
Monad.void $ Context.forkFinally checkStores \_eResult -> do
checkStores
Context.putMVar threadDone ()
Context.takeMVar threadDone
it "initially-empty stores with registered context" do
threadDone <- Context.newEmptyMVar
Context.withEmptyStore \store1 -> do
Context.use store1 Thing { stuff = 1 } do
Context.withEmptyStore \store2 -> do
Context.use store2 'a' do
let checkStores = do
Context.mineMay store1 `shouldReturn` Just Thing { stuff = 1 }
Context.mineMay store2 `shouldReturn` Just 'a'
Monad.void $ Context.forkFinally checkStores \_eResult -> do
checkStores
Context.putMVar threadDone ()
Context.takeMVar threadDone
it "initially-empty stores with nested contexts" do
threadDone <- Context.newEmptyMVar
Context.withEmptyStore \store1 -> do
Context.use store1 Thing { stuff = 1 } do
Context.use store1 Thing { stuff = 2 } do
Context.withEmptyStore \store2 -> do
Context.use store2 'a' do
Context.use store2 'b' do
let checkStores = do
Context.mineMay store1 `shouldReturn` Just Thing { stuff = 2 }
Context.mineMay store2 `shouldReturn` Just 'b'
Monad.void $ Context.forkFinally checkStores \_eResult -> do
checkStores
Context.putMVar threadDone ()
Context.takeMVar threadDone
it "non-empty stores" do
threadDone <- Context.newEmptyMVar
Context.withNonEmptyStore Thing { stuff = 1 } \store1 -> do
Context.withNonEmptyStore 'a' \store2 -> do
let checkStores = do
Context.mineMay store1 `shouldReturn` Just Thing { stuff = 1 }
Context.mineMay store2 `shouldReturn` Just 'a'
Monad.void $ Context.forkFinally checkStores \_eResult -> do
checkStores
Context.putMVar threadDone ()
Context.takeMVar threadDone
describe "forkIOWithUnmask" do
describe "mineMay" do
it "empty stores" do
threadDone <- Context.newEmptyMVar
Context.withEmptyStore @IO @Thing \store1 -> do
Context.withEmptyStore @IO @Char \store2 -> do
Monad.void $ Context.forkIOWithUnmask \_restore -> do
Context.mineMay store1 `shouldReturn` Nothing
Context.mineMay store2 `shouldReturn` Nothing
Context.putMVar threadDone ()
Context.takeMVar threadDone
it "initially-empty stores with registered context" do
threadDone <- Context.newEmptyMVar
Context.withEmptyStore \store1 -> do
Context.use store1 Thing { stuff = 1 } do
Context.withEmptyStore \store2 -> do
Context.use store2 'a' do
Monad.void $ Context.forkIOWithUnmask \_restore -> do
Context.mineMay store1 `shouldReturn` Just Thing { stuff = 1 }
Context.mineMay store2 `shouldReturn` Just 'a'
Context.putMVar threadDone ()
Context.takeMVar threadDone
it "initially-empty stores with nested contexts" do
threadDone <- Context.newEmptyMVar
Context.withEmptyStore \store1 -> do
Context.use store1 Thing { stuff = 1 } do
Context.use store1 Thing { stuff = 2 } do
Context.withEmptyStore \store2 -> do
Context.use store2 'a' do
Context.use store2 'b' do
Monad.void $ Context.forkIOWithUnmask \_restore -> do
Context.mineMay store1 `shouldReturn` Just Thing { stuff = 2 }
Context.mineMay store2 `shouldReturn` Just 'b'
Context.putMVar threadDone ()
Context.takeMVar threadDone
it "non-empty stores" do
threadDone <- Context.newEmptyMVar
Context.withNonEmptyStore Thing { stuff = 1 } \store1 -> do
Context.withNonEmptyStore 'a' \store2 -> do
Monad.void $ Context.forkIOWithUnmask \_restore -> do
Context.mineMay store1 `shouldReturn` Just Thing { stuff = 1 }
Context.mineMay store2 `shouldReturn` Just 'a'
Context.putMVar threadDone ()
Context.takeMVar threadDone
describe "forkOn" do
describe "mineMay" do
it "empty stores" do
threadDone <- Context.newEmptyMVar
Context.withEmptyStore @IO @Thing \store1 -> do
Context.withEmptyStore @IO @Char \store2 -> do
Monad.void $ Context.forkOn 1 do
Context.mineMay store1 `shouldReturn` Nothing
Context.mineMay store2 `shouldReturn` Nothing
Context.putMVar threadDone ()
Context.takeMVar threadDone
it "initially-empty stores with registered context" do
threadDone <- Context.newEmptyMVar
Context.withEmptyStore \store1 -> do
Context.use store1 Thing { stuff = 1 } do
Context.withEmptyStore \store2 -> do
Context.use store2 'a' do
Monad.void $ Context.forkOn 1 do
Context.mineMay store1 `shouldReturn` Just Thing { stuff = 1 }
Context.mineMay store2 `shouldReturn` Just 'a'
Context.putMVar threadDone ()
Context.takeMVar threadDone
it "initially-empty stores with nested contexts" do
threadDone <- Context.newEmptyMVar
Context.withEmptyStore \store1 -> do
Context.use store1 Thing { stuff = 1 } do
Context.use store1 Thing { stuff = 2 } do
Context.withEmptyStore \store2 -> do
Context.use store2 'a' do
Context.use store2 'b' do
Monad.void $ Context.forkOn 1 do
Context.mineMay store1 `shouldReturn` Just Thing { stuff = 2 }
Context.mineMay store2 `shouldReturn` Just 'b'
Context.putMVar threadDone ()
Context.takeMVar threadDone
it "non-empty stores" do
threadDone <- Context.newEmptyMVar
Context.withNonEmptyStore Thing { stuff = 1 } \store1 -> do
Context.withNonEmptyStore 'a' \store2 -> do
Monad.void $ Context.forkOn 1 do
Context.mineMay store1 `shouldReturn` Just Thing { stuff = 1 }
Context.mineMay store2 `shouldReturn` Just 'a'
Context.putMVar threadDone ()
Context.takeMVar threadDone
describe "forkOnWithUnmask" do
describe "mineMay" do
it "empty stores" do
threadDone <- Context.newEmptyMVar
Context.withEmptyStore @IO @Thing \store1 -> do
Context.withEmptyStore @IO @Char \store2 -> do
Monad.void $ Context.forkOnWithUnmask 1 \_restore -> do
Context.mineMay store1 `shouldReturn` Nothing
Context.mineMay store2 `shouldReturn` Nothing
Context.putMVar threadDone ()
Context.takeMVar threadDone
it "initially-empty stores with registered context" do
threadDone <- Context.newEmptyMVar
Context.withEmptyStore \store1 -> do
Context.use store1 Thing { stuff = 1 } do
Context.withEmptyStore \store2 -> do
Context.use store2 'a' do
Monad.void $ Context.forkOnWithUnmask 1 \_restore -> do
Context.mineMay store1 `shouldReturn` Just Thing { stuff = 1 }
Context.mineMay store2 `shouldReturn` Just 'a'
Context.putMVar threadDone ()
Context.takeMVar threadDone
it "initially-empty stores with nested contexts" do
threadDone <- Context.newEmptyMVar
Context.withEmptyStore \store1 -> do
Context.use store1 Thing { stuff = 1 } do
Context.use store1 Thing { stuff = 2 } do
Context.withEmptyStore \store2 -> do
Context.use store2 'a' do
Context.use store2 'b' do
Monad.void $ Context.forkOnWithUnmask 1 \_restore -> do
Context.mineMay store1 `shouldReturn` Just Thing { stuff = 2 }
Context.mineMay store2 `shouldReturn` Just 'b'
Context.putMVar threadDone ()
Context.takeMVar threadDone
it "non-empty stores" do
threadDone <- Context.newEmptyMVar
Context.withNonEmptyStore Thing { stuff = 1 } \store1 -> do
Context.withNonEmptyStore 'a' \store2 -> do
Monad.void $ Context.forkOnWithUnmask 1 \_restore -> do
Context.mineMay store1 `shouldReturn` Just Thing { stuff = 1 }
Context.mineMay store2 `shouldReturn` Just 'a'
Context.putMVar threadDone ()
Context.takeMVar threadDone
describe "forkOS" do
describe "mineMay" do
it "empty stores" do
threadDone <- Context.newEmptyMVar
Context.withEmptyStore @IO @Thing \store1 -> do
Context.withEmptyStore @IO @Char \store2 -> do
Monad.void $ Context.forkOS do
Context.mineMay store1 `shouldReturn` Nothing
Context.mineMay store2 `shouldReturn` Nothing
Context.putMVar threadDone ()
Context.takeMVar threadDone
it "initially-empty stores with registered context" do
threadDone <- Context.newEmptyMVar
Context.withEmptyStore \store1 -> do
Context.use store1 Thing { stuff = 1 } do
Context.withEmptyStore \store2 -> do
Context.use store2 'a' do
Monad.void $ Context.forkOS do
Context.mineMay store1 `shouldReturn` Just Thing { stuff = 1 }
Context.mineMay store2 `shouldReturn` Just 'a'
Context.putMVar threadDone ()
Context.takeMVar threadDone
it "initially-empty stores with nested contexts" do
threadDone <- Context.newEmptyMVar
Context.withEmptyStore \store1 -> do
Context.use store1 Thing { stuff = 1 } do
Context.use store1 Thing { stuff = 2 } do
Context.withEmptyStore \store2 -> do
Context.use store2 'a' do
Context.use store2 'b' do
Monad.void $ Context.forkOS do
Context.mineMay store1 `shouldReturn` Just Thing { stuff = 2 }
Context.mineMay store2 `shouldReturn` Just 'b'
Context.putMVar threadDone ()
Context.takeMVar threadDone
it "non-empty stores" do
threadDone <- Context.newEmptyMVar
Context.withNonEmptyStore Thing { stuff = 1 } \store1 -> do
Context.withNonEmptyStore 'a' \store2 -> do
Monad.void $ Context.forkOS do
Context.mineMay store1 `shouldReturn` Just Thing { stuff = 1 }
Context.mineMay store2 `shouldReturn` Just 'a'
Context.putMVar threadDone ()
Context.takeMVar threadDone
describe "forkOSWithUnmask" do
describe "mineMay" do
it "empty stores" do
threadDone <- Context.newEmptyMVar
Context.withEmptyStore @IO @Thing \store1 -> do
Context.withEmptyStore @IO @Char \store2 -> do
Monad.void $ Context.forkOSWithUnmask \_restore -> do
Context.mineMay store1 `shouldReturn` Nothing
Context.mineMay store2 `shouldReturn` Nothing
Context.putMVar threadDone ()
Context.takeMVar threadDone
it "initially-empty stores with registered context" do
threadDone <- Context.newEmptyMVar
Context.withEmptyStore \store1 -> do
Context.use store1 Thing { stuff = 1 } do
Context.withEmptyStore \store2 -> do
Context.use store2 'a' do
Monad.void $ Context.forkOSWithUnmask \_restore -> do
Context.mineMay store1 `shouldReturn` Just Thing { stuff = 1 }
Context.mineMay store2 `shouldReturn` Just 'a'
Context.putMVar threadDone ()
Context.takeMVar threadDone
it "initially-empty stores with nested contexts" do
threadDone <- Context.newEmptyMVar
Context.withEmptyStore \store1 -> do
Context.use store1 Thing { stuff = 1 } do
Context.use store1 Thing { stuff = 2 } do
Context.withEmptyStore \store2 -> do
Context.use store2 'a' do
Context.use store2 'b' do
Monad.void $ Context.forkOSWithUnmask \_restore -> do
Context.mineMay store1 `shouldReturn` Just Thing { stuff = 2 }
Context.mineMay store2 `shouldReturn` Just 'b'
Context.putMVar threadDone ()
Context.takeMVar threadDone
it "non-empty stores" do
threadDone <- Context.newEmptyMVar
Context.withNonEmptyStore Thing { stuff = 1 } \store1 -> do
Context.withNonEmptyStore 'a' \store2 -> do
Monad.void $ Context.forkOSWithUnmask \_restore -> do
Context.mineMay store1 `shouldReturn` Just Thing { stuff = 1 }
Context.mineMay store2 `shouldReturn` Just 'a'
Context.putMVar threadDone ()
Context.takeMVar threadDone
describe "runInBoundThread" do
describe "mineMay" do
it "empty stores" do
threadDone <- Context.newEmptyMVar
Context.withEmptyStore @IO @Thing \store1 -> do
Context.withEmptyStore @IO @Char \store2 -> do
Context.runInBoundThread do
Context.mineMay store1 `shouldReturn` Nothing
Context.mineMay store2 `shouldReturn` Nothing
Context.putMVar threadDone ()
Context.takeMVar threadDone
it "initially-empty stores with registered context" do
threadDone <- Context.newEmptyMVar
Context.withEmptyStore \store1 -> do
Context.use store1 Thing { stuff = 1 } do
Context.withEmptyStore \store2 -> do
Context.use store2 'a' do
Context.runInBoundThread do
Context.mineMay store1 `shouldReturn` Just Thing { stuff = 1 }
Context.mineMay store2 `shouldReturn` Just 'a'
Context.putMVar threadDone ()
Context.takeMVar threadDone
it "initially-empty stores with nested contexts" do
threadDone <- Context.newEmptyMVar
Context.withEmptyStore \store1 -> do
Context.use store1 Thing { stuff = 1 } do
Context.use store1 Thing { stuff = 2 } do
Context.withEmptyStore \store2 -> do
Context.use store2 'a' do
Context.use store2 'b' do
Context.runInBoundThread do
Context.mineMay store1 `shouldReturn` Just Thing { stuff = 2 }
Context.mineMay store2 `shouldReturn` Just 'b'
Context.putMVar threadDone ()
Context.takeMVar threadDone
it "non-empty stores" do
threadDone <- Context.newEmptyMVar
Context.withNonEmptyStore Thing { stuff = 1 } \store1 -> do
Context.withNonEmptyStore 'a' \store2 -> do
Context.runInBoundThread do
Context.mineMay store1 `shouldReturn` Just Thing { stuff = 1 }
Context.mineMay store2 `shouldReturn` Just 'a'
Context.putMVar threadDone ()
Context.takeMVar threadDone
describe "runInUnboundThread" do
describe "mineMay" do
it "empty stores" do
threadDone <- Context.newEmptyMVar
Context.withEmptyStore @IO @Thing \store1 -> do
Context.withEmptyStore @IO @Char \store2 -> do
Context.runInUnboundThread do
Context.mineMay store1 `shouldReturn` Nothing
Context.mineMay store2 `shouldReturn` Nothing
Context.putMVar threadDone ()
Context.takeMVar threadDone
it "initially-empty stores with registered context" do
threadDone <- Context.newEmptyMVar
Context.withEmptyStore \store1 -> do
Context.use store1 Thing { stuff = 1 } do
Context.withEmptyStore \store2 -> do
Context.use store2 'a' do
Context.runInUnboundThread do
Context.mineMay store1 `shouldReturn` Just Thing { stuff = 1 }
Context.mineMay store2 `shouldReturn` Just 'a'
Context.putMVar threadDone ()
Context.takeMVar threadDone
it "initially-empty stores with nested contexts" do
threadDone <- Context.newEmptyMVar
Context.withEmptyStore \store1 -> do
Context.use store1 Thing { stuff = 1 } do
Context.use store1 Thing { stuff = 2 } do
Context.withEmptyStore \store2 -> do
Context.use store2 'a' do
Context.use store2 'b' do
Context.runInUnboundThread do
Context.mineMay store1 `shouldReturn` Just Thing { stuff = 2 }
Context.mineMay store2 `shouldReturn` Just 'b'
Context.putMVar threadDone ()
Context.takeMVar threadDone
it "non-empty stores" do
threadDone <- Context.newEmptyMVar
Context.withNonEmptyStore Thing { stuff = 1 } \store1 -> do
Context.withNonEmptyStore 'a' \store2 -> do
Context.runInUnboundThread do
Context.mineMay store1 `shouldReturn` Just Thing { stuff = 1 }
Context.mineMay store2 `shouldReturn` Just 'a'
Context.putMVar threadDone ()
Context.takeMVar threadDone