type-assertions-0.1.0.0: test-suite/Test/TypeAssertionsSpec.hs
{-# OPTIONS_GHC -fno-warn-unused-top-binds #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeApplications #-}
module Test.TypeAssertionsSpec (spec) where
import Test.Hspec
import Test.TypeAssertions
import Control.Exception (evaluate)
import Data.Typeable (Typeable)
import Control.Monad.TestFixture
import Control.Monad.TestFixture.TH
newtype Id a = Id Int
deriving (Eq, Show, Num)
class (Show a, Typeable a) => DBRecord a
data User = User
deriving (Eq, Show)
instance DBRecord User
data Post = Post
deriving (Eq, Show)
instance DBRecord Post
class Monad m => DB m where
fetchRecord :: DBRecord a => Id a -> m (Maybe a)
insertRecord :: DBRecord a => a -> m (Maybe (Id a))
mkFixture "Fixture" [ts| DB |]
spec :: Spec
spec = do
describe "assertEq" $ do
let fixture :: FixturePure = def {
_insertRecord = \record -> case assertHasT @Post record of
Refl -> return $ Just 3 }
it "produces a witness if the provided value matches the given type" $ do
let result = unTestFixture (insertRecord Post) fixture
result `shouldBe` Just 3
it "throws an exception if the provided value does not match the given type" $ do
let result = unTestFixture (insertRecord User) fixture
let message = "expected value of type ‘Post’, but got ‘User’, which is of type ‘User’"
evaluate result `shouldThrow` errorCall message
describe "withAssertEq" $ do
let fixture :: FixturePure = def {
_insertRecord = \record -> withAssertHasT @Post record $
return $ Just 3 }
it "produces a witness if the provided value matches the given type" $ do
let result = unTestFixture (insertRecord Post) fixture
result `shouldBe` Just 3
it "throws an exception if the provided value does not match the given type" $ do
let result = unTestFixture (insertRecord User) fixture
let message = "expected value of type ‘Post’, but got ‘User’, which is of type ‘User’"
evaluate result `shouldThrow` errorCall message
describe "assertEqT" $ do
let fixture :: FixturePure = def {
_fetchRecord = \(_ :: Id record) -> case assertEqT @record @Post of
Refl -> return $ Just Post }
it "gains type information when the given types match" $ do
let result = unTestFixture (fetchRecord 0) fixture
result `shouldBe` Just Post
it "throws an exception if the given types do not match" $ do
let result = unTestFixture (fetchRecord (0 :: Id User)) fixture
let message = "expected type ‘Post’, but got type ‘User’"
evaluate result `shouldThrow` errorCall message
describe "withAssertEqT" $ do
let fixture :: FixturePure = def {
_fetchRecord = \(_ :: Id record) -> withAssertEqT @record @Post $
return $ Just Post }
it "gains type information when the given types match" $ do
let result = unTestFixture (fetchRecord 0) fixture
result `shouldBe` Just Post
it "throws an exception if the given types do not match" $ do
let result = unTestFixture (fetchRecord (0 :: Id User)) fixture
let message = "expected type ‘Post’, but got type ‘User’"
evaluate result `shouldThrow` errorCall message