-- | -- Module: Test.Hspec.NeedEnv -- Description: Read environment variables for hspec tests -- Maintainer: Toshio Ito -- -- : -- -- > module Synopsis (main,spec) where -- > -- > import Control.Applicative ((<$>), (<*>)) -- > import Test.Hspec (Spec, SpecWith, hspec, before, describe, it, shouldBe) -- > import Test.Hspec.NeedEnv (EnvMode(Need), needEnv, needEnvRead) -- > -- > main :: IO () -- > main = hspec spec -- > -- > -- | Read environment variables for parameters necessary for testing. -- > getEnvs :: IO (String, Int) -- > getEnvs = (,) -- > <$> needEnv mode "TEST_USER_NAME" -- > <*> needEnvRead mode "TEST_SEED" -- > where -- > mode = Need -- > -- > spec :: Spec -- > spec = before getEnvs $ specWithUserAndSeed -- > -- ^ Use 'before' and similar functions to write 'SpecWith' -- > -- that takes parameters. -- > -- > -- | Test spec that depends on the environment variables. -- > specWithUserAndSeed :: SpecWith (String, Int) -- > specWithUserAndSeed = describe "funcUnderTest" $ do -- > it "should do something" $ \(user_name, seed) -> do -- > funcUnderTest user_name seed `shouldBe` "SOMETHING" -- > -- > funcUnderTest :: String -> Int -> String -- > funcUnderTest = undefined -- -- This module exports 'needEnv' and other similar functions that read -- environment variables in hspec tests. They are useful to write -- tests that depend on some external entities, e.g. Web servers, -- database servers and random number generators. module Test.Hspec.NeedEnv ( -- * Basics EnvMode(..), needEnv, needEnvParse, needEnvRead, -- * Utilities needEnvHostPort ) where import Control.Applicative ((<$>), (<*>)) import Data.Monoid ((<>)) import System.Environment (lookupEnv) import Test.Hspec.Core.Spec (pendingWith) import Test.Hspec.Expectations (expectationFailure) import Text.Read (readEither) -- | How to treat missing environment variable. data EnvMode = Need -- ^ If the environment variable is not set, the test -- fails. | Want -- ^ If the environment variable is not set, the test -- gets pending. deriving (Show,Eq,Ord,Enum,Bounded) -- | Get value of the specified environment variable. If the -- environment variable is not set, it executes the action specified -- by the 'EnvMode'. needEnv :: EnvMode -> String -- ^ name of the environment variable -> IO String -- ^ value of the environment variable needEnv mode envkey = do mval <- lookupEnv envkey case mval of Nothing -> do signalMsg ("Environment variable " <> envkey <> " is not set.") return "" Just str -> return str where signalMsg = case mode of Need -> expectationFailure Want -> pendingWith -- | Get environment variable by 'needEnv', and parse the value. If it -- fails to parse, the test fails. needEnvParse :: EnvMode -> (String -> Either String a) -- ^ the parser of the environment variable -> String -> IO a needEnvParse mode parseEnvVal envkey = do val_str <- needEnv mode envkey case parseEnvVal val_str of Right val -> return val Left e -> do let error_msg = "Fail to parse environment variable " <> envkey <> ": " <> e expectationFailure error_msg error error_msg -- | Parse the environment variable with 'Read' class. needEnvRead :: (Read a) => EnvMode -> String -> IO a needEnvRead mode = needEnvParse mode readEither -- | Get the pair of hostname and port number from environment -- variables. -- -- It reads environment variables @(prefix ++ \"_HOST\")@ and -- @(prefix ++ \"_PORT\")@. needEnvHostPort :: EnvMode -> String -- ^ prefix of environment variables -> IO (String,Int) needEnvHostPort mode prefix = (,) <$> needStr "_HOST" <*> needInt "_PORT" where needStr suffix = needEnv mode (prefix ++ suffix) needInt suffix = needEnvRead mode (prefix ++ suffix)