From 445d092a497add1f2f58be119255067be91932af Mon Sep 17 00:00:00 2001 From: Max Ulidtko Date: Sun, 27 Apr 2025 19:36:08 +0200 Subject: [PATCH 01/13] tests: chmod +x on test scripts --- tests/integration/run-single-test.sh | 0 tests/integration/run-sort-tests.sh | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 tests/integration/run-single-test.sh mode change 100644 => 100755 tests/integration/run-sort-tests.sh diff --git a/tests/integration/run-single-test.sh b/tests/integration/run-single-test.sh old mode 100644 new mode 100755 diff --git a/tests/integration/run-sort-tests.sh b/tests/integration/run-sort-tests.sh old mode 100644 new mode 100755 From f68fc0f6434f477907034c37efbe1601c04166f1 Mon Sep 17 00:00:00 2001 From: Max Ulidtko Date: Sun, 27 Apr 2025 20:28:06 +0200 Subject: [PATCH 02/13] tests: fix missed -ignore-dot-ghci --- tests/integration/tests/3926-ghci-with-sublibraries/Main.hs | 2 +- tests/integration/tests/4270-files-order/Main.hs | 2 +- tests/integration/tests/module-added-multiple-times/Main.hs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/integration/tests/3926-ghci-with-sublibraries/Main.hs b/tests/integration/tests/3926-ghci-with-sublibraries/Main.hs index df43dd9891..ff3eb3c148 100644 --- a/tests/integration/tests/3926-ghci-with-sublibraries/Main.hs +++ b/tests/integration/tests/3926-ghci-with-sublibraries/Main.hs @@ -18,7 +18,7 @@ main replThread replThread :: IO () -replThread = repl [] $ do +replThread = repl ["--ghci-options=-ignore-dot-ghci"] $ do -- The command must be issued before searching the output for the next prompt, -- otherwise, on Windows from msys2-20230526, `stack repl` encounters a EOF -- and terminates gracefully. diff --git a/tests/integration/tests/4270-files-order/Main.hs b/tests/integration/tests/4270-files-order/Main.hs index 4219d3ae7c..ee8479b2f0 100644 --- a/tests/integration/tests/4270-files-order/Main.hs +++ b/tests/integration/tests/4270-files-order/Main.hs @@ -4,7 +4,7 @@ import StackTest main :: IO () main = do stack ["build"] - repl [] $ do + repl ["--ghci-options=-ignore-dot-ghci"] $ do -- The command must be issued before searching the output for the next -- prompt, otherwise, on Windows from msys2-20230526, `stack repl` -- encounters a EOF and terminates gracefully. diff --git a/tests/integration/tests/module-added-multiple-times/Main.hs b/tests/integration/tests/module-added-multiple-times/Main.hs index d2745cffa3..f9134e62d1 100644 --- a/tests/integration/tests/module-added-multiple-times/Main.hs +++ b/tests/integration/tests/module-added-multiple-times/Main.hs @@ -3,7 +3,7 @@ import Data.List import StackTest main :: IO () -main = repl [] $ do +main = repl ["--ghci-options=-ignore-dot-ghci"] $ do -- The command must be issued before searching the output for the next prompt, -- otherwise, on Windows from msys2-20230526, `stack repl` encounters a EOF -- and terminates gracefully. From 8e99af9dc937e647718f680e30ac07af3683b953 Mon Sep 17 00:00:00 2001 From: Max Ulidtko Date: Sun, 27 Apr 2025 20:43:43 +0200 Subject: [PATCH 03/13] tests(3926): fix test [on linux] --- tests/integration/lib/StackTest.hs | 22 +++++++++++-------- .../tests/3926-ghci-with-sublibraries/Main.hs | 18 +++++---------- 2 files changed, 18 insertions(+), 22 deletions(-) diff --git a/tests/integration/lib/StackTest.hs b/tests/integration/lib/StackTest.hs index b279bd0f08..ac571fd9e5 100644 --- a/tests/integration/lib/StackTest.hs +++ b/tests/integration/lib/StackTest.hs @@ -51,7 +51,9 @@ module StackTest import Control.Monad ( forever, unless, void, when ) import Control.Monad.IO.Class ( liftIO ) -import Control.Monad.Trans.Reader ( ReaderT, ask, runReaderT ) +import Control.Monad.Trans.Reader ( ReaderT, ask, asks, runReaderT ) +import qualified Control.Monad.Trans.State as State +import Control.Monad.Trans ( lift ) import Control.Concurrent ( forkIO ) import Control.Exception ( Exception (..), IOException, bracket_, catch, throw @@ -157,14 +159,16 @@ data ReplConnection = ReplConnection } nextPrompt :: Repl () -nextPrompt = do - (ReplConnection _ replStdoutHandle) <- ask - c <- liftIO $ hGetChar replStdoutHandle - if c == '>' - then do - -- Skip next character - void $ liftIO $ hGetChar replStdoutHandle - else nextPrompt +nextPrompt = State.evalStateT poll "" where + poll = do + c <- lift (asks replStdout) >>= liftIO . hGetChar + State.modify (++ [c]) -- FIXME crap perf + when (c == '\n') $ do + State.get >>= liftIO . putStr . ("ghci> " <>) + State.put "" + buf <- State.get + unless (buf == "ghci> ") + poll replCommand :: String -> Repl () replCommand cmd = do diff --git a/tests/integration/tests/3926-ghci-with-sublibraries/Main.hs b/tests/integration/tests/3926-ghci-with-sublibraries/Main.hs index ff3eb3c148..b887697f87 100644 --- a/tests/integration/tests/3926-ghci-with-sublibraries/Main.hs +++ b/tests/integration/tests/3926-ghci-with-sublibraries/Main.hs @@ -1,4 +1,3 @@ -import Control.Concurrent import Control.Monad.IO.Class import Control.Monad import Data.List @@ -14,7 +13,6 @@ main copy "src/Lib.v1" "src/Lib.hs" copy "src-internal/Internal.v1" "src-internal/Internal.hs" stack ["build"] -- need a build before ghci at the moment, see #4148 - forkIO fileEditingThread replThread replThread :: IO () @@ -23,7 +21,9 @@ replThread = repl ["--ghci-options=-ignore-dot-ghci"] $ do -- otherwise, on Windows from msys2-20230526, `stack repl` encounters a EOF -- and terminates gracefully. replCommand ":main" + liftIO $ putStrLn "Awaiting prompt..." nextPrompt + liftIO $ putStrLn "Initial prompt received" line <- replGetLine let expected = "hello world" when (line /= expected) $ @@ -31,25 +31,17 @@ replThread = repl ["--ghci-options=-ignore-dot-ghci"] $ do "Main module didn't load correctly.\n" <> "Expected: " <> expected <> "\n" <> "Actual : " <> line <> "\n" - liftIO $ threadDelay 1000000 -- wait for an edit of the internal library + liftIO $ copy "src-internal/Internal.v2" "src-internal/Internal.hs" reloadAndTest "testInt" "42" "Internal library didn't reload." - liftIO $ threadDelay 1000000 -- wait for an edit of the internal library + liftIO $ copy "src/Lib.v2" "src/Lib.hs" reloadAndTest "testStr" "\"OK\"" "Main library didn't reload." -fileEditingThread :: IO () -fileEditingThread = do - threadDelay 1000000 - -- edit the internal library and pure to ghci - copy "src-internal/Internal.v2" "src-internal/Internal.hs" - threadDelay 1000000 - -- edit the internal library and end thread, returning to ghci - copy "src/Lib.v2" "src/Lib.hs" - reloadAndTest :: String -> String -> String -> Repl () reloadAndTest cmd exp err = do reload replCommand cmd line <- replGetLine + liftIO . putStrLn $ line unless (exp `isSuffixOf` line) $ error err reload :: Repl () From 007da91a0441bfea16435acaabeee08fd84265e7 Mon Sep 17 00:00:00 2001 From: Max Ulidtko Date: Fri, 16 May 2025 15:18:10 +0200 Subject: [PATCH 04/13] refactor: split off StackTest.Repl --- stack.cabal | 1 + tests/integration/lib/StackTest.hs | 96 +--------------- tests/integration/lib/StackTest/Repl.hs | 104 ++++++++++++++++++ .../tests/3926-ghci-with-sublibraries/Main.hs | 1 + .../tests/4270-files-order/Main.hs | 1 + .../tests/module-added-multiple-times/Main.hs | 3 +- 6 files changed, 113 insertions(+), 93 deletions(-) create mode 100644 tests/integration/lib/StackTest/Repl.hs diff --git a/stack.cabal b/stack.cabal index d333e1291b..b7aab690b1 100644 --- a/stack.cabal +++ b/stack.cabal @@ -629,6 +629,7 @@ executable stack-integration-test main-is: IntegrationSpec.hs other-modules: StackTest + StackTest.Repl Paths_stack autogen-modules: Paths_stack diff --git a/tests/integration/lib/StackTest.hs b/tests/integration/lib/StackTest.hs index ac571fd9e5..e19838ed4c 100644 --- a/tests/integration/lib/StackTest.hs +++ b/tests/integration/lib/StackTest.hs @@ -13,14 +13,6 @@ module StackTest , stackCleanFull , stackIgnoreException , stackErr - , Repl - , ReplConnection (..) - , nextPrompt - , replCommand - , replGetChar - , replGetLine - , runRepl - , repl , stackStderr , stackCheckStderr , stackErrStderr @@ -49,17 +41,11 @@ module StackTest , superslow ) where -import Control.Monad ( forever, unless, void, when ) -import Control.Monad.IO.Class ( liftIO ) -import Control.Monad.Trans.Reader ( ReaderT, ask, asks, runReaderT ) -import qualified Control.Monad.Trans.State as State -import Control.Monad.Trans ( lift ) -import Control.Concurrent ( forkIO ) +import Control.Monad ( unless, void, when ) import Control.Exception - ( Exception (..), IOException, bracket_, catch, throw + ( Exception (..), IOException, bracket_, catch , throwIO ) -import Data.Maybe ( fromMaybe ) import GHC.Stack ( HasCallStack ) import System.Environment ( getEnv, lookupEnv ) import System.Directory @@ -68,14 +54,12 @@ import System.Directory , setCurrentDirectory ) import System.IO - ( BufferMode (..), Handle, IOMode (..), hGetChar, hGetLine - , hPutChar, hPutStr, hPutStrLn, hSetBuffering, stderr - , withFile + ( hPutStr, hPutStrLn, stderr ) import System.IO.Error - ( isDoesNotExistError, isEOFError ) + ( isDoesNotExistError ) import System.Process - ( CreateProcess (..), StdStream (..), createProcess, proc + ( CreateProcess (..), createProcess, proc , readCreateProcessWithExitCode, readProcessWithExitCode , shell, waitForProcess ) @@ -151,76 +135,6 @@ stackErr args = do ec <- stack' args when (ec == ExitSuccess) $ error "stack was supposed to fail, but didn't" -type Repl = ReaderT ReplConnection IO - -data ReplConnection = ReplConnection - { replStdin :: Handle - , replStdout :: Handle - } - -nextPrompt :: Repl () -nextPrompt = State.evalStateT poll "" where - poll = do - c <- lift (asks replStdout) >>= liftIO . hGetChar - State.modify (++ [c]) -- FIXME crap perf - when (c == '\n') $ do - State.get >>= liftIO . putStr . ("ghci> " <>) - State.put "" - buf <- State.get - unless (buf == "ghci> ") - poll - -replCommand :: String -> Repl () -replCommand cmd = do - (ReplConnection replStdinHandle _) <- ask - liftIO $ hPutStrLn replStdinHandle cmd - -replGetLine :: Repl String -replGetLine = ask >>= liftIO . hGetLine . replStdout - -replGetChar :: Repl Char -replGetChar = ask >>= liftIO . hGetChar . replStdout - -runRepl :: - HasCallStack - => FilePath - -> [String] - -> ReaderT ReplConnection IO () - -> IO ExitCode -runRepl cmd args actions = do - logInfo $ "Running: " ++ cmd ++ " " ++ unwords (map showProcessArgDebug args) - (Just rStdin, Just rStdout, Just rStderr, ph) <- - createProcess (proc cmd args) - { std_in = CreatePipe - , std_out = CreatePipe - , std_err = CreatePipe - } - hSetBuffering rStdin NoBuffering - hSetBuffering rStdout NoBuffering - hSetBuffering rStderr NoBuffering - -- Log stack repl's standard error output - tempDir <- if isWindows - then fromMaybe "" <$> lookupEnv "TEMP" - else pure "/tmp" - let tempLogFile = tempDir ++ "/stderr" - _ <- forkIO $ withFile tempLogFile WriteMode $ \logFileHandle -> do - hSetBuffering logFileHandle NoBuffering - forever $ - catch - (hGetChar rStderr >>= hPutChar logFileHandle) - (\e -> unless (isEOFError e) $ throw e) - runReaderT actions (ReplConnection rStdin rStdout) - waitForProcess ph - -repl :: HasCallStack => [String] -> Repl () -> IO () -repl args action = do - stackExe' <- stackExe - ec <- runRepl stackExe' ("repl":args) action - unless (ec == ExitSuccess) $ pure () - -- TODO: Understand why the exit code is 1 despite running GHCi tests - -- successfully. - -- else error $ "Exited with exit code: " ++ show ec - stackStderr :: HasCallStack => [String] -> IO (ExitCode, String) stackStderr args = do stackExe' <- stackExe diff --git a/tests/integration/lib/StackTest/Repl.hs b/tests/integration/lib/StackTest/Repl.hs new file mode 100644 index 0000000000..e0b5d7ca8b --- /dev/null +++ b/tests/integration/lib/StackTest/Repl.hs @@ -0,0 +1,104 @@ +{- | +Integration-test helpers & fixtures for testing `stack repl` +-} +module StackTest.Repl + ( Repl + , ReplConnection (..) + , nextPrompt + , repl + , replCommand + , replGetLine + ) where + +import Control.Concurrent (forkIO) +import Control.Exception (throw, catch) +import Control.Monad (forever, unless, when) +import Control.Monad.IO.Class (liftIO) +import Data.Maybe (fromMaybe) +import GHC.Stack (HasCallStack) +import System.Environment (lookupEnv) +import System.Exit (ExitCode (..)) +import System.IO + ( BufferMode (NoBuffering), Handle, IOMode (WriteMode) + , hGetChar, hGetLine, hPutChar, hPutStrLn, hSetBuffering + , withFile + ) +import System.IO.Error (isEOFError) + +import Control.Monad.Trans (lift) +import Control.Monad.Trans.Reader +import Control.Monad.Trans.State qualified as State +import System.Process + ( CreateProcess (std_err, std_in, std_out) + , StdStream (CreatePipe) + , createProcess, proc, waitForProcess + ) + +import StackTest + +type Repl = ReaderT ReplConnection IO + +data ReplConnection = ReplConnection + { replStdin :: Handle + , replStdout :: Handle + } + +nextPrompt :: Repl () +nextPrompt = State.evalStateT poll "" where + poll = do + c <- lift (asks replStdout) >>= liftIO . hGetChar + State.modify (++ [c]) -- FIXME crap perf + when (c == '\n') $ do + State.get >>= liftIO . putStr . ("ghci> " <>) + State.put "" + buf <- State.get + unless (buf == "ghci> ") + poll + +replCommand :: String -> Repl () +replCommand cmd = do + (ReplConnection replStdinHandle _) <- ask + liftIO $ hPutStrLn replStdinHandle cmd + +replGetLine :: Repl String +replGetLine = ask >>= liftIO . hGetLine . replStdout + +runRepl + :: HasCallStack + => FilePath + -> [String] + -> ReaderT ReplConnection IO () + -> IO ExitCode +runRepl cmd args actions = do + logInfo $ "Running: " ++ cmd ++ " " ++ unwords (map showProcessArgDebug args) + (Just rStdin, Just rStdout, Just rStderr, ph) <- + createProcess (proc cmd args) + { std_in = CreatePipe + , std_out = CreatePipe + , std_err = CreatePipe + } + hSetBuffering rStdin NoBuffering + hSetBuffering rStdout NoBuffering + hSetBuffering rStderr NoBuffering + -- Log stack repl's standard error output + tempDir <- if isWindows + then fromMaybe "" <$> lookupEnv "TEMP" + else pure "/tmp" + let tempLogFile = tempDir ++ "/stderr" + _ <- forkIO $ withFile tempLogFile WriteMode $ \logFileHandle -> do + --hSetBuffering logFileHandle NoBuffering + forever $ + catch + (hGetChar rStderr >>= hPutChar logFileHandle) + (\e -> unless (isEOFError e) $ throw e) + runReaderT actions (ReplConnection rStdin rStdout) + waitForProcess ph + +repl :: HasCallStack => [String] -> Repl () -> IO () +repl args action = do + stackExe' <- stackExe + ec <- runRepl stackExe' ("repl":args) action + unless (ec == ExitSuccess) $ pure () + -- TODO: Understand why the exit code is 1 despite running GHCi tests + -- successfully. + -- else error $ "Exited with exit code: " ++ show ec diff --git a/tests/integration/tests/3926-ghci-with-sublibraries/Main.hs b/tests/integration/tests/3926-ghci-with-sublibraries/Main.hs index b887697f87..882c8f3bdb 100644 --- a/tests/integration/tests/3926-ghci-with-sublibraries/Main.hs +++ b/tests/integration/tests/3926-ghci-with-sublibraries/Main.hs @@ -2,6 +2,7 @@ import Control.Monad.IO.Class import Control.Monad import Data.List import StackTest +import StackTest.Repl main :: IO () main diff --git a/tests/integration/tests/4270-files-order/Main.hs b/tests/integration/tests/4270-files-order/Main.hs index ee8479b2f0..02d224faba 100644 --- a/tests/integration/tests/4270-files-order/Main.hs +++ b/tests/integration/tests/4270-files-order/Main.hs @@ -1,5 +1,6 @@ import Control.Monad import StackTest +import StackTest.Repl main :: IO () main = do diff --git a/tests/integration/tests/module-added-multiple-times/Main.hs b/tests/integration/tests/module-added-multiple-times/Main.hs index f9134e62d1..eb762ee8bb 100644 --- a/tests/integration/tests/module-added-multiple-times/Main.hs +++ b/tests/integration/tests/module-added-multiple-times/Main.hs @@ -1,6 +1,5 @@ import Control.Monad -import Data.List -import StackTest +import StackTest.Repl main :: IO () main = repl ["--ghci-options=-ignore-dot-ghci"] $ do From a123a289113b324737030f3b5b24a39ab224ff8c Mon Sep 17 00:00:00 2001 From: Max Ulidtko Date: Fri, 16 May 2025 15:32:13 +0200 Subject: [PATCH 05/13] refactor: move -ignore-dot-ghci to repl fixture --- tests/integration/lib/StackTest/Repl.hs | 2 +- tests/integration/tests/3926-ghci-with-sublibraries/Main.hs | 2 +- tests/integration/tests/4270-files-order/Main.hs | 2 +- tests/integration/tests/module-added-multiple-times/Main.hs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/integration/lib/StackTest/Repl.hs b/tests/integration/lib/StackTest/Repl.hs index e0b5d7ca8b..25c666904b 100644 --- a/tests/integration/lib/StackTest/Repl.hs +++ b/tests/integration/lib/StackTest/Repl.hs @@ -97,7 +97,7 @@ runRepl cmd args actions = do repl :: HasCallStack => [String] -> Repl () -> IO () repl args action = do stackExe' <- stackExe - ec <- runRepl stackExe' ("repl":args) action + ec <- runRepl stackExe' ("repl" : "--ghci-options=-ignore-dot-ghci" : args) action unless (ec == ExitSuccess) $ pure () -- TODO: Understand why the exit code is 1 despite running GHCi tests -- successfully. diff --git a/tests/integration/tests/3926-ghci-with-sublibraries/Main.hs b/tests/integration/tests/3926-ghci-with-sublibraries/Main.hs index 882c8f3bdb..c9f64ac4c7 100644 --- a/tests/integration/tests/3926-ghci-with-sublibraries/Main.hs +++ b/tests/integration/tests/3926-ghci-with-sublibraries/Main.hs @@ -17,7 +17,7 @@ main replThread replThread :: IO () -replThread = repl ["--ghci-options=-ignore-dot-ghci"] $ do +replThread = repl [] $ do -- The command must be issued before searching the output for the next prompt, -- otherwise, on Windows from msys2-20230526, `stack repl` encounters a EOF -- and terminates gracefully. diff --git a/tests/integration/tests/4270-files-order/Main.hs b/tests/integration/tests/4270-files-order/Main.hs index 02d224faba..34e9669b86 100644 --- a/tests/integration/tests/4270-files-order/Main.hs +++ b/tests/integration/tests/4270-files-order/Main.hs @@ -5,7 +5,7 @@ import StackTest.Repl main :: IO () main = do stack ["build"] - repl ["--ghci-options=-ignore-dot-ghci"] $ do + repl [] $ do -- The command must be issued before searching the output for the next -- prompt, otherwise, on Windows from msys2-20230526, `stack repl` -- encounters a EOF and terminates gracefully. diff --git a/tests/integration/tests/module-added-multiple-times/Main.hs b/tests/integration/tests/module-added-multiple-times/Main.hs index eb762ee8bb..41397416cc 100644 --- a/tests/integration/tests/module-added-multiple-times/Main.hs +++ b/tests/integration/tests/module-added-multiple-times/Main.hs @@ -2,7 +2,7 @@ import Control.Monad import StackTest.Repl main :: IO () -main = repl ["--ghci-options=-ignore-dot-ghci"] $ do +main = repl [] $ do -- The command must be issued before searching the output for the next prompt, -- otherwise, on Windows from msys2-20230526, `stack repl` encounters a EOF -- and terminates gracefully. From 609205c0d9f255706c06d3680e93931e04d308fe Mon Sep 17 00:00:00 2001 From: Max Ulidtko Date: Fri, 16 May 2025 19:28:57 +0200 Subject: [PATCH 06/13] fix: resolve a TODO about unexpected exit code 1 runRepl was missing the `hClose rStdin` call -- causing the ghci subprocess to terminate abnormally with EPIPE on its stdin read. --- tests/integration/lib/StackTest/Repl.hs | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/tests/integration/lib/StackTest/Repl.hs b/tests/integration/lib/StackTest/Repl.hs index 25c666904b..b9ea6073e7 100644 --- a/tests/integration/lib/StackTest/Repl.hs +++ b/tests/integration/lib/StackTest/Repl.hs @@ -19,8 +19,8 @@ import GHC.Stack (HasCallStack) import System.Environment (lookupEnv) import System.Exit (ExitCode (..)) import System.IO - ( BufferMode (NoBuffering), Handle, IOMode (WriteMode) - , hGetChar, hGetLine, hPutChar, hPutStrLn, hSetBuffering + ( BufferMode (NoBuffering, LineBuffering), Handle, IOMode (WriteMode) + , hClose, hGetChar, hGetLine, hPutChar, hPutStrLn, hSetBuffering , withFile ) import System.IO.Error (isEOFError) @@ -67,7 +67,7 @@ runRepl :: HasCallStack => FilePath -> [String] - -> ReaderT ReplConnection IO () + -> Repl () -> IO ExitCode runRepl cmd args actions = do logInfo $ "Running: " ++ cmd ++ " " ++ unwords (map showProcessArgDebug args) @@ -77,7 +77,7 @@ runRepl cmd args actions = do , std_out = CreatePipe , std_err = CreatePipe } - hSetBuffering rStdin NoBuffering + hSetBuffering rStdin LineBuffering hSetBuffering rStdout NoBuffering hSetBuffering rStderr NoBuffering -- Log stack repl's standard error output @@ -91,14 +91,18 @@ runRepl cmd args actions = do catch (hGetChar rStderr >>= hPutChar logFileHandle) (\e -> unless (isEOFError e) $ throw e) + + -- run the test script which is to talk to the GHCi subprocess. runReaderT actions (ReplConnection rStdin rStdout) + + -- once done with the test, signal EOF on stdin for clean termination of ghci + hClose rStdin + -- read out the exit-code waitForProcess ph repl :: HasCallStack => [String] -> Repl () -> IO () repl args action = do stackExe' <- stackExe ec <- runRepl stackExe' ("repl" : "--ghci-options=-ignore-dot-ghci" : args) action - unless (ec == ExitSuccess) $ pure () - -- TODO: Understand why the exit code is 1 despite running GHCi tests - -- successfully. - -- else error $ "Exited with exit code: " ++ show ec + unless (ec == ExitSuccess) $ + error $ "GHCi exited with " <> show ec From 368a0e7c4ceaedbb1fb216c11af6e591b9cddcfb Mon Sep 17 00:00:00 2001 From: Max Ulidtko Date: Fri, 16 May 2025 20:22:28 +0200 Subject: [PATCH 07/13] tests: redirect stderr, instead of shuffling bytes one-by-one --- tests/integration/lib/StackTest/Repl.hs | 62 ++++++++++++------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/tests/integration/lib/StackTest/Repl.hs b/tests/integration/lib/StackTest/Repl.hs index b9ea6073e7..344d3ea89b 100644 --- a/tests/integration/lib/StackTest/Repl.hs +++ b/tests/integration/lib/StackTest/Repl.hs @@ -10,27 +10,24 @@ module StackTest.Repl , replGetLine ) where -import Control.Concurrent (forkIO) -import Control.Exception (throw, catch) -import Control.Monad (forever, unless, when) +import Control.Monad (unless, when) import Control.Monad.IO.Class (liftIO) import Data.Maybe (fromMaybe) import GHC.Stack (HasCallStack) import System.Environment (lookupEnv) import System.Exit (ExitCode (..)) import System.IO - ( BufferMode (NoBuffering, LineBuffering), Handle, IOMode (WriteMode) - , hClose, hGetChar, hGetLine, hPutChar, hPutStrLn, hSetBuffering - , withFile + ( BufferMode (NoBuffering, LineBuffering), Handle + , hClose, hGetChar, hGetLine, hPutStrLn, hSetBuffering + , openTempFile ) -import System.IO.Error (isEOFError) import Control.Monad.Trans (lift) import Control.Monad.Trans.Reader import Control.Monad.Trans.State qualified as State import System.Process ( CreateProcess (std_err, std_in, std_out) - , StdStream (CreatePipe) + , StdStream (CreatePipe, UseHandle) , createProcess, proc, waitForProcess ) @@ -43,6 +40,16 @@ data ReplConnection = ReplConnection , replStdout :: Handle } +replCommand :: String -> Repl () +replCommand cmd = do + (ReplConnection replStdinHandle _) <- ask + -- echo what we send to the test's stdout + liftIO . putStrLn $ "____> " <> cmd + liftIO $ hPutStrLn replStdinHandle cmd + +replGetLine :: Repl String +replGetLine = ask >>= liftIO . hGetLine . replStdout + nextPrompt :: Repl () nextPrompt = State.evalStateT poll "" where poll = do @@ -55,14 +62,6 @@ nextPrompt = State.evalStateT poll "" where unless (buf == "ghci> ") poll -replCommand :: String -> Repl () -replCommand cmd = do - (ReplConnection replStdinHandle _) <- ask - liftIO $ hPutStrLn replStdinHandle cmd - -replGetLine :: Repl String -replGetLine = ask >>= liftIO . hGetLine . replStdout - runRepl :: HasCallStack => FilePath @@ -70,27 +69,21 @@ runRepl -> Repl () -> IO ExitCode runRepl cmd args actions = do - logInfo $ "Running: " ++ cmd ++ " " ++ unwords (map showProcessArgDebug args) - (Just rStdin, Just rStdout, Just rStderr, ph) <- + (stderrBufPath, stderrBufHandle) <- openTempStderrBufferFile + hSetBuffering stderrBufHandle NoBuffering + + logInfo $ "Running: " ++ cmd ++ " " ++ unwords (map showProcessArgDebug args) ++ "\n\ + \ with stderr in " ++ stderrBufPath + + -- launch the GHCi subprocess, grab its FD handles and process handle + (Just rStdin, Just rStdout, Nothing, ph) <- createProcess (proc cmd args) { std_in = CreatePipe , std_out = CreatePipe - , std_err = CreatePipe + , std_err = UseHandle stderrBufHandle } hSetBuffering rStdin LineBuffering hSetBuffering rStdout NoBuffering - hSetBuffering rStderr NoBuffering - -- Log stack repl's standard error output - tempDir <- if isWindows - then fromMaybe "" <$> lookupEnv "TEMP" - else pure "/tmp" - let tempLogFile = tempDir ++ "/stderr" - _ <- forkIO $ withFile tempLogFile WriteMode $ \logFileHandle -> do - --hSetBuffering logFileHandle NoBuffering - forever $ - catch - (hGetChar rStderr >>= hPutChar logFileHandle) - (\e -> unless (isEOFError e) $ throw e) -- run the test script which is to talk to the GHCi subprocess. runReaderT actions (ReplConnection rStdin rStdout) @@ -100,6 +93,13 @@ runRepl cmd args actions = do -- read out the exit-code waitForProcess ph +-- | Roll a bicycle, rather than just `import Path.IO (getTempDir, openTempFile)`, +-- because it's a hassle to use anything beyond base & boot libs here. +openTempStderrBufferFile :: IO (FilePath, Handle) +openTempStderrBufferFile = getTempDir >>= (`openTempFile` "err.log") where + getTempDir | isWindows = fromMaybe "" <$> lookupEnv "TEMP" + | otherwise = pure "/tmp" + repl :: HasCallStack => [String] -> Repl () -> IO () repl args action = do stackExe' <- stackExe From 38d03c229304a67f4ba9edef85368bfcebc0fd73 Mon Sep 17 00:00:00 2001 From: Max Ulidtko Date: Fri, 16 May 2025 20:52:15 +0200 Subject: [PATCH 08/13] feat: show repl stderr on exceptions in test --- tests/integration/lib/StackTest/Repl.hs | 29 ++++++++-- .../tests/3926-ghci-with-sublibraries/Main.hs | 55 ++++++++----------- 2 files changed, 48 insertions(+), 36 deletions(-) diff --git a/tests/integration/lib/StackTest/Repl.hs b/tests/integration/lib/StackTest/Repl.hs index 344d3ea89b..cf58f88b84 100644 --- a/tests/integration/lib/StackTest/Repl.hs +++ b/tests/integration/lib/StackTest/Repl.hs @@ -10,16 +10,19 @@ module StackTest.Repl , replGetLine ) where +import Control.Exception (SomeException, catch, displayException, finally) import Control.Monad (unless, when) import Control.Monad.IO.Class (liftIO) import Data.Maybe (fromMaybe) import GHC.Stack (HasCallStack) +import System.Directory (removeFile) import System.Environment (lookupEnv) -import System.Exit (ExitCode (..)) +import System.Exit (ExitCode (..), exitFailure) import System.IO - ( BufferMode (NoBuffering, LineBuffering), Handle - , hClose, hGetChar, hGetLine, hPutStrLn, hSetBuffering + ( BufferMode (NoBuffering, LineBuffering), Handle, IOMode (ReadMode) + , hClose, hGetChar, hGetContents', hGetLine, hPutStrLn, hSetBuffering , openTempFile + , withFile ) import Control.Monad.Trans (lift) @@ -87,6 +90,18 @@ runRepl cmd args actions = do -- run the test script which is to talk to the GHCi subprocess. runReaderT actions (ReplConnection rStdin rStdout) + -- the nested actions script may fail in arbitrary ways; handle that here, + -- attaching the subprocess stderr as relevant context + `catch` \(e :: SomeException) -> do + putStrLn "==============================" + putStrLn "EXCEPTION in test: " + putStrLn . quote $ displayException e + putStrLn "------[ stderr of repl ]------" + withFile stderrBufPath ReadMode $ \h -> hGetContents' h >>= putStr . quote + putStrLn "==============================" + `finally` do + hClose stderrBufHandle + removeFile stderrBufPath -- once done with the test, signal EOF on stdin for clean termination of ghci hClose rStdin @@ -104,5 +119,9 @@ repl :: HasCallStack => [String] -> Repl () -> IO () repl args action = do stackExe' <- stackExe ec <- runRepl stackExe' ("repl" : "--ghci-options=-ignore-dot-ghci" : args) action - unless (ec == ExitSuccess) $ - error $ "GHCi exited with " <> show ec + unless (ec == ExitSuccess) $ do + putStrLn $ "repl exited with " <> show ec + exitFailure + +quote :: String -> String +quote = unlines . map ("> " <>) . lines diff --git a/tests/integration/tests/3926-ghci-with-sublibraries/Main.hs b/tests/integration/tests/3926-ghci-with-sublibraries/Main.hs index c9f64ac4c7..a7768f6c5c 100644 --- a/tests/integration/tests/3926-ghci-with-sublibraries/Main.hs +++ b/tests/integration/tests/3926-ghci-with-sublibraries/Main.hs @@ -5,37 +5,30 @@ import StackTest import StackTest.Repl main :: IO () -main - | isWindows = - putStrLn "This test was disabled on Windows on 25 June 2023 (see \ - \https://github.com/commercialhaskell/stack/issues/6170)." - | otherwise = do - stack ["clean"] -- to make sure we can load the code even after a clean - copy "src/Lib.v1" "src/Lib.hs" - copy "src-internal/Internal.v1" "src-internal/Internal.hs" - stack ["build"] -- need a build before ghci at the moment, see #4148 - replThread - -replThread :: IO () -replThread = repl [] $ do - -- The command must be issued before searching the output for the next prompt, - -- otherwise, on Windows from msys2-20230526, `stack repl` encounters a EOF - -- and terminates gracefully. - replCommand ":main" - liftIO $ putStrLn "Awaiting prompt..." - nextPrompt - liftIO $ putStrLn "Initial prompt received" - line <- replGetLine - let expected = "hello world" - when (line /= expected) $ - error $ - "Main module didn't load correctly.\n" - <> "Expected: " <> expected <> "\n" - <> "Actual : " <> line <> "\n" - liftIO $ copy "src-internal/Internal.v2" "src-internal/Internal.hs" - reloadAndTest "testInt" "42" "Internal library didn't reload." - liftIO $ copy "src/Lib.v2" "src/Lib.hs" - reloadAndTest "testStr" "\"OK\"" "Main library didn't reload." +main = do + stack ["clean"] -- to make sure we can load the code even after a clean + copy "src/Lib.v1" "src/Lib.hs" + copy "src-internal/Internal.v1" "src-internal/Internal.hs" + stack ["build"] -- need a build before ghci at the moment, see #4148 + repl [] $ do + -- The command must be issued before searching the output for the next prompt, + -- otherwise, on Windows from msys2-20230526, `stack repl` encounters a EOF + -- and terminates gracefully. + replCommand ":main" + liftIO $ putStrLn "Awaiting prompt..." + nextPrompt + liftIO $ putStrLn "Initial prompt received" + line <- replGetLine + let expected = "hello world" + when (line /= expected) $ + error $ + "Main module didn't load correctly.\n" + <> "Expected: " <> expected <> "\n" + <> "Actual : " <> line <> "\n" + liftIO $ copy "src-internal/Internal.v2" "src-internal/Internal.hs" + reloadAndTest "testInt" "42" "Internal library didn't reload." + liftIO $ copy "src/Lib.v2" "src/Lib.hs" + reloadAndTest "testStr" "\"OK\"" "Main library didn't reload." reloadAndTest :: String -> String -> String -> Repl () reloadAndTest cmd exp err = do From 5b2927c351c788cf75f8eeffb5a7ec0b5ffba840 Mon Sep 17 00:00:00 2001 From: Max Ulidtko Date: Fri, 16 May 2025 20:59:27 +0200 Subject: [PATCH 09/13] =?UTF-8?q?refactor:=20rename=20StackTest.Repl.{repl?= =?UTF-8?q?=20=E2=86=92=20stackRepl}?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/integration/lib/StackTest/Repl.hs | 7 ++++--- tests/integration/tests/3315-multi-ghc-options/Main.hs | 4 ++-- .../integration/tests/3926-ghci-with-sublibraries/Main.hs | 2 +- tests/integration/tests/4270-files-order/Main.hs | 2 +- .../integration/tests/module-added-multiple-times/Main.hs | 2 +- 5 files changed, 9 insertions(+), 8 deletions(-) diff --git a/tests/integration/lib/StackTest/Repl.hs b/tests/integration/lib/StackTest/Repl.hs index cf58f88b84..e75dd6afbb 100644 --- a/tests/integration/lib/StackTest/Repl.hs +++ b/tests/integration/lib/StackTest/Repl.hs @@ -5,9 +5,9 @@ module StackTest.Repl ( Repl , ReplConnection (..) , nextPrompt - , repl , replCommand , replGetLine + , stackRepl ) where import Control.Exception (SomeException, catch, displayException, finally) @@ -115,8 +115,9 @@ openTempStderrBufferFile = getTempDir >>= (`openTempFile` "err.log") where getTempDir | isWindows = fromMaybe "" <$> lookupEnv "TEMP" | otherwise = pure "/tmp" -repl :: HasCallStack => [String] -> Repl () -> IO () -repl args action = do +-- | Testing helper to exercise `stack repl`. +stackRepl :: HasCallStack => [String] -> Repl () -> IO () +stackRepl args action = do stackExe' <- stackExe ec <- runRepl stackExe' ("repl" : "--ghci-options=-ignore-dot-ghci" : args) action unless (ec == ExitSuccess) $ do diff --git a/tests/integration/tests/3315-multi-ghc-options/Main.hs b/tests/integration/tests/3315-multi-ghc-options/Main.hs index 1a0ea36fce..60d8c9eec4 100644 --- a/tests/integration/tests/3315-multi-ghc-options/Main.hs +++ b/tests/integration/tests/3315-multi-ghc-options/Main.hs @@ -1,6 +1,6 @@ -import StackTest +import StackTest.Repl main :: IO () main = do stack ["build", "--ghc-options=-ddump-simpl -ddump-asm -DBAR -DBAZ"] - repl ["--ghc-options=-ddump-simpl -ddump-asm"] (pure ()) + stackRepl ["--ghc-options=-ddump-simpl -ddump-asm"] (pure ()) diff --git a/tests/integration/tests/3926-ghci-with-sublibraries/Main.hs b/tests/integration/tests/3926-ghci-with-sublibraries/Main.hs index a7768f6c5c..1969d6ebaf 100644 --- a/tests/integration/tests/3926-ghci-with-sublibraries/Main.hs +++ b/tests/integration/tests/3926-ghci-with-sublibraries/Main.hs @@ -10,7 +10,7 @@ main = do copy "src/Lib.v1" "src/Lib.hs" copy "src-internal/Internal.v1" "src-internal/Internal.hs" stack ["build"] -- need a build before ghci at the moment, see #4148 - repl [] $ do + stackRepl [] $ do -- The command must be issued before searching the output for the next prompt, -- otherwise, on Windows from msys2-20230526, `stack repl` encounters a EOF -- and terminates gracefully. diff --git a/tests/integration/tests/4270-files-order/Main.hs b/tests/integration/tests/4270-files-order/Main.hs index 34e9669b86..adcaa8ed01 100644 --- a/tests/integration/tests/4270-files-order/Main.hs +++ b/tests/integration/tests/4270-files-order/Main.hs @@ -5,7 +5,7 @@ import StackTest.Repl main :: IO () main = do stack ["build"] - repl [] $ do + stackRepl [] $ do -- The command must be issued before searching the output for the next -- prompt, otherwise, on Windows from msys2-20230526, `stack repl` -- encounters a EOF and terminates gracefully. diff --git a/tests/integration/tests/module-added-multiple-times/Main.hs b/tests/integration/tests/module-added-multiple-times/Main.hs index 41397416cc..2163b70ff3 100644 --- a/tests/integration/tests/module-added-multiple-times/Main.hs +++ b/tests/integration/tests/module-added-multiple-times/Main.hs @@ -2,7 +2,7 @@ import Control.Monad import StackTest.Repl main :: IO () -main = repl [] $ do +main = stackRepl [] $ do -- The command must be issued before searching the output for the next prompt, -- otherwise, on Windows from msys2-20230526, `stack repl` encounters a EOF -- and terminates gracefully. From 27e3587adf170196fe9ca3ddf282b71564ee8911 Mon Sep 17 00:00:00 2001 From: Max Ulidtko Date: Fri, 16 May 2025 21:07:37 +0200 Subject: [PATCH 10/13] fix: avoid quadratic String traversals, resolving a fixme --- tests/integration/lib/StackTest/Repl.hs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/tests/integration/lib/StackTest/Repl.hs b/tests/integration/lib/StackTest/Repl.hs index e75dd6afbb..9df83204a8 100644 --- a/tests/integration/lib/StackTest/Repl.hs +++ b/tests/integration/lib/StackTest/Repl.hs @@ -13,7 +13,12 @@ module StackTest.Repl import Control.Exception (SomeException, catch, displayException, finally) import Control.Monad (unless, when) import Control.Monad.IO.Class (liftIO) +import Control.Monad.Trans (lift) +import Control.Monad.Trans.Reader +import Control.Monad.Trans.State qualified as State import Data.Maybe (fromMaybe) +import Data.Foldable (toList) +import Data.Sequence as Seq (Seq(Empty), (|>), fromList) import GHC.Stack (HasCallStack) import System.Directory (removeFile) import System.Environment (lookupEnv) @@ -24,10 +29,6 @@ import System.IO , openTempFile , withFile ) - -import Control.Monad.Trans (lift) -import Control.Monad.Trans.Reader -import Control.Monad.Trans.State qualified as State import System.Process ( CreateProcess (std_err, std_in, std_out) , StdStream (CreatePipe, UseHandle) @@ -54,15 +55,15 @@ replGetLine :: Repl String replGetLine = ask >>= liftIO . hGetLine . replStdout nextPrompt :: Repl () -nextPrompt = State.evalStateT poll "" where +nextPrompt = State.evalStateT poll Seq.Empty where poll = do c <- lift (asks replStdout) >>= liftIO . hGetChar - State.modify (++ [c]) -- FIXME crap perf + State.modify (|> c) when (c == '\n') $ do - State.get >>= liftIO . putStr . ("ghci> " <>) - State.put "" + State.get >>= liftIO . putStr . ("ghci> " ++) . toList + State.put Seq.Empty buf <- State.get - unless (buf == "ghci> ") + unless (buf == Seq.fromList "ghci> ") poll runRepl From 547f2746188865185990a4418bd41bd827eb4db9 Mon Sep 17 00:00:00 2001 From: Max Ulidtko Date: Sat, 17 May 2025 15:27:48 +0200 Subject: [PATCH 11/13] refactor(tests): reexport StackTest from StackTest.Repl --- tests/integration/lib/StackTest/Repl.hs | 2 ++ tests/integration/tests/3926-ghci-with-sublibraries/Main.hs | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/integration/lib/StackTest/Repl.hs b/tests/integration/lib/StackTest/Repl.hs index 9df83204a8..ef951da962 100644 --- a/tests/integration/lib/StackTest/Repl.hs +++ b/tests/integration/lib/StackTest/Repl.hs @@ -8,6 +8,8 @@ module StackTest.Repl , replCommand , replGetLine , stackRepl + -- * Reexport + , module StackTest ) where import Control.Exception (SomeException, catch, displayException, finally) diff --git a/tests/integration/tests/3926-ghci-with-sublibraries/Main.hs b/tests/integration/tests/3926-ghci-with-sublibraries/Main.hs index 1969d6ebaf..a0c94cb23d 100644 --- a/tests/integration/tests/3926-ghci-with-sublibraries/Main.hs +++ b/tests/integration/tests/3926-ghci-with-sublibraries/Main.hs @@ -1,7 +1,7 @@ import Control.Monad.IO.Class import Control.Monad import Data.List -import StackTest + import StackTest.Repl main :: IO () From a0a5fd93f020d53f96ff8173cd83679c2ab90d41 Mon Sep 17 00:00:00 2001 From: Max Ulidtko Date: Sat, 17 May 2025 16:37:57 +0200 Subject: [PATCH 12/13] cleanup: undo tests workarounds for msys2-20230526 Resolves #6170 --- tests/integration/tests/3926-ghci-with-sublibraries/Main.hs | 5 +---- tests/integration/tests/4270-files-order/Main.hs | 5 +---- tests/integration/tests/module-added-multiple-times/Main.hs | 5 +---- 3 files changed, 3 insertions(+), 12 deletions(-) diff --git a/tests/integration/tests/3926-ghci-with-sublibraries/Main.hs b/tests/integration/tests/3926-ghci-with-sublibraries/Main.hs index a0c94cb23d..ba045b541a 100644 --- a/tests/integration/tests/3926-ghci-with-sublibraries/Main.hs +++ b/tests/integration/tests/3926-ghci-with-sublibraries/Main.hs @@ -11,13 +11,10 @@ main = do copy "src-internal/Internal.v1" "src-internal/Internal.hs" stack ["build"] -- need a build before ghci at the moment, see #4148 stackRepl [] $ do - -- The command must be issued before searching the output for the next prompt, - -- otherwise, on Windows from msys2-20230526, `stack repl` encounters a EOF - -- and terminates gracefully. - replCommand ":main" liftIO $ putStrLn "Awaiting prompt..." nextPrompt liftIO $ putStrLn "Initial prompt received" + replCommand ":main" line <- replGetLine let expected = "hello world" when (line /= expected) $ diff --git a/tests/integration/tests/4270-files-order/Main.hs b/tests/integration/tests/4270-files-order/Main.hs index adcaa8ed01..c4b1a56588 100644 --- a/tests/integration/tests/4270-files-order/Main.hs +++ b/tests/integration/tests/4270-files-order/Main.hs @@ -6,11 +6,8 @@ main :: IO () main = do stack ["build"] stackRepl [] $ do - -- The command must be issued before searching the output for the next - -- prompt, otherwise, on Windows from msys2-20230526, `stack repl` - -- encounters a EOF and terminates gracefully. - replCommand "putStrLn greeting" nextPrompt + replCommand "putStrLn greeting" line <- replGetLine let expected = "Hello, world!" when (line /= expected) $ diff --git a/tests/integration/tests/module-added-multiple-times/Main.hs b/tests/integration/tests/module-added-multiple-times/Main.hs index 2163b70ff3..73cfee36f5 100644 --- a/tests/integration/tests/module-added-multiple-times/Main.hs +++ b/tests/integration/tests/module-added-multiple-times/Main.hs @@ -3,11 +3,8 @@ import StackTest.Repl main :: IO () main = stackRepl [] $ do - -- The command must be issued before searching the output for the next prompt, - -- otherwise, on Windows from msys2-20230526, `stack repl` encounters a EOF - -- and terminates gracefully. - replCommand ":main" nextPrompt + replCommand ":main" line <- replGetLine let expected = "Hello World!" when (line /= expected) $ From 3a939d5cfe31fdb222e4a83d4ac67c8d23d4a38f Mon Sep 17 00:00:00 2001 From: Max Ulidtko Date: Mon, 19 May 2025 09:03:52 +0200 Subject: [PATCH 13/13] cleanup: code review --- tests/integration/lib/StackTest/Repl.hs | 8 ++++++-- .../integration/tests/3926-ghci-with-sublibraries/Main.hs | 2 -- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/integration/lib/StackTest/Repl.hs b/tests/integration/lib/StackTest/Repl.hs index ef951da962..f08bdfceb5 100644 --- a/tests/integration/lib/StackTest/Repl.hs +++ b/tests/integration/lib/StackTest/Repl.hs @@ -6,6 +6,7 @@ module StackTest.Repl , ReplConnection (..) , nextPrompt , replCommand + , replGetChar , replGetLine , stackRepl -- * Reexport @@ -13,7 +14,7 @@ module StackTest.Repl ) where import Control.Exception (SomeException, catch, displayException, finally) -import Control.Monad (unless, when) +import Control.Monad ((>=>), unless, when) import Control.Monad.IO.Class (liftIO) import Control.Monad.Trans (lift) import Control.Monad.Trans.Reader @@ -53,6 +54,9 @@ replCommand cmd = do liftIO . putStrLn $ "____> " <> cmd liftIO $ hPutStrLn replStdinHandle cmd +replGetChar :: Repl Char +replGetChar = asks replStdout >>= liftIO . hGetChar + replGetLine :: Repl String replGetLine = ask >>= liftIO . hGetLine . replStdout @@ -100,7 +104,7 @@ runRepl cmd args actions = do putStrLn "EXCEPTION in test: " putStrLn . quote $ displayException e putStrLn "------[ stderr of repl ]------" - withFile stderrBufPath ReadMode $ \h -> hGetContents' h >>= putStr . quote + withFile stderrBufPath ReadMode $ hGetContents' >=> putStr . quote putStrLn "==============================" `finally` do hClose stderrBufHandle diff --git a/tests/integration/tests/3926-ghci-with-sublibraries/Main.hs b/tests/integration/tests/3926-ghci-with-sublibraries/Main.hs index ba045b541a..2685fe87e4 100644 --- a/tests/integration/tests/3926-ghci-with-sublibraries/Main.hs +++ b/tests/integration/tests/3926-ghci-with-sublibraries/Main.hs @@ -11,9 +11,7 @@ main = do copy "src-internal/Internal.v1" "src-internal/Internal.hs" stack ["build"] -- need a build before ghci at the moment, see #4148 stackRepl [] $ do - liftIO $ putStrLn "Awaiting prompt..." nextPrompt - liftIO $ putStrLn "Initial prompt received" replCommand ":main" line <- replGetLine let expected = "hello world"