packages feed

CurryDB-0.1.1.0: tests/hspec.hs

{-# LANGUAGE OverloadedStrings #-}

import           Control.Applicative
import           Control.Concurrent.Chan.Lifted
import           Control.Concurrent.Lifted
import           Control.Monad
import           Control.Monad.Trans
import           Data.Conduit
import qualified Data.Conduit.List              as CL
import           Data.List                      (sort)

import           Test.Hspec
-- import Test.QuickCheck
-- import Test.HUnit

import           Database.Curry

import           Prelude                        hiding (lookup)

main :: IO ()
main = hspec $ do
  describe "core apis" $ do
    it "insert correctly" $ do
      runDBMT def $ do
        v1 <- transaction $ lookup "foo"
        liftIO $ v1 `shouldBe` Nothing
        transaction $ insert "foo" (123 :: Int)
        v2 <- transaction $ lookup "foo"
        liftIO $ v2 `shouldBe` Just 123
        v3 <- transaction $ lookup "bar"
        liftIO $ v3 `shouldBe` Nothing
      return () :: IO ()

    it "insertWith correctly" $ do
      runDBMT def $ do
        transaction $ insert     "foo" (123 :: Int)
        transaction $ insertWith (+) "foo" 456
        v1 <- transaction $ lookup "foo"
        liftIO $ v1 `shouldBe` Just (123 + 456)
      return () :: IO ()

    it "delete correctly" $ do
      runDBMT def $ do
        transaction $ insert     "foo" (123 :: Int)
        v1 <- transaction $ lookup "foo"
        liftIO $ v1 `shouldBe` Just 123
        transaction $ delete     "foo"
        v2 <- transaction $ lookup "foo"
        liftIO $ v2 `shouldBe` Nothing
      return () :: IO ()

    it "lookupDefault correctly" $ do
      runDBMT def $ do
        v1 <- transaction $ lookupDefault "foo"
        liftIO $ v1 `shouldBe` 0
        transaction $ insert     "foo" (123 :: Int)
        v2 <- transaction $ lookupDefault "foo"
        liftIO $ v2 `shouldBe` 123
      return () :: IO ()

    it "keys correctly" $ do
      runDBMT def $ do
        transaction $ insert "foo" (123 :: Int)
        transaction $ insert "bar" (456 :: Int)
        transaction $ insert "baz" (789 :: Int)
        ks <- transaction $ keys
        ls <- ks $$ CL.consume
        liftIO $ sort ls `shouldBe` sort ["foo", "bar", "baz"]
      return () :: IO ()

    it "keys correctly even after updates" $ do
      runDBMT def $ do
        transaction $ insert "foo" (123 :: Int)
        transaction $ insert "bar" (456 :: Int)
        transaction $ insert "baz" (789 :: Int)
        ks <- transaction $ keys
        transaction $ insert "hoge" (123 :: Int)
        transaction $ insert "moge" (456 :: Int)
        ls <- ks $$ CL.consume
        liftIO $ sort ls `shouldBe` sort ["foo", "bar", "baz"]
      return () :: IO ()

    it "transaction correctly" $ do
      runDBMT def $ do
        transaction $ insert "foo" (123 :: Int)
        transaction $ insert "bar" (456 :: Int)
        transaction $ do
          insertWith (+) "foo" 456
          insertWith subtract "bar" 123
        v1 <- transaction $ lookup "foo"
        liftIO $ v1 `shouldBe` Just (123 + 456)
        v2 <- transaction $ lookup "bar"
        liftIO $ v2 `shouldBe` Just (456 - 123)
      return () :: IO ()

    it "transaction rollbacks correctly" $ do
      runDBMT def $ do
        transaction $ insert "foo" (123 :: Int)
        transaction $ insert "bar" (456 :: Int)
        transaction $ do
          insertWith (+) "foo" 456
          insertWith subtract "bar" 123
          insert "baz" 789
          lift mzero
          <|> return ()
        v1 <- transaction $ lookup "foo"
        liftIO $ v1 `shouldBe` Just 123
        v2 <- transaction $ lookup "bar"
        liftIO $ v2 `shouldBe` Just 456
        v3 <- transaction $ lookup "baz"
        liftIO $ v3 `shouldBe` Nothing
      return () :: IO ()

  describe "concurrent support" $ do
    it "does not race" $ do
      runDBMT def $ do
        chan <- newChan
        replicateM_ 10 $ fork $ do
          replicateM_ 10000 $ do
            transaction $ insertWith (+) "foo" (1 :: Int)
          writeChan chan ()
        replicateM_ 10 $ readChan chan
        cnt <- transaction $ lookupDefault "foo"
        liftIO $ cnt `shouldBe` 100000
      return () :: IO ()