packages feed

tokyocabinet-haskell-0.0.6: tests/FDBTest.hs

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