packages feed

couchdb-enumerator-0.3.5: test/Database/CouchDB/Enumerator/Test/Basic.hs

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}

-- | Basic tests
module Database.CouchDB.Enumerator.Test.Basic where

import           Control.Monad
import           Control.Monad.Trans.Class (lift)
import qualified Control.Exception.Lifted as E
import           Data.Aeson ((.=))
import qualified Data.Aeson as A
import qualified Data.HashMap.Lazy as M
import           Data.List (nubBy)

import Database.CouchDB.Enumerator
import Database.CouchDB.Enumerator.Test.Util

import Test.Framework (testGroup, Test)
import Test.Framework.Providers.HUnit (testCase)
import Test.HUnit (Assertion)
import Test.QuickCheck (sample', arbitrary)

tests :: Test
tests = testGroup "Basic" [
      testGroup "DB" [
          testCouchCase "basic connection"        connectTest
        , testCouchCase "basic error"             missingObjectTest
        , testCouchCase "conflict"                conflictError
        --, testCouchProperty "single insert" (1,7) insertTest
        , testCouchCase "insert"                  insertTestCase
        , testCouchCase "basic delete"            deleteTest
        , testCase "Delete noexistent"            case_deleteNoexistentDb

        -- TODO: right now, the following test screws up other tests by deleting the db.
        -- Perhaps the code should be updated to put the database at the beginning of each test?
        --, testCouchCase "Double put and delete"   case_doublePutAndDel
      ]
    ]

connectTest :: CouchT IO ()
connectTest = do
    v <- couchGet "" []
    lift $ assertObjMember "db_name" (assertStr "testcouchenum") v

missingObjectTest :: CouchT IO ()
missingObjectTest = assertRecvError (Just 404) $ couchGet "jaosihaweoghaweiouhawef" []

conflictError :: CouchT IO ()
conflictError = do
    E.handle catch404 $ do rev <- couchRev "conflicttest"
                           couchDelete "conflicttest" rev
    --E.handle catch404 $ couchRev "somebadobject" >> return ()
    couchPut_ "conflicttest" [] $ A.object [ "foo" .= True ]
    return ()
  where catch404 e@(CouchError c _) = unless (c == Just 404) $ E.throwIO e

insertTestCase :: CouchT IO ()
insertTestCase = replicateM_ 20 $ do
    objs <- lift $ sample' arbitrary
    insertTest objs

insertTest :: [(Int,ArbitraryObject,ArbitraryObject,ArbitraryObject)] -> CouchT IO ()
insertTest objs = do
    let objs' = nubBy (\(a,_,_,_) (b,_,_,_) -> a == b) objs
    let keys  = map (("otest"++) . show . (\(a,_,_,_) -> a)) objs'
    let vals1 = map (\(_,ArbitraryObject a,_,_) -> a) objs'
    let vals2 = map (\(_,_,ArbitraryObject a,_) -> a) objs'
    let vals3 = map (\(_,_,_,ArbitraryObject a) -> a) objs'

    mapM_ clearObject keys

    rev <- forM (zip keys vals1) $ \(k,o) ->
        couchPut k [] o

    forM_ (zip3 rev keys vals1) $ \(r,k,o) -> do
        checkLoad k $ M.insert "_rev" (A.toJSON r) o
        checkRevision k r

    rev2 <- forM (zip3 rev keys vals2) $ \(r,k,o) ->
        couchPut k [] $ M.insert "_rev" (A.toJSON r) o

    forM_ (zip3 rev2 keys vals2) $ \(r,k,o) -> do
        checkLoad k $ M.insert "_rev" (A.toJSON r) o
        checkRevision k r

    rev3 <- forM (zip3 rev2 keys vals3) $ \(r,k,o) ->
        couchPutRev k r [] o

    forM_ (zip3 rev3 keys vals3) $ \(r,k,o) -> do
        checkLoad k $ M.insert "_rev" (A.toJSON r) o
        checkRevision k r

deleteTest :: CouchT IO ()
deleteTest = do
    (ArbitraryObject obj) <- liftM (head . drop 5) $ lift $ sample' arbitrary

    clearObject "deltest"

    rev <- couchPut "deltest" [] obj
    checkLoad "deltest" obj
    couchDelete "deltest" rev
    assertRecvError (Just 404) $ couchGet "deltest" []


case_doublePutAndDel :: CouchT IO ()
case_doublePutAndDel = do
    couchPutDb ""
    couchPutDb ""
    couchDeleteDb ""

-- | A test with an empty db
case_deleteNoexistentDb :: Assertion
case_deleteNoexistentDb = runCouch "localhost" 5984 "" $ 
    checkError (Just 404) $ couchDeleteDb "cdbe_noexistent"