{-# LANGUAGE DeriveDataTypeable #-} module UnliftIO.MemoizeSpec (spec) where import Control.Concurrent (threadDelay) import Control.Monad (replicateM_) import Test.Hspec import Test.Hspec.QuickCheck import UnliftIO import Data.Typeable data Dummy = Dummy deriving (Show, Typeable) instance Exception Dummy spec :: Spec spec = do let basics maker = do prop "sanity" $ \i -> do x <- maker $ return (i :: Int) runMemoized x `shouldReturn` i prop "runs once" $ \i -> do count <- newIORef (0 :: Int) x <- maker $ do modifyIORef' count (+ 1) return (i :: Int) replicateM_ 10 $ runMemoized x `shouldReturn` i readIORef count `shouldReturn` 1 it "runs once with exception" $ do count <- newIORef (0 :: Int) x <- maker $ do modifyIORef' count (+ 1) throwIO Dummy replicateM_ 10 $ runMemoized x `shouldThrow` (\Dummy -> True) readIORef count `shouldReturn` 1 describe "memoizeRef" $ basics memoizeRef describe "memoizeMVar" $ do basics memoizeMVar prop "runs once in multiple threads" $ \i -> do count <- newIORef (0 :: Int) x <- memoizeMVar $ do threadDelay 10000 atomicModifyIORef' count $ \cnt -> (cnt + 1, ()) return (i :: Int) replicateConcurrently_ 10 $ runMemoized x `shouldReturn` i readIORef count `shouldReturn` 1