can-i-haz-0.2.0.0: test/Spec.hs
{-# LANGUAGE MultiParamTypeClasses, RankNTypes, GADTs #-}
import Test.Hspec
import Test.HUnit.Lang
import Control.DeepSeq
import Control.Exception
import Data.List
import Control.Monad.Except.CoHas
import Control.Monad.Reader.Has
import Common
import TypecheckFailures
-- Reimplementing due to https://github.com/CRogers/should-not-typecheck/issues/18
shouldNotTypecheck :: NFData a => (() ~ () => a) -> Assertion
shouldNotTypecheck a = do
result <- try (evaluate $ force a)
case result of
Right _ -> assertFailure "Expected expression to not compile but it did compile"
Left e@(TypeError msg) -> case isSuffixOf "(deferred type error)" msg of
True -> return ()
False -> throwIO e
main :: IO ()
main = hspec $ do
let baseFooEnv = FooEnv 10 "meh"
let baseBarEnv = BarEnv 4.2 [1, 2, 3]
describe "Has" $ do
describe "Basic instance" $
it "any type Has itself" $ do
let exFoo = extract baseFooEnv
exFoo `shouldBe` baseFooEnv
describe "Generic instances" $ do
it "envs have their components" $ do
let exFoo = extract $ AppEnv baseFooEnv baseBarEnv
exFoo `shouldBe` baseFooEnv
let exBar = extract $ AppEnv baseFooEnv baseBarEnv
exBar `shouldBe` baseBarEnv
it "tuples have their components" $ do
let exFoo = extract (baseFooEnv, baseBarEnv)
exFoo `shouldBe` baseFooEnv
let exBar = extract (baseFooEnv, baseBarEnv)
exBar `shouldBe` baseBarEnv
describe "Should not typecheck" $ do
it "if there is no such type in the hierarchy" $ shouldNotTypecheck extractMissing
it "if there is more than one such type in the hierarchy" $ shouldNotTypecheck extractMultiple
describe "CoHas" $ do
describe "Basic instance" $
it "any type CoHas itself" $ do
let injected = 10 :: Int
let inFoo = inject injected
inFoo `shouldBe` injected
describe "Generic instances" $ do
it "sums have their components" $ do
let inFoo = inject baseFooEnv
inFoo `shouldBe` FooEnvErr baseFooEnv
let inBar = inject baseBarEnv
inBar `shouldBe` BarEnvErr baseBarEnv
it "Either has its components" $ do
let inFoo = inject baseFooEnv :: Either FooEnv Int
inFoo `shouldBe` Left baseFooEnv
let inBar = inject baseBarEnv :: Either Int BarEnv
inBar `shouldBe` Right baseBarEnv
describe "Should not typecheck" $ do
it "if there is no such type in the hierarchy" $ shouldNotTypecheck injectMissing
it "if there is more than one such type in the hierarchy" $ shouldNotTypecheck injectMultiple