{-# LANGUAGE MagicHash #-} {-# LANGUAGE ScopedTypeVariables #-} module GenericsSpec (main, spec) where import Data.Functor.Classes import Data.Proxy (Proxy(..)) import GenericsTypes import Test.Hspec import Test.Hspec.QuickCheck (prop) import Test.QuickCheck (Arbitrary) import Text.Read (minPrec) main :: IO () main = hspec spec prop_Eq :: (Eq a, Eq (f a), Eq1 f) => f a -> f a -> Expectation prop_Eq x y = (x == y) `shouldBe` eq1 x y eqSpec :: forall f a. (Arbitrary (f a), Show (f a), Eq a, Eq (f a), Eq1 f) => Proxy (f a) -> Spec eqSpec _ = prop "has a valid Eq1 instance" (prop_Eq :: f a -> f a -> Expectation) prop_Ord :: (Ord a, Ord (f a), Ord1 f) => f a -> f a -> Expectation prop_Ord x y = compare x y `shouldBe` compare1 x y ordSpec :: forall f a. (Arbitrary (f a), Show (f a), Ord a, Ord (f a), Ord1 f) => Proxy (f a) -> Spec ordSpec _ = prop "has a valid Ord1 instance" (prop_Ord :: f a -> f a -> Expectation) -- Adapted from the definition of readEither readEither' :: String -> (Int -> ReadS a) -> Either String a readEither' s rs = case [ x | (x,"") <- rs minPrec s ] of [x] -> Right x [] -> Left "read': no parse" _ -> Left "read': ambiguous parse" read' :: String -> (Int -> ReadS a) -> a read' s = either error id . readEither' s prop_Read :: forall f a. (Read a, Read (f a), Read1 f, Eq (f a), Show (f a)) => f a -> Expectation prop_Read x = readArb readsPrec `shouldBe` readArb readsPrec1 where readArb :: (Int -> ReadS (f a)) -> f a readArb = read' (show x) readSpec :: forall f a. (Arbitrary (f a), Eq (f a), Show (f a), Read a, Read (f a), Read1 f) => Proxy (f a) -> Spec readSpec _ = prop "has a valid Read1 instance" (prop_Read :: f a -> Expectation) prop_Show :: (Show a, Show (f a), Show1 f) => Int -> f a -> Expectation prop_Show p x = showsPrec p x "" `shouldBe` showsPrec1 p x "" showSpec :: forall f a. (Arbitrary (f a), Show a, Show (f a), Show1 f) => Proxy (f a) -> Spec showSpec _ = prop "has a valid Show1 instance" (prop_Show :: Int -> f a -> Expectation) classes1Spec :: forall f a. (Arbitrary (f a), Ord a, Ord (f a), Ord1 f, Read a, Read (f a), Read1 f, Show a, Show (f a), Show1 f) => String -> Proxy (f a) -> Spec classes1Spec str proxy = describe str $ do eqSpec proxy ordSpec proxy readSpec proxy showSpec proxy spec :: Spec spec = parallel $ do classes1Spec "TestParam" (Proxy :: Proxy (TestParam Int)) classes1Spec "T#" (Proxy :: Proxy (T# Int)) classes1Spec "Infix" (Proxy :: Proxy (Infix Int)) classes1Spec "GADT" (Proxy :: Proxy (GADT Int)) classes1Spec "Record" (Proxy :: Proxy (Record Int)) describe "Prim" $ do let proxy :: Proxy (Prim Int) proxy = Proxy eqSpec proxy ordSpec proxy showSpec proxy describe "Empty" $ do let proxy :: Proxy (Empty Int) proxy = Proxy eqSpec proxy ordSpec proxy it "should fail to parse eagerly" $ do let readEmpty :: String -> (Int -> ReadS (Empty Int)) -> Either String (Empty Int) readEmpty = readEither' readEmpty "" readsPrec `shouldBe` readEmpty "" readsPrec1 readEmpty (error "boom") readsPrec `shouldBe` readEmpty (error "boom") readsPrec1