hspec-need-env-0.1.0.0: test/Test/Hspec/NeedEnvSpec.hs
{-# LANGUAGE CPP #-}
module Test.Hspec.NeedEnvSpec (main, spec) where
import Control.Monad.IO.Class (liftIO)
import Data.List (isInfixOf)
import Data.IORef (IORef, newIORef, modifyIORef, readIORef)
import System.SetEnv (setEnv, unsetEnv)
import Test.Hspec
import Test.Hspec.Core.Runner (hspecWithResult, Summary(..), Config(..), defaultConfig)
import Test.Hspec.Core.Formatters (Formatter)
import qualified Test.Hspec.Core.Formatters as F
import Test.Hspec.Core.Util (Path)
import Test.Hspec.NeedEnv
( EnvMode(..), needEnv, needEnvRead, needEnvHostPort
)
main :: IO ()
main = hspec spec
spec :: Spec
spec = do
describe "needEnv Need" $ do
it "should get the specified env" $ do
setEnv "HOGE" "hoge"
successCase (needEnv Need) "HOGE" "hoge"
it "should fail when the specified env is not present" $ do
unsetEnv "HOGE"
failCase (needEnv Need) "HOGE" (\msg -> "not set" `isInfixOf` msg)
describe "needEnvRead Need" $ do
it "should get and parse the specified env" $ do
setEnv "FOOBAR" "100"
successCase (needEnvRead Need) "FOOBAR" (100 :: Int)
it "should fail when it fails to parse" $ do
let needEnvInt :: String -> IO Int
needEnvInt = needEnvRead Need
setEnv "FOOBAR" "hoge"
failCase needEnvInt "FOOBAR" (\msg -> "parse" `isInfixOf` msg)
describe "needEnv Want" $ do
it "should get the specified env" $ do
setEnv "FOOBAR" "foo_bar"
successCase (needEnv Want) "FOOBAR" "foo_bar"
it "should make the test pending when the specified env is not present" $ do
unsetEnv "FOOBAR"
pendingCase (needEnv Want) "FOOBAR" (\msg -> "not set" `isInfixOf` msg)
describe "needEnvRead Want" $ do
it "should fail (even if it's Want) when it fails to parse the env" $ do
let needEnvInt :: String -> IO Int
needEnvInt = needEnvRead Want
setEnv "FOOBAR" "hoge"
failCase needEnvInt "FOOBAR" (\msg -> "parse" `isInfixOf` msg)
describe "needEnvHostPort Need" $ do
it "should get host and port from environment variables the common name prefix" $ do
(conf, ref_results) <- configForTest
setEnv "PREFIX_HOGE_HOST" "192.168.17.223"
setEnv "PREFIX_HOGE_PORT" "1123"
got_summary <- hspecWithResult conf $ before (needEnvHostPort Need "PREFIX_HOGE") $ do
specify "dummny" $ \(host, port) -> do
host `shouldBe` "192.168.17.223"
port `shouldBe` 1123
got <- readIORef ref_results
map resultBody got `shouldBe` [ExampleSuccess]
got_summary `shouldBe` Summary { summaryExamples = 1, summaryFailures = 0 }
successCase :: (Read a, Show a, Eq a) => (String -> IO a) -> String -> a -> IO ()
successCase envGet envkey envval = do
(conf, ref_results) <- configForTest
got_summary <- hspecWithResult conf (before (envGet envkey) $ sampleSpec envval)
got <- readIORef ref_results
map resultBody got `shouldBe` [ExampleSuccess]
got_summary `shouldBe` Summary { summaryExamples = 1, summaryFailures = 0 }
failOrPendingCase :: (ExampleResultBody -> Maybe String) -> (String -> IO a) -> String -> (String -> Bool) -> Int -> IO ()
failOrPendingCase extractMsg envGet envkey andExpect exp_sum_failures = do
let expect [body] = case extractMsg body of
Nothing -> False
Just msg -> (envkey `isInfixOf` msg) && andExpect msg
expect _ = False
(conf, ref_results) <- configForTest
got_summary <- hspecWithResult conf (before (envGet envkey) sampleSuccess)
got <- fmap (map resultBody) $ readIORef ref_results
got `shouldSatisfy` expect
got_summary `shouldBe` Summary { summaryExamples = 1, summaryFailures = exp_sum_failures }
failCase :: (String -> IO a) -> String -> (String -> Bool) -> IO ()
failCase envGet envkey andExpect = failOrPendingCase extract envGet envkey andExpect 1
where
extract (ExampleFailure mmsg) = mmsg
extract _ = Nothing
pendingCase :: (String -> IO a) -> String -> (String -> Bool) -> IO ()
pendingCase envGet envkey andExpect = failOrPendingCase extract envGet envkey andExpect 0
where
extract (ExamplePending mmsg) = mmsg
extract _ = Nothing
sampleSpec :: (Eq a, Show a) => a -> SpecWith a
sampleSpec expected = specify "dummy" $ \got -> got `shouldBe` expected
sampleSuccess :: SpecWith a
sampleSuccess = specify "dummy" $ const (True `shouldBe` True)
data ExampleResultBody = ExampleSuccess
| ExampleFailure (Maybe String)
| ExamplePending (Maybe String)
deriving (Show,Eq,Ord)
type ExampleResult = (Path, ExampleResultBody)
resultBody :: ExampleResult -> ExampleResultBody
resultBody (_, b) = b
#if MIN_VERSION_hspec_core(2,4,0)
failureReasonToString :: Either e F.FailureReason -> Maybe String
failureReasonToString (Right (F.Reason s)) = Just s
failureReasonToString _ = Nothing
#else
failureReasonToString :: Either e String -> Maybe String
failureReasonToString (Right s) = Just s
failureReasonToString _ = Nothing
#endif
formatterForTest :: IO (Formatter, IORef [ExampleResult])
formatterForTest = do
ref_results <- newIORef []
let putRet r = liftIO $ modifyIORef ref_results (\rs -> rs ++ [r])
#if MIN_VERSION_hspec_core(2,5,0)
f = F.silent { F.exampleSucceeded = \p _ -> putRet (p, ExampleSuccess),
F.exampleFailed = \p _ fr -> putRet (p, ExampleFailure (failureReasonToString $ Right fr)),
F.examplePending = \p _ ms -> putRet (p, ExamplePending ms)
}
#else
f = F.silent { F.exampleSucceeded = \p -> putRet (p, ExampleSuccess),
F.exampleFailed = \p efr -> putRet (p, ExampleFailure (failureReasonToString efr)),
F.examplePending = \p ms -> putRet (p, ExamplePending ms)
}
#endif
return (f, ref_results)
configForTest :: IO (Config, IORef [ExampleResult])
configForTest = do
(fmt, ref_results) <- formatterForTest
let conf = defaultConfig { -- configIgnoreConfigFile = True, -- not in hspec-core-2.3.2
configDryRun = False,
configFormatter = Just fmt
}
return (conf, ref_results)