diff --git a/cabal.project b/cabal.project index 282723f..a4eadbd 100644 --- a/cabal.project +++ b/cabal.project @@ -1,7 +1,7 @@ packages: sensei.cabal -package sensei +program-options ghc-options: -Werror tests: True diff --git a/src/Language/Haskell/GhciWrapper.hs b/src/Language/Haskell/GhciWrapper.hs index 8947df2..2836432 100644 --- a/src/Language/Haskell/GhciWrapper.hs +++ b/src/Language/Haskell/GhciWrapper.hs @@ -1,10 +1,19 @@ {-# LANGUAGE CPP #-} +{-# LANGUAGE BlockArguments #-} module Language.Haskell.GhciWrapper ( Config(..) , Interpreter(echo) , withInterpreter , eval , evalVerbose +, evalVerbose_ + +, ReloadingSucceeded(..) +, reload + +#ifdef TEST +, extractDiagnostics +#endif ) where import Imports @@ -20,7 +29,7 @@ import System.Exit (exitFailure) import Util (isWritableByOthers) import qualified ReadHandle -import ReadHandle (ReadHandle, toReadHandle) +import ReadHandle (ReadHandle, toReadHandle, Extract(..)) data Config = Config { configIgnoreDotGhci :: Bool @@ -123,13 +132,13 @@ new startupFile Config{..} envDefaults args_ = do hSetBuffering h LineBuffering hSetEncoding h utf8 - printStartupMessages :: Interpreter -> IO String + printStartupMessages :: Interpreter -> IO (String, [ReloadingSucceeded]) printStartupMessages interpreter = evalVerbose interpreter "" close :: Interpreter -> IO () close Interpreter{..} = do hClose hIn - ReadHandle.drain readHandle echo + ReadHandle.drain extractNothing readHandle echo hClose hOut e <- waitForProcess process when (e /= ExitSuccess) $ do @@ -141,14 +150,52 @@ putExpression Interpreter{hIn = stdin} e = do ByteString.hPut stdin ReadHandle.marker hFlush stdin -getResult :: Interpreter -> IO String -getResult Interpreter{..} = T.unpack . decodeUtf8 <$> ReadHandle.getResult readHandle echo +data ReloadingSucceeded = ReloadingFailed | ReloadingSucceeded + deriving (Eq, Show) + +extractDiagnostics :: Extract ReloadingSucceeded +extractDiagnostics = Extract { + isPartialMessage = \ chunk -> or [ + ByteString.isPrefixOf chunk ok + , ByteString.isPrefixOf ok chunk + , ByteString.isPrefixOf chunk failed + , ByteString.isPrefixOf failed chunk + ] + , parseMessage = \ case + line | ByteString.isPrefixOf ok line -> Just (ReloadingSucceeded, "") + line | ByteString.isPrefixOf failed line -> Just (ReloadingFailed, "") + _ -> Nothing + } + where + + ok = "Ok, modules loaded: " + failed = "Failed, modules loaded: " + +extractNothing :: Extract () +extractNothing = Extract { + isPartialMessage = const False +, parseMessage = undefined +} + +getResult :: Interpreter -> IO (String, [ReloadingSucceeded]) +getResult Interpreter{..} = first (T.unpack . decodeUtf8) <$> ReadHandle.getResult extractDiagnostics readHandle echo + +getResult_ :: Extract a -> Interpreter -> IO (String, [a]) +getResult_ extract Interpreter{..} = first (T.unpack . decodeUtf8) <$> ReadHandle.getResult extract readHandle echo silent :: ByteString -> IO () silent _ = pass eval :: Interpreter -> String -> IO String -eval ghci = evalVerbose ghci {echo = silent} +eval ghci = fmap fst . evalVerbose ghci {echo = silent} -evalVerbose :: Interpreter -> String -> IO String +evalVerbose :: Interpreter -> String -> IO (String, [ReloadingSucceeded]) evalVerbose ghci expr = putExpression ghci expr >> getResult ghci + +evalVerbose_ :: Extract a -> Interpreter -> String -> IO (String, [a]) +evalVerbose_ extract ghci expr = putExpression ghci expr >> getResult_ extract ghci + +reload :: Interpreter -> IO (String, ReloadingSucceeded) +reload ghci = evalVerbose_ extractDiagnostics ghci ":reload" <&> second \ case + [ReloadingSucceeded] -> ReloadingSucceeded + _ -> ReloadingFailed diff --git a/src/ReadHandle.hs b/src/ReadHandle.hs index 058a509..5b14bb0 100644 --- a/src/ReadHandle.hs +++ b/src/ReadHandle.hs @@ -3,9 +3,11 @@ module ReadHandle ( ReadHandle(..) , toReadHandle , marker +, Extract(..) , getResult , drain #ifdef TEST +, breakAfterNewLine , newEmptyBuffer #endif ) where @@ -34,9 +36,9 @@ data ReadHandle = ReadHandle { , buffer :: IORef Buffer } -drain :: ReadHandle -> (ByteString -> IO ()) -> IO () -drain h echo = while (not <$> isEOF h) $ do - _ <- getResult h echo +drain :: Extract a -> ReadHandle -> (ByteString -> IO ()) -> IO () +drain extract h echo = while (not <$> isEOF h) $ do + _ <- getResult extract h echo pass isEOF :: ReadHandle -> IO Bool @@ -73,15 +75,58 @@ toReadHandle h n = do newEmptyBuffer :: IO (IORef Buffer) newEmptyBuffer = newIORef BufferEmpty -getResult :: ReadHandle -> (ByteString -> IO ()) -> IO ByteString -getResult h echo = mconcat <$> go - where - go :: IO [ByteString] - go = nextChunk h >>= \ case - Chunk chunk -> echo chunk >> (chunk :) <$> go +data Extract a = Extract { + isPartialMessage :: ByteString -> Bool +, parseMessage :: ByteString -> Maybe (a, ByteString) +} + +getResult :: Extract a -> ReadHandle -> (ByteString -> IO ()) -> IO (ByteString, [a]) +getResult extract h echo = do + ref <- newIORef [] + + let + startOfLine :: ByteString -> IO [ByteString] + startOfLine chunk + | extract.isPartialMessage chunk = goJson chunk + | otherwise = notStartOfLine chunk + + notStartOfLine :: ByteString -> IO [ByteString] + notStartOfLine chunk = case breakAfterNewLine chunk of + Nothing -> echo chunk >> (chunk :) <$> withMoreInput_ notStartOfLine + Just (c, "") -> echo c >> (c :) <$> withMoreInput_ startOfLine + Just (c, xs) -> echo c >> (c :) <$> startOfLine xs + + goJson :: ByteString -> IO [ByteString] + goJson chunk = case breakAfterNewLine chunk of + Nothing -> withMoreInput chunk goJson + Just (pre, suf) -> do + d <- case extract.parseMessage pre of + Nothing -> do + return pre + Just (diagnostic, formatted) -> do + modifyIORef' ref (diagnostic :) + return formatted + echo d >> (d :) <$> startOfLine suf + + withMoreInput_ :: (ByteString -> IO [ByteString]) -> IO [ByteString] + withMoreInput_ action = nextChunk h >>= \ case + Chunk chunk -> action chunk Marker -> return [] EOF -> return [] + withMoreInput :: ByteString -> (ByteString -> IO [ByteString]) -> IO [ByteString] + withMoreInput acc action = nextChunk h >>= \ case + Chunk chunk -> action (acc <> chunk) + Marker -> echo acc >> return [acc] + EOF -> echo acc >> return [acc] + + (,) <$> (mconcat <$> withMoreInput_ startOfLine) <*> readIORef ref + +breakAfterNewLine :: ByteString -> Maybe (ByteString, ByteString) +breakAfterNewLine input = case ByteString.elemIndex '\n' input of + Just n -> Just (ByteString.splitAt (n + 1) input) + Nothing -> Nothing + data Chunk = Chunk ByteString | Marker | EOF nextChunk :: ReadHandle -> IO Chunk diff --git a/src/Session.hs b/src/Session.hs index ce07cb1..144c05c 100644 --- a/src/Session.hs +++ b/src/Session.hs @@ -4,6 +4,8 @@ module Session ( , Session(..) , echo , withSession + +, ReloadingSucceeded(..) , reload , Summary(..) @@ -26,7 +28,8 @@ import Imports import Data.IORef -import Language.Haskell.GhciWrapper +import Language.Haskell.GhciWrapper hiding (reload) +import qualified Language.Haskell.GhciWrapper as Interpreter import Util import Options @@ -57,8 +60,8 @@ withSession config args action = do where (ghciArgs, hspecArgs) = splitArgs args -reload :: MonadIO m => Session -> m String -reload session = liftIO $ evalVerbose session.interpreter ":reload" +reload :: MonadIO m => Session -> m (String, ReloadingSucceeded) +reload session = liftIO $ Interpreter.reload session.interpreter data Summary = Summary { summaryExamples :: Int @@ -103,7 +106,7 @@ runSpec :: String -> Session -> IO String runSpec command session = do failedPreviously <- isFailure <$> hspecPreviousSummary session let args = "--color" : (if failedPreviously then addRerun else id) session.hspecArgs - r <- evalVerbose session.interpreter $ "System.Environment.withArgs " ++ show args ++ " $ " ++ command + (r, _) <- evalVerbose session.interpreter $ "System.Environment.withArgs " ++ show args ++ " $ " ++ command writeIORef session.hspecPreviousSummaryRef (parseSummary r) return r where diff --git a/src/Trigger.hs b/src/Trigger.hs index 4053115..6d6afbc 100644 --- a/src/Trigger.hs +++ b/src/Trigger.hs @@ -25,7 +25,7 @@ import Control.Monad.Except import Util import Config (Hook, HookResult(..)) -import Session (Session, isFailure, isSuccess, hspecPreviousSummary, resetSummary) +import Session (Session, ReloadingSucceeded(..), isFailure, isSuccess, hspecPreviousSummary, resetSummary) import qualified Session data Hooks = Hooks { @@ -47,12 +47,6 @@ triggerAll session hooks = do resetSummary session trigger session hooks -reloadedSuccessfully :: String -> Bool -reloadedSuccessfully = any success . lines - where - success :: String -> Bool - success = isPrefixOf "Ok, modules loaded: " - removeProgress :: String -> String removeProgress xs = case break (== '\r') xs of (_, "") -> xs @@ -71,13 +65,13 @@ trigger session hooks = runWriterT (runExceptT go) >>= \ case go :: Trigger () go = do runHook hooks.beforeReload - output <- Session.reload session + (output, r) <- Session.reload session tell output - case reloadedSuccessfully output of - False -> do + case r of + ReloadingFailed -> do echo $ withColor Red "RELOADING FAILED" <> "\n" abort - True -> do + ReloadingSucceeded -> do echo $ withColor Green "RELOADING SUCCEEDED" <> "\n" runHook hooks.afterReload diff --git a/test/Helper.hs b/test/Helper.hs index c287bb4..4e6284c 100644 --- a/test/Helper.hs +++ b/test/Helper.hs @@ -96,7 +96,7 @@ failingSpec = unlines [ data Status = Ok | Failed deriving (Eq, Show) -modulesLoaded :: Status -> [String] -> String +modulesLoaded :: Status -> [String] -> String -- FIXME: remove modulesLoaded status xs = show status ++ ", modules loaded: " <> mods <> "." where mods = case xs of diff --git a/test/Language/Haskell/GhciWrapperSpec.hs b/test/Language/Haskell/GhciWrapperSpec.hs index 5947045..c4eb5ba 100644 --- a/test/Language/Haskell/GhciWrapperSpec.hs +++ b/test/Language/Haskell/GhciWrapperSpec.hs @@ -4,7 +4,7 @@ module Language.Haskell.GhciWrapperSpec (main, spec) where import Helper import qualified Data.ByteString.Char8 as ByteString -import Language.Haskell.GhciWrapper (Config(..), Interpreter(..)) +import Language.Haskell.GhciWrapper (Config(..), Interpreter(..), ReloadingSucceeded(..)) import qualified Language.Haskell.GhciWrapper as Interpreter main :: IO () @@ -55,7 +55,7 @@ spec = do it "echos result" $ do fmap mconcat . withSpy $ \ spy -> do withInterpreter [] $ \ ghci -> do - Interpreter.evalVerbose ghci {echo = spy} "23" `shouldReturn` "23\n" + Interpreter.evalVerbose ghci {echo = spy} "23" `shouldReturn` ("23\n", []) `shouldReturn` "23\n" describe "eval" $ do @@ -116,9 +116,37 @@ spec = do ghci "exitWith $ ExitFailure 10" `shouldReturn` "*** Exception: ExitFailure 10\n" it "gives an error message for identifiers that are not in scope" $ withGhci $ \ ghci -> do - ghci "foo" >>= (`shouldSatisfy` isInfixOf "Variable not in scope: foo") + ghci "foo" >>= (`shouldContain` "Variable not in scope: foo") context "with -XNoImplicitPrelude" $ do it "works" $ withInterpreter ["-XNoImplicitPrelude"] $ \ ghci -> do Interpreter.eval ghci "putStrLn \"foo\"" >>= (`shouldContain` "Variable not in scope: putStrLn") Interpreter.eval ghci "23" `shouldReturn` "23\n" + + describe "reload" $ do + it "reloads" $ do + withTempDirectory $ \ dir -> do + let + name :: FilePath + name = dir "Foo.hs" + + writeFile name $ unlines [ + "module Foo where" + ] + + withInterpreter [name] $ \ ghci -> do + Interpreter.reload ghci `shouldReturn` ("", ReloadingSucceeded) + + it "reloads" $ do + withTempDirectory $ \ dir -> do + let + name :: FilePath + name = dir "Foo.hs" + + writeFile name $ unlines [ + "module Foo where" + , "foo = bar" + ] + + withInterpreter [name] $ \ ghci -> do + snd <$> Interpreter.reload ghci `shouldReturn` ReloadingFailed diff --git a/test/ReadHandleSpec.hs b/test/ReadHandleSpec.hs index ccd5e56..881d7d6 100644 --- a/test/ReadHandleSpec.hs +++ b/test/ReadHandleSpec.hs @@ -1,11 +1,14 @@ module ReadHandleSpec (spec) where -import Helper +import Prelude hiding (span) +import Helper hiding (span) import Test.QuickCheck import qualified Data.ByteString as ByteString import ReadHandle +import Language.Haskell.GhciWrapper (extractDiagnostics) + chunkByteString :: (Int, Int) -> ByteString -> Gen [ByteString] chunkByteString size = go where @@ -24,22 +27,29 @@ withRandomChunkSizes :: [ByteString] -> (ReadHandle -> Expectation) -> Property withRandomChunkSizes (mconcat -> input) action = property $ do chunkSizes <- elements [SmallChunks, BigChunks] let + maxChunkSize :: Int maxChunkSize = case chunkSizes of SmallChunks -> 4 BigChunks -> ByteString.length input chunks <- chunkByteString (1, maxChunkSize) input - return $ fakeHandle chunks >>= action + return $ do + counterexample (unlines $ map show chunks) $ do + fakeHandle chunks >>= action partialMarker :: ByteString partialMarker = ByteString.take 5 marker spec :: Spec spec = do + describe "breakAfterNewLine" $ do + it "" $ do + breakAfterNewLine "foo\nbar\nbaz" `shouldBe` Just ("foo\n", "bar\nbaz") + describe "drain" $ do it "drains all remaining input" $ do h <- fakeHandle ["foo", marker, "bar", marker, "baz", marker, ""] - withSpy (drain h) `shouldReturn` ["foo", "bar", "baz"] + withSpy (drain extractDiagnostics h) `shouldReturn` ["foo", "bar", "baz"] describe "getResult" $ do context "with a single result" $ do @@ -48,62 +58,111 @@ spec = do it "returns result" $ do withSpy $ \ echo -> do h <- fakeHandle input - getResult h echo `shouldReturn` "foobarbaz" + getResult extractDiagnostics h echo `shouldReturn` ("foobarbaz", []) `shouldReturn` ["foo", "bar", "baz"] context "with chunks of arbitrary size" $ do it "returns result" $ do withRandomChunkSizes input $ \ h -> do fmap mconcat . withSpy $ \ echo -> do - getResult h echo `shouldReturn` "foobarbaz" + getResult extractDiagnostics h echo `shouldReturn` ("foobarbaz", []) `shouldReturn` "foobarbaz" +{- + context "" $ do + let + extract = extractDiagnostics { + parseMessage = \ xs -> flip (,) "" <$> Diagnostic.parse xs + } + + it "" $ do + let + start :: Location + start = Location 23 42 + + span :: Span + span = Span "Foo.hs" start start + + err :: Diagnostic + err = Diagnostic "" "" span Error Nothing [] [] + + bar :: ByteString + bar = toStrict $ Aeson.encode err + + foo :: [ByteString] + foo = [ + "foo\n" + , "bar\n" + , bar <> "\n" + , "baz\n" + , marker + ] + withRandomChunkSizes foo $ \ h -> do + fmap mconcat . withSpy $ \ echo -> do + getResult extract h echo `shouldReturn` ("foo\nbar\nbaz\n", [err]) + `shouldReturn` "foo\nbar\nbaz\n" + + it "" $ do + let + foo :: [ByteString] + foo = [ + "foo\n" + , "bar\n" + , "{..." + , marker + ] + withRandomChunkSizes foo $ \ h -> do + fmap mconcat . withSpy $ \ echo -> do + getResult extract h echo `shouldReturn` ("foo\nbar\n{...", []) + `shouldReturn` "foo\nbar\n{..." + -} + context "with multiple results" $ do let input = ["foo", marker, "bar", marker, "baz", marker] it "returns one result at a time" $ do withSpy $ \ echo -> do h <- fakeHandle input - getResult h echo `shouldReturn` "foo" - getResult h echo `shouldReturn` "bar" - getResult h echo `shouldReturn` "baz" + getResult extractDiagnostics h echo `shouldReturn` ("foo", []) + getResult extractDiagnostics h echo `shouldReturn` ("bar", []) + getResult extractDiagnostics h echo `shouldReturn` ("baz", []) `shouldReturn` ["foo", "bar", "baz"] context "with chunks of arbitrary size" $ do it "returns one result at a time" $ do withRandomChunkSizes input $ \ h -> do fmap mconcat . withSpy $ \ echo -> do - getResult h echo `shouldReturn` "foo" - getResult h echo `shouldReturn` "bar" - getResult h echo `shouldReturn` "baz" + getResult extractDiagnostics h echo `shouldReturn` ("foo", []) + getResult extractDiagnostics h echo `shouldReturn` ("bar", []) + getResult extractDiagnostics h echo `shouldReturn` ("baz", []) `shouldReturn` "foobarbaz" context "when a chunk that contains a marker ends with a partial marker" $ do it "correctly gives the marker precedence over the partial marker" $ do withSpy $ \ echo -> do h <- fakeHandle ["foo" <> marker <> "bar" <> partialMarker, ""] - getResult h echo `shouldReturn` "foo" - getResult h echo `shouldReturn` ("bar" <> partialMarker) + getResult extractDiagnostics h echo `shouldReturn` ("foo", []) + getResult extractDiagnostics h echo `shouldReturn` ("bar" <> partialMarker, []) `shouldReturn` ["foo", "bar", partialMarker] context "on EOF" $ do it "returns all remaining input" $ do withSpy $ \ echo -> do h <- fakeHandle ["foo", "bar", "baz", ""] - getResult h echo `shouldReturn` "foobarbaz" + getResult extractDiagnostics h echo `shouldReturn` ("foobarbaz", []) `shouldReturn` ["foo", "bar", "baz"] context "with a partialMarker at the end" $ do it "includes the partial marker in the output" $ do withSpy $ \ echo -> do h <- fakeHandle ["foo", "bar", "baz", partialMarker, ""] - getResult h echo `shouldReturn` ("foobarbaz" <> partialMarker) + getResult extractDiagnostics h echo `shouldReturn` ("foobarbaz" <> partialMarker, []) `shouldReturn` ["foo", "bar", "baz", partialMarker] context "after a marker" $ do it "returns all remaining input" $ do withSpy $ \ echo -> do h <- fakeHandle ["foo", "bar", "baz", marker, "qux", ""] - getResult h echo `shouldReturn` "foobarbaz" - getResult h echo `shouldReturn` "qux" + getResult extractDiagnostics h echo `shouldReturn` ("foobarbaz", []) + getResult extractDiagnostics h echo `shouldReturn` ("qux", []) `shouldReturn` ["foo", "bar", "baz", "qux"] diff --git a/test/SessionSpec.hs b/test/SessionSpec.hs index 60ca90f..e12e411 100644 --- a/test/SessionSpec.hs +++ b/test/SessionSpec.hs @@ -38,8 +38,8 @@ spec = do describe "reload" $ do it "reloads" $ do - withSession [] $ \session -> do - Session.reload session `shouldReturn` (modulesLoaded Ok [] ++ "\n") + withSession [] $ \ session -> do + Session.reload session `shouldReturn` ("", ReloadingSucceeded) describe "hasSpec" $ around withSomeSpec $ do context "when module contains spec" $ do diff --git a/test/TriggerSpec.hs b/test/TriggerSpec.hs index 1903410..6620cfb 100644 --- a/test/TriggerSpec.hs +++ b/test/TriggerSpec.hs @@ -36,7 +36,7 @@ withSession specPath args = do : "-fdiagnostics-color=never" : file : args - ++ ["--no-color", "--seed=0"] + ++ ["--expert", "--no-color", "--seed=0"] where (dir, file) = splitFileName specPath @@ -93,8 +93,7 @@ spec = do withSession name [] $ \ session -> do writeFile name failingSpec (trigger session >> triggerAll session) `shouldReturn` (Failure, [ - modulesLoaded Ok ["Spec"] - , withColor Green "RELOADING SUCCEEDED" + withColor Green "RELOADING SUCCEEDED" , "" , "foo [✔]" , "bar [✘]" @@ -115,8 +114,7 @@ spec = do it "reloads and runs specs" $ \ name -> do withSession name [] $ \ session -> do trigger session `shouldReturn` (Success, [ - modulesLoaded Ok ["Spec"] - , withColor Green "RELOADING SUCCEEDED" + withColor Green "RELOADING SUCCEEDED" , "" , "foo [✔]" , "bar [✔]" @@ -131,8 +129,7 @@ spec = do withHooks $ \ hooks -> do withSession name [] $ \ session -> do triggerWithHooks session hooks `shouldReturn` (Success, [ - modulesLoaded Ok ["Spec"] - , withColor Green "RELOADING SUCCEEDED" + withColor Green "RELOADING SUCCEEDED" , "" , "foo [✔]" , "bar [✔]" @@ -157,8 +154,7 @@ spec = do withHooks $ \ hooks -> do withSession name [] $ \ session -> do triggerWithHooks session hooks { afterReload = failingHook } `shouldReturn` (HookFailed, [ - modulesLoaded Ok ["Spec"] - , withColor Green "RELOADING SUCCEEDED" + withColor Green "RELOADING SUCCEEDED" , "hook failed" ]) `shouldReturn` [BeforeReloadSucceeded] @@ -180,7 +176,6 @@ spec = do #if __GLASGOW_HASKELL__ >= 910 , "" #endif - , modulesLoaded Failed [] , withColor Red "RELOADING FAILED" ]) @@ -189,15 +184,32 @@ spec = do withSession name [] $ \ session -> do writeFile name failingSpec (Failure, xs) <- trigger session - xs `shouldContain` [modulesLoaded Ok ["Spec"]] - xs `shouldContain` ["2 examples, 1 failure"] + xs `shouldBe` [ + "[1 of 1] Compiling Spec [Source file changed]" + , withColor Green "RELOADING SUCCEEDED" + , "" + , "foo [✔]" + , "bar [✘]" + , "" + , "Failures:" + , "" + , " Spec.hs:8:3: " + , " 1) bar" + , "" + , "Randomized with seed 0" + , "" + , "Finished in ..." + , "2 examples, 1 failure" + , "Summary {summaryExamples = 2, summaryFailures = 1}" + ] + -- xs `shouldContain` [modulesLoaded Ok ["Spec"]] + -- xs `shouldContain` ["2 examples, 1 failure"] it "only reruns failing specs" $ \ name -> do withSession name [] $ \ session -> do writeFile name failingSpec (trigger session >> trigger session) `shouldReturn` (Failure, [ - modulesLoaded Ok ["Spec"] - , withColor Green "RELOADING SUCCEEDED" + withColor Green "RELOADING SUCCEEDED" , "" , "bar [✘]" , "" @@ -221,7 +233,6 @@ spec = do writeFile name passingSpec trigger session `shouldReturn` (Success, [ "[1 of 1] Compiling Spec [Source file changed]" - , modulesLoaded Ok ["Spec"] , withColor Green "RELOADING SUCCEEDED" , "" , "bar [✔]" @@ -243,8 +254,7 @@ spec = do withSession name [] $ \ session -> do writeFile name "module Spec where" (trigger session >> trigger session) `shouldReturn` (Success, [ - modulesLoaded Ok ["Spec"] - , withColor Green "RELOADING SUCCEEDED" + withColor Green "RELOADING SUCCEEDED" ]) context "with an hspec-meta spec" $ do @@ -252,8 +262,7 @@ spec = do requiresHspecMeta $ withSession name ["-package hspec-meta"] $ \ session -> do writeFile name passingMetaSpec (trigger session >> trigger session) `shouldReturn` (Success, [ - modulesLoaded Ok ["Spec"] - , withColor Green "RELOADING SUCCEEDED" + withColor Green "RELOADING SUCCEEDED" , "" , "foo [✔]" , "bar [✔]"