sydtest-0.0.0.0: An advanced modern testing framework for Haskell with good defaults and advanced testing features.
Safe HaskellNone
LanguageHaskell2010

Test.Syd

Synopsis

Top level API functions

sydTest :: Spec -> IO () Source #

Evaluate a test suite definition and then run it, with default Settings

sydTestWith :: Settings -> Spec -> IO () Source #

Evaluate a test suite definition and then run it, with given Settings

Defining a test suite

Declaring tests

describe :: String -> TestDefM a b () -> TestDefM a b () Source #

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

it :: forall outers test. (HasCallStack, IsTest test, Arg1 test ~ ()) => String -> test -> TestDefM outers (Arg2 test) () Source #

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

itWithOuter :: (HasCallStack, IsTest test) => String -> test -> TestDefM (Arg2 test ': l) (Arg1 test) () Source #

Declare a test that uses an outer resource

Example usage:

Tests with an outer resource

Pure test
Expand

This is quite a rare use-case but here is an example anyway:

beforeAll (pure 3) $ describe "addition" $
    itWithBoth "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" $
    itWithBoth "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
Expand

This is quite a rare use-case but here is an example anyway:

beforeAll (pure 3) $ describe "multiplication" $
    itWithBoth "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" $
    itWithBoth "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

itWithBoth :: (HasCallStack, IsTest test) => String -> test -> TestDefM (Arg1 test ': l) (Arg2 test) () Source #

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
Expand

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
Expand

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

itWithAll :: (HasCallStack, IsTest test, Arg1 test ~ HList l) => String -> test -> TestDefM l (Arg2 test) () Source #

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)

specify :: forall outers test. (HasCallStack, IsTest test, Arg1 test ~ ()) => String -> test -> TestDefM outers (Arg2 test) () Source #

A synonym for it

specifyWithOuter :: (HasCallStack, IsTest test) => String -> test -> TestDefM (Arg2 test ': l) (Arg1 test) () Source #

A synonym for itWithOuter

specifyWithBoth :: (HasCallStack, IsTest test) => String -> test -> TestDefM (Arg1 test ': l) (Arg2 test) () Source #

A synonym for itWithBoth

specifyWithAll :: (HasCallStack, IsTest test, Arg1 test ~ HList l) => String -> test -> TestDefM l (Arg2 test) () Source #

A synonym for itWithAll

Commented-out tests

xdescribe :: String -> TestDefM a b () -> TestDefM a b () Source #

xit :: forall outers test. (HasCallStack, IsTest test, Arg1 test ~ ()) => String -> test -> TestDefM outers (Arg2 test) () Source #

xitWithOuter :: (HasCallStack, IsTest test) => String -> test -> TestDefM (Arg2 test ': l) (Arg1 test) () Source #

xitWithBoth :: (HasCallStack, IsTest test) => String -> test -> TestDefM (Arg1 test ': l) (Arg2 test) () Source #

xitWithAll :: (HasCallStack, IsTest test, Arg1 test ~ HList l) => String -> test -> TestDefM l (Arg2 test) () Source #

xspecify :: forall outers test. (HasCallStack, IsTest test, Arg1 test ~ ()) => String -> test -> TestDefM outers (Arg2 test) () Source #

xspecifyWithOuter :: (HasCallStack, IsTest test) => String -> test -> TestDefM (Arg2 test ': l) (Arg1 test) () Source #

xspecifyWithBoth :: (HasCallStack, IsTest test) => String -> test -> TestDefM (Arg1 test ': l) (Arg2 test) () Source #

xspecifyWithAll :: (HasCallStack, IsTest test, Arg1 test ~ HList l) => String -> test -> TestDefM l (Arg2 test) () Source #

Pending tests

pending :: String -> TestDefM a b () Source #

Declare a test that has not been written yet.

pendingWith :: String -> String -> TestDefM a b () Source #

Declare a test that has not been written yet for the given reason.

Environment-based tests

eit :: HasCallStack => String -> ReaderT env IO () -> TestDef l env Source #

For defining a part of a test suite in 'ReaderT IO' instead of in IO.

This way you can write this:

spec :: Spec
spec = around withConnectionPool $
  it "can read what it writes" $ \pool ->
    let person = Person { name = "Dave", age = 25 }
    i <- runSqlPool (insert person) pool
    person' <- runSqlPool (get i) pool
    person' `shouldBe` person

like this instead:

spec :: Spec
spec = around withConnectionPool $
  eit "can read what it writes" $ do
    let person = Person { name = "Dave", age = 25 }
    i <- runDB $ insert person
    person' <- runDB $ get i
    liftIO $ person' `shouldBe` person

runDB :: ReaderT ConnectionPool IO a -> IO a

Note that you use eit with a property test. In that case you would have to write it like this:

spec :: Spec
spec = around withConnectionPool $
  it "can read what it writes" $ \pool -> do
    forAllValid $ \person -> withTestEnv pool $ do
      i <- runDB $ insert person
      person' <- runDB $ get i
      liftIO $ person' `shouldBe` person

withTestEnv :: env -> ReaderT env IO a -> IO a Source #

Helper function to run a property test with an env.

withTestEnv = flip runReaderT

Golden tests

pureGoldenByteStringFile :: FilePath -> ByteString -> GoldenTest ByteString Source #

Test that the given bytestring is the same as what we find in the given golden file.

goldenByteStringFile :: FilePath -> IO ByteString -> GoldenTest ByteString Source #

Test that the produced bytestring is the same as what we find in the given golden file.

pureGoldenTextFile :: FilePath -> Text -> GoldenTest Text Source #

Test that the given text is the same as what we find in the given golden file.

goldenTextFile :: FilePath -> IO Text -> GoldenTest Text Source #

Test that the produced text is the same as what we find in the given golden file.

pureGoldenStringFile :: FilePath -> String -> GoldenTest String Source #

Test that the given string is the same as what we find in the given golden file.

goldenStringFile :: FilePath -> IO String -> GoldenTest String Source #

Test that the produced string is the same as what we find in the given golden file.

goldenShowInstance :: Show a => FilePath -> a -> GoldenTest String Source #

Test that the show instance has not changed for the given value.

goldenPrettyShowInstance :: Show a => FilePath -> a -> GoldenTest String Source #

Test that the show instance has not changed for the given value, via ppShow.

Expectations

shouldBe :: (HasCallStack, Show a, Eq a) => a -> a -> IO () infix 1 Source #

Assert that two values are equal according to ==.

shouldNotBe :: (HasCallStack, Show a, Eq a) => a -> a -> IO () infix 1 Source #

Assert that two values are not equal according to ==.

shouldSatisfy :: (HasCallStack, Show a) => a -> (a -> Bool) -> IO () infix 1 Source #

Assert that a value satisfies the given predicate.

shouldSatisfyNamed :: (HasCallStack, Show a) => a -> String -> (a -> Bool) -> IO () Source #

Assert that a value satisfies the given predicate with the given predicate name.

shouldNotSatisfy :: (HasCallStack, Show a) => a -> (a -> Bool) -> IO () infix 1 Source #

Assert that a value does not satisfy the given predicate.

shouldNotSatisfyNamed :: (HasCallStack, Show a) => a -> String -> (a -> Bool) -> IO () Source #

Assert that a value does not satisfy the given predicate with the given predicate name.

shouldReturn :: (HasCallStack, Show a, Eq a) => IO a -> a -> IO () infix 1 Source #

Assert that computation returns the given value (according to ==).

shouldNotReturn :: (HasCallStack, Show a, Eq a) => IO a -> a -> IO () infix 1 Source #

Assert that computation returns the given value (according to ==).

shouldStartWith :: (HasCallStack, Show a, Eq a) => [a] -> [a] -> Expectation infix 1 Source #

Assert that the given list has the given prefix

shouldEndWith :: (HasCallStack, Show a, Eq a) => [a] -> [a] -> Expectation infix 1 Source #

Assert that the given list has the given suffix

shouldContain :: (HasCallStack, Show a, Eq a) => [a] -> [a] -> Expectation infix 1 Source #

Assert that the given list has the given infix

expectationFailure :: HasCallStack => String -> IO a Source #

Make a test fail

Note that this is mostly backward compatible, but it has return type a instead of () because execution will not continue beyond this function. In this way it is not entirely backward compatible with hspec because now there could be an ambiguous type error.

context :: String -> IO a -> IO a Source #

Annotate a given action with a context, for contextual assertions

type Expectation = IO () Source #

For easy hspec migration

shouldThrow :: forall e a. (HasCallStack, Exception e) => IO a -> Selector e -> Expectation infix 1 Source #

Assert that a given IO action throws an exception that matches the given exception

type Selector a = a -> Bool Source #

For easy hspec migration

String expectations

stringShouldBe :: HasCallStack => String -> String -> IO () Source #

Assert that two Strings are equal according to ==.

Note that using function could mess up the colours in your terminal if the Texts contain ANSI codes. In that case you may want to show your values first or use shouldBe instead.

textShouldBe :: HasCallStack => Text -> Text -> IO () Source #

Assert that two Texts are equal according to ==.

Note that using function could mess up the colours in your terminal if the Texts contain ANSI codes. In that case you may want to show your values first or use shouldBe instead.

For throwing raw assertions

stringsNotEqualButShouldHaveBeenEqual :: String -> String -> Assertion Source #

An assertion that says two Strings should have been equal according to ==.

Note that using function could mess up the colours in your terminal if the Texts contain ANSI codes. In that case you may want to show your values first or use shouldBe instead.

textsNotEqualButShouldHaveBeenEqual :: Text -> Text -> Assertion Source #

An assertion that says two Texts should have been equal according to ==.

Note that using function could mess up the colours in your terminal if the Texts contain ANSI codes. In that case you may want to show your values first or use shouldBe instead.

bytestringsNotEqualButShouldHaveBeenEqual :: ByteString -> ByteString -> Assertion Source #

An assertion that says two ByteStrings should have been equal according to ==.

data Assertion Source #

Instances

Instances details
Eq Assertion Source # 
Instance details

Defined in Test.Syd.Run

Show Assertion Source # 
Instance details

Defined in Test.Syd.Run

Generic Assertion Source # 
Instance details

Defined in Test.Syd.Run

Associated Types

type Rep Assertion :: Type -> Type #

Exception Assertion Source # 
Instance details

Defined in Test.Syd.Run

type Rep Assertion Source # 
Instance details

Defined in Test.Syd.Run

type Rep Assertion = D1 ('MetaData "Assertion" "Test.Syd.Run" "sydtest-0.0.0.0-EjyWah0Afr8IDyOeZu1XeF" 'False) ((C1 ('MetaCons "NotEqualButShouldHaveBeenEqual" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 String) :*: S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 String)) :+: (C1 ('MetaCons "EqualButShouldNotHaveBeenEqual" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 String) :*: S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 String)) :+: C1 ('MetaCons "PredicateSucceededButShouldHaveFailed" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 String) :*: S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (Maybe String))))) :+: (C1 ('MetaCons "PredicateFailedButShouldHaveSucceeded" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 String) :*: S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (Maybe String))) :+: (C1 ('MetaCons "ExpectationFailed" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 String)) :+: C1 ('MetaCons "Context" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 Assertion) :*: S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 String)))))

Declaring test dependencies

Dependencies around all of a group of tests

beforeAll :: IO a -> TestDefM (a ': l) c e -> TestDefM l c e Source #

Run a custom action before all spec items in a group, to set up an outer resource a.

beforeAll_ :: IO () -> TestDefM a b e -> TestDefM a b e Source #

Run a custom action before all spec items in a group without setting up any outer resources.

beforeAllWith :: (b -> IO a) -> TestDefM (a ': (b ': l)) c e -> TestDefM (b ': l) c e Source #

Run a custom action before all spec items in a group, to set up an outer resource b by using the outer resource a.

afterAll :: (a -> IO ()) -> TestDefM (a ': l) b e -> TestDefM (a ': l) b e Source #

Run a custom action after all spec items, using the outer resource a.

afterAll' :: (HList l -> IO ()) -> TestDefM l b e -> TestDefM l b e Source #

Run a custom action after all spec items, using all the outer resources.

afterAll_ :: IO () -> TestDefM a b e -> TestDefM a b e Source #

Run a custom action after all spec items without using any outer resources.

aroundAll :: ((a -> IO ()) -> IO ()) -> TestDefM (a ': l) c e -> TestDefM l c e Source #

Run a custom action before and/or after all spec items in group, to provide access to a resource a.

See the FOOTGUN note in the docs for around_.

aroundAll_ :: (IO () -> IO ()) -> TestDefM a b e -> TestDefM a b e Source #

Run a custom action before and/or after all spec items in a group without accessing any resources.

FOOTGUN

Expand

This combinator gives the programmer a lot of power. In fact, it gives the programmer enough power to break the test framework. Indeed, you can provide a wrapper function that just _doesn't_ run the function like this:

spec :: Spec
spec = do
   let don'tDo :: IO () -> IO ()
       don'tDo _ = pure ()
   aroundAll_ don'tDo $ do
     it "should pass" True

During execution, you'll then get an error like this:

thread blocked indefinitely in an MVar operation

The same problem exists when using around_.

Something even more pernicious goes wrong when you run the given action more than once like this:

spec :: Spec
spec = do
   let doTwice :: IO () -> IO ()
       doTwice f = f >> f
   aroundAll_ doTwice $ do
     it "should pass" True

In this case, the test will "just work", but it will be executed twice even if the output reports that it only passed once.

Note: If you're interested in fixing this, talk to me, but only after GHC has gotten impredicative types because that will likely be a requirement.

aroundAllWith :: forall a b c l r. ((a -> IO ()) -> b -> IO ()) -> TestDefM (a ': (b ': l)) c r -> TestDefM (b ': l) c r Source #

Run a custom action before and/or after all spec items in a group to provide access to a resource a while using a resource b

See the FOOTGUN note in the docs for around_.

Dependencies around each of a group of tests

before :: IO c -> TestDefM a c e -> TestDefM a () e Source #

Run a custom action before every spec item, to set up an inner resource c.

before_ :: IO () -> TestDefM a c e -> TestDefM a c e Source #

Run a custom action before every spec item without setting up any inner resources.

after :: (c -> IO ()) -> TestDefM a c e -> TestDefM a c e Source #

Run a custom action after every spec item, using the inner resource c.

after_ :: IO () -> TestDefM a c e -> TestDefM a c e Source #

Run a custom action after every spec item without using any inner resources.

around :: ((c -> IO ()) -> IO ()) -> TestDefM a c e -> TestDefM a () e Source #

Run a custom action before and/or after every spec item, to provide access to an inner resource c.

See the FOOTGUN note in the docs for around_.

around_ :: (IO () -> IO ()) -> TestDefM a c e -> TestDefM a c e Source #

Run a custom action before and/or after every spec item without accessing any inner resources.

It is important that the wrapper function that you provide runs the action that it gets _exactly once_.

FOOTGUN

Expand

This combinator gives the programmer a lot of power. In fact, it gives the programmer enough power to break the test framework. Indeed, you can provide a wrapper function that just _doesn't_ run the function like this:

spec :: Spec
spec = do
   let don'tDo :: IO () -> IO ()
       don'tDo _ = pure ()
   around_ don'tDo $ do
     it "should pass" True

During execution, you'll then get an error like this:

thread blocked indefinitely in an MVar operation

The same problem exists when using aroundAll_.

The same thing will go wrong if you run the given action more than once like this:

spec :: Spec
spec = do
   let doTwice :: IO () -> IO ()
       doTwice f = f >> f
   around_ doTwice $ do
     it "should pass" True

Note: If you're interested in fixing this, talk to me, but only after GHC has gotten impredicative types because that will likely be a requirement.

aroundWith :: forall a c d r. ((c -> IO ()) -> d -> IO ()) -> TestDefM a c r -> TestDefM a d r Source #

Run a custom action before and/or after every spec item, to provide access to an inner resource c while using the inner resource d.

See the FOOTGUN note in the docs for around_.

Setup functions

Using setup functions

setupAround :: SetupFunc () c -> TestDefM a c e -> TestDefM a () e Source #

Use around with a SetupFunc

setupAroundWith' :: HContains l a => (a -> SetupFunc d c) -> TestDefM l c e -> TestDefM l d e Source #

Creating setup functions

newtype SetupFunc b a Source #

A function that can provide an a given a b.

You can think of this as a potentially-resource-aware version of 'b -> IO a'.

Constructors

SetupFunc 

Fields

Instances

Instances details
Monad (SetupFunc c) Source # 
Instance details

Defined in Test.Syd.Def.SetupFunc

Methods

(>>=) :: SetupFunc c a -> (a -> SetupFunc c b) -> SetupFunc c b #

(>>) :: SetupFunc c a -> SetupFunc c b -> SetupFunc c b #

return :: a -> SetupFunc c a #

Functor (SetupFunc c) Source # 
Instance details

Defined in Test.Syd.Def.SetupFunc

Methods

fmap :: (a -> b) -> SetupFunc c a -> SetupFunc c b #

(<$) :: a -> SetupFunc c b -> SetupFunc c a #

Applicative (SetupFunc c) Source # 
Instance details

Defined in Test.Syd.Def.SetupFunc

Methods

pure :: a -> SetupFunc c a #

(<*>) :: SetupFunc c (a -> b) -> SetupFunc c a -> SetupFunc c b #

liftA2 :: (a -> b -> c0) -> SetupFunc c a -> SetupFunc c b -> SetupFunc c c0 #

(*>) :: SetupFunc c a -> SetupFunc c b -> SetupFunc c b #

(<*) :: SetupFunc c a -> SetupFunc c b -> SetupFunc c a #

MonadIO (SetupFunc c) Source # 
Instance details

Defined in Test.Syd.Def.SetupFunc

Methods

liftIO :: IO a -> SetupFunc c a #

Category SetupFunc Source # 
Instance details

Defined in Test.Syd.Def.SetupFunc

Methods

id :: forall (a :: k). SetupFunc a a #

(.) :: forall (b :: k) (c :: k) (a :: k). SetupFunc b c -> SetupFunc a b -> SetupFunc a c #

makeSimpleSetupFunc :: (forall r. (a -> IO r) -> IO r) -> SetupFunc () a Source #

Turn a simple provider function into a SetupFunc.

This works together nicely with most supplier functions. Some examples:

useSimpleSetupFunc :: SetupFunc () a -> forall r. (a -> IO r) -> IO r Source #

Use a 'SetupFunc ()' as a simple provider function.

This is the opposite of the makeSimpleSetupFunc function

connectSetupFunc :: SetupFunc c b -> SetupFunc b a -> SetupFunc c a Source #

Connect two setup functions.

This is basically 'flip (.)' but for SetupFuncs. It's exactly 'flip composeSetupFunc'.

composeSetupFunc :: SetupFunc b a -> SetupFunc c b -> SetupFunc c a Source #

Compose two setup functions.

This is basically (.) but for SetupFuncs

wrapSetupFunc :: (b -> SetupFunc () a) -> SetupFunc b a Source #

Wrap a function that produces a SetupFunc to into a SetupFunc.

This is useful to combine a given 'SetupFunc b' with other 'SetupFunc ()'s as follows:

mySetupFunc :: SetupFunc B A
mySetupFunc = wrapSetupFunc $ \b -> do
  r <- setupSomething
  c <- setupSomethingElse b r
  pure $ somehowCombine c r

setupSomething :: SetupFunc () R
setupSomething :: B -> R -> SetupFunc () C
somehowCombine :: C -> R -> A

unwrapSetupFunc :: SetupFunc b a -> b -> SetupFunc () a Source #

Unwrap a SetupFunc into a function that produces a SetupFunc

This is the opposite of wrapSetupFunc.

Declaring different test settings

modifyMaxSuccess :: (Int -> Int) -> TestDefM a b c -> TestDefM a b c Source #

modifyMaxSize :: (Int -> Int) -> TestDefM a b c -> TestDefM a b c Source #

modifyMaxShrinks :: (Int -> Int) -> TestDefM a b c -> TestDefM a b c Source #

data TestRunSettings Source #

Instances

Instances details
Show TestRunSettings Source # 
Instance details

Defined in Test.Syd.Run

Generic TestRunSettings Source # 
Instance details

Defined in Test.Syd.Run

Associated Types

type Rep TestRunSettings :: Type -> Type #

MonadReader TestRunSettings (TestDefM a b) Source # 
Instance details

Defined in Test.Syd.Def.TestDefM

Methods

ask :: TestDefM a b TestRunSettings #

local :: (TestRunSettings -> TestRunSettings) -> TestDefM a b a0 -> TestDefM a b a0 #

reader :: (TestRunSettings -> a0) -> TestDefM a b a0 #

type Rep TestRunSettings Source # 
Instance details

Defined in Test.Syd.Run

type Rep TestRunSettings = D1 ('MetaData "TestRunSettings" "Test.Syd.Run" "sydtest-0.0.0.0-EjyWah0Afr8IDyOeZu1XeF" 'False) (C1 ('MetaCons "TestRunSettings" 'PrefixI 'True) ((S1 ('MetaSel ('Just "testRunSettingSeed") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 Int) :*: (S1 ('MetaSel ('Just "testRunSettingMaxSuccess") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 Int) :*: S1 ('MetaSel ('Just "testRunSettingMaxSize") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 Int))) :*: ((S1 ('MetaSel ('Just "testRunSettingMaxDiscardRatio") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 Int) :*: S1 ('MetaSel ('Just "testRunSettingMaxShrinks") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 Int)) :*: (S1 ('MetaSel ('Just "testRunSettingGoldenStart") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 Bool) :*: S1 ('MetaSel ('Just "testRunSettingGoldenReset") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 Bool)))))

Declaring parallelism

sequential :: TestDefM a b c -> TestDefM a b c Source #

Declare that all tests below must be run sequentially

parallel :: TestDefM a b c -> TestDefM a b c Source #

Declare that all tests below may be run in parallel. (This is the default.)

Declaring randomisation order

Doing IO during test definition

runIO :: IO e -> TestDefM a b e Source #

Test definition types

newtype TestDefM a b c Source #

The test definition monad

This type has three parameters:

  • a: The type of the result of aroundAll
  • b: The type of the result of around
  • c: The result

In practice, all of these three parameters should be () at the top level.

Constructors

TestDefM 

Instances

Instances details
MonadReader TestRunSettings (TestDefM a b) Source # 
Instance details

Defined in Test.Syd.Def.TestDefM

Methods

ask :: TestDefM a b TestRunSettings #

local :: (TestRunSettings -> TestRunSettings) -> TestDefM a b a0 -> TestDefM a b a0 #

reader :: (TestRunSettings -> a0) -> TestDefM a b a0 #

MonadState () (TestDefM a b) Source # 
Instance details

Defined in Test.Syd.Def.TestDefM

Methods

get :: TestDefM a b () #

put :: () -> TestDefM a b () #

state :: (() -> (a0, ())) -> TestDefM a b a0 #

Monad (TestDefM a b) Source # 
Instance details

Defined in Test.Syd.Def.TestDefM

Methods

(>>=) :: TestDefM a b a0 -> (a0 -> TestDefM a b b0) -> TestDefM a b b0 #

(>>) :: TestDefM a b a0 -> TestDefM a b b0 -> TestDefM a b b0 #

return :: a0 -> TestDefM a b a0 #

Functor (TestDefM a b) Source # 
Instance details

Defined in Test.Syd.Def.TestDefM

Methods

fmap :: (a0 -> b0) -> TestDefM a b a0 -> TestDefM a b b0 #

(<$) :: a0 -> TestDefM a b b0 -> TestDefM a b a0 #

Applicative (TestDefM a b) Source # 
Instance details

Defined in Test.Syd.Def.TestDefM

Methods

pure :: a0 -> TestDefM a b a0 #

(<*>) :: TestDefM a b (a0 -> b0) -> TestDefM a b a0 -> TestDefM a b b0 #

liftA2 :: (a0 -> b0 -> c) -> TestDefM a b a0 -> TestDefM a b b0 -> TestDefM a b c #

(*>) :: TestDefM a b a0 -> TestDefM a b b0 -> TestDefM a b b0 #

(<*) :: TestDefM a b a0 -> TestDefM a b b0 -> TestDefM a b a0 #

MonadIO (TestDefM a b) Source # 
Instance details

Defined in Test.Syd.Def.TestDefM

Methods

liftIO :: IO a0 -> TestDefM a b a0 #

MonadWriter (TestForest a b) (TestDefM a b) Source # 
Instance details

Defined in Test.Syd.Def.TestDefM

Methods

writer :: (a0, TestForest a b) -> TestDefM a b a0 #

tell :: TestForest a b -> TestDefM a b () #

listen :: TestDefM a b a0 -> TestDefM a b (a0, TestForest a b) #

pass :: TestDefM a b (a0, TestForest a b -> TestForest a b) -> TestDefM a b a0 #

type TestDef a b = TestDefM a b () Source #

A synonym for a test suite definition

Test suite types

data TDef v Source #

Constructors

TDef 

Instances

Instances details
Functor TDef Source # 
Instance details

Defined in Test.Syd.SpecDef

Methods

fmap :: (a -> b) -> TDef a -> TDef b #

(<$) :: a -> TDef b -> TDef a #

Foldable TDef Source # 
Instance details

Defined in Test.Syd.SpecDef

Methods

fold :: Monoid m => TDef m -> m #

foldMap :: Monoid m => (a -> m) -> TDef a -> m #

foldMap' :: Monoid m => (a -> m) -> TDef a -> m #

foldr :: (a -> b -> b) -> b -> TDef a -> b #

foldr' :: (a -> b -> b) -> b -> TDef a -> b #

foldl :: (b -> a -> b) -> b -> TDef a -> b #

foldl' :: (b -> a -> b) -> b -> TDef a -> b #

foldr1 :: (a -> a -> a) -> TDef a -> a #

foldl1 :: (a -> a -> a) -> TDef a -> a #

toList :: TDef a -> [a] #

null :: TDef a -> Bool #

length :: TDef a -> Int #

elem :: Eq a => a -> TDef a -> Bool #

maximum :: Ord a => TDef a -> a #

minimum :: Ord a => TDef a -> a #

sum :: Num a => TDef a -> a #

product :: Num a => TDef a -> a #

Traversable TDef Source # 
Instance details

Defined in Test.Syd.SpecDef

Methods

traverse :: Applicative f => (a -> f b) -> TDef a -> f (TDef b) #

sequenceA :: Applicative f => TDef (f a) -> f (TDef a) #

mapM :: Monad m => (a -> m b) -> TDef a -> m (TDef b) #

sequence :: Monad m => TDef (m a) -> m (TDef a) #

type TestForest a c = SpecDefForest a c () Source #

type TestTree a c = SpecDefTree a c () Source #

type SpecDefForest (a :: [Type]) c e = [SpecDefTree a c e] Source #

data SpecDefTree (a :: [Type]) c e where Source #

Constructors

DefSpecifyNode :: Text -> TDef (((HList a -> c -> IO ()) -> IO ()) -> IO TestRunResult) -> e -> SpecDefTree a c e 
DefPendingNode :: Text -> Maybe Text -> SpecDefTree a c e 
DefDescribeNode :: Text -> SpecDefForest a c e -> SpecDefTree a c e 
DefWrapNode :: (IO () -> IO ()) -> SpecDefForest a c e -> SpecDefTree a c e 
DefBeforeAllNode :: IO a -> SpecDefForest (a ': l) c e -> SpecDefTree l c e 
DefAroundAllNode :: ((a -> IO ()) -> IO ()) -> SpecDefForest (a ': l) c e -> SpecDefTree l c e 
DefAroundAllWithNode :: ((b -> IO ()) -> a -> IO ()) -> SpecDefForest (b ': (a ': l)) c e -> SpecDefTree (a ': l) c e 
DefAfterAllNode :: (HList a -> IO ()) -> SpecDefForest a c e -> SpecDefTree a c e 
DefParallelismNode :: Parallelism -> SpecDefForest a c e -> SpecDefTree a c e 
DefRandomisationNode :: ExecutionOrderRandomisation -> SpecDefForest a c e -> SpecDefTree a c e 

Instances

Instances details
Functor (SpecDefTree a c) Source # 
Instance details

Defined in Test.Syd.SpecDef

Methods

fmap :: (a0 -> b) -> SpecDefTree a c a0 -> SpecDefTree a c b #

(<$) :: a0 -> SpecDefTree a c b -> SpecDefTree a c a0 #

Foldable (SpecDefTree a c) Source # 
Instance details

Defined in Test.Syd.SpecDef

Methods

fold :: Monoid m => SpecDefTree a c m -> m #

foldMap :: Monoid m => (a0 -> m) -> SpecDefTree a c a0 -> m #

foldMap' :: Monoid m => (a0 -> m) -> SpecDefTree a c a0 -> m #

foldr :: (a0 -> b -> b) -> b -> SpecDefTree a c a0 -> b #

foldr' :: (a0 -> b -> b) -> b -> SpecDefTree a c a0 -> b #

foldl :: (b -> a0 -> b) -> b -> SpecDefTree a c a0 -> b #

foldl' :: (b -> a0 -> b) -> b -> SpecDefTree a c a0 -> b #

foldr1 :: (a0 -> a0 -> a0) -> SpecDefTree a c a0 -> a0 #

foldl1 :: (a0 -> a0 -> a0) -> SpecDefTree a c a0 -> a0 #

toList :: SpecDefTree a c a0 -> [a0] #

null :: SpecDefTree a c a0 -> Bool #

length :: SpecDefTree a c a0 -> Int #

elem :: Eq a0 => a0 -> SpecDefTree a c a0 -> Bool #

maximum :: Ord a0 => SpecDefTree a c a0 -> a0 #

minimum :: Ord a0 => SpecDefTree a c a0 -> a0 #

sum :: Num a0 => SpecDefTree a c a0 -> a0 #

product :: Num a0 => SpecDefTree a c a0 -> a0 #

Traversable (SpecDefTree a c) Source # 
Instance details

Defined in Test.Syd.SpecDef

Methods

traverse :: Applicative f => (a0 -> f b) -> SpecDefTree a c a0 -> f (SpecDefTree a c b) #

sequenceA :: Applicative f => SpecDefTree a c (f a0) -> f (SpecDefTree a c a0) #

mapM :: Monad m => (a0 -> m b) -> SpecDefTree a c a0 -> m (SpecDefTree a c b) #

sequence :: Monad m => SpecDefTree a c (m a0) -> m (SpecDefTree a c a0) #

MonadWriter (TestForest a b) (TestDefM a b) Source # 
Instance details

Defined in Test.Syd.Def.TestDefM

Methods

writer :: (a0, TestForest a b) -> TestDefM a b a0 #

tell :: TestForest a b -> TestDefM a b () #

listen :: TestDefM a b a0 -> TestDefM a b (a0, TestForest a b) #

pass :: TestDefM a b (a0, TestForest a b -> TestForest a b) -> TestDefM a b a0 #

Hspec synonyms

type Spec = SpecWith () Source #

A synonym for easy migration from hspec

type SpecWith a = SpecM a () Source #

A synonym for easy migration from hspec

type SpecM a b = TestDefM '[] a b Source #

A synonym for easy migration from hspec

Utilities

ppShow :: Show a => a -> String #

Convert a generic value into a pretty String, if possible.

Reexports