1-----------------------------------------------------------------------------
4-- License : MIT (http://opensource.org/licenses/MIT)
6-- Maintainer : Phil Freeman <paf31@cantab.net>
7-- Stability : experimental
12-----------------------------------------------------------------------------
14{-# LANGUAGE DataKinds #-}
15{-# LANGUAGE DoAndIfThenElse #-}
16{-# LANGUAGE TupleSections #-}
17{-# LANGUAGE FlexibleInstances #-}
19-- Failing tests can specify the kind of error that should be thrown with a
20-- @shouldFailWith declaration. For example:
22-- "-- @shouldFailWith TypesDoNotUnify"
24-- will cause the test to fail unless that module fails to compile with exactly
25-- one TypesDoNotUnify error.
27-- If a module is expected to produce multiple type errors, then use multiple
28-- @shouldFailWith lines; for example:
30-- -- @shouldFailWith TypesDoNotUnify
31-- -- @shouldFailWith TypesDoNotUnify
32-- -- @shouldFailWith TransitiveExportError
35module Main (main) where
40import qualified Language.PureScript as P
41import qualified Language.PureScript.CodeGen.JS as J
42import qualified Language.PureScript.CoreFn as CF
43import qualified Language.PureScript.Docs as Docs
45import Data.Char (isSpace)
46import Data.Maybe (mapMaybe, fromMaybe)
47import Data.List (isSuffixOf, sort, stripPrefix)
48import Data.Time.Clock (UTCTime())
50import qualified Data.Map as M
53import Control.Monad.IO.Class (liftIO)
54import Control.Arrow ((>>>))
56import Control.Monad.Reader
57import Control.Monad.Writer.Strict
58import Control.Monad.Trans.Maybe
59import Control.Monad.Trans.Except
60import Control.Monad.Error.Class
65import System.Directory
67import qualified System.Info
68import qualified System.FilePath.Glob as Glob
70import Text.Parsec (ParseError)
74import qualified TestDocs
77modulesDir = ".test_modules" </> "node_modules"
79makeActions :: M.Map P.ModuleName FilePath -> P.MakeActions P.Make
80makeActions foreigns = (P.buildMakeActions modulesDir (P.internalError "makeActions: input file map was read.") foreigns False)
81 { P.getInputTimestamp = getInputTimestamp
82 , P.getOutputTimestamp = getOutputTimestamp
85 getInputTimestamp :: P.ModuleName -> P.Make (Either P.RebuildPolicy (Maybe UTCTime))
87 | isSupportModule (P.runModuleName mn) = return (Left P.RebuildNever)
88 | otherwise = return (Left P.RebuildAlways)
90 isSupportModule = flip elem supportModules
92 getOutputTimestamp :: P.ModuleName -> P.Make (Maybe UTCTime)
93 getOutputTimestamp mn = do
94 let filePath = modulesDir </> P.runModuleName mn
95 exists <- liftIO $ doesDirectoryExist filePath
96 return (if exists then Just (P.internalError "getOutputTimestamp: read timestamp") else Nothing)
98readInput :: [FilePath] -> IO [(FilePath, String)]
99readInput inputFiles = forM inputFiles $ \inputFile -> do
100 text <- readUTF8File inputFile
101 return (inputFile, text)
103type TestM = WriterT [(FilePath, String)] IO
105runTest :: P.Make a -> IO (Either P.MultipleErrors a)
106runTest = fmap fst . P.runMake P.defaultOptions
108compile :: [FilePath] -> M.Map P.ModuleName FilePath -> IO (Either P.MultipleErrors P.Environment)
109compile inputFiles foreigns = runTest $ do
110 fs <- liftIO $ readInput inputFiles
111 ms <- P.parseModulesFromFiles id fs
112 P.make (makeActions foreigns) (map snd ms)
114assert :: [FilePath] ->
115 M.Map P.ModuleName FilePath ->
116 (Either P.MultipleErrors P.Environment -> IO (Maybe String)) ->
118assert inputFiles foreigns f = do
119 e <- liftIO $ compile inputFiles foreigns
120 maybeErr <- liftIO $ f e
122 Just err -> tell [(last inputFiles, err)]
125assertCompiles :: [FilePath] -> M.Map P.ModuleName FilePath -> TestM ()
126assertCompiles inputFiles foreigns = do
127 liftIO . putStrLn $ "Assert " ++ last inputFiles ++ " compiles successfully"
128 assert inputFiles foreigns $ \e ->
130 Left errs -> return . Just . P.prettyPrintMultipleErrors False $ errs
132 process <- findNodeProcess
133 let entryPoint = modulesDir </> "index.js"
134 writeFile entryPoint "require('Main').main()"
135 result <- traverse (\node -> readProcessWithExitCode node [entryPoint] "") process
137 Just (ExitSuccess, out, _) -> putStrLn out >> return Nothing
138 Just (ExitFailure _, _, err) -> return $ Just err
139 Nothing -> return $ Just "Couldn't find node.js executable"
141assertDoesNotCompile :: [FilePath] -> M.Map P.ModuleName FilePath -> TestM ()
142assertDoesNotCompile inputFiles foreigns = do
143 let testFile = last inputFiles
144 liftIO . putStrLn $ "Assert " ++ testFile ++ " does not compile"
145 shouldFailWith <- getShouldFailWith testFile
146 assert inputFiles foreigns $ \e ->
149 putStrLn (P.prettyPrintMultipleErrors False errs)
150 return $ if null shouldFailWith
151 then Just $ "shouldFailWith declaration is missing (errors were: "
152 ++ show (map P.errorCode (P.runMultipleErrors errs))
154 else checkShouldFailWith shouldFailWith errs
156 return $ Just "Should not have compiled"
163 >>> mapMaybe (stripPrefix "-- @shouldFailWith ")
167 checkShouldFailWith expected errs =
168 let actual = map P.errorCode $ P.runMultipleErrors errs
169 in if sort expected == sort actual
171 else Just $ "Expected these errors: " ++ show expected ++ ", but got these: " ++ show actual
174 dropWhile isSpace >>> reverse >>> dropWhile isSpace >>> reverse
178 heading "Main compiler test suite"
180 heading "Documentation test suite"
182 -- heading "psc-publish test suite"
188 putStrLn $ replicate 79 '#'
189 putStrLn $ "# " ++ msg
190 putStrLn $ replicate 79 '#'
196 cwd <- getCurrentDirectory
198 let supportDir = cwd </> "tests" </> "support" </> "flattened"
199 let supportFiles ext = Glob.globDir1 (Glob.compile ("*." ++ ext)) supportDir
201 supportPurs <- supportFiles "purs"
202 supportJS <- supportFiles "js"
204 foreignFiles <- forM supportJS (\f -> (f,) <$> readUTF8File f)
205 Right (foreigns, _) <- runExceptT $ runWriterT $ P.parseForeignModulesFromFiles foreignFiles
207 let passing = cwd </> "examples" </> "passing"
208 passingTestCases <- sort . filter (".purs" `isSuffixOf`) <$> getDirectoryContents passing
209 let failing = cwd </> "examples" </> "failing"
210 failingTestCases <- sort . filter (".purs" `isSuffixOf`) <$> getDirectoryContents failing
212 failures <- execWriterT $ do
213 forM_ passingTestCases $ \inputFile ->
214 assertCompiles (supportPurs ++ [passing </> inputFile]) foreigns
215 forM_ failingTestCases $ \inputFile ->
216 assertDoesNotCompile (supportPurs ++ [failing </> inputFile]) foreigns
222 forM_ failures $ \(fp, err) ->
223 let fp' = fromMaybe fp $ stripPrefix (failing ++ [pathSeparator]) fp
224 in putStrLn $ fp' ++ ": " ++ err
227testPscPublish :: IO ()
229 testPackage "tests/support/prelude"
232supportModules :: [String]
234 [ "Control.Monad.Eff.Class"
235 , "Control.Monad.Eff.Console"
236 , "Control.Monad.Eff"
237 , "Control.Monad.Eff.Unsafe"
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list