module Festung.Concurrency.JobSpec (spec) where

import Test.Hspec

import Control.Concurrent
import Data.Maybe (isNothing)
import Festung.Concurrency.Job


newSquareJob :: IO (Job (Command Int Int))
newSquareJob = newJob_ handler
    where handler (Command n responder) = putMVar responder (n * n)


-- Same as isEmptyMVar except that it really tries to read the MVar.
checkEmptyMVar :: MVar a -> IO Bool
checkEmptyMVar mvar = isNothing <$> tryReadMVar mvar


spec :: Spec
spec = do
    describe "newJob" $
        it "Starts a running job" $ do
            job <- newSquareJob
            isJobRunning job `shouldReturn` True

    describe "sendCommand" $ do
        it "Sends commands" $ do
            job <- newSquareJob
            let sendCommand' = sendCommand job
            sendCommand' 1 `shouldReturn` Just 1
            sendCommand' 2 `shouldReturn` Just 4

        it "Returns Nothing when the Job is terminated" $ do
            job <- newSquareJob
            killJob job
            sendCommand job 1 `shouldReturn` Nothing

    -- These tests might be flaky. Remove them if they fail!
    describe "killJob" $ do
        it "Exits the job" $ do
            job <- newSquareJob
            killJob job
            isJobExited job `shouldReturn` True

        it "Prevents the job from running" $ do
            job <- newSquareJob
            killJob job
            isJobRunning job `shouldReturn` False