log4hs-0.5.0.0: test/LoggingTest/TypesSpec.hs
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TypeApplications #-}
module LoggingTest.TypesSpec ( spec ) where
import Control.Lens hiding (Level (..))
import Control.Monad
import Data.Default (def)
import Data.Generics.Product.Typed
import Data.IORef
import Data.String (fromString)
import Prelude hiding (filter)
import System.IO
import System.Process (createPipe)
import Test.Hspec
import Test.Hspec.QuickCheck
import Test.QuickCheck
import Test.QuickCheck.Monadic
import Logging.Prelude
import Logging.Types
import LoggingTest.Prelude
spec :: Spec
spec = do
levelSpec
filterSpec
handlerSpec
levelSpec :: Spec
levelSpec = describe "Level" $ do
prop "read & show" $ \v ->
let level = Level v in read (show level) == level
prop "overload string" $ \v ->
let level = Level v in fromString (show level) == level
filterSpec :: Spec
filterSpec = describe "Filter" $ do
prop "pass" $ \rcd@LogRecord{..} ->
let filterer = map fromString $
[logger, parent logger, parent $ parent logger, ""]
in filter (filterer :: Filterer) rcd
prop "reject" $ \rcd@LogRecord{..} ->
let filters = map (fromString . (++ "Test")) $
[logger, parent logger, parent $ parent logger, ""]
in all (== False) [filter (f :: Filter) rcd | f <- filters]
handlerSpec :: Spec
handlerSpec = describe "Handler" $ do
(read, write) <- runIO createPipe
fileRef <- runIO $ newIORef undefined
rotateFileRef <- runIO $ newIORef undefined
runIO $ hSetEncoding read utf8 >> hSetEncoding write utf8
let handler = toHandler $ StreamHandler def [] "{message}" write
fileHandler = toHandler $
FileHandler def [] "{message}" "/tmp/log4hs/file.log" utf8 fileRef
rotateHandler = toHandler $
RotatingFileHandler def [] "{message}" "/tmp/log4hs/rotate.log" utf8
1000 5 rotateFileRef
runIO $ open handler >> open fileHandler >> open rotateHandler
prop "filter" $ \(rcd@LogRecord{..}) -> monadicIO $ do
let loggers = [logger, parent logger, parent $ parent logger, ""]
-- level reject
forM_ logger $ \logger -> do
let handler' = handler & typed @Level .~ (succ level)
res <- run $ handle handler' rcd
assert $ not res
-- filterer reject
forM_ loggers $ \logger -> do
let handler' = handler & typed @Filterer .~ [fromString $ logger ++ "Test"]
res <- run $ handle handler' rcd
assert $ not res
-- filterer pass
forM_ loggers $ \logger -> do
let handler' = handler & typed @Filterer .~ [fromString logger]
res <- run $ handle handler' rcd
msg <- run $ hTryGetLine read
assert res
assert (msg == message)
-- empty filterer
res <- run $ handle handler rcd
msg <- run $ hTryGetLine read
assert res
assert (msg == message)
prop "file" $ \(rcd@LogRecord{..}) -> monadicIO $ do
file <- run $ readIORef fileRef
run $ hSetFileSize file 0 >> hSeek file AbsoluteSeek 0
run $ handle fileHandler rcd
run $ hSeek file AbsoluteSeek 0
msg <- run $ hTryGetLine file
assert (msg == message)
prop "rotate" $ \(rcd, Alphabet c) -> monadicIO $ do
file <- run $ readIORef rotateFileRef
run $ hSetFileSize file 0 >> hSeek file AbsoluteSeek 0
let message = replicate 99 c
rcd' = rcd { message = message }
-- not rollover yet
run $ forM [1..9] $ \_ -> handle rotateHandler rcd'
run $ hSeek file AbsoluteSeek 0
msgs <- run $ forM [1..9] $ \_ -> hTryGetLine file
assert $ all (== message) msgs
-- rollover
run $ handle rotateHandler rcd'
closed <- run $ hIsClosed file
assert closed
pos <- run $ readIORef rotateFileRef >>= hTell
assert (pos == 0)
-- rotate.1.log
file1 <- run $ openLogFile "/tmp/log4hs/rotate.1.log" utf8
run $ hSeek file1 AbsoluteSeek 0
msgs1 <- run $ forM [1..10] $ \_ -> hTryGetLine file1
run $ hClose file1
assert $ all (== message) msgs1
-- rollover again
file' <- run $ readIORef rotateFileRef
run $ forM [1..10] $ \_ -> handle rotateHandler rcd'
closed1 <- run $ hIsClosed file'
assert closed1
-- rotate.2.log
file2 <- run $ openLogFile "/tmp/log4hs/rotate.2.log" utf8
run $ hSeek file2 AbsoluteSeek 0
msgs2 <- run $ forM [1..10] $ \_ -> hTryGetLine file2
run $ hClose file2
-- rotate.2.log
assert $ all (== message) msgs2