packages feed

extrapolate 0.0.1 → 0.1.0

raw patch · 10 files changed

+508/−49 lines, 10 filesdep ~basedep ~leancheckdep ~speculate

Dependency ranges changed: base, leancheck, speculate

Files

README.md view
@@ -4,37 +4,39 @@ [![Extrapolate Build Status][build-status]][build-log] [![Extrapolate on Hackage][hackage-version]][extrapolate-on-hackage] -Extrapolate automatically generalizes counter-examples to test properties.+Extrapolate is a property-based testing library for Haskell+capable of reporting generalized counter-examples.   Example ------- -Consider the following (faulty) sort function and property:+Consider the following (faulty) sort function and a property about it:      sort :: Ord a => [a] -> [a]-    sort [] = []-    sort (x:xs) = sort (filter (< x) xs)-               ++ [x]-               ++ sort (filter (> x) xs)+    sort []      =  []+    sort (x:xs)  =  sort (filter (< x) xs)+                 ++ [x]+                 ++ sort (filter (> x) xs)      prop_sortCount :: Ord a => a -> [a] -> Bool-    prop_sortCount x xs = count x (sort xs) == count x xs+    prop_sortCount x xs  =  count x (sort xs) == count x xs       where       count x = length . filter (== x) -Extrapolate both returns a fully defined counter-example along with a-generalization:+After testing the property, Extrapolate returns a fully defined counter-example+along with a generalization:      > import Test.Extrapolate     > check (prop_sortCount :: Int -> [Int] -> Bool)     *** Failed! Falsifiable (after 4 tests):     0 [0,0]+     Generalization:     x (x:x:xs) -This hopefully makes it easier to find the source of the bug.-In this case, the faulty sort function discard repeated elements.+This hopefully makes it easier to find the source of the bug.  In this case,+the faulty sort function discards repeated elements.   More documentation
TODO.md view
@@ -3,6 +3,24 @@  A non-exhaustive list of things TO DO for Extrapolate. ++bugs+----++* `stack-derivation`:+  the current derivation mechanism cannot handle the following datatype:++    data Stack a = Stack a (Stack a) | Empty++  Change it to use `asTypeOf` instead of `argTypes0`.++* `simplify-derived-instances`:+  it seems to me that `argTypesN` is too complicated and unreliable and there+  is a simpler solution.  Maybe using sommething like `stack-derivation` but+  for all other arities of constructors.  For example, I don't think+  `argTypesN` can handle the `Either` type.  Test and see.++ examples -------- 
extrapolate.cabal view
@@ -1,5 +1,5 @@ name:                extrapolate-version:             0.0.1+version:             0.1.0 synopsis:            generalize counter-examples of test properties description:   Extrapolate is a tool able to provide generalized counter-examples of test@@ -31,7 +31,7 @@ source-repository this   type:            git   location:        https://github.com/rudymatela/speculate-  tag:             v0.0.1+  tag:             v0.1.0  library   exposed-modules: Test.Extrapolate@@ -43,13 +43,12 @@                  , Test.Extrapolate.TypeBinding   other-modules:   Test.Extrapolate.Utils   other-extensions:    TemplateHaskell, CPP-  build-depends: base >=4.9 && <4.10-               , leancheck+  build-depends: base >= 4 && < 5+               , leancheck >= 0.6.4                , template-haskell-               , speculate+               , speculate >= 0.2.6   hs-source-dirs:      src   default-language:    Haskell2010-  ghc-options:         -dynamic  test-suite test   type:                exitcode-stdio-1.0@@ -57,9 +56,10 @@   hs-source-dirs:      src, tests   build-depends:       base >= 4 && < 5, leancheck, speculate, template-haskell   default-language:    Haskell2010-  ghc-options:         -dynamic --- NOTE: for some reason, my system is not able to compile extrapolate using--- cabal unless the -dynamic flag is present in ghc-options.  I do not know if--- this affects other systems, so I am including it by default.---           --  Rudy  2017-08-01+test-suite derive+  type:                exitcode-stdio-1.0+  main-is:             test-derive.hs+  hs-source-dirs:      src, tests+  build-depends:       base >= 4 && < 5, leancheck, speculate, template-haskell+  default-language:    Haskell2010
src/Test/Extrapolate.hs view
@@ -4,31 +4,70 @@ -- License     : 3-Clause BSD  (see the file LICENSE) -- Maintainer  : Rudy Matela <rudy@matela.com.br> ----- Extrapolate is a library for generalization of counter-examples.+-- Extrapolate is a property-based testing library capable of reporting+-- generalized counter-examples. -- -- Consider the following faulty implementation of sort: -- -- > sort :: Ord a => [a] -> [a]--- > sort [] = []--- > sort (x:xs) = sort (filter (< x) xs)--- >            ++ [x]--- >            ++ sort (filter (> x) xs)+-- > sort []      =  []+-- > sort (x:xs)  =  sort (filter (< x) xs)+-- >              ++ [x]+-- >              ++ sort (filter (> x) xs) ----- Extrapolate works like so:+-- When tests pass, Extrapolate works like a regular property-based testing+-- library.  See: ----- > > check $ \xs -> ordered (sort xs)--- > +++ OK, passed 360 tests!--- > > check $ \x xs -> count x (sort xs) == count x xs--- > *** Failed! Falsifiable (after 4 tests):--- > 0 [0,0]+-- > > check $ \xs -> sort (sort xs :: [Int]) == sort xs+-- > +++ OK, passed 360 tests.+--+-- When tests fail, Extrapolate reports a fully defined counter-example and a+-- generalization of failing inputs.  See:+--+-- > > > check $ \xs -> length (sort xs :: [Int]) == length xs+-- > *** Failed! Falsifiable (after 3 tests):+-- > [0,0]+-- > -- > Generalization:--- > x (x:x:xs)+-- > x:x:_+--+-- The property fails for any integer @x@ and for any list @_@ at the tail. module Test.Extrapolate-  ( module Test.Extrapolate.Core-  , module Test.Extrapolate.Basic-  , module Test.Extrapolate.Derive+  (+-- * Checking properties+    check+  , checkResult+  , for+  , withBackground+  , withConditionSize++-- * Obtaining generalizations+  , counterExampleGen+  , counterExampleGens++-- * Generalizable types+-- | The following typeclass and functions are currently very hacky.+--   Expect them to change in the near future.+  , Generalizable (..)+  , this+  , these+  , usefuns+  , nameOf+  , Expr (..)+  , constant, showConstant++-- * Testable properties+  , Testable++-- ** Automatically deriving Generalizable instances+  , deriveGeneralizable+  , deriveGeneralizableIfNeeded+  , deriveGeneralizableCascading++-- * Other useful modules   , module Test.Extrapolate.TypeBinding-  , module Test.Extrapolate.IO+  , module Test.LeanCheck+  , module Test.LeanCheck.Utils.TypeBinding   ) where @@ -37,3 +76,16 @@ import Test.Extrapolate.Derive import Test.Extrapolate.TypeBinding import Test.Extrapolate.IO++import Test.LeanCheck hiding+  ( Testable (..)+  , results+  , counterExamples+  , counterExample+  , productWith+  , check+  , checkFor+  , checkResult+  , checkResultFor+  )+import Test.LeanCheck.Utils.TypeBinding
src/Test/Extrapolate/Core.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE DeriveDataTypeable #-} -- for GHC <= 7.8 -- | -- Module      : Test.Extrapolate.Core -- Copyright   : (c) 2017 Rudy Matela@@ -19,6 +20,7 @@   , usefuns   , (+++)   , nameOf+  , backgroundOf    , Option (..)   , options@@ -67,6 +69,7 @@ import Data.Maybe (listToMaybe, fromJust, isJust) import Data.Either (isRight) import Data.List (insert)+import Data.Functor ((<$>)) -- for GHC <= 7.8 import Test.Extrapolate.Exprs import Test.LeanCheck.Error (errorToFalse) @@ -76,6 +79,11 @@   useful _ = []   instances :: a -> Instances -> Instances   instances _ = id+-- TODO: change Generalizable to include name and background:+--   name :: a -> String+--   background :: a -> [Expr]+-- Use the instance being declared itself on instances.+-- This is a _big change_: prototype first.  instance Generalizable () where   expr = showConstant@@ -177,6 +185,9 @@ getBackground :: Instances -> [Expr] getBackground is = concat [es | Instance "Background" _ es <- is] +backgroundOf :: Generalizable a => a -> [Expr]+backgroundOf x = getBackground $ instances x []+ -- |  generalizes an expression by making it less defined, --    starting with smaller changes, then bigger changes: --@@ -213,7 +224,7 @@ data Option = MaxTests Int             | ExtraInstances Instances             | MaxConditionSize Int-  deriving Show+  deriving (Show, Typeable) -- Typeable needed for GHC <= 7.8  data WithOption a = With                   { property :: a
src/Test/Extrapolate/Derive.hs view
@@ -21,7 +21,7 @@   ) where -import Test.Extrapolate.Core (Generalizable(..), Expr ((:$)))+import Test.Extrapolate.Core hiding (isInstanceOf) import Test.Extrapolate.TypeBinding import Language.Haskell.TH import Test.LeanCheck.Basic@@ -29,6 +29,7 @@ import Control.Monad (unless, liftM, liftM2, filterM) import Data.List (delete,nub,sort) import Data.Char (toLower)+import Data.Functor ((<$>)) -- for GHC <= 7.8 import Data.Typeable  -- | Derives a 'Generalizable' instance for a given type 'Name'.@@ -44,9 +45,14 @@ -- will automatically derive the following 'Generalizable' instance: -- -- > instance Generalizable a => Generalizable (Stack a) where--- >   tiers = cons2 Stack \/ cons0 Empty+-- >   expr s@(Stack x y) = constant "Stack" (Stack ->>: s) :$ expr x :$ expr y+-- >   expr s@Empty       = constant "Empty" (Empty   -: s)+-- >   instances s = this "s" s+-- >               $ let Stack x y = Stack undefined undefined `asTypeOf` s+-- >                 in instances x+-- >                  . instances y ----- Needs the @TemplateHaskell@ extension.+-- This function needs the @TemplateHaskell@ extension. deriveGeneralizable :: Name -> DecsQ deriveGeneralizable = deriveGeneralizableX True False @@ -78,18 +84,24 @@   isEq <- t `isInstanceOf` ''Eq   isOrd <- t `isInstanceOf` ''Ord   (nt,vs) <- normalizeType t+#if __GLASGOW_HASKELL__ >= 710   cxt <- sequence [ [t| $(conT c) $(return v) |]+#else+  -- template-haskell <= 2.9.0.0:+  cxt <- sequence [ classP c [return v]+#endif                   | c <- ''Generalizable:([''Eq | isEq] ++ [''Ord | isOrd])                   , v <- vs]   cs <- typeConstructorsArgNames t+  asName <- newName "x"   let generalizableExpr = mergeIFns $ foldr1 mergeI-        [ do argTypesN <- lookupValN $ "argTypes" ++ show (length ns)+        [ do retTypeOf <- lookupValN $ "-" ++ replicate (length ns) '>' ++ ":"              let exprs = [[| expr $(varE n) |] | n <- ns]-             let conex = foldl AppE (VarE argTypesN) $ (ConE c:map VarE ns)-             let root = [| constant $(stringE $ showJustName c) $(return conex) |]+             let conex = [| $(varE retTypeOf) $(conE c) $(varE asName) |]+             let root = [| constant $(stringE $ showJustName c) $(conex) |]              let rhs = foldl (\e1 e2 -> [| $e1 :$ $e2 |]) root exprs              [d| instance Generalizable $(return nt) where-                   expr ($(conP c (map varP ns))) = $rhs |]+                   expr $(asP asName $ conP c (map varP ns)) = $rhs |]         | (c,ns) <- cs         ]   let generalizableInstances = do@@ -329,7 +341,11 @@ mergeIFns qds = do ds <- qds                    return $ map m' ds   where+#if __GLASGOW_HASKELL__ < 800+  m' (InstanceD   c ts ds) = InstanceD   c ts [foldr1 m ds]+#else   m' (InstanceD o c ts ds) = InstanceD o c ts [foldr1 m ds]+#endif   FunD n cs1 `m` FunD _ cs2 = FunD n (cs1 ++ cs2)  mergeI :: DecsQ -> DecsQ -> DecsQ@@ -337,13 +353,22 @@                         ds2 <- qds2                         return $ ds1 `m` ds2   where+#if __GLASGOW_HASKELL__ < 800+  [InstanceD   c ts ds1] `m` [InstanceD   _ _ ds2] = [InstanceD   c ts (ds1 ++ ds2)]+#else   [InstanceD o c ts ds1] `m` [InstanceD _ _ _ ds2] = [InstanceD o c ts (ds1 ++ ds2)]+#endif  whereI :: DecsQ -> [Dec] -> DecsQ qds `whereI` w = do ds <- qds                     return $ map (`aw` w) ds+#if __GLASGOW_HASKELL__ < 800+  where aw (InstanceD   c ts ds) w' = InstanceD   c ts (ds++w')+        aw d                     _  = d+#else   where aw (InstanceD o c ts ds) w' = InstanceD o c ts (ds++w')         aw d                     _  = d+#endif  -- > nubMerge xs ys == nub (merge xs ys) -- > nubMerge xs ys == nub (sort (xs ++ ys))
src/Test/Extrapolate/Exprs.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE DeriveDataTypeable #-} -- for GHC <= 7.8 -- | -- Module      : Test.Extrapolate.IO -- Copyright   : (c) 2017 Rudy Matela@@ -34,7 +35,7 @@ import qualified Test.Speculate.Expr as E import qualified Test.Speculate.Engine as E import Test.LeanCheck.Error (errorToFalse)-import Data.Typeable (typeOf, TypeRep)+import Data.Typeable (typeOf, TypeRep, Typeable) import Data.List ((\\))  canonicalizeWith :: Instances -> [Expr] -> [Expr]@@ -75,6 +76,7 @@   rs = [errorToFalse $ eval False e' | [e'] <- take m $ grounds is [e]]  data MarkerType = MarkerType+  deriving Typeable -- for GHC <= 7.8  fold :: [Expr] -> Expr fold []     = constant "[]" MarkerType
src/Test/Extrapolate/IO.hs view
@@ -29,15 +29,35 @@ import Data.List (find, intercalate) import Control.Exception as E (SomeException, catch, evaluate) +-- | Use @`for`@ to configure the number of tests performed by @check@.+--+-- > > check `for` 10080 $ \xs -> sort (sort xs) == sort (xs :: [Int])+-- > +++ OK, passed 10080 tests.+--+-- Don't forget the dollar (@$@)! for :: Testable a => (WithOption a -> b) -> Int -> a -> b check `for` m  =  \p -> check $ p `With` MaxTests m +-- | Allows the user to customize instance information available when generalized.+--   (For advanced users.) withInstances :: Testable a => (WithOption a -> b) -> Instances -> a -> b check `withInstances` is  =  \p -> check $ p `With` ExtraInstances is +-- | Use @`withBackground`@ to provide additional functions to appear in side-conditions.+--+-- > check `withBackground` [constant "isSpace" isSpace] $ \xs -> unwords (words xs) == xs+-- > *** Failed! Falsifiable (after 4 tests):+-- > " "+-- >+-- > Generalization:+-- > ' ':_+-- >+-- > Conditional Generalization:+-- > c:_  when  isSpace c withBackground :: Testable a => (WithOption a -> b) -> [Expr] -> a -> b check `withBackground` ufs  =  check `withInstances` usefuns (undefined::Option) ufs +-- | Use @`withConditionSize`@ to configure the maximum condition size allowed. withConditionSize :: Testable a => (WithOption a -> b) -> Int -> a -> b check `withConditionSize` s  =   \p -> check $ p `With` MaxConditionSize s @@ -45,11 +65,13 @@ -- -- > > check $ \xs -> sort (sort xs) == sort (xs::[Int]) -- > +++ OK, passed 360 tests.+-- > -- > > check $ \xs ys -> xs `union` ys == ys `union` (xs::[Int]) -- > *** Failed! Falsifiable (after 4 tests): -- > [] [0,0]+-- > -- > Generalization:--- > [] (x:x:xs)+-- > [] (x:x:_) check :: Testable a => a -> IO () check p = checkResult p >> return () @@ -58,7 +80,7 @@ --   returning 'True' on success. -- -- There is no option to silence this function:--- for silence, you should use 'TestLean.Check.holds'.+-- for silence, you should use 'Test.LeanCheck.holds'. checkResult :: Testable a => a -> IO Bool checkResult p = do   (r,ces) <- resultIO m p
+ tests/test-derive.hs view
@@ -0,0 +1,192 @@+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE DeriveDataTypeable, StandaloneDeriving, CPP #-} -- for GHC <= 7.8+-- Copyright (c) 2017 Rudy Matela.+-- Distributed under the 3-Clause BSD licence (see the file LICENSE).+import Test+import Data.List (isPrefixOf)++#if __GLASGOW_HASKELL__ < 710+import Data.Typeable (Typeable)+deriving instance Typeable List+deriving instance Typeable Perhaps+deriving instance Typeable Ship+deriving instance Typeable Arrangement+deriving instance Typeable NonEmptyList+deriving instance Typeable Mutual+deriving instance Typeable Shared+deriving instance Typeable Tree+deriving instance Typeable Leafy+deriving instance Typeable Dict+#endif++-- List is isomorphic to []+data List a = Cons a (List a)+            | Nil+  deriving (Show, Eq, Ord)++-- Perhaps is isomorphic to Maybe+data Perhaps a = Naught+               | Simply a+  deriving (Show, Eq, Ord)++-- Ship is isomorphic to Either+data Ship a b = Port a+              | Starboard b+  deriving (Show, Eq, Ord)++-- Arrangement is isomorphic to Ordering+data Arrangement = Lesser+                 | Equal+                 | Greater+  deriving (Show, Eq, Ord)++data NonEmptyList a = Buil a (NonEmptyList a)+                    | Unit a+  deriving (Show, Eq, Ord)++data Mutual a = Mutual a (Shared a) | M a deriving (Show, Eq, Ord)+data Shared a = Shared (Mutual a) a | S a deriving (Show, Eq, Ord)++data Tree a  = Node (Tree a) a (Tree a) | Empty+  deriving (Show, Eq, Ord)++data Leafy a = Branch (Leafy a) (Leafy a) | Leaf a+  deriving (Show, Eq, Ord)++data Dict a b = Meaning a b (Dict a b)+              | End+  deriving (Show, Eq, Ord)+++-- Dummy undefined values --++ls :: a -> List a+ls = undefined++perhaps :: a -> Perhaps a+perhaps = undefined++ship :: a -> b -> Ship a b+ship = undefined++arrangement :: Arrangement+arrangement = undefined++nonEmptyList :: a -> NonEmptyList a+nonEmptyList = undefined++mutual :: a -> Mutual a+mutual = undefined++shared :: a -> Shared a+shared = undefined++tree :: a -> Tree a+tree = undefined++leafy :: a -> Leafy a+leafy = undefined++dict :: a -> b -> Dict a b+dict = undefined+++-- TODO: auto-derive Listable from deriveGeneralizable?+deriveListable ''List+deriveListable ''Perhaps+deriveListable ''Ship+deriveListable ''Arrangement++deriveListable ''NonEmptyList++deriveListable ''Mutual+deriveListable ''Shared++deriveListable ''Tree+deriveListable ''Leafy++deriveListable ''Dict+++deriveGeneralizable ''List+{- -- derivation:+instance (Generalizable a) => Generalizable (List a) where+  expr xs@Nil          =  constant "Nil"  (Nil    -: xs)+  expr xs@(Cons y ys)  =  constant "Cons" (Cons ->>: xs) :$ expr y :$ expr ys+  instances xs = this "xs" xs+               $ instances (argTy1of1 xs)+-- note the use of -: and ->>: instead of argTypes<N>+-}++deriveGeneralizable ''Perhaps+{- -- derivation:+instance (Generalizable a) => Generalizable (Perhaps a) where+  expr px@Naught      =  constant "Naught" (Naught  -: px)+  expr px@(Simply x)  =  constant "Simply" (Simply ->: px) :$ expr x+  instances px = this "px" px+               $ instances (argTy1of1 px)+-}++deriveGeneralizable ''Ship+{- -- derivation:+instance (Generalizable a, Generalizable b) => Generalizable (Ship a b) where+  expr s@(Port x)       =  constant "Port"      (Port      ->: s) :$ expr x+  expr s@(Starboard y)  =  constant "Starboard" (Starboard ->: s) :$ expr y+  instances s = this "s" s+              $ instances (argTy1of2 s)+              . instances (argTy2of2 s)+-}++-- deriveGeneralizable ''Arrangement -- TODO: make this work++deriveGeneralizable ''NonEmptyList++deriveGeneralizable ''Mutual+deriveGeneralizable ''Shared++deriveGeneralizable ''Tree+deriveGeneralizable ''Leafy++deriveGeneralizable ''Dict+++main :: IO ()+main = mainTest tests 2160++tests :: Int -> [Bool]+tests n =+  [ True++  , holds n $ generalizableOK -:> ls int+  , holds n $ generalizableOK -:> ls bool+  , holds n $ generalizableOK -:> perhaps int+  , holds n $ generalizableOK -:> perhaps bool+  , holds n $ generalizableOK -:> ship int int+  , holds n $ generalizableOK -:> ship bool ()+--, holds n $ generalizableOK -:> arrangement -- TODO: make this work+  , holds n $ generalizableOK -:> mutual int+  , holds n $ generalizableOK -:> mutual bool+  , holds n $ generalizableOK -:> shared int+  , holds n $ generalizableOK -:> shared bool+  , holds n $ generalizableOK -:> tree int+  , holds n $ generalizableOK -:> tree bool+  , holds n $ generalizableOK -:> leafy int+  , holds n $ generalizableOK -:> leafy bool+  , holds n $ generalizableOK -:> dict int bool+  , holds n $ generalizableOK -:> dict bool int+  ]+++generalizableOK :: (Eq a, Show a, Generalizable a) => a -> Bool+generalizableOK x = idExprEval x && showOK x++idExprEval :: (Eq a, Generalizable a) => a -> Bool+idExprEval x = eval (error "idExprEval: could not eval") (expr x) == x++showOK :: (Show a, Generalizable a) => a -> Bool+showOK x = show x == dropType (show (expr x))+  where+  dropType :: String -> String+  dropType cs     | " :: " `isPrefixOf` cs = ""+  dropType ""     =  ""+  dropType (c:cs) =  c : dropType cs
tests/test-extrapolate.hs view
@@ -2,10 +2,145 @@ -- Distributed under the 3-Clause BSD licence (see the file LICENSE). import Test +import Data.List (sort)+ main :: IO () main = mainTest tests 10000  tests :: Int -> [Bool] tests n =   [ True++  -- Transforming lists into Exprs+  , expr ([]::[Int]) == constant "[]" ([]::[Int])+  , expr ([0::Int])  == zero -:- ll+  , expr ([0::Int,1])  == zero -:- one -:- ll+  , holds n $ \xs -> expr xs == foldr (-:-) ll (map expr (xs :: [Int]))+  , holds n $ \ps -> expr ps == foldr (-:-) llb (map expr (ps :: [Bool]))++  -- Transforming Maybes into Exprs+  , expr (Nothing    :: Maybe Int)   ==  nothing+  , expr (Nothing    :: Maybe Bool)  ==  nothingBool+  , expr (Just 1     :: Maybe Int)   ==  just one+  , expr (Just False :: Maybe Bool)  ==  just false+  , holds n $ \x -> expr (Just x) == just (expr (x :: Int))+  , holds n $ \p -> expr (Just p) == just (expr (p :: Bool))++  -- Transforming Tuples into Exprs+  , expr ((0,False) :: (Int,Bool))  ==  zero `comma` false+  , expr ((True,1)  :: (Bool,Int))  ==  true `comma` one++  -- Showing of Exprs+  , holds n $ \x -> show (expr x) == show (x :: ()) ++ " :: ()"+  , holds n $ \x -> show (expr x) == show (x :: Int) ++ " :: Int"+  , holds n $ \p -> show (expr p) == show (p :: Bool) ++ " :: Bool"+  , holds n $ \x -> show (expr x) == show (x :: Integer) ++ " :: Integer"++  , holds 9 $ \xs -> show (expr xs) == show (xs :: [()]) ++ " :: [()]"+  , holds n $ \xs -> show (expr xs) == show (xs :: [Int]) ++ " :: [Int]"+  , holds n $ \ps -> show (expr ps) == show (ps :: [Bool]) ++ " :: [Bool]"+  , holds n $ \xs -> show (expr xs) == show (xs :: [Integer]) ++ " :: [Integer]"++  , holds n $ \mx -> show (expr mx) == show (mx :: Maybe ()) ++ " :: Maybe ()"+  , holds n $ \mx -> show (expr mx) == show (mx :: Maybe Int) ++ " :: Maybe Int"+  , holds n $ \mp -> show (expr mp) == show (mp :: Maybe Bool) ++ " :: Maybe Bool"+  , holds n $ \mx -> show (expr mx) == show (mx :: Maybe Integer) ++ " :: Maybe Integer"++  , holds n $ \xy -> show (expr xy) == show (xy :: ((),Int)) ++ " :: ((),Int)"+  , holds n $ \xy -> show (expr xy) == show (xy :: (Bool,Integer)) ++ " :: (Bool,Integer)"+  , holds n $ \xyz -> show (expr xyz) == show (xyz :: ((),Int,Bool)) ++ " :: ((),Int,Bool)"+-- TODO: implement further tuple instances (4,5,6) and uncomment below+--, holds n $ \xyzw -> show (expr xyzw)+--                  == show (xyzw :: ((),Int,Integer,Bool)) ++ " :: ((),Int,Integer,Bool)"+--, holds n $ \xyzwv -> show (expr xyzwv)+--                   == show (xyzwv :: ((),Int,Integer,Bool,())) ++ " :: ((),Int,Integer,Bool,())"+--, holds n $ \xyzwvu -> show (expr xyzwvu)+--                    == show (xyzwvu :: ((),Int,Integer,Bool,(),Int)) ++ " :: ((),Int,Integer,Bool,(),Int)"++  , holds n $ idExprEval -:> ()+  , holds n $ idExprEval -:> int+  , holds n $ idExprEval -:> integer+  , holds n $ idExprEval -:> bool+  , holds n $ idExprEval -:> char+  , holds 9 $ idExprEval -:> [()]+  , holds n $ idExprEval -:> [int]+  , holds n $ idExprEval -:> [integer]+  , holds n $ idExprEval -:> [bool]+  , holds n $ idExprEval -:> [char]+  , holds n $ idExprEval -:> (mayb ())+  , holds n $ idExprEval -:> (mayb int)+  , holds n $ idExprEval -:> (mayb integer)+  , holds n $ idExprEval -:> (mayb bool)+  , holds n $ idExprEval -:> (mayb char)+  , holds n $ idExprEval -:> (int,bool)+  , holds n $ idExprEval -:> ((),integer)+  , holds n $ idExprEval -:> ((),bool,integer)+-- TODO: implement further tuple instances (4,5,6) and uncomment below+--, holds n $ idExprEval -:> (int,(),bool,integer)+--, holds n $ idExprEval -:> (int,(),bool,integer,char)+--, holds n $ idExprEval -:> (string,int,(),bool,integer,char)+-- TODO: implement further tuple instances (7,8,9,10,11,12) and uncomment below+--, holds n $ idExprEval -:> ((),(),(),(),(),(),())+--, holds n $ idExprEval -:> ((),(),(),(),(),(),(),())+--, holds n $ idExprEval -:> ((),(),(),(),(),(),(),(),())+--, holds n $ idExprEval -:> ((),(),(),(),(),(),(),(),(),())+--, holds n $ idExprEval -:> ((),(),(),(),(),(),(),(),(),(),())+--, holds n $ idExprEval -:> ((),(),(),(),(),(),(),(),(),(),(),())+++  -- Silly test, as it basically replicates the actual implementation:+  , backgroundOf int =$ sort $= [ constant "==" $ (==) -:> int+                                , constant "/=" $ (/=) -:> int+                                , constant "<=" $ (<=) -:> int+                                , constant "<"  $ (<)  -:> int+                                ]++  -- background tests+  , listBackgroundOK ()+  , listBackgroundOK int+  , listBackgroundOK integer+  , listBackgroundOK bool+  , listBackgroundOK char+  , listBackgroundOK [()]+  , listBackgroundOK [int]+  , listBackgroundOK [integer]+  , listBackgroundOK [bool]+  , listBackgroundOK [char]+  , listBackgroundOK (mayb ())+  , listBackgroundOK (mayb int)+  , listBackgroundOK (mayb integer)+  , listBackgroundOK (mayb bool)+  , listBackgroundOK (mayb char)++  , maybeBackgroundOK ()+  , maybeBackgroundOK int+  , maybeBackgroundOK integer+  , maybeBackgroundOK bool+  , maybeBackgroundOK char+  , maybeBackgroundOK [()]+  , maybeBackgroundOK [int]+  , maybeBackgroundOK [integer]+  , maybeBackgroundOK [bool]+  , maybeBackgroundOK [char]+  , maybeBackgroundOK (mayb ())+  , maybeBackgroundOK (mayb int)+  , maybeBackgroundOK (mayb integer)+  , maybeBackgroundOK (mayb bool)+  , maybeBackgroundOK (mayb char)   ]++idExprEval :: (Eq a, Generalizable a) => a -> Bool+idExprEval x = eval (error "idExprEval: could not eval") (expr x) == x++listBackgroundOK :: Generalizable a => a -> Bool+listBackgroundOK x = backgroundOf [x] =$ sort $= backgroundListOf x+  where+  backgroundListOf x = [ constant "length" $ length  -:> [x]+                       , constant "filter" $ filter ->:> [x]+                       ]+                     +++ backgroundOf x++maybeBackgroundOK :: Generalizable a => a -> Bool+maybeBackgroundOK x = backgroundOf (mayb x) =$ sort $= backgroundMaybeOf x+  where+  backgroundMaybeOf x = [constant "Just" $ Just -:> x] +++ backgroundOf x