packages feed

sydtest-hedgehog-0.0.0.0: src/Test/Syd/Hedgehog.hs

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}

module Test.Syd.Hedgehog (fromHedgehogGroup) where

import Control.Monad
import qualified Data.Map as M
import qualified Hedgehog
import qualified Hedgehog.Internal.Config as Hedgehog
import qualified Hedgehog.Internal.Property as Hedgehog
import qualified Hedgehog.Internal.Report as Hedgehog
import qualified Hedgehog.Internal.Runner as Hedgehog
import qualified Hedgehog.Internal.Seed as Seed
import Test.Syd as Syd

-- | Import an Hedgehog 'Hedgehog.Group' as a Sydtest 'Test.Syd.Spec'.
--
-- The reasoning behind this function is that, eventhough migration from hedgehog
-- to sydtest is usually very simple, you might depend on certain libraries
-- beyond your control that still use hedgehog.  In that case you want to be able
-- to still use those libraries but also use sydtest already.
fromHedgehogGroup :: Hedgehog.Group -> Syd.Spec
fromHedgehogGroup hedgehogGroup = Syd.describe (Hedgehog.unGroupName $ Hedgehog.groupName hedgehogGroup) $
  forM_ (Hedgehog.groupProperties hedgehogGroup) $ \(propertyName, property) -> do
    it (Hedgehog.unPropertyName propertyName) property

instance IsTest Hedgehog.Property where
  type Arg1 Hedgehog.Property = ()
  type Arg2 Hedgehog.Property = ()
  runTest = runHedgehogProperty

runHedgehogProperty :: Hedgehog.Property -> Syd.TestRunSettings -> ((() -> () -> IO ()) -> IO ()) -> IO TestRunResult
runHedgehogProperty hedgehogProp TestRunSettings {..} wrapper = do
  let config =
        (Hedgehog.propertyConfig hedgehogProp)
          { Hedgehog.propertyDiscardLimit = Hedgehog.DiscardLimit testRunSettingMaxDiscardRatio,
            Hedgehog.propertyShrinkLimit = Hedgehog.ShrinkLimit testRunSettingMaxShrinks
          }
  let size = Hedgehog.Size testRunSettingMaxSize
  seed <- case testRunSettingSeed of
    RandomSeed -> Seed.random
    FixedSeed i -> pure $ Seed.from (fromIntegral i)
  errOrReport <- applyWrapper2 wrapper $ \() () ->
    Hedgehog.checkReport
      config
      size
      seed
      (Hedgehog.propertyTest hedgehogProp)
      (\_ -> pure ()) -- Don't report progress
  ( testRunResultStatus,
    testRunResultException,
    testRunResultNumTests,
    testRunResultLabels,
    testRunResultNumShrinks,
    testRunResultFailingInputs
    ) <- case errOrReport of
    Left e -> pure (TestFailed, Just e, Nothing, Nothing, Nothing, [])
    Right report -> do
      let Hedgehog.TestCount testCountInt = Hedgehog.reportTests report
          numTests = Just $ fromIntegral testCountInt
          labelList =
            M.toList
              . Hedgehog.coverageLabels
              $ Hedgehog.reportCoverage report

          labels =
            if null labelList
              then Nothing
              else
                Just
                  . M.fromList
                  . map
                    ( \(labelName, label) ->
                        ([Hedgehog.unLabelName labelName], Hedgehog.unCoverCount $ Hedgehog.labelAnnotation label)
                    )
                  $ labelList
      case Hedgehog.reportStatus report of
        Hedgehog.OK -> pure (TestPassed, Nothing, numTests, labels, Nothing, [])
        Hedgehog.GaveUp -> pure (TestFailed, Nothing, numTests, labels, Nothing, [])
        Hedgehog.Failed failureReport -> do
          s <-
            Hedgehog.renderResult
              Hedgehog.EnableColor
              Nothing
              report
          let Hedgehog.ShrinkCount shrinkCountInt = Hedgehog.failureShrinks failureReport
              numShrinks = Just $ fromIntegral shrinkCountInt
              exception = Just $ Left s
              inputs = map Hedgehog.failedValue $ Hedgehog.failureAnnotations failureReport
          pure (TestFailed, exception, numTests, labels, numShrinks, inputs) -- TODO
  let testRunResultRetries = Nothing
  let testRunResultGoldenCase = Nothing
  let testRunResultExtraInfo = Nothing
  let testRunResultClasses = Nothing
  let testRunResultTables = Nothing
  let testRunResultFlakinessMessage = Nothing

  pure TestRunResult {..}