packages feed

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")
                               ]