-- |
--
-- Module      : Test.Tasty.Golden.Extra.Internal
-- Copyright   : (C) 2024 Bellroy Pty Ltd
-- License     : BSD-3-Clause
-- Maintainer  : Bellroy Tech Team <haskell@bellroy.com>
-- Stability   : experimental
--
-- Common types and functions  used by the other modules in `tasty-golden-extra`.
module Test.Tasty.Golden.Extra.Internal
  ( checkJsonDifference,
    maybeDifference,
    JsonDifference (..),
  )
where

import qualified Data.Aeson as Aeson
import Data.Aeson.Diff (diff)
import Data.Aeson.Patch (patchOperations)
import qualified Data.Text.Lazy as TL
import Text.Pretty.Simple (pShowNoColor)

-- | Represents the result of comparing two JSON values - either the JSON is
-- identical, or there are differences and you are given an error message
-- containing the differences.
data JsonDifference
  = JsonIdentical
  | JsonDifferent String

-- | Convert a `JsonDifference` to a `Maybe String` containing the error message.
maybeDifference :: JsonDifference -> Maybe String
maybeDifference :: JsonDifference -> Maybe String
maybeDifference JsonDifference
JsonIdentical = Maybe String
forall a. Maybe a
Nothing
maybeDifference (JsonDifferent String
diffString) = String -> Maybe String
forall a. a -> Maybe a
Just String
diffString

-- | Compare two JSON values and return a `JsonDifference` representing the result.
checkJsonDifference ::
  Aeson.Value ->
  Aeson.Value ->
  JsonDifference
checkJsonDifference :: Value -> Value -> JsonDifference
checkJsonDifference Value
goldenJson Value
actualJson =
  case Patch -> [Operation]
patchOperations (Patch -> [Operation]) -> Patch -> [Operation]
forall a b. (a -> b) -> a -> b
$ Value -> Value -> Patch
diff Value
goldenJson Value
actualJson of
    [] -> JsonDifference
JsonIdentical
    [Operation]
ds ->
      String -> JsonDifference
JsonDifferent (String -> JsonDifference) -> String -> JsonDifference
forall a b. (a -> b) -> a -> b
$
        String
"Files contain different JSON values:\n" String -> String -> String
forall a. Semigroup a => a -> a -> a
<> Text -> String
TL.unpack ([Operation] -> Text
forall a. Show a => a -> Text
pShowNoColor [Operation]
ds)