packages feed

ChasingBottoms 1.2.4 → 1.3.0

raw patch · 25 files changed

+275/−352 lines, 25 filesdep +arraydep +sybdep ~QuickCheckdep ~basedep ~containersnew-component:exe:ChasingBottomsTestSuitePVP ok

version bump matches the API change (PVP)

Dependencies added: array, syb

Dependency ranges changed: QuickCheck, base, containers, mtl, random

API changes (from Hackage documentation)

- Test.ChasingBottoms.Approx: instance Eq DataType
- Test.ChasingBottoms.TimeOut: instance (Eq a) => Eq (Result a)
+ Test.ChasingBottoms.Nat: instance CoArbitrary Nat
+ Test.ChasingBottoms.TimeOut: instance Exception Die
+ Test.ChasingBottoms.TimeOut: instance Show Die
- Test.ChasingBottoms.TimeOut: Exception :: Exception -> Result a
+ Test.ChasingBottoms.TimeOut: Exception :: SomeException -> Result a

Files

− .boring
@@ -1,9 +0,0 @@-(^|/)_darcs($|/)-^docs$-^dist$-^ChasingBottoms\.tar\.gz$-\..*-config$-\.hi$-\.o$-(^|/)#.*#$-\.processed$
ChasingBottoms.cabal view
@@ -1,13 +1,10 @@ name:               ChasingBottoms-version:            1.2.4+version:            1.3.0 license:            OtherLicense license-file:       LICENCE-copyright:          Copyright (c) Nils Anders Danielsson 2004-2008.+copyright:          Copyright (c) Nils Anders Danielsson 2004-2010. author:             Nils Anders Danielsson maintainer:         http://www.cs.nott.ac.uk/~nad/contact.html-stability:          experimental-homepage:           http://www.cs.nott.ac.uk/~nad/software/#Chasing Bottoms-package-url:        http://www.cs.nott.ac.uk/~nad/software/ChasingBottoms/ChasingBottoms.tgz synopsis:           For testing partial and infinite values. description:   Do you ever feel the need to test code involving bottoms (e.g. calls to@@ -59,9 +56,9 @@   computations, such as the following example, and then it can be nice to   be able to apply a time-out:   .-    [@> timeOut' 1 (reverse [1..5\]) >>= print@] @Value [5,4,3,2,1]@+    [@> timeOut' 1 (reverse [1..5\])@] @Value [5,4,3,2,1]@   .-    [@> timeOut' 1 (reverse [1..\]) >>= print@] @NonTermination@+    [@> timeOut' 1 (reverse [1..\])@] @NonTermination@   .   The time-out functionality can be used to treat \"slow\" computations as   bottoms:@@ -84,34 +81,29 @@   .     [@> let primes = unfoldr (\\(x:xs) -> Just (x, filter ((\/= 0) . (\`mod\` x)) xs)) [2..\]@]   .-    [@> timeOutMicro 100 (print $ filter ((== 1) . (\`mod\` 83)) primes) >>= print@] @[167,499NonTermination@+    [@> timeOutMicro 100 (print $ filter ((== 1) . (\`mod\` 83)) primes)@] @[167,499,9NonTermination@   .-    [@> timeOutMicro 100 (print $ take 4 $ filter ((== 1) . (\`mod\` 83)) primes) >>= print@] @[167,499,997NonTermination@+    [@> timeOutMicro 100 (print $ take 6 $ filter ((== 1) . (\`mod\` 83)) primes)@] @[167,499,997,1163,1993NonTermination@   .-    [@> timeOutMicro 100 (print $ take 4 $ filter ((== 1) . (\`mod\` 83)) primes) >>= print@] @[167,499,997,1163]@+    [@> timeOutMicro 100 (print $ take 6 $ filter ((== 1) . (\`mod\` 83)) primes)@] @[167,499,997,1163,1993,2657]@   .     [@ @] @Value ()@   .-  All the type annotations above are required.-  .   For the underlying theory and a larger example involving use of   QuickCheck, see the article \"Chasing Bottoms, A Case Study in Program   Verification in the Presence of Partial and Infinite Values\"   (<http://www.cs.nott.ac.uk/~nad/publications/danielsson-jansson-mpc2004.html>).   .-  The code has been tested under GHC 6.8. Most parts can probably be+  The code has been tested under GHC 6.12. Most parts can probably be   ported to other Haskell compilers, but that would require some work.   The @TimeOut@ functions require preemptive scheduling, and most of the   rest requires @Data.Generics@; @isBottom@ only requires exceptions,   though. category:           Testing-tested-with:        GHC == 6.8.2-cabal-version:      >= 1.2 && < 2+tested-with:        GHC == 6.12.1+cabal-version:      == 1.8.* build-type:         Simple -flag small_base-    description: Choose the new smaller, split-up base package.- library     exposed-modules:         Test.ChasingBottoms,@@ -125,15 +117,39 @@      other-modules: Test.ChasingBottoms.IsType -    build-depends: QuickCheck >= 1.1 && < 2,-                   mtl >= 1.1 && < 2-    if flag(small_base)-        build-depends: base >= 3 && < 4,-                       containers >= 0.1 && < 1,-                       random >= 1 && < 2-    else-        build-depends: base >= 2 && < 3+    build-depends: QuickCheck == 2.1.*,+                   mtl == 1.1.*,+                   base == 4.*,+                   containers == 0.3.*,+                   random == 1.0.*,+                   syb >= 0.1.0.2 && < 0.2 --- It would be nice if the tests that can be accessed through--- Test.ChasingBottoms.Tests.main could be run automatically using--- Cabal (in a simple way). See make test.+flag build-tests+    description: Build the test suite.+    default:     False+    manual:      True++executable ChasingBottomsTestSuite+    if !flag(build-tests)+      buildable:   False++    main-is:       Test/ChasingBottoms/Tests.hs++    other-modules: Test.ChasingBottoms.Approx.Tests,+                   Test.ChasingBottoms.ApproxShow.Tests,+                   Test.ChasingBottoms.ContinuousFunctions.Tests,+                   Test.ChasingBottoms.IsBottom.Tests,+                   Test.ChasingBottoms.IsType.Tests,+                   Test.ChasingBottoms.Nat.Tests,+                   Test.ChasingBottoms.SemanticOrd.Tests,+                   Test.ChasingBottoms.TestUtilities,+                   Test.ChasingBottoms.TestUtilities.Generators,+                   Test.ChasingBottoms.TimeOut.Tests++    build-depends: QuickCheck == 2.1.*,+                   mtl == 1.1.*,+                   base == 4.*,+                   containers == 0.3.*,+                   random == 1.0.*,+                   syb >= 0.1.0.2 && < 0.2,+                   array == 0.3.*
LICENCE view
@@ -1,7 +1,7 @@ I have chosen to distribute this library under the MIT/Expat licence: --------------------------------------------------------------------- -Copyright (c) 2004-2008 Nils Anders Danielsson+Copyright (c) 2004-2010 Nils Anders Danielsson  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the
− Makefile
@@ -1,24 +0,0 @@-# This Makefile is currently only used to run a test suite-# automatically using darcs.--########################################################################-# You may need to edit the following variables:--# Path to GHC 6.8, used to run the tests.-GHC_68 ?= ghc--# GHC packages necessary for building and testing the library.-PACKAGES = base-3.0.1.0 containers-0.1.0.1 random-1.0.0.0 mtl-1.1.0.0	\-QuickCheck-1.1.0.0 array-0.1.0.0--########################################################################--# Runs all tests using GHC 6.8.-compile = $(1) -ignore-dot-ghci -no-recomp -hide-all-packages \-	  $(foreach pkg,$(PACKAGES),-package $(pkg)) --make $(2)-testWithCompiler = $(call compile,$(1),Test.ChasingBottoms) && $(call	\-compile,$(1),Test.ChasingBottoms.Tests -main-is				\-Test.ChasingBottoms.Tests.main -o tests) && ./tests-.PHONY : test-test:-	$(call testWithCompiler,$(GHC_68))
− README
@@ -1,28 +0,0 @@-ChasingBottoms-----------------Building-----------To build: Use Cabal, or use ghc --make Test.ChasingBottoms. (If-Test.ChasingBottoms is already installed you may need to add something-like -ignore-package ChasingBottoms.)--Do not use Cabal to build the documentation. Use make docs instead.-You may need to edit the Makefile first.--To run through the test suite, execute Test.ChasingBottoms.Tests.main.--Possible future work-----------------------* Making it easier to test equality etc. of functions. (This may be-  easier using the new version of Scrap your boilerplate, Scrap your-  boilerplate with class.)--* More custom generators for partial and infinite values.--Known bugs-------------None.
Test/ChasingBottoms.hs view
@@ -1,9 +1,9 @@ -- | -- Module      :  Test.ChasingBottoms--- Copyright   :  (c) Nils Anders Danielsson 2004-2007+-- Copyright   :  (c) Nils Anders Danielsson 2004-2010 -- License     :  See the file LICENCE.--- --- Maintainer  :  http://www.cs.chalmers.se/~nad/+--+-- Maintainer  :  http://www.cs.nott.ac.uk/~nad/ -- Stability   :  experimental -- Portability :  non-portable (GHC-specific) --@@ -26,15 +26,3 @@ import Test.ChasingBottoms.Nat import Test.ChasingBottoms.SemanticOrd import Test.ChasingBottoms.TimeOut--{----- If this module is imported the library refuses to be built whenever--- the tests fail. Doing this adds a dependency on Template Haskell,--- though, and the compilation takes considerably longer, plus some--- (intended) warnings are emitted. Furthermore, if some test should--- fail, then the emitted error message is rather unreadable.--import Test.ChasingBottoms.TestLibraryWhenCompiling---}
Test/ChasingBottoms/Approx.hs view
@@ -1,11 +1,12 @@-{-# OPTIONS -fglasgow-exts -fallow-undecidable-instances #-}+{-# LANGUAGE ScopedTypeVariables,+             FlexibleInstances, UndecidableInstances #-}  -- | -- Module      :  Test.ChasingBottoms.Approx--- Copyright   :  (c) Nils Anders Danielsson 2004-2007+-- Copyright   :  (c) Nils Anders Danielsson 2004-2010 -- License     :  See the file LICENCE.--- --- Maintainer  :  http://www.cs.chalmers.se/~nad/+--+-- Maintainer  :  http://www.cs.nott.ac.uk/~nad/ -- Stability   :  experimental -- Portability :  non-portable (GHC-specific) --@@ -15,6 +16,7 @@   ) where  import Test.ChasingBottoms.Nat+import Data.Function import Data.Generics import qualified Data.List as List @@ -96,11 +98,9 @@   | otherwise = \x ->      let d = dataTypeOf x          n' = pred n-         fun childTerm = if dataTypeOf childTerm == d then+         fun childTerm = if dataTypeOf childTerm === d then                            approxGen' n' childTerm                           else                            childTerm      in gmapT fun x--instance Eq DataType where-  d1 == d2 = dataTypeRep d1 == dataTypeRep d2+    where (===) = (==) `on` dataTypeRep
Test/ChasingBottoms/Approx/Tests.hs view
@@ -1,4 +1,5 @@-{-# OPTIONS -fglasgow-exts #-}+{-# LANGUAGE ScopedTypeVariables, RankNTypes,+             DeriveDataTypeable #-}  -- | Tests of the functions in "Test.ChasingBottoms.Approx". 
Test/ChasingBottoms/ApproxShow.hs view
@@ -1,11 +1,12 @@-{-# OPTIONS -fglasgow-exts -fallow-undecidable-instances #-}+{-# LANGUAGE ScopedTypeVariables,+             FlexibleInstances, UndecidableInstances #-}  -- | -- Module      :  Test.ChasingBottoms.ApproxShow--- Copyright   :  (c) Nils Anders Danielsson 2004-2007+-- Copyright   :  (c) Nils Anders Danielsson 2004-2010 -- License     :  See the file LICENCE.--- --- Maintainer  :  http://www.cs.chalmers.se/~nad/+--+-- Maintainer  :  http://www.cs.nott.ac.uk/~nad/ -- Stability   :  experimental -- Portability :  non-portable (GHC-specific) --@@ -37,7 +38,7 @@   --   * All detectable occurences of bottoms are replaced by @\"_|_\"@.   --   --   * Non-bottom functions are displayed as @\"\<function \/= _|_\>\"@.-  -- +  --   approxShowsPrec :: Nat -> Prec -> a -> ShowS   approxShows     :: Nat -> a -> ShowS   approxShow      :: Nat -> a -> String@@ -109,7 +110,7 @@   | otherwise    = showParen (not (isAtom a) && p > appPrec) $                    showCon a .                    continueL (.^.) nil (succ appPrec) a-                   +     where     continueL f x p = gmapQl f x (gShowsPrec False (pred n) p)     continueR f x p = gmapQr f x (gShowsPrec False (pred n) p)@@ -122,12 +123,7 @@ -- Some infix constructors seem to have parentheses around them in -- their conString representations. Maybe something should be done about -- that. See the Q test case, and compare with ordinary lists.-showCon a      = showString $ showConstr' a-  where-  showConstr' a-    | dataTypeRep (dataTypeOf a) == dataTypeRep (dataTypeOf 'c') = -        "'" ++ showConstr (toConstr a) ++ "'"-    | otherwise = showConstr $ toConstr a+showCon a      = showString $ showConstr $ toConstr a isAtom a       = glength a == 0 isPrimitive a  = not $ isAlgType (dataTypeOf a) isInfix a      = if isPrimitive a then
Test/ChasingBottoms/ApproxShow/Tests.hs view
@@ -1,4 +1,4 @@-{-# OPTIONS -fglasgow-exts #-}+{-# LANGUAGE DeriveDataTypeable #-}  -- | Tests of the functions in "Test.ChasingBottoms.ApproxShow". 
Test/ChasingBottoms/ContinuousFunctions.hs view
@@ -1,4 +1,5 @@-{-# OPTIONS -fglasgow-exts #-}+{-# LANGUAGE RankNTypes, ScopedTypeVariables,+             GeneralizedNewtypeDeriving, DeriveDataTypeable #-}  -- TODO: Can we pattern match on functions? -- What about functions of several arguments? Can we have interleaved@@ -11,22 +12,18 @@  -- | -- Module      :  Test.ChasingBottoms.ContinuousFunctions--- Copyright   :  (c) Nils Anders Danielsson 2005-2007+-- Copyright   :  (c) Nils Anders Danielsson 2005-2010 -- License     :  See the file LICENCE.--- --- Maintainer  :  http://www.cs.chalmers.se/~nad/+--+-- Maintainer  :  http://www.cs.nott.ac.uk/~nad/ -- Stability   :  experimental -- Portability :  non-portable (GHC-specific) ----- Note: /This module is unfinished and experimental. However, I do--- not think that I will ever finish it, so I have released it in its--- current state. The documentation below may not be completely--- correct. The source code lists some things which should be--- addressed./+-- Note: /This module is unfinished and experimental. However, I do not think that I will ever finish it, so I have released it in its current state. The documentation below may not be completely correct. The source code lists some things which should be addressed./ -- -- A framework for generating possibly non-strict, partial, -- continuous functions.--- +-- -- The functions generated using the standard QuickCheck 'Arbitrary' -- instances are all strict. In the presence of partial and infinite -- values testing using only strict functions leads to worse coverage@@ -37,15 +34,15 @@ -- instance, using -- -- > type Cogen a = forall b. a -> Gen b -> Gen b--- > +-- > -- > integer :: Gen Integer -- > integer = frequency [ (1, return bottom), (10, arbitrary) ]--- > +-- > -- > coBool :: CoGen Bool -- > coBool b | isBottom b = variant 0 -- > coBool False          = variant 1 -- > coBool True           = variant 2--- > +-- > -- > function :: Cogen a -> Gen b -> Gen (a -> b) -- > function coGen gen = promote (\a -> coGen a gen) --@@ -57,11 +54,10 @@ -- -- Sometimes using possibly non-monotone functions is good enough, -- since that set of functions is a superset of the continuous--- functions. However, say that we want to test that @x--- 'Test.ChasingBottoms.SemanticOrd.<=!' y@ implies that @f x--- 'Test.ChasingBottoms.SemanticOrd.<=!' f y@ for all functions @f@--- (whenever the latter expression returns a total result). This--- property is not valid in the presence of non-monotone functions.+-- functions. However, say that we want to test that @x 'O.<=!' y@+-- implies that @f x 'O.<=!' f y@ for all functions @f@ (whenever the+-- latter expression returns a total result). This property is not+-- valid in the presence of non-monotone functions. -- -- By avoiding 'isBottom' and, unlike the standard 'coarbitrary' -- functions, deferring some pattern matches, we can generate@@ -78,7 +74,7 @@ --     just one transformation per input, but one transformation per --     constructor in the input. 'PatternMatch'es can be constructed --     generically using 'match'.--- +-- -- (2) Then the result is generated, almost like for a normal --     'Arbitrary' instance. However, for each constructor generated a --     subset of the transformations from step 1 are applied. This@@ -94,7 +90,7 @@ -- >   = Branch (Tree a) (Tree a) -- >   | Leaf a -- >     deriving (Show, Typeable, Data)--- > +-- > -- > finiteTreeOf :: MakeResult a -> MakeResult (Tree a) -- > finiteTreeOf makeResult = sized' tree -- >   where@@ -107,7 +103,7 @@ -- >                  ] -- >     where -- >     tree' = tree (size `div` 2)--- > +-- > -- >     baseCase = -- >       frequency' [ (1, return bottom) -- >                  , (2, liftM Leaf makeResult)@@ -147,7 +143,7 @@   , listOf   ) where -import Test.QuickCheck+import Test.QuickCheck hiding ((><), listOf) import Data.Sequence as Seq import Data.Foldable as Seq (foldr) import Prelude as P hiding (concat)@@ -159,6 +155,8 @@ import Data.Generics import qualified Data.List as L +import qualified Test.ChasingBottoms.SemanticOrd as O+ ------------------------------------------------------------------------ -- Generation of functions @@ -215,7 +213,7 @@  -- These functions provided inspiration for the generic one below. -matchFlat :: Arbitrary a => MakePM a+matchFlat :: CoArbitrary a => MakePM a matchFlat a = PatternMatch { apply = coarbitrary a, more = empty }  data Tree a@@ -240,15 +238,12 @@             , more  = more x             }   where-  -- seq added since toConstr is not strict enough for-  -- one-constructor data types. (Bug reported; should be fixed in the-  -- CVS repository.)   toVariant :: forall a b. Data a => a -> Gen b -> Gen b-  toVariant x = x `seq` case constrRep (toConstr x) of-    AlgConstr n    -> variant (n - 1)  -- n >= 1.-    IntConstr i    -> coarbitrary i-    FloatConstr d  -> coarbitrary d-    StringConstr s -> nonBottomError "match: Encountered StringConstr."+  toVariant x = case constrRep (toConstr x) of+    AlgConstr n   -> variant (n - 1)  -- n >= 1.+    IntConstr i   -> coarbitrary i+    FloatConstr d -> coarbitrary d+    CharConstr s  -> nonBottomError "match: Encountered CharConstr."    more :: forall a. Data a => a -> Seq PatternMatch   more = gmapQr (<|) empty match@@ -308,9 +303,9 @@ getMatches :: Seq PatternMatch -> Gen (GenTransformer', Seq PatternMatch) getMatches pms = do   -- Throw away pattern matches with probability 0.1.-  (_, pms') <- partition 9 pms+  (_, pms') <- partition' 9 pms   -- Use pattern matches with probability 0.33.-  (use, keep) <- partition 2 pms'+  (use, keep) <- partition' 2 pms'   let transform = compose $ fmap apply use       further = concat $ fmap more use   if Seq.null further then@@ -336,11 +331,11 @@ -- the relative probability with which elements end up in the second -- part compared to the first one. -partition :: Int -> Seq a -> Gen (Seq a, Seq a)-partition freq ss = case viewl ss of+partition' :: Int -> Seq a -> Gen (Seq a, Seq a)+partition' freq ss = case viewl ss of   EmptyL  -> return (empty, empty)   x :< xs -> do-    (ys, zs) <- partition freq xs+    (ys, zs) <- partition' freq xs     frequency [ (1,    return (x <| ys, zs))               , (freq, return (ys, x <| zs))               ]@@ -447,7 +442,7 @@                map (handle (L.genericLength constrs)) constrs              IntRep         -> [(9, cast' (arbitrary' :: MakeResult Integer))]              FloatRep       -> [(9, cast' (arbitrary' :: MakeResult Double))]-             StringRep      -> nonBottomError "makeResult: StringRep."+             CharRep        -> nonBottomError "makeResult: CharRep."              NoRep          -> nonBottomError "makeResult: NoRep."    handle noConstrs con =
Test/ChasingBottoms/ContinuousFunctions/Tests.hs view
@@ -1,4 +1,4 @@-{-# OPTIONS -fglasgow-exts #-}+{-# LANGUAGE ScopedTypeVariables, DeriveDataTypeable #-}  -- TODO: Tests passed even though for finiteTreeOf and finiteListOf -- transform was only applied once at the top-level!@@ -11,13 +11,14 @@ import Test.ChasingBottoms.ContinuousFunctions import Test.ChasingBottoms.IsBottom import Test.ChasingBottoms.SemanticOrd+import Test.ChasingBottoms.TestUtilities import qualified Test.ChasingBottoms.TestUtilities.Generators as Gen import Test.ChasingBottoms.TestUtilities.Generators (Tree(..)) import Test.ChasingBottoms.ApproxShow import Data.Generics import Test.QuickCheck-import Test.QuickCheck.Batch (run, TestOptions(..), TestResult(..)) import Test.ChasingBottoms.TestUtilities+import Control.Arrow import Control.Monad import Data.List import Data.Ratio@@ -73,36 +74,33 @@ -- How do we test these properties?  testDistribution test t = do-  result <- run t testOptions+  result <- run t   let (ok, msg) = apply test result   unless ok $ putStrLn msg   return ok   where-  apply test (TestOk _ n args) = test n args-  apply _    _                 = (False, "Test failed.")--  testOptions = TestOptions { no_of_tests     = 1000-                            , length_of_tests = 0      -- No time limit.-                            , debug_tests     = False-                            }-+  apply test (Success labels) = test labels+  apply _    _                = (False, "Test failed.") -spread n args = (uniqueShare >= 3%4, "uniqueShare: " ++ show uniqueShare)-  where noUniqueArgs = length . group . sort $ args-        uniqueShare = noUniqueArgs % n+spread labels = (uniqueShare >= 3%4, "uniqueShare: " ++ show uniqueShare)+  where+  noUniqueArgs = length labels+  noArgs       = sum $ map snd labels+  uniqueShare  = noUniqueArgs % noArgs -len max avg short n args =+len max avg short labels =   ( maxLen >= max && averageLen >= avg && shortShare >= 1%10   , "maxLen: " ++ show maxLen ++     ", averageLen: " ++ show averageLen ++     ", shortShare: " ++ show shortShare   )-  where maxLen = maximum lengths-        averageLen = sum lengths % noArgs-        noShortLists = genericLength (filter (<= short) lengths)-        lengths = map read . concat $ args :: [Integer]-        noArgs = toInteger n-        shortShare = noShortLists % noArgs+  where+  lengths      = map (read *** toInteger) labels :: [(Integer, Integer)]+  noArgs       = sum (map snd lengths)+  maxLen       = maximum $ map fst lengths+  averageLen   = sum (map (uncurry (*)) lengths) % noArgs+  noShortLists = sum . map snd . filter ((<= short) . fst) $ lengths+  shortShare   = noShortLists % noArgs  -- | We want to make sure that we can generate many different kinds of -- lazy functions.@@ -116,7 +114,7 @@  -- | The generated lists should not be too short. -prop_lists_have_decent_length = testDistribution (len 20 6 5) $+prop_lists_have_decent_length = testDistribution (len 20 5 5) $   forAll (functionTo (finiteListOf flat)) $ \(f :: Integer -> [Bool]) ->   forAll integer $ \(i :: Integer) ->     collect (length' (f i) :: Integer) $@@ -200,7 +198,7 @@ -- Manual inspection of function tables  viewFun :: (ApproxShow b, Data a) => MakeResult b -> [a] -> IO ()-viewFun (makeResult :: MakeResult b) (inputs :: [a]) = test $+viewFun (makeResult :: MakeResult b) (inputs :: [a]) = quickCheck $   forAll (functionTo makeResult) $ \(f :: a -> b) ->     collect (map (approxShow 5 . f) inputs) $ True 
Test/ChasingBottoms/IsBottom.hs view
@@ -1,9 +1,11 @@+{-# LANGUAGE ScopedTypeVariables #-}+ -- | -- Module      :  Test.ChasingBottoms.IsBottom--- Copyright   :  (c) Nils Anders Danielsson 2004-2007+-- Copyright   :  (c) Nils Anders Danielsson 2004-2010 -- License     :  See the file LICENCE.--- --- Maintainer  :  http://www.cs.chalmers.se/~nad/+--+-- Maintainer  :  http://www.cs.nott.ac.uk/~nad/ -- Stability   :  experimental -- Portability :  non-portable (exceptions) --@@ -16,25 +18,41 @@   ) where  import Prelude hiding (catch)-import Control.Exception (catch, throw, Exception(..), evaluate)+import qualified Control.Exception as E import System.IO.Unsafe (unsafePerformIO) import qualified Test.ChasingBottoms.TimeOut as T  -- | @'isBottom' a@ returns 'False' if @a@ is distinct from bottom. If--- @a@ equals bottom and results in an exception which is caught by--- 'isBottom', and this exception is of a certain kind (see below),--- then @'isBottom' a = 'True'@. Other caught exceptions are--- re-thrown. If @a@ never reaches a weak head normal form and--- never throws an exception, then @'isBottom' a@ never terminates.+-- @a@ equals bottom and results in an exception of a certain kind+-- (see below), then @'isBottom' a = 'True'@. If @a@ never reaches a+-- weak head normal form and never throws one of these exceptions,+-- then @'isBottom' a@ never terminates. ----- The exceptions that yield 'True' are those that correspond to--- \"pure bottoms\", i.e. bottoms that can originate in pure code.--- Assertions are excluded, since their behaviour depends on compiler--- flags (not pure, and a failed assertion should really yield an--- exception and nothing else). The same applies to arithmetic--- exceptions (machine dependent, except possibly for--- 'Control.Exception.DivideByZero', but the value infinity makes that--- case unclear as well).+-- The exceptions that yield 'True' correspond to \"pure bottoms\",+-- i.e. bottoms that can originate in pure code:+--+--   * 'E.ArrayException'+--+--   * 'E.ErrorCall'+--+--   * 'E.NoMethodError'+--+--   * 'E.NonTermination'+--+--   * 'E.PatternMatchFail'+--+--   * 'E.RecConError'+--+--   * 'E.RecSelError'+--+--   * 'E.RecUpdError'+--+-- Assertions are excluded, because their behaviour depends on+-- compiler flags (not pure, and a failed assertion should really+-- yield an exception and nothing else). The same applies to+-- arithmetic exceptions (machine dependent, except possibly for+-- 'E.DivideByZero', but the value infinity makes that case unclear as+-- well).  -- Should we use throw or throwIO below? --   It doesn't seem to matter, and I don't think it matters, but@@ -55,11 +73,12 @@ bottom :: a bottom = error "_|_" --- | @'nonBottomError' s@ raises an exception ('AssertionFailed') that--- is not caught by 'isBottom'. Use @s@ to describe the exception.+-- | @'nonBottomError' s@ raises an exception ('E.AssertionFailed')+-- that is not caught by 'isBottom'. Use @s@ to describe the+-- exception.  nonBottomError :: String -> a-nonBottomError = throw . AssertionFailed+nonBottomError = E.throw . E.AssertionFailed  -- | @'isBottomTimeOut' timeOutLimit@ works like 'isBottom', but if -- @timeOutLimit@ is @'Just' lim@, then computations taking more than@@ -68,28 +87,21 @@ -- that this \"function\" may return different answers upon different -- invocations. Take it for what it is worth. ----- 'isBottomTimeOut' is subject to all the same scheduling vagaries as--- 'Test.ChasingBottoms.TimeOut.timeOut'.+-- 'isBottomTimeOut' is subject to all the same vagaries as+-- 'T.timeOut'.  isBottomTimeOut :: Maybe Int -> a -> Bool isBottomTimeOut timeOutLimit f = unsafePerformIO $-  maybeTimeOut (evaluate f) `catch` \e -> case e of-    ArithException _   -> throw e-    ArrayException _   -> return True-    AssertionFailed _  -> throw e-    AsyncException _   -> throw e-    BlockedOnDeadMVar  -> throw e-    Deadlock           -> throw e-    DynException _     -> throw e-    ErrorCall _        -> return True-    ExitException _    -> throw e-    IOException _      -> throw e-    NoMethodError _    -> return True-    NonTermination     -> return True-    PatternMatchFail _ -> return True-    RecConError _      -> return True-    RecSelError _      -> return True-    RecUpdError _      -> return True+  maybeTimeOut (E.evaluate f) `E.catches`+    [ E.Handler (\(_ :: E.ArrayException)   -> return True)+    , E.Handler (\(_ :: E.ErrorCall)        -> return True)+    , E.Handler (\(_ :: E.NoMethodError)    -> return True)+    , E.Handler (\(_ :: E.NonTermination)   -> return True)+    , E.Handler (\(_ :: E.PatternMatchFail) -> return True)+    , E.Handler (\(_ :: E.RecConError)      -> return True)+    , E.Handler (\(_ :: E.RecSelError)      -> return True)+    , E.Handler (\(_ :: E.RecUpdError)      -> return True)+    ]   where   maybeTimeOut io = case timeOutLimit of     Nothing -> do@@ -100,4 +112,4 @@       case result of               -- Note that evaluate bottom /= bottom.         T.Value _        -> return False         T.NonTermination -> return True-        T.Exception e    -> throw e  -- Catch the exception above.+        T.Exception e    -> E.throw e  -- Catch the exception above.
+ Test/ChasingBottoms/IsBottom.hs-boot view
@@ -0,0 +1,3 @@+module Test.ChasingBottoms.IsBottom where++bottom :: a
Test/ChasingBottoms/IsBottom/Tests.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE ScopedTypeVariables #-}+ -- | Tests of the functions in "Test.ChasingBottoms.IsBottom". -- -- Note that the warnings given when compiling this module are@@ -12,7 +14,8 @@ import qualified Control.Exception as E  isException f = unsafePerformIO $-  (E.evaluate f >> return False) `E.catch` const (return True)+  (E.evaluate f >> return False)+    `E.catch` (\(_ :: E.SomeException) -> return True)  bot = bot notbot x = notbot x
Test/ChasingBottoms/IsType.hs view
@@ -1,9 +1,9 @@ -- | -- Module      :  Test.ChasingBottoms.IsType--- Copyright   :  (c) Nils Anders Danielsson 2004-2007+-- Copyright   :  (c) Nils Anders Danielsson 2004-2010 -- License     :  See the file LICENCE.--- --- Maintainer  :  http://www.cs.chalmers.se/~nad/+--+-- Maintainer  :  http://www.cs.nott.ac.uk/~nad/ -- Stability   :  experimental -- Portability :  non-portable (GHC-specific) --@@ -16,6 +16,7 @@   , isString   ) where +import Data.List import Data.Typeable  -- | '@isFunction@ f' returns 'True' iff the top level \"constructor\"@@ -31,8 +32,7 @@ -- for debugging purposes anyway. The unit type is not considered to -- be a tuple. isTuple :: Typeable a => a -> Bool-isTuple x = if null s then False else head s == ','-  where s = tyConString (con x)+isTuple x = "(," `isPrefixOf` tyConString (con x)  isString :: Typeable a => a -> Bool isString x = isList x && typeRepArgs (typeOf x) == typeRepArgs (typeOf "")
Test/ChasingBottoms/Nat.hs view
@@ -1,11 +1,11 @@-{-# OPTIONS -fglasgow-exts #-}+{-# LANGUAGE DeriveDataTypeable #-}  -- | -- Module      :  Test.ChasingBottoms.Nat--- Copyright   :  (c) Nils Anders Danielsson 2004-2007+-- Copyright   :  (c) Nils Anders Danielsson 2004-2010 -- License     :  See the file LICENCE.--- --- Maintainer  :  http://www.cs.chalmers.se/~nad/+--+-- Maintainer  :  http://www.cs.nott.ac.uk/~nad/ -- Stability   :  experimental -- Portability :  non-portable (GHC-specific) --@@ -16,6 +16,7 @@ module Test.ChasingBottoms.Nat(Nat, isSucc, fromSucc, natrec, foldN) where  import Test.QuickCheck+import qualified Data.Generics as G import Data.Ratio ((%)) import Data.Typeable @@ -23,12 +24,11 @@  -- | Natural numbers. ----- No 'Data.Generics.Basics.Data' instance is provided since the--- implementation should be abstract.+-- No 'G.Data' instance is provided, because the implementation should+-- be abstract. --- Could add 'Data.Generics.Basics.Data' instance based on unary--- representation of natural numbers, but that would lead to--- inefficiencies.+-- Could add 'G.Data' instance based on unary representation of+-- natural numbers, but that would lead to inefficiencies. newtype Nat = Nat { nat2int :: Integer } deriving (Eq, Ord, Typeable)  -- | @'isSucc' 0 == 'False'@, for other total natural numbers it is 'True'.@@ -106,4 +106,9 @@   arbitrary = do     n <- arbitrary :: Gen Integer     return $ fromInteger $ abs n++  shrink 0 = []+  shrink n = [n - 1]++instance CoArbitrary Nat where   coarbitrary n = coarbitrary (toInteger n)
Test/ChasingBottoms/Nat/Tests.hs view
@@ -1,4 +1,4 @@-{-# OPTIONS -fglasgow-exts #-}+{-# LANGUAGE ScopedTypeVariables #-}  -- | Tests for "Test.ChasingBottoms.Nat". @@ -10,7 +10,6 @@ import Test.ChasingBottoms.SemanticOrd import Test.ChasingBottoms.TestUtilities import Test.QuickCheck-import Test.QuickCheck.Batch import Data.Maybe import Data.List import Data.Ratio
Test/ChasingBottoms/SemanticOrd.hs view
@@ -1,11 +1,12 @@-{-# OPTIONS -fglasgow-exts -fallow-undecidable-instances #-}+{-# LANGUAGE ScopedTypeVariables, RankNTypes,+             FlexibleInstances, UndecidableInstances #-}  -- | -- Module      :  Test.ChasingBottoms.SemanticOrd--- Copyright   :  (c) Nils Anders Danielsson 2004-2007+-- Copyright   :  (c) Nils Anders Danielsson 2004-2010 -- License     :  See the file LICENCE.--- --- Maintainer  :  http://www.cs.chalmers.se/~nad/+--+-- Maintainer  :  http://www.cs.nott.ac.uk/~nad/ -- Stability   :  experimental -- Portability :  non-portable (GHC-specific) --@@ -188,7 +189,7 @@     bottom    else     gzipWithT (\x y -> semanticMeet' tweak x y) a b-    + semanticJoin' :: (Data a, Data b) => Tweak -> a -> b -> Maybe b semanticJoin' tweak a (b :: b) =   case ( isBottomTimeOut (timeOutLimit tweak) a
Test/ChasingBottoms/SemanticOrd/Tests.hs view
@@ -1,4 +1,4 @@-{-# OPTIONS -fglasgow-exts #-}+{-# LANGUAGE RankNTypes #-}  -- | Tests for "Test.ChasingBottoms.SemanticOrd". The functions using -- tweaks are currently not tested.@@ -9,7 +9,6 @@ import Test.ChasingBottoms.TestUtilities import Test.ChasingBottoms.TestUtilities.Generators hiding (tests) import Test.QuickCheck-import Test.QuickCheck.Batch (run) import Data.Generics import Control.Monad import Data.Maybe
− Test/ChasingBottoms/TestLibraryWhenCompiling.hs
@@ -1,21 +0,0 @@-{-# OPTIONS -fth #-}---- | By importing this module in e.g. "Test.ChasingBottoms" the--- library refuses to be built if the tests fail.--module Test.ChasingBottoms.TestLibraryWhenCompiling () where--import qualified Test.ChasingBottoms.Tests as Tests-import qualified System.IO as IO-import qualified Language.Haskell.TH as TH--$(do -     b <- TH.runIO $ do putStr "----- Testing the library. -----\n\n"-                        b <- Tests.main-                        IO.hFlush IO.stdout-                        return b-     if not b then-       fail "Tests failed. Refusing to build library."-      else-       return []- )
Test/ChasingBottoms/TestUtilities.hs view
@@ -2,7 +2,8 @@  module Test.ChasingBottoms.TestUtilities   ( -- * Batch execution of QuickCheck tests-    runQuickCheckTests+    run+  , runQuickCheckTests     -- * Various algebraic properties   , isAssociative   , isCommutative@@ -24,7 +25,6 @@   ) where  import Test.QuickCheck-import Test.QuickCheck.Batch import Data.List import Control.Arrow import Control.Monad@@ -33,50 +33,38 @@ ------------------------------------------------------------------------ -- Batch execution of QuickCheck tests +-- | Runs a single test, using suitable settings.++run :: Testable p => p -> IO Result+run = quickCheckWithResult (stdArgs { maxSuccess = 1000+                                    , maxDiscard = 5000+                                    })+ -- | Runs a bunch of QuickCheck tests, printing suitable information -- to standard output. Returns 'True' if no tests fail. Note that a -- test where the inputs are exhausted is considered to have -- succeeded. -runQuickCheckTests :: [TestOptions -> IO TestResult]+runQuickCheckTests :: [IO Result]                       -- ^ Create the tests in this list from ordinary                       -- QuickCheck tests by using 'run'.                       -> IO Bool runQuickCheckTests tests = do-  results <- mapM ($ testOptions) tests-  mapM_ (putStr . showTR) results+  results <- sequence tests+  mapM_ (putStrLn . showTR) results   return $ all ok $ results   where-  ok (TestOk {})       = True-  ok (TestExausted {}) = True   -- We treat this as OK since the-                                -- distribution of test data is displayed.-  ok (TestFailed {})   = False-  ok (TestAborted {})  = False--  testOptions = TestOptions { no_of_tests     = 1000-                            , length_of_tests = 0      -- No time limit.-                            , debug_tests     = False-                            }--  showTR (TestOk _ n args) =-    "OK, passed " ++ show n ++ " tests.\n" ++ showArgs args-  showTR (TestExausted _ n args) =-    "Arguments exhausted after " ++ show n ++ " tests.\n" ++ showArgs args-  showTR (TestFailed _ _) = "Test failed.\n"-  showTR (TestAborted _) = "Test resulted in exception.\n"+  ok (Success {})           = True+  ok (GaveUp {})            = False+  ok (Failure {})           = False+  ok (NoExpectedFailure {}) = False -  showArgs :: [[String]] -> String-  showArgs args-    | all null args = ""-    | otherwise     =-        unlines-        . map (indent . uncurry (++)-               . (formatNum *** (concat . intersperse ", ")))-        . sortBy (\x y -> compare (fst y) (fst x))-        . map (length &&& head) . group . sort-        $ args-    where indent = ("  " ++)-          formatNum = flip shows ": "+  showTR (Success {})              = "OK."+  showTR (GaveUp { numTests = n }) =+    "Gave up after " ++ show n ++ " tests."+  showTR (Failure {})              = "Test failed."+  showTR (NoExpectedFailure {})    =+    "Test did not fail, but it should have."  ------------------------------------------------------------------------ -- Testing various algebraic properties@@ -230,19 +218,17 @@ isPartialOrder element equalTo differentFrom greaterThan (==.) (<=.) =   [reflexive, antisymmetric1, antisymmetric2, transitive]   where-  infix 4 ==., <=.-   reflexive =     forAll element $ \x ->       x <=. x    antisymmetric1 =     forAll (pair element equalTo) $ \(x, y) ->-      (x <=. y && y <=. x) && x ==. y+      ((x <=. y) && (y <=. x)) && x ==. y    antisymmetric2 =     forAll (pair element differentFrom) $ \(x, y) ->-      not (x <=. y && y <=. x) && not (x ==. y)+      not ((x <=. y) && (y <=. x)) && not (x ==. y)    transitive = forAll (pair element greaterThan) $ \(x, y) ->                  forAll (greaterThan y) $ \z ->@@ -271,12 +257,10 @@   isPartialOrder element equalTo differentFrom greaterThan (==.) (<=.)   ++ [total]   where-  infix 4 <=.-   total =     forAll element $ \x ->     forAll element $ \y ->-      x <=. y || y <=. x+      (x <=. y) || (y <=. x)  -- | Tests relating various partial order operators. Does not include -- any tests from 'isPartialOrder'.@@ -301,17 +285,15 @@ isPartialOrderOperators element greaterThan (==.) (<=.) (<.) (>=.) (>.) =   [lt_le, gt_ge, ge_le, lt_gt]   where-  infix 4 ==., <=., <., >=., >.-   twoElems = pair3 element greaterThan    lt_le =     forAll twoElems $ \(x, y) ->-      (x <. y) == (x <=. y && not (x ==. y))+      (x <. y) == ((x <=. y) && not (x ==. y))    gt_ge =     forAll twoElems $ \(x, y) ->-      (x >. y) == (x >=. y && not (x ==. y))+      (x >. y) == ((x >=. y) && not (x ==. y))    ge_le =     forAll twoElems $ \(x, y) ->
Test/ChasingBottoms/TestUtilities/Generators.hs view
@@ -1,4 +1,4 @@-{-# OPTIONS -fglasgow-exts #-}+{-# LANGUAGE RankNTypes, DeriveDataTypeable #-}  -- | Generators that are part of the testing framework. @@ -47,7 +47,6 @@ import Test.ChasingBottoms.SemanticOrd import Test.ChasingBottoms.TestUtilities import Test.QuickCheck-import Test.QuickCheck.Batch (run) import Data.Generics import Control.Monad import Data.Maybe@@ -118,7 +117,7 @@                       ]  testGen :: (Show a, Data a) => Nat -> Gen a -> IO ()-testGen depth gen = test $ forAll gen $ \n ->+testGen depth gen = quickCheck $ forAll gen $ \n ->                       collect (approxShow depth n) $ True  ------------------------------------------------------------------------@@ -163,7 +162,7 @@  testFunction :: (Data a, Data b) => Nat -> Cogen a -> Gen b -> [a] -> IO () testFunction depth coGen gen inputs =-  test $ forAll (function coGen gen) $ \f ->+  quickCheck $ forAll (function coGen gen) $ \f ->     collect (map (\x -> approxShow depth (x, f x)) inputs) $ True  ------------------------------------------------------------------------@@ -251,7 +250,7 @@     x /=! y  testGenPair :: (Show a, Data a) => Nat -> Gen a -> (a -> Gen a) -> IO ()-testGenPair depth gen gen' = test $+testGenPair depth gen gen' = quickCheck $   forAll (pair gen gen') $ \(x, y) ->     collect (approxShow depth (x, y)) $ True 
Test/ChasingBottoms/Tests.hs view
@@ -1,8 +1,8 @@-{-# OPTIONS -fglasgow-exts #-}+{-# LANGUAGE FlexibleInstances #-}  -- | Tests of almost everything related to "Test.ChasingBottoms". -module Test.ChasingBottoms.Tests (main) where+module Main (main) where  import qualified Test.ChasingBottoms.Approx.Tests              as Approx import qualified Test.ChasingBottoms.ApproxShow.Tests          as ApproxShow
Test/ChasingBottoms/TimeOut.hs view
@@ -1,11 +1,11 @@-{-# OPTIONS -fglasgow-exts #-}+{-# LANGUAGE ScopedTypeVariables, DeriveDataTypeable #-}  -- | -- Module      :  Test.ChasingBottoms.TimeOut--- Copyright   :  (c) Nils Anders Danielsson 2004-2007+-- Copyright   :  (c) Nils Anders Danielsson 2004-2010 -- License     :  See the file LICENCE.--- --- Maintainer  :  http://www.cs.chalmers.se/~nad/+--+-- Maintainer  :  http://www.cs.nott.ac.uk/~nad/ -- Stability   :  experimental -- Portability :  non-portable (preemptive scheduling) --@@ -29,25 +29,32 @@ import Data.Dynamic import qualified Control.Exception as E +import {-# SOURCE #-} qualified Test.ChasingBottoms.IsBottom as B+ data Result a   = Value a   | NonTermination-  | Exception E.Exception-    deriving (Eq, Show, Typeable)+  | Exception E.SomeException+    deriving (Show, Typeable)  -- | @'timeOut' n c@ runs @c@ for at most @n@ seconds (modulo -- scheduling issues). -----   * If the computation terminates before that, then---     @'Value' v@ is returned, where @v@ is the resulting value. Note---     that this value may be equal to bottom, e.g. if @c = 'return'---     'Test.ChasingBottoms.IsBottom.bottom'@.+--   * If the computation terminates before that, then @'Value' v@ is+--     returned, where @v@ is the resulting value. Note that this+--     value may be equal to bottom, e.g. if @c = 'return'+--     'B.bottom'@. -- --   * If the computation does not terminate, then 'NonTermination' is --     returned. -- --   * If the computation raises an exception, then @'Exception' e@ is --     returned, where @e@ is the exception.+--+-- Note that a user-defined exception is used to terminate the+-- computation, so if @c@ catches all exceptions, or blocks+-- asynchronous exceptions, then 'timeOut' may fail to function+-- properly.  timeOut :: Int -> IO a -> IO (Result a) timeOut = timeOutMicro . (* 10^6)@@ -61,12 +68,12 @@ timeOutMicro delay io = do   mv <- newEmptyMVar   let putException = putMVar mv . Exception-  ioThread <- forkIO $ (io >>= putMVar mv . Value)-                      `E.catch` (\e -> case e of-                        E.DynException d -> case fromDynamic d of-                          Just Die -> return ()  -- Thread properly killed.-                          Nothing -> putException e-                        _ -> putException e)+  ioThread <- forkIO $+    (io >>= putMVar mv . Value)+    `E.catch` (\(e :: E.SomeException) ->+                case E.fromException e of+                  Just Die -> return ()  -- Thread properly killed.+                  Nothing  -> putException e)   reaper <- forkIO $ do     threadDelay delay     putMVar mv NonTermination@@ -76,14 +83,16 @@   return result  -- Since 'ioThread' above should return exceptions raised in the code--- we cannot kill the thread using killThread, which raises--- @'AsyncException' 'ThreadKilled'@. We use the locally defined type--- 'Die' together with a dynamic exception instead.+-- it seems like a bad idea to kill the thread using killThread, which+-- raises @'AsyncException' 'ThreadKilled'@. We use the locally+-- defined type 'Die' instead. -data Die = Die deriving Typeable+data Die = Die deriving (Show, Typeable) -killThread' threadId = E.throwDynTo threadId Die+instance E.Exception Die +killThread' threadId = E.throwTo threadId Die+ -- | 'timeOut'' is a variant which can be used for pure -- computations. The definition, --@@ -91,12 +100,11 @@ --   'timeOut'' n = 'timeOut' n . 'E.evaluate' -- @ ----- ensures that @'timeOut'' 1 'Test.ChasingBottoms.IsBottom.bottom'@--- usually returns @'Exception' \<something\>@. (@'timeOut' 1 ('return'--- 'Test.ChasingBottoms.IsBottom.bottom')@ usually returns @'Value'--- 'Test.ChasingBottoms.IsBottom.bottom'@; in other words, the--- computation reaches whnf almost immediately, defeating the purpose--- of the time-out.)+-- ensures that @'timeOut'' 1 'B.bottom'@ usually returns @'Exception'+-- \<something\>@. (@'timeOut' 1 ('return' 'B.bottom')@ usually+-- returns @'Value' 'B.bottom'@; in other words, the computation+-- reaches whnf almost immediately, defeating the purpose of the+-- time-out.)  timeOut' :: Int -> a -> IO (Result a) timeOut' n = timeOut n . E.evaluate