sqlcipher-1.0.0.0: tests/Main.hs
module Main where
import Control.Exception.Base (bracket)
import Data.Maybe
import System.FilePath ((</>))
import System.IO.Temp (withTempDirectory)
import Test.Hspec
import Text.Printf (printf)
import Database.SQLCipher
newTable :: TableName -> Table SQLType
newTable tName =
VirtualTable
{ tabName = tName
, tabColumns =
[ Column { colName = "id"
, colType = SQLInt NORMAL False False
, colClauses = [PrimaryKey True]
}
, Column { colName = "name"
, colType = SQLVarChar 200
, colClauses = [IsNullable False]
}
, Column { colName = "age"
, colType = SQLVarChar 200
, colClauses = [IsNullable True]
}
]
, tabConstraints = []
, tabUsing = "FTS3"
}
withDB :: FilePath -> (SQLiteHandle -> IO a) -> IO a
withDB dbName = bracket (openConnection dbName) closeConnection
withTempDB :: (SQLiteHandle -> IO a) -> IO a
withTempDB f =
withTempDirectory "tmp" "test." $ \dirname ->
let dbName = dirname </> "database.sqlite3" in
withDB dbName f
withTempTable :: (String -> SQLiteHandle -> IO a) -> IO a
withTempTable f = withTempDB $ \h ->
let tab = "names" in
defineTable h (newTable "names") >> f tab h
flatExecStatement :: SQLiteResult a => SQLiteHandle -> String -> IO (Either String [Row a])
flatExecStatement h sqlStmt =
let flattenResults = concat
mapResult f (Right r) = Right (f r)
mapResult f (Left l) = Left l
in mapResult flattenResults <$> execStatement h sqlStmt
insertManyRows :: SQLiteHandle -> String -> [Row String] -> IO (Maybe String)
insertManyRows h tab rows = chain insertions
where insertions = map (insertRow h tab) rows
chain [] = return Nothing
chain (i:is) = do
r <- i
case r of
Nothing -> chain is
Just err -> return $ Just err
spec :: Spec
spec = parallel $ do
describe "execStatement and execStatement_" $ do
it "runs select statements" $ withTempDB $ \h -> do
result <- flatExecStatement h "SELECT 'Hello, World' AS h"
result `shouldBe` Right [[("h", "Hello, World")]]
it "fails on bad SQL" $ withTempDB $ \h -> do
error <- execStatement_ h "SELECT aieauie"
error `shouldSatisfy` isJust
describe "insertRow" $ do
it "stores data" $ withTempTable $ \tab h -> do
let row = [("id", "1"), ("name", "John Doe"), ("age", "45")]
error <- insertRow h tab row
error `shouldSatisfy` isNothing
ls <- flatExecStatement h $ printf "SELECT * FROM %s" tab
ls `shouldBe` Right [row]
it "can be called many times" $ withTempTable $ \tab h -> do
let rows = [ [ ("id", "1"), ("name", "Erika Munstermann"), ("age", "28") ]
, [ ("id", "2"), ("name", "Max Munstermann"), ("age", "24") ]
]
error <- insertManyRows h tab rows
error `shouldSatisfy` isNothing
ls <- flatExecStatement h $ printf "SELECT * FROM %s ORDER BY id" tab
ls `shouldBe` Right rows
it "fails on bad row insertion" $ withTempTable $ \tab h -> do
error <- insertRow h tab [("foo", "bar")]
error `shouldSatisfy` isJust
describe "createFunction" $ do
it "runs haskell code" $ withTempDB $ \h -> do
createFunction h "hi" (sum :: [Int] -> Int)
ls <- flatExecStatement h "SELECT hi(1, 2, 3, 4, 5) AS greeting"
ls `shouldBe` Right [[("greeting", show $ sum [1, 2, 3, 4, 5])]]
main :: IO ()
main = hspec spec