Takusen-0.7: Database/Stub/Test/Enumerator.lhs
|
Module : Database.Stub.Test.Enumerator
Copyright : (c) 2004 Oleg Kiselyov, Alistair Bayley
License : BSD-style
Maintainer : oleg@pobox.com, alistair@abayley.org
Stability : experimental
Portability : non-portable
Simple test harness for Stub.
Stub can't share the tests for \"real\" backends because it
returns a somewhat contrived result set.
> {-# OPTIONS -fglasgow-exts #-}
> {-# OPTIONS -fallow-overlapping-instances #-}
> module Database.Stub.Test.Enumerator (runTest) where
> import Database.Enumerator
> import Database.Stub.Enumerator
> -- import Database.Test.Performance as Perf
> import System.Time -- CalendarTime
> import Test.MiniUnit
> import Data.Int
> import Control.Monad.Trans (liftIO)
> runTest :: a -> [String] -> IO ()
> runTest _ _ =
> withSession (connect (ConnParm "" "" ""))
> (runTestTT "Stub tests" (map runOneTest testList) >> return ())
> runOneTest t = catchDB (t ()) reportRethrow
> testList :: [() -> DBM mark Session ()]
> testList =
> [ selectString, selectIterIO, selectFloatInt
> , selectStringNullInt, selectDatetime
> , selectCursor, selectExhaustCursor
> ]
> selectTest iter expect = catchDB ( do
> actual <- doQuery (sql "") iter []
> liftIO $ assertEqual "" expect actual
> ) (\e -> return () )
> selectTest' iter expect = catchDB ( do
> actual <- doQuery (prefetch 10 "") iter []
> liftIO $ assertEqual "" expect actual
> ) (\e -> return () )
> selectString () = selectTest iter expect
> where
> -- To illustrate that the full signature is not necessary as long
> -- as some type information (e.g., (c1::String)) is provided --
> -- or enough context for the compiler to figure that out.
> -- iter :: (Monad m) => String -> IterAct m [String]
> -- iter :: String -> IterAct (DBM mark Session) [String]
> iter (c1::String) acc = result $ c1:acc
> expect = [ "boo", "boo", "boo" ]
The following test illustrates doing IO in the iteratee itself.
> -- monomorphism restriction strikes...
> selectIterIO () = selectTest iter ([]::[String])
> where
> -- Here, it's better to avoid the signature and specify
> -- types of the arguments specifically so we do not have to
> -- figure out which exactly Monad we're operating in.
> -- We let the compiler figure out the right monad from
> -- the context (that is, from the Session)
> --iter :: String -> IterAct (ReaderT Query SessionQuery) ()
> iter (c1::String) seed = do
> ct <- liftIO $ getClockTime
> liftIO $ putStr "<look: IO>"
> result seed
> selectFloatInt () = selectTest' iter expect
> where
> iter :: (Monad m) => Double -> Int -> IterAct m [(Double, Int)]
> iter c1 c2 acc = result $ (c1, c2):acc
> expect = [ (1.1, 1), (1.1, 1), (1.1, 1) ]
> selectStringNullInt () = selectTest' iter expect
> where
> iter :: (Monad m) =>
> String -> Maybe Int -> IterAct m [(String, Int)]
> iter c1 c2 acc = result $ (c1, ifNull c2 (-(1))):acc
> expect = [ ("boo", 1), ("boo", -1), ("boo", 1) ]
> defDate = makeCalTime 19710701120101
> selectDatetime () = selectTest iter expect
> where
> iter :: (Monad m) => CalendarTime -> IterAct m [CalendarTime]
> iter c1 acc = result $ c1:acc
> expect = [ defDate, defDate, defDate ]
> selectCursor () = do
> let
> iter :: (Monad m) => Maybe Int -> IterAct m [Int]
> iter i acc = result $ (ifNull i 2):acc
> withCursor (sql "") iter [] $ \c -> do
> r <- cursorCurrent c
> liftIO $ assertEqual "selectCursor" [1] r
> doneBool <- cursorIsEOF c
> liftIO $ assertEqual "selectCursor" False doneBool
> --
> cursorNext c
> r <- cursorCurrent c
> liftIO $ assertEqual "selectCursor" [2, 1] r
> doneBool <- cursorIsEOF c
> liftIO $ assertEqual "selectCursor" False doneBool
> --
> cursorNext c
> r <- cursorCurrent c
> liftIO $ assertEqual "selectCursor" [1, 2, 1] r
> doneBool <- cursorIsEOF c
> liftIO $ assertEqual "selectCursor" False doneBool
> --
> cursorNext c
> r <- cursorCurrent c
> liftIO $ assertEqual "selectCursor" [1, 2, 1] r
> doneBool <- cursorIsEOF c
> liftIO $ assertEqual "selectCursor" True doneBool
> --
> return ()
> selectExhaustCursor () = catchDB (do
> let
> -- Again, here we demonstrate the use of a local argument
> -- type annotation rather than the complete signature.
> -- Let the compiler figure out the monad and the seed type.
> --iter :: (Maybe m) => Maybe Int -> IterAct m [Int]
> iter (i::Maybe Int) acc = result $ (ifNull i (-(1))):acc
> withCursor (sql "") iter [] $ \c -> do
> cursorNext c
> cursorNext c
> cursorNext c
> cursorNext c
> liftIO $ assertFailure "selectExhaustCursor"
> return ()
> ) (\e -> return () )
> makeCalTime :: Int64 -> CalendarTime
> makeCalTime i =
> let
> year = (i `quot` 10000000000)
> month = ((abs i) `rem` 10000000000) `quot` 100000000
> day = ((abs i) `rem` 100000000) `quot` 1000000
> hour = ((abs i) `rem` 1000000) `quot` 10000
> minute = ((abs i) `rem` 10000) `quot` 100
> second = ((abs i) `rem` 100)
> in CalendarTime
> { ctYear = fromIntegral year
> , ctMonth = toEnum (fromIntegral month - 1)
> , ctDay = fromIntegral day
> , ctHour = fromIntegral hour
> , ctMin = fromIntegral minute
> , ctSec = fromIntegral second
> , ctPicosec = 0
> , ctWDay = Sunday
> , ctYDay = -1
> , ctTZName = "UTC"
> , ctTZ = 0
> , ctIsDST = False
> }