forked from bohdan/loker
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtestingtool.hs
147 lines (129 loc) · 4.66 KB
/
testingtool.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
{-# LANGUAGE ExistentialQuantification, ScopedTypeVariables #-}
import Prelude hiding (catch)
import Control.Applicative
import Control.Monad
import Control.Exception
import System.Environment
import System.IO
import System.Exit
import System.Directory
import Data.List
import Data.Maybe
import AST
import Parsec
import Parse
-- for test with name "name":
-- tests/name.sh is test input
-- tests/name.sh.golden is expected output
data Test = forall a. (Show a, Read a, Eq a) =>
T { testParser :: Parser a, testName :: String }
withState :: Parser a -> Parser (a, SS)
withState p = (,) <$> p <*> getState
-- the tests
tests :: [Test]
tests = [T command "functions"
,T (withState program) "heredoc-quoted"
,T (withState program) "heredoc-newline-in-delimeter"
,T simpleCommand "line-cont"
,T simpleCommand "line-cont-space"
,T simpleCommand "line-cont-after-space"
,T token_word "line-cont-in-dquotes"
,T token_word "line-cont-in-squotes"
,T doubleQuoted "escape-dquote"
,T doubleQuoted "escape-dquote-2"
]
a </> b = a ++ "/" ++ b
a <.> b = a ++ "." ++ b
data TestResult a = NoTest
| NoGolden
| FailParseTest
| FailParseGolden
| DifferentResults
| OK a
deriving Show
data TestResultIO a = TestResultIO { runtrt :: IO (TestResult a) }
instance Monad TestResultIO where
return x = TestResultIO $ return $ OK x
a >>= f = TestResultIO $ do
x <- runtrt a
case x of
OK y -> runtrt $ f y
NoTest -> return NoTest
NoGolden -> return NoGolden
FailParseTest -> return FailParseTest
FailParseGolden -> return FailParseGolden
DifferentResults -> return DifferentResults
onError :: IO a -> TestResult a -> TestResultIO a
onError a r = TestResultIO $ (fmap OK $! a) `catch` (\(e :: SomeException) -> return r)
test :: Test -> IO (TestResult ())
test (T p name) = runtrt $ do
let inpf = "tests" </> name <.> "sh"
outpf = "tests" </> name <.> "sh" <.> "golden"
inp <- readFile inpf `onError` NoTest
outString <- readFile outpf `onError` NoGolden
outp <- evaluate (read outString) `onError` FailParseGolden
TestResultIO . return $ case parse p inpf inp of
Right r -> if r == outp then OK () else DifferentResults
Left _ -> FailParseTest
updateTest :: Test -> IO ()
updateTest (T p name) = do
let inpf = "tests" </> name <.> "sh"
outpf = "tests" </> name <.> "sh" <.> "golden"
inp <- readFile inpf
case parse p inpf inp of
Left err -> do
hPutStrLn stderr $ "WARNING: test " ++ name ++ " failed to parse:"
hPutStrLn stderr (show err)
Right r -> do
writeFile outpf $ show r ++ "\n"
-- runs all the tests in the test suite
-- todo: print more information
runTests = do
results <- forM tests $ \t -> do
r <- test t
case r of
OK _ -> return True
e -> do
putStrLn $ "test '" ++ testName t ++ "' failed: " ++ show e
return False
putStrLn $ "Successfully run " ++ show (length $ filter id results)
++ " out of " ++ show (length tests) ++ " tests"
-- lists all the tests in the test suite
listTests = putStr $ unlines $ map testName tests
-- updates the tests in the test suite
updateAllTests = mapM_ updateTest tests
updateTests names = forM_ names $ \n ->
case find ((n ==) .testName) tests of
Just t -> updateTest t
Nothing -> hPutStrLn stderr $ "WARNING: test "++n++" not found"
-- finds new tests in the "tests/" directory
findNewTests = do
files <- getDirectoryContents "tests"
let suffix = ".sh"
testNames = catMaybes $ flip map files $ \f ->
let (rsuffix,rprefix) = splitAt (length suffix) $ reverse f
in if rsuffix == reverse suffix
then Just $ reverse $ rprefix
else Nothing
putStr $ unlines $ testNames \\ map testName tests
-- prints usage information
usage = hPutStr stderr $ unlines
[ "USAGE: "
, "testingtool --run"
, "testingtool --help"
, "testingtool --list"
, "testingtool --update test ..."
, "testingtool --update-all-tests"
, "testingtool --find-new-tests"
]
main = do
args <- getArgs
case args of
[] -> runTests
["--run"] -> runTests
["--help"] -> usage
["--list"] -> listTests
"--update":tests -> updateTests tests
["--update-all-tests"] -> updateAllTests
["--find-new-tests"] -> findNewTests
_ -> do usage; exitFailure