convex-testing-interface
Safe HaskellSafe-Inferred
LanguageHaskell2010

Convex.TestingInterface

Synopsis

Testing interface

class (Show state, Eq state, Show (Action state), ToJSON state) => TestingInterface state where Source #

A testing interface defines the state and behavior of one or more smart contracts.

The type parameter state represents the model's view of the world. It should track all relevant information needed to validate that the contract is behaving correctly.

Minimal complete definition: Action, initialize, arbitraryAction, perform

Minimal complete definition

initialize, arbitraryAction, perform

Associated Types

data Action state Source #

Actions that can be performed on the contract. This is typically a data type with one constructor per contract operation.

Methods

initialize :: MonadIO m => TestingMonadT m state Source #

The initial state of the model, before any actions are performed. Any transactions submitted during initialization will not be subjected to tests. If you want to test the initialization transactions, you can add an initialization action, and keep the initialize method minimal.

arbitraryAction :: state -> Gen (Action state) Source #

Generate a random action given the current state. The generated action should be appropriate for the current state.

precondition :: state -> Action state -> Bool Source #

Precondition that must hold before an action can be executed. Return False to indicate that an action is not valid in the current state. Default: all actions are always valid.

perform :: MonadIO m => state -> Action state -> TestingMonadT m state Source #

Perform the action on the real blockchain (mockchain). This should execute the actual transaction(s) that implement the action. The current model state is provided to allow access to tracked blockchain state. The returned state should reflect the expected effect of the action on the contract state.

validate :: MonadIO m => state -> TestingMonadT m Bool Source #

Validate that the blockchain state matches the model state. Default: no validation (always succeeds).

monitoring :: state -> Action state -> Property -> Property Source #

Called after each successful action to wrap the enclosing QuickCheck property. This hook runs only after perform and validate succeed. Use it for property-level checks, labels, and counterexamples that should be attached to valid state transitions. Default: no additional checks.

discardNegativeTestForUserExceptions :: Bool Source #

Whether to discard (skip) test cases where the invalid action fails due to a user-level error (e.g., off-chain balancing failure) rather than an on-chain validator rejection during negative testing.

When True, negative tests that throw user exceptions are discarded (via QuickCheck's discard), so only on-chain rejections count as successful negative tests.

When False (the default), user exceptions also cause the test case to be discarded — meaning both off-chain and on-chain failures are treated the same way.

Override this in your TestingInterface instance if you need finer control over which failure modes are accepted in negative testing.

redeemerTagger :: RedeemerTagger Source #

Optional RedeemerTagger (Tier 2) that maps a script input's parsed Plutus redeemer Data to a human-readable RedeemerTag (label + optional JSON payload). The label surfaces in the streamed TxInputSummary as redeemerKind / redeemerPayload.

Default: a no-op tagger, so Tier 1 (redeemerRaw / redeemerConstr) is still streamed and Tier 2 fields stay Nothing. See autoRedeemerTag and labelRedeemer for ergonomics.

addressLabeler :: AddressLabeler Source #

Optional AddressLabeler that maps an address's credential hash to a human-readable label. The label surfaces in the streamed TxInputSummary / TxOutputSummary as addressLabel.

Default: mockWalletAddressLabeler, which labels the standard mock wallets (mockWallets) as "Wallet 1".."Wallet 10". Since those are the wallets nearly every test already uses, this default costs nothing and rarely needs overriding — extend it with (<>) to add labels for a model's own script hashes or extra keys.

data ModelState state Source #

Opaque wrapper for model state

Instances

Instances details
Show state => Show (ModelState state) Source # 
Instance details

Defined in Convex.TestingInterface

Methods

showsPrec :: Int -> ModelState state -> ShowS #

show :: ModelState state -> String #

showList :: [ModelState state] -> ShowS #

Eq state => Eq (ModelState state) Source # 
Instance details

Defined in Convex.TestingInterface

Methods

(==) :: ModelState state -> ModelState state -> Bool #

(/=) :: ModelState state -> ModelState state -> Bool #

class TestingInterface state => ThreatModelsFor state where Source #

Minimal complete definition

Nothing

Methods

threatModels :: [ThreatModel ()] Source #

Threat models the contract claims to resist. This is a coverage claim, checked in both directions: a listed model that never applies to any generated transaction fails the suite (the claim is unverifiable), and one that finds a vulnerability fails it too (the claim is false).

Default: nothing claimed. Listing a model here is the outcome of triage — you ran it, saw that it applies, and saw the contract hold. Models you have not triaged belong in candidateModels, which is where they start.

candidateModels :: [ThreatModel ()] Source #

Threat models run for information rather than as a claim: reported, but never failed for not applying. This is where every model starts, and what an empty instance runs.

Default: every parameterless threat model not already spoken for by another slot. A detection still fails — a finding is a finding, whether or not you asked for the model — but the message asks you to triage it into threatModels, expectedVulnerabilities, acceptedFindings or notApplicable rather than accusing the contract of a broken promise.

Set to [] to opt out of the survey entirely.

expectedVulnerabilities :: [(ThreatModel (), String)] Source #

Vulnerabilities the contract is known to have, each with the reason it is declared. Inverted pass/fail: detecting one is the required outcome, and failing to detect it means the contract (or the attack) improved and this declaration is now stale.

The reason travels into the failure message and the streamed summary, so a stale entry explains itself. Write what a reader six months from now needs in order to tell a deliberate declaration from an unexamined one.

Use this only for *genuine* vulnerabilities. A benign finding — an attack that "succeeds" against a design artifact that is not exploitable — belongs in acceptedFindings: listing it here advertises the contract as vulnerable, and fails the suite the moment the finding stops being reproduced.

acceptedFindings :: [(ThreatModel (), String)] Source #

Findings that are known, accepted artifacts of the contract's design rather than exploitable bugs, each with the reason it is accepted. A detection is the required outcome, and the report labels it as accepted by design rather than as a vulnerability.

Judged exactly like expectedVulnerabilities - an acceptance is a declaration too, so the case fails when the run disproves it ("NO LONGER DETECTED") or never verifies it. What differs is only what the declaration means: this slot says the attack lands on something harmless, where expectedVulnerabilities says the contract has a bug nobody has fixed. Prefer this one for anything that is not genuinely exploitable - the other advertises the contract as vulnerable in every report.

notApplicable :: [(ThreatModel (), String)] Source #

Threat models reviewed and found not to apply to this contract, each with the reason. The inverse claim to threatModels: these must not apply, and one that starts applying fails the suite.

That is the point of the slot. "Does not apply here" is a prediction about the contract's transaction shapes, and predictions break — a contract that grows a script output, or a harness change that widens what counts as applicable, should tell you rather than pass in silence. Deleting a model from the lists instead records the same triage where nothing can check it.

Redeemer tagging (Tier 2)

newtype RedeemerTagger Source #

An opt-in function from a parsed Plutus Data (the redeemer of a script input) to an optional RedeemerTag. The Monoid instance picks the first Just result, enabling composition of per-validator taggers.

data RedeemerTag Source #

A human-readable label for a redeemer, produced by a RedeemerTagger supplied by the implementor (Tier 2). When no tagger matches, both tisRedeemerKind and tisRedeemerPayload stay Nothing and only Tier 1 (tisRedeemerRaw / tisRedeemerConstr) is streamed.

Constructors

RedeemerTag 

Fields

autoRedeemerTag :: forall r proxy. (FromData r, Show r) => proxy r -> RedeemerTagger Source #

Label a redeemer with its show output and no payload.

Returns Nothing when the Data does not decode as r, so the tagger is a no-op for that redeemer and (when several taggers are combined via their Monoid instance) the next one gets a chance.

labelRedeemer :: forall r proxy. FromData r => proxy r -> (r -> RedeemerTag) -> RedeemerTagger Source #

Decode the redeemer as r and turn it into a RedeemerTag with a user-supplied function, giving full control over the label and an optional JSON payload.

Returns Nothing when the Data does not decode as r.

Address labeling

newtype AddressLabeler Source #

An opt-in function from the hex-encoded hash of an address's payment or stake credential (key hash or script hash) to a human-readable label, so a client doesn't need to recognise raw hashes to tell wallets and scripts apart. The TestingInterface default (mockWalletAddressLabeler) labels the standard mock wallets as "Wallet 1".."Wallet 10"; override or extend it (via the Monoid instance, which picks the first Just result) to label a model's own script hashes or additional keys.

Constructors

AddressLabeler 

Running Tests

propRunActions :: forall state. (HasCallStack, ThreatModelsFor state) => String -> TestTree Source #

Main property for testing a testing interface. Generates random action sequences and checks that the implementation matches the model.

propRunActionsWithOptions :: forall state. (HasCallStack, ThreatModelsFor state) => String -> RunOptions -> TestTree Source #

Run testing interface tests with custom options

data RunOptions Source #

Options for running property tests

Constructors

RunOptions 

Fields

defaultMainTestingInterface :: HasCallStack => TestTree -> IO () Source #

Default test-suite entrypoint for testing-interface packages.

genAction :: (TestingInterface state, Monad m) => state -> PropertyM m (Maybe (Action state)) Source #

Generate a valid actions

runActions :: (TestingInterface state, MonadIO m) => RunOptions -> state -> TestingMonadT (PropertyM m) state Source #

Generate up to maxActions actions and run them. Stops early when no action satisfying the precondition can be generated.

Trace recording

data TraceRecorder Source #

Callback for recording iteration traces as pre-serialized JSON. Arguments: group name, category ("positive"/"negative"), pre-serialized trace JSON. Default is a no-op (zero overhead when streaming is not active).

When trEnabled returns True, test bodies use the expensive traced code path (building IterationTrace values with UTxO snapshots, transaction summaries, and JSON serialisation). When it returns False (the IsOption default), the cheap runActions path is used instead, avoiding all that work.

trEnabled is an IO action so that the decision can be deferred until the streaming reporter has parsed --no-trace and written the shared IORef.

Constructors

TraceRecorder 

Fields

Threat model coverage policy

zeroCoverageVerdict :: ThreatModelCategory -> ThreatModelSummary -> [String] -> Either (Fault, String) [String] Source #

The coverage policy for a model that was never tested (no outcome was TMPassed or TMFailed): Left a failure message, or Right the status lines to report instead.

A claimed model promises that the contract resists the attack, an expected vulnerability that it does not; either promise is unchecked when the attack was never carried out, whatever the reason:

  • PreconditionNeverMet: the model does not apply to any generated transaction. For a model the suite declared - Claimed, Expected or Accepted - that is a fault in the test setup (it advertises coverage it cannot have), so it fails. A Surveyed model was never declared, so there it is only reported, and for NotApplicable it is the confirming outcome.
  • AttackNeverCarriedOut: the precondition held somewhere, but every attempt hit a Phase 1 invalidation or a rebalancing failure. Per iteration these are environmental skips and never fail anything (a harness limit is not a contract bug), but a model skipped this way on EVERY iteration provides exactly as much coverage as one never run.
  • ModelErrored: the model never got as far as a precondition, so the suite learned nothing at all.

In the latter two the declared slots fail, naming the distinct reasons so the setup can be fixed; a Surveyed model gets a loud warning instead, since the user did not opt into it and failing would block them on a limitation they may not be able to lift.

An Accepted finding is judged exactly like an Expected one: the acceptance is a declaration too, so a run that never verifies it fails, naming the same reasons.

Before this policy, the failure was guarded by "every skip was a precondition miss", so a single environmental skip silenced it and a model that never rebalanced stayed green forever.

data ThreatModelCategory Source #

Which list of a suite's ThreatModelsFor instance a threat model was run from. It decides how the counts in a ThreatModelSummary are to be read: the same tmsFailed (the attack's mutated transaction still validated) is a vulnerability for a Claimed model, the required outcome for an Expected one, and a known, tolerated artifact for an Accepted one. A consumer that alerts on failed > 0 must therefore filter on the category first.

Constructors

Claimed

From threatModels: the contract is claimed secure against it; a detection fails the test.

Expected

From expectedVulnerabilities: the contract is known vulnerable; no detection fails the test.

Accepted

From acceptedFindings: the finding is a known benign artifact. Judged like Expected - a detection is the required outcome.

Surveyed

From candidateModels: run for information. Reported, but never failed for not applying.

NotApplicable

From notApplicable: reviewed as not applying here; it applying at all fails the test.

Instances

Instances details
FromJSON ThreatModelCategory 
Instance details

Defined in Convex.Tasty.Streaming.TMSummary

ToJSON ThreatModelCategory 
Instance details

Defined in Convex.Tasty.Streaming.TMSummary

Bounded ThreatModelCategory 
Instance details

Defined in Convex.Tasty.Streaming.TMSummary

Enum ThreatModelCategory 
Instance details

Defined in Convex.Tasty.Streaming.TMSummary

Generic ThreatModelCategory 
Instance details

Defined in Convex.Tasty.Streaming.TMSummary

Associated Types

type Rep ThreatModelCategory :: Type -> Type #

Show ThreatModelCategory 
Instance details

Defined in Convex.Tasty.Streaming.TMSummary

Eq ThreatModelCategory 
Instance details

Defined in Convex.Tasty.Streaming.TMSummary

Ord ThreatModelCategory 
Instance details

Defined in Convex.Tasty.Streaming.TMSummary

type Rep ThreatModelCategory 
Instance details

Defined in Convex.Tasty.Streaming.TMSummary

type Rep ThreatModelCategory = D1 ('MetaData "ThreatModelCategory" "Convex.Tasty.Streaming.TMSummary" "convex-tasty-streaming-0.1.0.0-inplace" 'False) ((C1 ('MetaCons "Claimed" 'PrefixI 'False) (U1 :: Type -> Type) :+: C1 ('MetaCons "Expected" 'PrefixI 'False) (U1 :: Type -> Type)) :+: (C1 ('MetaCons "Accepted" 'PrefixI 'False) (U1 :: Type -> Type) :+: (C1 ('MetaCons "Surveyed" 'PrefixI 'False) (U1 :: Type -> Type) :+: C1 ('MetaCons "NotApplicable" 'PrefixI 'False) (U1 :: Type -> Type))))

data ZeroCoverageKind Source #

The three ways a model ends up with zero attack coverage.

Constructors

PreconditionNeverMet

The model applied to no generated transaction at all

AttackNeverCarriedOut

The model applied to some transaction, but every attempt ended in a Phase 1 invalidation or a rebalancing failure

ModelErrored

The model itself errored (e.g. no signing wallet could be detected), which happens before any precondition is evaluated

zeroCoverageKind :: ThreatModelSummary -> ZeroCoverageKind Source #

Which of the three it was. An environmental skip proves the precondition held at least once, so it outranks an error, which says nothing either way.

skippedMessage :: ThreatModelSummary -> String Source #

The status line for a run where the model was never tested: every outcome was a precondition miss, an environmental skip (phase 1 invalidation / rebalancing failure), or an error. Shared by all three per-model test cases; the wording says which of the three it was.

The Testing Monad

newtype TestingMonadT m a Source #

Tests run in the mockchain monad extended with balancing error handling.

Leaving handling of balancing errors to the testing interface is important because the errors can contain data for code coverage.

Instances

Instances details
MonadTrans TestingMonadT Source # 
Instance details

Defined in Convex.TestingInterface

Methods

lift :: Monad m => m a -> TestingMonadT m a #

Monad m => MonadBlockchain ConwayEra (TestingMonadT m) Source # 
Instance details

Defined in Convex.TestingInterface

Monad m => MonadMockchain ConwayEra (TestingMonadT m) Source # 
Instance details

Defined in Convex.TestingInterface

Monad m => MonadBalance ConwayEra (TestingMonadT m) Source # 
Instance details

Defined in Convex.TestingInterface

MonadIO m => MonadFail (TestingMonadT m) Source # 
Instance details

Defined in Convex.TestingInterface

Methods

fail :: String -> TestingMonadT m a #

MonadIO m => MonadIO (TestingMonadT m) Source # 
Instance details

Defined in Convex.TestingInterface

Methods

liftIO :: IO a -> TestingMonadT m a #

Monad m => Applicative (TestingMonadT m) Source # 
Instance details

Defined in Convex.TestingInterface

Methods

pure :: a -> TestingMonadT m a #

(<*>) :: TestingMonadT m (a -> b) -> TestingMonadT m a -> TestingMonadT m b #

liftA2 :: (a -> b -> c) -> TestingMonadT m a -> TestingMonadT m b -> TestingMonadT m c #

(*>) :: TestingMonadT m a -> TestingMonadT m b -> TestingMonadT m b #

(<*) :: TestingMonadT m a -> TestingMonadT m b -> TestingMonadT m a #

Functor m => Functor (TestingMonadT m) Source # 
Instance details

Defined in Convex.TestingInterface

Methods

fmap :: (a -> b) -> TestingMonadT m a -> TestingMonadT m b #

(<$) :: a -> TestingMonadT m b -> TestingMonadT m a #

Monad m => Monad (TestingMonadT m) Source # 
Instance details

Defined in Convex.TestingInterface

Methods

(>>=) :: TestingMonadT m a -> (a -> TestingMonadT m b) -> TestingMonadT m b #

(>>) :: TestingMonadT m a -> TestingMonadT m b -> TestingMonadT m b #

return :: a -> TestingMonadT m a #

Monad m => MonadUtxoQuery (TestingMonadT m) Source # 
Instance details

Defined in Convex.TestingInterface

MonadLog m => MonadLog (TestingMonadT m) Source # 
Instance details

Defined in Convex.TestingInterface

Monad m => MonadError (BalanceTxError ConwayEra) (TestingMonadT m) Source # 
Instance details

Defined in Convex.TestingInterface

Monad m => MonadState (MockChainState ConwayEra) (TestingMonadT m) Source # 
Instance details

Defined in Convex.TestingInterface

mockchainSucceedsWithOptions :: Options ConwayEra -> TestingMonadT IO a -> Assertion Source #

Run the TestingMonadT action with the given options and fail if there is an error

mockchainFailsWithOptions :: Options ConwayEra -> TestingMonadT IO a -> (BalanceTxError ConwayEra -> Assertion) -> Assertion Source #

Run the TestingMonadT action with the given options, fail if it succeeds, and handle the error appropriately.

data Options era Source #

Options for running the testing monad.

Constructors

Options 

modifyTransactionLimits :: Options ConwayEra -> Word32 -> Options ConwayEra Source #

Modify the maximum transaction size in the protocol parameters of the given options

Coverage helpers

Coverage with tasty-streaming

withCoverageIndices :: [CoverageIndex] -> TestTree -> TestTree Source #

Pass coverage index data to tasty-streaming.

main = defaultMainStreaming $ withCoverageIndices [covIdx] tests

covDataToSrcLocRanges :: CoverageData -> [SrcLocRange] Source #

Convert Plutus coverage data to a format suitable for tasty-streaming.

Coverage without tasty-streaming

withCoverage :: CoverageConfig -> (Options ConwayEra -> RunOptions -> IO ()) -> IO () Source #

Run a test suite with Plutus script coverage collection.

Creates the coverage IORef, wires it into Options and RunOptions, runs the user's action, and on exit produces a CoverageReport from the accumulated data.

The report is generated when the inner action throws an ExitCode exception (which is how tasty's defaultMain signals completion). The original exception is re-thrown after the report action runs.

main :: IO ()
main = withCoverage config $ \opts runOpts ->
  defaultMain $ testGroup "my tests"
    [ testCase "t1" (mockchainSucceedsWithOptions opts myTest)
    , myPropertyTests runOpts
    ]
 where
  config = CoverageConfig
    { coverageIndices = [myScriptCovIdx]
    , coverageReport  = printCoverageReport
    }

data CoverageConfig Source #

Configuration for coverage collection and reporting.

Use with withCoverage to set up coverage tracking for your test suite.

Constructors

CoverageConfig 

Fields

printCoverageReport :: CoverageReport -> IO () Source #

Print a coverage report to stdout using prettyprinter.

writeCoverageReport :: FilePath -> CoverageReport -> IO () Source #

Write a coverage report to a file.

silentCoverageReport :: CoverageReport -> IO () Source #

Collect coverage data but discard the report.

printCoverageJSON :: CoverageReport -> IO () Source #

Print a coverage report as compact JSON to stdout.

writeCoverageJSON :: FilePath -> CoverageReport -> IO () Source #

Write a coverage report as compact JSON to a file.

printCoverageJSONPretty :: CoverageReport -> IO () Source #

Print a coverage report as pretty-printed JSON to stdout.

writeCoverageJSONPretty :: FilePath -> CoverageReport -> IO () Source #

Write a coverage report as pretty-printed JSON to a file.

data CoverageSummary Source #

Minimal coverage summary matching what Pretty.pretty shows.

Constructors

CoverageSummary 

Fields

coverageSummary :: CoverageReport -> CoverageSummary Source #

Convert a CoverageReport to a compact summary (same info as Pretty.pretty shows).

Re-exports from QuickCheck

data Gen a Source #

A generator for values of type a.

The third-party packages QuickCheck-GenT and quickcheck-transformer provide monad transformer versions of Gen.

Instances

Instances details
MonadFix Gen 
Instance details

Defined in Test.QuickCheck.Gen

Methods

mfix :: (a -> Gen a) -> Gen a #

Applicative Gen 
Instance details

Defined in Test.QuickCheck.Gen

Methods

pure :: a -> Gen a #

(<*>) :: Gen (a -> b) -> Gen a -> Gen b #

liftA2 :: (a -> b -> c) -> Gen a -> Gen b -> Gen c #

(*>) :: Gen a -> Gen b -> Gen b #

(<*) :: Gen a -> Gen b -> Gen a #

Functor Gen 
Instance details

Defined in Test.QuickCheck.Gen

Methods

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

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

Monad Gen 
Instance details

Defined in Test.QuickCheck.Gen

Methods

(>>=) :: Gen a -> (a -> Gen b) -> Gen b #

(>>) :: Gen a -> Gen b -> Gen b #

return :: a -> Gen a #

Testable prop => Testable (Gen prop) 
Instance details

Defined in Test.QuickCheck.Property

Methods

property :: Gen prop -> Property Source #

propertyForAllShrinkShow :: Gen a -> (a -> [a]) -> (a -> [String]) -> (a -> Gen prop) -> Property Source #

class Arbitrary a where Source #

Random generation and shrinking of values.

QuickCheck provides Arbitrary instances for most types in base, except those which incur extra dependencies. For a wider range of Arbitrary instances see the quickcheck-instances package.

Minimal complete definition

arbitrary

Methods

arbitrary :: Gen a Source #

A generator for values of the given type.

It is worth spending time thinking about what sort of test data you want - good generators are often the difference between finding bugs and not finding them. You can use sample, label and classify to check the quality of your test data.

There is no generic arbitrary implementation included because we don't know how to make a high-quality one. If you want one, consider using the testing-feat or generic-random packages.

The QuickCheck manual goes into detail on how to write good generators. Make sure to look at it, especially if your type is recursive!

shrink :: a -> [a] Source #

Produces a (possibly) empty list of all the possible immediate shrinks of the given value.

The default implementation returns the empty list, so will not try to shrink the value. If your data type has no special invariants, you can enable shrinking by defining shrink = genericShrink, but by customising the behaviour of shrink you can often get simpler counterexamples.

Most implementations of shrink should try at least three things:

  1. Shrink a term to any of its immediate subterms. You can use subterms to do this.
  2. Recursively apply shrink to all immediate subterms. You can use recursivelyShrink to do this.
  3. Type-specific shrinkings such as replacing a constructor by a simpler constructor.

For example, suppose we have the following implementation of binary trees:

data Tree a = Nil | Branch a (Tree a) (Tree a)

We can then define shrink as follows:

shrink Nil = []
shrink (Branch x l r) =
  -- shrink Branch to Nil
  [Nil] ++
  -- shrink to subterms
  [l, r] ++
  -- recursively shrink subterms
  [Branch x' l' r' | (x', l', r') <- shrink (x, l, r)]

There are a couple of subtleties here:

  • QuickCheck tries the shrinking candidates in the order they appear in the list, so we put more aggressive shrinking steps (such as replacing the whole tree by Nil) before smaller ones (such as recursively shrinking the subtrees).
  • It is tempting to write the last line as [Branch x' l' r' | x' <- shrink x, l' <- shrink l, r' <- shrink r] but this is the wrong thing! It will force QuickCheck to shrink x, l and r in tandem, and shrinking will stop once one of the three is fully shrunk.

There is a fair bit of boilerplate in the code above. We can avoid it with the help of some generic functions. The function genericShrink tries shrinking a term to all of its subterms and, failing that, recursively shrinks the subterms. Using it, we can define shrink as:

shrink x = shrinkToNil x ++ genericShrink x
  where
    shrinkToNil Nil = []
    shrinkToNil (Branch _ l r) = [Nil]

genericShrink is a combination of subterms, which shrinks a term to any of its subterms, and recursivelyShrink, which shrinks all subterms of a term. These may be useful if you need a bit more control over shrinking than genericShrink gives you.

A final gotcha: we cannot define shrink as simply shrink x = Nil:genericShrink x as this shrinks Nil to Nil, and shrinking will go into an infinite loop.

If all this leaves you bewildered, you might try shrink = genericShrink to begin with, after deriving Generic for your type. However, if your data type has any special invariants, you will need to check that genericShrink can't break those invariants.

Instances

Instances details
Arbitrary ASCIIString 
Instance details

Defined in Test.QuickCheck.Modifiers

Arbitrary PrintableString 
Instance details

Defined in Test.QuickCheck.Modifiers

Arbitrary UnicodeString 
Instance details

Defined in Test.QuickCheck.Modifiers

Arbitrary QCGen 
Instance details

Defined in Test.QuickCheck.Arbitrary

Methods

arbitrary :: Gen QCGen Source #

shrink :: QCGen -> [QCGen] Source #

Arbitrary Key

Since: aeson-2.0.3.0

Instance details

Defined in Data.Aeson.Key

Arbitrary Value

Since: aeson-2.0.3.0

Instance details

Defined in Data.Aeson.Types.Internal

Arbitrary All 
Instance details

Defined in Test.QuickCheck.Arbitrary

Arbitrary Any 
Instance details

Defined in Test.QuickCheck.Arbitrary

Arbitrary Version

Generates Version with non-empty non-negative versionBranch, and empty versionTags

Instance details

Defined in Test.QuickCheck.Arbitrary

Arbitrary CChar 
Instance details

Defined in Test.QuickCheck.Arbitrary

Arbitrary CClock 
Instance details

Defined in Test.QuickCheck.Arbitrary

Arbitrary CDouble 
Instance details

Defined in Test.QuickCheck.Arbitrary

Arbitrary CFloat 
Instance details

Defined in Test.QuickCheck.Arbitrary

Arbitrary CInt 
Instance details

Defined in Test.QuickCheck.Arbitrary

Arbitrary CIntMax 
Instance details

Defined in Test.QuickCheck.Arbitrary

Arbitrary CIntPtr 
Instance details

Defined in Test.QuickCheck.Arbitrary

Arbitrary CLLong 
Instance details

Defined in Test.QuickCheck.Arbitrary

Arbitrary CLong 
Instance details

Defined in Test.QuickCheck.Arbitrary

Arbitrary CPtrdiff 
Instance details

Defined in Test.QuickCheck.Arbitrary

Arbitrary CSChar 
Instance details

Defined in Test.QuickCheck.Arbitrary

Arbitrary CSUSeconds 
Instance details

Defined in Test.QuickCheck.Arbitrary

Arbitrary CShort 
Instance details

Defined in Test.QuickCheck.Arbitrary

Arbitrary CSigAtomic 
Instance details

Defined in Test.QuickCheck.Arbitrary

Arbitrary CSize 
Instance details

Defined in Test.QuickCheck.Arbitrary

Arbitrary CTime 
Instance details

Defined in Test.QuickCheck.Arbitrary

Arbitrary CUChar 
Instance details

Defined in Test.QuickCheck.Arbitrary

Arbitrary CUInt 
Instance details

Defined in Test.QuickCheck.Arbitrary

Arbitrary CUIntMax 
Instance details

Defined in Test.QuickCheck.Arbitrary

Arbitrary CUIntPtr 
Instance details

Defined in Test.QuickCheck.Arbitrary

Arbitrary CULLong 
Instance details

Defined in Test.QuickCheck.Arbitrary

Arbitrary CULong 
Instance details

Defined in Test.QuickCheck.Arbitrary

Arbitrary CUSeconds 
Instance details

Defined in Test.QuickCheck.Arbitrary

Arbitrary CUShort 
Instance details

Defined in Test.QuickCheck.Arbitrary

Arbitrary CWchar 
Instance details

Defined in Test.QuickCheck.Arbitrary

Arbitrary ExitCode 
Instance details

Defined in Test.QuickCheck.Arbitrary

Arbitrary Newline 
Instance details

Defined in Test.QuickCheck.Arbitrary

Arbitrary NewlineMode 
Instance details

Defined in Test.QuickCheck.Arbitrary

Arbitrary Int16 
Instance details

Defined in Test.QuickCheck.Arbitrary

Arbitrary Int32 
Instance details

Defined in Test.QuickCheck.Arbitrary

Arbitrary Int64 
Instance details

Defined in Test.QuickCheck.Arbitrary

Arbitrary Int8 
Instance details

Defined in Test.QuickCheck.Arbitrary

Arbitrary Word16 
Instance details

Defined in Test.QuickCheck.Arbitrary

Arbitrary Word32 
Instance details

Defined in Test.QuickCheck.Arbitrary

Arbitrary Word64 
Instance details

Defined in Test.QuickCheck.Arbitrary

Arbitrary Word8 
Instance details

Defined in Test.QuickCheck.Arbitrary

Arbitrary ByteString64 
Instance details

Defined in Data.ByteString.Base64.Type

Arbitrary IntSet

WARNING: The same warning as for Arbitrary (Set a) applies here.

Instance details

Defined in Test.QuickCheck.Arbitrary

Arbitrary Ordering 
Instance details

Defined in Test.QuickCheck.Arbitrary

Arbitrary Integer 
Instance details

Defined in Test.QuickCheck.Arbitrary

Arbitrary () 
Instance details

Defined in Test.QuickCheck.Arbitrary

Methods

arbitrary :: Gen () Source #

shrink :: () -> [()] Source #

Arbitrary Bool 
Instance details

Defined in Test.QuickCheck.Arbitrary

Arbitrary Char 
Instance details

Defined in Test.QuickCheck.Arbitrary

Arbitrary Double 
Instance details

Defined in Test.QuickCheck.Arbitrary

Arbitrary Float 
Instance details

Defined in Test.QuickCheck.Arbitrary

Arbitrary Int 
Instance details

Defined in Test.QuickCheck.Arbitrary

Arbitrary Word 
Instance details

Defined in Test.QuickCheck.Arbitrary

Arbitrary a => Arbitrary (Blind a) 
Instance details

Defined in Test.QuickCheck.Modifiers

Methods

arbitrary :: Gen (Blind a) Source #

shrink :: Blind a -> [Blind a] Source #

Arbitrary a => Arbitrary (Fixed a) 
Instance details

Defined in Test.QuickCheck.Modifiers

Methods

arbitrary :: Gen (Fixed a) Source #

shrink :: Fixed a -> [Fixed a] Source #

Arbitrary a => Arbitrary (InfiniteList a) 
Instance details

Defined in Test.QuickCheck.Modifiers

Arbitrary a => Arbitrary (InfiniteListInternalData a) 
Instance details

Defined in Test.QuickCheck.Modifiers

Methods

arbitrary :: Gen (InfiniteListInternalData a) Source #

shrink :: InfiniteListInternalData a -> [InfiniteListInternalData a] Source #

(Integral a, Bounded a) => Arbitrary (Large a) 
Instance details

Defined in Test.QuickCheck.Modifiers

Methods

arbitrary :: Gen (Large a) Source #

shrink :: Large a -> [Large a] Source #

(Num a, Ord a, Arbitrary a) => Arbitrary (Negative a) 
Instance details

Defined in Test.QuickCheck.Modifiers

Arbitrary a => Arbitrary (NonEmptyList a) 
Instance details

Defined in Test.QuickCheck.Modifiers

(Num a, Ord a, Arbitrary a) => Arbitrary (NonNegative a) 
Instance details

Defined in Test.QuickCheck.Modifiers

(Num a, Ord a, Arbitrary a) => Arbitrary (NonPositive a) 
Instance details

Defined in Test.QuickCheck.Modifiers

(Num a, Eq a, Arbitrary a) => Arbitrary (NonZero a) 
Instance details

Defined in Test.QuickCheck.Modifiers

(Ord a, Arbitrary a) => Arbitrary (OrderedList a) 
Instance details

Defined in Test.QuickCheck.Modifiers

(Num a, Ord a, Arbitrary a) => Arbitrary (Positive a) 
Instance details

Defined in Test.QuickCheck.Modifiers

Arbitrary a => Arbitrary (Shrink2 a) 
Instance details

Defined in Test.QuickCheck.Modifiers

Integral a => Arbitrary (Small a) 
Instance details

Defined in Test.QuickCheck.Modifiers

Methods

arbitrary :: Gen (Small a) Source #

shrink :: Small a -> [Small a] Source #

Arbitrary a => Arbitrary (Smart a) 
Instance details

Defined in Test.QuickCheck.Modifiers

Methods

arbitrary :: Gen (Smart a) Source #

shrink :: Smart a -> [Smart a] Source #

(Arbitrary a, Ord a) => Arbitrary (SortedList a) 
Instance details

Defined in Test.QuickCheck.Modifiers

Arbitrary v => Arbitrary (KeyMap v)

Since: aeson-2.0.3.0

Instance details

Defined in Data.Aeson.KeyMap

Methods

arbitrary :: Gen (KeyMap v) Source #

shrink :: KeyMap v -> [KeyMap v] Source #

Arbitrary a => Arbitrary (ZipList a) 
Instance details

Defined in Test.QuickCheck.Arbitrary

Arbitrary a => Arbitrary (Complex a) 
Instance details

Defined in Test.QuickCheck.Arbitrary

Arbitrary a => Arbitrary (Identity a) 
Instance details

Defined in Test.QuickCheck.Arbitrary

Arbitrary a => Arbitrary (First a) 
Instance details

Defined in Test.QuickCheck.Arbitrary

Methods

arbitrary :: Gen (First a) Source #

shrink :: First a -> [First a] Source #

Arbitrary a => Arbitrary (Last a) 
Instance details

Defined in Test.QuickCheck.Arbitrary

Methods

arbitrary :: Gen (Last a) Source #

shrink :: Last a -> [Last a] Source #

Arbitrary a => Arbitrary (Dual a) 
Instance details

Defined in Test.QuickCheck.Arbitrary

Methods

arbitrary :: Gen (Dual a) Source #

shrink :: Dual a -> [Dual a] Source #

(Arbitrary a, CoArbitrary a) => Arbitrary (Endo a) 
Instance details

Defined in Test.QuickCheck.Arbitrary

Methods

arbitrary :: Gen (Endo a) Source #

shrink :: Endo a -> [Endo a] Source #

Arbitrary a => Arbitrary (Product a) 
Instance details

Defined in Test.QuickCheck.Arbitrary

Arbitrary a => Arbitrary (Sum a) 
Instance details

Defined in Test.QuickCheck.Arbitrary

Methods

arbitrary :: Gen (Sum a) Source #

shrink :: Sum a -> [Sum a] Source #

Integral a => Arbitrary (Ratio a) 
Instance details

Defined in Test.QuickCheck.Arbitrary

Methods

arbitrary :: Gen (Ratio a) Source #

shrink :: Ratio a -> [Ratio a] Source #

Arbitrary a => Arbitrary (IntMap a)

WARNING: The same warning as for Arbitrary (Set a) applies here.

Instance details

Defined in Test.QuickCheck.Arbitrary

Methods

arbitrary :: Gen (IntMap a) Source #

shrink :: IntMap a -> [IntMap a] Source #

Arbitrary a => Arbitrary (Seq a)

WARNING: The same warning as for Arbitrary (Set a) applies here.

Instance details

Defined in Test.QuickCheck.Arbitrary

Methods

arbitrary :: Gen (Seq a) Source #

shrink :: Seq a -> [Seq a] Source #

(Ord a, Arbitrary a) => Arbitrary (Set a)

WARNING: Users working on the internals of the Set type via e.g. Data.Set.Internal should be aware that this instance aims to give a good representation of Set a as mathematical sets but *does not* aim to provide a varied distribution over the underlying representation.

Instance details

Defined in Test.QuickCheck.Arbitrary

Methods

arbitrary :: Gen (Set a) Source #

shrink :: Set a -> [Set a] Source #

Arbitrary a => Arbitrary (Tree a) 
Instance details

Defined in Test.QuickCheck.Arbitrary

Methods

arbitrary :: Gen (Tree a) Source #

shrink :: Tree a -> [Tree a] Source #

Arbitrary a => Arbitrary (Maybe a) 
Instance details

Defined in Test.QuickCheck.Arbitrary

Methods

arbitrary :: Gen (Maybe a) Source #

shrink :: Maybe a -> [Maybe a] Source #

Arbitrary a => Arbitrary [a] 
Instance details

Defined in Test.QuickCheck.Arbitrary

Methods

arbitrary :: Gen [a] Source #

shrink :: [a] -> [[a]] Source #

(Function a, CoArbitrary a, Arbitrary b) => Arbitrary (a :-> b) 
Instance details

Defined in Test.QuickCheck.Function

Methods

arbitrary :: Gen (a :-> b) Source #

shrink :: (a :-> b) -> [a :-> b] Source #

(Function a, CoArbitrary a, Arbitrary b) => Arbitrary (Fun a b) 
Instance details

Defined in Test.QuickCheck.Function

Methods

arbitrary :: Gen (Fun a b) Source #

shrink :: Fun a b -> [Fun a b] Source #

(Arbitrary a, ShrinkState s a) => Arbitrary (Shrinking s a) 
Instance details

Defined in Test.QuickCheck.Modifiers

Methods

arbitrary :: Gen (Shrinking s a) Source #

shrink :: Shrinking s a -> [Shrinking s a] Source #

Arbitrary (m a) => Arbitrary (WrappedMonad m a) 
Instance details

Defined in Test.QuickCheck.Arbitrary

(Arbitrary a, Arbitrary b) => Arbitrary (Either a b) 
Instance details

Defined in Test.QuickCheck.Arbitrary

Methods

arbitrary :: Gen (Either a b) Source #

shrink :: Either a b -> [Either a b] Source #

HasResolution a => Arbitrary (Fixed a) 
Instance details

Defined in Test.QuickCheck.Arbitrary

Methods

arbitrary :: Gen (Fixed a) Source #

shrink :: Fixed a -> [Fixed a] Source #

(Ord k, Arbitrary k, Arbitrary v) => Arbitrary (Map k v)

WARNING: The same warning as for Arbitrary (Set a) applies here.

Instance details

Defined in Test.QuickCheck.Arbitrary

Methods

arbitrary :: Gen (Map k v) Source #

shrink :: Map k v -> [Map k v] Source #

(Arbitrary a, Arbitrary b) => Arbitrary (a, b) 
Instance details

Defined in Test.QuickCheck.Arbitrary

Methods

arbitrary :: Gen (a, b) Source #

shrink :: (a, b) -> [(a, b)] Source #

(CoArbitrary a, Arbitrary b) => Arbitrary (a -> b) 
Instance details

Defined in Test.QuickCheck.Arbitrary

Methods

arbitrary :: Gen (a -> b) Source #

shrink :: (a -> b) -> [a -> b] Source #

Arbitrary (a b c) => Arbitrary (WrappedArrow a b c) 
Instance details

Defined in Test.QuickCheck.Arbitrary

Methods

arbitrary :: Gen (WrappedArrow a b c) Source #

shrink :: WrappedArrow a b c -> [WrappedArrow a b c] Source #

Arbitrary a => Arbitrary (Const a b) 
Instance details

Defined in Test.QuickCheck.Arbitrary

Methods

arbitrary :: Gen (Const a b) Source #

shrink :: Const a b -> [Const a b] Source #

Arbitrary (f a) => Arbitrary (Alt f a) 
Instance details

Defined in Test.QuickCheck.Arbitrary

Methods

arbitrary :: Gen (Alt f a) Source #

shrink :: Alt f a -> [Alt f a] Source #

Arbitrary a => Arbitrary (Constant a b) 
Instance details

Defined in Test.QuickCheck.Arbitrary

Methods

arbitrary :: Gen (Constant a b) Source #

shrink :: Constant a b -> [Constant a b] Source #

(Arbitrary a, Arbitrary b, Arbitrary c) => Arbitrary (a, b, c) 
Instance details

Defined in Test.QuickCheck.Arbitrary

Methods

arbitrary :: Gen (a, b, c) Source #

shrink :: (a, b, c) -> [(a, b, c)] Source #

(Arbitrary1 f, Arbitrary1 g, Arbitrary a) => Arbitrary (Product f g a) 
Instance details

Defined in Test.QuickCheck.Arbitrary

Methods

arbitrary :: Gen (Product f g a) Source #

shrink :: Product f g a -> [Product f g a] Source #

(Arbitrary a, Arbitrary b, Arbitrary c, Arbitrary d) => Arbitrary (a, b, c, d) 
Instance details

Defined in Test.QuickCheck.Arbitrary

Methods

arbitrary :: Gen (a, b, c, d) Source #

shrink :: (a, b, c, d) -> [(a, b, c, d)] Source #

(Arbitrary1 f, Arbitrary1 g, Arbitrary a) => Arbitrary (Compose f g a) 
Instance details

Defined in Test.QuickCheck.Arbitrary

Methods

arbitrary :: Gen (Compose f g a) Source #

shrink :: Compose f g a -> [Compose f g a] Source #

(Arbitrary a, Arbitrary b, Arbitrary c, Arbitrary d, Arbitrary e) => Arbitrary (a, b, c, d, e) 
Instance details

Defined in Test.QuickCheck.Arbitrary

Methods

arbitrary :: Gen (a, b, c, d, e) Source #

shrink :: (a, b, c, d, e) -> [(a, b, c, d, e)] Source #

(Arbitrary a, Arbitrary b, Arbitrary c, Arbitrary d, Arbitrary e, Arbitrary f) => Arbitrary (a, b, c, d, e, f) 
Instance details

Defined in Test.QuickCheck.Arbitrary

Methods

arbitrary :: Gen (a, b, c, d, e, f) Source #

shrink :: (a, b, c, d, e, f) -> [(a, b, c, d, e, f)] Source #

(Arbitrary a, Arbitrary b, Arbitrary c, Arbitrary d, Arbitrary e, Arbitrary f, Arbitrary g) => Arbitrary (a, b, c, d, e, f, g) 
Instance details

Defined in Test.QuickCheck.Arbitrary

Methods

arbitrary :: Gen (a, b, c, d, e, f, g) Source #

shrink :: (a, b, c, d, e, f, g) -> [(a, b, c, d, e, f, g)] Source #

(Arbitrary a, Arbitrary b, Arbitrary c, Arbitrary d, Arbitrary e, Arbitrary f, Arbitrary g, Arbitrary h) => Arbitrary (a, b, c, d, e, f, g, h) 
Instance details

Defined in Test.QuickCheck.Arbitrary

Methods

arbitrary :: Gen (a, b, c, d, e, f, g, h) Source #

shrink :: (a, b, c, d, e, f, g, h) -> [(a, b, c, d, e, f, g, h)] Source #

(Arbitrary a, Arbitrary b, Arbitrary c, Arbitrary d, Arbitrary e, Arbitrary f, Arbitrary g, Arbitrary h, Arbitrary i) => Arbitrary (a, b, c, d, e, f, g, h, i) 
Instance details

Defined in Test.QuickCheck.Arbitrary

Methods

arbitrary :: Gen (a, b, c, d, e, f, g, h, i) Source #

shrink :: (a, b, c, d, e, f, g, h, i) -> [(a, b, c, d, e, f, g, h, i)] Source #

(Arbitrary a, Arbitrary b, Arbitrary c, Arbitrary d, Arbitrary e, Arbitrary f, Arbitrary g, Arbitrary h, Arbitrary i, Arbitrary j) => Arbitrary (a, b, c, d, e, f, g, h, i, j) 
Instance details

Defined in Test.QuickCheck.Arbitrary

Methods

arbitrary :: Gen (a, b, c, d, e, f, g, h, i, j) Source #

shrink :: (a, b, c, d, e, f, g, h, i, j) -> [(a, b, c, d, e, f, g, h, i, j)] Source #

frequency :: HasCallStack => [(Int, Gen a)] -> Gen a Source #

Chooses one of the given generators, with a weighted random distribution. The input list must be non-empty.

oneof :: HasCallStack => [Gen a] -> Gen a Source #

Randomly uses one of the given generators. The input list must be non-empty.

elements :: HasCallStack => [a] -> Gen a Source #

Generates one of the given values. The input list must be non-empty.

Re-exports from Tasty

data TestTree Source #

The main data structure defining a test suite.

It consists of individual test cases and properties, organized in named groups which form a tree-like hierarchy.

There is no generic way to create a test case. Instead, every test provider (tasty-hunit, tasty-smallcheck etc.) provides a function to turn a test case into a TestTree.

Groups can be created using testGroup.

Since: tasty-0.1