packages feed

lrucaching-0.1.0: test/Data/LruCache/IOSpec.hs

module Data.LruCache.IOSpec
  (spec
  ) where

import           Control.Monad (foldM_)
import           Control.Monad.IO.Class
import           Data.IORef
import           Data.Set (Set)
import qualified Data.Set as Set
import           Test.Hspec
import qualified Test.QuickCheck as QC
import qualified Test.QuickCheck.Monadic as QC

import           Data.LruCache.IO
import           Data.LruCache.SpecHelper

spec :: Spec
spec =
  do describe "cached" $ do
       it "evicts leasts recently used elements" $ do
         QC.property historic

-- | Tests if elements not evicted have been recently accessed.
historic ::
  SmallInt ->             -- ^ Capacity
  [(SmallInt, String)] -> -- ^ Key-value pairs
  QC.Property             -- ^ Property
historic (SmallInt capacity) pairs = QC.monadicIO $
  do h <- liftIO $ newLruHandle capacity
     foldM_ (step h) [] pairs
     where
       step h history (k, v) = do
         wasInCacheRef <- liftIO $ newIORef True
         _             <- liftIO $ cached h k $ 
           do writeIORef wasInCacheRef False
              return v
         wasInCache    <- liftIO $ readIORef wasInCacheRef
         let recentKeys = nMostRecentKeys capacity Set.empty history
         QC.assert (Set.member k recentKeys == wasInCache)
         return ((k, v) : history)

nMostRecentKeys :: Ord k => Int -> Set k -> [(k, v)] -> Set k
nMostRecentKeys _ keys []   = keys
nMostRecentKeys n keys ((k, _) : history)
  | Set.size keys >= n      = keys
  | otherwise               =
      nMostRecentKeys n (Set.insert k keys) history