mockcat-1.0.0.0: test/Support/ParamSpec.hs
{-# LANGUAGE GADTs #-}
-- |
-- = ParamSpec (Experimental)
--
-- Minimal reversible specification for parameters.
--
-- This module is /experimental/ and its data constructors or semantics may
-- change between minor releases until the Scenario / Hedgehog integration is
-- stabilized. It intentionally stays tiny and dependency–free; integration
-- layers (QuickCheck / Hedgehog) live outside the core library for now.
--
-- Stability: experimental
--
-- Design notes:
-- * `PSPredicate` keeps the original predicate for fallback generation /
-- validation. We do not attempt predicate decomposition.
-- * `PSRangeInt` focuses on a common ergonomic win first; more numeric ranges
-- can be added when needed.
-- * Future additions may introduce pretty-printing or normalisation helpers
-- (e.g. enum duplicate collapse) without breaking existing pattern matches.
--
-- When in doubt prefer using smart constructors (`exact`, `enum`, ...) instead
-- of pattern matching directly so future internal tweaks are easier.
module Support.ParamSpec
(
ParamSpec(..)
, fromParam
, exact
, enum
, rangeInt
, anySpec
, predicate
) where
import Test.MockCat.Param (Param(..))
-- | A small, closed specification set.
-- NOTE: 'PSPredicate' keeps the original predicate for fallback generation / validation.
-- For now we do not attempt to decompose arbitrary predicates.
-- 'PSRangeInt' is specialised so we can show a concrete ergonomic win early.
-- Future: add textual pretty printer / merging / normalisation if needed.
data ParamSpec a where
-- | Exact value expectation.
PSExact :: a -> ParamSpec a
-- | Enumeration of acceptable values (duplicates preserved for now).
PSEnum :: [a] -> ParamSpec a -- ^ Non-empty expected; empty is treated as unsatisfiable elsewhere.
-- | Inclusive integer range (caller responsible for low <= high; library may normalise in future).
PSRangeInt :: Int -> Int -> ParamSpec Int
-- | Arbitrary predicate with a human readable label.
PSPredicate :: (a -> Bool) -> String -> ParamSpec a
-- | Wildcard (accept any value of the domain).
PSAny :: ParamSpec a
-- | Construct exact.
exact :: a -> ParamSpec a
exact = PSExact
-- | Construct enumeration (duplicates allowed; kept verbatim so that later we could weight frequency if we wished).
enum :: [a] -> ParamSpec a
enum = PSEnum
-- | Inclusive integer range.
rangeInt :: Int -> Int -> ParamSpec Int
rangeInt = PSRangeInt
-- | Wildcard (accept any value of the domain).
anySpec :: ParamSpec a
anySpec = PSAny
-- | Explicit predicate (kept for validation / fallback generation filtering).
predicate :: (a -> Bool) -> String -> ParamSpec a
predicate = PSPredicate
-- | Derive a coarse specification from an existing 'Param'.
-- * ExpectValue v -> PSExact v
-- * ExpectCondition f l-> PSPredicate f l
fromParam :: Param a -> ParamSpec a
fromParam (ExpectValue v _) = PSExact v
fromParam (ExpectCondition f l) = PSPredicate f l
fromParam (ValueWrapper _ _) = PSPredicate (const True) "any"