summaryrefslogtreecommitdiff
path: root/test/runTests.hs
diff options
context:
space:
mode:
Diffstat (limited to 'test/runTests.hs')
-rw-r--r--test/runTests.hs198
1 files changed, 198 insertions, 0 deletions
diff --git a/test/runTests.hs b/test/runTests.hs
new file mode 100644
index 00000000..a25e6158
--- /dev/null
+++ b/test/runTests.hs
@@ -0,0 +1,198 @@
1{-# LANGUAGE OverloadedStrings, PackageImports, LambdaCase #-}
2{-# LANGUAGE FlexibleContexts #-}
3module Main where
4
5import Data.List
6import Control.Applicative
7import Control.Arrow
8import Control.Concurrent
9import Control.Concurrent.Async
10import Control.Monad
11import Control.Monad.Reader
12
13import System.Environment
14import System.Exit
15import System.Directory
16import System.FilePath
17import System.IO
18import Control.Exception hiding (catch)
19import Control.Monad.Trans.Control
20import Control.Monad.Catch
21import Control.DeepSeq
22import qualified Data.Set as Set
23
24import LambdaCube.Compiler.Pretty hiding ((</>))
25import LambdaCube.Compiler.CGExp
26import LambdaCube.Compiler.Driver
27import LambdaCube.Compiler.CoreToIR
28import IR (Backend(..))
29import Text.Parsec.Pos
30
31instance NFData SourcePos where
32 rnf _ = ()
33
34acceptPath = "./testdata/accept"
35rejectPath = "./testdata/reject"
36timeout = 15 {- in seconds -}
37
38data Res = Accepted | New | Rejected | Failed | ErrorCatched
39 deriving (Eq, Ord, Show)
40
41erroneous = (>= Rejected)
42
43instance NFData Res where
44 rnf a = a `seq` ()
45
46optionArgs = ["-v", "-r"]
47
48main :: IO ()
49main = do
50 hSetBuffering stdout NoBuffering
51 hSetBuffering stdin NoBuffering
52 args <- getArgs
53
54 let samplesToAccept = filter (not . flip elem optionArgs) args
55 verbose = elem "-v" args
56 reject = elem "-r" args
57 (testToAccept,testToReject) <- case samplesToAccept of
58 [] -> do
59 toAccept <- map dropExtension . filter (\n -> ".lc" == takeExtension n) <$> getDirectoryContents acceptPath
60 toReject <- map dropExtension . filter (\n -> ".lc" == takeExtension n) <$> getDirectoryContents rejectPath
61 return (toAccept, toReject)
62 _ -> do
63 let intersect = Set.toList . Set.intersection (Set.fromList samplesToAccept) . Set.fromList
64 toAccept <- intersect . map dropExtension . filter (\n -> ".lc" == takeExtension n) <$> getDirectoryContents acceptPath
65 toReject <- intersect . map dropExtension . filter (\n -> ".lc" == takeExtension n) <$> getDirectoryContents rejectPath
66 return (toAccept, toReject)
67
68 n <- runMM' $ do
69 liftIO $ putStrLn $ "------------------------------------ Checking valid pipelines"
70 n1 <- acceptTests reject testToAccept
71
72 liftIO $ putStrLn $ "------------------------------------ Catching errors (must get an error)"
73 n2 <- rejectTests reject testToReject
74
75 return $ n1 ++ n2
76
77 let sh b ty = [(if erroneous ty then "!" else "") ++ show (length ss) ++ " " ++ pad 10 (b ++ ": ") ++ intercalate ", " ss | not $ null ss]
78 where
79 ss = sort [s | (ty', s) <- n, ty' == ty]
80 let results = [t | (t,_) <- n]
81
82 putStrLn $ "------------------------------------ Summary\n" ++
83 if null n
84 then "All OK"
85 else unlines $
86 sh "crashed test" ErrorCatched
87 ++ sh "failed test" Failed
88 ++ sh "rejected result" Rejected
89 ++ sh "new result" New
90 ++ sh "accepted result" Accepted
91 when (any erroneous results) exitFailure
92
93acceptTests reject = testFrame reject [acceptPath, rejectPath] $ \case
94 Left e -> Left e
95 Right (Left e, i) -> Right ("typechecked", unlines $ e: "tooltips:": [showRange (b, e) ++ " " ++ m | (b, e, m) <- i])
96 Right (Right e, i)
97 | True <- i `deepseq` False -> error "impossible"
98 | tyOf e == TCon0 "Output"
99 -> Right ("compiled main", show . compilePipeline True OpenGL33 $ e)
100 | tyOf e == TCon0 "Bool" -> case e of
101 x@(A0 "True") -> Right ("main ~~> True", ppShow x)
102 x -> Left $ "main should be True but it is \n" ++ ppShow x
103 | otherwise -> Right ("reduced main " ++ ppShow (tyOf e), ppShow e)
104-- | otherwise -> Right ("System-F main ", ppShow . toCore mempty $ e)
105
106rejectTests reject = testFrame reject [rejectPath, acceptPath] $ \case
107 Left e -> Right ("error message", e)
108 Right _ -> Left "failed to catch error"
109
110runMM' = fmap (either (error "impossible") id . fst) . runMM (ioFetch [])
111
112testFrame :: Bool -> [FilePath] -> (Either String (Either String Exp, Infos) -> Either String (String, String)) -> [String] -> MMT IO [(Res, String)]
113testFrame reject dirs f tests
114 = local (const $ ioFetch dirs') . testFrame_ compare (head dirs') (\n -> do
115 result <- catchMM $ getDef (ExpN n) (ExpN "main") Nothing
116 return $ f result) $ tests
117 where
118 compare = if reject then alwaysReject else compareResult
119 dirs_ = [takeDirectory f | f <- tests, takeFileName f /= f]
120 dirs' = if null dirs_ then dirs else dirs_
121
122
123timeOut :: Int -> a -> MM a -> MM a
124timeOut n d m = MMT $
125 control (\runInIO ->
126 race' (runInIO (runMMT m))
127 (threadDelay (n * 1000000) >> (runInIO $ return d)))
128 where
129 race' a b = either id id <$> race a b
130
131testFrame_ compareResult path action tests = fmap concat $ forM (zip [1..] (tests :: [String])) $ \(i, n) -> do
132 let er e = do
133 liftIO $ putStrLn $ "\n!Crashed " ++ n ++ "\n" ++ tab e
134 return [(ErrorCatched, n)]
135 catchErr er $ do
136 result <- timeOut timeout (Left "Timed Out") (action n)
137 liftIO $ case result of
138 Left e -> do
139 putStrLn $ "\n!Failed " ++ n ++ "\n" ++ tab e
140 return [(Failed, n)]
141 Right (op, x) -> do
142 length x `seq` compareResult n (pad 15 op) (path </> (n ++ ".out")) x
143 where
144 tab = unlines . map (" " ++) . lines
145
146-- Reject unrigestered or chaned results automatically
147alwaysReject n msg ef e = doesFileExist ef >>= \b -> case b of
148 False -> putStrLn ("Unregistered - " ++ msg) >> return [(Rejected, n)]
149 True -> do
150 e' <- readFile ef
151 case map fst $ filter snd $ zip [0..] $ zipWith (/=) e e' of
152 [] -> return []
153 rs -> do
154 putStrLn $ msg ++ " has changed."
155 putStrLn "------------------------------------------- Old"
156 putStrLn $ showRanges ef rs e'
157 putStrLn "------------------------------------------- New"
158 putStrLn $ showRanges ef rs e
159 putStrLn "-------------------------------------------"
160 return [(Rejected, n)]
161
162compareResult n msg ef e = doesFileExist ef >>= \b -> case b of
163 False -> writeFile ef e >> putStrLn ("OK - " ++ msg ++ " is written") >> return [(New, n)]
164 True -> do
165 e' <- readFile ef
166 case map fst $ filter snd $ zip [0..] $ zipWith (/=) e e' ++ replicate (abs $ length e - length e') True of
167 [] -> return []
168 rs -> do
169 putStrLn $ msg ++ " has changed."
170 putStrLn "------------------------------------------- Old"
171 putStrLn $ showRanges ef rs e'
172 putStrLn "------------------------------------------- New"
173 putStrLn $ showRanges ef rs e
174 putStrLn "-------------------------------------------"
175 putStr $ "Accept new " ++ msg ++ " (y/n)? "
176 c <- length e' `seq` getChar
177 if c `elem` ("yY\n" :: String)
178 then writeFile ef e >> putStrLn " - accepted." >> return [(Accepted, n)]
179 else putStrLn " - not Accepted." >> return [(Rejected, n)]
180
181pad n s = s ++ replicate (n - length s) ' '
182
183limit :: String -> Int -> String -> String
184limit msg n s = take n s ++ if null (drop n s) then "" else msg
185
186showRanges :: String -> [Int] -> String -> String
187showRanges fname is e = (if head rs == 0 then "" else "...\n")
188 ++ limit ("\n... (see " ++ fname ++ " for more differences)") 140000 (intercalate "\n...\n" $ f (zipWith (-) rs (0:rs)) e)
189 where
190 f :: [Int] -> String -> [String]
191 f (i:is) e = g is $ drop i e
192 f [] "" = []
193 f [] _ = ["\n..."]
194 g (i:is) e = take i e: f is (drop i e)
195 rs = (head is - x) : concat [[a + x, b - x] | (a, b) <- zip is (tail is), a + y < b] ++ [last is + x]
196 x = 100000
197 y = 3*x
198