packages feed

test-invariant (empty) → 0.3.1.2

raw patch · 6 files changed

+312/−0 lines, 6 filesdep +QuickCheckdep +basedep +criterionsetup-changed

Dependencies added: QuickCheck, base, criterion, tasty, tasty-quickcheck, test-invariant

Files

+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2015, Florian Knupfer++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * Redistributions in binary form must reproduce the above+      copyright notice, this list of conditions and the following+      disclaimer in the documentation and/or other materials provided+      with the distribution.++    * Neither the name of Florian Knupfer nor the names of other+      contributors may be used to endorse or promote products derived+      from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ bench/Bench.hs view
@@ -0,0 +1,12 @@+module Main where++import Criterion.Main+import Test.Invariant+import Test.QuickCheck++main :: IO ()+main = defaultMain benchmarks++benchmarks :: [Benchmark]+benchmarks = [ bench "Monotonic" . nfIO . quickCheck $ monotonicIncreasing (*(0::Int)) ]+
+ src/Test/Invariant.hs view
@@ -0,0 +1,181 @@+module Test.Invariant where++import Test.QuickCheck+infix 1 <=>, &>++-- | Defines extensional equality.  This allows concise, point-free,+-- definitions of laws.  For example idempotence:+--+-- > f <=> f . f+(<=>) :: Eq b => (a -> b) -> (a -> b) -> a -> Bool+(f <=> g) x = f x == g x++-- | Pointfree version of QuickChecks ==>.  This notation reduces a+-- lot of lambdas, for example:+--+-- >>> quickCheck $ (/=0) &> not . idempotent (*(2::Int))+-- +++ OK, passed 100 tests.+(&>) :: Testable b => (a -> Bool) -> (a -> b) -> a -> Property+(a &> b) x = a x ==> b x++-- | Checks whether a function is idempotent.+--+-- > f(f(x)) == f(x)+--+-- >>> quickCheck $ idempotent (abs :: Int -> Int)+-- +++ OK, passed 100 tests.+idempotent :: Eq a => (a -> a) -> a -> Bool+idempotent f = f <=> f . f++-- | Checks whether a function is pointSymmetric.+--+-- > f(-x) == -f(x)+--+-- >>> quickCheck $ pointSymmetric (^3)+-- +++ OK, passed 100 tests.+pointSymmetric :: (Num a, Num b, Eq b) => (a -> b) -> a -> Bool+pointSymmetric f = f . negate <=> negate . f++-- | Checks whether a function is reflectionSymmetric.+--+-- > f(x) == f(-x)+--+-- >>> quickCheck $ pointSymmetric (^2)+-- +++ OK, passed 100 tests.+reflectionSymmetric :: (Num a, Eq b) => (a -> b) -> a -> Bool+reflectionSymmetric f = f . negate <=> f++-- | Checks whether a function is monotonicIncreasing.+--+-- > x >= y,  f(x) >= f(y)+--+-- >>> quickCheck $ monotonicIncreasing ceiling+-- +++ OK, passed 100 tests.+monotonicIncreasing :: (Ord a, Ord b) => (a -> b) -> a -> a -> Bool+monotonicIncreasing f x y  = compare (f x) (f y) `elem` [EQ, compare x y]++-- | Checks whether a function is strictly monotonicIncreasing'.+--+-- > x > y,  f(x) > f(y)+--+-- >>> quickCheck $ monotonicIncreasing' (+1)+-- +++ OK, passed 100 tests.+monotonicIncreasing' :: (Ord a, Ord b) => (a -> b) -> a -> a -> Bool+monotonicIncreasing' f x y = compare (f x) (f y) == compare x y++-- | Checks whether a function is monotonicDecreasing.+--+-- > x >= y,  f(x) <= f(y)+--+-- >>> quickCheck $ monotonicDecreasing (\x -> floor $ negate x)+-- +++ OK, passed 100 tests.+monotonicDecreasing :: (Ord a, Ord b) => (a -> b) -> a -> a -> Bool+monotonicDecreasing f x y  = compare (f x) (f y) `elem` [EQ, compare y x]++-- | Checks whether a function is strictly monotonicDecreasing'.+--+-- > x > y,  f(x) < f(y)+--+-- >>> quickCheck $ monotonicDecreasing' (-1)+-- +++ OK, passed 100 tests.+monotonicDecreasing' :: (Ord a, Ord b) => (a -> b) -> a -> a -> Bool+monotonicDecreasing' f x y = compare (f x) (f y) == compare y x++-- TODO create sorted list and fold with predicate over it++-- | Checks whether a function is involutory.+--+-- > f(f(x)) = x+--+-- >>> quickCheck $ involutory negate+-- +++ OK, passed 100 tests.+involutory :: Eq a => (a -> a) -> a -> Bool+involutory f = f . f <=> id++-- | Checks whether a function is the inverse of another function.+--+-- > f(g(x)) = x+--+-- >>> quickCheck $ (`div` 2) `inverts` (*2)+-- +++ OK, passed 100 tests.+inverts :: Eq a => (b -> a) -> (a -> b) -> a -> Bool+f `inverts` g = f . g <=> id++-- | Checks whether an binary operator is commutative.+--+-- > a * b = b * a+--+-- >>> quickCheck $ commutative (+)+-- +++ OK, passed 100 tests.+commutative :: Eq b => (a -> a -> b) -> a -> a -> Bool+commutative f x y = x `f` y == y `f` x++-- | Checks whether an binary operator is associative.+--+-- > a + (b + c) = (a + b) + c+--+-- >>> quickCheck $ associative (+)+-- +++ OK, passed 100 tests.+associative :: Eq a => (a -> a -> a) -> a -> a -> a -> Bool+associative f x y z = x `f` (y `f` z) == (x `f` y) `f` z++-- | Checks whether an operator is left-distributive over an other operator.+--+-- > a * (b + c) = (a * b) + (a * c)+--+-- >>> quickCheck $ (*) `distributesLeftOver` (+)+-- +++ OK, passed 100 tests.+distributesLeftOver :: Eq a => (a -> a -> a) -> (a -> a -> a) -> a -> a -> a -> Bool+(f `distributesLeftOver` g) x y z = x `f` (y `g` z) == (x `f` y) `g` (x `f` z)++-- | Checks whether an operator is right-distributive over an other operator.+--+-- > (b + c) / a = (b / a) + (c / a)+--+-- >>> quickCheck $ (/) `distributesRightOver` (+)+-- +++ OK, passed 100 tests.+distributesRightOver :: Eq a => (a -> a -> a) -> (a -> a -> a) -> a -> a -> a -> Bool+(f `distributesRightOver` g) x y z = (y `g` z) `f` x == (x `f` y) `g` (x `f` z)++-- | Checks whether an operator is distributive over an other operator.+--+-- > a * (b + c) = (a * b) + (a * c) = (b + c) * a+--+-- >>> quickCheck $ (*) `distributesOver` (+)+-- +++ OK, passed 100 tests.+distributesOver :: Eq a => (a -> a -> a) -> (a -> a -> a) -> a -> a -> a -> Bool+(f `distributesOver` g) x y z = (f `distributesLeftOver` g) x y z+                            && (f `distributesRightOver` g) x y z++-- | Checks whether a function increases the size of a foldable.+--+-- >>> quickCheck $ inflating (1:)+-- +++ OK, passed 100 tests.+inflating :: (Foldable f, Foldable f') => (f a -> f' b) -> f a -> Bool+inflating f xs = length (f xs) > length xs++-- | Checks whether a function decreases the size of a foldable.+--+--+-- >>> quickCheck $ deflating tail+-- +++ OK, passed 100 tests.+deflating :: (Foldable f, Foldable f') => (f a -> f' b) -> f a -> Bool+deflating f xs = null xs || length (f xs) < length xs++-- | Checks whether a function is cyclic by applying its result to+-- itself within n applications.+--+-- >>> quickCheck $ (`div` 10) `cyclesWithin` 100+-- +++ OK, passed 100 tests.+cyclesWithin :: Eq a => (a -> a) -> Int -> a -> Bool+f `cyclesWithin` n = go [] . take (n + 1) . iterate f+             where go xs (y:ys) | y `elem` xs = True+                                | otherwise   = go (y:xs) ys+                   go _ _ = False++-- | Checks whether a function is invariant over an other function.+--+-- >>> quickCheck $ length `invariatesOver` reverse+-- +++ OK, passed 100 tests.+invariatesOver :: Eq b => (a -> b) -> (a -> a) -> a -> Bool+f `invariatesOver` g = f . g <=> f
+ test-invariant.cabal view
@@ -0,0 +1,56 @@+name:                test-invariant+version:             0.3.1.2+synopsis:            Provide common invariants to be checked with QuickCheck++description: test-invariant is a library for providing common invariants of+             functions as higher order polymorphic functions.  This reduces for a+             lot of cases the need for writing prop_ functions for QuickCheck.+             .+             >>> quickCheck $ idempotent (abs :: Int -> Int)+             >>> quickCheck $ involutory not+             >>> quickCheck $ not . involutory (+ (2 :: Int))++license:             BSD3+license-file:        LICENSE+author:              Florian Knupfer <fknupfer@gmail.com>+maintainer:          Florian Knupfer <fknupfer@gmail.com>+copyright:           2015 Florian Knupfer+category:            Testing+build-type:          Simple+homepage:            https://github.com/knupfer/test-invariant+-- extra-source-files:+cabal-version:       >=1.10++source-repository head+  type:     git+  location: https://github.com/knupfer/test-invariant+                     +library+  exposed-modules:   Test.Invariant+  -- other-modules:+  -- other-extensions:+  build-depends:     base >=4.8 && <4.9+                   , QuickCheck+  hs-source-dirs:    src+  default-language:  Haskell2010++test-suite Tasty+  type:              exitcode-stdio-1.0+  build-depends:     base >=4.8 && <4.9+                   , test-invariant+                   , QuickCheck+                   , tasty+                   , tasty-quickcheck+  hs-source-dirs:    test+  main-is:           Test.hs+  default-language:  Haskell2010++benchmark Criterion+  build-depends:     base+                   , test-invariant+                   , criterion+                   , QuickCheck+  default-language:  Haskell2010+  hs-source-dirs:    bench+  main-is:           Bench.hs+  type:              exitcode-stdio-1.0
+ test/Test.hs view
@@ -0,0 +1,31 @@+module Main where++import Test.Invariant+import Test.Tasty+import Test.Tasty.QuickCheck++main :: IO ()+main = defaultMain $+  testGroup "Tests"+    [ testGroup "Arity 1"+      [ testProperty "Idempotence" $+        idempotent (* (0 :: Int))++      , testProperty "Idempotence" $+        (/=0) &> not . idempotent (* (2 :: Int))++      , testProperty "Idempotence" $+        idempotent (abs :: Double -> Double)++      , testProperty "Idempotence" $+        idempotent (signum :: Int -> Int)++      , testProperty "Idempotence" $+        ((*) :: Int -> Int -> Int) `distributesOver` (+)++      , testProperty "Idempotence" $+        (*) `distributesOver` ((+) :: Int -> Int -> Int)+      ]+    ]++