sensei 0.4.0 → 0.5.0
raw patch · 18 files changed
+374/−151 lines, 18 filesdep −base-compatdep ~base
Dependencies removed: base-compat
Dependency ranges changed: base
Files
- doctest/ghci-wrapper/src/Language/Haskell/GhciWrapper.hs +17/−5
- sensei.cabal +15/−13
- src/Client.hs +2/−7
- src/EventQueue.hs +111/−32
- src/HTTP.hs +5/−9
- src/Imports.hs +14/−0
- src/Options.hs +3/−1
- src/Run.hs +44/−27
- src/Session.hs +2/−5
- src/Trigger.hs +9/−5
- src/Util.hs +49/−8
- test/EventQueueSpec.hs +71/−0
- test/HTTPSpec.hs +2/−1
- test/Helper.hs +7/−28
- test/OptionsSpec.hs +1/−1
- test/SessionSpec.hs +4/−4
- test/TriggerSpec.hs +6/−4
- test/UtilSpec.hs +12/−1
doctest/ghci-wrapper/src/Language/Haskell/GhciWrapper.hs view
@@ -6,6 +6,7 @@ , new , close , eval+, evalIt , evalEcho ) where @@ -38,6 +39,9 @@ marker :: String marker = show "dcbd2a1e20ae519a1c7714df2859f1890581d57fac96ba3f499412b2f5c928a1" +itMarker :: String+itMarker = "d42472243a0e6fc481e7514cbc9eb08812ed48daa29ca815844d86010b1d113a"+ data Interpreter = Interpreter { hIn :: Handle , hOut :: Handle@@ -94,10 +98,12 @@ when (e /= ExitSuccess) $ do throwIO (userError $ "Language.Haskell.GhciWrapper.close: Interpreter exited with an error (" ++ show e ++ ")") -putExpression :: Interpreter -> String -> IO ()-putExpression Interpreter{hIn = stdin} e = do+putExpression :: Interpreter -> Bool -> String -> IO ()+putExpression Interpreter{hIn = stdin} preserveIt e = do hPutStrLn stdin e- hPutStrLn stdin marker+ when preserveIt $ hPutStrLn stdin $ "let " ++ itMarker ++ " = it"+ hPutStrLn stdin (marker ++ " :: String")+ when preserveIt $ hPutStrLn stdin $ "let it = " ++ itMarker hFlush stdin getResult :: Bool -> Interpreter -> IO String@@ -124,11 +130,17 @@ -- | Evaluate an expression eval :: Interpreter -> String -> IO String eval repl expr = do- putExpression repl expr+ putExpression repl False expr getResult False repl +-- | Like 'eval', but try to preserve the @it@ variable+evalIt :: Interpreter -> String -> IO String+evalIt repl expr = do+ putExpression repl True expr+ getResult False repl+ -- | Evaluate an expression evalEcho :: Interpreter -> String -> IO String evalEcho repl expr = do- putExpression repl expr+ putExpression repl False expr getResult True repl
sensei.cabal view
@@ -1,11 +1,11 @@--- This file has been generated from package.yaml by hpack version 0.26.0.+cabal-version: 1.12++-- This file has been generated from package.yaml by hpack version 0.34.3. -- -- see: https://github.com/sol/hpack------ hash: 1c99e15f659870947cd1d509837f537a52ef65ed0b14cf82f2ea563482748657 name: sensei-version: 0.4.0+version: 0.5.0 synopsis: Automatically run Hspec tests on file modifications category: Development homepage: https://github.com/hspec/sensei#readme@@ -14,7 +14,6 @@ license: MIT license-file: LICENSE build-type: Simple-cabal-version: >= 1.10 source-repository head type: git@@ -29,8 +28,7 @@ ghc-options: -Wall build-depends: ansi-terminal- , base >=4.7 && <5- , base-compat >=0.8+ , base >=4.11 && <5 , bytestring , directory , filepath@@ -49,6 +47,7 @@ Client EventQueue HTTP+ Imports Options Run Session@@ -67,8 +66,7 @@ ghc-options: -Wall build-depends: ansi-terminal- , base >=4.7 && <5- , base-compat >=0.8+ , base >=4.11 && <5 , bytestring , directory , filepath@@ -87,6 +85,7 @@ Client EventQueue HTTP+ Imports Options Run Session@@ -105,8 +104,7 @@ ghc-options: -Wall build-depends: ansi-terminal- , base >=4.7 && <5- , base-compat >=0.8+ , base >=4.11 && <5 , bytestring , directory , filepath@@ -125,6 +123,7 @@ Client EventQueue HTTP+ Imports Options Run Session@@ -143,10 +142,11 @@ test ghc-options: -Wall cpp-options: -DTEST+ build-tool-depends:+ hspec-discover:hspec-discover build-depends: ansi-terminal- , base >=4.7 && <5- , base-compat >=0.8+ , base >=4.11 && <5 , bytestring , directory , filepath@@ -171,6 +171,7 @@ Client EventQueue HTTP+ Imports Options Run Session@@ -178,6 +179,7 @@ Util Language.Haskell.GhciWrapper ClientSpec+ EventQueueSpec Helper HTTPSpec OptionsSpec
src/Client.hs view
@@ -1,13 +1,8 @@ {-# LANGUAGE RecordWildCards, OverloadedStrings #-} module Client (client) where -import Prelude ()-import Prelude.Compat-import Control.Monad.Compat-import Data.Monoid.Compat-import Control.Exception-import Data.String-import System.IO.Error+import Imports+ import Network.HTTP.Client import Network.HTTP.Client.Internal (Response(..)) import Network.HTTP.Types
src/EventQueue.hs view
@@ -1,40 +1,45 @@+{-# LANGUAGE CPP #-} {-# LANGUAGE LambdaCase #-}+{-# LANGUAGE MultiWayIf #-} module EventQueue ( EventQueue , newQueue-, emitTriggerAll-, emitModified-, emitDone++, Event(..)+, FileEventType(..)+, emitEvent++, Status(..) , processQueue++#ifdef TEST+, Action(..)+, processEvents+, combineFileEvents+, groupFileEvents+#endif ) where -import Prelude ()-import Prelude.Compat+import Imports -import Control.Monad.Compat-import Control.Concurrent (threadDelay)-import Control.Concurrent.STM.TChan import Control.Monad.STM-import Data.List.Compat+import Control.Concurrent.STM.TChan import Util type EventQueue = TChan Event -data Event = TriggerAll | Modified FilePath | Done- deriving Eq+data Event = TriggerAll | FileEvent FileEventType FilePath | Done+ deriving (Eq, Show) +data FileEventType = FileAdded | FileRemoved | FileModified+ deriving (Eq, Show)+ newQueue :: IO EventQueue newQueue = atomically $ newTChan -emitTriggerAll :: EventQueue -> IO ()-emitTriggerAll chan = atomically $ writeTChan chan TriggerAll--emitModified :: FilePath -> EventQueue -> IO ()-emitModified path chan = atomically $ writeTChan chan (Modified path)--emitDone :: EventQueue -> IO ()-emitDone chan = atomically $ writeTChan chan Done+emitEvent :: EventQueue -> Event -> IO ()+emitEvent chan = atomically . writeTChan chan readEvents :: EventQueue -> IO [Event] readEvents chan = do@@ -54,18 +59,92 @@ Nothing -> return [] Just e -> (e :) <$> emptyQueue -processQueue :: EventQueue -> IO () -> IO () -> IO ()+data Status = Terminate | Reload++processQueue :: EventQueue -> IO () -> IO () -> IO Status processQueue chan triggerAll trigger = go where- go = do- readEvents chan >>= \case- events | Done `elem` events -> return ()- events | TriggerAll `elem` events -> do- triggerAll- go- events -> do- let files = (nub . sort) [p | Modified p <- events]- withInfoColor $ do- mapM_ putStrLn (map ("--> " ++) files)- trigger- go+ go = readEvents chan >>= processEvents >>= \ case+ NoneAction -> do+ go+ TriggerAction files -> do+ output files+ trigger+ go+ TriggerAllAction -> do+ triggerAll+ go+ ReloadAction file t -> do+ output [file <> " (" <> show t <> ", reloading)"]+ return Reload+ DoneAction -> do+ return Terminate++ output :: [String] -> IO ()+ output = withInfoColor . mapM_ (putStrLn . mappend "--> ")++data Action = NoneAction | TriggerAction [FilePath] | TriggerAllAction | ReloadAction FilePath FileEventType | DoneAction+ deriving (Eq, Show)++processEvents :: [Event] -> IO Action+processEvents events = do+ files <- fileEvents events+ return $ if+ | Done `elem` events -> DoneAction+ | (file, t) : _ <- filter shouldReload files -> ReloadAction file t+ | TriggerAll `elem` events -> TriggerAllAction+ | not (null files) -> TriggerAction $ nub . sort $ map fst files+ | otherwise -> NoneAction++shouldReload :: (FilePath, FileEventType) -> Bool+shouldReload (name, event) = "Spec.hs" `isSuffixOf` name && case event of+ FileAdded -> True+ FileRemoved -> True+ FileModified -> False++fileEvents :: [Event] -> IO [(FilePath, FileEventType)]+fileEvents events = filterGitIgnored $ combineFileEvents [(p, e) | FileEvent e p <- events]++filterGitIgnored :: [(FilePath, FileEventType)] -> IO [(FilePath, FileEventType)]+filterGitIgnored events = map f <$> filterGitIgnoredFiles (map fst events)+ where+ f :: FilePath -> (FilePath, FileEventType)+ f p = (p, fromJust $ lookup p events)++combineFileEvents :: [(FilePath, FileEventType)] -> [(FilePath, FileEventType)]+combineFileEvents events = [(file, e) | (file, Just e) <- map (second combineFileEventTypes) $ groupFileEvents events]++groupFileEvents :: [(FilePath, FileEventType)] -> [(FilePath, [FileEventType])]+groupFileEvents = map (second $ map snd) . groupOn fst++groupOn :: Eq b => (a -> b) -> [a] -> [(b, [a])]+groupOn f = go+ where+ go = \ case+ [] -> []+ x : xs -> case partition (\ a -> f a == f x) xs of+ (ys, zs) -> (f x, (x : ys)) : go zs++combineFileEventTypes :: [FileEventType] -> Maybe FileEventType+combineFileEventTypes = go+ where+ go events = case events of+ [] -> Nothing+ [e] -> Just e+ e1 : e2 : es -> go $ (combine e1 e2) es++ combine e1 e2 = case (e1, e2) of+ (FileAdded, FileAdded) -> ignoreDuplicate FileAdded+ (FileAdded, FileRemoved) -> id+ (FileAdded, FileModified) -> (FileAdded :)++ (FileRemoved, FileAdded) -> (FileModified :)+ (FileRemoved, FileRemoved) -> ignoreDuplicate FileRemoved+ (FileRemoved, FileModified) -> shouldNeverHappen++ (FileModified, FileAdded) -> shouldNeverHappen+ (FileModified, FileRemoved) -> (FileRemoved :)+ (FileModified, FileModified) -> ignoreDuplicate FileModified++ ignoreDuplicate = (:)+ shouldNeverHappen = (FileModified :)
src/HTTP.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE CPP #-} {-# LANGUAGE OverloadedStrings #-} module HTTP ( withServer@@ -5,18 +6,13 @@ , newSocket , socketAddr --- exported for testing+#ifdef TEST , app+#endif ) where -import Prelude ()-import Prelude.Compat-import Data.String-import Data.Text.Lazy.Encoding (encodeUtf8)-import Control.Exception-import Control.Monad-import Control.Concurrent-import System.IO.Error+import Imports+ import System.Directory import Network.Wai import Network.HTTP.Types
+ src/Imports.hs view
@@ -0,0 +1,14 @@+module Imports (module Imports) where++import Control.Concurrent as Imports+import Control.Exception as Imports+import Control.Monad as Imports+import Data.Bifunctor as Imports+import Data.Char as Imports+import Data.List as Imports+import Data.Maybe as Imports+import Data.String as Imports+import Data.Text.Lazy.Encoding as Imports (encodeUtf8)+import Data.Tuple as Imports+import System.IO.Error as Imports (isDoesNotExistError)+import Text.Read as Imports (readMaybe)
src/Options.hs view
@@ -1,6 +1,7 @@ module Options (splitArgs) where -import Data.List+import Imports+ import System.Console.GetOpt splitArgs :: [String] -> ([String], [String])@@ -32,6 +33,7 @@ , Option [] ["qc-max-discard"] (ReqArg (const ()) "N") , Option [] ["seed"] (ReqArg (const ()) "N") , Option [] ["print-cpu-time"] (NoArg ())+ , Option [] ["focused-only"] (NoArg ()) , Option [] ["dry-run"] (NoArg ()) , Option [] ["fail-fast"] (NoArg ()) , Option "r" ["rerun"] (NoArg ())
src/Run.hs view
@@ -1,12 +1,11 @@-{-# LANGUAGE OverloadedStrings #-}-module Run where-import Prelude ()-import Prelude.Compat+{-# LANGUAGE LambdaCase #-}+module Run (+ run+, runWeb+) where -import Control.Concurrent-import Control.Exception-import Control.Monad (void, forever, when)-import Data.Foldable+import Imports+ import System.Exit import System.FSNotify @@ -22,33 +21,51 @@ waitForever = forever $ threadDelay 10000000 watchFiles :: EventQueue -> IO ()-watchFiles queue = void . forkIO $ do- withManager $ \manager -> do- _ <- watchTree manager "." (not . isBoring . eventPath) (\event -> emitModified (eventPath event) queue)- waitForever+watchFiles queue = do+ watch $ emitEvent queue . \ case+ Added file _ _ -> FileEvent FileAdded file+ Removed file _ _ -> FileEvent FileRemoved file+ Modified file _ _ -> FileEvent FileModified file+ Unknown file _ _ -> FileEvent FileModified file+ where+ isInteresting = (&&) <$> not . eventIsDirectory <*> not . isBoring . eventPath + watch action = void . forkIO $ do+ withManager $ \ manager -> do+ _stopListening <- watchTree manager "." isInteresting action+ waitForever++ watchInput :: EventQueue -> IO () watchInput queue = void . forkIO $ do input <- getContents forM_ (lines input) $ \_ -> do- emitTriggerAll queue- emitDone queue+ emitEvent queue TriggerAll+ emitEvent queue Done run :: [String] -> IO () run args = do- withSession args $ \session -> do- queue <- newQueue- watchFiles queue- watchInput queue- lastOutput <- newMVar (True, "")- HTTP.withServer (readMVar lastOutput) $ do- let saveOutput :: IO (Bool, String) -> IO ()- saveOutput action = modifyMVar_ lastOutput $ \_ -> action- triggerAction = saveOutput (trigger session)- triggerAllAction = saveOutput (triggerAll session)- triggerAction- processQueue queue triggerAllAction triggerAction+ queue <- newQueue+ watchFiles queue+ watchInput queue+ lastOutput <- newMVar (True, "")+ HTTP.withServer (readMVar lastOutput) $ do+ let+ saveOutput :: IO (Bool, String) -> IO ()+ saveOutput action = modifyMVar_ lastOutput $ \_ -> action + go = do+ status <- withSession args $ \ session -> do+ let+ triggerAction = saveOutput (trigger session)+ triggerAllAction = saveOutput (triggerAll session)+ triggerAction+ processQueue queue triggerAllAction triggerAction+ case status of+ Reload -> go+ Terminate -> return ()+ go+ runWeb :: [String] -> IO () runWeb args = do withSession args $ \session -> do@@ -57,7 +74,7 @@ HTTP.withServer (withMVar lock $ \() -> trigger session) $ do waitForever -withSession :: [String] -> (Session -> IO ()) -> IO ()+withSession :: [String] -> (Session -> IO a) -> IO a withSession args action = do check <- dotGhciWritableByOthers when check $ do
src/Session.hs view
@@ -23,12 +23,9 @@ #endif ) where +import Imports+ import Data.IORef-import Data.List.Compat-import Data.Maybe (listToMaybe, catMaybes)-import Prelude ()-import Prelude.Compat-import Text.Read.Compat import qualified Language.Haskell.GhciWrapper as GhciWrapper import Language.Haskell.GhciWrapper hiding (new, close)
src/Trigger.hs view
@@ -7,10 +7,10 @@ #endif ) where -import Prelude ()-import Prelude.Compat-import Data.List.Compat+import Imports ++import Util import Session (Session, isFailure, isSuccess, hspecPreviousSummary, resetSummary) import qualified Session @@ -34,8 +34,12 @@ trigger session = do xs <- Session.reload session fmap (xs ++) <$> if reloadedSuccessfully xs- then hspec- else return (False, "")+ then do+ withColor Green $ putStrLn "RELOADING SUCCEEDED"+ hspec+ else do+ withColor Red $ putStrLn "RELOADING FAILED"+ return (False, "") where hspec = do mRun <- Session.getRunSpec session
src/Util.hs view
@@ -1,20 +1,35 @@-{-# LANGUAGE OverloadedStrings, LambdaCase #-}-module Util where+{-# LANGUAGE CPP, OverloadedStrings, LambdaCase, RecordWildCards, ViewPatterns #-}+module Util (+ Color(..)+, withColor+, withInfoColor+, isBoring+, filterGitIgnoredFiles+, normalizeTypeSignatures+, dotGhciWritableByOthers -import Prelude ()-import Prelude.Compat+#ifdef TEST+, filterGitIgnoredFiles_+, writableByOthers+#endif+) where -import Control.Exception-import Data.List.Compat+import Imports+ import System.Console.ANSI import System.FilePath+import System.Process import System.Posix.Files import System.Posix.Types+import qualified Data.Text as T withInfoColor :: IO a -> IO a-withInfoColor = bracket_ set reset+withInfoColor = withColor Magenta++withColor :: Color -> IO a -> IO a+withColor c = bracket_ set reset where- set = setSGR [SetColor Foreground Dull Magenta]+ set = setSGR [SetColor Foreground Dull c] reset = setSGR [] isBoring :: FilePath -> Bool@@ -22,6 +37,32 @@ where dirs = splitDirectories p isEmacsAutoSave = isPrefixOf ".#" . takeFileName++filterGitIgnoredFiles :: [FilePath] -> IO [FilePath]+filterGitIgnoredFiles files = do+ (feedback, ignoredFiles) <- filterGitIgnoredFiles_ files+ printFeedback feedback+ return $ ignoredFiles+ where+ printFeedback :: Feedback -> IO ()+ printFeedback = mapM_ $ \ (color, err) -> withColor color $ putStrLn ('\n' : err)++type Feedback = Maybe (Color, String)++filterGitIgnoredFiles_ :: [FilePath] -> IO (Feedback, [FilePath])+filterGitIgnoredFiles_ files = fmap (files \\) <$> gitCheckIgnore files++gitCheckIgnore :: [FilePath] -> IO (Feedback, [FilePath])+gitCheckIgnore files = do+ (_, ignoredFiles, err) <- readProcessWithExitCode "git" ["check-ignore", "--stdin", "-z"] $ join_ files+ return (feedback err, split ignoredFiles)+ where+ join_ = intercalate "\0"+ split = map T.unpack . T.split (== '\0') . T.pack+ feedback err+ | err == "fatal: not a git repository (or any of the parent directories): .git\n" = Just (Cyan, "warning: not a git repository - .gitignore support not available\n")+ | err == "" = Nothing+ | otherwise = Just (Red, err) normalizeTypeSignatures :: String -> String normalizeTypeSignatures = normalize . concatMap replace
+ test/EventQueueSpec.hs view
@@ -0,0 +1,71 @@+module EventQueueSpec (spec) where++import Helper++import EventQueue++withGitRepository :: IO a -> IO a+withGitRepository action = inTempDirectory (readProcess "git" ["init"] "" >> action)++spec :: Spec+spec = do+ describe "processEvents" $ do+ around_ withGitRepository $ do++ context "with FileEvent" $ do+ it "returns TriggerAction" $ do+ processEvents [FileEvent FileModified "test/FooSpec.hs"] `shouldReturn` TriggerAction ["test/FooSpec.hs"]++ context "with git ignored files" $ do+ it "returns NoneAction" $ do+ writeFile ".gitignore" "test/FooSpec.hs"+ processEvents [FileEvent FileModified "test/FooSpec.hs"] `shouldReturn` NoneAction++ context "when a Spec file is added" $ do+ it "returns ReloadAction" $ do+ processEvents [FileEvent FileAdded "test/FooSpec.hs"] `shouldReturn` ReloadAction "test/FooSpec.hs" FileAdded++ it "takes precedence over TriggerAll" $ do+ processEvents [TriggerAll, FileEvent FileAdded "test/FooSpec.hs", TriggerAll] `shouldReturn` ReloadAction "test/FooSpec.hs" FileAdded++ it "is overruled by Done" $ do+ processEvents [Done, FileEvent FileAdded "test/FooSpec.hs", Done] `shouldReturn` DoneAction++ context "when a Spec file is removed" $ do+ it "returns ReloadAction" $ do+ processEvents [FileEvent FileRemoved "test/FooSpec.hs"] `shouldReturn` ReloadAction "test/FooSpec.hs" FileRemoved++ context "when file is first removed and then added" $ do+ it "returns TriggerAction" $ do+ processEvents [FileEvent FileRemoved "test/FooSpec.hs", FileEvent FileAdded "test/FooSpec.hs"] `shouldReturn` TriggerAction ["test/FooSpec.hs"]++ context "when file is first added and then removed" $ do+ it "returns NoneAction" $ do+ processEvents [FileEvent FileAdded "test/FooSpec.hs", FileEvent FileRemoved "test/FooSpec.hs"] `shouldReturn` NoneAction++ context "with TriggerAll" $ do+ it "returns TriggerAllAction" $ do+ processEvents [TriggerAll] `shouldReturn` TriggerAllAction++ it "takes precedence over FileEvent" $ do+ processEvents [FileEvent FileModified "foo", TriggerAll, FileEvent FileModified "foo"] `shouldReturn` TriggerAllAction++ context "with Done" $ do+ it "returns DoneAction" $ do+ processEvents [Done] `shouldReturn` DoneAction++ describe "combineFileEvents" $ do+ it "combines removed/added to modified" $ do+ combineFileEvents [fileRemoved "foo", fileModified "bar", fileAdded "foo"] `shouldBe` [fileModified "foo", fileModified "bar"]++ it "does not combine events with different file names" $ do+ combineFileEvents [fileRemoved "foo", fileAdded "bar"] `shouldBe` [fileRemoved "foo", fileAdded "bar"]++ describe "groupFileEvents" $ do+ it "groups file event types by file name" $ do+ groupFileEvents [fileRemoved "foo", fileModified "bar", fileAdded "foo"] `shouldBe` [("foo", [FileRemoved, FileAdded]), ("bar", [FileModified])]++ where+ fileRemoved file = (file, FileRemoved)+ fileAdded file = (file, FileAdded)+ fileModified file = (file, FileModified)
test/HTTPSpec.hs view
@@ -1,7 +1,8 @@ {-# LANGUAGE OverloadedStrings #-} module HTTPSpec (spec) where -import Test.Hspec+import Helper+ import Test.Hspec.Wai import HTTP
test/Helper.hs view
@@ -1,10 +1,6 @@-{-# LANGUAGE CPP #-} {-# LANGUAGE QuasiQuotes #-} module Helper (- module Test.Hspec-, module Test.Mockery.Directory-, module Control.Applicative-, module System.IO.Silently+ module Imports , withSession , withSomeSpec , passingSpec@@ -14,15 +10,13 @@ , modulesLoaded ) where -import Control.Applicative-import Control.Exception+import Imports+ import Data.String.Interpolate-#if __GLASGOW_HASKELL__ < 802-import Data.List.Compat-#endif-import System.IO.Silently-import Test.Hspec-import Test.Mockery.Directory+import System.IO.Silently as Imports+import System.Process as Imports (readProcess, callCommand)+import Test.Hspec as Imports+import Test.Mockery.Directory as Imports import Run () import qualified Session@@ -74,13 +68,6 @@ deriving (Eq, Show) modulesLoaded :: Status -> [String] -> String-#if __GLASGOW_HASKELL__ < 802-modulesLoaded status xs = show status ++ ", modules loaded: " ++ mods ++ "."- where- mods = case xs of- [] -> "none"- _ -> intercalate ", " xs-#elif MIN_VERSION_base(4,10,1) modulesLoaded status xs = show status ++ ", " ++ mods ++ " loaded." where n = length xs@@ -93,11 +80,3 @@ | n == 5 = "five modules" | n == 6 = "six modules" | otherwise = show n ++ " modules"-#else-modulesLoaded status xs = show status ++ ", " ++ show n ++ " " ++ mods ++ " loaded."- where- n = length xs- mods- | n == 1 = "module"- | otherwise = "modules"-#endif
test/OptionsSpec.hs view
@@ -1,6 +1,6 @@ module OptionsSpec (main, spec) where -import Test.Hspec+import Helper import Options
test/SessionSpec.hs view
@@ -1,11 +1,11 @@ {-# LANGUAGE RecordWildCards #-} module SessionSpec (spec) where -import Language.Haskell.GhciWrapper (eval)-import System.Environment.Compat- import Helper +import System.Environment.Blank (setEnv)++import Language.Haskell.GhciWrapper (eval) import qualified Session import Session (Session(..), Summary(..), hspecFailureEnvName, hspecPreviousSummary, hspecCommand) @@ -13,7 +13,7 @@ spec = do describe "new" $ do it "unsets HSPEC_FAILURES" $ do- setEnv hspecFailureEnvName "foo"+ setEnv hspecFailureEnvName "foo" True withSession [] $ \Session{..} -> do _ <- eval sessionInterpreter "import System.Environment" eval sessionInterpreter ("lookupEnv " ++ show hspecFailureEnvName) `shouldReturn` "Nothing\n"
test/TriggerSpec.hs view
@@ -1,8 +1,6 @@ module TriggerSpec (spec) where import Helper-import Data.List.Compat-import Data.Char import Trigger @@ -77,9 +75,11 @@ , "" , "Failures:" , ""- , " Spec.hs:9: "+ , " Spec.hs:9:3: " , " 1) bar" , ""+ , " To rerun use: --match \"/bar/\""+ , "" , "Randomized with seed ..." , "" , "Finished in ..."@@ -133,8 +133,10 @@ , "" , "Failures:" , ""- , " Spec.hs:9: "+ , " Spec.hs:9:3: " , " 1) bar"+ , ""+ , " To rerun use: --match \"/bar/\"" , "" , "Randomized with seed ..." , ""
test/UtilSpec.hs view
@@ -4,7 +4,6 @@ import Helper import System.Posix.Files-import System.Process import Util @@ -23,6 +22,18 @@ it "replaces unicode characters" $ do normalizeTypeSignatures "head ∷ [a] → a" `shouldBe` "head :: [a] -> a"++ describe "filterGitIgnoredFiles_" $ do+ around_ inTempDirectory $ do+ it "discards files that are ignored by git" $ do+ _ <- readProcess "git" ["init"] ""+ writeFile ".gitignore" "foo"+ filterGitIgnoredFiles_ ["foo", "bar"] `shouldReturn` (Nothing, ["bar"])++ context "when used outside of a git repository" $ do+ it "returns all files" $ do+ let feedback = Just (Cyan, "warning: not a git repository - .gitignore support not available\n")+ filterGitIgnoredFiles_ ["foo", "bar"] `shouldReturn` (feedback, ["foo", "bar"]) describe "dotGhciWritableByOthers" $ do around_ inTempDirectory $ do