Blammo-2.1.0.0: tests/Blammo/Logging/TerminalSpec.hs
{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}
module Blammo.Logging.TerminalSpec
( spec
) where
import Prelude
import Blammo.Logging
import Blammo.Logging.Logger (LoggedMessage (..))
import Blammo.Logging.Terminal
import Data.Aeson (encode, object)
import Data.Aeson.Types (Object, Pair, Value (..))
import Data.ByteString (ByteString)
import qualified Data.ByteString as BS
import qualified Data.ByteString.Char8 as BS8
import qualified Data.ByteString.Lazy as BSL
import Data.Text (Text)
import Data.Time
import Test.Hspec
spec :: Spec
spec = do
describe "reformatTerminal" $ do
it "passes-through none-LoggedMessages as-is" $ do
let
bs :: ByteString
bs = "I'm not even JSON"
bsJSON :: ByteString
bsJSON = "{\"I'm\":\"Valid JSON, but not LoggedMessage\"}"
reformatTerminal 0 False LevelInfo bs `shouldBe` bs
reformatTerminal 0 False LevelInfo bsJSON `shouldBe` bsJSON
it "reformats LoggedMessages with complex attributes" $ do
let
bs =
BSL.toStrict $
encode
LoggedMessage
{ loggedMessageTimestamp =
UTCTime
{ utctDay = fromGregorian 2022 1 1
, utctDayTime = 0
}
, loggedMessageLevel = LevelInfo
, loggedMessageLoc = Nothing
, loggedMessageLogSource = Just "app"
, loggedMessageThreadContext = keyMap ["x" .= object ["y" .= True]]
, loggedMessageText = "I'm a log message"
, loggedMessageMeta = keyMap ["a" .= [1 :: Int, 2, 3]]
}
expected =
mconcat
[ "2022-01-01 00:00:00 [info ] I'm a log message "
, " source=app x={y: True} a=[1, 2, 3]"
]
reformatTerminal 120 False LevelInfo bs `shouldBe` expected
it "moves attributes to multi-line at the given breakpoint" $ do
let
bs =
BSL.toStrict $
encode
LoggedMessage
{ loggedMessageTimestamp =
UTCTime
{ utctDay = fromGregorian 2022 1 1
, utctDayTime = 0
}
, loggedMessageLevel = LevelInfo
, loggedMessageLoc = Nothing
, loggedMessageLogSource = Just "app"
, loggedMessageThreadContext = mempty
, loggedMessageText = "I'm a log message"
, loggedMessageMeta =
keyMap
[ "a" .= ("aaaaaaaaa" :: Text)
, "b" .= ("aaaaaaaaa" :: Text)
, "c" .= ("aaaaaaaaa" :: Text)
, "d" .= ("aaaaaaaaa" :: Text)
]
}
single =
mconcat
[ "2022-01-01 00:00:00 [info ] I'm a log message "
, " source=app a=aaaaaaaaa b=aaaaaaaaa c=aaaaaaaaa d=aaaaaaaaa"
]
multi =
mconcat
[ "2022-01-01 00:00:00 [info ] I'm a log message \n"
, " source=app\n"
, " a=aaaaaaaaa\n"
, " b=aaaaaaaaa\n"
, " c=aaaaaaaaa\n"
, " d=aaaaaaaaa"
]
breakpoint = BS.length single
reformatTerminal breakpoint False LevelInfo bs `shouldBe` single
reformatTerminal (breakpoint - 1) False LevelInfo bs `shouldBe` multi
it "aligns multi-line correctly even with color escapes" $ do
let
bs =
BSL.toStrict $
encode
LoggedMessage
{ loggedMessageTimestamp =
UTCTime
{ utctDay = fromGregorian 2022 1 1
, utctDayTime = 0
}
, loggedMessageLevel = LevelInfo
, loggedMessageLoc = Nothing
, loggedMessageLogSource = Just "app"
, loggedMessageThreadContext = mempty
, loggedMessageText = "I'm a log message"
, loggedMessageMeta =
keyMap
[ "a" .= ("aaaaaaaaa" :: Text)
, "b" .= ("aaaaaaaaa" :: Text)
, "c" .= ("aaaaaaaaa" :: Text)
, "d" .= ("aaaaaaaaa" :: Text)
]
}
expected =
mconcat
[ "2022-01-01 00:00:00 [info ] I'm a log message \n"
, " source=app\n"
, " a=aaaaaaaaa\n"
, " b=aaaaaaaaa\n"
, " c=aaaaaaaaa\n"
, " d=aaaaaaaaa"
]
stripColor (reformatTerminal 120 True LevelInfo bs) `shouldBe` expected
keyMap :: [Pair] -> Object
keyMap ps = km where Object km = object ps
-- Removes from any '\ESC' Char to the next 'm' Char
stripColor :: ByteString -> ByteString
stripColor = snd . BS8.foldl' go (False, "")
where
go :: (Bool, ByteString) -> Char -> (Bool, ByteString)
go (dropping, acc) = \case
'\ESC' -> (True, acc)
'm' | dropping -> (False, acc)
_ | dropping -> (True, acc)
c -> (False, BS8.snoc acc c)