@@ -9,7 +9,7 @@ import Language.PureScript qualified as P
99import Language.PureScript.CST qualified as CST
1010
1111import Control.Concurrent (threadDelay )
12- import Control.Monad (guard , void , forM_ )
12+ import Control.Monad (guard , void , forM_ , when )
1313import Control.Exception (tryJust )
1414import Control.Monad.IO.Class (liftIO )
1515import Control.Concurrent.MVar (readMVar , newMVar , modifyMVar_ )
@@ -19,11 +19,13 @@ import Data.Text qualified as T
1919import Data.Set (Set )
2020import Data.Set qualified as Set
2121import Data.Map qualified as M
22+ import Data.Version (showVersion )
2223
24+ import Paths_purescript qualified as Paths
2325import System.FilePath ((</>) )
2426import System.Directory (createDirectory , removeDirectoryRecursive , removeFile , setModificationTime )
2527import System.IO.Error (isDoesNotExistError )
26- import System.IO.UTF8 (readUTF8FilesT , writeUTF8FileT )
28+ import System.IO.UTF8 (readUTF8FilesT , readUTF8FileT , writeUTF8FileT )
2729
2830import Test.Hspec (Spec , before_ , it , shouldReturn )
2931
@@ -55,6 +57,9 @@ spec = do
5557
5658 forM_ (zip [0 .. ] modules) $ \ (idx, (mn, content, _)) -> do
5759 writeFile (modulePath mn) (timestamp idx) content
60+ -- Write a fake foreign module to bypass compiler's check.
61+ when (T. isInfixOf " \n foreign import" content) $
62+ writeFile (foreignJsPath mn) (timestamp idx) content
5863
5964 compile paths `shouldReturn` moduleNames names
6065
@@ -189,15 +194,15 @@ spec = do
189194 it " recompiles if docs are requested but not up to date" $ do
190195 let mPath = sourcesDir </> " Module.purs"
191196
192- moduleContent1 = " module Module where\n x :: Int\n x = 1"
193- moduleContent2 = moduleContent1 <> " \n y :: Int\n y = 1"
197+ mContent1 = " module Module where\n x :: Int\n x = 1"
198+ mContent2 = mContent1 <> " \n y :: Int\n y = 1"
194199
195200 optsWithDocs = P. defaultOptions { P. optionsCodegenTargets = Set. fromList [P. JS , P. Docs ] }
196201 go opts = compileWithOptions opts [mPath] >>= assertSuccess
197202
198- writeFile mPath timestampA moduleContent1
203+ writeFile mPath timestampA mContent1
199204 go optsWithDocs `shouldReturn` moduleNames [" Module" ]
200- writeFile mPath timestampB moduleContent2
205+ writeFile mPath timestampB mContent2
201206 -- See Note [Sleeping to avoid flaky tests]
202207 threadDelay oneSecond
203208 go P. defaultOptions `shouldReturn` moduleNames [" Module" ]
@@ -207,21 +212,42 @@ spec = do
207212
208213 it " recompiles if CoreFn is requested but not up to date" $ do
209214 let mPath = sourcesDir </> " Module.purs"
210- moduleContent1 = " module Module where\n x :: Int\n x = 1"
211- moduleContent2 = moduleContent1 <> " \n y :: Int\n y = 1"
215+ mContent1 = " module Module where\n x :: Int\n x = 1"
216+ mContent2 = mContent1 <> " \n y :: Int\n y = 1"
212217 optsCoreFnOnly = P. defaultOptions { P. optionsCodegenTargets = Set. singleton P. CoreFn }
213218 go opts = compileWithOptions opts [mPath] >>= assertSuccess
214219
215- writeFile mPath timestampA moduleContent1
220+ writeFile mPath timestampA mContent1
216221 go optsCoreFnOnly `shouldReturn` moduleNames [" Module" ]
217- writeFile mPath timestampB moduleContent2
222+ writeFile mPath timestampB mContent2
218223 -- See Note [Sleeping to avoid flaky tests]
219224 threadDelay oneSecond
220225 go P. defaultOptions `shouldReturn` moduleNames [" Module" ]
221226 -- Since the existing CoreFn.json is now outdated, the module should be
222227 -- recompiled.
223228 go optsCoreFnOnly `shouldReturn` moduleNames [" Module" ]
224229
230+ it " recompiles if cache-db version differs from the current" $ do
231+ let mPath = sourcesDir </> " Module.purs"
232+ mContent = " module Module where\n foo :: Int\n foo = 1\n "
233+
234+ writeFile mPath timestampA mContent
235+ compile [mPath] `shouldReturn` moduleNames [" Module" ]
236+
237+ -- Replace version with illegal in cache-db file.
238+ let cacheDbFilePath = P. cacheDbFile modulesDir
239+ versionText ver = " \" version\" :\" " <> ver <> " \" "
240+
241+ cacheContent <- readUTF8FileT cacheDbFilePath
242+
243+ let currentVer = T. pack (showVersion Paths. version)
244+ let newContent =
245+ T. replace (versionText currentVer) (versionText " 0.0.0" ) cacheContent
246+
247+ writeUTF8FileT cacheDbFilePath newContent
248+
249+ compile [mPath] `shouldReturn` moduleNames [" Module" ]
250+
225251 -- Cut off rebuild tests.
226252
227253 -- If a module is compiled with effective changes for downstream they should
@@ -433,13 +459,34 @@ spec = do
433459 )
434460 [" A" ]
435461
462+ -- Type synonym in foreign import.
463+ recompile2 it " type synonym changed in foreign import"
464+ ( " module A where\n type SynA = Int\n "
465+ , " module A where\n type SynA = String\n "
466+ , " module B where\n import A as A\n foreign import a :: A.SynA\n "
467+ )
468+
436469 -- Type synonym change.
437470 recompile2 it " type synonym changed"
438471 ( " module A where\n type SynA = Int\n "
439472 , " module A where\n type SynA = String\n "
440473 , " module B where\n import A as A\n type SynB = Array A.SynA\n "
441474 )
442475
476+ -- Type synonym change in value.
477+ recompile2 it " type synonym changed in value"
478+ ( " module A where\n type SynA = Int\n "
479+ , " module A where\n type SynA = String\n "
480+ , " module B where\n import A as A\n value = ([] :: Array A.SynA)\n "
481+ )
482+
483+ -- Type synonym change in pattern.
484+ recompile2 it " type synonym changed in pattern"
485+ ( " module A where\n type SynA = Int\n "
486+ , " module A where\n type SynA = String\n "
487+ , " module B where\n import A as A\n fn = \\ (_ :: Array A.SynA) -> 0\n "
488+ )
489+
443490 -- Type synonym indirect change.
444491 recompile2 it " type synonym dependency changed"
445492 ( " module A where\n type SynA = Int\n type SynA2 = SynA\n "
@@ -516,7 +563,6 @@ spec = do
516563 , " module B where\n import A\n t = 1 :+: \" 1\" "
517564 )
518565
519-
520566 -- Type operator change.
521567 recompile2 it " type op changed"
522568 ( " module A where\n data T a b = T a b\n infixl 2 type T as :+:\n "
0 commit comments