packages feed

emgm-0.3: tests/Derive.hs

{-# LANGUAGE CPP                        #-}
{-# LANGUAGE TemplateHaskell            #-}
{-# LANGUAGE TypeOperators              #-}
{-# LANGUAGE FlexibleInstances          #-}
{-# LANGUAGE FlexibleContexts           #-}
{-# LANGUAGE MultiParamTypeClasses      #-}
{-# LANGUAGE OverlappingInstances       #-}
{-# LANGUAGE UndecidableInstances       #-}
{-# OPTIONS_GHC -fno-warn-unused-binds  #-}
{-  OPTIONS_GHC -ddump-splices           -}

-----------------------------------------------------------------------------
-- |
-- Module      :  Derive
-- Copyright   :  (c) 2008, 2009 Universiteit Utrecht
-- License     :  BSD3
--
-- Maintainer  :  generics@haskell.org
-----------------------------------------------------------------------------

module Derive (tests) where

--------------------------------------------------------------------------------
-- Imports
--------------------------------------------------------------------------------

import Data.Char (ord, toUpper)
import Test.HUnit

import Generics.EMGM as G
import Generics.EMGM.Derive

--------------------------------------------------------------------------------
-- Test deriving for functor type
--------------------------------------------------------------------------------

newtype A a = A a

$(derive ''A)

data B a
  = B1 a Int
  | B2 Char a
  | B3 (B a) (B a)
  | B4 (B Double)
  | B5 (Maybe a)
  | B6 (A (Maybe [a]))
  | B7 (a,a)
--  | B_ (Int -> a)         -- UNSUPPORTED

-- We only support a functor type containing constant types or another functor
-- type. In other words, we don't support higher arity type constructors (>1
-- type arguments).

$(derive ''B)

--------------------------------------------------------------------------------
-- Test for other things
--------------------------------------------------------------------------------

data C a
  = C1 (a,Int) -- ^ odd tuple
  | C2 String  -- ^ type synonym
  | C3 (a,a,a) (a,a,a,a) (a,a,C a,a,a) (a,a,a,a,a,a) (a,a,a,a,a,a,a)
       -- ^ tuples and type constructor application up to arity 7.
  | C4 a -- ^ included so we don't get the warning about the repC function's
         -- argument being defined but not used.
  deriving (Eq, Prelude.Show)

$(derive ''C)

test_mapC = "map ord (C3 ...)" ~: G.map ord i ~?= o
  where
    i = C3 ('a','a','a') ('b','b','b','b') ('c','c',C2 "blah",'c','c') ('d','d','d','d','d','d') ('e','e','e','e','e','e','e')
    o = C3 (97,97,97) (98,98,98,98) (99,99,C2 "blah",99,99) (100,100,100,100,100,100) (101,101,101,101,101,101,101)

--------------------------------------------------------------------------------
-- Test for deriving bifunctor type
--------------------------------------------------------------------------------

data D a b
  = D1 a Int
  | D2 Double b
  | D3 (D a b)
  | D4 (D a b) (D a b)
  | D5 (D b a)
  | D6 (Either a b) (b,a) (b,Int)
  | D7 [a]

-- We only support a bifunctor type containing constant types or another
-- bifunctor type. In other words, we don't support a bifunctor type containing
-- a functor type or a higher arity type constructors (>2 type arguments).

$(derive ''D)

--------------------------------------------------------------------------------
-- Test for ChangeTo
--------------------------------------------------------------------------------

infixr 7 :#

data a :* b
  = Int :% a
  | Float :# b
  | a :* b

$(deriveWith [(":%", ChangeTo "Percent"), (":#", ChangeTo "Hash"), (":*", ChangeTo "Star")] ''(:*))

test_ChangeTo1 = "ChangeTo Percent" ~: conPercent ~?= ConDescr ":%" 2 [] (Infixl 9)
test_ChangeTo2 = "ChangeTo Hash" ~: conHash ~?= ConDescr ":#" 2 [] (Infixr 7)
test_ChangeTo3 = "ChangeTo Star" ~: assert (G.show (to epStar (from epStar x)) `eq` "'a' :* 97")
  where
    x :: Char :* Integer
    x = 'a' :* 97

--------------------------------------------------------------------------------
-- Test for DefinedAs
--------------------------------------------------------------------------------

data E = E { unE :: Integer } deriving Prelude.Show

$(deriveWith [("E", DefinedAs "E")] ''E)
conE = ConDescr "E" 1 [] Nonfix

test_DefinedAs1 =
  "DefinedAs E" ~:
    (assert $ Prelude.show (E 37) `eq` "E {unE = 37}" && G.show (E 37) `eq` "E 37")

--------------------------------------------------------------------------------
-- Test for manual deriving
--------------------------------------------------------------------------------

data F a = F a Int

$(declareConDescrs ''F)
$(declareEP ''F)
$(declareRepValues ''F)
$(deriveRep ''F)
$(deriveFRep ''F)
$(deriveCollect ''F)
$(deriveEverywhere ''F)

test_manual1 =
  "show $ map ord (C 'a' 4)" ~:
    assert (G.show (G.map ord (F 'a' 4)) `eq` "F 97 4")

test_manual2 =
  "collect (F (4::Integer) 3)" ~:
    assert (collect (F (4::Integer) 3) `eq` ([F 4 3::F Integer]))

test_manual3 =
  "everywhere toUpper (F 'x' 3)" ~:
    assert (everywhere toUpper (F 'x' 3) `eq` F 'X' 3)

--------------------------------------------------------------------------------
-- Test collection
--------------------------------------------------------------------------------

tests =
  "Derive" ~:
    [ test_mapC
    , test_ChangeTo1
    , test_ChangeTo2
    , test_ChangeTo3
    , test_DefinedAs1
    , test_manual1
    , test_manual2
    , test_manual3
    ]