module Common where import Control.Concurrent import Control.Concurrent.STM import Control.Eff import Control.Eff.Concurrent hiding (Timeout) import Control.Eff.Concurrent.Process.ForkIOScheduler as Scheduler import Control.Eff.Extend import Control.Monad (void) import GHC.Stack import Test.Tasty import Test.Tasty.HUnit import Test.Tasty.Runners setTravisTestOptions :: TestTree -> TestTree setTravisTestOptions = localOption (timeoutSeconds 60) . localOption (NumThreads 1) timeoutSeconds :: Integer -> Timeout timeoutSeconds seconds = Timeout (seconds * 1000000) (show seconds ++ "s") runTestCase :: TestName -> Eff InterruptableProcEff () -> TestTree runTestCase msg = testCase msg . runLift . withTraceLogging "unit-tests" local0 allLogMessages . Scheduler.schedule . handleInterrupts onInt where onInt = lift . assertFailure . show withTestLogC :: (e -> IO ()) -> (IO (e -> IO ()) -> TestTree) -> TestTree withTestLogC doSchedule k = k (return doSchedule) untilInterrupted :: Member t r => t (ResumeProcess v) -> Eff r () untilInterrupted pa = do r <- send pa case r of Interrupted _ -> return () _ -> untilInterrupted pa scheduleAndAssert :: forall r. (Lifted IO r, LogsTo IO r) => IO (Eff (InterruptableProcess r) () -> IO ()) -> ((String -> Bool -> Eff (InterruptableProcess r) ()) -> Eff (InterruptableProcess r) ()) -> IO () scheduleAndAssert schedulerFactory testCaseAction = withFrozenCallStack $ do resultVar <- newEmptyTMVarIO void (applySchedulerFactory schedulerFactory (testCaseAction (\title cond -> lift (atomically (putTMVar resultVar (title, cond)))))) (title, result) <- atomically (takeTMVar resultVar) assertBool title result applySchedulerFactory :: forall r. (Lifted IO r, LogsTo IO r) => IO (Eff (InterruptableProcess r) () -> IO ()) -> Eff (InterruptableProcess r) () -> IO () applySchedulerFactory factory procAction = do scheduler <- factory scheduler (procAction >> lift (threadDelay 20000))