packages feed

nri-prelude-0.3.1.0: src/Test/Reporter/Logfile.hs

module Test.Reporter.Logfile
  ( report,
  )
where

import qualified Data.Text
import qualified Dict
import qualified GHC.Stack as Stack
import qualified List
import qualified Maybe
import NriPrelude
import qualified Platform.Internal as Platform
import qualified System.Directory as Directory
import qualified System.FilePath as FilePath
import qualified Test.Internal as Internal
import qualified Tuple
import qualified Prelude

report ::
  Stack.HasCallStack =>
  (Platform.TracingSpan -> Prelude.IO ()) ->
  Internal.SuiteResult ->
  Prelude.IO ()
report writeSpan results = do
  projectDir <- map FilePath.takeBaseName Directory.getCurrentDirectory
  let testSpans = spans results
  let maybeFrame =
        Stack.callStack
          |> Stack.getCallStack
          |> List.head
          |> map (Tuple.mapFirst Data.Text.pack)
  let rootSpan =
        Platform.TracingSpan
          { Platform.name = "test run",
            Platform.started =
              List.minimum (List.map Platform.started testSpans)
                |> Maybe.withDefault (Platform.MonotonicTime 0),
            Platform.finished =
              List.maximum (List.map Platform.finished testSpans)
                |> Maybe.withDefault (Platform.MonotonicTime 0),
            Platform.frame = maybeFrame,
            Platform.details = Nothing,
            Platform.summary = Just (Data.Text.pack projectDir),
            Platform.succeeded = case results of
              Internal.AllPassed _ -> Platform.Succeeded
              _ -> Platform.Failed,
            Platform.allocated = 0,
            Platform.children = testSpans
          }
  writeSpan rootSpan

spans :: Internal.SuiteResult -> [Platform.TracingSpan]
spans results =
  spansAndNamespaces results
    |> groupIntoNamespaces

spansAndNamespaces :: Internal.SuiteResult -> [([Text], Platform.TracingSpan)]
spansAndNamespaces results =
  case results of
    Internal.AllPassed tests -> List.map bodyAndDescribes tests
    Internal.OnlysPassed tests _ -> List.map bodyAndDescribes tests
    Internal.PassedWithSkipped tests _ -> List.map bodyAndDescribes tests
    Internal.TestsFailed passed _ failed ->
      List.map bodyAndDescribes passed
        ++ List.map (Tuple.mapSecond Tuple.first << bodyAndDescribes) failed
    Internal.NoTestsInSuite -> []
  where
    bodyAndDescribes :: Internal.SingleTest body -> ([Text], body)
    bodyAndDescribes test = (Internal.describes test, Internal.body test)

groupIntoNamespaces :: [([Text], Platform.TracingSpan)] -> [Platform.TracingSpan]
groupIntoNamespaces namespacedSpans =
  namespacedSpans
    |> groupBy (List.head << Tuple.first)
    |> Dict.toList
    |> List.concatMap
      ( \(headNamespace, namespacedSpanGroup) ->
          let spans' = List.map Tuple.second namespacedSpanGroup
           in case headNamespace of
                Nothing -> spans'
                Just namespace ->
                  [ Platform.TracingSpan
                      { Platform.name = "describe",
                        Platform.started =
                          List.minimum (List.map Platform.started spans')
                            |> Maybe.withDefault (Platform.MonotonicTime 0),
                        Platform.finished =
                          List.maximum (List.map Platform.finished spans')
                            |> Maybe.withDefault (Platform.MonotonicTime 0),
                        Platform.frame = Nothing,
                        Platform.details = Nothing,
                        Platform.summary = Just namespace,
                        Platform.succeeded =
                          Prelude.mconcat (List.map Platform.succeeded spans'),
                        Platform.allocated = 0,
                        Platform.children =
                          namespacedSpanGroup
                            |> List.filterMap
                              ( \(namespaces, span) ->
                                  case namespaces of
                                    [] -> Nothing
                                    _ : rest -> Just (rest, span)
                              )
                            |> groupIntoNamespaces
                      }
                  ]
      )

groupBy :: Ord b => (a -> b) -> List a -> Dict.Dict b (List a)
groupBy f list =
  List.foldr
    ( \x ->
        Dict.update (f x) <| \val ->
          case val of
            Nothing -> Just [x]
            Just xs -> Just (x : xs)
    )
    Dict.empty
    list