packages feed

skeletest 0.3.0 → 0.3.1

raw patch · 24 files changed

+406/−380 lines, 24 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

- Skeletest.Internal.TestRunner: TestResultMessageSection :: BoxSpec -> TestResultMessage
- Skeletest.Internal.Utils.BoxDrawing: BoxHeader :: Text -> BoxSpecContent
- Skeletest.Internal.Utils.BoxDrawing: BoxText :: Text -> BoxSpecContent
- Skeletest.Internal.Utils.BoxDrawing: data BoxSpecContent
- Skeletest.Internal.Utils.BoxDrawing: drawBox :: BoxSpec -> IO Text
- Skeletest.Internal.Utils.BoxDrawing: instance GHC.Classes.Eq Skeletest.Internal.Utils.BoxDrawing.BoxSpecContent
- Skeletest.Internal.Utils.BoxDrawing: instance GHC.Show.Show Skeletest.Internal.Utils.BoxDrawing.BoxSpecContent
- Skeletest.Internal.Utils.BoxDrawing: type BoxSpec = [BoxSpecContent]
- Skeletest.Plugin: TestResultMessageSection :: BoxSpec -> TestResultMessage
+ Skeletest.Internal.Spec.Output: BoxHeader :: Text -> BoxSpecContent
+ Skeletest.Internal.Spec.Output: BoxText :: Text -> BoxSpecContent
+ Skeletest.Internal.Spec.Output: data BoxSpecContent
+ Skeletest.Internal.Spec.Output: indent :: IndentLevel -> Text -> Text
+ Skeletest.Internal.Spec.Output: instance GHC.Classes.Eq Skeletest.Internal.Spec.Output.BoxSpecContent
+ Skeletest.Internal.Spec.Output: instance GHC.Show.Show Skeletest.Internal.Spec.Output.BoxSpecContent
+ Skeletest.Internal.Spec.Output: renderPrettyFailure :: Text -> [Text] -> [(FilePath, Int, Int, Int)] -> IO Text
+ Skeletest.Internal.Spec.Output: reportGroup :: IndentLevel -> Text -> IO ()
+ Skeletest.Internal.Spec.Output: reportTestInProgress :: IndentLevel -> Text -> IO ()
+ Skeletest.Internal.Spec.Output: reportTestResultWithBoxMessage :: Maybe (Window Int) -> IndentLevel -> Text -> Text -> BoxSpec -> IO ()
+ Skeletest.Internal.Spec.Output: reportTestResultWithInlineMessage :: IndentLevel -> Text -> Text -> IO ()
+ Skeletest.Internal.Spec.Output: reportTestResultWithoutMessage :: Text -> IO ()
+ Skeletest.Internal.Spec.Output: type BoxSpec = [BoxSpecContent]
+ Skeletest.Internal.Spec.Output: type IndentLevel = Int
+ Skeletest.Internal.TestRunner: TestResultMessageBox :: BoxSpec -> TestResultMessage
+ Skeletest.Plugin: BoxHeader :: Text -> BoxSpecContent
+ Skeletest.Plugin: BoxText :: Text -> BoxSpecContent
+ Skeletest.Plugin: TestResultMessageBox :: BoxSpec -> TestResultMessage
+ Skeletest.Plugin: data BoxSpecContent
+ Skeletest.Plugin: type BoxSpec = [BoxSpecContent]

Files

CHANGELOG.md view
@@ -1,3 +1,11 @@+## v0.3.1++API changes:+* Re-export `BoxSpec` and `BoxContent` from `Skeletest.Plugin`++Runtime changes:+* Tweak formatting of test failures/errors+ ## v0.3.0  GHC support:
skeletest.cabal view
@@ -1,7 +1,7 @@ cabal-version: 3.0  name: skeletest-version: 0.3.0+version: 0.3.1 synopsis: Batteries-included, opinionated test framework description: Batteries-included, opinionated test framework. See README.md for more details. homepage: https://github.com/brandonchinn178/skeletest#readme@@ -48,10 +48,10 @@     Skeletest.Internal.Preprocessor     Skeletest.Internal.Snapshot     Skeletest.Internal.Spec+    Skeletest.Internal.Spec.Output     Skeletest.Internal.TestInfo     Skeletest.Internal.TestRunner     Skeletest.Internal.TestTargets-    Skeletest.Internal.Utils.BoxDrawing     Skeletest.Internal.Utils.Color     Skeletest.Internal.Utils.Diff     Skeletest.Internal.Utils.HList
src/Skeletest/Internal/Capture.hs view
@@ -28,11 +28,11 @@   noCleanup,   withCleanup,  )+import Skeletest.Internal.Spec.Output (BoxSpecContent (..)) import Skeletest.Internal.TestRunner (   TestResult (..),   TestResultMessage (..),  )-import Skeletest.Internal.Utils.BoxDrawing (BoxSpecContent (..)) import System.Directory (removePathForcibly) import System.IO qualified as IO import UnliftIO.Exception (finally)@@ -85,7 +85,7 @@   updateResult output result =     result       { testResultMessage =-          TestResultMessageSection . concat $+          TestResultMessageBox . concat $             [ toBoxContents (testResultMessage result)             , renderOutput output             ]@@ -93,7 +93,7 @@   toBoxContents = \case     TestResultMessageNone -> []     TestResultMessageInline msg -> [BoxText msg]-    TestResultMessageSection box -> box+    TestResultMessageBox box -> box   renderOutput (stdout, stderr) =     concat       [ if Text.null stdout then [] else [BoxHeader "Captured stdout", BoxText stdout]
src/Skeletest/Internal/Spec.hs view
@@ -50,6 +50,13 @@   SomeMarker (..),   findMarker,  )+import Skeletest.Internal.Spec.Output (+  reportGroup,+  reportTestInProgress,+  reportTestResultWithBoxMessage,+  reportTestResultWithInlineMessage,+  reportTestResultWithoutMessage,+ ) import Skeletest.Internal.TestInfo (TestInfo (TestInfo), withTestInfo) import Skeletest.Internal.TestInfo qualified as TestInfo import Skeletest.Internal.TestRunner (@@ -60,11 +67,10 @@  ) import Skeletest.Internal.TestTargets (TestTarget, TestTargets, matchesTest) import Skeletest.Internal.TestTargets qualified as TestTargets-import Skeletest.Internal.Utils.BoxDrawing (drawBox) import Skeletest.Internal.Utils.Color qualified as Color import Skeletest.Plugin (Hooks (..), defaultHooks) import Skeletest.Prop.Internal (Property)-import System.IO qualified as IO+import System.Console.Terminal.Size qualified as Term import UnliftIO.Exception (   finally,   fromException,@@ -164,12 +170,11 @@   runTree baseTestInfo = \case     SpecGroup{..} -> do       let lvl = getIndentLevel baseTestInfo-      Text.putStrLn $ indent lvl groupLabel+      reportGroup lvl groupLabel       runTrees baseTestInfo{TestInfo.testContexts = TestInfo.testContexts baseTestInfo <> [groupLabel]} groupTrees     SpecTest{..} -> do       let lvl = getIndentLevel baseTestInfo-      Text.putStr $ indent lvl (testName <> ": ")-      IO.hFlush IO.stdout+      reportTestInProgress lvl testName        let testInfo =             baseTestInfo@@ -181,11 +186,14 @@           tid <- myThreadId           runTest testInfo testAction `finally` cleanupFixtures (PerTestFixtureKey tid) -      Text.putStrLn testResultLabel       case testResultMessage of-        TestResultMessageNone -> pure ()-        TestResultMessageInline msg -> Text.putStrLn $ indent (lvl + 1) msg-        TestResultMessageSection box -> drawBox box >>= Text.putStrLn+        TestResultMessageNone -> do+          reportTestResultWithoutMessage testResultLabel+        TestResultMessageInline msg -> do+          reportTestResultWithInlineMessage lvl testResultLabel msg+        TestResultMessageBox box -> do+          termSize <- Term.size+          reportTestResultWithBoxMessage termSize lvl testName testResultLabel box       pure testResultSuccess    runTest info action =@@ -200,7 +208,6 @@               Nothing -> testResultFromError e    getIndentLevel testInfo = length (TestInfo.testContexts testInfo) + 1 -- +1 to include the module name-  indent lvl = Text.intercalate "\n" . map (Text.replicate (lvl * 4) " " <>) . Text.splitOn "\n"  {----- Entrypoint -----} 
+ src/Skeletest/Internal/Spec/Output.hs view
@@ -0,0 +1,144 @@+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-}++module Skeletest.Internal.Spec.Output (+  reportGroup,+  reportTestInProgress,+  reportTestResultWithoutMessage,+  reportTestResultWithInlineMessage,+  reportTestResultWithBoxMessage,+  renderPrettyFailure,+  BoxSpec,+  BoxSpecContent (..),+  IndentLevel,+  indent,+) where++import Data.Maybe (listToMaybe)+import Data.Text (Text)+import Data.Text qualified as Text+import Data.Text.IO qualified as Text+import System.Console.Terminal.Size qualified as Term+import System.IO qualified as IO+import UnliftIO.Exception (SomeException, try)++reportGroup :: IndentLevel -> Text -> IO ()+reportGroup lvl name = do+  Text.putStrLn $ indent lvl name++reportTestInProgress :: IndentLevel -> Text -> IO ()+reportTestInProgress lvl testName = do+  Text.putStr $ indent lvl (testName <> ": ")+  IO.hFlush IO.stdout++reportTestResultWithoutMessage :: Text -> IO ()+reportTestResultWithoutMessage testResultLabel = do+  Text.putStrLn testResultLabel++reportTestResultWithInlineMessage :: IndentLevel -> Text -> Text -> IO ()+reportTestResultWithInlineMessage lvl testResultLabel testResultMessage = do+  Text.putStrLn testResultLabel+  Text.putStrLn $ indent (lvl + 1) testResultMessage++reportTestResultWithBoxMessage :: Maybe (Term.Window Int) -> IndentLevel -> Text -> Text -> BoxSpec -> IO ()+reportTestResultWithBoxMessage termSize lvl testName testResultLabel box = do+  if null box+    then do+      Text.putStrLn testResultLabel+    else do+      Text.putStr "\r"+      Text.putStrLn $ drawBoxHeader lvl testName <> ": " <> testResultLabel+      Text.putStrLn $ drawBoxBody termSize box++type IndentLevel = Int++indentSize :: Int+indentSize = 4++indentWith :: Text -> IndentLevel -> Text -> Text+indentWith fill lvl = Text.intercalate "\n" . map (Text.replicate (lvl * indentSize) fill <>) . Text.splitOn "\n"++indent :: IndentLevel -> Text -> Text+indent = indentWith " "++-- | Render a test failure like:+--+-- @+-- At test/Skeletest/Internal/TestTargetsSpec.hs:19:+-- |+-- |           parseTestTargets input `shouldBe` Right (Just expected)+-- |                                   ^^^^^^^^+--+-- Right 1 ≠ Left 1+-- @+renderPrettyFailure ::+  -- | Message+  Text ->+  -- | Failure context+  [Text] ->+  -- | Call stack (file, line, startCol, endCol)+  [(FilePath, Int, Int, Int)] ->+  IO Text+renderPrettyFailure msg ctx callstack = do+  prettyStackTrace <- mapM renderCallLine . reverse $ callstack+  pure . Text.intercalate "\n\n" . concat $+    [ prettyStackTrace+    , if null ctx+        then []+        else [Text.intercalate "\n" $ reverse ctx]+    , [msg]+    ]+ where+  renderCallLine (path, lineNum, startCol, endCol) = do+    mLine <-+      try (Text.readFile path) >>= \case+        Right srcFile -> pure $ getLineNum lineNum srcFile+        Left (_ :: SomeException) -> pure Nothing+    let (srcLine, pointerLine) =+          case mLine of+            Just line ->+              ( line+              , Text.replicate (startCol - 1) " " <> Text.replicate (endCol - startCol) "^"+              )+            Nothing ->+              ( "<unknown line>"+              , ""+              )++    pure . Text.intercalate "\n" $+      [ Text.pack path <> ":" <> (Text.pack . show) lineNum <> ":"+      , "│"+      , "│ " <> srcLine+      , "│ " <> pointerLine+      ]++  getLineNum n = listToMaybe . take 1 . drop (n - 1) . Text.lines++type BoxSpec = [BoxSpecContent]++data BoxSpecContent+  = BoxText Text+  | BoxHeader Text+  deriving (Show, Eq)++drawBoxHeader :: IndentLevel -> Text -> Text+drawBoxHeader lvl testName = "╭" <> Text.drop 2 (indentWith "─" lvl "") <> " " <> testName++drawBoxBody :: Maybe (Term.Window Int) -> BoxSpec -> Text+drawBoxBody termSize boxContents = Text.intercalate "\n" $ concatMap draw boxContents <> [footer]+ where+  termWidth = maybe 80 Term.width termSize+  width =+    maximum . (termWidth :) . flip concatMap boxContents $ \case+      BoxHeader s -> [Text.length s + indentSize + 2]+      BoxText s -> [Text.length line + 2 | line <- Text.lines s]++  footer = "╰" <> Text.replicate (width - 1) "─"++  draw = \case+    BoxHeader s ->+      [ drawLine ""+      , "╞═══ " <> s+      ]+    BoxText s -> map drawLine $ Text.lines s+  drawLine s = "│ " <> s
src/Skeletest/Internal/TestRunner.hs view
@@ -20,17 +20,19 @@  import Control.Monad (guard) import Control.Monad.IO.Class (MonadIO)-import Data.Maybe (listToMaybe) import Data.Text (Text) import Data.Text qualified as Text-import Data.Text.IO qualified as Text import Data.Typeable (typeOf) import GHC.IO.Exception qualified as GHC import GHC.Stack (CallStack) import GHC.Stack qualified as GHC import Skeletest.Internal.Error (SkeletestError)+import Skeletest.Internal.Spec.Output (+  BoxSpec,+  BoxSpecContent (..),+  renderPrettyFailure,+ ) import Skeletest.Internal.TestInfo (TestInfo)-import Skeletest.Internal.Utils.BoxDrawing (BoxSpec, BoxSpecContent (..)) import Skeletest.Internal.Utils.Color qualified as Color import Text.Read (readMaybe) import UnliftIO.Exception (@@ -38,7 +40,6 @@   SomeException (..),   displayException,   fromException,-  try,  )  {----- Testable -----}@@ -65,7 +66,7 @@ data TestResultMessage   = TestResultMessageNone   | TestResultMessageInline Text-  | TestResultMessageSection BoxSpec+  | TestResultMessageBox BoxSpec  testResultPass :: TestResult testResultPass =@@ -82,7 +83,7 @@     TestResult       { testResultSuccess = False       , testResultLabel = Color.red "FAIL"-      , testResultMessage = TestResultMessageSection [BoxText msg]+      , testResultMessage = TestResultMessageBox [BoxText msg]       }  testResultFromError :: SomeException -> IO TestResult@@ -92,7 +93,7 @@     TestResult       { testResultSuccess = False       , testResultLabel = Color.red "ERROR"-      , testResultMessage = TestResultMessageSection [BoxText msg]+      , testResultMessage = TestResultMessageBox [BoxText msg]       }  where   renderMsg@@ -184,55 +185,3 @@     [ (srcLocFile, srcLocStartLine, srcLocStartCol, srcLocEndCol)     | (_, GHC.SrcLoc{..}) <- GHC.getCallStack callStack     ]---- | Render a test failure like:------ @--- At test/Skeletest/Internal/TestTargetsSpec.hs:19:--- |--- |           parseTestTargets input `shouldBe` Right (Just expected)--- |                                   ^^^^^^^^------ Right 1 ≠ Left 1--- @-renderPrettyFailure ::-  -- | Message-  Text ->-  FailContext ->-  -- | Call stack (file, line, startCol, endCol)-  [(FilePath, Int, Int, Int)] ->-  IO Text-renderPrettyFailure msg ctx callstack = do-  prettyStackTrace <- mapM renderCallLine . reverse $ callstack-  pure . Text.intercalate "\n\n" . concat $-    [ prettyStackTrace-    , if null ctx-        then []-        else [Text.intercalate "\n" $ reverse ctx]-    , [msg]-    ]- where-  renderCallLine (path, lineNum, startCol, endCol) = do-    mLine <--      try (Text.readFile path) >>= \case-        Right srcFile -> pure $ getLineNum lineNum srcFile-        Left (_ :: SomeException) -> pure Nothing-    let (srcLine, pointerLine) =-          case mLine of-            Just line ->-              ( line-              , Text.replicate (startCol - 1) " " <> Text.replicate (endCol - startCol) "^"-              )-            Nothing ->-              ( "<unknown line>"-              , ""-              )--    pure . Text.intercalate "\n" $-      [ Text.pack path <> ":" <> (Text.pack . show) lineNum <> ":"-      , "|"-      , "| " <> srcLine-      , "| " <> pointerLine-      ]--  getLineNum n = listToMaybe . take 1 . drop (n - 1) . Text.lines
− src/Skeletest/Internal/Utils/BoxDrawing.hs
@@ -1,49 +0,0 @@-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE OverloadedStrings #-}--module Skeletest.Internal.Utils.BoxDrawing (-  BoxSpec,-  BoxSpecContent (..),-  drawBox,-) where--import Data.Text (Text)-import Data.Text qualified as Text-import System.Console.Terminal.Size qualified as Term--type BoxSpec = [BoxSpecContent]--data BoxSpecContent-  = BoxText Text-  | BoxHeader Text-  deriving (Show, Eq)--drawBox :: BoxSpec -> IO Text-drawBox box = do-  width <- maybe 80 (max 40 . Term.width) <$> Term.size-  pure $ drawBox' width box--drawBox' :: Int -> BoxSpec -> Text-drawBox' width boxContents = Text.intercalate "\n" $ [header] <> concatMap draw boxContents <> [footer]- where-  header = "╔" <> Text.replicate (width - 2) "═" <> "╗"-  footer = "╚" <> Text.replicate (width - 2) "═" <> "╝"--  draw = \case-    BoxHeader s ->-      [ drawLine ""-      , "╟─" <> cpad (width - 4) "─" ("⟨ " <> s <> " ⟩") <> "─╢"-      ]-    BoxText s ->-      [ drawLine line-      | rawLine <- Text.lines s-      , line <- if Text.null rawLine then [""] else Text.chunksOf (width - 4) rawLine-      ]-  drawLine s = "║ " <> rpad (width - 4) " " s <> " ║"--  rpad n fill s = s <> Text.replicate (n - Text.length s) fill-  cpad n fill s =-    let total = n - Text.length s-        left = total `div` 2-        right = total - left-     in Text.replicate left fill <> s <> Text.replicate right fill
src/Skeletest/Plugin.hs view
@@ -11,6 +11,8 @@   -- ** TestResult   TestResult (..),   TestResultMessage (..),+  BoxSpec,+  BoxSpecContent (..),    -- ** TestInfo   TestInfo (..),@@ -23,6 +25,7 @@ import Skeletest.Internal.CLI (Flag) import Skeletest.Internal.Markers (findMarker, hasMarkerNamed) import Skeletest.Internal.Snapshot (SnapshotRenderer)+import Skeletest.Internal.Spec.Output (BoxSpec, BoxSpecContent (..)) import Skeletest.Internal.TestInfo (TestInfo (..)) import Skeletest.Internal.TestRunner (TestResult (..), TestResultMessage (..)) 
test/Skeletest/AssertionsSpec.hs view
@@ -26,8 +26,7 @@         , "spec = it \"should fail\" $ 1 `shouldBe` (2 :: Int)"         ] -      (code, stdout, stderr) <- runTests runner []-      code `shouldBe` ExitFailure 1+      (stdout, stderr) <- expectFailure $ runTests runner []       stderr `shouldBe` ""       stdout `shouldSatisfy` P.matchesSnapshot @@ -45,8 +44,7 @@         , "spec = it \"should fail\" $ 1 `shouldNotBe` (1 :: Int)"         ] -      (code, stdout, stderr) <- runTests runner []-      code `shouldBe` ExitFailure 1+      (stdout, stderr) <- expectFailure $ runTests runner []       stderr `shouldBe` ""       stdout `shouldSatisfy` P.matchesSnapshot @@ -65,8 +63,7 @@         , "spec = it \"should fail\" $ (-1) `shouldSatisfy` P.gt (0 :: Int)"         ] -      (code, stdout, stderr) <- runTests runner []-      code `shouldBe` ExitFailure 1+      (stdout, stderr) <- expectFailure $ runTests runner []       stderr `shouldBe` ""       stdout `shouldSatisfy` P.matchesSnapshot @@ -85,8 +82,7 @@         , "spec = it \"should fail\" $ 1 `shouldNotSatisfy` P.gt (0 :: Int)"         ] -      (code, stdout, stderr) <- runTests runner []-      code `shouldBe` ExitFailure 1+      (stdout, stderr) <- expectFailure $ runTests runner []       stderr `shouldBe` ""       stdout `shouldSatisfy` P.matchesSnapshot @@ -103,8 +99,7 @@         , "    1 `shouldBe` (2 :: Int)"         ] -      (code, stdout, stderr) <- runTests runner []-      code `shouldBe` ExitFailure 1+      (stdout, stderr) <- expectFailure $ runTests runner []       stderr `shouldBe` ""       stdout `shouldSatisfy` P.matchesSnapshot @@ -119,8 +114,7 @@         , "spec = it \"should fail\" $ failTest \"error message\""         ] -      (code, stdout, stderr) <- runTests runner []-      code `shouldBe` ExitFailure 1+      (stdout, stderr) <- expectFailure $ runTests runner []       stderr `shouldBe` ""       stdout `shouldSatisfy` P.matchesSnapshot @@ -141,8 +135,7 @@       , "expectGT x actual = actual `shouldSatisfy` P.gt x"       ] -    (code, stdout, stderr) <- runTests runner []-    code `shouldBe` ExitFailure 1+    (stdout, stderr) <- expectFailure $ runTests runner []     stderr `shouldBe` ""     stdout `shouldSatisfy` P.matchesSnapshot @@ -159,8 +152,7 @@       , "  x `shouldBe` True"       ] -    (code, stdout, stderr) <- runTests runner []-    code `shouldBe` ExitFailure 1+    (stdout, stderr) <- expectFailure $ runTests runner []     stderr `shouldBe` ""     stdout `shouldSatisfy` P.matchesSnapshot @@ -177,8 +169,7 @@       , "  pure ()"       ] -    (code, stdout, stderr) <- runTests runner []-    code `shouldBe` ExitFailure 1+    (stdout, stderr) <- expectFailure $ runTests runner []     stderr `shouldBe` ""     sanitizeTraceback stdout `shouldSatisfy` P.matchesSnapshot @@ -188,8 +179,12 @@ #if __GLASGOW_HASKELL__ == 910 sanitizeTraceback s =   let (pre, post) = break (Text.pack "HasCallStack backtrace:" `Text.isInfixOf`) $ Text.lines $ Text.pack s-      (_, post2) = break (Text.pack "╚" `Text.isPrefixOf`) $ drop 1 post-   in Text.unpack . Text.unlines $ pre ++ post2+      (_, post2) = break (Text.pack "╰" `Text.isPrefixOf`) $ drop 1 post+      post2' =+        case post2 of+          [] -> []+          l : ls -> Text.take 80 l : ls+   in Text.unpack . Text.unlines $ pre ++ post2' #else sanitizeTraceback = id #endif
test/Skeletest/Internal/CLISpec.hs view
@@ -84,8 +84,7 @@         , "  pure ()"         ] -      (code, stdout, stderr) <- runTests runner []-      code `shouldBe` ExitFailure 1+      (stdout, stderr) <- expectFailure $ runTests runner []       stderr `shouldBe` ""       stdout `shouldSatisfy` P.matchesSnapshot 
test/Skeletest/Internal/CaptureSpec.hs view
@@ -64,10 +64,9 @@         , "    " <> render_hPutStrLn handle "line2"         , "    1 `shouldBe` 2"         ]-      (code, stdout, stderr) <- runTests runner []+      (stdout, stderr) <- expectFailure $ runTests runner []       stderr `shouldBe` ""       stdout `shouldSatisfy` P.matchesSnapshot-      code `shouldBe` ExitFailure 1      integration . it "is rendered on test error" $ do       runner <- getFixture@@ -88,10 +87,9 @@         , "    Just _ <- pure Nothing"         , "    pure ()"         ]-      (code, stdout, stderr) <- runTests runner []+      (stdout, stderr) <- expectFailure $ runTests runner []       stderr `shouldBe` ""       stdout `shouldSatisfy` P.matchesSnapshot-      code `shouldBe` ExitFailure 1      integration . it "is not captured with --capture-output=off" $ do       runner <- getFixture@@ -141,10 +139,8 @@         , "    s <- output." <> func         , "    s `shouldBe` " <> show "test1\ntest2\n"         ]-      (code, stdout, stderr) <- runTests runner []-      stderr `shouldBe` ""-      context stdout $-        code `shouldBe` ExitSuccess+      _ <- expectSuccess $ runTests runner []+      pure ()  fixtureReadSpec :: (String, String) -> Spec fixtureReadSpec (handle, func) =@@ -173,10 +169,8 @@         , "    s <- output." <> func         , "    s `shouldBe` " <> show "test2\n"         ]-      (code, stdout, stderr) <- runTests runner []-      stderr `shouldBe` ""-      context stdout $-        code `shouldBe` ExitSuccess+      _ <- expectSuccess $ runTests runner []+      pure ()  render_hPutStrLn :: String -> String -> String render_hPutStrLn handle s = "IO.hPutStrLn IO." <> handle <> " " <> show s
test/Skeletest/Internal/FixturesSpec.hs view
@@ -51,7 +51,6 @@         , "  pure ()"         ] -      (code, stdout, stderr) <- runTests runner []-      code `shouldBe` ExitFailure 1+      (stdout, stderr) <- expectFailure $ runTests runner []       stderr `shouldBe` ""       stdout `shouldSatisfy` P.matchesSnapshot
test/Skeletest/Internal/SnapshotSpec.hs view
@@ -43,8 +43,7 @@       ]     addTestFile runner "__snapshots__/ExampleSpec.snap.md" ["asdf"] -    (code, stdout, stderr) <- runTests runner []-    code `shouldBe` ExitFailure 1+    (stdout, stderr) <- expectFailure $ runTests runner []     stderr `shouldBe` ""     stdout `shouldSatisfy` P.matchesSnapshot @@ -105,8 +104,7 @@       , "```"       ] -    (code, stdout, stderr) <- runTests runner []-    code `shouldBe` ExitFailure 1+    (stdout, stderr) <- expectFailure $ runTests runner []     stderr `shouldBe` ""     stdout `shouldSatisfy` P.matchesSnapshot 
test/Skeletest/Internal/SpecSpec.hs view
@@ -52,8 +52,7 @@         , "  it \"should fail too\" $ pure ()"         ] -      (code, stdout, stderr) <- runTests runner []-      code `shouldBe` ExitFailure 1+      (stdout, stderr) <- expectFailure $ runTests runner []       stderr `shouldBe` ""       stdout `shouldSatisfy` P.matchesSnapshot 
test/Skeletest/Internal/__snapshots__/CLISpec.snap.md view
@@ -4,9 +4,7 @@  ``` ./ExampleSpec.hs-    should error: ERROR-╔══════════════════════════════════════════════════════════════════════════════╗-║ CLI flag 'my-flag' was not registered. Did you add it to cliFlags in Main.hs ║-║ ?                                                                            ║-╚══════════════════════════════════════════════════════════════════════════════╝+╭── should error: ERROR+│ CLI flag 'my-flag' was not registered. Did you add it to cliFlags in Main.hs?+╰─────────────────────────────────────────────────────────────────────────────── ```
test/Skeletest/Internal/__snapshots__/FixturesSpec.snap.md view
@@ -4,9 +4,7 @@  ``` ./ExampleSpec.hs-    should error: ERROR-╔══════════════════════════════════════════════════════════════════════════════╗-║ Found circular dependency when resolving fixtures: FixtureA -> FixtureB -> F ║-║ ixtureD -> FixtureA                                                          ║-╚══════════════════════════════════════════════════════════════════════════════╝+╭── should error: ERROR+│ Found circular dependency when resolving fixtures: FixtureA -> FixtureB -> FixtureD -> FixtureA+╰──────────────────────────────────────────────────────────────────────────────────────────────── ```
test/Skeletest/Internal/__snapshots__/SnapshotSpec.snap.md view
@@ -4,10 +4,9 @@  ``` ./ExampleSpec.hs-    should error: ERROR-╔══════════════════════════════════════════════════════════════════════════════╗-║ Snapshot file was corrupted: ./__snapshots__/ExampleSpec.snap.md             ║-╚══════════════════════════════════════════════════════════════════════════════╝+╭── should error: ERROR+│ Snapshot file was corrupted: ./__snapshots__/ExampleSpec.snap.md+╰─────────────────────────────────────────────────────────────────────────────── ```  ## renders JSON values@@ -25,23 +24,21 @@  ``` ./ExampleSpec.hs-    fails: FAIL-╔══════════════════════════════════════════════════════════════════════════════╗-║ ./ExampleSpec.hs:7:                                                          ║-║ |                                                                            ║-║ |   unlines ["new1", "same1", "same2", "new2"] `shouldSatisfy` P.matchesSnap ║-║ shot                                                                         ║-║ |                                              ^^^^^^^^^^^^^^^               ║-║                                                                              ║-║ Result differed from snapshot. Update snapshot with --update.                ║-║ --- expected                                                                 ║-║ +++ actual                                                                   ║-║ @@ -1,4 +1,4 @@                                                              ║-║ +new1                                                                        ║-║  same1                                                                       ║-║ -old1                                                                        ║-║  same2                                                                       ║-║ -old2                                                                        ║-║ +new2                                                                        ║-╚══════════════════════════════════════════════════════════════════════════════╝+╭── fails: FAIL+│ ./ExampleSpec.hs:7:+│ │+│ │   unlines ["new1", "same1", "same2", "new2"] `shouldSatisfy` P.matchesSnapshot+│ │                                              ^^^^^^^^^^^^^^^+│ +│ Result differed from snapshot. Update snapshot with --update.+│ --- expected+│ +++ actual+│ @@ -1,4 +1,4 @@+│ +new1+│  same1+│ -old1+│  same2+│ -old2+│ +new2+╰───────────────────────────────────────────────────────────────────────────────── ```
test/Skeletest/MainSpec.hs view
@@ -14,8 +14,7 @@     setMainFile runner []     addTestFile runner "ExampleSpec.hs" (minimalTest "ExampleSpec") -    (code, stdout, stderr) <- runTests runner []-    code `shouldBe` ExitFailure 1+    (stdout, stderr) <- expectFailure $ runTests runner []     stdout `shouldBe` ""     normalizePluginError stderr `shouldSatisfy` P.matchesSnapshot @@ -44,8 +43,7 @@       ]     addTestFile runner "ExampleSpec.hs" (minimalTest "ExampleSpec") -    (code, stdout, stderr) <- runTests runner []-    code `shouldBe` ExitFailure 1+    (stdout, stderr) <- expectFailure $ runTests runner []     stdout `shouldBe` ""     normalizeGhc29916 stderr `shouldSatisfy` P.matchesSnapshot 
test/Skeletest/PredicateSpec.hs view
@@ -143,8 +143,7 @@           , "  User \"alice\" `shouldSatisfy` P.con User{name = P.eq \"\"}"           ] -        (code, stdout, stderr) <- runTests runner []-        code `shouldBe` ExitFailure 1+        (stdout, stderr) <- expectFailure $ runTests runner []         stderr `shouldBe` ""         stdout `shouldSatisfy` P.matchesSnapshot @@ -162,8 +161,7 @@           , "  User \"alice\" `shouldSatisfy` P.con User{foo = P.eq \"\"}"           ] -        (code, stdout, stderr) <- runTests runner []-        code `shouldBe` ExitFailure 1+        (stdout, stderr) <- expectFailure $ runTests runner []         stdout `shouldBe` ""         stderr `shouldSatisfy` P.matchesSnapshot @@ -181,8 +179,7 @@           , "  User \"alice\" (Just 1) `shouldSatisfy` P.con (User (P.eq \"\"))"           ] -        (code, stdout, stderr) <- runTests runner []-        code `shouldBe` ExitFailure 1+        (stdout, stderr) <- expectFailure $ runTests runner []         stdout `shouldBe` ""         (normalizeConFailure . normalizeVars) stderr `shouldSatisfy` P.matchesSnapshot @@ -198,8 +195,7 @@           , "  \"\" `shouldSatisfy` P.con \"\""           ] -        (code, stdout, stderr) <- runTests runner []-        code `shouldBe` ExitFailure 1+        (stdout, stderr) <- expectFailure $ runTests runner []         stdout `shouldBe` ""         stderr `shouldSatisfy` P.matchesSnapshot @@ -215,8 +211,7 @@           , "  \"\" `shouldSatisfy` P.con"           ] -        (code, stdout, stderr) <- runTests runner []-        code `shouldBe` ExitFailure 1+        (stdout, stderr) <- expectFailure $ runTests runner []         stdout `shouldBe` ""         stderr `shouldSatisfy` P.matchesSnapshot @@ -232,8 +227,7 @@           , "  \"\" `shouldSatisfy` P.con 1 2"           ] -        (code, stdout, stderr) <- runTests runner []-        code `shouldBe` ExitFailure 1+        (stdout, stderr) <- expectFailure $ runTests runner []         stdout `shouldBe` ""         stderr `shouldSatisfy` P.matchesSnapshot 
test/Skeletest/PropSpec.hs view
@@ -22,8 +22,7 @@         , "  discard"         ] -      (code, stdout, stderr) <- runTests runner []-      code `shouldBe` ExitFailure 1+      (stdout, stderr) <- expectFailure $ runTests runner []       stderr `shouldBe` ""       stdout `shouldSatisfy` P.matchesSnapshot @@ -49,7 +48,6 @@         , "    (read . show) P.=== id `shouldNotSatisfy` P.isoWith (Gen.int $ Range.linear 0 10)"         ] -      (code, stdout, stderr) <- runTests runner ["--seed=0:0"]-      code `shouldBe` ExitFailure 1+      (stdout, stderr) <- expectFailure $ runTests runner ["--seed=0:0"]       stderr `shouldBe` ""       stdout `shouldSatisfy` P.matchesSnapshot
test/Skeletest/TestUtils/Integration.hs view
@@ -13,7 +13,9 @@    -- * runTests   runTests,+  expectCode,   expectSuccess,+  expectFailure,    -- * Re-exports   ExitCode (..),@@ -107,15 +109,25 @@       ]   setCWD dir p = p{cwd = Just dir} -  sanitize = Text.unpack . stripControlChars . Text.strip . Text.pack+  sanitize = Text.unpack . stripOverwrites . stripControlChars . Text.strip . Text.pack+  stripOverwrites s =+    case Text.breakOn "\r" s of+      (_, "") -> s+      (pre, post) -> Text.dropWhileEnd (/= '\n') pre <> stripOverwrites (Text.drop 1 post)   stripControlChars s =     case Text.breakOn "\x1b" s of       (_, "") -> s       (pre, post) -> pre <> stripControlChars (Text.drop 1 . Text.dropWhile (/= 'm') $ post) -expectSuccess :: (HasCallStack) => IO (ExitCode, String, String) -> IO (String, String)-expectSuccess m = do+expectCode :: (HasCallStack) => ExitCode -> IO (ExitCode, String, String) -> IO (String, String)+expectCode expected m = do   (code, stdout, stderr) <- m   context (unlines ["===== stdout =====", stdout, "===== stderr =====", stderr]) $-    code `shouldBe` ExitSuccess+    code `shouldBe` expected   pure (stdout, stderr)++expectSuccess :: (HasCallStack) => IO (ExitCode, String, String) -> IO (String, String)+expectSuccess = expectCode ExitSuccess++expectFailure :: (HasCallStack) => IO (ExitCode, String, String) -> IO (String, String)+expectFailure = expectCode $ ExitFailure 1
test/Skeletest/__snapshots__/AssertionsSpec.snap.md view
@@ -4,154 +4,145 @@  ``` ./ExampleSpec.hs-    should fail: FAIL-╔══════════════════════════════════════════════════════════════════════════════╗-║ ./ExampleSpec.hs:7:                                                          ║-║ |                                                                            ║-║ |     1 `shouldBe` (2 :: Int)                                                ║-║ |       ^^^^^^^^^^                                                           ║-║                                                                              ║-║ hello                                                                        ║-║ world                                                                        ║-║                                                                              ║-║ 1 ≠ 2                                                                        ║-╚══════════════════════════════════════════════════════════════════════════════╝+╭── should fail: FAIL+│ ./ExampleSpec.hs:7:+│ │+│ │     1 `shouldBe` (2 :: Int)+│ │       ^^^^^^^^^^+│ +│ hello+│ world+│ +│ 1 ≠ 2+╰─────────────────────────────────────────────────────────────────────────────── ```  ## failTest / should show failure  ``` ./ExampleSpec.hs-    should fail: FAIL-╔══════════════════════════════════════════════════════════════════════════════╗-║ ./ExampleSpec.hs:5:                                                          ║-║ |                                                                            ║-║ | spec = it "should fail" $ failTest "error message"                         ║-║ |                           ^^^^^^^^                                         ║-║                                                                              ║-║ error message                                                                ║-╚══════════════════════════════════════════════════════════════════════════════╝+╭── should fail: FAIL+│ ./ExampleSpec.hs:5:+│ │+│ │ spec = it "should fail" $ failTest "error message"+│ │                           ^^^^^^^^+│ +│ error message+╰─────────────────────────────────────────────────────────────────────────────── ```  ## shouldBe / should show helpful failure  ``` ./ExampleSpec.hs-    should fail: FAIL-╔══════════════════════════════════════════════════════════════════════════════╗-║ ./ExampleSpec.hs:5:                                                          ║-║ |                                                                            ║-║ | spec = it "should fail" $ 1 `shouldBe` (2 :: Int)                          ║-║ |                             ^^^^^^^^^^                                     ║-║                                                                              ║-║ 1 ≠ 2                                                                        ║-╚══════════════════════════════════════════════════════════════════════════════╝+╭── should fail: FAIL+│ ./ExampleSpec.hs:5:+│ │+│ │ spec = it "should fail" $ 1 `shouldBe` (2 :: Int)+│ │                             ^^^^^^^^^^+│ +│ 1 ≠ 2+╰─────────────────────────────────────────────────────────────────────────────── ```  ## shouldNotBe / should show helpful failure  ``` ./ExampleSpec.hs-    should fail: FAIL-╔══════════════════════════════════════════════════════════════════════════════╗-║ ./ExampleSpec.hs:5:                                                          ║-║ |                                                                            ║-║ | spec = it "should fail" $ 1 `shouldNotBe` (1 :: Int)                       ║-║ |                             ^^^^^^^^^^^^^                                  ║-║                                                                              ║-║ 1 = 1                                                                        ║-║                                                                              ║-║ Expected:                                                                    ║-║   ≠ 1                                                                        ║-║                                                                              ║-║ Got:                                                                         ║-║   1                                                                          ║-╚══════════════════════════════════════════════════════════════════════════════╝+╭── should fail: FAIL+│ ./ExampleSpec.hs:5:+│ │+│ │ spec = it "should fail" $ 1 `shouldNotBe` (1 :: Int)+│ │                             ^^^^^^^^^^^^^+│ +│ 1 = 1+│ +│ Expected:+│   ≠ 1+│ +│ Got:+│   1+╰─────────────────────────────────────────────────────────────────────────────── ```  ## shouldNotSatisfy / should show helpful failure  ``` ./ExampleSpec.hs-    should fail: FAIL-╔══════════════════════════════════════════════════════════════════════════════╗-║ ./ExampleSpec.hs:6:                                                          ║-║ |                                                                            ║-║ | spec = it "should fail" $ 1 `shouldNotSatisfy` P.gt (0 :: Int)             ║-║ |                             ^^^^^^^^^^^^^^^^^^                             ║-║                                                                              ║-║ 1 > 0                                                                        ║-║                                                                              ║-║ Expected:                                                                    ║-║   ≯ 0                                                                        ║-║                                                                              ║-║ Got:                                                                         ║-║   1                                                                          ║-╚══════════════════════════════════════════════════════════════════════════════╝+╭── should fail: FAIL+│ ./ExampleSpec.hs:6:+│ │+│ │ spec = it "should fail" $ 1 `shouldNotSatisfy` P.gt (0 :: Int)+│ │                             ^^^^^^^^^^^^^^^^^^+│ +│ 1 > 0+│ +│ Expected:+│   ≯ 0+│ +│ Got:+│   1+╰─────────────────────────────────────────────────────────────────────────────── ```  ## shouldSatisfy / should show helpful failure  ``` ./ExampleSpec.hs-    should fail: FAIL-╔══════════════════════════════════════════════════════════════════════════════╗-║ ./ExampleSpec.hs:6:                                                          ║-║ |                                                                            ║-║ | spec = it "should fail" $ (-1) `shouldSatisfy` P.gt (0 :: Int)             ║-║ |                                ^^^^^^^^^^^^^^^                             ║-║                                                                              ║-║ -1 ≯ 0                                                                       ║-╚══════════════════════════════════════════════════════════════════════════════╝+╭── should fail: FAIL+│ ./ExampleSpec.hs:6:+│ │+│ │ spec = it "should fail" $ (-1) `shouldSatisfy` P.gt (0 :: Int)+│ │                                ^^^^^^^^^^^^^^^+│ +│ -1 ≯ 0+╰─────────────────────────────────────────────────────────────────────────────── ```  ## shows backtrace of failed assertions  ``` ./ExampleSpec.hs-    should fail: FAIL-╔══════════════════════════════════════════════════════════════════════════════╗-║ ./ExampleSpec.hs:6:                                                          ║-║ |                                                                            ║-║ | spec = it "should fail" $ expectPositive (-1)                              ║-║ |                           ^^^^^^^^^^^^^^                                   ║-║                                                                              ║-║ ./ExampleSpec.hs:9:                                                          ║-║ |                                                                            ║-║ | expectPositive = expectGT 0                                                ║-║ |                  ^^^^^^^^                                                  ║-║                                                                              ║-║ ./ExampleSpec.hs:12:                                                         ║-║ |                                                                            ║-║ | expectGT x actual = actual `shouldSatisfy` P.gt x                          ║-║ |                            ^^^^^^^^^^^^^^^                                 ║-║                                                                              ║-║ -1 ≯ 0                                                                       ║-╚══════════════════════════════════════════════════════════════════════════════╝+╭── should fail: FAIL+│ ./ExampleSpec.hs:6:+│ │+│ │ spec = it "should fail" $ expectPositive (-1)+│ │                           ^^^^^^^^^^^^^^+│ +│ ./ExampleSpec.hs:9:+│ │+│ │ expectPositive = expectGT 0+│ │                  ^^^^^^^^+│ +│ ./ExampleSpec.hs:12:+│ │+│ │ expectGT x actual = actual `shouldSatisfy` P.gt x+│ │                            ^^^^^^^^^^^^^^^+│ +│ -1 ≯ 0+╰─────────────────────────────────────────────────────────────────────────────── ```  ## shows helpful error on pattern match fail  ``` ./ExampleSpec.hs-    should fail: ERROR-╔══════════════════════════════════════════════════════════════════════════════╗-║ ExampleSpec.hs:7:                                                            ║-║ |                                                                            ║-║ |   Just x <- pure Nothing                                                   ║-║ |   ^^^^^^                                                                   ║-║                                                                              ║-║ Pattern match failure in 'do' block                                          ║-╚══════════════════════════════════════════════════════════════════════════════╝+╭── should fail: ERROR+│ ExampleSpec.hs:7:+│ │+│ │   Just x <- pure Nothing+│ │   ^^^^^^+│ +│ Pattern match failure in 'do' block+╰─────────────────────────────────────────────────────────────────────────────── ```  ## shows unrecognized exceptions  ``` ./ExampleSpec.hs-    should fail: ERROR-╔══════════════════════════════════════════════════════════════════════════════╗-║ Got exception of type `IOException`:                                         ║-║ unknown-file.txt: openFile: does not exist (No such file or directory)       ║-╚══════════════════════════════════════════════════════════════════════════════╝+╭── should fail: ERROR+│ Got exception of type `IOException`:+│ unknown-file.txt: openFile: does not exist (No such file or directory)+╰─────────────────────────────────────────────────────────────────────────────── ```
test/Skeletest/__snapshots__/PredicateSpec.snap.md view
@@ -252,21 +252,20 @@  ``` ./ExampleSpec.hs-    should error: FAIL-╔══════════════════════════════════════════════════════════════════════════════╗-║ ./ExampleSpec.hs:9:                                                          ║-║ |                                                                            ║-║ |   User "alice" `shouldSatisfy` P.con User{name = P.eq ""}                  ║-║ |                ^^^^^^^^^^^^^^^                                             ║-║                                                                              ║-║ "alice" ≠ []                                                                 ║-║                                                                              ║-║ Expected:                                                                    ║-║   matches User{name = (= [])}                                                ║-║                                                                              ║-║ Got:                                                                         ║-║   User "alice"                                                               ║-╚══════════════════════════════════════════════════════════════════════════════╝+╭── should error: FAIL+│ ./ExampleSpec.hs:9:+│ │+│ │   User "alice" `shouldSatisfy` P.con User{name = P.eq ""}+│ │                ^^^^^^^^^^^^^^^+│ +│ "alice" ≠ []+│ +│ Expected:+│   matches User{name = (= [])}+│ +│ Got:+│   User "alice"+╰─────────────────────────────────────────────────────────────────────────────── ```  ## Data types / list / shows helpful failure messages
test/Skeletest/__snapshots__/PropSpec.snap.md view
@@ -4,51 +4,46 @@  ``` ./ExampleSpec.hs-    is isomorphic: FAIL-╔══════════════════════════════════════════════════════════════════════════════╗-║ ./ExampleSpec.hs:10:                                                         ║-║ |                                                                            ║-║ |     (read . show) P.=== (+ 1) `shouldSatisfy` P.isoWith (Gen.int $ Range.l ║-║ inear 0 10)                                                                  ║-║ |                               ^^^^^^^^^^^^^^^                              ║-║                                                                              ║-║ Failed after 1 tests.                                                        ║-║ Rerun with --seed=0:0 to reproduce.                                          ║-║                                                                              ║-║ ./ExampleSpec.hs:10:47 ==> 0                                                 ║-║                                                                              ║-║ 0 ≠ 1                                                                        ║-║ where                                                                        ║-║   0 = (read . show) 0                                                        ║-║   1 = (+ 1) 0                                                                ║-╚══════════════════════════════════════════════════════════════════════════════╝-    is not isomorphic: FAIL-╔══════════════════════════════════════════════════════════════════════════════╗-║ ./ExampleSpec.hs:12:                                                         ║-║ |                                                                            ║-║ |     (read . show) P.=== id `shouldNotSatisfy` P.isoWith (Gen.int $ Range.l ║-║ inear 0 10)                                                                  ║-║ |                            ^^^^^^^^^^^^^^^^^^                              ║-║                                                                              ║-║ Failed after 1 tests.                                                        ║-║ Rerun with --seed=0:0 to reproduce.                                          ║-║                                                                              ║-║ ./ExampleSpec.hs:12:47 ==> 0                                                 ║-║                                                                              ║-║ 0 = 0                                                                        ║-║ where                                                                        ║-║   0 = (read . show) 0                                                        ║-║   0 = id 0                                                                   ║-╚══════════════════════════════════════════════════════════════════════════════╝+╭── is isomorphic: FAIL+│ ./ExampleSpec.hs:10:+│ │+│ │     (read . show) P.=== (+ 1) `shouldSatisfy` P.isoWith (Gen.int $ Range.linear 0 10)+│ │                               ^^^^^^^^^^^^^^^+│ +│ Failed after 1 tests.+│ Rerun with --seed=0:0 to reproduce.+│ +│ ./ExampleSpec.hs:10:47 ==> 0+│ +│ 0 ≠ 1+│ where+│   0 = (read . show) 0+│   1 = (+ 1) 0+╰────────────────────────────────────────────────────────────────────────────────────────+╭── is not isomorphic: FAIL+│ ./ExampleSpec.hs:12:+│ │+│ │     (read . show) P.=== id `shouldNotSatisfy` P.isoWith (Gen.int $ Range.linear 0 10)+│ │                            ^^^^^^^^^^^^^^^^^^+│ +│ Failed after 1 tests.+│ Rerun with --seed=0:0 to reproduce.+│ +│ ./ExampleSpec.hs:12:47 ==> 0+│ +│ 0 = 0+│ where+│   0 = (read . show) 0+│   0 = id 0+╰──────────────────────────────────────────────────────────────────────────────────────── ```  ## setDiscardLimit / sets discard limit  ``` ./ExampleSpec.hs-    discards: FAIL-╔══════════════════════════════════════════════════════════════════════════════╗-║ Gave up after 10 discards.                                                   ║-║ Passed 0 tests.                                                              ║-╚══════════════════════════════════════════════════════════════════════════════╝+╭── discards: FAIL+│ Gave up after 10 discards.+│ Passed 0 tests.+╰─────────────────────────────────────────────────────────────────────────────── ```