{-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE ConstraintKinds #-} module Data.Aeson.Config.FromValueSpec where import Helper import GHC.Generics import qualified Data.Map.Lazy as Map import Data.Aeson.Config.FromValue shouldDecodeTo :: (HasCallStack, Eq a, Show a, FromValue a) => Value -> Result a -> Expectation shouldDecodeTo value expected = decodeValue value `shouldBe` expected shouldDecodeTo_ :: (HasCallStack, Eq a, Show a, FromValue a) => Value -> a -> Expectation shouldDecodeTo_ value expected = decodeValue value `shouldBe` Right (expected, []) data Person = Person { personName :: String , personAge :: Int , personAddress :: Maybe Address } deriving (Eq, Show, Generic, FromValue) data Address = Address { addressRegion :: String , addressZip :: String } deriving (Eq, Show, Generic, FromValue) data Job = Job { jobRole :: String , jobSalary :: Int } deriving (Eq, Show, Generic, FromValue) spec :: Spec spec = do describe "fromValue" $ do context "with a record" $ do let left :: String -> Result Person left = Left it "decodes a record" $ do [yaml| name: "Joe" age: 23 |] `shouldDecodeTo_` Person "Joe" 23 Nothing it "captures unrecognized fields" $ do [yaml| name: "Joe" age: 23 foo: bar |] `shouldDecodeTo` Right (Person "Joe" 23 Nothing, ["$.foo"]) it "captures nested unrecognized fields" $ do [yaml| name: "Joe" age: 23 address: region: somewhere zip: "123456" foo: bar: 23 |] `shouldDecodeTo` Right (Person "Joe" 23 (Just (Address "somewhere" "123456")), ["$.address.foo"]) it "ignores fields that start with an underscore" $ do [yaml| name: "Joe" age: 23 address: region: somewhere zip: "123456" _foo: bar: 23 |] `shouldDecodeTo_` Person "Joe" 23 (Just (Address "somewhere" "123456")) it "fails on missing field" $ do [yaml| name: "Joe" |] `shouldDecodeTo` left "Error while parsing $ - key \"age\" not present" it "fails on invalid field value" $ do [yaml| name: "Joe" age: "23" |] `shouldDecodeTo` left "Error while parsing $.age - expected Int, encountered String" context "with (,)" $ do it "captures unrecognized fields" $ do [yaml| name: Joe age: 23 role: engineer salary: 100000 foo: bar |] `shouldDecodeTo` Right ((Person "Joe" 23 Nothing, Job "engineer" 100000), ["$.foo"]) context "with []" $ do it "captures unrecognized fields" $ do let expected = [Person "Joe" 23 (Just (Address "somewhere" "123456")), Person "Marry" 25 Nothing] [yaml| - name: "Joe" age: 23 address: region: somewhere zip: "123456" foo: 23 - name: "Marry" age: 25 bar: 42 |] `shouldDecodeTo` Right (expected, ["$[1].bar", "$[0].address.foo"]) context "with Map" $ do it "captures unrecognized fields" $ do [yaml| Joe: region: somewhere zip: '123456' foo: bar |] `shouldDecodeTo` Right (Map.fromList [("Joe", Address "somewhere" "123456")], ["$.Joe.foo"])