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 +7/−0
- LICENSE +29/−0
- README.md +8/−0
- src/Test/Tasty/Golden/Extra/GoldenVsShow.hs +76/−0
- src/Test/Tasty/Golden/Extra/GoldenVsString.hs +41/−0
- src/Test/Tasty/Golden/Extra/GoldenVsToJSON.hs +85/−0
- src/Test/Tasty/Golden/Extra/GoldenVsToYAML.hs +98/−0
- src/Test/Tasty/Golden/Extra/Internal.hs +45/−0
- tasty-golden-extra.cabal +71/−0
+ 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