@@ -27,14 +27,15 @@ import qualified Language.PureScript as P
28import Data.Char (isSpace)
28import Data.Char (isSpace)
29import Data.Function (on)
29import Data.Function (on)
30−import Data.List (sort, stripPrefix, intercalate, groupBy, sortBy, partition)
30+import Data.List (sort, stripPrefix, intercalate, groupBy, sortBy)
31import Data.Maybe (mapMaybe)
31import Data.Maybe (mapMaybe)
32import Data.Time.Clock (UTCTime())
32import Data.Time.Clock (UTCTime())
33+import Data.Tuple (swap)
34import qualified Data.Map as M
35import qualified Data.Map as M
36import Control.Monad
37import Control.Monad
37−import Control.Arrow ((>>>))
38+import Control.Arrow ((***), (>>>))
39import Control.Monad.Reader
40import Control.Monad.Reader
40import Control.Monad.Writer.Strict
41import Control.Monad.Writer.Strict
@@ -57,7 +58,7 @@ main = hspec spec
57spec :: Spec
58spec :: Spec
60− (supportExterns, supportForeigns, passingTestCases, failingTestCases) <- runIO $ do
61+ (supportExterns, passingTestCases, failingTestCases) <- runIO $ do
61 cwd <- getCurrentDirectory
62 cwd <- getCurrentDirectory
62 let passing = cwd </> "examples" </> "passing"
63 let passing = cwd </> "examples" </> "passing"
63 let failing = cwd </> "examples" </> "failing"
64 let failing = cwd </> "examples" </> "failing"
@@ -66,49 +67,40 @@ spec = do
66 passingFiles <- getTestFiles passing <$> testGlob passing
67 passingFiles <- getTestFiles passing <$> testGlob passing
67 failingFiles <- getTestFiles failing <$> testGlob failing
68 failingFiles <- getTestFiles failing <$> testGlob failing
68 supportPurs <- supportFiles "purs"
69 supportPurs <- supportFiles "purs"
69− supportForeigns <- loadForeigns =<< supportFiles "js"
70 supportPursFiles <- readInput supportPurs
70 supportPursFiles <- readInput supportPurs
71 supportExterns <- runExceptT $ do
71 supportExterns <- runExceptT $ do
72 modules <- ExceptT . return $ P.parseModulesFromFiles id supportPursFiles
72 modules <- ExceptT . return $ P.parseModulesFromFiles id supportPursFiles
73+ foreigns <- inferForeignModules modules
73− externs <- ExceptT . runTest $ P.make (makeActions supportForeigns) (map snd modules)
74+ externs <- ExceptT . runTest $ P.make (makeActions foreigns) (map snd modules)
74 return (zip (map snd modules) externs)
75 return (zip (map snd modules) externs)
75 case supportExterns of
76 case supportExterns of
76 Left errs -> fail (P.prettyPrintMultipleErrors False errs)
77 Left errs -> fail (P.prettyPrintMultipleErrors False errs)
77− Right externs -> return (externs, supportForeigns, passingFiles, failingFiles)
78+ Right externs -> return (externs, passingFiles, failingFiles)
79 context ("Passing examples") $ do
80 context ("Passing examples") $ do
80− forM_ passingTestCases $ \(testPurs, testJS) ->
81+ forM_ passingTestCases $ \testPurs ->
81− it ("'" <> takeFileName (getTestMain testPurs) <> "' should compile and run without error") $ do
82+ it ("'" <> takeFileName (getTestMain testPurs) <> "' should compile and run without error") $
82− testForeigns <- loadForeigns testJS
83− assertCompiles supportExterns testPurs (supportForeigns <> testForeigns)
83+ assertCompiles supportExterns testPurs
85 context ("Failing examples") $ do
85 context ("Failing examples") $ do
86− forM_ failingTestCases $ \(testPurs, testJS) -> do
86+ forM_ failingTestCases $ \testPurs -> do
87 let mainPath = getTestMain testPurs
87 let mainPath = getTestMain testPurs
88 expectedFailures <- runIO $ getShouldFailWith mainPath
88 expectedFailures <- runIO $ getShouldFailWith mainPath
89− it ("'" <> takeFileName mainPath <> "' should fail with '" <> intercalate "', '" expectedFailures <> "'") $ do
89+ it ("'" <> takeFileName mainPath <> "' should fail with '" <> intercalate "', '" expectedFailures <> "'") $
90− testForeigns <- loadForeigns testJS
91− assertDoesNotCompile supportExterns testPurs (supportForeigns <> testForeigns) expectedFailures
90+ assertDoesNotCompile supportExterns testPurs expectedFailures
95 -- A glob for all purs and js files within a test directory
94 -- A glob for all purs and js files within a test directory
96 testGlob :: FilePath -> IO [FilePath]
95 testGlob :: FilePath -> IO [FilePath]
97− testGlob dir = join . fst <$> Glob.globDir (map Glob.compile ["**/*.purs", "**/*.js"]) dir
96+ testGlob = Glob.globDir1 (Glob.compile "**/*.purs")
99− -- Loads foreign modules from source files
100− loadForeigns :: [FilePath] -> IO (M.Map P.ModuleName FilePath)
101− loadForeigns paths = do
102− files <- forM paths (\f -> (f,) <$> readUTF8File f)
103− Right (foreigns, _) <- runExceptT $ runWriterT $ P.parseForeignModulesFromFiles files
106 -- Groups the test files so that a top-level file can have dependencies in a
98 -- Groups the test files so that a top-level file can have dependencies in a
107 -- subdirectory of the same name. The inner tuple contains a list of the
99 -- subdirectory of the same name. The inner tuple contains a list of the
108 -- .purs files and the .js files for the test case.
100 -- .purs files and the .js files for the test case.
109− getTestFiles :: FilePath -> [FilePath] -> [([FilePath], [FilePath])]
101+ getTestFiles :: FilePath -> [FilePath] -> [[FilePath]]
110 getTestFiles baseDir
102 getTestFiles baseDir
111− = map (partition ((== ".purs") . takeExtensions))
103+ = map (filter ((== ".purs") . takeExtensions))
112 . map (map (baseDir </>))
104 . map (map (baseDir </>))
113 . groupBy ((==) `on` extractPrefix)
105 . groupBy ((==) `on` extractPrefix)
114 . sortBy (compare `on` extractPrefix)
106 . sortBy (compare `on` extractPrefix)
@@ -137,6 +129,15 @@ spec = do
138 extractFailWiths = lines >>> mapMaybe (stripPrefix "-- @shouldFailWith ") >>> map trim
130 extractFailWiths = lines >>> mapMaybe (stripPrefix "-- @shouldFailWith ") >>> map trim
134+ => [(FilePath, P.Module)]
135+ -> m (M.Map P.ModuleName FilePath)
136+inferForeignModules = P.inferForeignModules . fromList
138+ fromList :: [(FilePath, P.Module)] -> M.Map P.ModuleName (Either P.RebuildPolicy FilePath)
139+ fromList = M.fromList . map ((P.getModuleName *** Right) . swap)
140trim :: String -> String
141trim :: String -> String
141trim = dropWhile isSpace >>> reverse >>> dropWhile isSpace >>> reverse
142trim = dropWhile isSpace >>> reverse >>> dropWhile isSpace >>> reverse
@@ -175,12 +176,12 @@ runTest = fmap fst . P.runMake P.defaultOptions
176 :: [(P.Module, P.ExternsFile)]
177 :: [(P.Module, P.ExternsFile)]
177 -> [FilePath]
178 -> [FilePath]
178− -> M.Map P.ModuleName FilePath
179 -> ([P.Module] -> IO ())
179 -> ([P.Module] -> IO ())
180 -> IO (Either P.MultipleErrors [P.ExternsFile])
180 -> IO (Either P.MultipleErrors [P.ExternsFile])
181−compile supportExterns inputFiles foreigns check = silence $ runTest $ do
181+compile supportExterns inputFiles check = silence $ runTest $ do
182 fs <- liftIO $ readInput inputFiles
182 fs <- liftIO $ readInput inputFiles
183 ms <- P.parseModulesFromFiles id fs
183 ms <- P.parseModulesFromFiles id fs
184+ foreigns <- inferForeignModules ms
184 liftIO (check (map snd ms))
185 liftIO (check (map snd ms))
185 let actions = makeActions foreigns
186 let actions = makeActions foreigns
186 case ms of
187 case ms of
@@ -190,22 +191,20 @@ compile supportExterns inputFiles foreigns check = silence $ runTest $ do
191 :: [(P.Module, P.ExternsFile)]
192 :: [(P.Module, P.ExternsFile)]
192 -> [FilePath]
193 -> [FilePath]
193− -> M.Map P.ModuleName FilePath
194 -> ([P.Module] -> IO ())
194 -> ([P.Module] -> IO ())
195 -> (Either P.MultipleErrors [P.ExternsFile] -> IO (Maybe String))
195 -> (Either P.MultipleErrors [P.ExternsFile] -> IO (Maybe String))
196 -> Expectation
196 -> Expectation
197−assert supportExterns inputFiles foreigns check f = do
197+assert supportExterns inputFiles check f = do
198− e <- compile supportExterns inputFiles foreigns check
198+ e <- compile supportExterns inputFiles check
199 maybeErr <- f e
199 maybeErr <- f e
200 maybe (return ()) expectationFailure maybeErr
200 maybe (return ()) expectationFailure maybeErr
202assertCompiles
202assertCompiles
203 :: [(P.Module, P.ExternsFile)]
203 :: [(P.Module, P.ExternsFile)]
204 -> [FilePath]
204 -> [FilePath]
205− -> M.Map P.ModuleName FilePath
206 -> Expectation
205 -> Expectation
207−assertCompiles supportExterns inputFiles foreigns =
206+assertCompiles supportExterns inputFiles = do
208− assert supportExterns inputFiles foreigns checkMain $ \e ->
207+ assert supportExterns inputFiles checkMain $ \e ->
209 case e of
208 case e of
210 Left errs -> return . Just . P.prettyPrintMultipleErrors False $ errs
209 Left errs -> return . Just . P.prettyPrintMultipleErrors False $ errs
211 Right _ -> do
210 Right _ -> do
@@ -228,11 +227,10 @@ assertCompiles supportExterns inputFiles foreigns =
228assertDoesNotCompile
227assertDoesNotCompile
229 :: [(P.Module, P.ExternsFile)]
228 :: [(P.Module, P.ExternsFile)]
230 -> [FilePath]
229 -> [FilePath]
231− -> M.Map P.ModuleName FilePath
232 -> [String]
230 -> [String]
233 -> Expectation
231 -> Expectation
234−assertDoesNotCompile supportExterns inputFiles foreigns shouldFailWith =
232+assertDoesNotCompile supportExterns inputFiles shouldFailWith = do
235− assert supportExterns inputFiles foreigns noPreCheck $ \e ->
233+ assert supportExterns inputFiles noPreCheck $ \e ->
236 case e of
234 case e of
237 Left errs ->
235 Left errs ->
238 return $ if null shouldFailWith
236 return $ if null shouldFailWith