packages feed

redis-0.12: Test/HashCommands.hs

{-
Copyright (c) 2010-2011, Alexander Bogdanov <andorn@gmail.com>
License: MIT
-}

{-# LANGUAGE PackageImports #-}
module Test.HashCommands where

import Data.List
import Data.Map (Map(..), (!))
import qualified Data.Map as M
import qualified Data.Set as S
import Test.Setup hiding (sort)

tests = TList [TLabel "hgetall" test_hgetall,
               TLabel "hkeys" test_hkeys,
               TLabel "hvals" test_hvals,
               TLabel "hlen" test_hlen,
               TLabel "hexists, hset, hget and hdel" test_hexists_hset_hget_hdel,
               TLabel "hmset and hmget" test_hmset_hmget,
               TLabel "hincrBy" test_hincrBy,
               TLabel "variadic hdel" test_variadic_hdel,
               TLabel "hincrByFloat" test_hincrByFloat]

asHash :: Reply String -> IO (Map String String)
asHash r = fromRMultiBulk r >>= return . M.fromList . build . map fromJust . fromJust
    where build (a:b:z) = (a, b) : build z
          build (a:[]) = error "unpaired element"
          build [] = []

test_hgetall = TCase $ testRedis $
    let expected = M.fromList $ zip ["foo", "bar", "baz"] ["1", "2", "3"]
    in do r <- ask
          addHash
          liftIO $ do h <- hgetall r "hash" >>= asHash
                      assertEqual "" expected h
                      h <- hgetall r "no-such-key" >>= fromRMultiBulk :: IO (Maybe [Maybe String])
                      assertEqual "" (Just []) h

test_hkeys = TCase $ testRedis $
    do r <- ask
       addHash
       liftIO $ do h <- hgetall r "hash" >>= asHash
                   let expected = M.keys h
                   k <- hkeys r "hash" >>= fromRMultiBulk >>= return . sort . map fromJust . fromJust
                   assertEqual "" expected k
                   k <- hkeys r "no-such-key" >>= fromRMultiBulk :: IO (Maybe [Maybe String])
                   assertEqual "" (Just []) k

test_hvals = TCase $ testRedis $
    do r <- ask
       addHash
       liftIO $ do h <- hgetall r "hash" >>= asHash
                   let expected = S.fromList $ M.elems h -- Data.Set for order-independent equality
                   vals <- hvals r "hash" >>= fromRMultiBulk >>= return . S.fromList . map fromJust . fromJust
                   assertEqual "" expected vals
                   k <- hkeys r "no-such-key" >>= fromRMultiBulk :: IO (Maybe [Maybe String])
                   assertEqual "" (Just []) k

test_hlen = TCase $ testRedis $
    do r <- ask
       addHash
       liftIO $ do h <- hgetall r "hash" >>= asHash
                   l <- hlen r "hash" >>= fromRInt
                   assertEqual "" (M.size h) l
                   l <- hlen r "no-such-key" >>= fromRInt
                   assertEqual "" 0 l

test_hexists_hset_hget_hdel = TCase $ testRedis $
    do r <- ask
       addHash
       liftIO $ do hexists r "hash" "foo" >>= fromRInt >>= assertEqual "" 1
                   hexists r "hash" "jaz" >>= fromRInt >>= assertEqual "" 0
                   hdel r "hash" "foo" >>= fromRInt >>= assertEqual "" 1
                   hdel r "hash" "jaz" >>= fromRInt >>= assertEqual "" 0
                   hexists r "hash" "foo" >>= fromRInt >>= assertEqual "" 0
                   hset r "hash" "foo" "1" >>= fromRInt >>= assertEqual "" 1
                   hexists r "hash" "foo" >>= fromRInt >>= assertEqual "" 1
                   hset r "hash" "foo" "bar" >>= fromRInt >>= assertEqual "" 0
                   hget r "hash" "foo" >>= fromRBulk >>= assertEqual "" (Just "bar")
                   hget r "hash" "jaz" >>= fromRBulk >>= assertEqual "" (Nothing :: Maybe String)

test_hmset_hmget = TCase $ testRedis $
    do r <- ask
       addHash
       liftIO $ do h <- hgetall r "hash" >>= asHash
                   h' <- hmget r "hash" ["foo", "bar"] >>= fromRMultiBulk >>= return . map fromJust . fromJust
                   let h'' = M.fromList $ zip ["foo", "bar"] h'
                   assertEqual "" h (M.union h'' h)
                   hmset r "hash" [("foo", "foo"), ("bar", "bar")] >>= noError
                   let expected = M.update (const $ Just "foo") "foo" $ M.update (const $ Just "bar") "bar" h
                   h' <- hgetall r "hash" >>= asHash
                   assertEqual "" expected h'

test_hincrBy = TCase $ testRedis $
    do r <- ask
       addHash
       liftIO $ do h <- hgetall r "hash" >>= asHash >>= return . M.map read :: IO (Map String Int)
                   res <- hincrBy r "hash" "foo" 2 >>= fromRInt
                   assertEqual "" (h ! "foo" + 2) res
                   hget r "hash" "foo" >>= fromRBulk >>= assertEqual "" (Just res)
                   res <- hincrBy r "hash" "foo" (-2) >>= fromRInt
                   assertEqual "" (h ! "foo") res
                   hget r "hash" "foo" >>= fromRBulk >>= assertEqual "" (Just res)

test_variadic_hdel = TCase $ testRedis $
    do r <- ask
       addHash
       liftIO $ do res <- hdel_ r "hash" ["foo", "bar", "nope"] >>= fromRInt
                   assertEqual "2 fields deleted" 2 res
                   res <- hkeys r "hash" >>= fromRMultiBulk >>= return . fromJust
                   assertEqual "Only baz field remains" [Just "baz"] res
                   res <- hdel_ r "hash" ([] :: [String])
                   assertRError "Empty field list leads to error" res

test_hincrByFloat = TCase $ testRedis $
    do r <- ask
       addHash
       liftIO $ do h <- hgetall r "hash" >>= asHash >>= return . M.map read :: IO (Map String Double)
                   res <- hincrByFloat r "hash" "foo" 0.2 >>= fromRBulk >>= return . fromJust
                   assertEqual "" (h ! "foo" + 0.2) res
                   hget r "hash" "foo" >>= fromRBulk >>= assertEqual "" (Just res)
                   res <- hincrByFloat r "hash" "foo" (-0.2) >>= fromRBulk >>= return . fromJust
                   assertEqual "" (h ! "foo") res
                   hget r "hash" "foo" >>= fromRBulk >>= assertEqual "" (Just res)