{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE IncoherentInstances #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# OPTIONS_GHC -fno-warn-redundant-constraints #-}

-- | This module defines all the functions you will use to define your test suite.
module Test.Syd.Def.Specify
  ( -- * API Functions

    -- ** Declaring tests
    describe,
    it,
    itWithOuter,
    itWithBoth,
    itWithAll,
    specify,
    specifyWithOuter,
    specifyWithBoth,
    specifyWithAll,
    prop,

    -- ** Declaring commented-out tests
    xdescribe,
    xit,
    xitWithOuter,
    xitWithBoth,
    xitWithAll,
    xspecify,
    xspecifyWithOuter,
    xspecifyWithBoth,
    xspecifyWithAll,

    -- ** Pending tests
    pending,
    pendingWith,
  )
where

import Control.Monad.RWS.Strict
import qualified Data.Text as T
import GHC.Stack
import Test.QuickCheck
import Test.QuickCheck.IO ()
import Test.Syd.Def.TestDefM
import Test.Syd.HList
import Test.Syd.Run
import Test.Syd.SpecDef

-- | Declare a test group
--
-- === Example usage:
--
-- > describe "addition" $ do
-- >     it "adds 3 to 5 to result in 8" $
-- >         3 + 5 `shouldBe` 8
-- >     it "adds 4 to 7 to result in 11" $
-- >         4 + 7 `shouldBe` 11
describe ::
  -- | The test group description
  String ->
  TestDefM outers inner () ->
  TestDefM outers inner ()
describe :: forall (outers :: [*]) inner.
String -> TestDefM outers inner () -> TestDefM outers inner ()
describe String
s =
  let t :: Text
t = String -> Text
T.pack String
s
   in forall r (m :: * -> *) a. MonadReader r m => (r -> r) -> m a -> m a
local (\TestDefEnv
tde -> TestDefEnv
tde {testDefEnvDescriptionPath :: [Text]
testDefEnvDescriptionPath = Text
t forall a. a -> [a] -> [a]
: TestDefEnv -> [Text]
testDefEnvDescriptionPath TestDefEnv
tde})
        forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall w (m :: * -> *) a. MonadWriter w m => (w -> w) -> m a -> m a
censor ((forall a. a -> [a] -> [a]
: []) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (outers :: [*]) inner extra.
Text
-> SpecDefForest outers inner extra
-> SpecDefTree outers inner extra
DefDescribeNode Text
t)

xdescribe :: String -> TestDefM outers inner () -> TestDefM outers inner ()
xdescribe :: forall (outers :: [*]) inner.
String -> TestDefM outers inner () -> TestDefM outers inner ()
xdescribe String
s = forall (outers :: [*]) inner.
String -> TestDefM outers inner () -> TestDefM outers inner ()
describe String
s forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall w (m :: * -> *) a. MonadWriter w m => (w -> w) -> m a -> m a
censor (forall (outers :: [*]) inner result.
Maybe Text
-> SpecDefForest outers inner result
-> SpecDefForest outers inner result
markSpecForestAsPending forall a. Maybe a
Nothing)

-- | Declare a test
--
-- __Note: Don't look at the type signature unless you really have to, just follow the examples.__
--
-- === Example usage:
--
-- ==== Tests without resources
--
-- ===== Pure test
--
-- > describe "addition" $
-- >     it "adds 3 to 5 to result in 8" $
-- >         3 + 5 == 8
--
--
-- ===== IO test
--
-- > describe "readFile and writeFile" $
-- >     it "reads back what it wrote for this example" $ do
-- >         let cts = "hello world"
-- >         let fp = "test.txt"
-- >         writeFile fp cts
-- >         cts' <- readFile fp
-- >         cts' `shouldBe` cts
--
--
-- ===== Pure Property test
--
-- > describe "sort" $
-- >     it "is idempotent" $
-- >         forAllValid $ \ls ->
-- >             sort (sort ls) `shouldBe` (sort (ls :: [Int]))
--
--
-- ===== IO Property test
--
-- > describe "readFile and writeFile" $
-- >     it "reads back what it wrote for any example" $ do
-- >         forAllValid $ \fp ->
-- >             forAllValid $ \cts -> do
-- >                 writeFile fp cts
-- >                 cts' <- readFile fp
-- >                 cts' `shouldBe` cts
--
--
-- ==== Tests with an inner resource
--
-- ===== Pure test
--
-- This is quite a rare use-case but here is an example anyway:
--
-- > before (pure 3) $ describe "addition" $
-- >     it "adds 3 to 5 to result in 8" $ \i ->
-- >         i + 5 == 8
--
--
-- ===== IO test
--
-- This test sets up a temporary directory as an inner resource, and makes it available to each test in the group below.
--
-- > let setUpTempDir func = withSystemTempDir $ \tempDir -> func tempDir
-- > in around setUpTempDir describe "readFile and writeFile" $
-- >     it "reads back what it wrote for this example" $ \tempDir -> do
-- >         let cts = "hello world"
-- >         let fp = tempDir </> "test.txt"
-- >         writeFile fp cts
-- >         cts' <- readFile fp
-- >         cts' `shouldBe` cts
--
--
-- ===== Pure property test
--
-- This is quite a rare use-case but here is an example anyway:
--
-- > before (pure 3) $ describe "multiplication" $
-- >     it "is commutative for 5" $ \i ->
-- >         i * 5 == 5 * 3
--
--
-- ===== IO property test
--
-- > let setUpTempDir func = withSystemTempDir $ \tempDir -> func tempDir
-- > in around setUpTempDir describe "readFile and writeFile" $
-- >     it "reads back what it wrote for this example" $ \tempDir ->
-- >         property $ \cts -> do
-- >             let fp = tempDir </> "test.txt"
-- >             writeFile fp cts
-- >             cts' <- readFile fp
-- >             cts' `shouldBe` cts
it ::
  forall outers inner test.
  (HasCallStack, IsTest test, Arg1 test ~ (), Arg2 test ~ inner) =>
  -- | The description of the test
  String ->
  -- | The test itself
  test ->
  TestDefM outers inner ()
it :: forall (outers :: [*]) inner test.
(HasCallStack, IsTest test, Arg1 test ~ (), Arg2 test ~ inner) =>
String -> test -> TestDefM outers inner ()
it String
s test
t = forall a. HasCallStack => (HasCallStack => a) -> a
withFrozenCallStack forall a b. (a -> b) -> a -> b
$ do
  TestRunSettings
sets <- forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks TestDefEnv -> TestRunSettings
testDefEnvTestRunSettings
  let testDef :: TDef
  (ProgressReporter
   -> ((HList outers -> inner -> IO ()) -> IO ()) -> IO TestRunResult)
testDef =
        TDef
          { testDefVal :: ProgressReporter
-> ((HList outers -> inner -> IO ()) -> IO ()) -> IO TestRunResult
testDefVal = \ProgressReporter
progressReporter (HList outers -> inner -> IO ()) -> IO ()
supplyArgs ->
              forall e.
IsTest e =>
e
-> TestRunSettings
-> ProgressReporter
-> ((Arg1 e -> Arg2 e -> IO ()) -> IO ())
-> IO TestRunResult
runTest
                test
t
                TestRunSettings
sets
                ProgressReporter
progressReporter
                ( \Arg1 test -> Arg2 test -> IO ()
func -> (HList outers -> inner -> IO ()) -> IO ()
supplyArgs (\HList outers
_ inner
arg2 -> Arg1 test -> Arg2 test -> IO ()
func () inner
arg2)
                ),
            testDefCallStack :: CallStack
testDefCallStack = HasCallStack => CallStack
callStack
          }
  forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell [forall (outers :: [*]) inner extra.
Text
-> TDef
     (ProgressReporter
      -> ((HList outers -> inner -> IO ()) -> IO ()) -> IO TestRunResult)
-> extra
-> SpecDefTree outers inner extra
DefSpecifyNode (String -> Text
T.pack String
s) TDef
  (ProgressReporter
   -> ((HList outers -> inner -> IO ()) -> IO ()) -> IO TestRunResult)
testDef ()]

xit ::
  forall outers inner test.
  (HasCallStack, IsTest test, Arg1 test ~ (), Arg2 test ~ inner) =>
  -- | The description of the test
  String ->
  -- | The test itself
  test ->
  TestDefM outers inner ()
xit :: forall (outers :: [*]) inner test.
(HasCallStack, IsTest test, Arg1 test ~ (), Arg2 test ~ inner) =>
String -> test -> TestDefM outers inner ()
xit String
s test
_ = forall (outers :: [*]) inner. String -> TestDefM outers inner ()
pending String
s

-- | A synonym for 'it'
specify ::
  forall outers inner test.
  (HasCallStack, IsTest test, Arg1 test ~ (), Arg2 test ~ inner) =>
  -- | The description of the test
  String ->
  -- | The test itself
  test ->
  TestDefM outers inner ()
specify :: forall (outers :: [*]) inner test.
(HasCallStack, IsTest test, Arg1 test ~ (), Arg2 test ~ inner) =>
String -> test -> TestDefM outers inner ()
specify String
s test
t = forall a. HasCallStack => (HasCallStack => a) -> a
withFrozenCallStack forall a b. (a -> b) -> a -> b
$ forall (outers :: [*]) inner test.
(HasCallStack, IsTest test, Arg1 test ~ (), Arg2 test ~ inner) =>
String -> test -> TestDefM outers inner ()
it String
s test
t

-- | A synonym for 'xit'
xspecify ::
  forall outers inner test.
  (HasCallStack, IsTest test, Arg1 test ~ (), Arg2 test ~ inner) =>
  -- | The description of the test
  String ->
  -- | The test itself
  test ->
  TestDefM outers inner ()
xspecify :: forall (outers :: [*]) inner test.
(HasCallStack, IsTest test, Arg1 test ~ (), Arg2 test ~ inner) =>
String -> test -> TestDefM outers inner ()
xspecify = forall (outers :: [*]) inner test.
(HasCallStack, IsTest test, Arg1 test ~ (), Arg2 test ~ inner) =>
String -> test -> TestDefM outers inner ()
xit

-- | Declare a test that uses an outer resource
--
-- === Example usage:
--
-- ==== Tests with an outer resource
--
-- ===== __Pure test__
--
-- This is quite a rare use-case but here is an example anyway:
--
-- > beforeAll (pure 3) $ describe "addition" $
-- >     itWithOuter "adds 3 to 5 to result in 8" $ \i ->
-- >         i + 5 == 8
--
--
-- ===== IO test
--
-- This test sets up a temporary directory as an inner resource, and makes it available to each test in the group below.
--
-- > let setUpTempDir func = withSystemTempDir $ \tempDir -> func tempDir
-- > in aroundAll setUpTempDir describe "readFile and writeFile" $
-- >     itWithOuter "reads back what it wrote for this example" $ \tempDir -> do
-- >         let cts = "hello world"
-- >         let fp = tempDir </> "test.txt"
-- >         writeFile fp cts
-- >         cts' <- readFile fp
-- >         cts' `shouldBe` cts
--
--
-- ===== __Pure property test__
--
-- This is quite a rare use-case but here is an example anyway:
--
-- > beforeAll (pure 3) $ describe "multiplication" $
-- >     itWithOuter "is commutative for 5" $ \i ->
-- >         i * 5 == 5 * 3
--
--
-- ===== IO property test
--
-- > let setUpTempDir func = withSystemTempDir $ \tempDir -> func tempDir
-- > in aroundAll setUpTempDir describe "readFile and writeFile" $
-- >     itWithouter "reads back what it wrote for this example" $ \tempDir ->
-- >         property $ \cts -> do
-- >             let fp = tempDir </> "test.txt"
-- >             writeFile fp cts
-- >             cts' <- readFile fp
-- >             cts' `shouldBe` cts
itWithOuter ::
  (HasCallStack, IsTest test, Arg1 test ~ inner, Arg2 test ~ outer) =>
  -- The test description
  String ->
  -- The test itself
  test ->
  TestDefM (outer ': otherOuters) inner ()
itWithOuter :: forall test inner outer (otherOuters :: [*]).
(HasCallStack, IsTest test, Arg1 test ~ inner,
 Arg2 test ~ outer) =>
String -> test -> TestDefM (outer : otherOuters) inner ()
itWithOuter String
s test
t = forall a. HasCallStack => (HasCallStack => a) -> a
withFrozenCallStack forall a b. (a -> b) -> a -> b
$ do
  TestRunSettings
sets <- forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks TestDefEnv -> TestRunSettings
testDefEnvTestRunSettings
  let testDef :: TDef
  (ProgressReporter
   -> ((HList (outer : otherOuters) -> inner -> IO ()) -> IO ())
   -> IO TestRunResult)
testDef =
        TDef
          { testDefVal :: ProgressReporter
-> ((HList (outer : otherOuters) -> inner -> IO ()) -> IO ())
-> IO TestRunResult
testDefVal = \ProgressReporter
progressReporter (HList (outer : otherOuters) -> inner -> IO ()) -> IO ()
supplyArgs ->
              forall e.
IsTest e =>
e
-> TestRunSettings
-> ProgressReporter
-> ((Arg1 e -> Arg2 e -> IO ()) -> IO ())
-> IO TestRunResult
runTest
                test
t
                TestRunSettings
sets
                ProgressReporter
progressReporter
                (\Arg1 test -> Arg2 test -> IO ()
func -> (HList (outer : otherOuters) -> inner -> IO ()) -> IO ()
supplyArgs forall a b. (a -> b) -> a -> b
$ \(HCons e
outerArgs HList l
_) inner
innerArg -> Arg1 test -> Arg2 test -> IO ()
func inner
innerArg e
outerArgs),
            testDefCallStack :: CallStack
testDefCallStack = HasCallStack => CallStack
callStack
          }
  forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell [forall (outers :: [*]) inner extra.
Text
-> TDef
     (ProgressReporter
      -> ((HList outers -> inner -> IO ()) -> IO ()) -> IO TestRunResult)
-> extra
-> SpecDefTree outers inner extra
DefSpecifyNode (String -> Text
T.pack String
s) TDef
  (ProgressReporter
   -> ((HList (outer : otherOuters) -> inner -> IO ()) -> IO ())
   -> IO TestRunResult)
testDef ()]

xitWithOuter ::
  (HasCallStack, IsTest test, Arg1 test ~ inner, Arg2 test ~ outer) =>
  -- The test description
  String ->
  -- The test itself
  test ->
  TestDefM (outer ': otherOuters) inner ()
xitWithOuter :: forall test inner outer (otherOuters :: [*]).
(HasCallStack, IsTest test, Arg1 test ~ inner,
 Arg2 test ~ outer) =>
String -> test -> TestDefM (outer : otherOuters) inner ()
xitWithOuter String
s test
_ = forall (outers :: [*]) inner. String -> TestDefM outers inner ()
pending String
s

-- | A synonym for 'itWithOuter'
specifyWithOuter ::
  (HasCallStack, IsTest test, Arg1 test ~ inner, Arg2 test ~ outer) =>
  -- The test description
  String ->
  -- The test itself
  test ->
  TestDefM (outer ': otherOuters) inner ()
specifyWithOuter :: forall test inner outer (otherOuters :: [*]).
(HasCallStack, IsTest test, Arg1 test ~ inner,
 Arg2 test ~ outer) =>
String -> test -> TestDefM (outer : otherOuters) inner ()
specifyWithOuter String
s test
t = forall a. HasCallStack => (HasCallStack => a) -> a
withFrozenCallStack forall a b. (a -> b) -> a -> b
$ forall test inner outer (otherOuters :: [*]).
(HasCallStack, IsTest test, Arg1 test ~ inner,
 Arg2 test ~ outer) =>
String -> test -> TestDefM (outer : otherOuters) inner ()
itWithOuter String
s test
t

-- | A synonym for 'xitWithOuter'
xspecifyWithOuter ::
  (HasCallStack, IsTest test, Arg1 test ~ inner, Arg2 test ~ outer) =>
  -- The test description
  String ->
  -- The test itself
  test ->
  TestDefM (outer ': otherOuters) inner ()
xspecifyWithOuter :: forall test inner outer (otherOuters :: [*]).
(HasCallStack, IsTest test, Arg1 test ~ inner,
 Arg2 test ~ outer) =>
String -> test -> TestDefM (outer : otherOuters) inner ()
xspecifyWithOuter = forall test inner outer (otherOuters :: [*]).
(HasCallStack, IsTest test, Arg1 test ~ inner,
 Arg2 test ~ outer) =>
String -> test -> TestDefM (outer : otherOuters) inner ()
xitWithOuter

-- | Declare a test that uses both an inner and an outer resource
--
-- === Example usage:
--
-- ==== Tests with both an inner and an outer resource
--
-- ===== __Pure test__
--
-- This is quite a rare use-case but here is an example anyway:
--
-- > beforeAll (pure 3) $ before (pure 5) $ describe "addition" $
-- >     itWithBoth "adds 3 to 5 to result in 8" $ \i j ->
-- >         i + j == 8
--
--
-- ===== IO test
--
-- This test sets up a temporary directory as an inner resource, and makes it available to each test in the group below.
--
-- > let setUpTempDir func = withSystemTempDir $ \tempDir -> func tempDir
-- > in aroundAll setUpTempDir describe "readFile and writeFile" $ before (pure "hello world") $
-- >     itWithBoth "reads back what it wrote for this example" $ \tempDir cts -> do
-- >         let fp = tempDir </> "test.txt"
-- >         writeFile fp cts
-- >         cts' <- readFile fp
-- >         cts' `shouldBe` cts
--
--
-- ===== __Pure property test__
--
-- This is quite a rare use-case but here is an example anyway:
--
-- > beforeAll (pure 3) $ before (pure 5) $ describe "multiplication" $
-- >     itWithBoth "is commutative" $ \i j ->
-- >         i * j == 5 * 3
--
--
-- ===== IO property test
--
-- > let setUpTempDir func = withSystemTempDir $ \tempDir -> func tempDir
-- > in aroundAll setUpTempDir describe "readFile and writeFile" $ before (pure "test.txt") $
-- >     itWithBoth "reads back what it wrote for this example" $ \tempDir fileName ->
-- >         property $ \cts -> do
-- >             let fp = tempDir </> fileName
-- >             writeFile fp cts
-- >             cts' <- readFile fp
-- >             cts' `shouldBe` cts
itWithBoth ::
  ( HasCallStack,
    IsTest test,
    Arg1 test ~ outer,
    Arg2 test ~ inner
  ) =>
  String ->
  test ->
  TestDefM (outer ': otherOuters) inner ()
itWithBoth :: forall test outer inner (otherOuters :: [*]).
(HasCallStack, IsTest test, Arg1 test ~ outer,
 Arg2 test ~ inner) =>
String -> test -> TestDefM (outer : otherOuters) inner ()
itWithBoth String
s test
t = forall a. HasCallStack => (HasCallStack => a) -> a
withFrozenCallStack forall a b. (a -> b) -> a -> b
$ do
  TestRunSettings
sets <- forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks TestDefEnv -> TestRunSettings
testDefEnvTestRunSettings
  let testDef :: TDef
  (ProgressReporter
   -> ((HList (outer : otherOuters) -> inner -> IO ()) -> IO ())
   -> IO TestRunResult)
testDef =
        TDef
          { testDefVal :: ProgressReporter
-> ((HList (outer : otherOuters) -> inner -> IO ()) -> IO ())
-> IO TestRunResult
testDefVal = \ProgressReporter
progressReporter (HList (outer : otherOuters) -> inner -> IO ()) -> IO ()
supplyArgs ->
              forall e.
IsTest e =>
e
-> TestRunSettings
-> ProgressReporter
-> ((Arg1 e -> Arg2 e -> IO ()) -> IO ())
-> IO TestRunResult
runTest
                test
t
                TestRunSettings
sets
                ProgressReporter
progressReporter
                (\Arg1 test -> Arg2 test -> IO ()
func -> (HList (outer : otherOuters) -> inner -> IO ()) -> IO ()
supplyArgs forall a b. (a -> b) -> a -> b
$ \(HCons e
outerArgs HList l
_) inner
innerArg -> Arg1 test -> Arg2 test -> IO ()
func e
outerArgs inner
innerArg),
            testDefCallStack :: CallStack
testDefCallStack = HasCallStack => CallStack
callStack
          }
  forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell [forall (outers :: [*]) inner extra.
Text
-> TDef
     (ProgressReporter
      -> ((HList outers -> inner -> IO ()) -> IO ()) -> IO TestRunResult)
-> extra
-> SpecDefTree outers inner extra
DefSpecifyNode (String -> Text
T.pack String
s) TDef
  (ProgressReporter
   -> ((HList (outer : otherOuters) -> inner -> IO ()) -> IO ())
   -> IO TestRunResult)
testDef ()]

xitWithBoth ::
  ( HasCallStack,
    IsTest test,
    Arg1 test ~ outer,
    Arg2 test ~ inner
  ) =>
  String ->
  test ->
  TestDefM (outer ': otherOuters) inner ()
xitWithBoth :: forall test outer inner (otherOuters :: [*]).
(HasCallStack, IsTest test, Arg1 test ~ outer,
 Arg2 test ~ inner) =>
String -> test -> TestDefM (outer : otherOuters) inner ()
xitWithBoth String
s test
_ = forall (outers :: [*]) inner. String -> TestDefM outers inner ()
pending String
s

-- | A synonym for 'itWithBoth'
specifyWithBoth ::
  ( HasCallStack,
    IsTest test,
    Arg1 test ~ outer,
    Arg2 test ~ inner
  ) =>
  String ->
  test ->
  TestDefM (outer ': otherOuters) inner ()
specifyWithBoth :: forall test outer inner (otherOuters :: [*]).
(HasCallStack, IsTest test, Arg1 test ~ outer,
 Arg2 test ~ inner) =>
String -> test -> TestDefM (outer : otherOuters) inner ()
specifyWithBoth String
s test
t = forall a. HasCallStack => (HasCallStack => a) -> a
withFrozenCallStack forall a b. (a -> b) -> a -> b
$ forall test outer inner (otherOuters :: [*]).
(HasCallStack, IsTest test, Arg1 test ~ outer,
 Arg2 test ~ inner) =>
String -> test -> TestDefM (outer : otherOuters) inner ()
itWithBoth String
s test
t

-- | A synonym for 'xitWithBoth'
xspecifyWithBoth ::
  ( HasCallStack,
    IsTest test,
    Arg1 test ~ outer,
    Arg2 test ~ inner
  ) =>
  String ->
  test ->
  TestDefM (outer ': otherOuters) inner ()
xspecifyWithBoth :: forall test outer inner (otherOuters :: [*]).
(HasCallStack, IsTest test, Arg1 test ~ outer,
 Arg2 test ~ inner) =>
String -> test -> TestDefM (outer : otherOuters) inner ()
xspecifyWithBoth = forall test outer inner (otherOuters :: [*]).
(HasCallStack, IsTest test, Arg1 test ~ outer,
 Arg2 test ~ inner) =>
String -> test -> TestDefM (outer : otherOuters) inner ()
xitWithBoth

-- | Declare a test that uses all outer resources
--
-- You will most likely never need this function, but in case you do:
-- Note that this will always require a type annotation, along with the @GADTs@ and @ScopedTypeVariables@ extensions.
--
-- === Example usage
--
-- > beforeAll (pure 'a') $ beforeAll (pure 5) $
-- >     itWithAll "example" $
-- >         \(HCons c (HCons i HNil) :: HList '[Char, Int]) () ->
-- >             (c, i) `shouldeBe` ('a', 5)
itWithAll ::
  ( HasCallStack,
    IsTest test,
    Arg1 test ~ HList outers,
    Arg2 test ~ inner
  ) =>
  String ->
  test ->
  TestDefM outers inner ()
itWithAll :: forall test (outers :: [*]) inner.
(HasCallStack, IsTest test, Arg1 test ~ HList outers,
 Arg2 test ~ inner) =>
String -> test -> TestDefM outers inner ()
itWithAll String
s test
t = forall a. HasCallStack => (HasCallStack => a) -> a
withFrozenCallStack forall a b. (a -> b) -> a -> b
$ do
  TestRunSettings
sets <- forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks TestDefEnv -> TestRunSettings
testDefEnvTestRunSettings
  let testDef :: TDef
  (ProgressReporter
   -> ((HList outers -> inner -> IO ()) -> IO ()) -> IO TestRunResult)
testDef =
        TDef
          { testDefVal :: ProgressReporter
-> ((HList outers -> inner -> IO ()) -> IO ()) -> IO TestRunResult
testDefVal = \ProgressReporter
progressReporter (HList outers -> inner -> IO ()) -> IO ()
supplyArgs ->
              forall e.
IsTest e =>
e
-> TestRunSettings
-> ProgressReporter
-> ((Arg1 e -> Arg2 e -> IO ()) -> IO ())
-> IO TestRunResult
runTest
                test
t
                TestRunSettings
sets
                ProgressReporter
progressReporter
                (\Arg1 test -> Arg2 test -> IO ()
func -> (HList outers -> inner -> IO ()) -> IO ()
supplyArgs Arg1 test -> Arg2 test -> IO ()
func),
            testDefCallStack :: CallStack
testDefCallStack = HasCallStack => CallStack
callStack
          }
  forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell [forall (outers :: [*]) inner extra.
Text
-> TDef
     (ProgressReporter
      -> ((HList outers -> inner -> IO ()) -> IO ()) -> IO TestRunResult)
-> extra
-> SpecDefTree outers inner extra
DefSpecifyNode (String -> Text
T.pack String
s) TDef
  (ProgressReporter
   -> ((HList outers -> inner -> IO ()) -> IO ()) -> IO TestRunResult)
testDef ()]

xitWithAll ::
  ( HasCallStack,
    IsTest test,
    Arg1 test ~ HList outers,
    Arg2 test ~ inner
  ) =>
  String ->
  test ->
  TestDefM outers inner ()
xitWithAll :: forall test (outers :: [*]) inner.
(HasCallStack, IsTest test, Arg1 test ~ HList outers,
 Arg2 test ~ inner) =>
String -> test -> TestDefM outers inner ()
xitWithAll String
s test
_ = forall (outers :: [*]) inner. String -> TestDefM outers inner ()
pending String
s

-- | A synonym for 'itWithAll'
specifyWithAll ::
  ( HasCallStack,
    IsTest test,
    Arg1 test ~ HList outers,
    Arg2 test ~ inner
  ) =>
  String ->
  test ->
  TestDefM outers inner ()
specifyWithAll :: forall test (outers :: [*]) inner.
(HasCallStack, IsTest test, Arg1 test ~ HList outers,
 Arg2 test ~ inner) =>
String -> test -> TestDefM outers inner ()
specifyWithAll String
s test
t = forall a. HasCallStack => (HasCallStack => a) -> a
withFrozenCallStack forall a b. (a -> b) -> a -> b
$ forall test (outers :: [*]) inner.
(HasCallStack, IsTest test, Arg1 test ~ HList outers,
 Arg2 test ~ inner) =>
String -> test -> TestDefM outers inner ()
itWithAll String
s test
t

-- | A synonym for 'xitWithAll'
xspecifyWithAll ::
  ( HasCallStack,
    IsTest test,
    Arg1 test ~ HList outers,
    Arg2 test ~ inner
  ) =>
  String ->
  test ->
  TestDefM outers inner ()
xspecifyWithAll :: forall test (outers :: [*]) inner.
(HasCallStack, IsTest test, Arg1 test ~ HList outers,
 Arg2 test ~ inner) =>
String -> test -> TestDefM outers inner ()
xspecifyWithAll = forall test (outers :: [*]) inner.
(HasCallStack, IsTest test, Arg1 test ~ HList outers,
 Arg2 test ~ inner) =>
String -> test -> TestDefM outers inner ()
xitWithAll

-- | Convenience function for backwards compatibility with @hspec@
--
-- > prop s p = it s $ property p
prop :: Testable prop => String -> prop -> Spec
prop :: forall prop. Testable prop => String -> prop -> Spec
prop String
s prop
p = forall a. HasCallStack => (HasCallStack => a) -> a
withFrozenCallStack forall a b. (a -> b) -> a -> b
$ forall (outers :: [*]) inner test.
(HasCallStack, IsTest test, Arg1 test ~ (), Arg2 test ~ inner) =>
String -> test -> TestDefM outers inner ()
it String
s forall a b. (a -> b) -> a -> b
$ forall prop. Testable prop => prop -> Property
property prop
p

-- | Declare a test that has not been written yet.
pending :: String -> TestDefM outers inner ()
pending :: forall (outers :: [*]) inner. String -> TestDefM outers inner ()
pending String
s = forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell [forall (outers :: [*]) inner extra.
Text -> Maybe Text -> SpecDefTree outers inner extra
DefPendingNode (String -> Text
T.pack String
s) forall a. Maybe a
Nothing]

-- | Declare a test that has not been written yet for the given reason.
pendingWith :: String -> String -> TestDefM outers inner ()
pendingWith :: forall (outers :: [*]) inner.
String -> String -> TestDefM outers inner ()
pendingWith String
description String
reasonWhyItsPending = forall w (m :: * -> *). MonadWriter w m => w -> m ()
tell [forall (outers :: [*]) inner extra.
Text -> Maybe Text -> SpecDefTree outers inner extra
DefPendingNode (String -> Text
T.pack String
description) (forall a. a -> Maybe a
Just (String -> Text
T.pack String
reasonWhyItsPending))]