@hackage / keiki-codec-json-test

Property-test toolkit for keiki-codec-json downstream consumers.

Latest0.1.0.0

About

Metadata

  • Last updated , by shinzui
  • License BSD-3-Clause
  • Categories Testing
  • Maintained by: nadeem@gmail.com

  • Lottery factor: 1

Links

Installation

Tested Compilers

  1. 9.12.2
  2. 9.12.1

Readme

keiki-codec-json-test

Property-test toolkit for downstream consumers of keiki-codec-json.

Use this package in test suites that persist RegFile rs snapshots as JSON and want release-time protection against schema drift. Production code that only needs JSON encoding and decoding should depend on keiki-codec-json, not this package.

What this is for

The primary tool is the case-#10 detector: a per-slot-type golden-byte test that catches a silent change to a slot type's Aeson.ToJSON instance. This is the schema-evolution failure mode the shape hash in Keiki.Shape cannot detect by design — the hash is over the slot type's TypeRep, not over its encoding. If a consumer edits the ToJSON instance to change the on-the-wire shape, the hash stays the same and old snapshots silently fail to decode. slotGoldenSpec is the contract anchor that makes the drift loud and obvious.

The secondary helpers expose the in-tree property disciplines as library functions parameterised over the consumer's own slot list: Value-path and Encoding-path round-trip, within-path determinism, and structural sensitivity.

Using

import Data.Proxy (Proxy (..))
import qualified Data.Text as T
import Test.Hspec (describe, hspec)

import Keiki.Codec.JSON.Test
  ( regFileCodecProps
  , regFileShapeSensitivitySpec
  , someKnownShape
  )
import Keiki.Codec.JSON.Test.Golden
  ( SlotGolden (..)
  , slotGoldenSpec
  )

-- Your slot type and slot lists:
-- data Email = Email Text deriving (...)
-- type MySlots = '[ '("email", Email), '("count", Int) ]
-- type MySlotsRenamed = '[ '("emailAddress", Email), '("count", Int) ]

main :: IO ()
main = hspec $ do
  -- Case-#10 detector. Add one slotGoldenSpec per slot type whose
  -- ToJSON / FromJSON instances you want to pin.
  slotGoldenSpec "Email" (SlotGolden
    { sgInput = Email (T.pack "alice@example.com")
    , sgBytes = "\"alice@example.com\""
    })

  -- Round-trip + determinism over the snapshot's slot list.
  describe "props: MySlots" (regFileCodecProps @MySlots)

  -- Sensitivity: every named mutation must flip the shape hash.
  describe "sensitivity: MySlots" $
    regFileShapeSensitivitySpec
      (Proxy @MySlots)
      [ ("rename email", someKnownShape @MySlotsRenamed) ]

The toolkit assumes each slot type has Aeson.ToJSON, Aeson.FromJSON, Arbitrary (for the property suite), CanonicalTypeName (for the shape hash; default Typeable-based instance is usually enough), Eq, and Show. If your slot type lacks Arbitrary, write one — it is typically a one-liner via quickcheck-instances for the standard library types.

When you don't need this

keiki-codec-json alone is sufficient for production use. This package is opt-in for test suites. Pulling it in adds QuickCheck, hspec, and quickcheck-instances as transitive deps; if you only want the codec in production, do not depend on this package.

Running the self-test

cabal test keiki-codec-json-test:keiki-codec-json-test-test

The self-test exercises every public helper against a small toy fixture (Email, DemoSlots, DemoSlotsRenamed). Expected output: 7 examples, 0 failures.