mockcat-0.5.4.0: test/Test/MockCat/PartialMockSpec.hs
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
{-# OPTIONS_GHC -Wno-orphans #-}
{-# OPTIONS_GHC -Wno-name-shadowing #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE InstanceSigs #-}
{-# OPTIONS_GHC -Wno-redundant-constraints #-}
{-# LANGUAGE MultiParamTypeClasses #-}
module Test.MockCat.PartialMockSpec (spec) where
import Data.Text (Text, pack)
import Test.Hspec (Spec, it, shouldBe, describe)
import Test.MockCat
import Test.MockCat.Definition
import Test.MockCat.Impl ()
import Prelude hiding (readFile, writeFile)
import Data.Data
import Data.List (find)
import GHC.TypeLits (KnownSymbol, symbolVal)
import Unsafe.Coerce (unsafeCoerce)
import Control.Monad.IO.Class (MonadIO, liftIO)
import Control.Monad.Trans.Class (lift)
import Control.Monad.Trans.Maybe (MaybeT (..))
import Control.Monad.Trans.Reader hiding (ask)
instance (MonadIO m, FileOperation m) => FileOperation (MockT m) where
readFile path = MockT do
defs <- getDefinitions
case findParam (Proxy :: Proxy "readFile") defs of
Just mock -> do
let !result = stubFn mock path
pure result
Nothing -> lift $ readFile path
writeFile path content = MockT do
defs <- getDefinitions
case findParam (Proxy :: Proxy "writeFile") defs of
Just mock -> do
let !result = stubFn mock path content
pure result
Nothing -> lift $ writeFile path content
_readFile :: (MockBuilder params (FilePath -> Text) (Param FilePath), MonadIO m) => params -> MockT m ()
_readFile p = MockT $ do
mockInstance <- liftIO $ createNamedMock "readFile" p
addDefinition (Definition (Proxy :: Proxy "readFile") mockInstance shouldApplyToAnything)
_writeFile :: (MockBuilder params (FilePath -> Text -> ()) (Param FilePath :> Param Text), MonadIO m) => params -> MockT m ()
_writeFile p = MockT $ do
mockInstance <- liftIO $ createNamedMock "writeFile" p
addDefinition (Definition (Proxy :: Proxy "writeFile") mockInstance shouldApplyToAnything)
findParam :: KnownSymbol sym => Proxy sym -> [Definition] -> Maybe a
findParam pa definitions = do
let definition = find (\(Definition s _ _) -> symbolVal s == symbolVal pa) definitions
fmap (\(Definition _ mock _) -> unsafeCoerce mock) definition
instance (MonadIO m, Finder a b m) => Finder a b (MockT m) where
findIds :: (Finder a b m) => MockT m [a]
findIds = MockT do
defs <- getDefinitions
case findParam (Proxy :: Proxy "_findIds") defs of
Just mock -> do
let !result = stubFn mock
pure result
Nothing -> lift findIds
findById :: (Finder a b m) => a -> MockT m b
findById id = MockT do
defs <- getDefinitions
case findParam (Proxy :: Proxy "_findById") defs of
Just mock -> do
let !result = stubFn mock id
pure result
Nothing -> lift $ findById id
_findIds :: MonadIO m => r -> MockT m ()
_findIds p = MockT $ do
mockInstance <- liftIO $ createNamedConstantMock "_findIds" p
addDefinition (Definition (Proxy :: Proxy "_findIds") mockInstance shouldApplyToAnything)
spec :: Spec
spec = do
describe "Partial Mock Test" do
it "MaybeT" do
result <- runMaybeT do
runMockT do
_writeFile $ "output.text" |> pack "MaybeT content" |> ()
program "input.txt" "output.text"
result `shouldBe` Just ()
it "IO" do
result <- runMockT do
_writeFile $ "output.text" |> pack "IO content" |> ()
program "input.txt" "output.text"
result `shouldBe` ()
it "ReaderT" do
result <- flip runReaderT "foo" do
runMockT do
_writeFile $ "output.text" |> pack "ReaderT content foo" |> ()
program "input.txt" "output.text"
result `shouldBe` ()
describe "MultiParamType" do
it "all real function" do
values <- runMockT findValue
values `shouldBe` ["{id: 1}", "{id: 2}", "{id: 3}"]
it "partial 1" do
values <- runMockT do
_findIds [1 :: Int, 2]
findValue
values `shouldBe` ["{id: 1}", "{id: 2}"]