{-# LANGUAGE CPP, OverloadedStrings #-}
import Control.Applicative ((<|>))
import Control.Exception (bracket)
import Data.Text (Text)
import Database.MySQL.Simple
import Database.MySQL.Simple.Param
import System.Environment (getEnvironment)
import Test.Hspec
import Blaze.ByteString.Builder (toByteString)
import Common ()
import DateTimeSpec (dateTimeUnit, dateTimeSpec)
import CustomTypeSpec (customTypeUnit, customTypeSpec)
isCI :: IO Bool
isCI = do
env <- getEnvironment
return $ case lookup "TRAVIS" env <|> lookup "CI" env of
Just "true" -> True
_ -> False
-- This is how to connect to our test database
testConn :: Bool -> ConnectInfo
testConn ci = defaultConnectInfo {
connectHost = "127.0.0.1"
, connectUser = "test"
, connectPassword = "test"
, connectDatabase = "test"
, connectPort = if ci then 33306 else 3306
}
-- Allow tests to do things which would be prevented in strict SQL mode
withConnection :: (Connection -> IO()) -> IO()
withConnection action = do
ci <- isCI
bracket (do conn <- connect $ testConn ci
_ <- execute_ conn "set session sql_mode=''"
return conn
)
close
action
main :: IO ()
main =
withConnection $ \conn ->
hspec $ do
describe "Database.MySQL.Simple.unitSpec" unitSpec
describe "Database.MySQL.Simple.integrationSpec" $ integrationSpec conn
describe "Database.MySQL.Simple.DateTimeSpec" $ do
dateTimeUnit
dateTimeSpec conn
describe "Database.MySQL.Simple.CustomTypeSpec" $ do
customTypeUnit
customTypeSpec conn
unitSpec :: Spec
unitSpec = do
describe "Param a => Param (In [a]) instance" $ do
it "renders an empty list correctly" $ do
let empty :: [Text]
empty = mempty
case render (In empty) of
Plain a -> toByteString a `shouldBe` "(null)"
_ -> expectationFailure "expected a Plain"
it "renders a non-empty list correctly" $ do
let l :: [Text]
l = ["foo", "bar"]
case render (In l) of
Many [Plain _, Escape "foo", Plain _, Escape "bar", Plain _] -> pure ()
_ -> expectationFailure "expected a Many with specific contents"
describe "splitQuery" $ do
it "works for a single question mark" $ do
splitQuery "select * from foo where name = ?"
`shouldBe`
["select * from foo where name = ", ""]
it "works with a question mark in a string literal" $ do
splitQuery "select 'hello?'"
`shouldBe`
["select 'hello?'"]
it "works with many question marks" $ do
splitQuery "select ? + ? + what from foo where bar = ?"
`shouldBe`
["select ", " + ", " + what from foo where bar = ", ""]
integrationSpec :: Connection -> Spec
integrationSpec conn = do
describe "query_" $ do
it "can connect to a database" $ do
result <- query_ conn "select 1 + 1"
result `shouldBe` [Only (2::Int)]
it "can have question marks in string literals" $ do
result <- query_ conn "select 'hello?'"
result `shouldBe` [Only ("hello?" :: Text)]
describe "query" $ do
it "can have question marks in string literals" $ do
result <- query conn "select 'hello?'" ()
result `shouldBe` [Only ("hello?" :: Text)]
describe "with too many query params" $ do
it "should have the right message" $ do
(query conn "select 'hello?'" (Only ['a']) :: IO [Only Text])
`shouldThrow`
(\e -> fmtMessage e == "0 '?' characters, but 1 parameters")
describe "with too few query params" $ do
it "should have the right message" $ do
(query conn "select 'hello?' = ?" () :: IO [Only Text])
`shouldThrow`
(\e -> fmtMessage e == "1 '?' characters, but 0 parameters")
describe "formatQuery" $ do
it "should not blow up on a question mark in string literal" $ do
formatQuery conn "select 'hello?'" ()
`shouldReturn`
"select 'hello?'"