packages feed

hedgehog-lockstep-0.1.0.0: CHANGELOG.md

# Changelog

All notable changes to `hedgehog-lockstep` will be documented in this file.

The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Haskell PVP](https://pvp.haskell.org/).

## 0.1.0.0

Initial release.

### Added

- `LockstepCmd` record bundling an API operation with its model
  interpretation and observation.
- `LockstepState` wrapping a user-defined model plus a `ModelEnv`,
  a `Map` keyed by Hedgehog `Var` identity (O(log n) lookup) using a
  phase-polymorphic `Ord1`-based comparison. `initialLockstepState`,
  `getModel`, and `getEntries` construct and project from it.
- `GVar` and `Op` (`OpId`, `OpFst`, `OpSnd`, `OpLeft`, `OpRight`,
  `OpComp`, plus `(>>>)` for left-to-right composition) for projecting
  values out of compound action outputs.
- `varsOfType`, `mkGVar`, `mkGVarId`, `mapGVar`, `resolveGVar`,
  `concreteGVar`, `gvarLabel` for enumerating and resolving generalized
  variables. `mapGVar` composes an additional projection (any
  `InterpretOp` instance, including the built-in `Op`) onto an existing
  `GVar`, the analogue of `quickcheck-lockstep`'s `mapGVar`.
- Four test entry points:
  `lockstepProperty`, `lockstepPropertyWith`, `lockstepParallel`, and
  `lockstepParallelWith`.
- Monad-parameterized variants
  `lockstepPropertyM`, `lockstepPropertyWithM`, `lockstepParallelM`, and
  `lockstepParallelWithM` accepting a
  `forall a. m a -> PropertyT IO a` (or `env -> m a -> PropertyT IO a`)
  natural transformation. Lets users write commands in a custom monad
  stack (e.g., `ReaderT env (PropertyT IO)`) and supply the runner
  separately, without hardcoding `PropertyT IO` into every `lsCmdExec`.
- `hoistLockstepCmd :: (forall a. m a -> n a) -> LockstepCmd m model -> LockstepCmd n model`
  for retargeting a command's monad.
- New module `Hedgehog.Lockstep.Observe` exposing an `Observation`
  GADT (`ObserveEq`, `ObserveProject`, `ObservePair`, `ObserveCustom`)
  and `runObservation`. The GADT factors out the common
  model-output-versus-real-output comparison patterns into a typed DSL
  so users can write `lsCmdObserve = runObservation ObserveEq` or
  `lsCmdObserve = runObservation (ObserveProject normM normR)` instead
  of writing the assertion by hand. This is the hedgehog-lockstep
  analogue of `quickcheck-lockstep`'s `Observable`/`ModelValue` split.
- New module `Hedgehog.Lockstep.Examples` exposing
  `lockstepLabelledExamples`, a model-only driver that samples random
  command sequences, accumulates the tags emitted by `lsCmdTag`, and
  prints one shortest sampled trace per tag. This is the analogue of
  `QuickCheck`'s `labelledExamples` and `quickcheck-lockstep`'s
  `tagActions`: it answers "is the generator actually hitting the
  labelled cases I expect" without running the real system at all.
  The accompanying `LabelledExamples` summary type and `ModelStep`
  trace entry are exposed for callers that want to inspect the
  sampled traces directly.
- `lockstepCommands` for users who want to drive
  `Gen.sequential` / `executeSequential` directly.
- README guidance and a `Test.KVStore` example for using
  `Hedgehog.label` / `classify` inside `lsCmdObserve` for coverage labels.
- `lsCmdInvariants :: model -> output -> Test ()` field on `LockstepCmd`
  for system invariants that should hold after every command, separate
  from the lockstep equality check in `lsCmdObserve`.
- `lsCmdTag :: model -> model -> modelOutput -> [String]` field on
  `LockstepCmd` for per-step coverage tagging. Receives the pre- and
  post-step model and the model's predicted output; each returned tag is
  reported via `Hedgehog.label`. This is the analogue of
  `quickcheck-lockstep`'s `tagStep` and is the natural place for tags
  whose value depends on how the model state changed during the step.
- Per-step model-state footnote: `toLockstepCommand` adds a `footnote`
  of the post-step model after every command. Hedgehog only displays
  footnotes on test failure, so passing tests are unaffected; on
  failure the model-state evolution shows alongside the shrunken
  command sequence (analogue of `quickcheck-lockstep`'s `monitoring`
  counterexample enrichment).
- Module-level Haddock for every public module, plus disambiguated
  identifier references so Haddock builds cleanly with no warnings.
- README caveat documenting the dependency on `Hedgehog.Internal.State`.
- `Test.UnitCoverage` exercising `applyOp`, `gvarLabel`, `mapGVar`, and
  `mkGVarId`.
- `InterpretOp` class with `interpretOp :: op a b -> a -> Maybe b`.
  `mkGVar` and `mapGVar` accept any op type with `InterpretOp` and
  `Show` instances, not just the built-in `Op`. Users can extend the
  projection vocabulary (e.g., a list-head op) by defining their own
  GADT and supplying instances. The built-in `Op` is itself an
  instance of `InterpretOp`, and `applyOp` is exported as a synonym
  for `interpretOp`. This is the analogue of `quickcheck-lockstep`'s
  `Operation`/`InterpretOp` classes, closing the structural-flexibility
  gap with that library.
- `Test.CustomOp` exercising a user-defined op (`MyOpHead :: MyOp [a] a`)
  end-to-end through a real lockstep test.