| Copyright | (c) 2026 The Polytropos Authors |
|---|---|
| License | EUPL-1.2 OR Apache-2.0 |
| Maintainer | nadia.yvette.chambers@ik.me |
| Stability | experimental |
| Portability | non-portable (GHC extensions) |
| Safe Haskell | None |
| Language | GHC2021 |
Polytropos.QuickCheck
Description
Integrates polytropos open records and variants with QuickCheck
property-based testing.
Architectural Overview & Rationale
Records
'Arbitrary (Record r)' generates each field value via that field's own
Arbitrary instance (the walk is heterogeneous: rows may freely mix field
types) and packs the results straight into the contiguous SmallArray
payload — with no intermediate tuples or generic-representation trees.
Shrinking is slot-indexed: each field slot is shrunk independently, one field at a time, so shrinking a \(k\)-field record yields \(O(k)\) candidates per level instead of the full Cartesian product over per-field shrink lists.
Variants
'Arbitrary (Variant s)' uniformly selects a constructor tag index and generates that constructor's payload fields. Shrinking is branch-preserving: only the payload of the currently active constructor is shrunk; the tag never changes, so a counterexample stays on the constructor branch that triggered the property failure.
When to Use This Module
- When property-testing systems that use
polytroposopen records and variants.
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE OverloadedRecordDot #-}
{-# LANGUAGE TypeApplications #-}
import Test.QuickCheck
import Polytropos
import Polytropos.QuickCheck
type User = Record '["id" ':= Int, "active" ':= Bool]
prop_userPositiveId :: Property
prop_userPositiveId = forAll (arbitrary @User) $ \u ->
u.id == u.idSynopsis
- class AllArbitrary (r :: Row) where
- genFields :: Proxy r -> Gen [Identity (Any :: Type)]
- shrinkFields :: Proxy r -> [Identity (Any :: Type)] -> [[Identity (Any :: Type)]]
- class AllCtorsArbitrary (s :: SumRow) where
- numCtors :: Proxy s -> Int
- genCtorFields :: Proxy s -> Int -> Gen [Identity (Any :: Type)]
- shrinkCtorFields :: Proxy s -> Int -> [Identity (Any :: Type)] -> [[Identity (Any :: Type)]]
Row and Sum Constraint Walks
class AllArbitrary (r :: Row) where Source #
Heterogeneous generation walk: every field of the row r has an
Arbitrary instance at its own type.
Methods
genFields :: Proxy r -> Gen [Identity (Any :: Type)] Source #
Generate a value for each payload slot, in row order.
shrinkFields :: Proxy r -> [Identity (Any :: Type)] -> [[Identity (Any :: Type)]] Source #
Slot-indexed shrinks of the payload: one field shrinks at a time.
Instances
| AllArbitrary ('[] :: [Pair Symbol Type]) Source # | |
Defined in Polytropos.QuickCheck | |
| (Arbitrary a, AllArbitrary r) => AllArbitrary ((n ':= a) ': r) Source # | |
Defined in Polytropos.QuickCheck | |
class AllCtorsArbitrary (s :: SumRow) where Source #
Heterogeneous generation walk over a sum row: every constructor's
field row satisfies AllArbitrary.
Methods
numCtors :: Proxy s -> Int Source #
Number of constructors in the sum.
genCtorFields :: Proxy s -> Int -> Gen [Identity (Any :: Type)] Source #
Generate the payload fields of constructor i (0-based).
shrinkCtorFields :: Proxy s -> Int -> [Identity (Any :: Type)] -> [[Identity (Any :: Type)]] Source #
Slot-indexed shrinks of the payload of constructor i.
Instances
| AllCtorsArbitrary ('[] :: [Pair Symbol Row]) Source # | |
Defined in Polytropos.QuickCheck | |
| (AllArbitrary fs, AllCtorsArbitrary s) => AllCtorsArbitrary ((c ':= fs) ': s) Source # | |
Defined in Polytropos.QuickCheck | |