packages feed

tasty-golden-extra (empty) → 0.1.0.0

raw patch · 9 files changed

+460/−0 lines, 9 filesdep +aesondep +aeson-diffdep +aeson-pretty

Dependencies added: aeson, aeson-diff, aeson-pretty, base, bytestring, pretty-show, pretty-simple, tasty, tasty-discover, tasty-golden, text, yaml

Files

+ CHANGELOG.md view
@@ -0,0 +1,7 @@+# Changes++## Version 0.1.0.0++_2024-12-17_++- Introducing `GoldenVsShow`, `GoldenVsString`, `GoldenVsToJSON`, `GoldenVsToYAML`
+ LICENSE view
@@ -0,0 +1,29 @@+Copyright (C) 2024 Bellroy Pty Ltd++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are+met:++1. Redistributions of source code must retain the above copyright+   notice, this list of conditions and the following disclaimer.++2. Redistributions in binary form must reproduce the above copyright+   notice, this list of conditions and the following disclaimer in the+   documentation and/or other materials provided with the+   distribution.++3. Neither the name of the copyright holder nor the names of its+   contributors may be used to endorse or promote products derived+   from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.md view
@@ -0,0 +1,8 @@+# tasty-golden-extra++A library providing additional golden test helpers for the+@tasty-golden@ package. These helpers are useful for testing+the output of functions that return textual output and instances of @Show@,+@ToJSON@ or @ToYAML@.++To find out what's new, read the [change log](https://github.com/bellroy/tasty-golden-extra/blob/master/CHANGELOG.md).
+ src/Test/Tasty/Golden/Extra/GoldenVsShow.hs view
@@ -0,0 +1,76 @@+{-# LANGUAGE ExistentialQuantification #-}++-- |+--+-- Module      : Test.Tasty.Golden.Extra.GoldenVsShow+-- Copyright   : (C) 2024 Bellroy Pty Ltd+-- License     : BSD-3-Clause+-- Maintainer  : Bellroy Tech Team <haskell@bellroy.com>+-- Stability   : experimental+--+-- These helpers are useful for creating golden tests for @Show@ instances.+module Test.Tasty.Golden.Extra.GoldenVsShow+  ( goldenVsShow,+    GoldenVsShow (..),+  )+where++import qualified Data.Text.Lazy as Text+import Data.Text.Lazy.Encoding (encodeUtf8)+import Test.Tasty (TestName, TestTree)+import qualified Test.Tasty.Discover as Discover+import Test.Tasty.Golden+import Text.Show.Pretty (ppShow)++-- | Tasty-discoverable type for creating golden tests for @Show@ instances.+--+-- Example use:+--+-- @+--  import MySchemasWithShowAndToJSONInstances.Person (Person)+--  import qualified Data.Aeson as Aeson+--  import System.FilePath ((\</\>))+--  import Test.Tasty.Golden.Extra.GoldenVsShow (GoldenVsShow (..))+--+--  tasty_GoldenVsShow :: GoldenVsShow+--  tasty_GoldenVsShow =+--    GoldenVsShow (goldenFilesPath \</\> "Person.golden.txt") $+--      Aeson.eitherDecodeFileStrict @Person (goldenFilesPath \</\> "Person.json")+-- @+data GoldenVsShow = forall a. (Show a) => GoldenVsShow FilePath (IO a)++instance Discover.Tasty GoldenVsShow where+  tasty info (GoldenVsShow ref act) =+    pure $ goldenVsShow (Discover.nameOf info) ref act++-- | Helper function for creating a @TestTree@ for @Show@ golden tests.+-- Use when you want to test @Show@ instances against a golden example on disk.+--+-- Example use:+--+-- @+--  import MySchemasWithShowAndShowInstances.Person (Person)+--  import qualified Data.Aeson as Aeson+--  import System.FilePath ((\</\>))+--  import Test.Tasty.Golden.Extra.GoldenVsShow (goldenVsShow)+--+--  test_Show :: TestTree+--  test_Show = do+--    let inputFile = goldenFilesPath \</\> "Person.json"+--    goldenVsShow+--      "Test Show instance for Person"+--      (goldenFilesPath \</\> "Person.golden.txt")+--      (Aeson.decodeFileStrict' @Person inputFile)+-- @+goldenVsShow ::+  (Show a) =>+  -- | test name+  TestName ->+  -- | path to the «golden» file (the file that contains correct output)+  FilePath ->+  -- | action that returns an instance of the type whose instance is being tested+  IO a ->+  -- | the test verifies that the returned string is the same as the golden file contents+  TestTree+goldenVsShow name ref =+  goldenVsString name ref . fmap (encodeUtf8 . Text.pack . ppShow)
+ src/Test/Tasty/Golden/Extra/GoldenVsString.hs view
@@ -0,0 +1,41 @@+-- |+--+-- Module      : Test.Tasty.Golden.Extra.GoldenVsString+-- Copyright   : (C) 2024 Bellroy Pty Ltd+-- License     : BSD-3-Clause+-- Maintainer  : Bellroy Tech Team <haskell@bellroy.com>+-- Stability   : experimental+--+-- These helpers are useful for creating golden tests for functions that+-- produce textual output.+module Test.Tasty.Golden.Extra.GoldenVsString+  ( GoldenVsString (..),+    goldenVsString,+  )+where++import Data.ByteString.Lazy (ByteString)+import qualified Test.Tasty.Discover as Discover+import Test.Tasty.Golden++-- | Tasty-discoverable type for creating golden tests for functions that produce+-- textual output.+--+-- Example use:+--+-- @+--  import MySchemasWithShowAndToJSONInstances.Person (convertToCSVText)+--  import qualified Data.Aeson as Aeson+--  import System.FilePath ((\</\>))+--  import Test.Tasty.Golden.Extra.GoldenVsString (GoldenVsString (..))+--+--  tasty_FromJSON_ToJSON :: GoldenVsString+--  tasty_FromJSON_ToJSON =+--    GoldenVsString (goldenFilesPath \</\> "Person.golden.csv") $+--      maybe "Error" convertToCSVText <$>+--        Aeson.decodeFileStrict' (goldenFilesPath \</\> "Person.json")+-- @+data GoldenVsString = GoldenVsString FilePath (IO ByteString)++instance Discover.Tasty GoldenVsString where+  tasty info (GoldenVsString ref act) = pure $ goldenVsString (Discover.nameOf info) ref act
+ src/Test/Tasty/Golden/Extra/GoldenVsToJSON.hs view
@@ -0,0 +1,85 @@+{-# LANGUAGE ExistentialQuantification #-}++-- |+--+-- Module      : Test.Tasty.Golden.Extra.GoldenVsToJSON+-- Copyright   : (C) 2024 Bellroy Pty Ltd+-- License     : BSD-3-Clause+-- Maintainer  : Bellroy Tech Team <haskell@bellroy.com>+-- Stability   : experimental+--+-- These helpers are useful for creating golden tests for @ToJSON@ instances.+module Test.Tasty.Golden.Extra.GoldenVsToJSON+  ( GoldenVsToJSON (..),+    goldenVsToJson,+  )+where++import qualified Data.Aeson as Aeson+import Data.Aeson.Encode.Pretty (encodePretty)+import qualified Data.ByteString.Lazy as BL+import Test.Tasty (TestName, TestTree)+import qualified Test.Tasty.Discover as Discover+import Test.Tasty.Golden.Advanced (goldenTest)+import Test.Tasty.Golden.Extra.Internal (checkJsonDifference, maybeDifference)++-- | Tasty-discoverable type for creating golden tests for @ToJSON@ instances.+--+-- Example use:+--+-- @+--  import MySchemasWithToJSONInstances.Person (Person)+--  import qualified Data.Aeson as Aeson+--  import System.FilePath ((\</\>))+--  import Test.Tasty.Golden.Extra.GoldenVsToJSON (GoldenVsToJSON (..))+--+--  tasty_FromJSON_ToJSON :: GoldenVsToJSON+--  tasty_FromJSON_ToJSON =+--    GoldenVsToJSON (goldenFilesPath \</\> "Person.golden.json") $+--      Aeson.eitherDecodeFileStrict @Person (goldenFilesPath \</\> "Person.json")+-- @+data GoldenVsToJSON = forall a. (Aeson.ToJSON a) => GoldenVsToJSON FilePath (IO a)++instance Discover.Tasty GoldenVsToJSON where+  tasty info (GoldenVsToJSON ref act) = pure $ goldenVsToJson (Discover.nameOf info) ref act++-- | Helper function for creating a @TestTree@ for @ToJSON@ golden tests.+-- Use when you want to test @ToJSON@ instances against a golden example on disk.+--+-- Example use:+--+-- @+--  import MySchemasWithToJSONInstances.Person (Person)+--  import qualified Data.Aeson as Aeson+--  import System.FilePath ((\</\>))+--  import Test.Tasty.Golden.Extra.GoldenVsToJSON (goldenVsToJSON)+--+--  test_ToJSON :: TestTree+--  test_ToJSON = do+--    let inputFile = goldenFilesPath \</\> "Person.json"+--    goldenVsToJSON+--      "Test ToJSON instance for Person"+--      (goldenFilesPath \</\> "Person.golden.json")+--      (Aeson.decodeFileStrict' @Person inputFile)+-- @+goldenVsToJson ::+  forall a.+  (Aeson.ToJSON a) =>+  -- | test name+  TestName ->+  -- | path to the «golden» file (the file that contains correct output)+  FilePath ->+  -- | action that returns an instance of the type whose instance is being tested+  IO a ->+  -- | the test verifies that the returned string is the same as the golden file contents+  TestTree+goldenVsToJson name fp act =+  goldenTest+    name+    (Aeson.decodeFileStrict fp >>= orFailTest ("Couldn't decode golden JSON file:" <> fp))+    (Aeson.toJSON <$> act)+    (\a b -> pure . maybeDifference $ checkJsonDifference a b)+    (BL.writeFile fp . encodePretty)++orFailTest :: String -> Maybe a -> IO a+orFailTest msg = maybe (error msg) pure
+ src/Test/Tasty/Golden/Extra/GoldenVsToYAML.hs view
@@ -0,0 +1,98 @@+{-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE ExistentialQuantification #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RankNTypes #-}++-- |+--+-- Module      : Test.Tasty.Golden.Extra.GoldenVsToYAML+-- Copyright   : (C) 2024 Bellroy Pty Ltd+-- License     : BSD-3-Clause+-- Maintainer  : Bellroy Tech Team <haskell@bellroy.com>+-- Stability   : experimental+--+-- These helpers are useful for creating golden tests for @ToJSON@ instances,+-- that you want to convert to YAML using the @Data.Yaml@ package.+module Test.Tasty.Golden.Extra.GoldenVsToYAML+  ( goldenVsToYaml,+    GoldenVsToYAML (..),+  )+where++import Data.Aeson+import qualified Data.Aeson as Aeson+import qualified Data.ByteString as BL+import qualified Data.Yaml as Yaml+import Test.Tasty+import qualified Test.Tasty.Discover as Discover+import Test.Tasty.Golden.Advanced (goldenTest)+import Test.Tasty.Golden.Extra.Internal (checkJsonDifference, maybeDifference)++-- | Tasty-discoverable type for creating golden tests for @ToJSON@ instances,+-- that you want to convert to YAML using the @Data.Yaml@ package.+--+-- Example use:+--+-- @+--  import MySchemasWithToJSONInstances.Person (Person)+--  import qualified Data.Aeson as Aeson+--  import System.FilePath ((\</\>))+--  import Test.Tasty.Golden.Extra.GoldenVsToYAML (GoldenVsToYAML (..))+--+--  tasty_FromJSON_ToYAML :: GoldenVsToYAML+--  tasty_FromJSON_ToYAML =+--    GoldenVsToYAML (goldenFilesPath \</\> "Person.golden.yaml") $+--      Aeson.eitherDecodeFileStrict @Person (goldenFilesPath \</\> "Person.json")+-- @+data GoldenVsToYAML = forall a. (Aeson.ToJSON a) => GoldenVsToYAML FilePath (IO a)++instance Discover.Tasty GoldenVsToYAML where+  tasty info (GoldenVsToYAML ref act) = pure $ goldenVsToYaml (Discover.nameOf info) ref act++-- | Helper function for creating a @TestTree@ for @ToJSON@-to-YAML golden tests.+-- Use when you want to test @ToJSON@ instances against a golden example of YAML+-- on disk.+--+-- Example use:+--+-- @+--  import MySchemasWithToJSONInstances.Person (Person)+--  import qualified Data.Aeson as Aeson+--  import System.FilePath ((\</\>))+--  import Test.Tasty.Golden.Extra.GoldenVsToYAML (goldenVsToYAML)+--+--  test_ToYAML :: TestTree+--  test_ToYAML = do+--    let inputFile = goldenFilesPath \</\> "Person.yaml"+--    goldenVsToYAML+--      "Test YAML serialization for Person"+--      (goldenFilesPath \</\> "Person.golden.yaml")+--      (Aeson.decodeFileStrict' @Person inputFile)+-- @+goldenVsToYaml ::+  forall a.+  (ToJSON a) =>+  -- | test name+  TestName ->+  -- | path to the «golden» file (the file that contains correct output)+  FilePath ->+  -- | action that returns an instance of the type whose instance is being tested+  IO a ->+  -- | the test verifies that the returned string is the same as the golden file contents+  TestTree+goldenVsToYaml name fp act =+  goldenTest+    name+    (Yaml.decodeFileEither fp >>= orFailTest fp)+    (Aeson.toJSON <$> act)+    (\a b -> pure . maybeDifference $ checkJsonDifference a b)+    (BL.writeFile fp . Yaml.encode)++orFailTest :: FilePath -> Either Yaml.ParseException a -> IO a+orFailTest fp =+  either+    ( fail+        . (\t -> mconcat ["Failed to decode file ", fp, "\n", t])+        . Yaml.prettyPrintParseException+    )+    pure
+ src/Test/Tasty/Golden/Extra/Internal.hs view
@@ -0,0 +1,45 @@+-- |+--+-- 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 JsonIdentical = Nothing+maybeDifference (JsonDifferent diffString) = Just diffString++-- | Compare two JSON values and return a `JsonDifference` representing the result.+checkJsonDifference ::+  Aeson.Value ->+  Aeson.Value ->+  JsonDifference+checkJsonDifference goldenJson actualJson =+  case patchOperations $ diff goldenJson actualJson of+    [] -> JsonIdentical+    ds ->+      JsonDifferent $+        "Files contain different JSON values:\n" <> TL.unpack (pShowNoColor ds)
+ tasty-golden-extra.cabal view
@@ -0,0 +1,71 @@+cabal-version:      3.0+name:               tasty-golden-extra+version:            0.1.0.0+license:            BSD-3-Clause+license-file:       LICENSE+category:           Testing+homepage:+  https://github.com/bellroy/tasty-golden-extra++bug-reports:        https://github.com/bellroy/tasty-golden-extra/issues+author:             Bellroy+maintainer:         geeks@bellroy.com+build-type:         Simple+synopsis:           Additional golden test helpers for the tasty-golden package+description:+  A library providing additional golden test helpers for the+  @tasty-golden@ package.  These helpers are useful for testing+  the output of functions that return @String@s, @Show@, @ToJSON@ or @ToYAML@+  instances.++tested-with:+  GHC ==8.10.7 || ==9.0.2 || ==9.2.4 || ==9.4.5 || ==9.6.6 || ==9.8.2++extra-source-files:+  CHANGELOG.md+  README.md++source-repository head+  type:     git+  location: https://github.com/bellroy/tasty-golden-extra.git++common deps+  build-depends:+    , aeson           >=2.1        && <2.3+    , aeson-diff      ^>=1.1.0.13+    , aeson-pretty    ^>=0.8.10+    , base            >=4.14       && <4.20+    , bytestring      >=0.10       && <0.13+    , pretty-show     ^>=1.10+    , pretty-simple   ^>=4.1.3.0+    , tasty           ^>=1.5.2+    , tasty-discover  ^>=5.0.0+    , tasty-golden    ^>=2.3.5+    , text            ^>=1.2       || ^>=2.0 || ^>=2.1+    , yaml            ^>=0.11.11.2++common opts+  default-language:   Haskell2010+  default-extensions:+    DuplicateRecordFields+    OverloadedStrings++  ghc-options:+    -Wall -Wcompat -Widentities -Wincomplete-record-updates+    -Wincomplete-uni-patterns -Werror=incomplete-patterns+    -Wredundant-constraints -Wpartial-fields -Wtabs+    -Wmissing-local-signatures -fhelpful-errors+    -fprint-expanded-synonyms -fwarn-unused-do-bind++library+  import:          deps, opts+  ghc-options:     -Wunused-packages+  hs-source-dirs:  src++  -- cabal-fmt: expand src/+  exposed-modules:+    Test.Tasty.Golden.Extra.GoldenVsShow+    Test.Tasty.Golden.Extra.GoldenVsString+    Test.Tasty.Golden.Extra.GoldenVsToJSON+    Test.Tasty.Golden.Extra.GoldenVsToYAML+    Test.Tasty.Golden.Extra.Internal