@@ -46,6 +46,11 @@ data TestJSON = TestJSON
47deriveJSON defaultOptions ''TestJSON
47deriveJSON defaultOptions ''TestJSON
49+shouldDecode :: (Show a, D.FromJSON a, Eq a) => B8.ByteString -> a -> IO ()
50+shouldDecode bs expected = do
51+ actual <- D.decodeThrow bs
52+ actual `shouldBe` expected
49main :: IO ()
54main :: IO ()
50main = hspec spec
55main = hspec spec
@@ -120,13 +125,13 @@ spec = do
120 describe "special keys" $ do
125 describe "special keys" $ do
121 let tester key = it (T.unpack key) $
126 let tester key = it (T.unpack key) $
122 let value = object [key .= True]
127 let value = object [key .= True]
123− in D.decode (D.encode value) `shouldBe` Just value
128+ in D.encode value `shouldDecode` value
124 mapM_ tester specialStrings
129 mapM_ tester specialStrings
126 describe "special values" $ do
131 describe "special values" $ do
127 let tester value = it (T.unpack value) $
132 let tester value = it (T.unpack value) $
128 let value' = object ["foo" .= value]
133 let value' = object ["foo" .= value]
129− in D.decode (D.encode value') `shouldBe` Just value'
134+ in D.encode value' `shouldDecode` value'
130 mapM_ tester specialStrings
135 mapM_ tester specialStrings
132 describe "decodeFileEither" $ do
137 describe "decodeFileEither" $ do
@@ -149,13 +154,13 @@ spec = do
149 let special = words "y Y On ON false 12345 12345.0 12345a 12e3"
154 let special = words "y Y On ON false 12345 12345.0 12345a 12e3"
150 forM_ special $ \w -> it w $
155 forM_ special $ \w -> it w $
151 let v = object ["word" .= w]
156 let v = object ["word" .= w]
152− in D.decode (D.encode v) `shouldBe` Just v
157+ in D.encode v `shouldDecode` v
153 it "no tags" $ D.encode (object ["word" .= ("true" :: String)]) `shouldBe` "word: 'true'\n"
158 it "no tags" $ D.encode (object ["word" .= ("true" :: String)]) `shouldBe` "word: 'true'\n"
155 it "aliases in keys #49" caseIssue49
160 it "aliases in keys #49" caseIssue49
157 it "serialization of +123 #64" $ do
162 it "serialization of +123 #64" $ do
158− D.decode (D.encode ("+123" :: String)) `shouldBe` Just ("+123" :: String)
163+ D.encode ("+123" :: String) `shouldDecode` ("+123" :: String)
160 it "preserves Scientific precision" casePreservesScientificPrecision
165 it "preserves Scientific precision" casePreservesScientificPrecision
@@ -299,9 +304,6 @@ mappingKey :: D.Value-> String -> D.Value
299mappingKey (D.Object m) k = (fromJust . M.lookup (T.pack k) $ m)
304mappingKey (D.Object m) k = (fromJust . M.lookup (T.pack k) $ m)
300mappingKey _ _ = error "expected Object"
305mappingKey _ _ = error "expected Object"
302−decodeYaml :: String -> Maybe D.Value
303−decodeYaml s = D.decode $ B8.pack s
305sample :: D.Value
307sample :: D.Value
306sample = array
308sample = array
307 [ D.String "foo"
309 [ D.String "foo"
@@ -313,20 +315,17 @@ sample = array
315caseEncodeDecodeData :: Assertion
317caseEncodeDecodeData :: Assertion
316−caseEncodeDecodeData = do
318+caseEncodeDecodeData = D.encode sample `shouldDecode` sample
317− let out = D.decode $ D.encode sample
320caseEncodeDecodeDataPretty :: Assertion
320caseEncodeDecodeDataPretty :: Assertion
321−caseEncodeDecodeDataPretty = do
321+caseEncodeDecodeDataPretty =
322− let out = D.decode $ Pretty.encodePretty Pretty.defConfig sample
322+ Pretty.encodePretty Pretty.defConfig sample `shouldDecode` sample
325caseEncodeDecodeFileData :: Assertion
324caseEncodeDecodeFileData :: Assertion
326caseEncodeDecodeFileData = withFile "" $ \fp -> do
325caseEncodeDecodeFileData = withFile "" $ \fp -> do
327 D.encodeFile fp sample
326 D.encodeFile fp sample
328− out <- D.decodeFile fp
327+ out <- D.decodeFileThrow fp
329− out @?= Just sample
328+ out @?= sample
331caseEncodeDecodeNonAsciiFileData :: Assertion
330caseEncodeDecodeNonAsciiFileData :: Assertion
332caseEncodeDecodeNonAsciiFileData = do
331caseEncodeDecodeNonAsciiFileData = do
@@ -334,89 +333,74 @@ caseEncodeDecodeNonAsciiFileData = do
334 inTempDirectory $ do
333 inTempDirectory $ do
335 createDirectory "accenté"
334 createDirectory "accenté"
336 D.encodeFile "accenté/bar.yaml" mySample
335 D.encodeFile "accenté/bar.yaml" mySample
337− out1 <- D.decodeFile "accenté/bar.yaml"
336+ out1 <- D.decodeFileThrow "accenté/bar.yaml"
338− out1 @?= Just mySample
337+ out1 @?= mySample
340 c <- readFile "test/resources/accent/foo.yaml"
339 c <- readFile "test/resources/accent/foo.yaml"
341 inTempDirectory $ do
340 inTempDirectory $ do
342 createDirectoryIfMissing True "test/resources/unicode/accenté/"
341 createDirectoryIfMissing True "test/resources/unicode/accenté/"
343 writeFile "test/resources/unicode/accenté/foo.yaml" c
342 writeFile "test/resources/unicode/accenté/foo.yaml" c
344− out2 <- D.decodeFile "test/resources/unicode/accenté/foo.yaml"
343+ out2 <- D.decodeFileThrow "test/resources/unicode/accenté/foo.yaml"
345− out2 @?= Just mySample
344+ out2 @?= mySample
347caseEncodeDecodeStrings :: Assertion
346caseEncodeDecodeStrings :: Assertion
348−caseEncodeDecodeStrings = do
347+caseEncodeDecodeStrings = D.encode sample `shouldDecode` sample
349− let out = D.decode $ D.encode sample
352caseEncodeDecodeStringsPretty :: Assertion
349caseEncodeDecodeStringsPretty :: Assertion
353−caseEncodeDecodeStringsPretty = do
350+caseEncodeDecodeStringsPretty =
354− let out = D.decode $ Pretty.encodePretty Pretty.defConfig sample
351+ Pretty.encodePretty Pretty.defConfig sample `shouldDecode` sample
357caseDecodeInvalid :: Assertion
353caseDecodeInvalid :: Assertion
358−caseDecodeInvalid = do
354+caseDecodeInvalid =
359− let invalid = B8.pack "\tthis is 'not' valid :-)"
355+ D.decodeThrow "\tthis is 'not' valid :-)" `shouldBe`
360− Nothing @=? (D.decode invalid :: Maybe D.Value)
356+ (Nothing :: Maybe D.Value)
362caseSimpleScalarAlias :: Assertion
358caseSimpleScalarAlias :: Assertion
363−caseSimpleScalarAlias = do
359+caseSimpleScalarAlias =
364− let maybeRes = decodeYaml "- &anch foo\n- baz\n- *anch"
360+ "- &anch foo\n- baz\n- *anch" `shouldDecode`
365− isJust maybeRes @? "decoder should return Just YamlObject but returned Nothing"
366− let res = fromJust maybeRes
367− res @?= array [(mkScalar "foo"), (mkScalar "baz"), (mkScalar "foo")]
361+ array [(mkScalar "foo"), (mkScalar "baz"), (mkScalar "foo")]
369caseSimpleSequenceAlias :: Assertion
363caseSimpleSequenceAlias :: Assertion
370−caseSimpleSequenceAlias = do
364+caseSimpleSequenceAlias =
371− let maybeRes = decodeYaml "seq: &anch\n - foo\n - baz\nseq2: *anch"
365+ "seq: &anch\n - foo\n - baz\nseq2: *anch" `shouldDecode`
372− isJust maybeRes @? "decoder should return Just YamlObject but returned Nothing"
373− let res = fromJust maybeRes
374− res @?= object [("seq", array [(mkScalar "foo"), (mkScalar "baz")]), ("seq2", array [(mkScalar "foo"), (mkScalar "baz")])]
366+ object [("seq", array [(mkScalar "foo"), (mkScalar "baz")]), ("seq2", array [(mkScalar "foo"), (mkScalar "baz")])]
376caseSimpleMappingAlias :: Assertion
368caseSimpleMappingAlias :: Assertion
377−caseSimpleMappingAlias = do
369+caseSimpleMappingAlias =
378− let maybeRes = decodeYaml "map: &anch\n key1: foo\n key2: baz\nmap2: *anch"
370+ "map: &anch\n key1: foo\n key2: baz\nmap2: *anch" `shouldDecode`
379− isJust maybeRes @? "decoder should return Just YamlObject but returned Nothing"
380− let res = fromJust maybeRes
381− res @?= object [(T.pack "map", object [("key1", mkScalar "foo"), ("key2", (mkScalar "baz"))]), (T.pack "map2", object [("key1", (mkScalar "foo")), ("key2", mkScalar "baz")])]
371+ object [(T.pack "map", object [("key1", mkScalar "foo"), ("key2", (mkScalar "baz"))]), (T.pack "map2", object [("key1", (mkScalar "foo")), ("key2", mkScalar "baz")])]
383caseMappingAliasBeforeAnchor :: Assertion
373caseMappingAliasBeforeAnchor :: Assertion
384−caseMappingAliasBeforeAnchor = do
374+caseMappingAliasBeforeAnchor =
385− let res = decodeYaml "map: *anch\nmap2: &anch\n key1: foo\n key2: baz"
375+ case D.decodeThrow "map: *anch\nmap2: &anch\n key1: foo\n key2: baz" of
386− isNothing res @? "decode should return Nothing due to unknown alias"
377+ Just (_ :: D.Value) -> error "decode should return Nothing due to unknown alias"
388caseMappingAliasInsideAnchor :: Assertion
379caseMappingAliasInsideAnchor :: Assertion
389caseMappingAliasInsideAnchor = do
380caseMappingAliasInsideAnchor = do
390− let res = decodeYaml "map: &anch\n key1: foo\n key2: *anch"
381+ case D.decodeThrow "map: &anch\n key1: foo\n key2: *anch" of
391− isNothing res @? "decode should return Nothing due to unknown alias"
383+ Just (_ :: D.Value) -> error "decode should return Nothing due to unknown alias"
393caseScalarAliasOverriding :: Assertion
385caseScalarAliasOverriding :: Assertion
394−caseScalarAliasOverriding = do
386+caseScalarAliasOverriding =
395− let maybeRes = decodeYaml "- &anch foo\n- baz\n- *anch\n- &anch boo\n- buz\n- *anch"
387+ "- &anch foo\n- baz\n- *anch\n- &anch boo\n- buz\n- *anch" `shouldDecode`
396− isJust maybeRes @? "decoder should return Just YamlObject but returned Nothing"
397− let res = fromJust maybeRes
398− res @?= array [(mkScalar "foo"), (mkScalar "baz"), (mkScalar "foo"), (mkScalar "boo"), (mkScalar "buz"), (mkScalar "boo")]
388+ array [(mkScalar "foo"), (mkScalar "baz"), (mkScalar "foo"), (mkScalar "boo"), (mkScalar "buz"), (mkScalar "boo")]
400caseAllKeysShouldBeUnique :: Assertion
390caseAllKeysShouldBeUnique :: Assertion
401caseAllKeysShouldBeUnique = do
391caseAllKeysShouldBeUnique = do
402− let maybeRes = decodeYaml "foo1: foo\nfoo2: baz\nfoo1: buz"
392+ res <- D.decodeThrow "foo1: foo\nfoo2: baz\nfoo1: buz"
403− isJust maybeRes @? "decoder should return Just YamlObject but returned Nothing"
404− let res = fromJust maybeRes
405− mappingKey res "foo1" @?= (mkScalar "buz")
393+ mappingKey res "foo1" `shouldBe` mkScalar "buz"
407caseSimpleMappingMerge :: Assertion
395caseSimpleMappingMerge :: Assertion
408caseSimpleMappingMerge = do
396caseSimpleMappingMerge = do
409− let maybeRes = decodeYaml "foo1: foo\nfoo2: baz\n<<:\n foo1: buz\n foo3: fuz"
397+ res <- D.decodeThrow "foo1: foo\nfoo2: baz\n<<:\n foo1: buz\n foo3: fuz"
410− isJust maybeRes @? "decoder should return Just YamlObject but returned Nothing"
411− let res = fromJust maybeRes
412− mappingKey res "foo1" @?= (mkScalar "foo")
398+ mappingKey res "foo1" `shouldBe` mkScalar "foo"
413− mappingKey res "foo3" @?= (mkScalar "fuz")
399+ mappingKey res "foo3" `shouldBe` mkScalar "fuz"
415caseMergeSequence :: Assertion
401caseMergeSequence :: Assertion
416caseMergeSequence = do
402caseMergeSequence = do
417− let maybeRes = decodeYaml "m1: &m1\n k1: !!str 1\n k2: !!str 2\nm2: &m2\n k1: !!str 3\n k3: !!str 4\nfoo1: foo\n<<: [ *m1, *m2 ]"
403+ res <- D.decodeThrow "m1: &m1\n k1: !!str 1\n k2: !!str 2\nm2: &m2\n k1: !!str 3\n k3: !!str 4\nfoo1: foo\n<<: [ *m1, *m2 ]"
418− isJust maybeRes @? "decoder should return Just YamlObject but returned Nothing"
419− let res = fromJust maybeRes
420 mappingKey res "foo1" @?= (mkScalar "foo")
404 mappingKey res "foo1" @?= (mkScalar "foo")
421 mappingKey res "k1" @?= (D.String "1")
405 mappingKey res "k1" @?= (D.String "1")
422 mappingKey res "k2" @?= (D.String "2")
406 mappingKey res "k2" @?= (D.String "2")
@@ -424,7 +408,7 @@ caseMergeSequence = do
425caseDataTypes :: Assertion
409caseDataTypes :: Assertion
426caseDataTypes =
410caseDataTypes =
427− D.decode (D.encode val) @?= Just val
411+ D.encode val `shouldDecode` val
429 val = object
413 val = object
430 [ ("string", D.String "foo")
414 [ ("string", D.String "foo")
@@ -437,11 +421,11 @@ caseDataTypes =
438caseEncodeInvalidNumbers :: Assertion
422caseEncodeInvalidNumbers :: Assertion
439caseEncodeInvalidNumbers =
423caseEncodeInvalidNumbers =
440− D.encode (D.String ".") @?= ".\n"
424+ D.encode (D.String ".") `shouldBe` ".\n"
442caseDataTypesPretty :: Assertion
426caseDataTypesPretty :: Assertion
443caseDataTypesPretty =
427caseDataTypesPretty =
444− D.decode (Pretty.encodePretty Pretty.defConfig val) @?= Just val
428+ Pretty.encodePretty Pretty.defConfig val `shouldDecode` val
446 val = object
430 val = object
447 [ ("string", D.String "foo")
431 [ ("string", D.String "foo")
@@ -452,21 +436,21 @@ caseDataTypesPretty =
452 , ("null", D.Null)
436 , ("null", D.Null)
454caseQuotedNumber, caseUnquotedNumber, caseAttribNumber, caseIntegerDecimals :: Assertion
438caseQuotedNumber, caseUnquotedNumber, caseAttribNumber, caseIntegerDecimals :: Assertion
455−caseQuotedNumber = D.decode "foo: \"1234\"" @?= Just (object [("foo", D.String "1234")])
439+caseQuotedNumber = "foo: \"1234\"" `shouldDecode` object [("foo", D.String "1234")]
456−caseUnquotedNumber = D.decode "foo: 1234" @?= Just (object [("foo", D.Number 1234)])
440+caseUnquotedNumber = "foo: 1234" `shouldDecode` object [("foo", D.Number 1234)]
457−caseAttribNumber = D.decode "foo: !!str 1234" @?= Just (object [("foo", D.String "1234")])
441+caseAttribNumber = "foo: !!str 1234" `shouldDecode` object [("foo", D.String "1234")]
458−caseIntegerDecimals = D.encode (1 :: Int) @?= "1\n"
442+caseIntegerDecimals = "1\n" `shouldDecode` (1 :: Int)
460−obj :: Maybe D.Value
444+obj :: D.Value
461−obj = Just (object [("foo", D.Bool False), ("bar", D.Bool True), ("baz", D.Bool True)])
445+obj = object [("foo", D.Bool False), ("bar", D.Bool True), ("baz", D.Bool True)]
463caseLowercaseBool, caseUppercaseBool, caseTitlecaseBool :: Assertion
447caseLowercaseBool, caseUppercaseBool, caseTitlecaseBool :: Assertion
464−caseLowercaseBool = D.decode "foo: off\nbar: y\nbaz: true" @?= obj
448+caseLowercaseBool = "foo: off\nbar: y\nbaz: true" `shouldDecode` obj
465−caseUppercaseBool = D.decode "foo: FALSE\nbar: Y\nbaz: ON" @?= obj
449+caseUppercaseBool = "foo: FALSE\nbar: Y\nbaz: ON" `shouldDecode` obj
466−caseTitlecaseBool = D.decode "foo: No\nbar: Yes\nbaz: True" @?= obj
450+caseTitlecaseBool = "foo: No\nbar: Yes\nbaz: True" `shouldDecode` obj
468caseEmptyInput :: Assertion
452caseEmptyInput :: Assertion
469−caseEmptyInput = D.decodeEither B8.empty @?= Right D.Null
453+caseEmptyInput = B8.empty `shouldDecode` D.Null
471caseEmptyInputFile :: Assertion
455caseEmptyInputFile :: Assertion
472caseEmptyInputFile = do
456caseEmptyInputFile = do
@@ -474,7 +458,7 @@ caseEmptyInputFile = do
474 either (Left . D.prettyPrintParseException) Right out @?= Right D.Null
458 either (Left . D.prettyPrintParseException) Right out @?= Right D.Null
476caseCommentOnlyInput :: Assertion
460caseCommentOnlyInput :: Assertion
477−caseCommentOnlyInput = D.decodeEither "# comment\n" @?= Right D.Null
461+caseCommentOnlyInput = "# comment\n" `shouldDecode` D.Null
479caseCommentOnlyInputFile :: Assertion
463caseCommentOnlyInputFile :: Assertion
480caseCommentOnlyInputFile = do
464caseCommentOnlyInputFile = do
@@ -483,13 +467,12 @@ caseCommentOnlyInputFile = do
484checkNull :: T.Text -> Spec
468checkNull :: T.Text -> Spec
485checkNull x =
469checkNull x =
486− it ("null recognized: " ++ show x) assertion
470+ it ("null recognized: " ++ show x) $
487− where
471+ B8.pack ("foo: " ++ T.unpack x) `shouldDecode` object [("foo", D.Null)]
488− assertion = Just (object [("foo", D.Null)]) @=? D.decode (B8.pack $ "foo: " ++ T.unpack x)
490caseStripAlias :: Assertion
473caseStripAlias :: Assertion
491caseStripAlias =
474caseStripAlias =
492− D.decode src @?= Just (object
475+ src `shouldDecode` object
493 [ "Default" .= object
476 [ "Default" .= object
494 [ "foo" .= (1 :: Int)
477 [ "foo" .= (1 :: Int)
495 , "bar" .= (2 :: Int)
478 , "bar" .= (2 :: Int)
@@ -499,24 +482,24 @@ caseStripAlias =
499 , "bar" .= (2 :: Int)
482 , "bar" .= (2 :: Int)
500 , "key" .= (3 :: Int)
483 , "key" .= (3 :: Int)
504 src = "Default: &def\n foo: 1\n bar: 2\nObj:\n <<: *def\n key: 3\n"
487 src = "Default: &def\n foo: 1\n bar: 2\nObj:\n <<: *def\n key: 3\n"
506caseIssue49 :: Assertion
489caseIssue49 :: Assertion
507caseIssue49 =
490caseIssue49 =
508− D.decodeEither src @?= Right (object
491+ src `shouldDecode` object
509 [ "a" .= object [ "value" .= (1.0 :: Double) ]
492 [ "a" .= object [ "value" .= (1.0 :: Double) ]
510 , "b" .= object [ "value" .= (1.2 :: Double) ]
493 , "b" .= object [ "value" .= (1.2 :: Double) ]
513 src = "---\na:\n &id5 value: 1.0\nb:\n *id5: 1.2"
496 src = "---\na:\n &id5 value: 1.0\nb:\n *id5: 1.2"
515-- | We cannot guarantee this before aeson started using 'Scientific'.
498-- | We cannot guarantee this before aeson started using 'Scientific'.
516casePreservesScientificPrecision :: Assertion
499casePreservesScientificPrecision :: Assertion
517casePreservesScientificPrecision = do
500casePreservesScientificPrecision = do
518− D.decodeEither "x: 1e-100000" @?= Right (object
501+ "x: 1e-100000" `shouldDecode` object
519− [ "x" .= D.Number (read "1e-100000") ])
502+ [ "x" .= D.Number (read "1e-100000") ]
520 -- Note that this ought to work also without 'Scientific', given
503 -- Note that this ought to work also without 'Scientific', given
521 -- that @read (show "9.78159610558926e-5") == 9.78159610558926e-5@.
504 -- that @read (show "9.78159610558926e-5") == 9.78159610558926e-5@.
522 -- However, it didn't work (and still doesn't work with aeson < 0.7)
505 -- However, it didn't work (and still doesn't work with aeson < 0.7)
@@ -526,8 +509,8 @@ casePreservesScientificPrecision = do
526 -- can be;
509 -- can be;
527 -- * Even if we used 'Data.Text.Read.rational' we would not get good
510 -- * Even if we used 'Data.Text.Read.rational' we would not get good
528 -- results, because of <https://github.com/bos/text/issues/34>.
511 -- results, because of <https://github.com/bos/text/issues/34>.
529− D.decodeEither "x: 9.78159610558926e-5" @?= Right (object
512+ "x: 9.78159610558926e-5" `shouldDecode` object
530− [ "x" .= D.Number (read "9.78159610558926e-5") ])
513+ [ "x" .= D.Number (read "9.78159610558926e-5") ]
532caseTruncatesFiles :: Assertion
515caseTruncatesFiles :: Assertion
533caseTruncatesFiles = withSystemTempFile "truncate.yaml" $ \fp h -> do
516caseTruncatesFiles = withSystemTempFile "truncate.yaml" $ \fp h -> do