module Main where import Test.HUnit hiding (path) import TestUtil import Database.TokyoCabinet.FDB import Data.Maybe (catMaybes, fromJust) import Data.List (sort) import Control.Monad dbname :: String dbname = "foo.tcf" withOpenedFDB :: String -> (FDB -> IO a) -> IO () withOpenedFDB name action = do h <- new open h name [OREADER, OWRITER, OCREAT] res <- action h close h return () test_ecode = withoutFile dbname $ \fn -> do h <- new open h fn [OREADER] ecode h >>= (ENOFILE @=?) test_new_delete = do fdb <- new delete fdb test_open_close = withoutFile dbname $ \fn -> do fdb <- new not `fmap` open fdb fn [OREADER] @? "file does not exist" open fdb fn [OREADER, OWRITER, OCREAT] @? "open" close fdb @? "close" not `fmap` close fdb @? "cannot close closed file" test_putxx = withoutFile dbname $ \fn -> withOpenedFDB fn $ \fdb -> do put fdb "1" "bar" get fdb "1" >>= (Just "bar" @=?) putkeep fdb "1" "baz" get fdb "1" >>= (Just "bar" @=?) putcat fdb "1" "baz" get fdb "1" >>= (Just "barbaz" @=?) test_out = withoutFile dbname $ \fn -> withOpenedFDB fn $ \fdb -> do put fdb "1" "bar" get fdb "1" >>= (Just "bar" @=?) out fdb "1" @? "out succeeded" get fdb "1" >>= ((Nothing :: Maybe String) @=?) test_put_get = withoutFile dbname $ \fn -> withOpenedFDB fn $ \fdb -> do put fdb "2" "foo" put fdb "3" "bar" put fdb "4" "baz" put fdb IDNEXT "hoge" put fdb IDPREV "fuga" get fdb "2" >>= (Just "foo" @=?) get fdb "3" >>= (Just "bar" @=?) get fdb "4" >>= (Just "baz" @=?) get fdb (5 :: Int) >>= (Just "hoge" @=?) get fdb (1 :: Int) >>= (Just "fuga" @=?) put fdb IDMAX "max" put fdb IDMIN "min" get fdb (5 :: Int) >>= (Just "max" @=?) get fdb (1 :: Int) >>= (Just "min" @=?) test_iterate = withoutFile dbname $ \fn -> withOpenedFDB fn $ \fdb -> do let keys = [1, 2, 3] :: [Int] vals = ["foo", "bar", "baz"] zipWithM_ (put fdb) keys vals iterinit fdb keys' <- sequence $ replicate (length keys) (iternext fdb) (sort $ catMaybes keys') @?= (sort keys) iternext fdb >>= ((Nothing :: Maybe String) @=?) test_vsiz = withoutFile dbname $ \fn -> withOpenedFDB fn $ \fdb -> do put fdb "123" "bar" vsiz fdb "123" >>= (Just 3 @=?) vsiz fdb "234" >>= ((Nothing :: Maybe Int) @=?) test_range = withoutFile dbname $ \fn -> withOpenedFDB fn $ \fdb -> do zipWithM_ (put fdb) ([1..10] :: [Int]) ([100, 200..1000] :: [Int]) range fdb (2 :: Int) (5 :: Int) (-1) >>= (([2..5] :: [Int]) @=?) range fdb IDMIN IDMAX (-1) >>= (([1..10] :: [Int]) @=?) range fdb IDMIN IDMAX 2 >>= (([1..2] :: [Int]) @=?) test_fwmkeys = withoutFile dbname $ \fn -> withOpenedFDB fn $ \fdb -> do zipWithM_ (put fdb) ([1..10] :: [Int]) ([100, 200..1000] :: [Int]) fwmkeys fdb "[min,max]" 10 >>= ((map show [1..10]) @=?) test_addint = withoutFile dbname $ \fn -> withOpenedFDB fn $ \fdb -> do let ini = 32 :: Int put fdb "10" ini get fdb "10" >>= (Just ini @=?) addint fdb "10" 3 get fdb "10" >>= (Just (ini+3) @=?) addint fdb "20" 1 >>= (Just 1 @=?) put fdb "20" "foo" addint fdb "20" 1 >>= (Nothing @=?) test_adddouble = withoutFile dbname $ \fn -> withOpenedFDB fn $ \fdb -> do let ini = 0.003 :: Double put fdb "1" ini get fdb "1" >>= (Just ini @=?) adddouble fdb "1" 0.3 (get fdb "1" >>= (isIn (ini+0.3))) @? "isIn" adddouble fdb "2" 0.5 >>= (Just 0.5 @=?) put fdb "2" "foo" adddouble fdb "2" 1.2 >>= (Nothing @=?) where margin = 1e-30 isIn :: Double -> (Maybe Double) -> IO Bool isIn expected (Just actual) = let diff = expected - actual in return $ abs diff <= margin test_vanish = withoutFile dbname $ \fn -> withOpenedFDB fn $ \fdb -> do put fdb "1" "111" put fdb "2" "222" put fdb "3" "333" rnum fdb >>= (3 @=?) vanish fdb rnum fdb >>= (0 @=?) test_copy = withoutFile dbname $ \fns -> withoutFile "bar.tcf" $ \fnd -> withOpenedFDB fns $ \fdb -> do put fdb "1" "bar" copy fdb fnd close fdb open fdb fnd [OREADER] get fdb "1" >>= (Just "bar" @=?) test_path = withoutFile dbname $ \fn -> withOpenedFDB fn $ \fdb -> path fdb >>= (Just dbname @=?) test_util = withoutFile dbname $ \fn -> do fdb <- new tune fdb 0 100000000 @? "tune" open fdb fn [OREADER, OWRITER, OCREAT] path fdb >>= (Just fn @=?) rnum fdb >>= (0 @=?) ((> 0) `fmap` fsiz fdb) @? "fsiz" sync fdb @? "sync" put fdb (1 :: Int) "dummy record" optimize fdb 0 0 @? "optimize" close fdb tests = test [ "new delete" ~: test_new_delete , "ecode" ~: test_ecode , "open close" ~: test_open_close , "put get" ~: test_put_get , "out" ~: test_out , "putxx" ~: test_putxx , "copy" ~: test_copy , "range" ~: test_range , "fwmkeys" ~: test_fwmkeys , "path" ~: test_path , "addint" ~: test_addint , "adddouble" ~: test_adddouble , "util" ~: test_util , "vsiz" ~: test_vsiz , "vanish" ~: test_vanish , "iterate" ~: test_iterate ] main = runTestTT tests