derive-2.0.1: Derive/Test.hs
module Derive.Test(test) where
import Derive.Utils
import Language.Haskell.Exts
import Data.Derive.DSL.HSE
import Data.DeriveDSL
import Control.Monad
import Data.Maybe
import Data.List
import System.FilePath
import System.Directory
import System.Cmd
import System.Exit
import Control.Arrow
import Data.Char
import Data.Derive.All
import Data.Derive.Internal.Derivation
listType :: Decl
listType = DataDecl sl DataType [] (Ident "[]") [UnkindedVar $ Ident "a"]
[QualConDecl sl [] [] (ConDecl (Ident "[]") [])
,QualConDecl sl [] [] (ConDecl (Ident "Cons")
[UnBangedTy (TyVar (Ident "a"))
,UnBangedTy (TyApp (TyCon (UnQual (Ident "List"))) (TyVar (Ident "a")))])]
[]
-- test each derivation
test :: IO ()
test = do
decls <- fmap (filter isDataDecl . moduleDecls) $ readHSE "Data/Derive/Internal/Test.hs"
-- check the test bits
let ts = ("[]",listType) : map (dataDeclName &&& id) decls
mapM_ (testFile ts) derivations
-- check the $(derive) bits
putStrLn "Type checking examples"
let name = "AutoGenerated_Test.hs"
srcs <- sequence [readSrc $ "Data/Derive" </> derivationName d <.> "hs" | d <- derivations]
writeFile name $ unlines $ autoTest srcs decls derivations
res <- system $ "runhaskell " ++ name
when (res /= ExitSuccess) $ error "Failed to typecheck results"
testFile :: [(String,Decl)] -> Derivation -> IO ()
testFile types (Derivation name op) = do
putStrLn $ "Testing " ++ name
src <- readSrc $ "Data/Derive/" ++ name ++ ".hs"
forM_ (srcTest src) $ \(typ,res) -> do
let t = fromMaybe (error $ "wanting type: " ++ typ) $ lookup typ types
let Right r = op (ModuleName "Example", t)
when (not $ r `outEq` res) $
error $ "Results don't match!\nExpected:\n" ++ showOut res ++ "\nGot:\n" ++ showOut r ++ "\n\n" ++ detailedNeq res r
detailedNeq as bs | na /= nb = "Lengths don't match, " ++ show na ++ " vs " ++ show nb
where na = length as ; nb = length bs
detailedNeq as bs = "Mismatch on line " ++ show i ++ "\n" ++ show a ++ "\n" ++ show b
where (i,a,b) = head $ filter (\(i,a,b) -> a /= b) $ zip3 [1..] (noSl as) (noSl bs)
ignore = ["ArbitraryOld","Serial","BinaryDefer","EnumCyclic","Ref","PlateTypeable","LazySet"]
autoTest :: [Src] -> [DataDecl] -> [Derivation] -> [String]
autoTest ss ts ds =
["{-# LANGUAGE TemplateHaskell,FlexibleInstances,MultiParamTypeClasses #-}"
,"{-# OPTIONS_GHC -Wall -fno-warn-missing-fields #-}"
,"import Data.DeriveTH"
,"import Derive.TestInstances()"] ++
[prettyPrint i | s <- ss2, i <- srcImportStd s] ++
["main :: IO ()"
,"main = putStrLn \"Type checking successful\""] ++
[prettyPrint t | t <- ts2] ++
["$(derives [make" ++ derivationName d ++ "] " ++ types ++ ")" | d <- ds2]
where
types = "[" ++ intercalate "," ["''" ++ dataDeclName t | t <- ts2] ++ "]"
ts2 = filter (not . isBuiltIn) ts
ds2 = filter (flip notElem ignore . derivationName) $ order ds
ss2 = filter (flip notElem ignore . srcName) ss
isBuiltIn x = dataDeclName x `elem` ["Bool","Either"]
order :: [Derivation] -> [Derivation]
order ds = yes ++ no
where (yes,no) = partition (flip elem ["Eq","Typeable"] . derivationName) ds