-- This file is part of the Wire Server implementation.
--
-- Copyright (C) 2022 Wire Swiss GmbH <opensource@wire.com>
--
-- This program is free software: you can redistribute it and/or modify it under
-- the terms of the GNU Affero General Public License as published by the Free
-- Software Foundation, either version 3 of the License, or (at your option) any
-- later version.
--
-- This program is distributed in the hope that it will be useful, but WITHOUT
-- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-- FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
-- details.
--
-- You should have received a copy of the GNU Affero General Public License along
-- with this program. If not, see <https://www.gnu.org/licenses/>.

module Test.System.Logger.ExtendedSpec where

import Data.Aeson ((.=))
import Data.Aeson qualified as Aeson
import Data.String.Conversions
import Imports
import System.IO.Temp
import System.Logger.Extended hiding ((.=))
import Test.Hspec (Spec, describe, it, shouldBe)

spec :: Spec
spec =
  describe "System.Loggger.Extended" $ do
    describe "LogFormat: StructuredJSON" $ do
      it "should encode logs as new line separated structured JSON with log level, messages and fields" $ do
        withSystemTempFile "structured-json" $ \f h -> do
          hClose h -- The handle is not required
          l <-
            new
              . setRenderer structuredJSONRenderer
              . setOutput (Path f)
              . setFormat Nothing -- date format, not having it makes it easier to test.
              $ defSettings

          warn l $
            msg ("first message" :: ByteString)
              . field "field1" ("val 1.1" :: ByteString)
              . field "field2" ("val 2" :: ByteString)
              . field "field1" ("val 1.2" :: ByteString)
              . msg ("second message" :: ByteString)
          info l $ msg ("just a message" :: ByteString)

          flush l
          close l
          actualLogs <- map (Aeson.eitherDecode @Aeson.Value . cs) . lines <$> readFile f

          let expectedLogs =
                [ Aeson.object
                    [ "level" .= Warn,
                      "msgs" .= ["first message" :: Text, "second message"],
                      "field1" .= ["val 1.1" :: Text, "val 1.2"],
                      "field2" .= ("val 2" :: Text)
                    ],
                  Aeson.object
                    [ "level" .= Info,
                      "msgs" .= ["just a message" :: Text]
                    ]
                ]
          actualLogs `shouldBe` (Right <$> expectedLogs)
