waargonaut 0.1.0.0 → 0.2.0.0
raw patch · 9 files changed
+246/−28 lines, 9 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- Waargonaut.Decode.Internal: instance (Waargonaut.Decode.Internal.CursorHistory' i ~ t) => Control.Lens.Wrapped.Rewrapped (Waargonaut.Decode.Internal.CursorHistory' i) t
- Waargonaut.Decode.Types: instance (Waargonaut.Decode.Types.JCurs ~ t) => Control.Lens.Wrapped.Rewrapped Waargonaut.Decode.Types.JCurs t
- Waargonaut.Encode: instance (Waargonaut.Encode.Encoder f a ~ t) => Control.Lens.Wrapped.Rewrapped (Waargonaut.Encode.Encoder f a) t
- Waargonaut.Generic: instance forall k (t :: k) a. Waargonaut.Generic.JsonDecode t a => Waargonaut.Generic.JsonDecode t (GHC.Base.Maybe a)
- Waargonaut.Generic: instance forall k (t :: k) a. Waargonaut.Generic.JsonEncode t a => Waargonaut.Generic.JsonEncode t (GHC.Base.Maybe a)
- Waargonaut.Types.JArray: instance (Waargonaut.Types.JArray.JArray ws a ~ t) => Control.Lens.Wrapped.Rewrapped (Waargonaut.Types.JArray.JArray ws a) t
- Waargonaut.Types.JChar: instance (Waargonaut.Types.JChar.JCharUnescaped ~ t) => Control.Lens.Wrapped.Rewrapped Waargonaut.Types.JChar.JCharUnescaped t
- Waargonaut.Types.JNumber: instance (Waargonaut.Types.JNumber.Frac ~ t) => Control.Lens.Wrapped.Rewrapped Waargonaut.Types.JNumber.Frac t
- Waargonaut.Types.JObject: instance (Waargonaut.Types.JObject.JObject ws a ~ t) => Control.Lens.Wrapped.Rewrapped (Waargonaut.Types.JObject.JObject ws a) t
- Waargonaut.Types.JObject: instance (Waargonaut.Types.JObject.MapLikeObj ws a ~ t) => Control.Lens.Wrapped.Rewrapped (Waargonaut.Types.JObject.MapLikeObj ws a) t
- Waargonaut.Types.JString: instance (Waargonaut.Types.JString.JString' digit ~ t) => Control.Lens.Wrapped.Rewrapped (Waargonaut.Types.JString.JString' digit) t
- Waargonaut.Types.Json: instance (Waargonaut.Types.Json.Json ~ t) => Control.Lens.Wrapped.Rewrapped Waargonaut.Types.Json.Json t
- Waargonaut.Types.Whitespace: instance (Waargonaut.Types.Whitespace.WS ~ t) => Control.Lens.Wrapped.Rewrapped Waargonaut.Types.Whitespace.WS t
+ Waargonaut.Decode.Internal: instance (Waargonaut.Decode.Internal.CursorHistory' i Data.Type.Equality.~ t) => Control.Lens.Wrapped.Rewrapped (Waargonaut.Decode.Internal.CursorHistory' i) t
+ Waargonaut.Decode.Types: instance (Waargonaut.Decode.Types.JCurs Data.Type.Equality.~ t) => Control.Lens.Wrapped.Rewrapped Waargonaut.Decode.Types.JCurs t
+ Waargonaut.Encode: instance (Waargonaut.Encode.Encoder f a Data.Type.Equality.~ t) => Control.Lens.Wrapped.Rewrapped (Waargonaut.Encode.Encoder f a) t
+ Waargonaut.Generic: --
+ Waargonaut.Generic: -- '[ '[ Int ]
+ Waargonaut.Generic: -- , '[ Tree, Tree ]
+ Waargonaut.Generic: -- </pre>
+ Waargonaut.Generic: -- <i>Example:</i> The datatype
+ Waargonaut.Generic: -- <pre>
+ Waargonaut.Generic: -- This is a list of lists of its components. The outer list contains one
+ Waargonaut.Generic: -- ]
+ Waargonaut.Generic: -- constructor argument (field).
+ Waargonaut.Generic: -- data Tree = Leaf Int | Node Tree Tree
+ Waargonaut.Generic: -- element per constructor. The inner list contains one element per
+ Waargonaut.Generic: -- is supposed to have the following code:
+ Waargonaut.Generic: -- type instance Code (Tree a) =
+ Waargonaut.Generic: -- | Type-level datatype info
+ Waargonaut.Generic: instance forall k (t :: k) a. Waargonaut.Generic.JsonDecode t a => Waargonaut.Generic.JsonDecode t (GHC.Maybe.Maybe a)
+ Waargonaut.Generic: instance forall k (t :: k) a. Waargonaut.Generic.JsonEncode t a => Waargonaut.Generic.JsonEncode t (GHC.Maybe.Maybe a)
+ Waargonaut.Types.JArray: instance (Waargonaut.Types.JArray.JArray ws a Data.Type.Equality.~ t) => Control.Lens.Wrapped.Rewrapped (Waargonaut.Types.JArray.JArray ws a) t
+ Waargonaut.Types.JChar: instance (Waargonaut.Types.JChar.JCharUnescaped Data.Type.Equality.~ t) => Control.Lens.Wrapped.Rewrapped Waargonaut.Types.JChar.JCharUnescaped t
+ Waargonaut.Types.JNumber: instance (Waargonaut.Types.JNumber.Frac Data.Type.Equality.~ t) => Control.Lens.Wrapped.Rewrapped Waargonaut.Types.JNumber.Frac t
+ Waargonaut.Types.JObject: instance (Waargonaut.Types.JObject.JObject ws a Data.Type.Equality.~ t) => Control.Lens.Wrapped.Rewrapped (Waargonaut.Types.JObject.JObject ws a) t
+ Waargonaut.Types.JObject: instance (Waargonaut.Types.JObject.MapLikeObj ws a Data.Type.Equality.~ t) => Control.Lens.Wrapped.Rewrapped (Waargonaut.Types.JObject.MapLikeObj ws a) t
+ Waargonaut.Types.JString: instance (Waargonaut.Types.JString.JString' digit Data.Type.Equality.~ t) => Control.Lens.Wrapped.Rewrapped (Waargonaut.Types.JString.JString' digit) t
+ Waargonaut.Types.Json: instance (Waargonaut.Types.Json.Json Data.Type.Equality.~ t) => Control.Lens.Wrapped.Rewrapped Waargonaut.Types.Json.Json t
+ Waargonaut.Types.Whitespace: instance (Waargonaut.Types.Whitespace.WS Data.Type.Equality.~ t) => Control.Lens.Wrapped.Rewrapped Waargonaut.Types.Whitespace.WS t
- Waargonaut: JArr :: (JArray ws a) -> ws -> JType ws a
+ Waargonaut: JArr :: JArray ws a -> ws -> JType ws a
- Waargonaut: JObj :: (JObject ws a) -> ws -> JType ws a
+ Waargonaut: JObj :: JObject ws a -> ws -> JType ws a
- Waargonaut: Json :: (JType WS Json) -> Json
+ Waargonaut: Json :: JType WS Json -> Json
- Waargonaut.Decode: Decoder :: ParseFn -> JCurs -> DecodeResultT Count DecodeError f a -> Decoder f a
+ Waargonaut.Decode: Decoder :: (ParseFn -> JCurs -> DecodeResultT Count DecodeError f a) -> Decoder f a
- Waargonaut.Decode: fromKey :: (Monad f) => Text -> Decoder f b -> JCurs -> DecodeResult f b
+ Waargonaut.Decode: fromKey :: Monad f => Text -> Decoder f b -> JCurs -> DecodeResult f b
- Waargonaut.Decode.Error: KeyDecodeFailed :: Text -> DecodeError
+ Waargonaut.Decode.Error: KeyDecodeFailed :: DecodeError
- Waargonaut.Decode.Error: _KeyDecodeFailed :: AsDecodeError r => Prism' r Text
+ Waargonaut.Decode.Error: _KeyDecodeFailed :: AsDecodeError r => Prism' r ()
- Waargonaut.Decode.Internal: Decoder' :: c -> DecodeResultT i e f a -> Decoder' c i e f a
+ Waargonaut.Decode.Internal: Decoder' :: (c -> DecodeResultT i e f a) -> Decoder' c i e f a
- Waargonaut.Decode.Internal: KeyDecodeFailed :: Text -> DecodeError
+ Waargonaut.Decode.Internal: KeyDecodeFailed :: DecodeError
- Waargonaut.Decode.Internal: _KeyDecodeFailed :: AsDecodeError r => Prism' r Text
+ Waargonaut.Decode.Internal: _KeyDecodeFailed :: AsDecodeError r => Prism' r ()
- Waargonaut.Decode.Traversal: fromKey :: (Monad f) => Text -> Decoder f b -> JCursor h Json -> DecodeResult f b
+ Waargonaut.Decode.Traversal: fromKey :: Monad f => Text -> Decoder f b -> JCursor h Json -> DecodeResult f b
- Waargonaut.Decode.Traversal: moveToKey :: (AsJType s ws s, Monad f) => Text -> JCursor h s -> DecodeResult f (h :>> s :>> Elems ws (JAssoc ws s) :>> JAssoc ws s :>> s)
+ Waargonaut.Decode.Traversal: moveToKey :: (AsJType s ws s, Monad f) => Text -> JCursor h s -> DecodeResult f ((((h :>> s) :>> Elems ws (JAssoc ws s)) :>> JAssoc ws s) :>> s)
- Waargonaut.Decode.Types: Decoder :: ParseFn -> JCurs -> DecodeResultT Count DecodeError f a -> Decoder f a
+ Waargonaut.Decode.Types: Decoder :: (ParseFn -> JCurs -> DecodeResultT Count DecodeError f a) -> Decoder f a
- Waargonaut.Encode: Encoder :: a -> f Json -> Encoder f a
+ Waargonaut.Encode: Encoder :: (a -> f Json) -> Encoder f a
- Waargonaut.Generic: Options :: String -> String -> NewtypeName -> Options
+ Waargonaut.Generic: Options :: (String -> String) -> NewtypeName -> Options
- Waargonaut.Generic: class All (SListI :: [*] -> Constraint) Code a => Generic a where {
+ Waargonaut.Generic: class All (SListI :: [Type] -> Constraint) Code a => Generic a where {
- Waargonaut.Generic: class HasDatatypeInfo a where {
+ Waargonaut.Generic: class Generic a => HasDatatypeInfo a where {
- Waargonaut.Generic: datatypeInfo :: HasDatatypeInfo a => proxy a -> DatatypeInfo Code a
+ Waargonaut.Generic: datatypeInfo :: HasDatatypeInfo a => proxy a -> DatatypeInfo (Code a)
- Waargonaut.Types.CommaSep: CommaSeparated :: ws -> (Maybe (Elems ws a)) -> CommaSeparated ws a
+ Waargonaut.Types.CommaSep: CommaSeparated :: ws -> Maybe (Elems ws a) -> CommaSeparated ws a
- Waargonaut.Types.JArray: JArray :: (CommaSeparated ws a) -> JArray ws a
+ Waargonaut.Types.JArray: JArray :: CommaSeparated ws a -> JArray ws a
- Waargonaut.Types.JChar: EscapedJChar :: (JCharEscaped digit) -> JChar digit
+ Waargonaut.Types.JChar: EscapedJChar :: JCharEscaped digit -> JChar digit
- Waargonaut.Types.JChar: Hex :: (HexDigit4 digit) -> JCharEscaped digit
+ Waargonaut.Types.JChar: Hex :: HexDigit4 digit -> JCharEscaped digit
- Waargonaut.Types.JNumber: Frac :: (NonEmpty DecDigit) -> Frac
+ Waargonaut.Types.JNumber: Frac :: NonEmpty DecDigit -> Frac
- Waargonaut.Types.JObject: JObject :: (CommaSeparated ws (JAssoc ws a)) -> JObject ws a
+ Waargonaut.Types.JObject: JObject :: CommaSeparated ws (JAssoc ws a) -> JObject ws a
- Waargonaut.Types.JString: JString' :: (Vector (JChar digit)) -> JString' digit
+ Waargonaut.Types.JString: JString' :: Vector (JChar digit) -> JString' digit
- Waargonaut.Types.Json: JArr :: (JArray ws a) -> ws -> JType ws a
+ Waargonaut.Types.Json: JArr :: JArray ws a -> ws -> JType ws a
- Waargonaut.Types.Json: JObj :: (JObject ws a) -> ws -> JType ws a
+ Waargonaut.Types.Json: JObj :: JObject ws a -> ws -> JType ws a
- Waargonaut.Types.Json: Json :: (JType WS Json) -> Json
+ Waargonaut.Types.Json: Json :: JType WS Json -> Json
- Waargonaut.Types.Whitespace: WS :: (Vector Whitespace) -> WS
+ Waargonaut.Types.Whitespace: WS :: Vector Whitespace -> WS
Files
- README.md +177/−0
- changelog.md +7/−1
- src/Waargonaut.hs +4/−4
- src/Waargonaut/Decode.hs +12/−9
- src/Waargonaut/Decode/Error.hs +5/−5
- src/Waargonaut/Decode/ZipperMove.hs +3/−3
- src/Waargonaut/Generic.hs +3/−3
- test/Decoder.hs +32/−1
- waargonaut.cabal +3/−2
+ README.md view
@@ -0,0 +1,177 @@+<img src="http://i.imgur.com/0h9dFhl.png" width="300px"/>++[](https://travis-ci.org/qfpl/waargonaut)++# Waargonaut++Flexible, precise, and efficient JSON decoding/encoding library. This package+provides a plethora of tools for decoding, encoding, and manipulating JSON data.++## Features++* Fully RFC compliant, with property based testing used to ensure the desired+ invariants are preserved.++* Encoders and Decoders are values, they are not tied to a typeclass and as such+ you are not tied to a single interpretation of how a particular type+ "_should_" be handled.+ +* No information is discarded on parsing. Trailing whitespace, and any+ formatting whitespace (carriage returns etc) are all preserved. ++* A history keeping zipper is used for Decoding, providing precise control of+ how _you_ decode _your_ JSON data. With informative error messages if things+ don't go according to plan.++* Flexible and expressive Decoder & Encoder functions let you parse and build+ the JSON structures _you_ require, with no surprises.++* BYO parsing library, the parser built into Waargonaut does not tie you to a+ particular parsing library. With the caveat that your parsing library must+ have an instance of `CharParsing` from the [parsers](https://hackage.haskell.org/package/parsers) package.++* Generic functions are provided to make the creation of Encoders and Decoders+ are bit easier. However these _are_ tied to typeclasses, so they do come with+ some assumptions.++* Lenses, Prisms, and Traversals are provided to allow you to investigate and+ manipulate the JSON data structures to your hearts content, without breaking+ the invariants.++* The awesome work on succinct data structures by John Ky and [Haskell Works](https://github.com/haskell-works/) + is used to power the decoder. Providing the same zipper capabilities and+ property based guarantees, but with all the speed and efficiency capabilities+ that succinct data structures have to offer.++## Example++- Data Structure:+```haskell+data Image = Image+ { _imageWidth :: Int+ , _imageHeight :: Int+ , _imageTitle :: Text+ , _imageAnimated :: Bool+ , _imageIDs :: [Int]+ }+```++- Encoder:+```haskell+encodeImage :: Applicative f => Encoder f Image+encodeImage = E.mapLikeObj $ \img ->+ E.intAt "Width" (_imageWidth img)+ . E.intAt "Height" (_imageHeight img)+ . E.textAt "Title" (_imageTitle img)+ . E.boolAt "Animated" (_imageAnimated img)+ . E.listAt E.int "IDs" (_imageIDs img)+```++- Decoder:+```haskell+imageDecoder :: Monad f => D.Decoder f Image+imageDecoder = D.withCursor $ \curs -> do+ -- Move down into the JSON object.+ io <- D.down curs+ -- We need individual values off of our object,+ Image+ <$> D.fromKey "Width" D.int io+ <*> D.fromKey "Height" D.int io+ <*> D.fromKey "Title" D.text io+ <*> D.fromKey "Animated" D.bool io+ <*> D.fromKey "IDs" (D.list D.int) io+```++### Zippers++Waargonaut uses zippers for its decoding which allows for precise control in+how you interrogate your JSON input. Take JSON structures and decode them+precisely as you require:++##### Input:++```JSON+["a","fred",1,2,3,4]+```++##### Data Structure:++```haskell+data Foo = Foo (Char,String,[Int])+```++##### Decoder:++The zipper starts the very root of the JSON input, we tell it to move 'down'+into the first element.+```haskell+fooDecoder :: Monad f => Decoder f Foo+fooDecoder = D.withCursor $ \cursor -> do+ fstElem <- D.down cursor+```+From the first element we can then decode the focus of the zipper using a+specific decoder:+```haskell+ aChar <- D.focus D.unboundedChar fstElem+```+The next thing we want to decode is the second element of the array, so we+move right one step or tooth, and then attempt to decode a string at the+focus.+```haskell+ aString <- D.moveRight1 fstElem >>= D.focus D.string+```+Finally we want to take everything else in the list and combine them into a+single list of Int values. Starting from the first element, we move right+two positions (over the char and the string elements), then we use one of+the provided decoder functions that will repeatedly move in a direction and+combine all of the elements it can until it can no longer move.+```haskell+ aIntList <- D.moveRightN 2 fstElem >>= D.rightwardSnoc [] D.int+```+Lastly, we build the Foo using the decoded values.+```haskell+ pure $ Foo (aChar, aString, aIntList)+```++The zipper stores the history of your movements, so any errors provide+information about the path they took prior to encountering an error. Making+debugging precise and straight-forward.++### Property Driven Development++This library is built to parse and produce JSON in accordance with the [RFC+8259](https://tools.ietf.org/html/rfc8259) standard. The data structures,+parser, and printer are built to satify the [Round Trip Property](https://teh.id.au/posts/2017/06/07/round-trip-property/):++Which may be expressed using the following pseudocode:++```+parse . print = id+```+This indicates that any JSON produced by this library will be parsed back in as+the exact data structure that produced it. This includes whitespace such as+carriage returns and trailing whitespace. There is no loss of information.++There is also this property, again in pseudocode:++```+print . parse . print = print+```+This states that the printed form of the JSON will not change will be identical+after parsing and then re-printing. There is no loss of information.++This provides a solid foundation to build upon.++**NB:** The actual code will of course return values that account for the+possibility of failure. Computers being what they are.++### TODO(s)++In no particular order...++- [ ] improve/bikeshed encoding object api +- [ ] gather feedback on tests/benchmarks that matter+- [ ] provide testing functions so users can be more confident in their Encoder/Decoder construction+- [x] (feedback required) documentation in the various modules to explain any weirdness or things that users may consider to be 'missing' or 'wrong'.+- [x] (mostly) provide greater rationale behind lack of reliance in typeclasses for encoding/decoding+- [ ] provide functions to add preset whitespace layouts to encoded json.
changelog.md view
@@ -1,5 +1,11 @@ # Revision history for waargonaut -## 0.1.0.0 -- YYYY-mm-dd+## 0.2.0.0 -- 2018-11-06++* Provide more precise errors from Decoder for missing or invalid keys+* Removed a parameter from `KeyDecodeFailed` error constructor+* Fix issue where printing the zipper movements had left and right movement arrows swapped.++## 0.1.0.0 -- 2018-11-01 * First version. Released on an unsuspecting world.
src/Waargonaut.hs view
@@ -121,10 +121,10 @@ -- @ -- personDecoder2 :: Monad f => Decoder f Person -- personDecoder2 = Person--- <$> D.atKey "name" D.text--- <*> D.atKey "age" D.int--- <*> D.atKey "address" D.text--- <*> D.atKey "numbers" (D.list D.int)+-- \<$> D.atKey "name" D.text+-- \<*> D.atKey "age" D.int+-- \<*> D.atKey "address" D.text+-- \<*> D.atKey "numbers" (D.list D.int) -- @ -- -- Using the 'Waargonaut.Decode.atKey' function which tries to handle those basic movements for us
src/Waargonaut/Decode.hs view
@@ -86,7 +86,7 @@ Snoc, cons, lens, modifying, preview, snoc, traverseOf,- view, (.~), (^.),+ view, (.~), (^.), (#), _Wrapped) import Prelude (Bool, Bounded, Char,@@ -108,7 +108,7 @@ import Control.Monad.State (MonadState) import Control.Error.Util (note)-import Control.Monad.Error.Hoist ((<?>))+import Control.Monad.Error.Hoist ((<?>),(<!?>)) import Data.Either (Either (..)) import Data.Foldable (foldl)@@ -148,7 +148,7 @@ import qualified HaskellWorks.Data.Json.Cursor as JC -import Waargonaut.Decode.Error (DecodeError (..),+import Waargonaut.Decode.Error (DecodeError (..), AsDecodeError (..), Err (..)) import Waargonaut.Decode.ZipperMove (ZipperMove (..)) @@ -423,13 +423,16 @@ => Text -> JCurs -> DecodeResult f JCurs-moveToKey k c =+moveToKey k c = do -- Tease out the key- focus text c >>= \k' -> if k' == k -- Are we at the key we want to be at ?- -- if we are, then move into the THING at the key- then moveRight1 c- -- if not, then jump to the next key index, the adjacent sibling is opening of the value of the current key- else moveRightN 2 c >>= moveToKey k+ k' <- DI.try (focus text c) <!?> (_KeyDecodeFailed # ())++ -- Are we at the key we want to be at ?+ if k' == k+ -- Then move into the THING at the key+ then moveRight1 c+ -- Try jump to the next key index+ else ( DI.try (moveRightN 2 c) <!?> (_KeyNotFound # k) ) >>= moveToKey k -- | Move to the first occurence of this key, as per 'moveToKey' and then -- attempt to run the given 'Decoder' on that value, returning the result.
src/Waargonaut/Decode/Error.hs view
@@ -29,7 +29,7 @@ -- data DecodeError = ConversionFailure Text- | KeyDecodeFailed Text+ | KeyDecodeFailed | KeyNotFound Text | FailedToMove ZipperMove | NumberOutOfBounds JNumber@@ -41,7 +41,7 @@ class AsDecodeError r where _DecodeError :: Prism' r DecodeError _ConversionFailure :: Prism' r Text- _KeyDecodeFailed :: Prism' r Text+ _KeyDecodeFailed :: Prism' r () _KeyNotFound :: Prism' r Text _FailedToMove :: Prism' r ZipperMove _NumberOutOfBounds :: Prism' r JNumber@@ -67,10 +67,10 @@ ) _KeyDecodeFailed- = L.prism KeyDecodeFailed+ = L.prism (const KeyDecodeFailed) (\x -> case x of- KeyDecodeFailed y -> Right y- _ -> Left x+ KeyDecodeFailed -> Right ()+ _ -> Left x ) _KeyNotFound
src/Waargonaut/Decode/ZipperMove.hs view
@@ -34,10 +34,10 @@ ppZipperMove :: ZipperMove -> Doc a ppZipperMove m = case m of U -> WL.text "up/"- D -> WL.text "into\\"+ D -> WL.text "down\\" - (L n) -> WL.text "->-" <+> ntxt n- (R n) -> WL.text "-<-" <+> ntxt n+ (L n) -> WL.text "-<-" <+> ntxt n+ (R n) -> WL.text "->-" <+> ntxt n (DAt k) -> WL.text "into\\" <+> itxt "key" k (Item t) -> WL.text "-::" <+> itxt "item" t
src/Waargonaut/Generic.hs view
@@ -232,14 +232,14 @@ -- Becomes: -- -- @--- (proxy mkDecoder @GWaarg) :: Monad f => Decoder f Image+-- (proxy mkDecoder \@GWaarg) :: Monad f => Decoder f Image -- @ -- -- You can also use the @TypeApplications@ directly on the 'mkEncoder' or 'mkDecoder' function: -- -- @--- mkEncoder @GWaarg :: Applicative f => Tagged GWaarg (Encoder f Image)--- mkDecoder @GWaarg :: Monad f => Tagged GWaarg (Decoder f Image)+-- mkEncoder \@GWaarg :: Applicative f => Tagged GWaarg (Encoder f Image)+-- mkDecoder \@GWaarg :: Monad f => Tagged GWaarg (Decoder f Image) -- @ --
test/Decoder.hs view
@@ -4,7 +4,7 @@ ( decoderTests ) where -import Prelude (Char, Int, String, print)+import Prelude (Char, Int, String, print, (==)) import Control.Applicative (liftA3, (<$>)) import Control.Category ((.))@@ -24,6 +24,7 @@ import Waargonaut.Decode.Internal (ppCursorHistory) import qualified Waargonaut.Decode as D+import qualified Waargonaut.Decode.Error as D import Types.Common (imageDecodeSuccinct, parseBS, testImageDataType)@@ -33,7 +34,37 @@ [ testCase "Decode Image (test1.json)" decodeTest1Json , testCase "Decode [Int]" decodeTest2Json , testCase "Decode (Char,String,[Int])" decodeTest3Json+ , testCase "Decode Fail with Bad Key" decodeTestBadObjKey+ , testCase "Decode Fail with Missing Key" decodeTestMissingObjKey ]++decodeTestMissingObjKey :: Assertion+decodeTestMissingObjKey = do+ let+ j = "{\"foo\":33}"++ d = D.withCursor $ D.down >=> D.fromKey "bar" D.int++ r <- D.runDecode d parseBS (D.mkCursor j)++ Either.either+ (\(e, _) -> assertBool "Incorrect Error - Expected KeyDecodeFailed" (e == D.KeyNotFound "bar") )+ (\_ -> assertFailure "Expected Error!")+ r++decodeTestBadObjKey :: Assertion+decodeTestBadObjKey = do+ let+ j = "{33:33}"++ d = D.withCursor $ D.down >=> D.fromKey "foo" D.int++ r <- D.runDecode d parseBS (D.mkCursor j)++ Either.either+ (\(e, _) -> assertBool "Incorrect Error - Expected KeyDecodeFailed" (e == D.KeyDecodeFailed) )+ (\_ -> assertFailure "Expected Error!")+ r decodeTest1Json :: Assertion decodeTest1Json = D.runPureDecode imageDecodeSuccinct parseBS . D.mkCursor
waargonaut.cabal view
@@ -10,7 +10,7 @@ -- PVP summary: +-+------- breaking API changes -- | | +----- non-breaking API additions -- | | | +--- code changes with no API change-version: 0.1.0.0+version: 0.2.0.0 -- A short (one-line) description of the package. synopsis: JSON wrangling@@ -32,7 +32,7 @@ maintainer: oᴉ˙ldɟb@uɐǝs -- A copyright notice.-copyright: Copyright (C) 2017 Commonwealth Scientific and Industrial Research Organisation (CSIRO)+copyright: Copyright (C) 2018 Commonwealth Scientific and Industrial Research Organisation (CSIRO) category: Parser, Web, JSON @@ -41,6 +41,7 @@ -- Extra files to be distributed with the package, such as examples or a -- README. extra-source-files: changelog.md+ , README.md , test/json-data/numbers.json , test/json-data/test1.json , test/json-data/test2.json