{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE NumericUnderscores #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}

module Test.Syd.Output.Pretty where

import Control.Arrow (second)
import Data.List (sortOn)
import qualified Data.List as L
import Data.Map (Map)
import qualified Data.Map as M
import Data.Maybe
import Data.Text (Text)
import qualified Data.Text as T
import qualified Data.Text.Lazy.Builder as Text
import GHC.Stack
import Safe
import Test.Syd.OptParse
import Test.Syd.Output.Common
import Test.Syd.Run
import Test.Syd.SpecDef
import Test.Syd.SpecForest
import Text.Colour
import Text.Printf

renderPrettyReport :: Settings -> Timed ResultForest -> Text.Builder
renderPrettyReport :: Settings -> Timed ResultForest -> Builder
renderPrettyReport Settings
settings Timed ResultForest
rf =
  [Builder] -> Builder
forall a. Monoid a => [a] -> a
mconcat ([Builder] -> Builder) -> [Builder] -> Builder
forall a b. (a -> b) -> a -> b
$
    ([Chunk] -> Builder) -> [[Chunk]] -> [Builder]
forall a b. (a -> b) -> [a] -> [b]
map
      (\[Chunk]
line -> TerminalCapabilities -> [Chunk] -> Builder
forall (f :: * -> *).
Foldable f =>
TerminalCapabilities -> f Chunk -> Builder
renderChunksBuilder (Settings -> TerminalCapabilities
settingTerminalCapabilities Settings
settings) [Chunk]
line Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
"\n")
      (Settings -> Timed ResultForest -> [[Chunk]]
outputResultReport Settings
settings Timed ResultForest
rf)

outputResultReport :: Settings -> Timed ResultForest -> [[Chunk]]
outputResultReport :: Settings -> Timed ResultForest -> [[Chunk]]
outputResultReport Settings
settings Timed ResultForest
trf =
  let rf :: ResultForest
rf = Timed ResultForest -> ResultForest
forall a. Timed a -> a
timedValue Timed ResultForest
trf
   in [[[Chunk]]] -> [[Chunk]]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat
        [ [[Chunk]]
outputTestsHeader,
          Settings -> Int -> Int -> ResultForest -> [[Chunk]]
outputSpecForest Settings
settings Int
0 (ResultForest -> Int
forall a. SpecForest a -> Int
resultForestWidth ResultForest
rf) ResultForest
rf,
          [ [Text -> Chunk
chunk Text
""],
            [Text -> Chunk
chunk Text
""]
          ],
          Settings -> Timed ResultForest -> [[Chunk]]
outputPrettySummary Settings
settings Timed ResultForest
trf
        ]

outputPrettySummary :: Settings -> Timed ResultForest -> [[Chunk]]
outputPrettySummary :: Settings -> Timed ResultForest -> [[Chunk]]
outputPrettySummary Settings
settings Timed ResultForest
trf =
  let rf :: ResultForest
rf = Timed ResultForest -> ResultForest
forall a. Timed a -> a
timedValue Timed ResultForest
trf
   in [[[Chunk]]] -> [[Chunk]]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat
        [ Settings -> ResultForest -> [[Chunk]]
outputFailuresWithHeading Settings
settings ResultForest
rf,
          [[Text -> Chunk
chunk Text
""]],
          Timed TestSuiteStats -> [[Chunk]]
outputStats (Settings -> ResultForest -> TestSuiteStats
computeTestSuiteStats Settings
settings (ResultForest -> TestSuiteStats)
-> Timed ResultForest -> Timed TestSuiteStats
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Timed ResultForest
trf),
          [[Text -> Chunk
chunk Text
""]],
          if Settings -> Bool
settingProfile Settings
settings
            then Timed ResultForest -> [[Chunk]]
outputProfilingInfo Timed ResultForest
trf
            else []
        ]

outputFailuresHeader :: [[Chunk]]
outputFailuresHeader :: [[Chunk]]
outputFailuresHeader = Text -> [[Chunk]]
outputHeader Text
"Failures:"

outputFailuresWithHeading :: Settings -> ResultForest -> [[Chunk]]
outputFailuresWithHeading :: Settings -> ResultForest -> [[Chunk]]
outputFailuresWithHeading Settings
settings ResultForest
rf =
  if Settings -> ResultForest -> Bool
anyFailedTests Settings
settings ResultForest
rf
    then
      [[[Chunk]]] -> [[Chunk]]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat
        [ [[Chunk]]
outputFailuresHeader,
          Settings -> ResultForest -> [[Chunk]]
outputFailures Settings
settings ResultForest
rf
        ]
    else []

outputStats :: Timed TestSuiteStats -> [[Chunk]]
outputStats :: Timed TestSuiteStats -> [[Chunk]]
outputStats Timed TestSuiteStats
timed =
  let TestSuiteStats {Word
Word64
testSuiteStatSuccesses :: Word
testSuiteStatExamples :: Word
testSuiteStatFailures :: Word
testSuiteStatFlakyTests :: Word
testSuiteStatPending :: Word
testSuiteStatSumTime :: Word64
testSuiteStatSumTime :: TestSuiteStats -> Word64
testSuiteStatPending :: TestSuiteStats -> Word
testSuiteStatFlakyTests :: TestSuiteStats -> Word
testSuiteStatFailures :: TestSuiteStats -> Word
testSuiteStatExamples :: TestSuiteStats -> Word
testSuiteStatSuccesses :: TestSuiteStats -> Word
..} = Timed TestSuiteStats -> TestSuiteStats
forall a. Timed a -> a
timedValue Timed TestSuiteStats
timed
      sumTimeSeconds :: Double
      sumTimeSeconds :: Double
sumTimeSeconds = Word64 -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word64
testSuiteStatSumTime Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Double
1_000_000_000
      totalTimeSeconds :: Double
      totalTimeSeconds :: Double
totalTimeSeconds = Word64 -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Timed TestSuiteStats -> Word64
forall a. Timed a -> Word64
timedTime Timed TestSuiteStats
timed) Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Double
1_000_000_000
   in ([Chunk] -> [Chunk]) -> [[Chunk]] -> [[Chunk]]
forall a b. (a -> b) -> [a] -> [b]
map (Chunk
padding Chunk -> [Chunk] -> [Chunk]
forall a. a -> [a] -> [a]
:) ([[Chunk]] -> [[Chunk]]) -> [[Chunk]] -> [[Chunk]]
forall a b. (a -> b) -> a -> b
$
        [[[Chunk]]] -> [[Chunk]]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat
          [ [ [ Text -> Chunk
chunk Text
"Examples:                     ",
                Colour -> Chunk -> Chunk
fore Colour
green (Chunk -> Chunk) -> Chunk -> Chunk
forall a b. (a -> b) -> a -> b
$ Text -> Chunk
chunk (String -> Text
T.pack (Word -> String
forall a. Show a => a -> String
show Word
testSuiteStatExamples))
              ]
              | Word
testSuiteStatExamples Word -> Word -> Bool
forall a. Eq a => a -> a -> Bool
/= Word
testSuiteStatSuccesses
            ],
            [ [ Text -> Chunk
chunk Text
"Passed:                       ",
                ( if Word
testSuiteStatSuccesses Word -> Word -> Bool
forall a. Ord a => a -> a -> Bool
<= Word
0
                    then Colour -> Chunk -> Chunk
fore Colour
red
                    else Colour -> Chunk -> Chunk
fore Colour
green
                )
                  (Chunk -> Chunk) -> Chunk -> Chunk
forall a b. (a -> b) -> a -> b
$ Text -> Chunk
chunk (String -> Text
T.pack (Word -> String
forall a. Show a => a -> String
show Word
testSuiteStatSuccesses))
              ],
              [ Text -> Chunk
chunk Text
"Failed:                       ",
                ( if Word
testSuiteStatFailures Word -> Word -> Bool
forall a. Ord a => a -> a -> Bool
> Word
0
                    then Colour -> Chunk -> Chunk
fore Colour
red
                    else Colour -> Chunk -> Chunk
fore Colour
green
                )
                  (Chunk -> Chunk) -> Chunk -> Chunk
forall a b. (a -> b) -> a -> b
$ Text -> Chunk
chunk (String -> Text
T.pack (Word -> String
forall a. Show a => a -> String
show Word
testSuiteStatFailures))
              ]
            ],
            [ [ Text -> Chunk
chunk Text
"Flaky:                        ",
                Colour -> Chunk -> Chunk
fore Colour
red (Chunk -> Chunk) -> Chunk -> Chunk
forall a b. (a -> b) -> a -> b
$ Text -> Chunk
chunk (String -> Text
T.pack (Word -> String
forall a. Show a => a -> String
show Word
testSuiteStatFlakyTests))
              ]
              | Word
testSuiteStatFlakyTests Word -> Word -> Bool
forall a. Ord a => a -> a -> Bool
> Word
0
            ],
            [ [ Text -> Chunk
chunk Text
"Pending:                      ",
                Colour -> Chunk -> Chunk
fore Colour
magenta (Chunk -> Chunk) -> Chunk -> Chunk
forall a b. (a -> b) -> a -> b
$ Text -> Chunk
chunk (String -> Text
T.pack (Word -> String
forall a. Show a => a -> String
show Word
testSuiteStatPending))
              ]
              | Word
testSuiteStatPending Word -> Word -> Bool
forall a. Ord a => a -> a -> Bool
> Word
0
            ],
            [ [ Text -> Chunk
chunk Text
"Sum of test runtimes:",
                Colour -> Chunk -> Chunk
fore Colour
yellow (Chunk -> Chunk) -> Chunk -> Chunk
forall a b. (a -> b) -> a -> b
$ Text -> Chunk
chunk (Text -> Chunk) -> Text -> Chunk
forall a b. (a -> b) -> a -> b
$ String -> Text
T.pack (String -> Double -> String
forall r. PrintfType r => String -> r
printf String
"%13.2f seconds" Double
sumTimeSeconds)
              ],
              [ Text -> Chunk
chunk Text
"Test suite took:     ",
                Colour -> Chunk -> Chunk
fore Colour
yellow (Chunk -> Chunk) -> Chunk -> Chunk
forall a b. (a -> b) -> a -> b
$ Text -> Chunk
chunk (Text -> Chunk) -> Text -> Chunk
forall a b. (a -> b) -> a -> b
$ String -> Text
T.pack (String -> Double -> String
forall r. PrintfType r => String -> r
printf String
"%13.2f seconds" Double
totalTimeSeconds)
              ]
            ]
          ]

outputProfilingInfo :: Timed ResultForest -> [[Chunk]]
outputProfilingInfo :: Timed ResultForest -> [[Chunk]]
outputProfilingInfo Timed {Int
ResultForest
Word64
timedValue :: forall a. Timed a -> a
timedValue :: ResultForest
timedWorker :: Int
timedBegin :: Word64
timedEnd :: Word64
timedEnd :: forall a. Timed a -> Word64
timedBegin :: forall a. Timed a -> Word64
timedWorker :: forall a. Timed a -> Int
..} =
  (([Text], Word64) -> [Chunk]) -> [([Text], Word64)] -> [[Chunk]]
forall a b. (a -> b) -> [a] -> [b]
map
    ( \([Text]
path, Word64
nanos) ->
        [ Word64 -> Chunk
timeChunkFor Word64
nanos,
          Chunk
" ",
          Text -> Chunk
chunk (Text -> Chunk) -> Text -> Chunk
forall a b. (a -> b) -> a -> b
$ Text -> [Text] -> Text
T.intercalate Text
"." [Text]
path
        ]
    )
    ( (([Text], Word64) -> Word64)
-> [([Text], Word64)] -> [([Text], Word64)]
forall b a. Ord b => (a -> b) -> [a] -> [a]
sortOn
        ([Text], Word64) -> Word64
forall a b. (a, b) -> b
snd
        ( (([Text], TDef (Timed TestRunReport)) -> ([Text], Word64))
-> [([Text], TDef (Timed TestRunReport))] -> [([Text], Word64)]
forall a b. (a -> b) -> [a] -> [b]
map
            ((TDef (Timed TestRunReport) -> Word64)
-> ([Text], TDef (Timed TestRunReport)) -> ([Text], Word64)
forall b c d. (b -> c) -> (d, b) -> (d, c)
forall (a :: * -> * -> *) b c d.
Arrow a =>
a b c -> a (d, b) (d, c)
second (Timed TestRunReport -> Word64
forall a. Timed a -> Word64
timedTime (Timed TestRunReport -> Word64)
-> (TDef (Timed TestRunReport) -> Timed TestRunReport)
-> TDef (Timed TestRunReport)
-> Word64
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TDef (Timed TestRunReport) -> Timed TestRunReport
forall value. TDef value -> value
testDefVal))
            (ResultForest -> [([Text], TDef (Timed TestRunReport))]
forall a. SpecForest a -> [([Text], a)]
flattenSpecForest ResultForest
timedValue)
        )
    )

outputTestsHeader :: [[Chunk]]
outputTestsHeader :: [[Chunk]]
outputTestsHeader = Text -> [[Chunk]]
outputHeader Text
"Tests:"

outputHeader :: Text -> [[Chunk]]
outputHeader :: Text -> [[Chunk]]
outputHeader Text
t =
  [ [Colour -> Chunk -> Chunk
fore Colour
blue (Chunk -> Chunk) -> Chunk -> Chunk
forall a b. (a -> b) -> a -> b
$ Text -> Chunk
chunk Text
t],
    [Text -> Chunk
chunk Text
""]
  ]

outputSpecForest :: Settings -> Int -> Int -> ResultForest -> [[Chunk]]
outputSpecForest :: Settings -> Int -> Int -> ResultForest -> [[Chunk]]
outputSpecForest Settings
settings Int
level Int
treeWidth = (SpecTree (TDef (Timed TestRunReport)) -> [[Chunk]])
-> ResultForest -> [[Chunk]]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap (Settings
-> Int -> Int -> SpecTree (TDef (Timed TestRunReport)) -> [[Chunk]]
outputSpecTree Settings
settings Int
level Int
treeWidth)

outputSpecTree :: Settings -> Int -> Int -> ResultTree -> [[Chunk]]
outputSpecTree :: Settings
-> Int -> Int -> SpecTree (TDef (Timed TestRunReport)) -> [[Chunk]]
outputSpecTree Settings
settings Int
level Int
treeWidth = \case
  SpecifyNode Text
t TDef (Timed TestRunReport)
td -> Settings
-> Int -> Int -> Text -> TDef (Timed TestRunReport) -> [[Chunk]]
outputSpecifyLines Settings
settings Int
level Int
treeWidth Text
t TDef (Timed TestRunReport)
td
  PendingNode Text
t Maybe Text
mr -> Text -> Maybe Text -> [[Chunk]]
outputPendingLines Text
t Maybe Text
mr
  DescribeNode Text
t ResultForest
sf -> Text -> [Chunk]
outputDescribeLine Text
t [Chunk] -> [[Chunk]] -> [[Chunk]]
forall a. a -> [a] -> [a]
: ([Chunk] -> [Chunk]) -> [[Chunk]] -> [[Chunk]]
forall a b. (a -> b) -> [a] -> [b]
map (Chunk
padding Chunk -> [Chunk] -> [Chunk]
forall a. a -> [a] -> [a]
:) (Settings -> Int -> Int -> ResultForest -> [[Chunk]]
outputSpecForest Settings
settings (Int
level Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) Int
treeWidth ResultForest
sf)
  SubForestNode ResultForest
sf -> Settings -> Int -> Int -> ResultForest -> [[Chunk]]
outputSpecForest Settings
settings Int
level Int
treeWidth ResultForest
sf

outputDescribeLine :: Text -> [Chunk]
outputDescribeLine :: Text -> [Chunk]
outputDescribeLine Text
t = [Colour -> Chunk -> Chunk
fore Colour
yellow (Chunk -> Chunk) -> Chunk -> Chunk
forall a b. (a -> b) -> a -> b
$ Text -> Chunk
chunk Text
t]

outputSpecifyLines :: Settings -> Int -> Int -> Text -> TDef (Timed TestRunReport) -> [[Chunk]]
outputSpecifyLines :: Settings
-> Int -> Int -> Text -> TDef (Timed TestRunReport) -> [[Chunk]]
outputSpecifyLines Settings
settings Int
level Int
treeWidth Text
specifyText (TDef Timed TestRunReport
timed CallStack
_) =
  let testRunReport :: TestRunReport
testRunReport = Timed TestRunReport -> TestRunReport
forall a. Timed a -> a
timedValue Timed TestRunReport
timed
      executionTime :: Word64
executionTime = Timed TestRunReport -> Word64
forall a. Timed a -> Word64
timedTime Timed TestRunReport
timed
      status :: TestStatus
status = Settings -> TestRunReport -> TestStatus
testRunReportStatus Settings
settings TestRunReport
testRunReport
      TestRunResult {[String]
Maybe String
Maybe Word
Maybe (Map String Int)
Maybe (Map String (Map String Int))
Maybe (Map [String] Int)
Maybe SomeException
Maybe GoldenCase
TestStatus
testRunResultStatus :: TestStatus
testRunResultException :: Maybe SomeException
testRunResultNumTests :: Maybe Word
testRunResultNumShrinks :: Maybe Word
testRunResultFailingInputs :: [String]
testRunResultLabels :: Maybe (Map [String] Int)
testRunResultClasses :: Maybe (Map String Int)
testRunResultTables :: Maybe (Map String (Map String Int))
testRunResultGoldenCase :: Maybe GoldenCase
testRunResultExtraInfo :: Maybe String
testRunResultExtraInfo :: TestRunResult -> Maybe String
testRunResultGoldenCase :: TestRunResult -> Maybe GoldenCase
testRunResultTables :: TestRunResult -> Maybe (Map String (Map String Int))
testRunResultClasses :: TestRunResult -> Maybe (Map String Int)
testRunResultLabels :: TestRunResult -> Maybe (Map [String] Int)
testRunResultFailingInputs :: TestRunResult -> [String]
testRunResultNumShrinks :: TestRunResult -> Maybe Word
testRunResultNumTests :: TestRunResult -> Maybe Word
testRunResultException :: TestRunResult -> Maybe SomeException
testRunResultStatus :: TestRunResult -> TestStatus
..} = TestRunReport -> TestRunResult
testRunReportReportedRun TestRunReport
testRunReport
      withStatusColour :: Chunk -> Chunk
withStatusColour = Colour -> Chunk -> Chunk
fore (TestStatus -> Colour
statusColour TestStatus
status)
      pad :: [Chunk] -> [Chunk]
pad = (Text -> Chunk
chunk (String -> Text
T.pack (Int -> Char -> String
forall a. Int -> a -> [a]
replicate Int
paddingSize Char
' ')) Chunk -> [Chunk] -> [Chunk]
forall a. a -> [a] -> [a]
:)
      timeChunk :: Chunk
timeChunk = Word64 -> Chunk
timeChunkFor Word64
executionTime
   in ([[Chunk]] -> [[Chunk]]) -> [[[Chunk]]] -> [[Chunk]]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap
        (([Chunk] -> Bool) -> [[Chunk]] -> [[Chunk]]
forall a. (a -> Bool) -> [a] -> [a]
filter (Bool -> Bool
not (Bool -> Bool) -> ([Chunk] -> Bool) -> [Chunk] -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Chunk] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null))
        [ [ [ Chunk -> Chunk
withStatusColour (Chunk -> Chunk) -> Chunk -> Chunk
forall a b. (a -> b) -> a -> b
$ Text -> Chunk
chunk (TestStatus -> Text
statusCheckMark TestStatus
status),
              Chunk -> Chunk
withStatusColour (Chunk -> Chunk) -> Chunk -> Chunk
forall a b. (a -> b) -> a -> b
$ Text -> Chunk
chunk Text
specifyText,
              Int -> Text -> Text -> Int -> Chunk
spacingChunk Int
level Text
specifyText (Chunk -> Text
chunkText Chunk
timeChunk) Int
treeWidth,
              Chunk
timeChunk
            ]
          ],
          ([Chunk] -> [Chunk]) -> [[Chunk]] -> [[Chunk]]
forall a b. (a -> b) -> [a] -> [b]
map [Chunk] -> [Chunk]
pad ([[Chunk]] -> [[Chunk]]) -> [[Chunk]] -> [[Chunk]]
forall a b. (a -> b) -> a -> b
$ TestRunReport -> [[Chunk]]
retriesChunks TestRunReport
testRunReport,
          [ [Chunk] -> [Chunk]
pad
              [ Text -> Chunk
chunk Text
"passed for all of ",
                case Word
w of
                  Word
0 -> Colour -> Chunk -> Chunk
fore Colour
red (Chunk -> Chunk) -> Chunk -> Chunk
forall a b. (a -> b) -> a -> b
$ Text -> Chunk
chunk Text
"0"
                  Word
_ -> Colour -> Chunk -> Chunk
fore Colour
green (Chunk -> Chunk) -> Chunk -> Chunk
forall a b. (a -> b) -> a -> b
$ Text -> Chunk
chunk (String -> Text
T.pack (String -> Word -> String
forall r. PrintfType r => String -> r
printf String
"%d" Word
w)),
                Chunk
" inputs."
              ]
            | TestStatus
status TestStatus -> TestStatus -> Bool
forall a. Eq a => a -> a -> Bool
== TestStatus
TestPassed,
              Word
w <- Maybe Word -> [Word]
forall a. Maybe a -> [a]
maybeToList Maybe Word
testRunResultNumTests
          ],
          ([Chunk] -> [Chunk]) -> [[Chunk]] -> [[Chunk]]
forall a b. (a -> b) -> [a] -> [b]
map [Chunk] -> [Chunk]
pad ([[Chunk]] -> [[Chunk]]) -> [[Chunk]] -> [[Chunk]]
forall a b. (a -> b) -> a -> b
$ Word -> Maybe (Map [String] Int) -> [[Chunk]]
labelsChunks (Word -> Maybe Word -> Word
forall a. a -> Maybe a -> a
fromMaybe Word
1 Maybe Word
testRunResultNumTests) Maybe (Map [String] Int)
testRunResultLabels,
          ([Chunk] -> [Chunk]) -> [[Chunk]] -> [[Chunk]]
forall a b. (a -> b) -> [a] -> [b]
map [Chunk] -> [Chunk]
pad ([[Chunk]] -> [[Chunk]]) -> [[Chunk]] -> [[Chunk]]
forall a b. (a -> b) -> a -> b
$ Maybe (Map String Int) -> [[Chunk]]
classesChunks Maybe (Map String Int)
testRunResultClasses,
          ([Chunk] -> [Chunk]) -> [[Chunk]] -> [[Chunk]]
forall a b. (a -> b) -> [a] -> [b]
map [Chunk] -> [Chunk]
pad ([[Chunk]] -> [[Chunk]]) -> [[Chunk]] -> [[Chunk]]
forall a b. (a -> b) -> a -> b
$ Maybe (Map String (Map String Int)) -> [[Chunk]]
tablesChunks Maybe (Map String (Map String Int))
testRunResultTables,
          [[Chunk] -> [Chunk]
pad ([Chunk] -> [Chunk]) -> [Chunk] -> [Chunk]
forall a b. (a -> b) -> a -> b
$ GoldenCase -> [Chunk]
outputGoldenCase GoldenCase
gc | GoldenCase
gc <- Maybe GoldenCase -> [GoldenCase]
forall a. Maybe a -> [a]
maybeToList Maybe GoldenCase
testRunResultGoldenCase]
        ]

exampleNrChunk :: Word -> Word -> Chunk
exampleNrChunk :: Word -> Word -> Chunk
exampleNrChunk Word
total Word
current =
  let digits :: Word
      digits :: Word
digits = Word -> Word -> Word
forall a. Ord a => a -> a -> a
max Word
2 (Word -> Word) -> Word -> Word
forall a b. (a -> b) -> a -> b
$ Word -> Word
forall a. Enum a => a -> a
succ (Word -> Word) -> Word -> Word
forall a b. (a -> b) -> a -> b
$ Double -> Word
forall b. Integral b => Double -> b
forall a b. (RealFrac a, Integral b) => a -> b
floor (Double -> Word) -> Double -> Word
forall a b. (a -> b) -> a -> b
$ Double -> Double -> Double
forall a. Floating a => a -> a -> a
logBase Double
10 (Double -> Double) -> Double -> Double
forall a b. (a -> b) -> a -> b
$ (Word -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral :: Word -> Double) Word
total
      formatStr :: String
formatStr = String
"%" String -> String -> String
forall a. Semigroup a => a -> a -> a
<> Word -> String
forall a. Show a => a -> String
show Word
digits String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
"d"
   in Text -> Chunk
chunk (Text -> Chunk) -> Text -> Chunk
forall a b. (a -> b) -> a -> b
$ String -> Text
T.pack (String -> Text) -> String -> Text
forall a b. (a -> b) -> a -> b
$ String -> Word -> String
forall r. PrintfType r => String -> r
printf String
formatStr Word
current

retriesChunks :: TestRunReport -> [[Chunk]]
retriesChunks :: TestRunReport -> [[Chunk]]
retriesChunks TestRunReport
testRunReport =
  case TestRunReport -> Maybe Word
testRunReportRetries TestRunReport
testRunReport of
    Maybe Word
Nothing -> []
    Just Word
retries ->
      let flaky :: Bool
flaky = TestRunReport -> Bool
testRunReportWasFlaky TestRunReport
testRunReport
          mMessage :: Maybe String
mMessage = case TestRunReport -> FlakinessMode
testRunReportFlakinessMode TestRunReport
testRunReport of
            MayBeFlaky Maybe String
mmesg -> Maybe String
mmesg
            FlakinessMode
MayNotBeFlaky -> Maybe String
forall a. Maybe a
Nothing
       in if Bool
flaky
            then
              [[[Chunk]]] -> [[Chunk]]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat
                [ [[Chunk
"Retries: ", Text -> Chunk
chunk (String -> Text
T.pack (Word -> String
forall a. Show a => a -> String
show Word
retries)), Colour -> Chunk -> Chunk
fore Colour
red Chunk
" !!! FLAKY !!!"]],
                  [[Colour -> Chunk -> Chunk
fore Colour
magenta (Chunk -> Chunk) -> Chunk -> Chunk
forall a b. (a -> b) -> a -> b
$ Text -> Chunk
chunk (Text -> Chunk) -> Text -> Chunk
forall a b. (a -> b) -> a -> b
$ String -> Text
T.pack String
message] | String
message <- Maybe String -> [String]
forall a. Maybe a -> [a]
maybeToList Maybe String
mMessage]
                ]
            else [[Chunk
"Retries: ", Text -> Chunk
chunk (String -> Text
T.pack (Word -> String
forall a. Show a => a -> String
show Word
retries)), Chunk
" (does not look flaky)"]]

labelsChunks :: Word -> Maybe (Map [String] Int) -> [[Chunk]]
labelsChunks :: Word -> Maybe (Map [String] Int) -> [[Chunk]]
labelsChunks Word
_ Maybe (Map [String] Int)
Nothing = []
labelsChunks Word
totalCount (Just Map [String] Int
labels)
  | Map [String] Int -> Bool
forall k a. Map k a -> Bool
M.null Map [String] Int
labels = []
  | (([String], Int) -> [String]) -> [([String], Int)] -> [[String]]
forall a b. (a -> b) -> [a] -> [b]
map ([String], Int) -> [String]
forall a b. (a, b) -> a
fst (Map [String] Int -> [([String], Int)]
forall k a. Map k a -> [(k, a)]
M.toList Map [String] Int
labels) [[String]] -> [[String]] -> Bool
forall a. Eq a => a -> a -> Bool
== [[]] = []
  | Bool
otherwise =
      [Text -> Chunk
chunk Text
"Labels"]
        [Chunk] -> [[Chunk]] -> [[Chunk]]
forall a. a -> [a] -> [a]
: (([String], Int) -> [Chunk]) -> [([String], Int)] -> [[Chunk]]
forall a b. (a -> b) -> [a] -> [b]
map
          ( [Chunk] -> [Chunk]
pad
              ([Chunk] -> [Chunk])
-> (([String], Int) -> [Chunk]) -> ([String], Int) -> [Chunk]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ( \([String]
ss, Int
i) ->
                    [ Text -> Chunk
chunk
                        ( String -> Text
T.pack
                            ( String -> Double -> String -> String
forall r. PrintfType r => String -> r
printf
                                String
"%5.2f%% %s"
                                (Double
100 Double -> Double -> Double
forall a. Num a => a -> a -> a
* Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
i Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Word -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word
totalCount :: Double)
                                ([String] -> String
commaList ((String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map String -> String
forall a. Show a => a -> String
show [String]
ss))
                            )
                        )
                    ]
                )
          )
          (Map [String] Int -> [([String], Int)]
forall k a. Map k a -> [(k, a)]
M.toList Map [String] Int
labels)
  where
    pad :: [Chunk] -> [Chunk]
pad = (Text -> Chunk
chunk (String -> Text
T.pack (Int -> Char -> String
forall a. Int -> a -> [a]
replicate Int
paddingSize Char
' ')) Chunk -> [Chunk] -> [Chunk]
forall a. a -> [a] -> [a]
:)

classesChunks :: Maybe (Map String Int) -> [[Chunk]]
classesChunks :: Maybe (Map String Int) -> [[Chunk]]
classesChunks Maybe (Map String Int)
Nothing = []
classesChunks (Just Map String Int
classes)
  | Map String Int -> Bool
forall k a. Map k a -> Bool
M.null Map String Int
classes = []
  | Bool
otherwise =
      [Text -> Chunk
chunk Text
"Classes"]
        [Chunk] -> [[Chunk]] -> [[Chunk]]
forall a. a -> [a] -> [a]
: ((String, Int) -> [Chunk]) -> [(String, Int)] -> [[Chunk]]
forall a b. (a -> b) -> [a] -> [b]
map
          ( [Chunk] -> [Chunk]
pad
              ([Chunk] -> [Chunk])
-> ((String, Int) -> [Chunk]) -> (String, Int) -> [Chunk]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ( \(String
s, Int
i) ->
                    [ Text -> Chunk
chunk
                        ( String -> Text
T.pack
                            ( String -> Double -> String -> String
forall r. PrintfType r => String -> r
printf String
"%5.2f%% %s" (Double
100 Double -> Double -> Double
forall a. Num a => a -> a -> a
* Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
i Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
total :: Double) String
s
                            )
                        )
                    ]
                )
          )
          (Map String Int -> [(String, Int)]
forall k a. Map k a -> [(k, a)]
M.toList Map String Int
classes)
  where
    pad :: [Chunk] -> [Chunk]
pad = (Text -> Chunk
chunk (String -> Text
T.pack (Int -> Char -> String
forall a. Int -> a -> [a]
replicate Int
paddingSize Char
' ')) Chunk -> [Chunk] -> [Chunk]
forall a. a -> [a] -> [a]
:)
    total :: Int
total = [Int] -> Int
forall a. Num a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum ([Int] -> Int) -> [Int] -> Int
forall a b. (a -> b) -> a -> b
$ ((String, Int) -> Int) -> [(String, Int)] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map (String, Int) -> Int
forall a b. (a, b) -> b
snd ([(String, Int)] -> [Int]) -> [(String, Int)] -> [Int]
forall a b. (a -> b) -> a -> b
$ Map String Int -> [(String, Int)]
forall k a. Map k a -> [(k, a)]
M.toList Map String Int
classes

tablesChunks :: Maybe (Map String (Map String Int)) -> [[Chunk]]
tablesChunks :: Maybe (Map String (Map String Int)) -> [[Chunk]]
tablesChunks Maybe (Map String (Map String Int))
Nothing = []
tablesChunks (Just Map String (Map String Int)
tables) = ((String, Map String Int) -> [[Chunk]])
-> [(String, Map String Int)] -> [[Chunk]]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap ((String -> Map String Int -> [[Chunk]])
-> (String, Map String Int) -> [[Chunk]]
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry String -> Map String Int -> [[Chunk]]
goTable) ([(String, Map String Int)] -> [[Chunk]])
-> [(String, Map String Int)] -> [[Chunk]]
forall a b. (a -> b) -> a -> b
$ Map String (Map String Int) -> [(String, Map String Int)]
forall k a. Map k a -> [(k, a)]
M.toList Map String (Map String Int)
tables
  where
    goTable :: String -> Map String Int -> [[Chunk]]
    goTable :: String -> Map String Int -> [[Chunk]]
goTable String
tableName Map String Int
percentages =
      [Text -> Chunk
chunk Text
" "]
        [Chunk] -> [[Chunk]] -> [[Chunk]]
forall a. a -> [a] -> [a]
: [Text -> Chunk
chunk (String -> Text
T.pack String
tableName)]
        [Chunk] -> [[Chunk]] -> [[Chunk]]
forall a. a -> [a] -> [a]
: ((String, Int) -> [Chunk]) -> [(String, Int)] -> [[Chunk]]
forall a b. (a -> b) -> [a] -> [b]
map
          ( [Chunk] -> [Chunk]
pad
              ([Chunk] -> [Chunk])
-> ((String, Int) -> [Chunk]) -> (String, Int) -> [Chunk]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ( \(String
s, Int
i) ->
                    [ Text -> Chunk
chunk
                        ( String -> Text
T.pack
                            ( String -> Double -> String -> String
forall r. PrintfType r => String -> r
printf String
"%5.2f%% %s" (Double
100 Double -> Double -> Double
forall a. Num a => a -> a -> a
* Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
i Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
total :: Double) String
s
                            )
                        )
                    ]
                )
          )
          (Map String Int -> [(String, Int)]
forall k a. Map k a -> [(k, a)]
M.toList Map String Int
percentages)
      where
        pad :: [Chunk] -> [Chunk]
pad = (Text -> Chunk
chunk (String -> Text
T.pack (Int -> Char -> String
forall a. Int -> a -> [a]
replicate Int
paddingSize Char
' ')) Chunk -> [Chunk] -> [Chunk]
forall a. a -> [a] -> [a]
:)
        total :: Int
total = [Int] -> Int
forall a. Num a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum ([Int] -> Int) -> [Int] -> Int
forall a b. (a -> b) -> a -> b
$ ((String, Int) -> Int) -> [(String, Int)] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map (String, Int) -> Int
forall a b. (a, b) -> b
snd ([(String, Int)] -> [Int]) -> [(String, Int)] -> [Int]
forall a b. (a -> b) -> a -> b
$ Map String Int -> [(String, Int)]
forall k a. Map k a -> [(k, a)]
M.toList Map String Int
percentages

outputPendingLines :: Text -> Maybe Text -> [[Chunk]]
outputPendingLines :: Text -> Maybe Text -> [[Chunk]]
outputPendingLines Text
specifyText Maybe Text
mReason =
  ([Chunk] -> Bool) -> [[Chunk]] -> [[Chunk]]
forall a. (a -> Bool) -> [a] -> [a]
filter
    (Bool -> Bool
not (Bool -> Bool) -> ([Chunk] -> Bool) -> [Chunk] -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Chunk] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null)
    [ [Colour -> Chunk -> Chunk
fore Colour
magenta (Chunk -> Chunk) -> Chunk -> Chunk
forall a b. (a -> b) -> a -> b
$ Text -> Chunk
chunk Text
specifyText],
      case Maybe Text
mReason of
        Maybe Text
Nothing -> []
        Just Text
reason -> [Chunk
padding, Text -> Chunk
chunk Text
reason]
    ]

outputFailureLabels :: Maybe (Map [String] Int) -> [[Chunk]]
outputFailureLabels :: Maybe (Map [String] Int) -> [[Chunk]]
outputFailureLabels Maybe (Map [String] Int)
Nothing = []
outputFailureLabels (Just Map [String] Int
labels)
  | Map [String] Int
labels Map [String] Int -> Map [String] Int -> Bool
forall a. Eq a => a -> a -> Bool
== [String] -> Int -> Map [String] Int
forall k a. k -> a -> Map k a
M.singleton [] Int
1 = []
  | Bool
otherwise = [[Chunk
"Labels: ", Text -> Chunk
chunk (String -> Text
T.pack ([String] -> String
commaList ((String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map String -> String
forall a. Show a => a -> String
show ([[String]] -> [String]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat ([[String]] -> [String]) -> [[String]] -> [String]
forall a b. (a -> b) -> a -> b
$ Map [String] Int -> [[String]]
forall k a. Map k a -> [k]
M.keys Map [String] Int
labels))))]]

outputFailureClasses :: Maybe (Map String Int) -> [[Chunk]]
outputFailureClasses :: Maybe (Map String Int) -> [[Chunk]]
outputFailureClasses Maybe (Map String Int)
Nothing = []
outputFailureClasses (Just Map String Int
classes)
  | Map String Int -> Bool
forall k a. Map k a -> Bool
M.null Map String Int
classes = []
  | Bool
otherwise = [[Chunk
"Class: ", Text -> Chunk
chunk (String -> Text
T.pack ([String] -> String
commaList (Map String Int -> [String]
forall k a. Map k a -> [k]
M.keys Map String Int
classes)))]]

outputGoldenCase :: GoldenCase -> [Chunk]
outputGoldenCase :: GoldenCase -> [Chunk]
outputGoldenCase = \case
  GoldenCase
GoldenNotFound -> [Colour -> Chunk -> Chunk
fore Colour
red (Chunk -> Chunk) -> Chunk -> Chunk
forall a b. (a -> b) -> a -> b
$ Text -> Chunk
chunk Text
"Golden output not found"]
  GoldenCase
GoldenStarted -> [Colour -> Chunk -> Chunk
fore Colour
cyan (Chunk -> Chunk) -> Chunk -> Chunk
forall a b. (a -> b) -> a -> b
$ Text -> Chunk
chunk Text
"Golden output created"]
  GoldenCase
GoldenReset -> [Colour -> Chunk -> Chunk
fore Colour
cyan (Chunk -> Chunk) -> Chunk -> Chunk
forall a b. (a -> b) -> a -> b
$ Text -> Chunk
chunk Text
"Golden output reset"]

-- The chunk for spacing between the description and the timing
--
-- initial padding | checkmark | description | THIS CHUNK | execution time
spacingChunk :: Int -> Text -> Text -> Int -> Chunk
spacingChunk :: Int -> Text -> Text -> Int -> Chunk
spacingChunk Int
level Text
descriptionText Text
executionTimeText Int
treeWidth = Text -> Chunk
chunk (Text -> Chunk) -> Text -> Chunk
forall a b. (a -> b) -> a -> b
$ String -> Text
T.pack (String -> Text) -> String -> Text
forall a b. (a -> b) -> a -> b
$ Int -> Char -> String
forall a. Int -> a -> [a]
replicate Int
paddingWidth Char
' '
  where
    paddingWidth :: Int
paddingWidth =
      let preferredMaxWidth :: Int
preferredMaxWidth = Int
80
          checkmarkWidth :: Int
checkmarkWidth = Int
2
          minimumSpacing :: Int
minimumSpacing = Int
1
          actualDescriptionWidth :: Int
actualDescriptionWidth = Text -> Int
T.length Text
descriptionText
          actualTimingWidth :: Int
actualTimingWidth = Text -> Int
T.length Text
executionTimeText
          totalNecessaryWidth :: Int
totalNecessaryWidth = Int
treeWidth Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
checkmarkWidth Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
minimumSpacing Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
actualTimingWidth -- All timings are the same width
          actualMaxWidth :: Int
actualMaxWidth = Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
totalNecessaryWidth Int
preferredMaxWidth
       in Int
actualMaxWidth Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
paddingSize Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
level Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
actualTimingWidth Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
actualDescriptionWidth

outputFailures :: Settings -> ResultForest -> [[Chunk]]
outputFailures :: Settings -> ResultForest -> [[Chunk]]
outputFailures Settings
settings ResultForest
rf =
  let failures :: [([Text], TDef (Timed TestRunReport))]
failures = (([Text], TDef (Timed TestRunReport)) -> Bool)
-> [([Text], TDef (Timed TestRunReport))]
-> [([Text], TDef (Timed TestRunReport))]
forall a. (a -> Bool) -> [a] -> [a]
filter (Settings -> TestRunReport -> Bool
testRunReportFailed Settings
settings (TestRunReport -> Bool)
-> (([Text], TDef (Timed TestRunReport)) -> TestRunReport)
-> ([Text], TDef (Timed TestRunReport))
-> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Timed TestRunReport -> TestRunReport
forall a. Timed a -> a
timedValue (Timed TestRunReport -> TestRunReport)
-> (([Text], TDef (Timed TestRunReport)) -> Timed TestRunReport)
-> ([Text], TDef (Timed TestRunReport))
-> TestRunReport
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TDef (Timed TestRunReport) -> Timed TestRunReport
forall value. TDef value -> value
testDefVal (TDef (Timed TestRunReport) -> Timed TestRunReport)
-> (([Text], TDef (Timed TestRunReport))
    -> TDef (Timed TestRunReport))
-> ([Text], TDef (Timed TestRunReport))
-> Timed TestRunReport
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([Text], TDef (Timed TestRunReport)) -> TDef (Timed TestRunReport)
forall a b. (a, b) -> b
snd) ([([Text], TDef (Timed TestRunReport))]
 -> [([Text], TDef (Timed TestRunReport))])
-> [([Text], TDef (Timed TestRunReport))]
-> [([Text], TDef (Timed TestRunReport))]
forall a b. (a -> b) -> a -> b
$ ResultForest -> [([Text], TDef (Timed TestRunReport))]
forall a. SpecForest a -> [([Text], a)]
flattenSpecForest ResultForest
rf
      nbDigitsInFailureCount :: Int
      nbDigitsInFailureCount :: Int
nbDigitsInFailureCount = Double -> Int
forall b. Integral b => Double -> b
forall a b. (RealFrac a, Integral b) => a -> b
floor (Double -> Double -> Double
forall a. Floating a => a -> a -> a
logBase Double
10 ([([Text], TDef (Timed TestRunReport))] -> Double
forall i a. Num i => [a] -> i
L.genericLength [([Text], TDef (Timed TestRunReport))]
failures) :: Double)
      padFailureDetails :: [Chunk] -> [Chunk]
padFailureDetails = (Text -> Chunk
chunk (String -> Text
T.pack (Int -> Char -> String
forall a. Int -> a -> [a]
replicate (Int
nbDigitsInFailureCount Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
4) Char
' ')) Chunk -> [Chunk] -> [Chunk]
forall a. a -> [a] -> [a]
:)
   in ([Chunk] -> [Chunk]) -> [[Chunk]] -> [[Chunk]]
forall a b. (a -> b) -> [a] -> [b]
map (Chunk
padding Chunk -> [Chunk] -> [Chunk]
forall a. a -> [a] -> [a]
:) ([[Chunk]] -> [[Chunk]]) -> [[Chunk]] -> [[Chunk]]
forall a b. (a -> b) -> a -> b
$
        ([[Chunk]] -> [[Chunk]]) -> [[[Chunk]]] -> [[Chunk]]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap (([Chunk] -> Bool) -> [[Chunk]] -> [[Chunk]]
forall a. (a -> Bool) -> [a] -> [a]
filter (Bool -> Bool
not (Bool -> Bool) -> ([Chunk] -> Bool) -> [Chunk] -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Chunk] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null)) ([[[Chunk]]] -> [[Chunk]]) -> [[[Chunk]]] -> [[Chunk]]
forall a b. (a -> b) -> a -> b
$
          [([Text], TDef (Timed TestRunReport))]
-> (Word -> ([Text], TDef (Timed TestRunReport)) -> [[Chunk]])
-> [[[Chunk]]]
forall a b. [a] -> (Word -> a -> b) -> [b]
indexed [([Text], TDef (Timed TestRunReport))]
failures ((Word -> ([Text], TDef (Timed TestRunReport)) -> [[Chunk]])
 -> [[[Chunk]]])
-> (Word -> ([Text], TDef (Timed TestRunReport)) -> [[Chunk]])
-> [[[Chunk]]]
forall a b. (a -> b) -> a -> b
$ \Word
w ([Text]
ts, TDef Timed TestRunReport
timed CallStack
cs) ->
            let testRunReport :: TestRunReport
testRunReport = Timed TestRunReport -> TestRunReport
forall a. Timed a -> a
timedValue Timed TestRunReport
timed
                status :: TestStatus
status = Settings -> TestRunReport -> TestStatus
testRunReportStatus Settings
settings TestRunReport
testRunReport
                TestRunResult {[String]
Maybe String
Maybe Word
Maybe (Map String Int)
Maybe (Map String (Map String Int))
Maybe (Map [String] Int)
Maybe SomeException
Maybe GoldenCase
TestStatus
testRunResultExtraInfo :: TestRunResult -> Maybe String
testRunResultGoldenCase :: TestRunResult -> Maybe GoldenCase
testRunResultTables :: TestRunResult -> Maybe (Map String (Map String Int))
testRunResultClasses :: TestRunResult -> Maybe (Map String Int)
testRunResultLabels :: TestRunResult -> Maybe (Map [String] Int)
testRunResultFailingInputs :: TestRunResult -> [String]
testRunResultNumShrinks :: TestRunResult -> Maybe Word
testRunResultNumTests :: TestRunResult -> Maybe Word
testRunResultException :: TestRunResult -> Maybe SomeException
testRunResultStatus :: TestRunResult -> TestStatus
testRunResultStatus :: TestStatus
testRunResultException :: Maybe SomeException
testRunResultNumTests :: Maybe Word
testRunResultNumShrinks :: Maybe Word
testRunResultFailingInputs :: [String]
testRunResultLabels :: Maybe (Map [String] Int)
testRunResultClasses :: Maybe (Map String Int)
testRunResultTables :: Maybe (Map String (Map String Int))
testRunResultGoldenCase :: Maybe GoldenCase
testRunResultExtraInfo :: Maybe String
..} = TestRunReport -> TestRunResult
testRunReportReportedRun TestRunReport
testRunReport
             in [[[Chunk]]] -> [[Chunk]]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat
                  [ [ [ Colour -> Chunk -> Chunk
fore Colour
cyan (Chunk -> Chunk) -> Chunk -> Chunk
forall a b. (a -> b) -> a -> b
$
                          Text -> Chunk
chunk (Text -> Chunk) -> Text -> Chunk
forall a b. (a -> b) -> a -> b
$
                            String -> Text
T.pack (String -> Text) -> String -> Text
forall a b. (a -> b) -> a -> b
$
                              Int -> Char -> String
forall a. Int -> a -> [a]
replicate Int
2 Char
' '
                                String -> String -> String
forall a. [a] -> [a] -> [a]
++ case [(String, SrcLoc)] -> Maybe (String, SrcLoc)
forall a. [a] -> Maybe a
headMay ([(String, SrcLoc)] -> Maybe (String, SrcLoc))
-> [(String, SrcLoc)] -> Maybe (String, SrcLoc)
forall a b. (a -> b) -> a -> b
$ CallStack -> [(String, SrcLoc)]
getCallStack CallStack
cs of
                                  Maybe (String, SrcLoc)
Nothing -> String
"Unknown location"
                                  Just (String
_, SrcLoc {Int
String
srcLocPackage :: String
srcLocModule :: String
srcLocFile :: String
srcLocStartLine :: Int
srcLocStartCol :: Int
srcLocEndLine :: Int
srcLocEndCol :: Int
srcLocEndCol :: SrcLoc -> Int
srcLocEndLine :: SrcLoc -> Int
srcLocStartCol :: SrcLoc -> Int
srcLocStartLine :: SrcLoc -> Int
srcLocFile :: SrcLoc -> String
srcLocModule :: SrcLoc -> String
srcLocPackage :: SrcLoc -> String
..}) ->
                                    [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat
                                      [ String
srcLocFile,
                                        String
":",
                                        Int -> String
forall a. Show a => a -> String
show Int
srcLocStartLine
                                      ]
                      ],
                      (Chunk -> Chunk) -> [Chunk] -> [Chunk]
forall a b. (a -> b) -> [a] -> [b]
map
                        (Colour -> Chunk -> Chunk
fore (TestStatus -> Colour
statusColour TestStatus
status))
                        [ Text -> Chunk
chunk (Text -> Chunk) -> Text -> Chunk
forall a b. (a -> b) -> a -> b
$ TestStatus -> Text
statusCheckMark TestStatus
status,
                          Text -> Chunk
chunk (Text -> Chunk) -> Text -> Chunk
forall a b. (a -> b) -> a -> b
$ String -> Text
T.pack (String -> Word -> String
forall r. PrintfType r => String -> r
printf (String
"%" String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
nbDigitsInFailureCount String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"d ") Word
w),
                          Text -> Chunk
chunk (Text -> Chunk) -> Text -> Chunk
forall a b. (a -> b) -> a -> b
$ Text -> [Text] -> Text
T.intercalate Text
"." [Text]
ts
                        ]
                    ],
                    ([Chunk] -> [Chunk]) -> [[Chunk]] -> [[Chunk]]
forall a b. (a -> b) -> [a] -> [b]
map [Chunk] -> [Chunk]
padFailureDetails ([[Chunk]] -> [[Chunk]]) -> [[Chunk]] -> [[Chunk]]
forall a b. (a -> b) -> a -> b
$ TestRunReport -> [[Chunk]]
retriesChunks TestRunReport
testRunReport,
                    (String -> [Chunk]) -> [String] -> [[Chunk]]
forall a b. (a -> b) -> [a] -> [b]
map ([Chunk] -> [Chunk]
padFailureDetails ([Chunk] -> [Chunk]) -> (String -> [Chunk]) -> String -> [Chunk]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Chunk -> [Chunk] -> [Chunk]
forall a. a -> [a] -> [a]
: []) (Chunk -> [Chunk]) -> (String -> Chunk) -> String -> [Chunk]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Chunk
chunk (Text -> Chunk) -> (String -> Text) -> String -> Chunk
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
T.pack) ([String] -> [[Chunk]]) -> [String] -> [[Chunk]]
forall a b. (a -> b) -> a -> b
$
                      case (Maybe Word
testRunResultNumTests, Maybe Word
testRunResultNumShrinks) of
                        (Maybe Word
Nothing, Maybe Word
_) -> []
                        (Just Word
numTests, Maybe Word
Nothing) -> [String -> Word -> String
forall r. PrintfType r => String -> r
printf String
"Failed after %d tests" Word
numTests]
                        (Just Word
numTests, Just Word
0) -> [String -> Word -> String
forall r. PrintfType r => String -> r
printf String
"Failed after %d tests" Word
numTests]
                        (Just Word
numTests, Just Word
numShrinks) -> [String -> Word -> Word -> String
forall r. PrintfType r => String -> r
printf String
"Failed after %d tests and %d shrinks" Word
numTests Word
numShrinks],
                    (String -> [Chunk]) -> [String] -> [[Chunk]]
forall a b. (a -> b) -> [a] -> [b]
map ([Chunk] -> [Chunk]
padFailureDetails ([Chunk] -> [Chunk]) -> (String -> [Chunk]) -> String -> [Chunk]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (\Chunk
c -> [Text -> Chunk
chunk Text
"Generated: ", Chunk
c]) (Chunk -> [Chunk]) -> (String -> Chunk) -> String -> [Chunk]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Colour -> Chunk -> Chunk
fore Colour
yellow (Chunk -> Chunk) -> (String -> Chunk) -> String -> Chunk
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Chunk
chunk (Text -> Chunk) -> (String -> Text) -> String -> Chunk
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
T.pack) [String]
testRunResultFailingInputs,
                    ([Chunk] -> [Chunk]) -> [[Chunk]] -> [[Chunk]]
forall a b. (a -> b) -> [a] -> [b]
map [Chunk] -> [Chunk]
padFailureDetails ([[Chunk]] -> [[Chunk]]) -> [[Chunk]] -> [[Chunk]]
forall a b. (a -> b) -> a -> b
$ Maybe (Map [String] Int) -> [[Chunk]]
outputFailureLabels Maybe (Map [String] Int)
testRunResultLabels,
                    ([Chunk] -> [Chunk]) -> [[Chunk]] -> [[Chunk]]
forall a b. (a -> b) -> [a] -> [b]
map [Chunk] -> [Chunk]
padFailureDetails ([[Chunk]] -> [[Chunk]]) -> [[Chunk]] -> [[Chunk]]
forall a b. (a -> b) -> a -> b
$ Maybe (Map String Int) -> [[Chunk]]
outputFailureClasses Maybe (Map String Int)
testRunResultClasses,
                    ([Chunk] -> [Chunk]) -> [[Chunk]] -> [[Chunk]]
forall a b. (a -> b) -> [a] -> [b]
map [Chunk] -> [Chunk]
padFailureDetails ([[Chunk]] -> [[Chunk]]) -> [[Chunk]] -> [[Chunk]]
forall a b. (a -> b) -> a -> b
$ [[Chunk]]
-> (SomeException -> [[Chunk]]) -> Maybe SomeException -> [[Chunk]]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe [] SomeException -> [[Chunk]]
outputSomeException Maybe SomeException
testRunResultException,
                    [[Chunk] -> [Chunk]
padFailureDetails ([Chunk] -> [Chunk]) -> [Chunk] -> [Chunk]
forall a b. (a -> b) -> a -> b
$ GoldenCase -> [Chunk]
outputGoldenCase GoldenCase
gc | GoldenCase
gc <- Maybe GoldenCase -> [GoldenCase]
forall a. Maybe a -> [a]
maybeToList Maybe GoldenCase
testRunResultGoldenCase],
                    [[[Chunk]]] -> [[Chunk]]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [([Chunk] -> [Chunk]) -> [[Chunk]] -> [[Chunk]]
forall a b. (a -> b) -> [a] -> [b]
map [Chunk] -> [Chunk]
padFailureDetails ([[Chunk]] -> [[Chunk]]) -> [[Chunk]] -> [[Chunk]]
forall a b. (a -> b) -> a -> b
$ String -> [[Chunk]]
stringChunks String
ei | String
ei <- Maybe String -> [String]
forall a. Maybe a -> [a]
maybeToList Maybe String
testRunResultExtraInfo],
                    [[Text -> Chunk
chunk Text
""]]
                  ]