2021-11-17 22:50:39 +03:00
|
|
|
-- | Helper functions for easily testing features.
|
2022-01-21 10:48:27 +03:00
|
|
|
module Harness.Test.Feature
|
2021-11-17 22:50:39 +03:00
|
|
|
( feature,
|
|
|
|
Feature (..),
|
|
|
|
Backend (..),
|
2022-02-09 18:26:14 +03:00
|
|
|
BackendOptions (..),
|
|
|
|
defaultBackendOptions,
|
2021-11-17 22:50:39 +03:00
|
|
|
)
|
|
|
|
where
|
|
|
|
|
2021-11-23 21:15:17 +03:00
|
|
|
import Control.Exception
|
2021-11-17 22:50:39 +03:00
|
|
|
import Data.Foldable
|
2021-11-23 21:15:17 +03:00
|
|
|
import Harness.State (State)
|
2021-11-17 22:50:39 +03:00
|
|
|
import Test.Hspec
|
|
|
|
import Prelude
|
|
|
|
|
|
|
|
-- | Use this record to put together a test against a set of backends.
|
|
|
|
data Feature = Feature
|
|
|
|
{ backends :: [Backend],
|
2022-02-09 18:26:14 +03:00
|
|
|
tests :: BackendOptions -> SpecWith State
|
2021-11-17 22:50:39 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
-- | A backend specification.
|
|
|
|
data Backend = Backend
|
|
|
|
{ -- | Can be any name you want (e.g. "PostgreSQL" or "MySQL v1.2")
|
|
|
|
-- or whatnot.
|
|
|
|
name :: String,
|
|
|
|
-- | To setup the test suite: Run SQL commands, run metadata track
|
|
|
|
-- tables calls.
|
2021-11-23 21:15:17 +03:00
|
|
|
setup :: State -> IO (),
|
2021-11-17 22:50:39 +03:00
|
|
|
-- | Clean up any resources you created in 'setup'.
|
2022-02-09 18:26:14 +03:00
|
|
|
teardown :: State -> IO (),
|
|
|
|
-- | Backend-specific details which should be taken into account in tests
|
|
|
|
backendOptions :: BackendOptions
|
2021-11-17 22:50:39 +03:00
|
|
|
}
|
|
|
|
|
2022-02-09 18:26:14 +03:00
|
|
|
data BackendOptions = BackendOptions
|
|
|
|
{ -- | Defines whether numeric values for the particular backend output as strings
|
|
|
|
stringifyNumbers :: Bool
|
|
|
|
}
|
|
|
|
|
|
|
|
defaultBackendOptions :: BackendOptions
|
|
|
|
defaultBackendOptions = BackendOptions {stringifyNumbers = False}
|
|
|
|
|
2021-11-17 22:50:39 +03:00
|
|
|
-- | Test the feature, running the setup before any tests are run, and
|
|
|
|
-- and ensuring teardown happens after all tests are run.
|
2021-11-23 21:15:17 +03:00
|
|
|
feature :: Feature -> SpecWith State
|
2021-11-17 22:50:39 +03:00
|
|
|
feature Feature {backends, tests} =
|
|
|
|
for_
|
|
|
|
backends
|
2022-02-09 18:26:14 +03:00
|
|
|
( \Backend {name, setup, teardown, backendOptions} ->
|
2021-11-17 22:50:39 +03:00
|
|
|
describe
|
|
|
|
name
|
2021-11-23 21:15:17 +03:00
|
|
|
( aroundAllWith
|
2021-12-30 14:00:52 +03:00
|
|
|
( \actionWith state -> do
|
2022-01-26 15:17:17 +03:00
|
|
|
finallyRethrow
|
2021-12-30 14:00:52 +03:00
|
|
|
( do
|
|
|
|
setup state
|
|
|
|
actionWith state
|
|
|
|
)
|
|
|
|
(teardown state)
|
2021-11-23 21:15:17 +03:00
|
|
|
)
|
2022-02-09 18:26:14 +03:00
|
|
|
(tests backendOptions)
|
2021-11-23 21:15:17 +03:00
|
|
|
)
|
2021-11-17 22:50:39 +03:00
|
|
|
)
|
2022-01-26 15:17:17 +03:00
|
|
|
|
|
|
|
-- | A custom 'finally' which re-throws exceptions from both the main action and the sequel action.
|
|
|
|
--
|
|
|
|
-- The standard 'finally' only re-throws the @sequel@ exception.
|
|
|
|
finallyRethrow :: IO a -> IO b -> IO a
|
|
|
|
finallyRethrow a sequel =
|
|
|
|
mask $ \restore -> do
|
|
|
|
r <-
|
|
|
|
catch
|
|
|
|
(restore a)
|
|
|
|
( \restoreEx -> do
|
|
|
|
_ <- sequel `catch` (throwIO . Exceptions restoreEx)
|
|
|
|
(throwIO restoreEx)
|
|
|
|
)
|
|
|
|
_ <- sequel
|
|
|
|
pure r
|
|
|
|
|
|
|
|
-- | Two exceptions
|
|
|
|
data Exceptions
|
|
|
|
= Exceptions SomeException SomeException
|
|
|
|
|
|
|
|
instance Show Exceptions where
|
|
|
|
show (Exceptions e1 e2) =
|
|
|
|
unlines
|
|
|
|
[ "1. " <> show e1,
|
|
|
|
"",
|
|
|
|
"2. " <> show e2
|
|
|
|
]
|
|
|
|
|
|
|
|
instance Exception Exceptions
|