packages feed

genvalidity-hspec 0.2.0.5 → 1.0.0.4

raw patch · 48 files changed

Files

+ CHANGELOG.md view
@@ -0,0 +1,77 @@+# Changelog++## [1.0.0.4] - 2022-10-04++### Changed++* Compatibility with `hspec >= 2.11.10`.++## [1.0.0.3] - 2022-10-04++### Changed++* Compatibility with `hspec-core >= 2.11`.++## [1.0.0.2] - 2022-09-20++Same as 1.0.0.1, but with the right commit.++## [1.0.0.1] - 2022-09-02++### Changed++* Compatibility with `hspec-core >= 2.10`++## [1.0.0.0] - 2021-11-20++### Changed++* Compatibility with `validity >= 0.12.0.0`+* Compatibility with `genvalidity >= 1.0.0.0`+* Renamed every combinator that ends in `OnValid` (or similar) to not have that suffix anymore.++### Removed++* Every combinator that relates to unchecked or invalid values.+* Everything related to `RelativeValidity`.+++## [0.7.0.3] - 2020-02-10++### Changed++* Removed doctests+* Improved the cabal file+* Fixed the `monadSpec` to not generate the list length using `genUnchecked`++## [0.7.0.2] - 2019-09-23++* Removed nonsense shrinking from `genValidSpec` and `genInvalidSpec`.++## [0.7.0.1] - 2019-09-23++* Removed nonsense shrinking from `arbitraryGeneratesOnlyValid`, `genValidGeneratesValid` and `genInvalidGeneratesInvalid`.++## [0.7.0.0] - 2019-03-06++### Changed++* Fixed compatibility with genvalidity >=0.8++## [0.6.2.3] - 2019-02-28++### Changed++* Clearer docs++## [0.6.2.2] - 2019-01-09++### Changed++* Fixed a forward incompatibility with hspec 2.6.x.++## [0.3.0.1] - 2018-10-07++### Changed++* Compatibility with validity >=0.9, genvalidity >=0.7 and genvalidity-property >=0.3
LICENSE view
@@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2016 Tom Sydney Kerckhove+Copyright (c) 2016-2021 Tom Sydney Kerckhove  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal
− Setup.hs
@@ -1,2 +0,0 @@-import Distribution.Simple-main = defaultMain
genvalidity-hspec.cabal view
@@ -1,64 +1,93 @@-name:                genvalidity-hspec-version:             0.2.0.5-synopsis:            Standard spec's for GenValidity instances-description:         Please see README.md-homepage:            https://github.com/NorfairKing/validity#readme-license:             MIT-license-file:        LICENSE-author:              Tom Sydney Kerckhove-maintainer:          syd.kerckhove@gmail.com-copyright:           Copyright: (c) 2016 Tom Sydney Kerckhove-category:            Testing-build-type:          Simple--- extra-source-files:-cabal-version:       >=1.10+cabal-version: 1.12 +-- This file has been generated from package.yaml by hpack version 0.36.1.+--+-- see: https://github.com/sol/hpack++name:           genvalidity-hspec+version:        1.0.0.4+synopsis:       Standard spec's for GenValidity instances+description:    Note: There are companion packages for this library:+                .+                * <https://hackage.haskell.org/package/genvalidity-hspec-aeson genvalidity-hspec-aeson>+                .+                * <https://hackage.haskell.org/package/genvalidity-hspec-binary genvalidity-hspec-binary>+                .+                * <https://hackage.haskell.org/package/genvalidity-hspec-cereal genvalidity-hspec-cereal>+                .+                * <https://hackage.haskell.org/package/genvalidity-hspec-hashable genvalidity-hspec-hashable>+category:       Testing+homepage:       https://github.com/NorfairKing/validity#readme+bug-reports:    https://github.com/NorfairKing/validity/issues+author:         Tom Sydney Kerckhove+maintainer:     syd@cs-syd.eu+copyright:      Copyright: (c) 2016-2021 Tom Sydney Kerckhove+license:        MIT+license-file:   LICENSE+build-type:     Simple+extra-source-files:+    LICENSE+    CHANGELOG.md++source-repository head+  type: git+  location: https://github.com/NorfairKing/validity+ library-  hs-source-dirs:      src   exposed-modules:       Test.Validity-    , Test.Validity.Arbitrary-    , Test.Validity.Eq-    , Test.Validity.Ord-    , Test.Validity.Functions-    , Test.Validity.Functions.CanFail-    , Test.Validity.Functions.Equivalence-    , Test.Validity.Functions.Idempotence-    , Test.Validity.Functions.Inverse-    , Test.Validity.Functions.Validity-    , Test.Validity.GenValidity-    , Test.Validity.GenRelativeValidity-    , Test.Validity.Operations-    , Test.Validity.Operations.Identity-    , Test.Validity.Operations.Associativity-    , Test.Validity.Operations.Commutativity-    , Test.Validity.Relations-    , Test.Validity.Relations.Antisymmetry-    , Test.Validity.Relations.Reflexivity-    , Test.Validity.Relations.Symmetry-    , Test.Validity.Relations.Transitivity-    , Test.Validity.RelativeValidity-    , Test.Validity.Types-  other-modules:+      Test.Validity.Applicative+      Test.Validity.Arbitrary+      Test.Validity.Eq+      Test.Validity.Functor+      Test.Validity.GenValidity+      Test.Validity.Monad+      Test.Validity.Monoid+      Test.Validity.Ord+      Test.Validity.Show+      Test.Validity.Shrinking       Test.Validity.Utils-  build-depends:       base                               < 5-                     , validity                 >= 0.3 && < 0.4-                     , genvalidity-                     , QuickCheck-                     , hspec                    >= 2.2 && < 2.3-  default-language:    Haskell2010-+  other-modules:+      Paths_genvalidity_hspec+  hs-source-dirs:+      src+  ghc-options: -Wall -fwarn-redundant-constraints+  build-depends:+      QuickCheck+    , base >=4.9 && <5+    , genvalidity >=1.0+    , genvalidity-property >=0.5+    , hspec+    , hspec-core >=2.5.0+    , transformers+    , validity >=0.5+  default-language: Haskell2010 -test-suite genvalidity-hspec-doctests-  default-language:   Haskell2010-  hs-source-dirs:     test-  type:               exitcode-stdio-1.0-  ghc-options:        -threaded-  main-is:            DocTest.hs-  build-depends:      base-    , doctest               >= 0.11      && < 0.12+test-suite genvalidity-hspec-test+  type: exitcode-stdio-1.0+  main-is: Spec.hs+  other-modules:+      Test.Validity.ApplicativeSpec+      Test.Validity.ArbitrarySpec+      Test.Validity.EqSpec+      Test.Validity.FunctorSpec+      Test.Validity.GenRelativeValiditySpec+      Test.Validity.GenValiditySpec+      Test.Validity.MonadSpec+      Test.Validity.MonoidSpec+      Test.Validity.OrdSpec+      Test.Validity.RelativeValiditySpec+      Test.Validity.ShowSpec+      Test.Validity.ShrinkingSpec+      Paths_genvalidity_hspec+  hs-source-dirs:+      test/+  ghc-options: -threaded -rtsopts -with-rtsopts=-N -Wall+  build-depends:+      QuickCheck+    , base >=4.9 && <5+    , genvalidity     , genvalidity-hspec--source-repository head-  type:     git-  location: https://github.com/NorfairKing/validity+    , hspec+    , hspec-core >=2.5.0+  default-language: Haskell2010
src/Test/Validity.hs view
@@ -1,213 +1,268 @@ {-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE ScopedTypeVariables   #-}+{-# LANGUAGE ScopedTypeVariables #-}++-- | To use the 'Spec' functions in this module, you will need @TypeApplications@.+--+--+-- The most interesting functions in this module for most uses are:+--+-- * 'genValidSpec'+-- * 'eqSpec'+-- * 'ordSpec'+-- * 'producesValidsOnValids'+-- * 'forAllValid'+-- * 'shouldBeValid' module Test.Validity-    ( module Data.GenValidity-    , Proxy(Proxy)+  ( -- * Writing properties -      -- * Tests for Arbitrary instances involving Validity-    , arbitrarySpec-    , arbitraryGeneratesOnlyValid-    , shrinkProducesOnlyValids+    -- ** Cheap generation with shrinking+    forAllValid, -      -- * Tests for GenValidity instances-    , genValiditySpec-    , genValidityValidGeneratesValid-    , genGeneratesValid-    , genValidityInvalidGeneratesInvalid-    , genGeneratesInvalid+    -- ** Cheap assertions+    shouldBeValid,+    shouldBeInvalid, -      -- * Tests for RelativeValidity instances-    , relativeValiditySpec-    , relativeValidityImpliesValidA-    , relativeValidityImpliesValidB+    -- * Tests for GenValidity instances+    genValidSpec,+    genValidGeneratesValid,+    genGeneratesValid,+    shrinkValidSpec,+    shrinkValidSpecWithLimit,+    shrinkValidPreservesValidOnGenValid,+    shrinkPreservesValidOnGenValid,+    shrinkValidPreservesValid,+    shrinkingStaysValid,+    shrinkingPreserves, -      -- * Tests for GenRelativeValidity instances-    , genRelativeValiditySpec-    , genRelativeValidityValidGeneratesValid-    , genRelativeValidityInvalidGeneratesInvalid+    -- * Tests for Arbitrary instances involving Validity+    arbitrarySpec,+    arbitraryGeneratesOnlyValid, +    -- * Standard tests involving functions -      -- * Standard tests involving functions+    -- ** Standard tests involving validity+    producesValidsOnGen,+    producesValid,+    producesValidsOnArbitrary,+    producesValidsOnGens2,+    producesValid2,+    producesValidsOnArbitrary2,+    producesValidsOnGens3,+    producesValid3,+    producesValidsOnArbitrary3, -      -- ** Standard tests involving validity-    , producesValidsOnGen-    , producesValidsOnValids-    , producesValid-    , producesValidsOnArbitrary-    , producesValidsOnGens2-    , producesValidsOnValids2-    , producesValid2-    , producesValidsOnArbitrary2-    , producesValidsOnGens3-    , producesValidsOnValids3-    , producesValid3-    , producesValidsOnArbitrary3+    -- ** Standard tests involving functions that can fail+    CanFail (..),+    succeedsOnGen,+    succeeds,+    succeedsOnArbitrary,+    succeedsOnGens2,+    succeeds2,+    succeedsOnArbitrary2,+    failsOnGen,+    failsOnGens2,+    validIfSucceedsOnGen,+    validIfSucceedsOnArbitrary,+    validIfSucceeds,+    validIfSucceedsOnGens2,+    validIfSucceeds2,+    validIfSucceedsOnArbitrary2,+    validIfSucceedsOnGens3,+    validIfSucceeds3,+    validIfSucceedsOnArbitrary3, -      -- ** Standard tests involving functions that can fail-    , CanFail(..)+    -- ** Standard tests involving equivalence of functions -    , succeedsOnGen-    , succeedsOnValid-    , succeeds-    , succeedsOnArbitrary+    -- *** Simple functions -    , succeedsOnGens2-    , succeedsOnValids2-    , succeeds2-    , succeedsOnArbitrary2+    -- **** One argument+    equivalentOnGen,+    equivalent,+    equivalentOnArbitrary, -    , failsOnGen-    , failsOnInvalid+    -- **** Two arguments+    equivalentOnGens2,+    equivalent2,+    equivalentOnArbitrary2, -    , failsOnGens2-    , failsOnInvalid2+    -- **** Three arguments+    equivalentOnGens3,+    equivalent3,+    equivalentOnArbitrary3, -    , validIfSucceedsOnGen-    , validIfSucceedsOnValid-    , validIfSucceedsOnArbitrary-    , validIfSucceeds+    -- *** First function can fail -    , validIfSucceedsOnGens2-    , validIfSucceedsOnValids2-    , validIfSucceeds2-    , validIfSucceedsOnArbitrary2+    -- **** One argument+    equivalentWhenFirstSucceedsOnGen,+    equivalentWhenFirstSucceeds,+    equivalentWhenFirstSucceedsOnArbitrary, -      -- ** Standard tests involving equivalence of functions-    , equivalentOnGen-    , equivalentOnValid-    , equivalent-    , equivalentOnGens2-    , equivalentOnValids2-    , equivalent2-    , equivalentWhenFirstSucceedsOnGen-    , equivalentWhenFirstSucceedsOnValid-    , equivalentWhenFirstSucceeds-    , equivalentWhenFirstSucceedsOnGens2-    , equivalentWhenFirstSucceedsOnValids2-    , equivalentWhenFirstSucceeds2-    , equivalentWhenSecondSucceedsOnGen-    , equivalentWhenSecondSucceedsOnValid-    , equivalentWhenSecondSucceeds-    , equivalentWhenSecondSucceedsOnGens2-    , equivalentWhenSecondSucceedsOnValids2-    , equivalentWhenSecondSucceeds2-    , equivalentWhenSucceedOnGen-    , equivalentWhenSucceedOnValid-    , equivalentWhenSucceed-    , equivalentWhenSucceedOnGens2-    , equivalentWhenSucceedOnValids2-    , equivalentWhenSucceed2+    -- **** Two arguments+    equivalentWhenFirstSucceedsOnGens2,+    equivalentWhenFirstSucceeds2,+    equivalentWhenFirstSucceedsOnArbitrary2, -      -- ** Standard tests involving inverse functions-    , inverseFunctionsOnGen-    , inverseFunctionsOnValid-    , inverseFunctions-    , inverseFunctionsOnArbitrary-    , inverseFunctionsIfFirstSucceedsOnGen-    , inverseFunctionsIfFirstSucceedsOnValid-    , inverseFunctionsIfFirstSucceeds-    , inverseFunctionsIfFirstSucceedsOnArbitrary-    , inverseFunctionsIfSecondSucceedsOnGen-    , inverseFunctionsIfSecondSucceedsOnValid-    , inverseFunctionsIfSecondSucceeds-    , inverseFunctionsIfSecondSucceedsOnArbitrary-    , inverseFunctionsIfSucceedOnGen-    , inverseFunctionsIfSucceedOnValid-    , inverseFunctionsIfSucceed-    , inverseFunctionsIfSucceedOnArbitrary+    -- *** Second function can fail -      -- ** Properties involving idempotence-    , idempotentOnGen-    , idempotentOnValid-    , idempotent-    , idempotentOnArbitrary+    -- **** One argument+    equivalentWhenSecondSucceedsOnGen,+    equivalentWhenSecondSucceeds,+    equivalentWhenSecondSucceedsOnArbitrary, +    -- **** Two arguments+    equivalentWhenSecondSucceedsOnGens2,+    equivalentWhenSecondSucceeds2,+    equivalentWhenSecondSucceedsOnArbitrary2, -      -- * Properties of relations+    -- *** Both functions can fail -      -- ** Reflexivity-    , reflexiveOnElem-    , reflexivityOnGen-    , reflexivityOnValid-    , reflexivity-    , reflexivityOnArbitrary+    -- **** One argument+    equivalentWhenSucceedOnGen,+    equivalentWhenSucceed,+    equivalentWhenSucceedOnArbitrary, -      -- ** Transitivity-    , transitiveOnElems-    , transitivityOnGens-    , transitivityOnValid-    , transitivity-    , transitivityOnArbitrary+    -- **** Two arguments+    equivalentWhenSucceedOnGens2,+    equivalentWhenSucceed2,+    equivalentWhenSucceedOnArbitrary2, -      -- ** Antisymmetry-    , antisymmetricOnElemsWithEquality-    , antisymmetryOnGensWithEquality-    , antisymmetryOnGensEq-    , antisymmetryOnValid-    , antisymmetry-    , antisymmetryOnArbitrary+    -- ** Standard tests involving inverse functions+    inverseFunctionsOnGen,+    inverseFunctions,+    inverseFunctionsOnArbitrary,+    inverseFunctionsIfFirstSucceedsOnGen,+    inverseFunctionsIfFirstSucceeds,+    inverseFunctionsIfFirstSucceedsOnArbitrary,+    inverseFunctionsIfSecondSucceedsOnGen,+    inverseFunctionsIfSecondSucceeds,+    inverseFunctionsIfSecondSucceedsOnArbitrary,+    inverseFunctionsIfSucceedOnGen,+    inverseFunctionsIfSucceed,+    inverseFunctionsIfSucceedOnArbitrary, -      -- ** Symmetry-    , symmetricOnElems-    , symmetryOnGens-    , symmetryOnValid-    , symmetry-    , symmetryOnArbitrary+    -- ** Properties involving idempotence+    idempotentOnGen,+    idempotent,+    idempotentOnArbitrary, +    -- * Properties of relations -      -- * Properties of operations+    -- ** Reflexivity+    reflexiveOnElem,+    reflexivityOnGen,+    reflexivity,+    reflexivityOnArbitrary, -      -- ** Identity element+    -- ** Transitivity+    transitiveOnElems,+    transitivityOnGens,+    transitivity,+    transitivityOnArbitrary, -      -- *** Left Identity-    , leftIdentityOnElemWithEquality-    , leftIdentityOnGenWithEquality-    , leftIdentityOnGen-    , leftIdentityOnValid-    , leftIdentity+    -- ** Antisymmetry+    antisymmetricOnElemsWithEquality,+    antisymmetryOnGensWithEquality,+    antisymmetryOnGens,+    antisymmetry,+    antisymmetryOnArbitrary, -      -- *** Right Identity-    , rightIdentityOnElemWithEquality-    , rightIdentityOnGenWithEquality-    , rightIdentityOnGen-    , rightIdentityOnValid-    , rightIdentity+    -- ** Antireflexivity+    antireflexiveOnElem,+    antireflexivityOnGen,+    antireflexivity,+    antireflexivityOnArbitrary, -      -- *** Identity-    , identityOnGen-    , identityOnValid-    , identity+    -- ** Symmetry+    symmetricOnElems,+    symmetryOnGens,+    symmetry,+    symmetryOnArbitrary, -      -- ** Associativity-    , associativeOnGens-    , associativeOnValids-    , associative-    , associativeOnArbitrary+    -- * Properties of operations -      -- ** Commutativity-    , commutativeOnGens-    , commutativeOnValids-    , commutative-    , commutativeOnArbitrary+    -- ** Identity element +    -- *** Left Identity+    leftIdentityOnElemWithEquality,+    leftIdentityOnGenWithEquality,+    leftIdentityOnGen,+    leftIdentity,+    leftIdentityOnArbitrary, -      -- * Eq properties-    , eqSpec+    -- *** Right Identity+    rightIdentityOnElemWithEquality,+    rightIdentityOnGenWithEquality,+    rightIdentityOnGen,+    rightIdentity,+    rightIdentityOnArbitrary, -      -- * Ord properties-    , ordSpec-    ) where+    -- *** Identity+    identityOnGen,+    identity,+    identityOnArbitrary, -import           Data.GenValidity-import           Data.Data+    -- ** Associativity+    associativeOnGens,+    associative,+    associativeOnArbitrary, -import           Test.Validity.Arbitrary-import           Test.Validity.Eq-import           Test.Validity.Functions-import           Test.Validity.GenRelativeValidity-import           Test.Validity.GenValidity-import           Test.Validity.Operations-import           Test.Validity.Ord-import           Test.Validity.Relations-import           Test.Validity.RelativeValidity-import           Test.Validity.Types+    -- ** Commutativity+    commutativeOnGens,+    commutative,+    commutativeOnArbitrary,++    -- * Show and Read properties+    showReadSpec,+    showReadSpecOnArbitrary,+    showReadSpecOnGen,++    -- * Eq properties+    eqSpec,+    eqSpecOnArbitrary,+    eqSpecOnGen,++    -- * Ord properties+    ordSpecOnGen,+    ordSpec,+    ordSpecOnArbitrary,++    -- * Monoid properties+    monoidSpec,+    monoidSpecOnArbitrary,+    monoidSpecOnGen,++    -- * Functor properties+    functorSpec,+    functorSpecOnArbitrary,+    functorSpecOnGens,++    -- * Applicative properties+    applicativeSpec,+    applicativeSpecOnArbitrary,+    applicativeSpecOnGens,++    -- * Monad properties+    monadSpec,+    monadSpecOnArbitrary,+    monadSpecOnGens,++    -- * Re-exports+    module Data.GenValidity,+  )+where++import Data.GenValidity+import Test.Validity.Applicative+import Test.Validity.Arbitrary+import Test.Validity.Eq+import Test.Validity.Functions+import Test.Validity.Functor+import Test.Validity.GenValidity+import Test.Validity.Monad+import Test.Validity.Monoid+import Test.Validity.Operations+import Test.Validity.Ord+import Test.Validity.Property+import Test.Validity.Show+import Test.Validity.Shrinking+import Test.Validity.Utils
+ src/Test/Validity/Applicative.hs view
@@ -0,0 +1,296 @@+{-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}++-- | Applicative properties+--+-- You will need @TypeApplications@ to use these.+module Test.Validity.Applicative+  ( applicativeSpec,+    applicativeSpecOnArbitrary,+    applicativeSpecOnGens,+  )+where++import Data.Data+import Data.GenValidity+import Data.Kind+import GHC.Stack+import Test.Hspec+import Test.QuickCheck+import Test.Validity.Functions+import Test.Validity.Utils++{-# ANN module "HLint: ignore Avoid lambda" #-}++pureTypeStr ::+  forall (f :: Type -> Type).+  (Typeable f) =>+  String+pureTypeStr = unwords ["pure", "::", "a", "->", nameOf @f, "a"]++seqTypeStr ::+  forall (f :: Type -> Type).+  (Typeable f) =>+  String+seqTypeStr =+  unwords+    [ "(<*>)",+      "::",+      nameOf @f,+      "(a",+      "->",+      "b)",+      "->",+      nameOf @f,+      "a",+      "->",+      nameOf @f,+      "b"+    ]++seqrTypeStr ::+  forall (f :: Type -> Type).+  (Typeable f) =>+  String+seqrTypeStr =+  unwords+    [ "(*>)",+      "::",+      nameOf @f,+      "a",+      "->",+      nameOf @f,+      "b",+      "->",+      nameOf @f,+      "b"+    ]++seqlTypeStr ::+  forall (f :: Type -> Type).+  (Typeable f) =>+  String+seqlTypeStr =+  unwords+    [ "(<*)",+      "::",+      nameOf @f,+      "a",+      "->",+      nameOf @f,+      "b",+      "->",+      nameOf @f,+      "a"+    ]++-- | Standard test spec for properties of Applicative instances for values generated with GenValid instances+--+-- Example usage:+--+-- > applicativeSpecOnArbitrary @[]+applicativeSpec ::+  forall (f :: Type -> Type).+  ( HasCallStack,+    Eq (f Int),+    Show (f Int),+    Applicative f,+    Typeable f,+    GenValid (f Int)+  ) =>+  Spec+applicativeSpec = withFrozenCallStack $ applicativeSpecWithInts @f genValid++-- | Standard test spec for properties of Applicative instances for values generated with Arbitrary instances+--+-- Example usage:+--+-- > applicativeSpecOnArbitrary @[]+applicativeSpecOnArbitrary ::+  forall (f :: Type -> Type).+  ( HasCallStack,+    Eq (f Int),+    Show (f Int),+    Applicative f,+    Typeable f,+    Arbitrary (f Int)+  ) =>+  Spec+applicativeSpecOnArbitrary = withFrozenCallStack $ applicativeSpecWithInts @f arbitrary++applicativeSpecWithInts ::+  forall (f :: Type -> Type).+  (HasCallStack, Show (f Int), Eq (f Int), Applicative f, Typeable f) =>+  Gen (f Int) ->+  Spec+applicativeSpecWithInts gen =+  withFrozenCallStack $+    applicativeSpecOnGens+      @f+      @Int+      genValid+      "int"+      gen+      (unwords [nameOf @f, "of ints"])+      gen+      (unwords [nameOf @f, "of ints"])+      ((+) <$> genValid)+      "increments"+      (pure <$> ((+) <$> genValid))+      (unwords [nameOf @f, "of increments"])+      (pure <$> ((*) <$> genValid))+      (unwords [nameOf @f, "of scalings"])++-- | Standard test spec for properties of Applicative instances for values generated by given generators (and names for those generator).+--+-- Unless you are building a specific regression test, you probably want to use the other 'applicativeSpec' functions.+--+-- Example usage:+--+-- > applicativeSpecOnGens+-- >     @Maybe+-- >     @String+-- >     (pure "ABC")+-- >     "ABC"+-- >     (Just <$> pure "ABC")+-- >     "Just an ABC"+-- >     (pure Nothing)+-- >     "purely Nothing"+-- >     ((++) <$> genValid)+-- >     "prepends"+-- >     (pure <$> ((++) <$> genValid))+-- >     "prepends in a Just"+-- >     (pure <$> (flip (++) <$> genValid))+-- >     "appends in a Just"+applicativeSpecOnGens ::+  forall (f :: Type -> Type) (a :: Type) (b :: Type) (c :: Type).+  ( HasCallStack,+    Show a,+    Show (f a),+    Eq (f a),+    Show (f b),+    Eq (f b),+    Show (f c),+    Eq (f c),+    Applicative f,+    Typeable f,+    Typeable a,+    Typeable b,+    Typeable c+  ) =>+  Gen a ->+  String ->+  Gen (f a) ->+  String ->+  Gen (f b) ->+  String ->+  Gen (a -> b) ->+  String ->+  Gen (f (a -> b)) ->+  String ->+  Gen (f (b -> c)) ->+  String ->+  Spec+applicativeSpecOnGens gena genaname gen genname genb genbname genfa genfaname genffa genffaname genffb genffbname =+  withFrozenCallStack $+    parallel $+      describe ("Applicative " ++ nameOf @f) $ do+        describe (unwords [pureTypeStr @f, "and", seqTypeStr @f]) $ do+          it+            ( unwords+                [ "satisfy the identity law: 'pure id <*> v = v' for",+                  genDescr @(f a) genname+                ]+            )+            $ equivalentOnGen (pure id <*>) id gen shrinkNothing+          it+            ( unwords+                [ "satisfy the composition law: 'pure (.) <*> u <*> v <*> w = u <*> (v <*> w)' for",+                  genDescr @(f (b -> c)) genffbname,+                  "composed with",+                  genDescr @(f (a -> b)) genffaname,+                  "and applied to",+                  genDescr @(f a) genname+                ]+            )+            $ equivalentOnGens3+              ( \(Anon u) (Anon v) w ->+                  pure (.)+                    <*> (u :: f (b -> c))+                    <*> (v :: f (a -> b))+                    <*> (w :: f a) ::+                    f c+              )+              (\(Anon u) (Anon v) w -> u <*> (v <*> w) :: f c)+              ((,,) <$> (Anon <$> genffb) <*> (Anon <$> genffa) <*> gen)+              shrinkNothing+          it+            ( unwords+                [ "satisfy the homomorphism law: 'pure f <*> pure x = pure (f x)' for",+                  genDescr @(a -> b) genfaname,+                  "sequenced with",+                  genDescr @a genaname+                ]+            )+            $ equivalentOnGens2+              (\(Anon f) x -> pure f <*> pure x :: f b)+              (\(Anon f) x -> pure $ f x :: f b)+              ((,) <$> (Anon <$> genfa) <*> gena)+              shrinkNothing+          it+            ( unwords+                [ "satisfy the interchange law: 'u <*> pure y = pure ($ y) <*> u' for",+                  genDescr @(f (a -> b)) genffaname,+                  "sequenced with",+                  genDescr @a genaname+                ]+            )+            $ equivalentOnGens2+              (\(Anon u) y -> u <*> pure y :: f b)+              (\(Anon u) y -> pure ($ y) <*> u :: f b)+              ((,) <$> (Anon <$> genffa) <*> gena)+              shrinkNothing+          it+            ( unwords+                [ "satisfy the law about the functor instance: fmap f x = pure f <*> x for",+                  genDescr @(a -> b) genfaname,+                  "mapped over",+                  genDescr @(f a) genname+                ]+            )+            $ equivalentOnGens2+              (\(Anon f) x -> fmap f x)+              (\(Anon f) x -> pure f <*> x)+              ((,) <$> (Anon <$> genfa) <*> gen)+              shrinkNothing+        describe (seqrTypeStr @f)+          $ it+            ( unwords+                [ "is equivalent to its default implementation 'u Type> v = pure (const id) <*> u <*> v' for",+                  genDescr @(f a) genname,+                  "in front of",+                  genDescr @b genbname+                ]+            )+          $ equivalentOnGens2+            (\u v -> u *> v)+            (\u v -> pure (const id) <*> u <*> v)+            ((,) <$> gen <*> genb)+            shrinkNothing+        describe (seqlTypeStr @f)+          $ it+            ( unwords+                [ "is equivalent to its default implementation 'u <* v = pure const <*> u <*> v' for",+                  genDescr @b genbname,+                  "behind",+                  genDescr @(f a) genname+                ]+            )+          $ equivalentOnGens2+            (\u v -> u <* v)+            (\u v -> pure const <*> u <*> v)+            ((,) <$> gen <*> genb)+            shrinkNothing
src/Test/Validity/Arbitrary.hs view
@@ -1,60 +1,46 @@+{-# LANGUAGE AllowAmbiguousTypes #-} {-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE ScopedTypeVariables   #-}-module Test.Validity.Arbitrary-    ( -- * Tests for Arbitrary instances involving Validity-      arbitrarySpec-    , arbitraryGeneratesOnlyValid-    , shrinkProducesOnlyValids-    ) where--import           Data.Data-import           Data.Proxy--import           Data.GenValidity+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-} -import           Test.Hspec-import           Test.QuickCheck+-- | Tests for Arbitrary instances involving Validity+--+-- You will need @TypeApplications@ to use these.+module Test.Validity.Arbitrary+  ( arbitrarySpec,+    arbitraryGeneratesOnlyValid,+  )+where -import           Test.Validity.Utils-import           Test.Validity.GenValidity+import Data.Data+import Data.GenValidity+import Test.Hspec+import Test.QuickCheck+import Test.Validity.GenValidity+import Test.Validity.Utils  -- | A @Spec@ that specifies that @arbitrary@ only generates data that--- satisfy @isValid@ and that @shrink@ only produces data that satisfy--- @isValid@.+-- satisfy @isValid@ -- -- Example usage: ----- > arbitrarySpec (Proxy :: Proxy MyData)-arbitrarySpec-    :: (Typeable a, Show a, Validity a, Arbitrary a)-    => Proxy a-    -> Spec-arbitrarySpec proxy = do-    let name = nameOf proxy-    describe ("Arbitrary " ++ name) $ do-        it ("is instantiated such that 'arbitrary' only generates valid \'"-            ++ name-            ++ "\'s.") $-            arbitraryGeneratesOnlyValid proxy--        it ("is instantiated such that 'shrink' only produces valid \'"-            ++ name-            ++ "\'s.") $-            forAll arbitrary $ \a ->-                shrink (a `asProxyTypeOf` proxy) `shouldSatisfy` all isValid+-- > arbitrarySpec @Int+arbitrarySpec ::+  forall a.+  (Typeable a, Show a, Validity a, Arbitrary a) =>+  Spec+arbitrarySpec = do+  let name = nameOf @a+  describe ("Arbitrary " ++ name) $+    describe ("arbitrary :: Gen " ++ name) $+      it "only generates valid values" $+        arbitraryGeneratesOnlyValid @a  -- | @arbitrary@ only generates valid data-arbitraryGeneratesOnlyValid-    :: forall a. (Show a, Validity a, Arbitrary a)-    => Proxy a-    -> Property-arbitraryGeneratesOnlyValid _ =-    genGeneratesValid (arbitrary :: Gen a)---- | @shrink@, applied to valid data only produces valid data-shrinkProducesOnlyValids-    :: forall a. (Show a, Validity a, Arbitrary a)-    => Proxy a-    -> Property-shrinkProducesOnlyValids _ =-    genGeneratesValid (shrink <$> arbitrary :: Gen [a])+--+-- prop> arbitraryGeneratesOnlyValid @Int+arbitraryGeneratesOnlyValid ::+  forall a.+  (Show a, Validity a, Arbitrary a) =>+  Property+arbitraryGeneratesOnlyValid = genGeneratesValid @a arbitrary
src/Test/Validity/Eq.hs view
@@ -1,47 +1,130 @@+{-# LANGUAGE AllowAmbiguousTypes #-} {-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE ScopedTypeVariables   #-}-module Test.Validity.Eq-    ( -- * Eq properties-      eqSpec-    ) where--import           Data.Data-import           Data.Proxy+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-} -import           Data.GenValidity+-- | Eq properties+--+-- You will need @TypeApplications@ to use these.+module Test.Validity.Eq+  ( eqSpec,+    eqSpecOnArbitrary,+    eqSpecOnGen,+  )+where -import           Test.Hspec+import Data.Data+import Data.GenValidity+import Test.Hspec+import Test.QuickCheck+import Test.Validity.Functions+import Test.Validity.Relations+import Test.Validity.Utils -import           Test.Validity.Relations-import           Test.Validity.Utils+eqTypeStr ::+  forall a.+  (Typeable a) =>+  String+eqTypeStr = binRelStr @a "==" -eqSpec-    :: (Show a, Eq a, Typeable a, GenValidity a)-    => Proxy a-    -> Spec-eqSpec proxy = do-    let name = nameOf proxy-        funeqstr = unwords-          [ "(==) ::"-          , name-          , "->"-          , name-          , "-> Bool"-          ]-        eq a b = a `asProxyTypeOf` proxy == b-    describe ("Eq " ++ name) $ do-        it ("is instantated such that "-            ++ funeqstr-            ++ " is reflexive") $-            reflexivity eq+neqTypeStr ::+  forall a.+  (Typeable a) =>+  String+neqTypeStr = binRelStr @a "/=" -        it ("is instantated such that "-            ++ funeqstr-            ++ " is symmetric") $-            symmetry eq+-- | Standard test spec for properties of Eq instances for valid values+--+-- Example usage:+--+-- > eqSpec @Int+eqSpec ::+  forall a.+  (Show a, Eq a, Typeable a, GenValid a) =>+  Spec+eqSpec = eqSpecOnGen @a genValid "valid" shrinkValid -        it ("is instantated such that "-            ++ funeqstr-            ++ " is transitive") $-            transitivity eq+-- | Standard test spec for properties of Eq instances for arbitrary values+--+-- Example usage:+--+-- > eqSpecOnArbitrary @Int+eqSpecOnArbitrary ::+  forall a.+  (Show a, Eq a, Typeable a, Arbitrary a) =>+  Spec+eqSpecOnArbitrary = eqSpecOnGen @a arbitrary "arbitrary" shrink +-- | Standard test spec for properties of Eq instances for values generated by a given generator (and name for that generator).+--+-- Example usage:+--+-- > eqSpecOnGen ((* 2) <$> genValid @Int) "even"+eqSpecOnGen ::+  forall a.+  (Show a, Eq a, Typeable a) =>+  Gen a ->+  String ->+  (a -> [a]) ->+  Spec+eqSpecOnGen gen genname s =+  parallel $ do+    let name = nameOf @a+        funeqstr = eqTypeStr @a+        funneqstr = neqTypeStr @a+        gen2 = (,) <$> gen <*> gen+        gen3 = (,,) <$> gen <*> gen <*> gen+        s2 = shrinkT2 s+    describe ("Eq " ++ name) $ do+      let eq = (==) @a+          neq = (/=) @a+      describe funeqstr $ do+        it+          ( unwords+              [ "is reflexive for",+                "\"" ++ genname,+                name ++ "\"" ++ "s"+              ]+          )+          $ reflexivityOnGen eq gen s+        it+          ( unwords+              [ "is symmetric for",+                "\"" ++ genname,+                name ++ "\"" ++ "s"+              ]+          )+          $ symmetryOnGens eq gen2 s+        it+          ( unwords+              [ "is transitive for",+                "\"" ++ genname,+                name ++ "\"" ++ "s"+              ]+          )+          $ transitivityOnGens eq gen3 s+        it+          ( unwords+              [ "is equivalent to (\\a b -> not $ a /= b) for",+                "\"" ++ genname,+                name ++ "\"" ++ "s"+              ]+          )+          $ equivalentOnGens2 eq (\a b -> not $ a `neq` b) gen2 s2+      describe funneqstr $ do+        it+          ( unwords+              [ "is antireflexive for",+                "\"" ++ genname,+                name ++ "\"" ++ "s"+              ]+          )+          $ antireflexivityOnGen neq gen s+        it+          ( unwords+              [ "is equivalent to (\\a b -> not $ a == b) for",+                "\"" ++ genname,+                name ++ "\"" ++ "s"+              ]+          )+          $ equivalentOnGens2 neq (\a b -> not $ a `eq` b) gen2 s2
− src/Test/Validity/Functions.hs
@@ -1,103 +0,0 @@-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE ScopedTypeVariables   #-}-module Test.Validity.Functions-    ( -- * Validity tests involving functions--      -- ** Standard tests involving validity-      producesValidsOnGen-    , producesValidsOnValids-    , producesValid-    , producesValidsOnArbitrary-    , producesValidsOnGens2-    , producesValidsOnValids2-    , producesValid2-    , producesValidsOnArbitrary2-    , producesValidsOnGens3-    , producesValidsOnValids3-    , producesValid3-    , producesValidsOnArbitrary3--      -- ** Standard tests involving functions that can fail-    , succeedsOnGen-    , succeedsOnValid-    , succeeds-    , succeedsOnArbitrary--    , succeedsOnGens2-    , succeedsOnValids2-    , succeeds2-    , succeedsOnArbitrary2--    , failsOnGen-    , failsOnInvalid--    , failsOnGens2-    , failsOnInvalid2--    , validIfSucceedsOnGen-    , validIfSucceedsOnValid-    , validIfSucceedsOnArbitrary-    , validIfSucceeds--    , validIfSucceedsOnGens2-    , validIfSucceedsOnValids2-    , validIfSucceeds2-    , validIfSucceedsOnArbitrary2--      -- ** Standard tests involving equivalence of functions-    , equivalentOnGen-    , equivalentOnValid-    , equivalent-    , equivalentOnGens2-    , equivalentOnValids2-    , equivalent2-    , equivalentWhenFirstSucceedsOnGen-    , equivalentWhenFirstSucceedsOnValid-    , equivalentWhenFirstSucceeds-    , equivalentWhenFirstSucceedsOnGens2-    , equivalentWhenFirstSucceedsOnValids2-    , equivalentWhenFirstSucceeds2-    , equivalentWhenSecondSucceedsOnGen-    , equivalentWhenSecondSucceedsOnValid-    , equivalentWhenSecondSucceeds-    , equivalentWhenSecondSucceedsOnGens2-    , equivalentWhenSecondSucceedsOnValids2-    , equivalentWhenSecondSucceeds2-    , equivalentWhenSucceedOnGen-    , equivalentWhenSucceedOnValid-    , equivalentWhenSucceed-    , equivalentWhenSucceedOnGens2-    , equivalentWhenSucceedOnValids2-    , equivalentWhenSucceed2--      -- ** Standard tests involving inverse functions-    , inverseFunctionsOnGen-    , inverseFunctionsOnValid-    , inverseFunctions-    , inverseFunctionsOnArbitrary-    , inverseFunctionsIfFirstSucceedsOnGen-    , inverseFunctionsIfFirstSucceedsOnValid-    , inverseFunctionsIfFirstSucceeds-    , inverseFunctionsIfFirstSucceedsOnArbitrary-    , inverseFunctionsIfSecondSucceedsOnGen-    , inverseFunctionsIfSecondSucceedsOnValid-    , inverseFunctionsIfSecondSucceeds-    , inverseFunctionsIfSecondSucceedsOnArbitrary-    , inverseFunctionsIfSucceedOnGen-    , inverseFunctionsIfSucceedOnValid-    , inverseFunctionsIfSucceed-    , inverseFunctionsIfSucceedOnArbitrary--      -- ** Properties involving idempotence-    , idempotentOnGen-    , idempotentOnValid-    , idempotent-    , idempotentOnArbitrary-    ) where--import           Test.Validity.Functions.CanFail-import           Test.Validity.Functions.Equivalence-import           Test.Validity.Functions.Idempotence-import           Test.Validity.Functions.Inverse-import           Test.Validity.Functions.Validity-
− src/Test/Validity/Functions/CanFail.hs
@@ -1,223 +0,0 @@-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE ScopedTypeVariables   #-}-module Test.Validity.Functions.CanFail-    ( -- ** Standard tests involving functions that can fail-      succeedsOnGen-    , succeedsOnValid-    , succeeds-    , succeedsOnArbitrary--    , succeedsOnGens2-    , succeedsOnValids2-    , succeeds2-    , succeedsOnArbitrary2--    , failsOnGen-    , failsOnInvalid--    , failsOnGens2-    , failsOnInvalid2--    , validIfSucceedsOnGen-    , validIfSucceedsOnValid-    , validIfSucceedsOnArbitrary-    , validIfSucceeds--    , validIfSucceedsOnGens2-    , validIfSucceedsOnValids2-    , validIfSucceeds2-    , validIfSucceedsOnArbitrary2-    ) where--import           Data.GenValidity--import           Test.Hspec-import           Test.QuickCheck--import           Test.Validity.Types---- | The function succeeds if the input is generated by the given generator-succeedsOnGen-    :: (Show a, Show b, Show (f b), CanFail f)-    => (a -> f b)-    -> Gen a-    -> Property-succeedsOnGen func gen-    = forAll gen $ \a -> func a `shouldNotSatisfy` hasFailed---- | The function succeeds if the input is generated by @genValid@-succeedsOnValid-    :: (Show a, Show b, Show (f b), GenValidity a, CanFail f)-    => (a -> f b)-    -> Property-succeedsOnValid = (`succeedsOnGen` genValid)---- | The function succeeds if the input is generated by @genUnchecked@-succeeds-    :: (Show a, Show b, Show (f b), GenValidity a, CanFail f)-    => (a -> f b)-    -> Property-succeeds = (`succeedsOnGen` genUnchecked)---- | The function succeeds if the input is generated by @arbitrary@-succeedsOnArbitrary-    :: (Show a, Show b, Show (f b), Arbitrary a, CanFail f)-    => (a -> f b)-    -> Property-succeedsOnArbitrary = (`succeedsOnGen` arbitrary)---- | The function fails if the input is generated by the given generator-failsOnGen-    :: (Show a, Show b, Show (f b), CanFail f)-    => (a -> f b)-    -> Gen a-    -> Property-failsOnGen func gen-    = forAll gen $ \a -> func a `shouldSatisfy` hasFailed---- | The function fails if the input is generated by @genInvalid@-failsOnInvalid-    :: (Show a, Show b, Show (f b), GenValidity a, CanFail f)-    => (a -> f b)-    -> Property-failsOnInvalid = (`failsOnGen` genInvalid)---- | The function produces output that satisfies @isValid@ if it is given input--- that is generated by the given generator.-validIfSucceedsOnGen-    :: (Show a, Show b, Show (f b), Validity b, CanFail f)-    => (a -> f b)-    -> Gen a-    -> Property-validIfSucceedsOnGen func gen-    = forAll gen $ \a ->-        case resultIfSucceeded (func a) of-            Nothing  -> return () -- Can happen-            Just res -> res `shouldSatisfy` isValid---- | The function produces output that satisfies @isValid@ if it is given input--- that is generated by @arbitrary@.-validIfSucceedsOnValid-    :: (Show a, Show b, Show (f b), GenValidity a, Validity b, CanFail f)-    => (a -> f b)-    -> Property-validIfSucceedsOnValid = (`validIfSucceedsOnGen` genValid)----- | The function produces output that satisfies @isValid@ if it is given input--- that is generated by @arbitrary@.-validIfSucceedsOnArbitrary-    :: (Show a, Show b, Show (f b), Arbitrary a, Validity b, CanFail f)-    => (a -> f b)-    -> Property-validIfSucceedsOnArbitrary = (`validIfSucceedsOnGen` arbitrary)---- | The function produces output that satisfies @isValid@ if it is given input--- that is generated by @genUnchecked@.-validIfSucceeds-    :: (Show a, Show b, Show (f b), GenValidity a, Validity b, CanFail f)-    => (a -> f b)-    -> Property-validIfSucceeds = (`validIfSucceedsOnGen` genUnchecked)---succeedsOnGens2-    :: (Show a, Show b, Show c, Show (f c),-        CanFail f)-    => (a -> b -> f c)-    -> Gen (a, b)-    -> Property-succeedsOnGens2 func gen =-    forAll gen $ \(a, b) ->-        func a b `shouldNotSatisfy` hasFailed---succeedsOnValids2-    :: (Show a, Show b, Show c, Show (f c),-        GenValidity a, GenValidity b,-        CanFail f)-    => (a -> b -> f c)-    -> Property-succeedsOnValids2 func-    = succeedsOnGens2 func genValid--succeeds2-    :: (Show a, Show b, Show c, Show (f c),-        GenValidity a, GenValidity b,-        CanFail f)-    => (a -> b -> f c)-    -> Property-succeeds2 func-    = succeedsOnGens2 func genUnchecked--succeedsOnArbitrary2-    :: (Show a, Show b, Show c, Show (f c),-        Arbitrary a, Arbitrary b,-        CanFail f)-    => (a -> b -> f c)-    -> Property-succeedsOnArbitrary2 func-    = succeedsOnGens2 func arbitrary---failsOnGens2-    :: (Show a, Show b, Show c, Show (f c),-        CanFail f)-    => (a -> b -> f c)-    -> Gen a -> Gen b-    -> Property-failsOnGens2 func genA genB =-    forAll genA $ \a ->-        forAll genB $ \b ->-            func a b `shouldSatisfy` hasFailed---failsOnInvalid2-    :: (Show a, Show b, Show c, Show (f c),-        GenValidity a, GenValidity b,-        CanFail f)-    => (a -> b -> f c)-    -> Property-failsOnInvalid2 func-    =    failsOnGens2 func genInvalid genUnchecked-    .&&. failsOnGens2 func genUnchecked genInvalid---validIfSucceedsOnGens2-    :: (Show a, Show b, Show c, Show (f c),-        Validity c, CanFail f)-    => (a -> b -> f c)-    -> Gen (a, b)-    -> Property-validIfSucceedsOnGens2 func gen =-    forAll gen $ \(a, b) ->-        case resultIfSucceeded (func a b) of-            Nothing  -> return () -- Can happen-            Just res -> res `shouldSatisfy` isValid--validIfSucceedsOnValids2-    :: (Show a, Show b, Show c, Show (f c),-        GenValidity a, GenValidity b,-        Validity c, CanFail f)-    => (a -> b -> f c)-    -> Property-validIfSucceedsOnValids2 func-    = validIfSucceedsOnGens2 func genValid--validIfSucceeds2-    :: (Show a, Show b, Show c, Show (f c),-        GenValidity a, GenValidity b,-        Validity c, CanFail f)-    => (a -> b -> f c)-    -> Property-validIfSucceeds2 func-    = validIfSucceedsOnGens2 func genUnchecked--validIfSucceedsOnArbitrary2-    :: (Show a, Show b, Show c, Show (f c),-        Arbitrary a, Arbitrary b,-        Validity c, CanFail f)-    => (a -> b -> f c)-    -> Property-validIfSucceedsOnArbitrary2 func-    = validIfSucceedsOnGens2 func arbitrary
− src/Test/Validity/Functions/Equivalence.hs
@@ -1,295 +0,0 @@-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE ScopedTypeVariables   #-}-module Test.Validity.Functions.Equivalence-    ( -- ** Standard tests involving equivalence of functions-      equivalentOnGen-    , equivalentOnValid-    , equivalent-    , equivalentOnGens2-    , equivalentOnValids2-    , equivalent2-    , equivalentWhenFirstSucceedsOnGen-    , equivalentWhenFirstSucceedsOnValid-    , equivalentWhenFirstSucceeds-    , equivalentWhenFirstSucceedsOnGens2-    , equivalentWhenFirstSucceedsOnValids2-    , equivalentWhenFirstSucceeds2-    , equivalentWhenSecondSucceedsOnGen-    , equivalentWhenSecondSucceedsOnValid-    , equivalentWhenSecondSucceeds-    , equivalentWhenSecondSucceedsOnGens2-    , equivalentWhenSecondSucceedsOnValids2-    , equivalentWhenSecondSucceeds2-    , equivalentWhenSucceedOnGen-    , equivalentWhenSucceedOnValid-    , equivalentWhenSucceed-    , equivalentWhenSucceedOnGens2-    , equivalentWhenSucceedOnValids2-    , equivalentWhenSucceed2-    ) where--import           Data.GenValidity--import           Test.Hspec-import           Test.QuickCheck--import           Test.Validity.Types--equivalentOnGen-    :: (Show a, Eq a, Show b, Eq b)-    => (a -> b)-    -> (a -> b)-    -> Gen a-    -> Property-equivalentOnGen f g gen =-    forAll gen $ \a ->-        f a `shouldBe` g a--equivalentOnValid-    :: (Show a, Eq a, GenValidity a, Show b, Eq b)-    => (a -> b)-    -> (a -> b)-    -> Property-equivalentOnValid f g-    = equivalentOnGen f g genValid--equivalent-    :: (Show a, Eq a, GenValidity a, Show b, Eq b)-    => (a -> b)-    -> (a -> b)-    -> Property-equivalent f g-    = equivalentOnGen f g genUnchecked--equivalentOnGens2-    :: (Show a, Eq a,-        Show b, Eq b,-        Show c, Eq c)-    => (a -> b -> c)-    -> (a -> b -> c)-    -> Gen (a, b)-    -> Property-equivalentOnGens2 f g gen =-    forAll gen $ \(a, b) ->-        f a b `shouldBe` g a b--equivalentOnValids2-    :: (Show a, Eq a, GenValidity a,-        Show b, Eq b, GenValidity b,-        Show c, Eq c)-    => (a -> b -> c)-    -> (a -> b -> c)-    -> Property-equivalentOnValids2 f g-    = equivalentOnGens2 f g genValid--equivalent2-    :: (Show a, Eq a, GenValidity a,-        Show b, Eq b, GenValidity b,-        Show c, Eq c)-    => (a -> b -> c)-    -> (a -> b -> c)-    -> Property-equivalent2 f g-    = equivalentOnGens2 f g genUnchecked--equivalentWhenFirstSucceedsOnGen-    :: (Show a, Eq a, Show b, Eq b, CanFail f)-    => (a -> f b)-    -> (a -> b)-    -> Gen a-    -> Property-equivalentWhenFirstSucceedsOnGen f g gen =-    forAll gen $ \a ->-        case resultIfSucceeded (f a) of-            Nothing -> return () -- fine-            Just r  -> r `shouldBe` g a--equivalentWhenFirstSucceedsOnValid-    :: (Show a, Eq a, GenValidity a, Show b, Eq b, CanFail f)-    => (a -> f b)-    -> (a -> b)-    -> Property-equivalentWhenFirstSucceedsOnValid f g-    = equivalentWhenFirstSucceedsOnGen f g genValid--equivalentWhenFirstSucceeds-    :: (Show a, Eq a, GenValidity a, Show b, Eq b, CanFail f)-    => (a -> f b)-    -> (a -> b)-    -> Property-equivalentWhenFirstSucceeds f g-    = equivalentWhenFirstSucceedsOnGen f g genUnchecked--equivalentWhenFirstSucceedsOnGens2-    :: (Show a, Eq a,-        Show b, Eq b,-        Show c, Eq c,-        CanFail f)-    => (a -> b -> f c)-    -> (a -> b -> c)-    -> Gen (a, b)-    -> Property-equivalentWhenFirstSucceedsOnGens2 f g gen =-    forAll gen $ \(a, b) ->-        case resultIfSucceeded (f a b) of-            Nothing -> return () -- fine-            Just rs -> rs `shouldBe` g a b--equivalentWhenFirstSucceedsOnValids2-    :: (Show a, Eq a, GenValidity a,-        Show b, Eq b, GenValidity b,-        Show c, Eq c,-        CanFail f)-    => (a -> b -> f c)-    -> (a -> b -> c)-    -> Property-equivalentWhenFirstSucceedsOnValids2 f g-    = equivalentWhenFirstSucceedsOnGens2 f g genValid--equivalentWhenFirstSucceeds2-    :: (Show a, Eq a, GenValidity a,-        Show b, Eq b, GenValidity b,-        Show c, Eq c,-        CanFail f)-    => (a -> b -> f c)-    -> (a -> b -> c)-    -> Property-equivalentWhenFirstSucceeds2 f g-    = equivalentWhenFirstSucceedsOnGens2 f g genUnchecked--equivalentWhenSecondSucceedsOnGen-    :: (Show a, Eq a, Show b, Eq b, CanFail f)-    => (a -> b)-    -> (a -> f b)-    -> Gen a-    -> Property-equivalentWhenSecondSucceedsOnGen f g gen =-    forAll gen $ \a ->-        case resultIfSucceeded (g a) of-            Nothing -> return () -- fine-            Just r  -> r `shouldBe` f a--equivalentWhenSecondSucceedsOnValid-    :: (Show a, Eq a, GenValidity a, Show b, Eq b, CanFail f)-    => (a -> b)-    -> (a -> f b)-    -> Property-equivalentWhenSecondSucceedsOnValid f g-    = equivalentWhenSecondSucceedsOnGen f g genValid--equivalentWhenSecondSucceeds-    :: (Show a, Eq a, GenValidity a, Show b, Eq b, CanFail f)-    => (a -> b)-    -> (a -> f b)-    -> Property-equivalentWhenSecondSucceeds f g-    = equivalentWhenSecondSucceedsOnGen f g genUnchecked--equivalentWhenSecondSucceedsOnGens2-    :: (Show a, Eq a,-        Show b, Eq b,-        Show c, Eq c,-        CanFail f)-    => (a -> b -> c)-    -> (a -> b -> f c)-    -> Gen (a, b)-    -> Property-equivalentWhenSecondSucceedsOnGens2 f g gen =-    forAll gen $ \(a, b) ->-        case resultIfSucceeded (g a b) of-            Nothing -> return () -- fine-            Just rs -> rs `shouldBe` f a b--equivalentWhenSecondSucceedsOnValids2-    :: (Show a, Eq a, GenValidity a,-         Show b, Eq b, GenValidity b,-         Show c, Eq c,-         CanFail f)-    => (a -> b -> c)-    -> (a -> b -> f c)-    -> Property-equivalentWhenSecondSucceedsOnValids2 f g-    = equivalentWhenSecondSucceedsOnGens2 f g genValid--equivalentWhenSecondSucceeds2-    :: (Show a, Eq a, GenValidity a,-        Show b, Eq b, GenValidity b,-        Show c, Eq c,-        CanFail f)-    => (a -> b -> c)-    -> (a -> b -> f c)-    -> Property-equivalentWhenSecondSucceeds2 f g-    = equivalentWhenSecondSucceedsOnGens2 f g genUnchecked--equivalentWhenSucceedOnGen-    :: (Show a, Eq a, Show b, Eq b, CanFail f)-    => (a -> f b)-    -> (a -> f b)-    -> Gen a-    -> Property-equivalentWhenSucceedOnGen f g gen =-    forAll gen $ \a ->-        case do fa <- resultIfSucceeded $ f a-                ga <- resultIfSucceeded $ g a-                return (fa, ga)-            of-            Nothing -> return () -- fine-            Just (fa, ga)  -> fa `shouldBe` ga--equivalentWhenSucceedOnValid-    :: (Show a, Eq a, GenValidity a, Show b, Eq b, CanFail f)-    => (a -> f b)-    -> (a -> f b)-    -> Property-equivalentWhenSucceedOnValid f g-    = equivalentWhenSucceedOnGen f g genValid--equivalentWhenSucceed-    :: (Show a, Eq a, GenValidity a, Show b, Eq b, CanFail f)-    => (a -> f b)-    -> (a -> f b)-    -> Property-equivalentWhenSucceed f g-    = equivalentWhenSucceedOnGen f g genUnchecked--equivalentWhenSucceedOnGens2-    :: (Show a, Eq a,-        Show b, Eq b,-        Show c, Eq c,-        CanFail f)-    => (a -> b -> f c)-    -> (a -> b -> f c)-    -> Gen (a, b)-    -> Property-equivalentWhenSucceedOnGens2 f g gen =-    forAll gen $ \(a, b) ->-        case do fab <- resultIfSucceeded $ f a b-                gab <- resultIfSucceeded $ g a b-                return (fab, gab)-                of-            Nothing -> return () -- fine-            Just (fab, gab) -> fab `shouldBe` gab--equivalentWhenSucceedOnValids2-    :: (Show a, Eq a, GenValidity a,-        Show b, Eq b, GenValidity b,-        Show c, Eq c,-        CanFail f)-    => (a -> b -> f c)-    -> (a -> b -> f c)-    -> Property-equivalentWhenSucceedOnValids2 f g-    = equivalentWhenSucceedOnGens2 f g genValid--equivalentWhenSucceed2-    :: (Show a, Eq a, GenValidity a,-        Show b, Eq b, GenValidity b,-        Show c, Eq c,-        CanFail f)-    => (a -> b -> f c)-    -> (a -> b -> f c)-    -> Property-equivalentWhenSucceed2 f g-    = equivalentWhenSucceedOnGens2 f g genUnchecked
− src/Test/Validity/Functions/Idempotence.hs
@@ -1,50 +0,0 @@-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE ScopedTypeVariables   #-}-module Test.Validity.Functions.Idempotence-    ( -- ** Standard tests involving validity-      idempotentOnGen-    , idempotentOnValid-    , idempotent-    , idempotentOnArbitrary-    ) where--import           Data.GenValidity--import           Test.Hspec-import           Test.QuickCheck--idempotentOnGen-    :: (Show a, Eq a)-    => (a -> a)-    -> Gen a-    -> Property-idempotentOnGen f gen-    = forAll gen $ \a ->-        f (f a) `shouldBe` f a--idempotentOnValid-    :: (Show a, Eq a, GenValidity a)-    => (a -> a)-    -> Property-idempotentOnValid func = idempotentOnGen func genValid--idempotent-    :: (Show a, Eq a, GenValidity a)-    => (a -> a)-    -> Property-idempotent func = idempotentOnGen func genUnchecked---- |------ 'id' is idempotent for any type:------ prop> idempotentOnArbitrary (id :: Int -> Int)------ 'const', given any input, is idempotent for any type as well:------ prop> \int -> idempotentOnArbitrary (const int :: Int -> Int)-idempotentOnArbitrary-    :: (Show a, Eq a, Arbitrary a)-    => (a -> a)-    -> Property-idempotentOnArbitrary func = idempotentOnGen func arbitrary
− src/Test/Validity/Functions/Inverse.hs
@@ -1,185 +0,0 @@-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE ScopedTypeVariables   #-}-module Test.Validity.Functions.Inverse-    ( -- ** Standard tests involving inverse functions-      inverseFunctionsOnGen-    , inverseFunctionsOnValid-    , inverseFunctions-    , inverseFunctionsOnArbitrary-    , inverseFunctionsIfFirstSucceedsOnGen-    , inverseFunctionsIfFirstSucceedsOnValid-    , inverseFunctionsIfFirstSucceeds-    , inverseFunctionsIfFirstSucceedsOnArbitrary-    , inverseFunctionsIfSecondSucceedsOnGen-    , inverseFunctionsIfSecondSucceedsOnValid-    , inverseFunctionsIfSecondSucceeds-    , inverseFunctionsIfSecondSucceedsOnArbitrary-    , inverseFunctionsIfSucceedOnGen-    , inverseFunctionsIfSucceedOnValid-    , inverseFunctionsIfSucceed-    , inverseFunctionsIfSucceedOnArbitrary-    ) where--import           Data.GenValidity--import           Test.Hspec-import           Test.QuickCheck--import           Test.Validity.Types--inverseFunctionsOnGen-    :: (Show a, Eq a)-    => (a -> b)-    -> (b -> a)-    -> Gen a-    -> Property-inverseFunctionsOnGen f g gen =-    forAll gen $ \a ->-      g (f a) `shouldBe` a---inverseFunctionsOnValid-    :: (Show a, Eq a, GenValidity a)-    => (a -> b)-    -> (b -> a)-    -> Property-inverseFunctionsOnValid f g-    = inverseFunctionsOnGen f g genValid---inverseFunctions-    :: (Show a, Eq a, GenValidity a)-    => (a -> b)-    -> (b -> a)-    -> Property-inverseFunctions f g-    = inverseFunctionsOnGen f g genUnchecked---- |--- 'id' is its own inverse function for every type:--- prop> inverseFunctionsOnArbitrary id (id :: Int -> Int)-inverseFunctionsOnArbitrary-    :: (Show a, Eq a, Arbitrary a)-    => (a -> b)-    -> (b -> a)-    -> Property-inverseFunctionsOnArbitrary f g-    = inverseFunctionsOnGen f g arbitrary---inverseFunctionsIfFirstSucceedsOnGen-    :: (Show a, Eq a, CanFail f)-    => (a -> f b)-    -> (b -> a)-    -> Gen a-    -> Property-inverseFunctionsIfFirstSucceedsOnGen f g gen =-    forAll gen $ \a ->-      case resultIfSucceeded (f a) of-          Nothing -> return () -- fine-          Just b  -> g b `shouldBe` a---inverseFunctionsIfFirstSucceedsOnValid-    :: (Show a, Eq a, GenValidity a, CanFail f)-    => (a -> f b)-    -> (b -> a)-    -> Property-inverseFunctionsIfFirstSucceedsOnValid f g-    = inverseFunctionsIfFirstSucceedsOnGen f g genValid---inverseFunctionsIfFirstSucceeds-    :: (Show a, Eq a, GenValidity a, CanFail f)-    => (a -> f b)-    -> (b -> a)-    -> Property-inverseFunctionsIfFirstSucceeds f g-    = inverseFunctionsIfFirstSucceedsOnGen f g genUnchecked--inverseFunctionsIfFirstSucceedsOnArbitrary-    :: (Show a, Eq a, Arbitrary a, CanFail f)-    => (a -> f b)-    -> (b -> a)-    -> Property-inverseFunctionsIfFirstSucceedsOnArbitrary f g-    = inverseFunctionsIfFirstSucceedsOnGen f g arbitrary---inverseFunctionsIfSecondSucceedsOnGen-    :: (Show a, Eq a, CanFail f)-    => (a -> b)-    -> (b -> f a)-    -> Gen a-    -> Property-inverseFunctionsIfSecondSucceedsOnGen f g gen =-    forAll gen $ \a ->-      case resultIfSucceeded (g (f a)) of-          Nothing -> return () -- fine-          Just r  -> r `shouldBe` a---inverseFunctionsIfSecondSucceedsOnValid-    :: (Show a, Eq a, GenValidity a, CanFail f)-    => (a -> b)-    -> (b -> f a)-    -> Property-inverseFunctionsIfSecondSucceedsOnValid f g-    = inverseFunctionsIfSecondSucceedsOnGen f g genValid---inverseFunctionsIfSecondSucceeds-    :: (Show a, Eq a, GenValidity a, CanFail f)-    => (a -> b)-    -> (b -> f a)-    -> Property-inverseFunctionsIfSecondSucceeds f g-    = inverseFunctionsIfSecondSucceedsOnGen f g genUnchecked--inverseFunctionsIfSecondSucceedsOnArbitrary-    :: (Show a, Eq a, Arbitrary a, CanFail f)-    => (a -> b)-    -> (b -> f a)-    -> Property-inverseFunctionsIfSecondSucceedsOnArbitrary f g-    = inverseFunctionsIfSecondSucceedsOnGen f g arbitrary---inverseFunctionsIfSucceedOnGen-    :: (Show a, Eq a, CanFail f, CanFail g)-    => (a -> f b)-    -> (b -> g a)-    -> Gen a-    -> Property-inverseFunctionsIfSucceedOnGen f g gen =-    forAll gen $ \a ->-      case do fa <- resultIfSucceeded $ f a-              resultIfSucceeded $ g fa-          of-          Nothing -> return () -- fine-          Just r  -> r `shouldBe` a---inverseFunctionsIfSucceedOnValid-    :: (Show a, Eq a, GenValidity a, CanFail f, CanFail g)-    => (a -> f b)-    -> (b -> g a)-    -> Property-inverseFunctionsIfSucceedOnValid f g-    = inverseFunctionsIfSucceedOnGen f g genValid--inverseFunctionsIfSucceed-    :: (Show a, Eq a, GenValidity a, CanFail f, CanFail g)-    => (a -> f b)-    -> (b -> g a)-    -> Property-inverseFunctionsIfSucceed f g-    = inverseFunctionsIfSucceedOnGen f g genUnchecked--inverseFunctionsIfSucceedOnArbitrary-    :: (Show a, Eq a, Arbitrary a, CanFail f, CanFail g)-    => (a -> f b)-    -> (b -> g a)-    -> Property-inverseFunctionsIfSucceedOnArbitrary f g-    = inverseFunctionsIfSucceedOnGen f g arbitrary
− src/Test/Validity/Functions/Validity.hs
@@ -1,122 +0,0 @@-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE ScopedTypeVariables   #-}-module Test.Validity.Functions.Validity-    ( -- ** Standard tests involving validity-      producesValidsOnGen-    , producesValidsOnValids-    , producesValid-    , producesValidsOnArbitrary-    , producesValidsOnGens2-    , producesValidsOnValids2-    , producesValid2-    , producesValidsOnArbitrary2-    , producesValidsOnGens3-    , producesValidsOnValids3-    , producesValid3-    , producesValidsOnArbitrary3-    ) where--import           Data.GenValidity--import           Test.Hspec-import           Test.QuickCheck---- | The function produces valid output when the input is generated as--- specified by the given generator.-producesValidsOnGen-    :: (Show a, Show b, Validity b)-    => (a -> b)-    -> Gen a-    -> Property-producesValidsOnGen func gen-    = forAll gen $ \a -> func a `shouldSatisfy` isValid---- | The function produces valid output when the input is generated by--- @arbitrary@-producesValidsOnArbitrary-    :: (Show a, Show b, Arbitrary a, Validity b)-    => (a -> b)-    -> Property-producesValidsOnArbitrary = (`producesValidsOnGen` arbitrary)---- | The function produces valid output when the input is generated by--- @genUnchecked@-producesValid-    :: (Show a, Show b, GenValidity a, Validity b)-    => (a -> b)-    -> Property-producesValid = (`producesValidsOnGen` genUnchecked)---- | The function produces valid output when the input is generated by--- @genValid@-producesValidsOnValids-    :: (Show a, Show b, GenValidity a, Validity b)-    => (a -> b)-    -> Property-producesValidsOnValids = (`producesValidsOnGen` genValid)--producesValidsOnGens2-    :: (Show a, Show b, Show c, Validity c)-    => (a -> b -> c)-    -> Gen (a, b)-    -> Property-producesValidsOnGens2 func gen-    = forAll gen $ \(a, b) ->-        func a b `shouldSatisfy` isValid--producesValidsOnValids2-    :: (Show a, Show b, Show c, GenValidity a, GenValidity b, Validity c)-    => (a -> b -> c)-    -> Property-producesValidsOnValids2 func-    = producesValidsOnGens2 func genValid--producesValidsOnArbitrary2-    :: (Show a, Show b, Show c, Arbitrary a, Arbitrary b, Validity c)-    => (a -> b -> c)-    -> Property-producesValidsOnArbitrary2 func-    = producesValidsOnGens2 func arbitrary--producesValid2-    :: (Show a, Show b, Show c, GenValidity a, GenValidity b, Validity c)-    => (a -> b -> c)-    -> Property-producesValid2 func-    = producesValidsOnGens2 func genUnchecked--producesValidsOnGens3-    :: (Show a, Show b, Show c, Show d, Validity d)-    => (a -> b -> c -> d)-    -> Gen (a, b, c)-    -> Property-producesValidsOnGens3 func gen-    = forAll gen $ \(a, b, c) ->-        func a b c `shouldSatisfy` isValid--producesValid3-    :: (Show a, Show b, Show c, Show d,-        GenValidity a, GenValidity b, GenValidity c,-        Validity d)-    => (a -> b -> c -> d)-    -> Property-producesValid3 func-    = producesValidsOnGens3 func genUnchecked--producesValidsOnValids3-    :: (Show a, Show b, Show c, Show d,-        GenValidity a, GenValidity b, GenValidity c,-        Validity d)-    => (a -> b -> c -> d)-    -> Property-producesValidsOnValids3 func-    = producesValidsOnGens3 func genValid--producesValidsOnArbitrary3-    :: (Show a, Show b, Show c, Show d,-        Arbitrary a, Arbitrary b, Arbitrary c,-        Validity d)-    => (a -> b -> c -> d)-    -> Property-producesValidsOnArbitrary3 func-    = producesValidsOnGens3 func arbitrary
+ src/Test/Validity/Functor.hs view
@@ -0,0 +1,167 @@+{-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}++-- | Functor properties+--+-- You will need @TypeApplications@ to use these.+module Test.Validity.Functor+  ( functorSpec,+    functorSpecOnArbitrary,+    functorSpecOnGens,+  )+where++import Data.Data+import Data.GenValidity+import Data.Kind+import Test.Hspec+import Test.QuickCheck+import Test.Validity.Functions+import Test.Validity.Utils++{-# ANN module "HLint: ignore Functor law" #-}++fmapTypeStr ::+  forall (f :: Type -> Type).+  (Typeable f) =>+  String+fmapTypeStr =+  unwords+    [ "fmap",+      "::",+      "(a",+      "->",+      "b)",+      "->",+      nameOf @f,+      "a",+      "->",+      nameOf @f,+      "b"+    ]++flTypeStr ::+  forall (f :: Type -> Type).+  (Typeable f) =>+  String+flTypeStr =+  unwords ["(<$)", "::", "a", "->", nameOf @f, "b", "->", nameOf @f, "a"]++-- | Standard test spec for properties of Functor instances for values generated with GenValid instances+--+-- Example usage:+--+-- > functorSpecOnArbitrary @[]+functorSpec ::+  forall (f :: Type -> Type).+  (Eq (f Int), Show (f Int), Functor f, Typeable f, GenValid (f Int)) =>+  Spec+functorSpec = functorSpecWithInts @f genValid++-- | Standard test spec for properties of Functor instances for values generated with Arbitrary instances+--+-- Example usage:+--+-- > functorSpecOnArbitrary @[]+functorSpecOnArbitrary ::+  forall (f :: Type -> Type).+  (Eq (f Int), Show (f Int), Functor f, Typeable f, Arbitrary (f Int)) =>+  Spec+functorSpecOnArbitrary = functorSpecWithInts @f arbitrary++functorSpecWithInts ::+  forall (f :: Type -> Type).+  (Eq (f Int), Show (f Int), Functor f, Typeable f) =>+  Gen (f Int) ->+  Spec+functorSpecWithInts gen =+  functorSpecOnGens+    @f+    @Int+    genValid+    "int"+    gen+    (unwords [nameOf @f, "of ints"])+    ((+) <$> genValid)+    "increments"+    ((*) <$> genValid)+    "scalings"++-- | Standard test spec for properties of Functor instances for values generated by given generators (and names for those generator).+--+-- Example usage:+--+-- > functorSpecOnGens+-- >     @[]+-- >     @Int+-- >     (pure 4) "four"+-- >     (genListOf $ pure 5) "list of fives"+-- >     ((+) <$> genValid) "additions"+-- >     ((*) <$> genValid) "multiplications"+functorSpecOnGens ::+  forall (f :: Type -> Type) (a :: Type) (b :: Type) (c :: Type).+  ( Show a,+    Show (f a),+    Show (f c),+    Eq (f a),+    Eq (f c),+    Functor f,+    Typeable f,+    Typeable a,+    Typeable b,+    Typeable c+  ) =>+  Gen a ->+  String ->+  Gen (f a) ->+  String ->+  Gen (b -> c) ->+  String ->+  Gen (a -> b) ->+  String ->+  Spec+functorSpecOnGens gena genaname gen genname genf genfname geng gengname =+  parallel $+    describe ("Functor " ++ nameOf @f) $ do+      describe (fmapTypeStr @f) $ do+        it+          ( unwords+              [ "satisfies the first Fuctor law: 'fmap id == id' for",+                genDescr @(f a) genname+              ]+          )+          $ equivalentOnGen (fmap @f id) (id @(f a)) gen shrinkNothing+        it+          ( unwords+              [ "satisfieds the second Functor law: 'fmap (f . g) == fmap f . fmap g' for",+                genDescr @(f a) genname,+                "'s",+                "given to",+                genDescr @(b -> c) genfname,+                "and",+                genDescr @(a -> b) gengname+              ]+          )+          $ forAll (Anon <$> genf)+          $ \(Anon f) ->+            forAll (Anon <$> geng) $ \(Anon g) ->+              equivalentOnGen+                (fmap (f . g))+                (fmap f . fmap g)+                gen+                shrinkNothing+      describe (flTypeStr @f)+        $ it+          ( unwords+              [ "is equivalent to its default implementation for",+                genDescr @a genaname,+                "and",+                genDescr @(f a) genname+              ]+          )+        $ forAll gena+        $ \a ->+          equivalentOnGen (a <$) (fmap $ const a) gen shrinkNothing
− src/Test/Validity/GenRelativeValidity.hs
@@ -1,85 +0,0 @@-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE ScopedTypeVariables   #-}-module Test.Validity.GenRelativeValidity-    ( -- * Tests for GenRelativeValidity instances-      genRelativeValiditySpec-    , genRelativeValidityValidGeneratesValid-    , genRelativeValidityInvalidGeneratesInvalid-    ) where--import           Data.Data-import           Data.Proxy--import           Data.GenRelativeValidity-import           Data.GenValidity--import           Test.Hspec-import           Test.QuickCheck--import           Test.Validity.Utils---- | A @Spec@ that specifies that @genValidFor@ and @genInvalidFor@ work as--- intended.------ In general it is a good idea to add this spec to your test suite if you--- write a custom implementation of @genValidFor@ or @genInvalidFor@.------ Example usage:------ > relativeGenValiditySpec (proxy :: MyDataFor) (proxy :: MyOtherData)-genRelativeValiditySpec-    :: (Typeable a, Typeable b,-        Show a, Show b,-        GenValidity a, GenValidity b,-        RelativeValidity a b,-        GenRelativeValidity a b)-    => Proxy a-    -> Proxy b-    -> Spec-genRelativeValiditySpec one two = do-    let nameOne = nameOf one-    let nameTwo = nameOf two-    describe ("GenRelativeValidity " ++ nameOne ++ " " ++ nameTwo) $ do-        describe ("genValidFor   :: " ++ nameTwo ++ " -> Gen " ++ nameOne) $-            it ("only generates valid \'"-                ++ nameOne-                ++ "\'s for the "-                ++ nameTwo) $-                genRelativeValidityValidGeneratesValid one two--        describe ("genInvalidFor :: " ++ nameTwo ++ " -> Gen " ++ nameOne) $-            it ("only generates invalid \'"-                ++ nameOne-                ++ "\'s for the "-                ++ nameTwo) $-                genRelativeValidityInvalidGeneratesInvalid one two---- | @genValidFor b@ only generates values that satisfy @isValidFor b@-genRelativeValidityValidGeneratesValid-    :: (Show a, Show b,-        GenValidity a, GenValidity b,-        RelativeValidity a b,-        GenRelativeValidity a b)-    => Proxy a-    -> Proxy b-    -> Property-genRelativeValidityValidGeneratesValid one two =-    forAll genValid $ \b ->-        forAll (genValidFor b) $ \a ->-            (a `asProxyTypeOf` one)-                `shouldSatisfy` (`isValidFor` (b `asProxyTypeOf` two))---- | @genInvalidFor b@ only generates values that do not satisfy @isValidFor b@-genRelativeValidityInvalidGeneratesInvalid-    :: (Show a, Show b,-        GenValidity a, GenValidity b,-        RelativeValidity a b,-        GenRelativeValidity a b)-    => Proxy a-    -> Proxy b-    -> Property-genRelativeValidityInvalidGeneratesInvalid one two =-    forAll genUnchecked $ \b ->-        forAll (genInvalidFor b) $ \a ->-            (a `asProxyTypeOf` one)-                `shouldNotSatisfy` (`isValidFor` (b `asProxyTypeOf` two))
src/Test/Validity/GenValidity.hs view
@@ -1,77 +1,60 @@+{-# LANGUAGE AllowAmbiguousTypes #-} {-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE ScopedTypeVariables   #-}-module Test.Validity.GenValidity-    ( -- * Tests for GenValidity instances-      genValiditySpec-    , genValidityValidGeneratesValid-    , genGeneratesValid-    , genValidityInvalidGeneratesInvalid-    , genGeneratesInvalid-    ) where--import           Data.Data--import           Data.GenValidity+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-} -import           Test.Hspec-import           Test.QuickCheck+-- | Tests for GenValidity instances+--+-- You will need @TypeApplications@ to use these.+module Test.Validity.GenValidity+  ( genValidSpec,+    genValidGeneratesValid,+    genGeneratesValid,+    genGeneratesInvalid,+  )+where -import           Test.Validity.Utils+import Data.Data+import Data.GenValidity+import Test.Hspec+import Test.QuickCheck+import Test.Validity.GenValidity.Property+import Test.Validity.Utils --- | A @Spec@ that specifies that @genValid@ only generates valid data and that--- @genInvalid@ only generates invalid data.+-- | A @Spec@ that specifies that @genValid@ only generates valid data. -- -- In general it is a good idea to add this spec to your test suite if you--- write a custom implementation of @genValid@ or @genInvalid@.+-- write a custom implementation of @genValid@. -- -- Example usage: ----- > genValiditySpec (Proxy :: Proxy MyData)-genValiditySpec-    :: (Typeable a, Show a, GenValidity a)-    => Proxy a-    -> Spec-genValiditySpec proxy = do-    let name = nameOf proxy-    describe ("GenValidity " ++ name) $ do-        describe ("genValid   :: Gen " ++ name) $-            it ("only generates valid \'" ++ name ++ "\'s") $-                genValidityValidGeneratesValid proxy--        describe ("genInvalid :: Gen " ++ name) $-            it ("only generates invalid \'" ++ name ++ "\'s") $-                genValidityInvalidGeneratesInvalid proxy+-- > genValidSpec @Int+genValidSpec ::+  forall a.+  (Typeable a, Show a, GenValid a) =>+  Spec+genValidSpec =+  parallel $ do+    let name = nameOf @a+    describe ("GenValid " ++ name) $+      describe ("genValid   :: Gen " ++ name) $+        it ("only generates valid \'" ++ name ++ "\'s") $+          genValidGeneratesValid @a  -- | @genValid@ only generates valid data-genValidityValidGeneratesValid-    :: forall a. (Show a, GenValidity a)-    => Proxy a-    -> Property-genValidityValidGeneratesValid _ =-    genGeneratesValid (genValid :: Gen a)---- | The given generator generates only valid data points-genGeneratesValid-    :: (Show a, Validity a)-    => Gen a-    -> Property-genGeneratesValid gen =-    forAll gen (`shouldSatisfy` isValid)----- | @genValid@ only generates invalid data-genValidityInvalidGeneratesInvalid-    :: forall a. (Show a, GenValidity a)-    => Proxy a-    -> Property-genValidityInvalidGeneratesInvalid _ =-    genGeneratesInvalid (genInvalid :: Gen a)---- | The given generator generates only invalid data points-genGeneratesInvalid-    :: (Show a, Validity a)-    => Gen a-    -> Property-genGeneratesInvalid gen =-    forAll gen (`shouldNotSatisfy` isValid)-+--+-- prop> genValidGeneratesValid @()+-- prop> genValidGeneratesValid @Bool+-- prop> genValidGeneratesValid @Ordering+-- prop> genValidGeneratesValid @Char+-- prop> genValidGeneratesValid @Int+-- prop> genValidGeneratesValid @Float+-- prop> genValidGeneratesValid @Double+-- prop> genValidGeneratesValid @Integer+-- prop> genValidGeneratesValid @(Maybe Int)+-- prop> genValidGeneratesValid @[Int]+genValidGeneratesValid ::+  forall a.+  (Show a, GenValid a) =>+  Property+genValidGeneratesValid = genGeneratesValid @a genValid
+ src/Test/Validity/Monad.hs view
@@ -0,0 +1,253 @@+{-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}++-- | Monad properties+--+-- You will need @TypeApplications@ to use these.+module Test.Validity.Monad+  ( monadSpec,+    monadSpecOnArbitrary,+    monadSpecOnGens,+  )+where++import Control.Monad (ap)+import Data.Data+import Data.GenValidity+import Data.Kind (Type)+import Test.Hspec+import Test.QuickCheck+import Test.QuickCheck.Gen (unGen)+import Test.QuickCheck.Random (mkQCGen)+import Test.Validity.Functions+import Test.Validity.Utils++{-# ANN module "HLint: ignore Use fmap" #-}++{-# ANN module "HLint: ignore Use <$>" #-}++{-# ANN module "HLint: ignore Use >=>" #-}++{-# ANN module "HLint: ignore Use id" #-}++{-# ANN module "HLint: ignore Monad law, left identity" #-}++{-# ANN module "HLint: ignore Monad law, right identity" #-}++{-# ANN module "HLint: ignore Avoid lambda" #-}++{-# ANN module "HLint: ignore Reduce duplication" #-}++returnTypeStr ::+  forall (m :: Type -> Type).+  (Typeable m) =>+  String+returnTypeStr = unwords ["return", "::", "a", "->", nameOf @m, "a"]++bindTypeStr ::+  forall (m :: Type -> Type).+  (Typeable m) =>+  String+bindTypeStr =+  unwords+    [ "(>>=)",+      "::",+      nameOf @m,+      "a",+      "->",+      "(b",+      "->",+      nameOf @m,+      "a)",+      "->",+      nameOf @m,+      "b"+    ]++-- | Standard test spec for properties of Monad instances for values generated with GenValid instances+--+-- Example usage:+--+-- > monadSpec @[]+monadSpec ::+  forall (f :: Type -> Type).+  (Eq (f Int), Show (f Int), Monad f, Typeable f, GenValid (f Int)) =>+  Spec+monadSpec = monadSpecWithInts @f genValid++-- | Standard test spec for properties of Monad instances for values generated with Arbitrary instances+--+-- Example usage:+--+-- > monadSpecOnArbitrary @[]+monadSpecOnArbitrary ::+  forall (f :: Type -> Type).+  (Eq (f Int), Show (f Int), Monad f, Typeable f, Arbitrary (f Int)) =>+  Spec+monadSpecOnArbitrary = monadSpecWithInts @f arbitrary++monadSpecWithInts ::+  forall (f :: Type -> Type).+  (Eq (f Int), Show (f Int), Monad f, Typeable f) =>+  Gen (f Int) ->+  Spec+monadSpecWithInts gen =+  monadSpecOnGens+    @f+    @Int+    genValid+    "int"+    gen+    (unwords [nameOf @f, "of ints"])+    gen+    (unwords [nameOf @f, "of ints"])+    ((+) <$> genValid)+    "increments"+    ( do+        s <- genListLength+        pure $ \b -> unGen gen (mkQCGen b) s+    )+    "perturbations using the int"+    ( do+        s <- genListLength+        pure $ \b -> unGen gen (mkQCGen $ 2 * b) s+    )+    "perturbations using the double the int"+    (pure <$> ((+) <$> genValid))+    (unwords [nameOf @f, "of additions"])++-- | Standard test spec for properties of Monad instances for values generated by given generators (and names for those generator).+--+-- Example usage:+--+-- > monadSpecOnGens+-- >     @[]+-- >     @Int+-- >     (pure 4)+-- >     "four"+-- >     (genListOf $ pure 5)+-- >     "list of fives"+-- >     (genListOf $ pure 6)+-- >     "list of sixes"+-- >     ((*) <$> genValid)+-- >     "factorisations"+-- >     (pure $ \a -> [a])+-- >     "singletonisation"+-- >     (pure $ \a -> [a])+-- >     "singletonisation"+-- >     (pure $ pure (+ 1))+-- >     "increment in list"+monadSpecOnGens ::+  forall (f :: Type -> Type) (a :: Type) (b :: Type) (c :: Type).+  ( Show a,+    Show (f a),+    Show (f b),+    Show (f c),+    Eq (f a),+    Eq (f b),+    Eq (f c),+    Monad f,+    Typeable f,+    Typeable a,+    Typeable b,+    Typeable c+  ) =>+  Gen a ->+  String ->+  Gen (f a) ->+  String ->+  Gen (f b) ->+  String ->+  Gen (a -> b) ->+  String ->+  Gen (a -> f b) ->+  String ->+  Gen (b -> f c) ->+  String ->+  Gen (f (a -> b)) ->+  String ->+  Spec+monadSpecOnGens gena genaname gen genname genb genbname geng gengname genbf genbfname gencf gencfname genfab genfabname =+  parallel $+    describe ("Monad " ++ nameOf @f) $ do+      describe (unwords [returnTypeStr @f, "and", bindTypeStr @f]) $ do+        it+          ( unwords+              [ "satisfy the first Monad law: 'return a >>= k = k a' for",+                genDescr @a genaname,+                "and",+                genDescr @(a -> f b) genbfname+              ]+          )+          $ equivalentOnGens2+            (\a (Anon k) -> return a >>= k)+            (\a (Anon k) -> k a)+            ((,) <$> gena <*> (Anon <$> genbf))+            shrinkNothing+        it+          ( unwords+              [ "satisfy the second Monad law: 'm >>= return = m' for",+                genDescr @(f a) genname+              ]+          )+          $ equivalentOnGen (\m -> m >>= return) (\m -> m) gen shrinkNothing+      describe (bindTypeStr @f)+        $ it+          ( unwords+              [ "satisfies the third Monad law: 'm >>= (x -> k x >>= h) = (m >>= k) >>= h' for",+                genDescr @(f a) genname,+                genDescr @(a -> f b) genbfname,+                "and",+                genDescr @(b -> f c) gencfname+              ]+          )+        $ equivalentOnGens3+          (\m (Anon k) (Anon h) -> m >>= (\x -> k x >>= h))+          (\m (Anon k) (Anon h) -> (m >>= k) >>= h)+          ((,,) <$> gen <*> (Anon <$> genbf) <*> (Anon <$> gencf))+          shrinkNothing+      describe (unwords ["relation with Applicative", nameOf @f]) $ do+        it+          ( unwords+              ["satisfies 'pure = return' for", genDescr @(f a) genname]+          )+          $ equivalentOnGen (pure @f) (return @f) gena shrinkNothing+        it+          ( unwords+              [ "satisfies '(<*>) = ap' for",+                genDescr @(f (a -> b)) genfabname,+                "and",+                genDescr @(f a) genname+              ]+          )+          $ equivalentOnGens2+            (\(Anon a) b -> a <*> b)+            (\(Anon a) b -> ap a b)+            ((,) <$> (Anon <$> genfab) <*> gen)+            shrinkNothing+        it+          ( unwords+              [ "satisfies '(>>) = (*>)' for",+                genDescr @(f a) genname,+                "and",+                genDescr @(f b) genbname+              ]+          )+          $ equivalentOnGens2 (>>) (*>) ((,) <$> gen <*> genb) shrinkNothing+      describe (unwords ["relation with Functor", nameOf @f])+        $ it+          ( unwords+              [ "satisfies 'fmap f xs = xs >>= return . f' for",+                genDescr @(a -> b) gengname,+                "and",+                genDescr @(f a) genname+              ]+          )+        $ equivalentOnGens2+          (\(Anon f) xs -> fmap f xs)+          (\(Anon f) xs -> xs >>= (return . f))+          ((,) <$> (Anon <$> geng) <*> gen)+          shrinkNothing
+ src/Test/Validity/Monoid.hs view
@@ -0,0 +1,131 @@+{-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}++-- | Monoid properties+--+-- You will need @TypeApplications@ to use these.+module Test.Validity.Monoid+  ( monoidSpecOnValid,+    monoidSpec,+    monoidSpecOnArbitrary,+    monoidSpecOnGen,+  )+where++import Data.Data+import Data.GenValidity+import Test.Hspec+import Test.QuickCheck+import Test.Validity.Functions+import Test.Validity.Operations+import Test.Validity.Utils++memptyTypeStr ::+  forall a.+  (Typeable a) =>+  String+memptyTypeStr = unwords ["mempty", "::", nameOf @a]++mappendTypeStr ::+  forall a.+  (Typeable a) =>+  String+mappendTypeStr = unwords ["mappend", "::", an, "->", an, "->", an]+  where+    an = nameOf @a++mconcatTypeStr ::+  forall a.+  (Typeable a) =>+  String+mconcatTypeStr = unwords ["mconcat", "::", "[" ++ an ++ "]", "->", an]+  where+    an = nameOf @a++-- | Standard test spec for properties of 'Monoid' instances for valid values+--+-- Example usage:+--+-- > monoidSpecOnValid @[Double]+monoidSpecOnValid ::+  forall a.+  (Show a, Eq a, Monoid a, Typeable a, GenValid a) =>+  Spec+monoidSpecOnValid = monoidSpecOnGen @a genValid "valid" shrinkValid++-- | Standard test spec for properties of 'Monoid' instances for valid values+--+-- Example usage:+--+-- > monoidSpec @[Int]+monoidSpec ::+  forall a.+  (Show a, Eq a, Monoid a, Typeable a, GenValid a) =>+  Spec+monoidSpec = monoidSpecOnGen @a genValid "valid" shrinkValid++-- | Standard test spec for properties of 'Monoid' instances for arbitrary values+--+-- Example usage:+--+-- > monoidSpecOnArbitrary @[Int]+monoidSpecOnArbitrary ::+  forall a.+  (Show a, Eq a, Monoid a, Typeable a, Arbitrary a) =>+  Spec+monoidSpecOnArbitrary = monoidSpecOnGen @a arbitrary "arbitrary" shrink++-- | Standard test spec for properties of Monoid instances for values generated by a given generator (and name for that generator).+--+-- Example usage:+--+-- > monoidSpecOnGen (pure "a") "singleton list of 'a'"+monoidSpecOnGen ::+  forall a.+  (Show a, Eq a, Monoid a, Typeable a) =>+  Gen a ->+  String ->+  (a -> [a]) ->+  Spec+monoidSpecOnGen gen genname s =+  parallel $ do+    let name = nameOf @a+        memptystr = memptyTypeStr @a+        mappendstr = mappendTypeStr @a+        mconcatstr = mconcatTypeStr @a+        gen3 = (,,) <$> gen <*> gen <*> gen+        s3 (a, b, c) = (,,) <$> s a <*> s b <*> s c+        genl = genListOf gen+        sl = shrinkList s+    describe ("Monoid " ++ name) $ do+      let mem = mempty @a+          mapp = mappend @a+          mcon = mconcat @a+      describe memptystr+        $ it+          ( unwords+              [ "is the identity for",+                mappendstr,+                "for",+                genDescr @a genname+              ]+          )+        $ identityOnGen mapp mem gen s+      describe mappendstr+        $ it+          ( unwords+              [ "is an associative operation for",+                genDescr @(a, a, a) genname+              ]+          )+        $ associativeOnGens mapp gen3 s3+      describe mconcatstr+        $ it+          ( unwords+              [ "is equivalent to its default implementation for",+                genDescr @[a] genname+              ]+          )+        $ equivalentOnGen mcon (foldr mapp mem) genl sl
− src/Test/Validity/Operations.hs
@@ -1,42 +0,0 @@-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE ScopedTypeVariables   #-}-module Test.Validity.Operations-    ( -- * Properties of operations--    -- ** Identity element--    -- *** Left identity-      leftIdentityOnElemWithEquality-    , leftIdentityOnGenWithEquality-    , leftIdentityOnGen-    , leftIdentityOnValid-    , leftIdentity--    -- *** Right identity-    , rightIdentityOnElemWithEquality-    , rightIdentityOnGenWithEquality-    , rightIdentityOnGen-    , rightIdentityOnValid-    , rightIdentity--    -- *** Identity-    , identityOnGen-    , identityOnValid-    , identity--    -- ** Associativity-    , associativeOnGens-    , associativeOnValids-    , associative-    , associativeOnArbitrary--    -- ** Commutativity-    , commutativeOnGens-    , commutativeOnValids-    , commutative-    , commutativeOnArbitrary-    ) where--import           Test.Validity.Operations.Identity-import           Test.Validity.Operations.Associativity-import           Test.Validity.Operations.Commutativity
− src/Test/Validity/Operations/Associativity.hs
@@ -1,44 +0,0 @@-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE ScopedTypeVariables   #-}-module Test.Validity.Operations.Associativity-    ( -- ** Associativity-      associativeOnGens-    , associativeOnValids-    , associative-    , associativeOnArbitrary-    ) where--import           Data.GenValidity--import           Test.Hspec-import           Test.QuickCheck--associativeOnGens-    :: (Show a, Eq a)-    => (a -> a -> a)-    -> Gen (a, a, a)-    -> Property-associativeOnGens op gen =-    forAll gen $ \(a, b, c) ->-        ((a `op` b) `op` c) `shouldBe` (a `op` (b `op` c))--associativeOnValids-    :: (Show a, Eq a, GenValidity a)-    => (a -> a -> a)-    -> Property-associativeOnValids op-    = associativeOnGens op genValid--associative-    :: (Show a, Eq a, GenValidity a)-    => (a -> a -> a)-    -> Property-associative op-    = associativeOnGens op genUnchecked--associativeOnArbitrary-    :: (Show a, Eq a, Arbitrary a)-    => (a -> a -> a)-    -> Property-associativeOnArbitrary op-    = associativeOnGens op arbitrary
− src/Test/Validity/Operations/Commutativity.hs
@@ -1,44 +0,0 @@-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE ScopedTypeVariables   #-}-module Test.Validity.Operations.Commutativity-    ( -- ** Commutativity-      commutativeOnGens-    , commutativeOnValids-    , commutative-    , commutativeOnArbitrary-    ) where--import           Data.GenValidity--import           Test.Hspec-import           Test.QuickCheck--commutativeOnGens-    :: (Show a, Eq a)-    => (a -> a -> a)-    -> Gen (a, a)-    -> Property-commutativeOnGens op gen =-    forAll gen $ \(a, b) ->-        (a `op` b) `shouldBe` (b `op` a)--commutativeOnValids-    :: (Show a, Eq a, GenValidity a)-    => (a -> a -> a)-    -> Property-commutativeOnValids op-    = commutativeOnGens op genValid--commutative-    :: (Show a, Eq a, GenValidity a)-    => (a -> a -> a)-    -> Property-commutative op-    = commutativeOnGens op genUnchecked--commutativeOnArbitrary-    :: (Show a, Eq a, Arbitrary a)-    => (a -> a -> a)-    -> Property-commutativeOnArbitrary op-    = commutativeOnGens op arbitrary
− src/Test/Validity/Operations/Identity.hs
@@ -1,148 +0,0 @@-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE ScopedTypeVariables   #-}-module Test.Validity.Operations.Identity-    ( -- *** Left identity-      leftIdentityOnElemWithEquality-    , leftIdentityOnGenWithEquality-    , leftIdentityOnGen-    , leftIdentityOnValid-    , leftIdentity--      -- *** Right identity-    , rightIdentityOnElemWithEquality-    , rightIdentityOnGenWithEquality-    , rightIdentityOnGen-    , rightIdentityOnValid-    , rightIdentity--    , identityOnGen-    , identityOnValid-    , identity-    ) where--import           Data.GenValidity--import           Test.QuickCheck---- |------ \[---   LeftIdentity(\star, \doteq, b)---   \quad\equiv\quad---   \forall a: (b \star a) \doteq a--- \]-leftIdentityOnElemWithEquality-    :: (b -> a -> a)    -- ^ A binary operation-    -> (a -> a -> Bool) -- ^ An equality-    -> b                -- ^ A candidate left-identity-    -> a                -- ^ An element-    -> Bool-leftIdentityOnElemWithEquality op eq b a = (b `op` a) `eq` a--leftIdentityOnGenWithEquality-    :: Show a-    => (b -> a -> a)    -- ^ A binary operation-    -> (a -> a -> Bool) -- ^ An equality-    -> b                -- ^ A candidate left-identity-    -> Gen a-    -> Property-leftIdentityOnGenWithEquality op eq b gen =-    forAll gen $ leftIdentityOnElemWithEquality op eq b--leftIdentityOnGen-    :: (Show a, Eq a)-    => (b -> a -> a) -- ^ A binary operation-    -> b             -- ^ A candidate left-identity-    -> Gen a-    -> Property-leftIdentityOnGen op = leftIdentityOnGenWithEquality op (==)--leftIdentityOnValid-    :: (Show a, Eq a, GenValidity a)-    => (b -> a -> a)-    -> b-    -> Property-leftIdentityOnValid op b-    = leftIdentityOnGen op b genValid--leftIdentity-    :: (Show a, Eq a, GenValidity a)-    => (b -> a -> a)-    -> b-    -> Property-leftIdentity op b-    = leftIdentityOnGen op b genUnchecked---- |------ \[---   RightIdentity(\star, \doteq, b)---   \quad\equiv\quad---   \forall a: (a \star b) \doteq a--- \]-rightIdentityOnElemWithEquality-    :: (a -> b -> a)    -- ^ A binary operation-    -> (a -> a -> Bool) -- ^ An equality-    -> b                -- ^ A candidate right-identity-    -> a                -- ^ An element-    -> Bool-rightIdentityOnElemWithEquality op eq b a = (a `op` b) `eq` a--rightIdentityOnGenWithEquality-    :: Show a-    => (a -> b -> a)    -- ^ A binary operation-    -> (a -> a -> Bool) -- ^ An equality-    -> b                -- ^ A candidate right-identity-    -> Gen a-    -> Property-rightIdentityOnGenWithEquality op eq b gen =-    forAll gen $ rightIdentityOnElemWithEquality op eq b--rightIdentityOnGen-    :: (Show a, Eq a)-    => (a -> b -> a)    -- ^ A binary operation-    -> b                -- ^ A candidate right-identity-    -> Gen a-    -> Property-rightIdentityOnGen op = rightIdentityOnGenWithEquality op (==)--rightIdentityOnValid-    :: (Show a, Eq a, GenValidity a)-    => (a -> b -> a)-    -> b-    -> Property-rightIdentityOnValid op b-    = rightIdentityOnGen op b genValid--rightIdentity-    :: (Show a, Eq a, GenValidity a)-    => (a -> b -> a)-    -> b-    -> Property-rightIdentity op b-    = rightIdentityOnGen op b genUnchecked--identityOnGen-    :: (Show a, Eq a)-    => (a -> a -> a)-    -> a-    -> Gen a-    -> Property-identityOnGen op e gen =-    leftIdentityOnGen op e gen .&&. rightIdentityOnGen op e gen--identityOnValid-    :: (Show a, Eq a, GenValidity a)-    => (a -> a -> a)-    -> a-    -> Property-identityOnValid op a-    = identityOnGen op a genValid--identity-    :: (Show a, Eq a, GenValidity a)-    => (a -> a -> a)-    -> a-    -> Property-identity op e-    = identityOnGen op e genUnchecked
src/Test/Validity/Ord.hs view
@@ -1,46 +1,150 @@+{-# LANGUAGE AllowAmbiguousTypes #-} {-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE ScopedTypeVariables   #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}++-- | Ord properties+--+-- You will need @TypeApplications@ to use these. module Test.Validity.Ord-    ( -- * Ord properties-      ordSpec-    ) where+  ( ordSpec,+    ordSpecOnGen,+    ordSpecOnArbitrary,+  )+where -import           Data.Data-import           Data.Proxy+import Data.Data+import Data.GenValidity+import Test.Hspec+import Test.QuickCheck+import Test.Validity.Functions+import Test.Validity.Relations+import Test.Validity.Utils -import           Data.GenValidity+{-# ANN module "HLint: ignore Use <=" #-} -import           Test.Hspec+{-# ANN module "HLint: ignore Use >=" #-} -import           Test.Validity.Relations-import           Test.Validity.Utils+{-# ANN module "HLint: ignore Use <" #-} -ordSpec-    :: (Show a, Eq a, Ord a, Typeable a, GenValidity a)-    => Proxy a-    -> Spec-ordSpec proxy = do-    let name = nameOf proxy-        funlestr = unwords-          [ "(<=) ::"-          , name-          , "->"-          , name-          , "-> Ordering"-          ]-        cmp a b = a `asProxyTypeOf` proxy <= b-    describe ("Ord " ++ name) $ do-        it ("is instantated such that "-            ++ funlestr-            ++ " is reflexive") $-            reflexivity cmp+{-# ANN module "HLint: ignore Use >" #-} -        it ("is instantated such that "-            ++ funlestr-            ++ " is antisymmetric") $-            antisymmetry cmp+leTypeStr ::+  forall a.+  (Typeable a) =>+  String+leTypeStr = binRelStr @a "<=" -        it ("is instantated such that "-            ++ funlestr-            ++ " is transitive") $-            transitivity cmp+geTypeStr ::+  forall a.+  (Typeable a) =>+  String+geTypeStr = binRelStr @a ">="++ltTypeStr ::+  forall a.+  (Typeable a) =>+  String+ltTypeStr = binRelStr @a "<"++gtTypeStr ::+  forall a.+  (Typeable a) =>+  String+gtTypeStr = binRelStr @a ">"++-- | Standard test spec for properties of Ord instances for valid values+--+-- Example usage:+--+-- > ordSpec @Int+ordSpec ::+  forall a.+  (Show a, Ord a, Typeable a, GenValid a) =>+  Spec+ordSpec = ordSpecOnGen @a genValid "valid" shrinkValid++-- | Standard test spec for properties of Ord instances for arbitrary values+--+-- Example usage:+--+-- > ordSpecOnArbitrary @Int+ordSpecOnArbitrary ::+  forall a.+  (Show a, Ord a, Typeable a, Arbitrary a) =>+  Spec+ordSpecOnArbitrary = ordSpecOnGen @a arbitrary "arbitrary" shrink++-- | Standard test spec for properties of Ord instances for values generated by a given generator (and name for that generator).+--+-- Example usage:+--+-- > ordSpecOnGen ((* 2) <$> genValid @Int) "even"+ordSpecOnGen ::+  forall a.+  (Show a, Ord a, Typeable a) =>+  Gen a ->+  String ->+  (a -> [a]) ->+  Spec+ordSpecOnGen gen genname s =+  parallel $ do+    let name = nameOf @a+        funlestr = leTypeStr @a+        fungestr = geTypeStr @a+        funltstr = ltTypeStr @a+        fungtstr = gtTypeStr @a+        minmaxtstr = genDescr @(a -> a -> a)+        itProp s_ =+          it $+            unwords+              [ s_,+                "\"" ++ genname,+                name ++ "\"" ++ "'s"+              ]+        cmple = (<=) @a+        cmpge = (>=) @a+        cmplt = (<) @a+        cmpgt = (>) @a+        gen2 = (,) <$> gen <*> gen+        gen3 = (,,) <$> gen <*> gen <*> gen+        s2 = shrinkT2 s+    describe ("Ord " ++ name) $ do+      describe funlestr $ do+        itProp "is reflexive for" $+          reflexivityOnGen cmple gen s+        itProp "is antisymmetric for" $+          antisymmetryOnGens cmple gen2 s+        itProp "is transitive for" $+          transitivityOnGens cmple gen3 s+        itProp "is equivalent to (\\a b -> compare a b /= GT) for" $+          equivalentOnGens2 cmple (\a b -> compare a b /= GT) gen2 s2+      describe fungestr $ do+        itProp "is reflexive for" $+          reflexivityOnGen cmpge gen s+        itProp "is antisymmetric for" $+          antisymmetryOnGens cmpge gen2 s+        itProp "is transitive for" $+          transitivityOnGens cmpge gen3 s+        itProp "is equivalent to (\\a b -> compare a b /= LT) for" $+          equivalentOnGens2 cmpge (\a b -> compare a b /= LT) gen2 s2+      describe funltstr $ do+        itProp "is antireflexive for" $+          antireflexivityOnGen cmplt gen s+        itProp "is transitive for" $+          transitivityOnGens cmplt gen3 s+        itProp "is equivalent to (\\a b -> compare a b == LT) for" $+          equivalentOnGens2 cmplt (\a b -> compare a b == LT) gen2 s2+      describe fungtstr $ do+        itProp "is antireflexive for" $+          antireflexivityOnGen cmpgt gen s+        itProp "is transitive for" $+          transitivityOnGens cmpgt gen3 s+        itProp "is equivalent to (\\a b -> compare a b == GT) for" $+          equivalentOnGens2 cmpgt (\a b -> compare a b == GT) gen2 s2+      describe (minmaxtstr "min") $ do+        itProp "is equivalent to (\\a b -> if a <= b then a else b) for" $+          equivalentOnGens2 min (\a b -> if a <= b then a else b) gen2 s2+      describe (minmaxtstr "max") $ do+        itProp "is equivalent to (\\a b -> if a >= b then a else b) for" $+          equivalentOnGens2 max (\a b -> if a >= b then a else b) gen2 s2
− src/Test/Validity/Relations.hs
@@ -1,41 +0,0 @@-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE ScopedTypeVariables   #-}-module Test.Validity.Relations-    (-    -- * Properties of relations--    -- ** Reflexivity-      reflexiveOnElem-    , reflexivityOnGen-    , reflexivityOnValid-    , reflexivity-    , reflexivityOnArbitrary--    -- ** Transitivity-    , transitiveOnElems-    , transitivityOnGens-    , transitivityOnValid-    , transitivity-    , transitivityOnArbitrary--    -- ** Antisymmetry-    , antisymmetricOnElemsWithEquality-    , antisymmetryOnGensWithEquality-    , antisymmetryOnGensEq-    , antisymmetryOnValid-    , antisymmetry-    , antisymmetryOnArbitrary--    -- ** Symmetry-    , symmetricOnElems-    , symmetryOnGens-    , symmetryOnValid-    , symmetry-    , symmetryOnArbitrary-    ) where--import           Test.Validity.Relations.Reflexivity-import           Test.Validity.Relations.Antisymmetry-import           Test.Validity.Relations.Symmetry-import           Test.Validity.Relations.Transitivity-
− src/Test/Validity/Relations/Antisymmetry.hs
@@ -1,72 +0,0 @@-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE ScopedTypeVariables   #-}-module Test.Validity.Relations.Antisymmetry-    ( antisymmetricOnElemsWithEquality-    , antisymmetryOnGensWithEquality-    , antisymmetryOnGensEq-    , antisymmetryOnValid-    , antisymmetry-    , antisymmetryOnArbitrary-    ) where--import           Data.GenValidity--import           Test.QuickCheck--import           Test.Validity.Utils---- |------ \[---   Antisymmetric(\prec, \doteq)---   \quad\equiv\quad---   \forall a, b: ((a \prec b) \wedge (b \prec a)) \Rightarrow (a \doteq b)--- \]-antisymmetricOnElemsWithEquality-    :: (a -> a -> Bool) -- ^ A relation-    -> (a -> a -> Bool) -- ^ An equivalence relation-    -> a -> a           -- ^ Two elements-    -> Bool-antisymmetricOnElemsWithEquality func eq a b =-    (func a b && func b a) ===> (a `eq` b)--antisymmetryOnGensWithEquality-    :: Show a-    => (a -> a -> Bool)-    -> Gen (a, a)-    -> (a -> a -> Bool)-    -> Property-antisymmetryOnGensWithEquality func gen eq =-    forAll gen $ uncurry $ antisymmetricOnElemsWithEquality func eq--antisymmetryOnGensEq-    :: (Show a, Eq a)-    => (a -> a -> Bool)-    -> Gen (a, a)-    -> Property-antisymmetryOnGensEq func gen-    = antisymmetryOnGensWithEquality func gen (==)--antisymmetryOnValid-    :: (Show a, Eq a, GenValidity a)-    => (a -> a -> Bool)-    -> Property-antisymmetryOnValid func =-    antisymmetryOnGensEq func genValid--antisymmetry-    :: (Show a, Eq a, GenValidity a)-    => (a -> a -> Bool)-    -> Property-antisymmetry func =-    antisymmetryOnGensEq func genUnchecked---- |------ prop> antisymmetryOnArbitrary ((<=) :: Int -> Int -> Bool)-antisymmetryOnArbitrary-    :: (Show a, Eq a, Arbitrary a)-    => (a -> a -> Bool)-    -> Property-antisymmetryOnArbitrary func =-    antisymmetryOnGensEq func arbitrary
− src/Test/Validity/Relations/Reflexivity.hs
@@ -1,58 +0,0 @@-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE ScopedTypeVariables   #-}-module Test.Validity.Relations.Reflexivity-    ( reflexiveOnElem-    , reflexivityOnGen-    , reflexivityOnValid-    , reflexivity-    , reflexivityOnArbitrary-    ) where--import           Data.GenValidity--import           Test.QuickCheck---- |------ \[---   Reflexive(prec)---   \quad\equiv\quad---   \forall a: (a \prec a)--- \]-reflexiveOnElem-    :: (a -> a -> Bool) -- ^ A relation-    -> a                -- ^ An element-    -> Bool-reflexiveOnElem func a = func a a--reflexivityOnGen-    :: Show a-    => (a -> a -> Bool)-    -> Gen a-    -> Property-reflexivityOnGen func gen =-    forAll gen $ reflexiveOnElem func--reflexivityOnValid-    :: (Show a, GenValidity a)-    => (a -> a -> Bool)-    -> Property-reflexivityOnValid func-    = reflexivityOnGen func genValid--reflexivity-    :: (Show a, GenValidity a)-    => (a -> a -> Bool)-    -> Property-reflexivity func-    = reflexivityOnGen func genUnchecked---- |------ prop> reflexivityOnArbitrary ((==) :: Int -> Int -> Bool)-reflexivityOnArbitrary-    :: (Show a, Arbitrary a)-    => (a -> a -> Bool)-    -> Property-reflexivityOnArbitrary func-    = reflexivityOnGen func arbitrary
− src/Test/Validity/Relations/Symmetry.hs
@@ -1,61 +0,0 @@-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE ScopedTypeVariables   #-}-module Test.Validity.Relations.Symmetry-    ( symmetricOnElems-    , symmetryOnGens-    , symmetryOnValid-    , symmetry-    , symmetryOnArbitrary-    ) where--import           Data.GenValidity--import           Test.QuickCheck--import           Test.Validity.Utils---- |------ \[---   Symmetric(\prec)---   \quad\equiv\quad---   \forall a, b: (a \prec b) \Leftrightarrow (b \prec a)--- \]-symmetricOnElems-    :: (a -> a -> Bool) -- ^ A relation-    -> a -> a           -- ^ Two elements-    -> Bool-symmetricOnElems func a b = func a b <==> func b a--symmetryOnGens-    :: Show a-    => (a -> a -> Bool)-    -> Gen (a, a)-    -> Property-symmetryOnGens func gen =-    forAll gen $ uncurry $ symmetricOnElems func--symmetryOnValid-    :: (Show a, GenValidity a)-    => (a -> a -> Bool)-    -> Property-symmetryOnValid func =-    symmetryOnGens func genValid--symmetry-    :: (Show a, GenValidity a)-    => (a -> a -> Bool)-    -> Property-symmetry func =-    symmetryOnGens func genUnchecked----- |------ prop> symmetryOnArbitrary ((==) :: Int -> Int -> Bool)-symmetryOnArbitrary-    :: (Show a, Arbitrary a)-    => (a -> a -> Bool)-    -> Property-symmetryOnArbitrary func =-    symmetryOnGens func arbitrary
− src/Test/Validity/Relations/Transitivity.hs
@@ -1,62 +0,0 @@-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE ScopedTypeVariables   #-}-module Test.Validity.Relations.Transitivity-    ( transitiveOnElems-    , transitivityOnGens-    , transitivityOnValid-    , transitivity-    , transitivityOnArbitrary-    ) where--import           Data.GenValidity--import           Test.QuickCheck--import           Test.Validity.Utils---- |------ \[---   Transitive(\prec)---   \quad\equiv\quad---   \forall a, b, c: ((a \prec b) \wedge (b \prec c)) \Rightarrow (a \prec c)--- \]-transitiveOnElems-    :: (a -> a -> Bool) -- ^ A relation-    -> a -> a -> a      -- ^ Three elements-    -> Bool-transitiveOnElems func a b c = (func a b && func b c) ===> func a c--transitivityOnGens-    :: Show a-    => (a -> a -> Bool)-    -> Gen (a, a, a)-    -> Property-transitivityOnGens func gen =-    forAll gen $ \(a, b, c) -> transitiveOnElems func a b c--transitivityOnValid-    :: (Show a, GenValidity a)-    => (a -> a -> Bool)-    -> Property-transitivityOnValid func-    = transitivityOnGens func genValid---transitivity-    :: (Show a, GenValidity a)-    => (a -> a -> Bool)-    -> Property-transitivity func-    = transitivityOnGens func genUnchecked---- |------ prop> transitivityOnArbitrary ((==) :: Int -> Int -> Bool)-transitivityOnArbitrary-    :: (Show a, Arbitrary a)-    => (a -> a -> Bool)-    -> Property-transitivityOnArbitrary func-    = transitivityOnGens func arbitrary-
− src/Test/Validity/RelativeValidity.hs
@@ -1,77 +0,0 @@-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE ScopedTypeVariables   #-}-module Test.Validity.RelativeValidity-    ( -- * Tests for RelativeValidity instances-      relativeValiditySpec-    , relativeValidityImpliesValidA-    , relativeValidityImpliesValidB-    ) where--import           Data.Data-import           Data.Proxy--import           Data.GenRelativeValidity-import           Data.GenValidity--import           Test.Hspec-import           Test.QuickCheck--import           Test.Validity.Utils---- | A @Spec@ that specifies that @isValidFor@ implies @isValid@------ In general it is a good idea to add this spec to your test suite if--- the @a@ and @b@ in @RelativeValidity a b@ also have a @Validity@ instance.------ Example usage:------ > relativeValiditySpec--- >     (Proxy :: Proxy MyDataFor)--- >     (Proxy :: Proxy MyOtherData)-relativeValiditySpec-    :: (Typeable a, Typeable b,-        Show a, Show b,-        GenValidity a, GenValidity b, GenRelativeValidity a b)-    => Proxy a-    -> Proxy b-    -> Spec-relativeValiditySpec one two = do-    let nameOne = nameOf one-        nameTwo = nameOf two-    describe ("RelativeValidity " ++ nameOne ++ " " ++ nameTwo) $-        describe ("isValidFor :: "-                  ++ nameOne-                  ++ " -> "-                  ++ nameTwo-                  ++ " -> Bool") $ do-            it ("implies isValid " ++ nameOne ++ " for any " ++ nameTwo) $-                relativeValidityImpliesValidA one two-            it ("implies isValid " ++ nameTwo ++ " for any " ++ nameOne) $-                relativeValidityImpliesValidB one two---- | @isValidFor a b@ implies @isValid a@ for all @b@-relativeValidityImpliesValidA-    :: (Show a, Show b,-        GenValidity a, GenValidity b, RelativeValidity a b)-    => Proxy a-    -> Proxy b-    -> Property-relativeValidityImpliesValidA one two =-    forAll genUnchecked $ \a ->-        forAll genUnchecked $ \b ->-            not ((a `asProxyTypeOf` one) `isValidFor` (b `asProxyTypeOf` two))-            || isValid a---- | @isValidFor a b@ implies @isValid b@ for all @a@-relativeValidityImpliesValidB-    :: (Show a, Show b,-        GenValidity a, GenValidity b, RelativeValidity a b)-    => Proxy a-    -> Proxy b-    -> Property-relativeValidityImpliesValidB one two =-    forAll genUnchecked $ \a ->-        forAll genUnchecked $ \b ->-            not ((a `asProxyTypeOf` one) `isValidFor` (b `asProxyTypeOf` two))-              || isValid b-
+ src/Test/Validity/Show.hs view
@@ -0,0 +1,89 @@+{-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}++-- | 'Show' and 'Read' properties+module Test.Validity.Show+  ( showReadSpec,+    showReadSpecOnArbitrary,+    showReadSpecOnGen,+    showReadRoundTrip,+    showReadRoundTripOnArbitrary,+    showReadRoundTripOnGen,+  )+where++import Data.Data+import Data.GenValidity+import Test.Hspec+import Test.QuickCheck+import Test.Validity.Utils+import Text.Read++-- | Standard test spec for properties of Show and Read instances for valid values+--+-- Example usage:+--+-- > showReadSpec @Int+showReadSpec ::+  forall a.+  (Show a, Eq a, Read a, Typeable a, GenValid a) =>+  Spec+showReadSpec = showReadSpecOnGen @a genValid "valid" shrinkValid++-- | Standard test spec for properties of Show and Read instances for arbitrary values+--+-- Example usage:+--+-- > showReadSpecOnArbitrary @Double+showReadSpecOnArbitrary ::+  forall a.+  (Show a, Eq a, Read a, Typeable a, Arbitrary a) =>+  Spec+showReadSpecOnArbitrary = showReadSpecOnGen @a arbitrary "arbitrary" shrink++-- | Standard test spec for properties of Show and Read instances for values generated by a custom generator+--+-- Example usage:+--+-- > showReadSpecOnGen ((* 2) <$> genValid @Int) "even" (const [])+showReadSpecOnGen ::+  forall a.+  (Show a, Eq a, Read a, Typeable a) =>+  Gen a ->+  String ->+  (a -> [a]) ->+  Spec+showReadSpecOnGen gen n s =+  describe (unwords ["Show", nameOf @a, "and Read", nameOf @a]) $+    it (unwords ["are implemented such that read . show == id for", n, "values"]) $+      showReadRoundTripOnGen gen s++-- |+--+-- prop> showReadRoundTrip @Int+showReadRoundTrip ::+  forall a.+  (Show a, Eq a, Read a, GenValid a) =>+  Property+showReadRoundTrip =+  showReadRoundTripOnGen (genValid :: Gen a) shrinkValid++-- |+--+-- prop> showReadRoundTripOnArbitrary @Double+showReadRoundTripOnArbitrary ::+  forall a.+  (Show a, Eq a, Read a, Arbitrary a) =>+  Property+showReadRoundTripOnArbitrary =+  showReadRoundTripOnGen (arbitrary :: Gen a) shrink++-- |+--+-- prop> showReadRoundTripOnGen (abs <$> genValid :: Gen Int) (const [])+showReadRoundTripOnGen ::+  (Show a, Eq a, Read a) => Gen a -> (a -> [a]) -> Property+showReadRoundTripOnGen gen s =+  forAllShrink gen s $ \v -> readMaybe (show v) `shouldBe` Just v
+ src/Test/Validity/Shrinking.hs view
@@ -0,0 +1,90 @@+{-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}++-- | Tests for Shrinking functions+--+-- You will need @TypeApplications@ to use these.+module Test.Validity.Shrinking+  ( shrinkValidSpec,+    shrinkValidSpecWithLimit,+    shrinkValidPreservesValidOnGenValid,+    shrinkValidPreservesValidOnGenValidWithLimit,+    shrinkPreservesValidOnGenValid,+    shrinkValidPreservesValid,+    shrinkingStaysValid,+    shrinkingPreserves,+    shrinkValidDoesNotShrinkToItself,+    shrinkValidDoesNotShrinkToItselfWithLimit,+  )+where++import Control.Monad+import Data.Data+import Data.GenValidity+import Test.Hspec+import Test.QuickCheck+import Test.Validity.Shrinking.Property+import Test.Validity.Utils++shrinkValidSpec ::+  forall a.+  (Show a, Eq a, Typeable a, GenValid a) =>+  Spec+shrinkValidSpec =+  describe ("shrinkValid :: " ++ nameOf @(a -> [a])) $ do+    it "preserves validity" $+      forAll (genValid @a) $+        \a -> forM_ (shrinkValid a) shouldBeValid+    it "never shrinks to itself for valid values" $+      shrinkValidDoesNotShrinkToItself @a++shrinkValidSpecWithLimit ::+  forall a.+  (Show a, Eq a, Typeable a, GenValid a) =>+  Int ->+  Spec+shrinkValidSpecWithLimit l =+  describe ("shrinkValid :: " ++ nameOf @(a -> [a])) $ do+    it (unwords ["preserves validity for the first", show l, "elements"]) $+      forAll (genValid @a) $ \a ->+        forM_ (take l $ shrinkValid a) shouldBeValid+    it+      ( unwords+          [ "never shrinks to itself for valid values for the first",+            show l,+            "elements"+          ]+      )+      $ shrinkValidDoesNotShrinkToItselfWithLimit @a l++shrinkValidPreservesValidOnGenValid ::+  forall a.+  (Show a, GenValid a) =>+  Property+shrinkValidPreservesValidOnGenValid =+  shrinkingStaysValid @a genValid shrinkValid++shrinkValidPreservesValidOnGenValidWithLimit ::+  forall a.+  (Show a, GenValid a) =>+  Int ->+  Property+shrinkValidPreservesValidOnGenValidWithLimit =+  shrinkingStaysValidWithLimit @a genValid shrinkValid++shrinkValidDoesNotShrinkToItself ::+  forall a.+  (Show a, Eq a, GenValid a) =>+  Property+shrinkValidDoesNotShrinkToItself =+  shrinkDoesNotShrinkToItself @a shrinkValid++shrinkValidDoesNotShrinkToItselfWithLimit ::+  forall a.+  (Show a, Eq a, GenValid a) =>+  Int ->+  Property+shrinkValidDoesNotShrinkToItselfWithLimit =+  shrinkDoesNotShrinkToItselfOnValidWithLimit @a shrinkValid
− src/Test/Validity/Types.hs
@@ -1,25 +0,0 @@-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE ScopedTypeVariables   #-}-module Test.Validity.Types-    ( CanFail(..)-    ) where---- | A class of types that are the result of functions that can fail-class CanFail f where-    hasFailed :: f a -> Bool-    resultIfSucceeded :: f a -> Maybe a--instance CanFail Maybe where-    hasFailed Nothing = True-    hasFailed _ = False--    resultIfSucceeded Nothing = Nothing-    resultIfSucceeded (Just r) = Just r--instance CanFail (Either e) where-    hasFailed (Left _) = True-    hasFailed _ = False--    resultIfSucceeded (Left _) = Nothing-    resultIfSucceeded (Right r) = Just r-
src/Test/Validity/Utils.hs view
@@ -1,20 +1,125 @@+{-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE CPP #-} {-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE ScopedTypeVariables   #-}+{-# LANGUAGE PolyKinds #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}+{-# OPTIONS_GHC -Wno-deprecations #-}++-- | Utilities for defining your own validity 'Spec's+--+-- You will need @TypeApplications@ to use these. module Test.Validity.Utils-    ( (<==>)-    , (===>)-    , nameOf-    ) where+  ( nameOf,+    genDescr,+    binRelStr,+    shouldFail,+    failsBecause,+    Anon (..),+    shouldBeValid,+    shouldBeInvalid,+  )+where -import           Data.Data+import Control.Arrow (second)+import Control.Monad.Trans.Writer (mapWriterT)+import Data.Data+import Test.Hspec+import Test.Hspec.Core.Formatters+import Test.Hspec.Core.Runner+import Test.Hspec.Core.Spec+import Test.QuickCheck.Property+import Test.Validity.Property.Utils -(===>) :: Bool -> Bool -> Bool-(===>) a b = not a || b+nameOf ::+  forall a.+  (Typeable a) =>+  String+nameOf =+  let s = show $ typeRep (Proxy @a)+   in if ' ' `elem` s+        then "(" ++ s ++ ")"+        else s -(<==>) :: Bool -> Bool -> Bool-(<==>) a b = a ===> b && b ===> a+genDescr ::+  forall a.+  (Typeable a) =>+  String ->+  String+genDescr genname = unwords ["\"" ++ genname, "::", nameOf @a ++ "\""] -nameOf :: Typeable a => Proxy a -> String-nameOf proxy =-    let (_, [ty]) = splitTyConApp $ typeOf proxy-    in show ty+binRelStr ::+  forall a.+  (Typeable a) =>+  String ->+  String+binRelStr op = unwords ["(" ++ op ++ ")", "::", name, "->", name, "->", "Bool"]+  where+    name = nameOf @a++newtype Anon a+  = Anon a++instance Show (Anon a) where+  show _ = "Anonymous"++instance Functor Anon where+  fmap f (Anon a) = Anon (f a)++-- I'm not sure why mapSpecTree was removed from hspec-core,+-- but it has been copied here for convenience.+-- https://github.com/hspec/hspec/commit/020c7ecc4a73c24af38e9fab049f60bb9aec6981#diff-29cb22f0ef6e98086a71fc045847bd21L22+mapSpecTree' :: (SpecTree a -> SpecTree b) -> SpecM a r -> SpecM b r++#if MIN_VERSION_hspec(2,10,0)+mapSpecTree' f (SpecM specs) = SpecM (mapWriterT (fmap (second (fmap (map f)))) specs)+#else+mapSpecTree' f (SpecM specs) = SpecM (mapWriterT (fmap (second (map f))) specs)+#endif+{- ORMOLU_DISABLE -}+-- | Asserts that a given 'Spec' tree fails _somewhere_.+--+-- It also shows the given string when reporting that the tree unexpectedly+-- succeeded.+failsBecause :: String -> SpecWith () -> SpecWith ()+failsBecause s = mapSpecTree' go+  where+    go :: SpecTree () -> SpecTree ()+    go sp =+      Leaf+        Item+          { itemRequirement = s,+            itemLocation = Nothing,+            itemIsFocused = False,+            itemIsParallelizable = Nothing,+#if MIN_VERSION_hspec(2,11,10)+            itemAnnotations = mempty,+#endif+            itemExample =+              \_ _ _ -> do+                let conf =+                      defaultConfig {configFormatter = Just silent}+                r <- hspecWithResult conf $ fromSpecList [sp]+                let succesful =+                      summaryExamples r > 0 && summaryFailures r > 0+                pure $ produceResult succesful+          }+{- ORMOLU_ENABLE -}++produceResult :: Bool -> Test.Hspec.Core.Spec.Result+produceResult succesful =+  Result+    { resultInfo = "",+      resultStatus =+        if succesful+          then Success+          else Failure Nothing $ Test.Hspec.Core.Spec.Reason "Should have failed but didn't."+    }++shouldFail :: Property -> Property+shouldFail =+  mapResult $ \res ->+    res+      { reason = unwords ["Should have failed:", reason res],+        expect = not $ expect res+      }
− test/DocTest.hs
@@ -1,4 +0,0 @@-import Test.DocTest--main :: IO ()-main = doctest ["-isrc", "src"]
+ test/Spec.hs view
@@ -0,0 +1,1 @@+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
+ test/Test/Validity/ApplicativeSpec.hs view
@@ -0,0 +1,45 @@+{-# LANGUAGE TypeApplications #-}++module Test.Validity.ApplicativeSpec where++import Data.GenValidity+import Test.Hspec+import Test.Validity.Applicative++spec :: Spec+spec = do+  applicativeSpec @(Either Int)+  applicativeSpec @[]+  applicativeSpec @Maybe+  applicativeSpecOnArbitrary @[]+  applicativeSpecOnArbitrary @Maybe+  applicativeSpecOnGens+    @[]+    @Int+    (pure 4)+    "four"+    (genListOf $ pure 5)+    "list of fives"+    (pure [])+    "purely empty list"+    ((+) <$> genValid)+    "increments"+    (pure <$> ((+) <$> genValid))+    "increments in a list"+    (pure <$> ((*) <$> genValid))+    "scalings in a list"+  applicativeSpecOnGens+    @Maybe+    @String+    (pure "ABC")+    "ABC"+    (Just <$> pure "ABC")+    "Just an ABC"+    (pure Nothing)+    "purely Nothing"+    ((++) <$> genValid)+    "prepends"+    (pure <$> ((++) <$> genValid))+    "prepends in a Just"+    (pure <$> (flip (++) <$> genValid))+    "appends in a Just"
+ test/Test/Validity/ArbitrarySpec.hs view
@@ -0,0 +1,9 @@+{-# LANGUAGE TypeApplications #-}++module Test.Validity.ArbitrarySpec where++import Test.Hspec+import Test.Validity.Arbitrary++spec :: Spec+spec = arbitrarySpec @Int
+ test/Test/Validity/EqSpec.hs view
@@ -0,0 +1,34 @@+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE TypeApplications #-}++module Test.Validity.EqSpec where++import Data.GenValidity+import GHC.Generics (Generic)+import Test.Hspec+import Test.Validity.Eq+import Test.Validity.Utils++spec :: Spec+spec = do+  eqSpec @Rational+  eqSpec @Int+  -- eqSpec @Double DOES NOT HOLD because of NaN+  eqSpecOnArbitrary @Int+  eqSpecOnGen ((* 2) <$> genValid @Int) "even" (const [])+  failsBecause "(/=) and (==) don't have opposite semantics" $+    eqSpec @EqFuncMismatch++newtype EqFuncMismatch+  = EqFuncMismatch ()+  deriving (Show, Generic)++instance Validity EqFuncMismatch++instance Eq EqFuncMismatch where+  (==) _ _ = True+  (/=) _ _ = True++instance GenValid EqFuncMismatch where+  genValid = EqFuncMismatch <$> genValid+  shrinkValid _ = []
+ test/Test/Validity/FunctorSpec.hs view
@@ -0,0 +1,55 @@+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE TypeApplications #-}++module Test.Validity.FunctorSpec where++import Data.GenValidity+import GHC.Generics (Generic)+import Test.Hspec+import Test.Validity.Functor+import Test.Validity.Utils++spec :: Spec+spec = do+  functorSpec @[]+  functorSpec @Maybe+  failsBecause "Fcks does not satisfy any Functor laws" $ functorSpec @Fcks+  functorSpec @(Either Int)+  functorSpec @((,) Int)+  functorSpecOnArbitrary @[]+  functorSpecOnArbitrary @Maybe+  functorSpecOnGens+    @[]+    @Int+    (pure 4)+    "four"+    (genListOf $ pure 5)+    "list of fives"+    ((+) <$> genValid)+    "increments"+    ((*) <$> genValid)+    "scalings"+  functorSpecOnGens+    @Maybe+    @String+    (pure "ABC")+    "ABC"+    (Just <$> pure "ABC")+    "Just an ABC"+    ((++) <$> genValid)+    "prepends"+    (flip (++) <$> genValid)+    "appends"++newtype Fcks a+  = Fcks Int+  deriving (Show, Eq, Generic)++instance Validity (Fcks a)++instance GenValid (Fcks a) where+  genValid = Fcks <$> genValid+  shrinkValid (Fcks i) = Fcks <$> shrinkValid i++instance Functor Fcks where+  fmap _ (Fcks i) = Fcks $ i * 2
+ test/Test/Validity/GenRelativeValiditySpec.hs view
@@ -0,0 +1,7 @@+module Test.Validity.GenRelativeValiditySpec where++import Test.Hspec++-- import Test.Validity.GenRelativeValidity+spec :: Spec+spec = pure () -- TODO add examples once we have some instances
+ test/Test/Validity/GenValiditySpec.hs view
@@ -0,0 +1,11 @@+{-# LANGUAGE TypeApplications #-}++module Test.Validity.GenValiditySpec where++import Test.Hspec+import Test.Validity.GenValidity++spec :: Spec+spec = do+  genValidSpec @Rational+  genValidSpec @Rational
+ test/Test/Validity/MonadSpec.hs view
@@ -0,0 +1,51 @@+{-# LANGUAGE TypeApplications #-}++module Test.Validity.MonadSpec where++import Data.GenValidity+import Test.Hspec+import Test.Validity.Monad++{-# ANN module "HLint: ignore Use :" #-}++spec :: Spec+spec = do+  monadSpec @[]+  monadSpec @Maybe+  monadSpec @(Either Int)+  monadSpecOnArbitrary @[]+  monadSpecOnArbitrary @Maybe+  monadSpecOnGens+    @[]+    @Int+    (pure 4)+    "four"+    (genListOf $ pure 5)+    "list of fives"+    (genListOf $ pure 6)+    "list of sixes"+    ((*) <$> genValid)+    "factorisations"+    (pure $ \a -> [a])+    "singletonisation"+    (pure $ \a -> [a])+    "singletonisation"+    (pure $ pure (+ 1))+    "increment in list"+  monadSpecOnGens+    @Maybe+    @String+    (pure "ABC")+    "ABC"+    (Just <$> pure "ABC")+    "Just an ABC"+    (Just <$> pure "CDE")+    "Just an ABC"+    (flip (++) <$> genValid)+    "appends"+    (pure $ \a -> Just a)+    "justisation"+    (pure $ \a -> Just a)+    "justisation"+    (pure $ pure (++ "a"))+    "append 'a' in Just"
+ test/Test/Validity/MonoidSpec.hs view
@@ -0,0 +1,13 @@+{-# LANGUAGE TypeApplications #-}++module Test.Validity.MonoidSpec where++import Test.Hspec+import Test.Validity.Monoid++spec :: Spec+spec = do+  monoidSpecOnValid @[Rational]+  monoidSpec @[Int]+  monoidSpecOnArbitrary @[Int]+  monoidSpecOnGen (pure "a") "singleton list of 'a'" (const [])
+ test/Test/Validity/OrdSpec.hs view
@@ -0,0 +1,16 @@+{-# LANGUAGE TypeApplications #-}++module Test.Validity.OrdSpec where++import Data.GenValidity+import Test.Hspec+import Test.Validity.Ord+import Test.Validity.Utils++spec :: Spec+spec = do+  ordSpec @Rational+  failsBecause "NaN >= NaN is False" $ ordSpec @Double+  ordSpec @Int+  ordSpecOnArbitrary @Int+  ordSpecOnGen ((* 2) <$> genValid @Int) "even" (const [])
+ test/Test/Validity/RelativeValiditySpec.hs view
@@ -0,0 +1,7 @@+module Test.Validity.RelativeValiditySpec where++import Test.Hspec++-- import Test.Validity.RelativeValidity+spec :: Spec+spec = pure ()
+ test/Test/Validity/ShowSpec.hs view
@@ -0,0 +1,32 @@+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE TypeApplications #-}++module Test.Validity.ShowSpec where++import Data.GenValidity+import GHC.Generics (Generic)+import Test.Hspec+import Test.Validity.Show+import Test.Validity.Utils++spec :: Spec+spec = do+  showReadSpec @Rational+  showReadSpec @Int+  showReadSpecOnArbitrary @Rational+  showReadSpecOnGen ((* 2) <$> genValid @Int) "even" (const [])+  failsBecause "show and read don't have the correct semantics" $+    showReadSpec @ShowFuncMismatch++data ShowFuncMismatch+  = ShowFuncMismatch+  deriving (Eq, Read, Generic)++instance Validity ShowFuncMismatch++instance Show ShowFuncMismatch where+  show ShowFuncMismatch = "wrong"++instance GenValid ShowFuncMismatch where+  genValid = pure ShowFuncMismatch+  shrinkValid _ = []
+ test/Test/Validity/ShrinkingSpec.hs view
@@ -0,0 +1,25 @@+{-# LANGUAGE TypeApplications #-}++module Test.Validity.ShrinkingSpec where++import Data.Int+import Data.Ratio+import Test.Hspec+import Test.Validity.Shrinking++spec :: Spec+spec = do+  shrinkValidSpec @(Ratio Int8)+  shrinkValidSpec @Int+  describe "shrinkValidPreservesValidOnGenValid" $ do+    it "Ordering" $ shrinkValidPreservesValidOnGenValid @Ordering+    it "[Ordering]" $ shrinkValidPreservesValidOnGenValid @[Ordering]+  describe "shrinkValidPreservesValidOnGenValid" $ do+    it "Ordering" $ shrinkValidPreservesValidOnGenValid @Ordering+    it "[Ordering]" $ shrinkValidPreservesValidOnGenValid @[Ordering]+  describe "shrinkValidDoesNotShrinkToItself" $ do+    it "Int" $ shrinkValidDoesNotShrinkToItself @Int+    it "[Int]" $ shrinkValidDoesNotShrinkToItself @[Int]+  describe "shrinkValidDoesNotShrinkToItself" $ do+    it "Ordering" $ shrinkValidDoesNotShrinkToItself @Ordering+    it "[Ordering]" $ shrinkValidDoesNotShrinkToItself @[Ordering]