packages feed

tricorder-0.2.0.0: test/Unit/Tricorder/Daemon/BuildStateSpec.hs

module Unit.Tricorder.Daemon.BuildStateSpec (spec_BuildState) where

import Data.Aeson (eitherDecode, encode)
import Data.Time (UTCTime (..), fromGregorian)
import Test.Hspec

import Tricorder.Build
    ( BuildId (..)
    , BuildResult (..)
    , BuildState (..)
    , Diagnostic (..)
    , PostBuild (..)
    , Severity (..)
    )
import Tricorder.Daemon.DaemonInfo (DaemonInfo (..))

import Tricorder.Build qualified as Build
import Tricorder.Build.EvalComment qualified as Eval


spec_BuildState :: Spec
spec_BuildState = do
    describe "JSON round-trip" do
        it "survives Unicode smart quotes in message text" do
            let msg =
                    Diagnostic
                        { severity = SWarning
                        , file = "<interactive>"
                        , line = 2
                        , col = 8
                        , endLine = 2
                        , endCol = 8
                        , title = "Found \8216qualified\8217 in prepositive position"
                        , text = "Found \8216qualified\8217 in prepositive position\n    Suggested fixes:\n      \8226 Place \8216qualified\8217 after the module name."
                        }
                bs = mkBuildState [msg]
            eitherDecode (encode bs) `shouldBe` Right bs

        it "survives control characters in message text" do
            let msg =
                    Diagnostic
                        { severity = SWarning
                        , file = "<interactive>"
                        , line = 1
                        , col = 1
                        , endLine = 1
                        , endCol = 1
                        , title = "text with \CAN control \EM chars and \ESC[1m ANSI \ESC[0m codes"
                        , text = "text with \CAN control \EM chars and \ESC[1m ANSI \ESC[0m codes"
                        }
                bs = mkBuildState [msg]
            eitherDecode (encode bs) `shouldBe` Right bs

        it "survives curly double quotes in message text" do
            let msg =
                    Diagnostic
                        { severity = SWarning
                        , file = "<interactive>"
                        , line = 1
                        , col = 1
                        , endLine = 1
                        , endCol = 1
                        , title = "\8220Place qualified after the module name.\8221"
                        , text = "\8220Place qualified after the module name.\8221"
                        }
                bs = mkBuildState [msg]
            eitherDecode (encode bs) `shouldBe` Right bs

        -- Guards the wire format for the BuildFailed phase: the captured
        -- cabal/build error (multi-line, Unicode) must round-trip intact so
        -- the CLI/UI clients can render it.
        it "survives a BuildFailed phase with a multi-line message" do
            let bs =
                    mkBuildState [] :: BuildState
                failed =
                    bs
                        { phase =
                            Build.Failed
                                "cabal: Could not resolve dependencies:\n[__0] trying: \8216base\8217\nrejecting: ..."
                        }
            eitherDecode (encode failed) `shouldBe` Right failed


mkBuildState :: [Diagnostic] -> BuildState
mkBuildState msgs =
    BuildState
        { buildId = BuildId 1
        , phase =
            Build.Finished
                ( BuildResult
                    { completedAt = epoch
                    , duration = 0
                    , moduleCount = 0
                    , diagnostics = msgs
                    }
                )
                $ PostBuild mempty Eval.NoneFound
        , daemonInfo =
            DaemonInfo
                { targets = []
                , watchDirs = []
                , sockPath = ""
                , logFile = ""
                }
        }
  where
    epoch = UTCTime (fromGregorian 1970 1 1) 0