packages feed

hspec-junit-formatter-1.3.0.0: library/Test/Hspec/JUnit/Schema.hs

-- | The structure of a JUnit XML file
--
-- This intends to be a complete and accurate representation of
-- <https://github.com/testmoapp/junitxml#complete-junit-xml-example>, though we
-- don't (and sometimes can't) exercise all of it.
module Test.Hspec.JUnit.Schema
  ( Testsuites (..)
  , Testsuite (..)
  , TestsuiteChild (..)
  , Testcase (..)
  , TestcaseChild (..)
  , Skipped (..)
  , Failure (..)
  , Error (..)
  , Properties (..)
  , Property (..)
  , SystemOut (..)
  , SystemErr (..)

    -- * Tagged XML types
  , Attr (..)
  , Content (..)

    -- * Other wrapper types
  , Seconds (..)
  ) where

import Prelude

import Data.String (IsString)
import Data.Text (Text)
import Data.Time (UTCTime)
import Numeric.Natural (Natural)
import Test.Hspec.Core.Format (Seconds (..))

-- | @<testsuites>@
--
-- Usually the root element of a JUnit XML file. Some tools leave out the
-- @<testsuites>@ element if there is only a single top-level @<testsuite>@
-- element (which is then used as the root element).
data Testsuites = Testsuites
  { name :: Attr Text
  -- ^ Name of the entire test run
  , tests :: Attr Natural
  -- ^ Total number of tests in this file
  , failures :: Attr Natural
  -- ^ Total number of failed tests in this file
  , errors :: Attr Natural
  -- ^ Total number of errored tests in this file
  , skipped :: Attr Natural
  -- ^ Total number of skipped tests in this file
  , assertions :: Attr Natural
  -- ^ Total number of assertions for all tests in this file
  , time :: Attr Seconds
  -- ^ Aggregated time of all tests in this file in seconds
  , timestamp :: Attr UTCTime
  -- ^ Date and time of when the test run was executed (in ISO 8601 format)
  , children :: [Testsuite]
  -- ^ Only @<testsuite>@s can be descendents of this node
  }

-- | @<testsuite>@
--
-- A test suite usually represents a class, folder or group of tests. There can
-- be many test suites in an XML file, and there can be test suites under other
-- test suites.
data Testsuite = Testsuite
  { name :: Attr Text
  -- ^ Name of the test suite (e.g. class name or folder name)
  , tests :: Attr Natural
  -- ^ Total number of tests in this suite
  , failures :: Attr Natural
  -- ^ Total number of failed tests in this suite
  , errors :: Attr Natural
  -- ^ Total number of errored tests in this suite
  , skipped :: Attr Natural
  -- ^ Total number of skipped tests in this suite
  , assertions :: Attr Natural
  -- ^ Total number of assertions for all tests in this suite
  , time :: Attr Seconds
  -- ^ Aggregated time of all tests in this file in seconds
  , timestamp :: Attr UTCTime
  -- ^ Date and time of when the test suite was executed (in ISO 8601 format)
  , file :: Maybe (Attr FilePath)
  -- ^ Source code file of this test suite
  , children :: [TestsuiteChild]
  }

-- | @<testsuite>@ can contain nodes that are any of these
data TestsuiteChild
  = TestsuiteProperties Properties
  | TestsuiteSystemOut SystemOut
  | TestsuiteSystemErr SystemErr
  | TestsuiteTestcase Testcase
  | TestsuiteTestsuite Testsuite

-- | @<properties>@
--
-- Test suites can have additional properties such as environment variables or
-- version numbers. Some tools also support properties for test cases.
newtype Properties = Properties
  { unwrap :: [Property]
  }

-- | @<property>@
--
-- Each property has a name and value. Some tools also support properties with
-- text values instead of value attributes.
data Property = Property
  { name :: Attr Text
  , value :: Either (Attr Text) Content
  }

-- | @<system-out>@
--
-- Optionally data written to standard out for the suite. Also supported on a
-- test case level, see below.
newtype SystemOut = SystemOut
  { unwrap :: Content
  }

-- | @<system-err>@
--
-- Optionally data written to standard error for the suite. Also supported on a
-- test case level, see below.
newtype SystemErr = SystemErr
  { unwrap :: Content
  }

-- | @<testcase>@
--
-- There are one or more test cases in a test suite. A test passed if there
-- isn't an additional result element (skipped, failure, error).
data Testcase = Testcase
  { name :: Attr Text
  -- ^ The name of this test case, often the method name
  , classname :: Attr Text
  -- ^ The name of the parent class/folder, often the same as the suite's name
  , assertions :: Attr Natural
  -- ^ Number of assertions checked during test case execution
  , time :: Attr Seconds
  -- ^ Execution time of the test in seconds
  , file :: Maybe (Attr FilePath)
  -- ^ Source code file of this test case
  , line :: Maybe (Attr Natural)
  -- ^ Source code line number of the start of this test case
  , properties :: Maybe Properties
  , systemStream :: [Either SystemOut SystemErr]
  -- ^ Stored as a combined list to represent ordering and interleaving
  , child :: TestcaseChild
  }

-- | @<testcase>@ will contain only one of these
data TestcaseChild
  = -- | Success case
    TestcaseEmpty
  | TestcaseSkipped Skipped
  | TestcaseFailure Failure
  | TestcaseError Error

-- | @<skipped>@
--
-- Indicates that the test was not executed. Can have an optional message
-- describing why the test was skipped.
newtype Skipped = Skipped
  { message :: Attr Text
  }

-- | @<failure>@
--
-- The test failed because one of the assertions/checks failed. Can have a
-- message and failure type, often the assertion type or class. The text content
-- of the element often includes the failure description or stack trace.
data Failure = Failure
  { message :: Attr Text
  , type_ :: Attr Text
  , content :: Content
  -- ^ Failure description or stack trace
  }

-- | @<error>@
--
-- The test had an unexpected error during execution. Can have a message and
-- error type, often the exception type or class. The text content of the
-- element often includes the error description or stack trace.
data Error = Error
  { message :: Attr Text
  , type_ :: Attr Text
  , content :: Content
  -- ^ Error description or stack trace
  }

newtype Attr a = Attr
  { unwrap :: a
  }
  deriving newtype (IsString, Num)

newtype Content = Content
  { unwrap :: Text
  }
  deriving newtype (IsString)