{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE ScopedTypeVariables #-} module RIO.DequeSpec (spec) where import RIO import Test.Hspec import Test.Hspec.QuickCheck import Test.QuickCheck.Arbitrary import Test.QuickCheck.Gen import qualified Data.Vector as VB import qualified Data.Vector.Generic as VG import qualified Data.Vector.Unboxed as VU import qualified Data.Vector.Storable as VS import qualified Data.Vector.Generic.Mutable as V data DequeAction = PushFront Int | PushBack Int | PopFront | PopBack deriving Show instance Arbitrary DequeAction where arbitrary = oneof $ concat [ replicate 25 $ fmap PushFront arbitrary , replicate 25 $ fmap PushBack arbitrary , [return PopFront, return PopBack] ] manyPushes :: [DequeAction] manyPushes = concat [ replicate 50 $ PushBack 0 , replicate 50 PopFront , replicate 50 $ PushFront 0 , replicate 50 PopBack ] specialCase :: [DequeAction] specialCase = [PushBack 9, PushBack 5,PushBack 11,PushBack 2,PushBack 13,PushBack 10,PushBack 4,PushBack 13,PushBack 7,PushBack 8,PushBack 6,PushBack 4,PushBack 7,PushBack 9,PushBack 10,PushBack 3,PushBack 2,PushBack 12,PushBack 12 ,PushBack 6,PushBack 3,PushBack 5,PushBack 14,PushBack 14,PushBack 11,PushBack 8,PopFront,PopFront,PopFront,PushBack 11,PushBack 3,PopFront,PopFront,PushBack 13,PushBack 12,PopFront,PushBack 10,PushBack 7,PopFront,PopFront,PushBack 13,PushBack 9,PopFront,PushBack 7,PushBack 2,PopFront,PopFront,PushBack 6,PushBack 4,PopFront,PopFront,PopFront,PushBack 9,PushBack 3,PopFront,PushBack 10,PushBack 6,PopFront,PopFront,PopFront,PushBack 12,PushBack 5,PopFront,PushBack 12,PushBack 5,PopFront,PushBack 6,PushBack 4,PopFront,PopFront,PopFront,PushBack 14,PushBack 10,PopFront,PushBack 14,PushBack 10,PopFront,PushBack 11,PushBack 8,PopFront,PushBack 8,PushBack 2,PopFront,PopFront,PopFront,PushBack 13,PushBack 7,PopFront,PushBack 12,PushBack 5,PopFront,PushBack 10,PushBack 8, PopFront,PushBack 7,PushBack 2,PopFront,PopFront,PushBack 9,PushBack 4,PopFront,PopFront,PopFront,PopFront,PopFront,PopFront,PopFront,PopFront,PushBack 4,PushBack 9,PushBack 3,PushBack 10,PushBack 6,PushBack 4,PushBack 13,PushBack 7,PushBack 9,PushBack 3,PopFront] spec :: Spec spec = do let runActions :: forall v . (VG.Vector v Int, Show (v Int), Eq (v Int)) => Proxy v -> [DequeAction] -> IO () runActions proxy actions = do base <- newIORef [] :: IO (IORef [Int]) tested <- newDeque :: IO (Deque (VG.Mutable v) (PrimState IO) Int) for_ (PopFront : PopBack : actions) $ \action -> do case action of PushFront i -> do pushFrontRef base i pushFrontDeque tested i same proxy base tested PushBack i -> do pushBackRef base i pushBackDeque tested i same proxy base tested PopFront -> do expected <- popFrontRef base actual <- popFrontDeque tested actual `shouldBe` expected same proxy base tested PopBack -> do expected <- popBackRef base actual <- popBackDeque tested actual `shouldBe` expected same proxy base tested let drain = do expected <- popBackRef base actual <- popBackDeque tested actual `shouldBe` expected case actual of Just _ -> drain Nothing -> return $! () drain test name proxy = describe name $ do prop "arbitrary actions" $ runActions proxy it "many pushes" $ runActions proxy manyPushes it "special case" $ runActions proxy specialCase test "UDeque" (Proxy :: Proxy VU.Vector) test "SDeque" (Proxy :: Proxy VS.Vector) test "BDeque" (Proxy :: Proxy VB.Vector) pushFrontRef :: IORef [Int] -> Int -> IO () pushFrontRef ref i = modifyIORef ref (i:) pushBackRef :: IORef [Int] -> Int -> IO () pushBackRef ref i = modifyIORef ref (++ [i]) popFrontRef :: IORef [Int] -> IO (Maybe Int) popFrontRef ref = do is <- readIORef ref case is of i:is' -> do writeIORef ref is' pure $ Just i [] -> pure Nothing popBackRef :: IORef [Int] -> IO (Maybe Int) popBackRef ref = do is <- readIORef ref case reverse is of i:is' -> do writeIORef ref $ reverse is' pure $ Just i [] -> pure Nothing same :: forall v. (Show (v Int), Eq (v Int), VG.Vector v Int) => Proxy v -> IORef [Int] -> Deque (VG.Mutable v) (PrimState IO) Int -> IO () same proxy ref deque = do fromRef <- readIORef ref fromRight <- foldrDeque (\i rest -> pure $ i : rest) [] deque fromRight `shouldBe` fromRef fromLeft <- foldlDeque (\rest i -> pure $ i : rest) [] deque fromLeft `shouldBe` reverse fromRef dequeToList deque `shouldReturn` fromRef dequeToVector deque `shouldReturn` (VU.fromList fromRef :: VU.Vector Int) uv :: v Int <- freezeDeque deque uv `shouldBe` VG.fromList fromRef