atelier-core-0.1.0.0: test/Unit/Atelier/Effects/LogSpec.hs
module Unit.Atelier.Effects.LogSpec (spec_Log) where
import Effectful (runPureEff)
import Effectful.Writer.Static.Shared (Writer, execWriter)
import Test.Hspec (Spec, describe, it, shouldBe)
import Atelier.Effects.Log (Log, Message (..), info, runLogWriter, withNamespace)
runLogTest :: Eff [Log, Writer [Message]] a -> [Message]
runLogTest =
runPureEff
. execWriter @[Message]
. runLogWriter
spec_Log :: Spec
spec_Log = do
describe "Log with namespace" $ do
it "logs without namespace when not provided" $ do
let logs =
fmap (\m -> (m.namespace, m.text))
. runLogTest
$ info "test message"
logs `shouldBe` [("", "test message")]
it "prepends a namespace to the logged message" $ do
let logs =
fmap (\m -> (m.namespace, m.text))
. runLogTest
. withNamespace "component"
$ info "test message"
logs `shouldBe` [("component", "test message")]
describe "nested namespaces" $ do
it "appends a namespace to the current namespace" $ do
let logs =
fmap (\m -> (m.namespace, m.text))
. runLogTest
. withNamespace "parent"
. withNamespace "child"
$ info "test message"
logs `shouldBe` [("parent.child", "test message")]
it "handles multiple levels of nesting" $ do
let logs =
fmap (\m -> (m.namespace, m.text))
. runLogTest
. withNamespace "level1"
. withNamespace "level2"
. withNamespace "level3"
$ info "test message"
logs `shouldBe` [("level1.level2.level3", "test message")]
describe "namespace scoping" $ do
it "only applies namespace within its scope" $ do
let logs =
fmap (\m -> (m.namespace, m.text))
. runPureEff
. execWriter @[Message]
. runLogWriter
$ do
info "before"
withNamespace "scoped" $ info "inside"
info "after"
logs
`shouldBe` [ ("", "before")
, ("scoped", "inside")
, ("", "after")
]
it "handles partially nested scopes" $ do
let logs =
fmap (\m -> (m.namespace, m.text))
. runPureEff
. execWriter @[Message]
. runLogWriter
. withNamespace "outer"
$ do
info "outer msg"
withNamespace "inner" $ info "inner msg"
info "outer again"
logs
`shouldBe` [ ("outer", "outer msg")
, ("outer.inner", "inner msg")
, ("outer", "outer again")
]