@@ -11,12 +11,18 @@ import Control.Concurrent (forkIO, threadDelay)
11
11
import Control.Concurrent.MVar
12
12
import Control.Concurrent.STM
13
13
14
+ import qualified Data.ByteString.Lazy as ByteString
15
+ import qualified Data.Text as Text
16
+ import qualified Data.Text.Encoding as Text
17
+ import Data.Function ((&) )
14
18
import Data.IORef
15
19
16
20
import System.IO
17
21
import System.FilePath
18
22
import System.Directory
23
+ import System.Environment (getEnvironment , unsetEnv )
19
24
import System.Exit
25
+ import System.Process.Typed
20
26
#if defined(mingw32_HOST_OS) || defined(__MINGW32__)
21
27
#else
22
28
import System.Posix.Signals
@@ -26,6 +32,7 @@ import Test.HUnit ((@?=), (@?), assertFailure)
26
32
import qualified Test.HUnit as HUnit
27
33
28
34
import Language.Haskell.Interpreter
35
+ import Language.Haskell.Interpreter.Unsafe
29
36
30
37
test_reload_modified :: TestCase
31
38
test_reload_modified = TestCase " reload_modified" [mod_file] $ do
@@ -291,6 +298,63 @@ test_normalize_type = TestCase "normalize_type" [mod_file] $ do
291
298
," type instance Foo x = ()" ]
292
299
mod_file = " TEST_NormalizeType.hs"
293
300
301
+ test_package_db :: IOTestCase
302
+ test_package_db = IOTestCase " package_db" [dir] $ \ wrapInterp -> do
303
+ setup
304
+ ghcVersionOutput <- readProcessStdout_ $ proc " ghc" [" --version" ]
305
+ let ghcVersion
306
+ :: String
307
+ ghcVersion
308
+ = ghcVersionOutput
309
+ -- "The Glorious Glasgow Haskell Compilation System, version 8.8.4" :: ByteString.Lazy
310
+ & ByteString. toStrict
311
+ -- "The Glorious Glasgow Haskell Compilation System, version 8.8.4" :: ByteString
312
+ & Text. decodeUtf8
313
+ -- "The Glorious Glasgow Haskell Compilation System, version 8.8.4" :: Text
314
+ & Text. unpack
315
+ -- "The Glorious Glasgow Haskell Compilation System, version 8.8.4" :: String
316
+ & words
317
+ -- ["The","Glorious","Glasgow","Haskell","Compilation","System,","version","8.8.4"]
318
+ & last
319
+ -- "8.8.4"
320
+ let pkgdb = dir </> " dist-newstyle" </> " packagedb" </> (" ghc-" ++ ghcVersion)
321
+ ghc_args = [" -package-db=" ++ pkgdb]
322
+
323
+ -- stack sets GHC_ENVIRONMENT to a file which pins down the versions of
324
+ -- all the packages we can load, and since it does not list my-package,
325
+ -- we cannot load it.
326
+ unsetEnv " GHC_ENVIRONMENT"
327
+
328
+ wrapInterp (unsafeRunInterpreterWithArgs ghc_args) $ do
329
+ -- succeeds (setImports [mod]) @@? "module from package-db must be visible"
330
+ setImports [mod ]
331
+ --
332
+ where pkg = " my-package"
333
+ dir = pkg
334
+ mod_file = dir </> mod <.> " hs"
335
+ mod = " MyModule"
336
+ cabal_file = dir </> pkg <.> " cabal"
337
+ setup = do createDirectory dir
338
+ writeFile cabal_file $ unlines
339
+ [ " cabal-version: 2.4"
340
+ , " name: " ++ pkg
341
+ , " version: 0.1.0.0"
342
+ , " "
343
+ , " library"
344
+ , " exposed-modules: " ++ mod
345
+ ]
346
+ writeFile mod_file $ unlines
347
+ [ " {-# LANGUAGE NoImplicitPrelude #-}"
348
+ , " module " ++ mod ++ " where"
349
+ ]
350
+ env <- getEnvironment
351
+ runProcess_
352
+ $ setWorkingDir dir
353
+ $ -- stack sets GHC_PACKAGE_PATH, but cabal complains
354
+ -- that it cannot run if that variable is set.
355
+ setEnv (filter ((/= " GHC_PACKAGE_PATH" ) . fst ) env)
356
+ $ proc " cabal" [" build" ]
357
+
294
358
-- earlier versions of hint were accidentally overwriting the signal handlers
295
359
-- for ^C and others.
296
360
--
@@ -299,9 +363,9 @@ test_normalize_type = TestCase "normalize_type" [mod_file] $ do
299
363
-- succeeds when executed from ghci and ghcid, regardless of whether the problematic
300
364
-- behaviour has been fixed or not.
301
365
test_signal_handlers :: IOTestCase
302
- test_signal_handlers = IOTestCase " signal_handlers" [] $ \ runInterp -> do
366
+ test_signal_handlers = IOTestCase " signal_handlers" [] $ \ wrapInterp -> do
303
367
#if defined(mingw32_HOST_OS) || defined(__MINGW32__)
304
- runInterp $ do
368
+ wrapInterp runInterpreter $ do
305
369
pure ()
306
370
#else
307
371
signalDetectedRef <- newIORef False
@@ -311,7 +375,7 @@ test_signal_handlers = IOTestCase "signal_handlers" [] $ \runInterp -> do
311
375
acquire = installHandler sigINT (Catch detectSignal) Nothing
312
376
release handler = installHandler sigINT handler Nothing
313
377
r <- bracket acquire release $ \ _ -> do
314
- runInterp $ do
378
+ wrapInterp runInterpreter $ do
315
379
liftIO $ do
316
380
r <- try $ do
317
381
raiseSignal sigINT
@@ -357,6 +421,7 @@ tests = [test_reload_modified
357
421
358
422
ioTests :: [IOTestCase ]
359
423
ioTests = [test_signal_handlers
424
+ ,test_package_db
360
425
]
361
426
362
427
main :: IO ()
@@ -406,29 +471,40 @@ noInterpreterError :: Either InterpreterError a -> IO a
406
471
noInterpreterError (Left e) = assertFailure (show e)
407
472
noInterpreterError (Right a) = pure a
408
473
409
- data IOTestCase = IOTestCase String [FilePath ] ((Interpreter () -> IO (Either InterpreterError () )) -> IO (Either InterpreterError () ))
474
+ data IOTestCase = IOTestCase
475
+ String -- test name
476
+ [FilePath ] -- temporary files and folders to delete after the test
477
+ ( ( (Interpreter () -> IO (Either InterpreterError () ))
478
+ -> (Interpreter () -> IO (Either InterpreterError () ))
479
+ ) -- please wrap your 'runInterpreter' calls with this
480
+ -> IO (Either InterpreterError () ) -- create temporary files and run the test
481
+ )
410
482
411
483
runIOTests :: Bool -> [IOTestCase ] -> IO HUnit. Counts
412
484
runIOTests sandboxed = HUnit. runTestTT . HUnit. TestList . map build
413
- where build (IOTestCase title tmps test) = HUnit. TestLabel title $
414
- HUnit. TestCase test_case
485
+ where build (IOTestCase title tmps test)
486
+ = HUnit. TestLabel title $ HUnit. TestCase test_case
415
487
where test_case = go `finally` clean_up
416
488
clean_up = mapM_ removeIfExists tmps
417
- go = do r <- test ( \ body -> runInterpreter
418
- (when sandboxed setSandbox >> body))
489
+ wrapInterp runInterp body = runInterp (when sandboxed setSandbox >> body)
490
+ go = do r <- test wrapInterp
419
491
noInterpreterError r
420
492
removeIfExists f = do existsF <- doesFileExist f
421
493
if existsF
422
494
then removeFile f
423
495
else
424
496
do existsD <- doesDirectoryExist f
425
497
when existsD $
426
- removeDirectory f
498
+ removeDirectoryRecursive f
427
499
428
- data TestCase = TestCase String [FilePath ] (Interpreter () )
500
+ data TestCase = TestCase
501
+ String -- test name
502
+ [FilePath ] -- temporary files and folders to delete after the test
503
+ (Interpreter () ) -- create temporary files and run the test
429
504
430
505
runTests :: Bool -> [TestCase ] -> IO HUnit. Counts
431
506
runTests sandboxed = runIOTests sandboxed . map toIOTestCase
432
507
where
433
508
toIOTestCase :: TestCase -> IOTestCase
434
- toIOTestCase (TestCase title tmps test) = IOTestCase title tmps ($ test)
509
+ toIOTestCase (TestCase title tmps test) = IOTestCase title tmps $ \ wrapInterp -> do
510
+ wrapInterp runInterpreter test
0 commit comments