[commit: packages/deepseq] master, typeable-with-kinds: Add simple test-suite for Generics deriving (733f4af)
git at git.haskell.org
git at git.haskell.org
Thu Mar 19 11:35:49 UTC 2015
Repository : ssh://git@git.haskell.org/deepseq
On branches: master,typeable-with-kinds
Link : http://git.haskell.org/packages/deepseq.git/commitdiff/733f4af3d34d28e004e58c38451575b655efb8b8
>---------------------------------------------------------------
commit 733f4af3d34d28e004e58c38451575b655efb8b8
Author: Herbert Valerio Riedel <hvr at gnu.org>
Date: Sat Dec 6 11:39:21 2014 +0100
Add simple test-suite for Generics deriving
This does not use ChasingBottoms as we're interested in testing each
field is evaluated exactly once which ChasingBottoms doesn't provide
afaics.
>---------------------------------------------------------------
733f4af3d34d28e004e58c38451575b655efb8b8
deepseq.cabal | 29 +++++++++++
tests/Main.hs | 152 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 181 insertions(+)
diff --git a/deepseq.cabal b/deepseq.cabal
index 261b01d..2e4aff6 100644
--- a/deepseq.cabal
+++ b/deepseq.cabal
@@ -56,3 +56,32 @@ library
ghc-options: -Wall
exposed-modules: Control.DeepSeq
+
+
+test-suite deepseq-generics-tests
+ default-language: Haskell2010
+ if !impl(ghc>=7.2)
+ buildable: False
+ type: exitcode-stdio-1.0
+ hs-source-dirs: . tests
+ main-is: Main.hs
+ other-extensions:
+ CPP
+ BangPatterns
+ DefaultSignatures
+ DeriveDataTypeable
+ DeriveGeneric
+ FlexibleContexts
+ Safe
+ TupleSections
+ TypeOperators
+
+ ghc-options: -Wall
+
+ build-depends:
+ array,
+ base,
+ -- end of packages with inherited version constraints
+ test-framework == 0.8.*,
+ test-framework-hunit == 0.3.*,
+ HUnit == 1.2.*
diff --git a/tests/Main.hs b/tests/Main.hs
new file mode 100644
index 0000000..5199a17
--- /dev/null
+++ b/tests/Main.hs
@@ -0,0 +1,152 @@
+-- Code reused from http://hackage.haskell.org/package/deepseq-generics
+
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE DeriveDataTypeable #-}
+{-# LANGUAGE DeriveGeneric #-}
+{-# LANGUAGE TupleSections #-}
+
+module Main (main) where
+
+import Control.Concurrent.MVar
+import Control.Exception
+import Control.Monad
+import Data.Bits
+import Data.IORef
+import Data.Typeable
+import Data.Word
+import GHC.Generics
+import System.IO.Unsafe (unsafePerformIO)
+
+-- import Test.Framework (defaultMain, testGroup, testCase)
+import Test.Framework
+import Test.Framework.Providers.HUnit
+import Test.HUnit
+
+-- IUT
+import Control.DeepSeq
+
+-- needed for GHC-7.4 compatibility
+#if !MIN_VERSION_base(4,6,0)
+atomicModifyIORef' :: IORef a -> (a -> (a,b)) -> IO b
+atomicModifyIORef' ref f = do
+ b <- atomicModifyIORef ref
+ (\x -> let (a, b) = f x
+ in (a, a `seq` b))
+ b `seq` return b
+#endif
+
+----------------------------------------------------------------------------
+-- simple hacky abstraction for testing forced evaluation via `rnf`-like functions
+
+seqStateLock :: MVar ()
+seqStateLock = unsafePerformIO $ newMVar ()
+{-# NOINLINE seqStateLock #-}
+
+withSeqState :: Word64 -> IO () -> IO ()
+withSeqState expectedState act = withMVar seqStateLock $ \() -> do
+ 0 <- resetSeqState
+ () <- act
+ st <- resetSeqState
+ unless (st == expectedState) $
+ assertFailure ("withSeqState: actual seq-state ("++show st++") doesn't match expected value ("++
+ show expectedState++")")
+
+seqState :: IORef Word64
+seqState = unsafePerformIO $ newIORef 0
+{-# NOINLINE seqState #-}
+
+resetSeqState :: IO Word64
+resetSeqState = atomicModifyIORef' seqState (0,)
+
+-- |Set flag and raise exception is flag already set
+setSeqState :: Int -> IO ()
+setSeqState i | 0 <= i && i < 64 = atomicModifyIORef' seqState go
+ | otherwise = error "seqSeqState: flag index must be in [0..63]"
+ where
+ go x | testBit x i = error ("setSeqState: flag #"++show i++" already set")
+ | otherwise = (setBit x i, ())
+
+-- weird type whose NFData instacne calls 'setSeqState' when rnf-ed
+data SeqSet = SeqSet !Int | SeqIgnore
+ deriving Show
+
+instance NFData SeqSet where
+ rnf (SeqSet i) = unsafePerformIO $ setSeqState i
+ rnf (SeqIgnore) = ()
+ {-# NOINLINE rnf #-}
+
+-- |Exception to be thrown for testing 'seq'/'rnf'
+data RnfEx = RnfEx deriving (Eq, Show, Typeable)
+
+instance Exception RnfEx
+
+instance NFData RnfEx where rnf e = throw e
+
+assertRnfEx :: () -> IO ()
+assertRnfEx v = handleJust isWanted (const $ return ()) $ do
+ () <- evaluate v
+ assertFailure "failed to trigger expected RnfEx exception"
+ where isWanted = guard . (== RnfEx)
+
+----------------------------------------------------------------------------
+
+case_1, case_2, case_3, case_4_1, case_4_2, case_4_3, case_4_4 :: Test.Framework.Test
+
+newtype Case1 = Case1 Int
+ deriving (Generic)
+
+instance NFData Case1
+
+case_1 = testCase "Case1" $ do
+ assertRnfEx $ rnf $ (Case1 (throw RnfEx))
+
+----
+
+data Case2 = Case2 Int
+ deriving (Generic)
+
+instance NFData Case2
+
+case_2 = testCase "Case2" $ do
+ assertRnfEx $ rnf $ (Case2 (throw RnfEx))
+
+----
+
+data Case3 = Case3 RnfEx
+ deriving (Generic)
+
+instance NFData Case3
+
+case_3 = testCase "Case3" $ do
+ assertRnfEx $ rnf $ Case3 RnfEx
+
+----
+
+data Case4 a = Case4a
+ | Case4b a a
+ | Case4c a (Case4 a)
+ deriving (Generic)
+
+instance NFData a => NFData (Case4 a)
+
+case_4_1 = testCase "Case4.1" $ withSeqState 0x0 $ do
+ evaluate $ rnf $ (Case4a :: Case4 SeqSet)
+
+case_4_2 = testCase "Case4.2" $ withSeqState 0x3 $ do
+ evaluate $ rnf $ (Case4b (SeqSet 0) (SeqSet 1) :: Case4 SeqSet)
+
+case_4_3 = testCase "Case4.3" $ withSeqState (bit 55) $ do
+ evaluate $ rnf $ (Case4b SeqIgnore (SeqSet 55) :: Case4 SeqSet)
+
+case_4_4 = testCase "Case4.4" $ withSeqState 0xffffffffffffffff $ do
+ evaluate $ rnf $ (genCase 63)
+ where
+ genCase n | n > 1 = Case4c (SeqSet n) (genCase (n-1))
+ | otherwise = Case4b (SeqSet 0) (SeqSet 1)
+
+----------------------------------------------------------------------------
+
+main :: IO ()
+main = defaultMain [tests]
+ where
+ tests = testGroup "" [case_1, case_2, case_3, case_4_1, case_4_2, case_4_3, case_4_4]
More information about the ghc-commits
mailing list