@@ -2,7 +2,7 @@
22{-# LANGUAGE PackageImports #-}
33{-# LANGUAGE ScopedTypeVariables #-}
44
5−import Text.Libyaml
5+import qualified Text.Libyaml as Y
66import qualified Data.ByteString.Char8 as B8
77
88import Test.HUnit hiding (Test, path)
@@ -16,6 +16,11 @@ import Control.Exception (try, SomeException)
1616import Test.Hspec.Monadic
1717import Test.Hspec.HUnit ()
1818
19+import Data.Object
20+import qualified Data.Yaml as D
21+import Data.Maybe
22+import Data.Convertible.Text (cs)
23+
1924main :: IO ()
2025main = hspecX $ do
2126 describe "streaming" $ do
@@ -29,17 +34,34 @@ main = hspecX $ do
2934 it "encode/decode file" caseEncodeDecodeFile
3035 it "interleaved encode/decode" caseInterleave
3136 it "decode invalid document (without segfault)" caseDecodeInvalidDocument
37+ describe "Data.Yaml" $ do
38+ it "encode/decode" caseEncodeDecodeData
39+ it "encode/decode file" caseEncodeDecodeFileData
40+ it "encode/decode strings" caseEncodeDecodeStrings
41+ it "decode invalid file" caseDecodeInvalid
42+ it "encode/decode in order" caseInOrder
43+ describe "Data.Yaml aliases" $ do
44+ it "simple scalar alias" caseSimpleScalarAlias
45+ it "simple sequence alias" caseSimpleSequenceAlias
46+ it "simple mapping alias" caseSimpleMappingAlias
47+ it "mapping alias before anchor" caseMappingAliasBeforeAnchor
48+ it "mapping alias inside anchor" caseMappingAliasInsideAnchor
49+ it "scalar alias overriding" caseScalarAliasOverriding
50+ describe "Data.Yaml merge keys" $ do
51+ it "test uniqueness of keys" caseAllKeysShouldBeUnique
52+ it "test mapping merge" caseSimpleMappingMerge
53+ it "test sequence of mappings merging" caseMergeSequence
3254
33−counter :: (Event -> Bool) -> C.Sink Event IO Int
55+counter :: (Y.Event -> Bool) -> C.Sink Y.Event IO Int
3456counter pred' =
3557 CL.fold (\cnt e -> (if pred' e then 1 else 0) + cnt) 0
3658
3759caseHelper :: String
38− -> (Event -> Bool)
60+ -> (Y.Event -> Bool)
3961 -> Int
4062 -> Assertion
4163caseHelper yamlString pred' expRes = do
42− res <- C.runResourceT $ decode (B8.pack yamlString) C.$$ counter pred'
64+ res <- C.runResourceT $ Y.decode (B8.pack yamlString) C.$$ counter pred'
4365 res @?= expRes
4466
4567caseCountScalarsWithAnchor :: Assertion
@@ -47,7 +69,7 @@ caseCountScalarsWithAnchor =
4769 caseHelper yamlString isScalarA 1
4870 where
4971 yamlString = "foo:\n - &anchor bin1\n - bin2\n - bin3"
50− isScalarA (EventScalar _ _ _ (Just _)) = True
72+ isScalarA (Y.EventScalar _ _ _ (Just _)) = True
5173 isScalarA _ = False
5274
5375caseCountSequencesWithAnchor :: Assertion
@@ -55,7 +77,7 @@ caseCountSequencesWithAnchor =
5577 caseHelper yamlString isSequenceStartA 1
5678 where
5779 yamlString = "foo: &anchor\n - bin1\n - bin2\n - bin3"
58− isSequenceStartA (EventSequenceStart (Just _)) = True
80+ isSequenceStartA (Y.EventSequenceStart (Just _)) = True
5981 isSequenceStartA _ = False
6082
6183caseCountMappingsWithAnchor :: Assertion
@@ -63,7 +85,7 @@ caseCountMappingsWithAnchor =
6385 caseHelper yamlString isMappingA 1
6486 where
6587 yamlString = "foo: &anchor\n key1: bin1\n key2: bin2\n key3: bin3"
66− isMappingA (EventMappingStart (Just _)) = True
88+ isMappingA (Y.EventMappingStart (Just _)) = True
6789 isMappingA _ = False
6890
6991caseCountAliases :: Assertion
@@ -71,47 +93,47 @@ caseCountAliases =
7193 caseHelper yamlString isAlias 1
7294 where
7395 yamlString = "foo: &anchor\n key1: bin1\n key2: bin2\n key3: bin3\nboo: *anchor"
74− isAlias EventAlias{} = True
96+ isAlias Y.EventAlias{} = True
7597 isAlias _ = False
7698
7799caseCountScalars :: Assertion
78100caseCountScalars = do
79− res <- C.runResourceT $ decode yamlBS C.$$ CL.fold adder accum
101+ res <- C.runResourceT $ Y.decode yamlBS C.$$ CL.fold adder accum
80102 res @?= (7, 1, 2)
81103 where
82104 yamlString = "foo:\n baz: [bin1, bin2, bin3]\nbaz: bazval"
83105 yamlBS = B8.pack yamlString
84− adder (s, l, m) (EventScalar{}) = (s + 1, l, m)
85− adder (s, l, m) (EventSequenceStart{}) = (s, l + 1, m)
86− adder (s, l, m) (EventMappingStart{}) = (s, l, m + 1)
106+ adder (s, l, m) (Y.EventScalar{}) = (s + 1, l, m)
107+ adder (s, l, m) (Y.EventSequenceStart{}) = (s, l + 1, m)
108+ adder (s, l, m) (Y.EventMappingStart{}) = (s, l, m + 1)
87109 adder a _ = a
88110 accum = (0, 0, 0) :: (Int, Int, Int)
89111
90112caseLargestString :: Assertion
91113caseLargestString = do
92− res <- C.runResourceT $ decodeFile filePath C.$$ CL.fold adder accum
114+ res <- C.runResourceT $ Y.decodeFile filePath C.$$ CL.fold adder accum
93115 res @?= (length expected, expected)
94116 where
95117 expected = "this one is just a little bit bigger than the others"
96118 filePath = "test/largest-string.yaml"
97− adder (i, s) (EventScalar bs _ _ _) =
119+ adder (i, s) (Y.EventScalar bs _ _ _) =
98120 let s' = B8.unpack bs
99121 i' = length s'
100122 in if i' > i then (i', s') else (i, s)
101123 adder acc _ = acc
102124 accum = (0, "no strings found")
103125
104−newtype MyEvent = MyEvent Event deriving Show
126+newtype MyEvent = MyEvent Y.Event deriving Show
105127instance Eq MyEvent where
106− (MyEvent (EventScalar s t _ _)) == (MyEvent (EventScalar s' t' _ _)) =
128+ (MyEvent (Y.EventScalar s t _ _)) == (MyEvent (Y.EventScalar s' t' _ _)) =
107129 s == s' && t == t'
108130 MyEvent e1 == MyEvent e2 = e1 == e2
109131
110132caseEncodeDecode :: Assertion
111133caseEncodeDecode = do
112− eList <- C.runResourceT $ decode yamlBS C.$$ CL.consume
113− bs <- C.runResourceT $ CL.sourceList eList C.$$ encode
114− eList2 <- C.runResourceT $ decode bs C.$$ CL.consume
134+ eList <- C.runResourceT $ Y.decode yamlBS C.$$ CL.consume
135+ bs <- C.runResourceT $ CL.sourceList eList C.$$ Y.encode
136+ eList2 <- C.runResourceT $ Y.decode bs C.$$ CL.consume
115137 map MyEvent eList @=? map MyEvent eList2
116138 where
117139 yamlString = "foo: bar\nbaz:\n - bin1\n - bin2\n"
@@ -125,9 +147,9 @@ removeFile' fp = do
125147caseEncodeDecodeFile :: Assertion
126148caseEncodeDecodeFile = do
127149 removeFile' tmpPath
128− eList <- C.runResourceT $ decodeFile filePath C.$$ CL.consume
129− C.runResourceT $ CL.sourceList eList C.$$ encodeFile tmpPath
130− eList2 <- C.runResourceT $ decodeFile filePath C.$$ CL.consume
150+ eList <- C.runResourceT $ Y.decodeFile filePath C.$$ CL.consume
151+ C.runResourceT $ CL.sourceList eList C.$$ Y.encodeFile tmpPath
152+ eList2 <- C.runResourceT $ Y.decodeFile filePath C.$$ CL.consume
131153 map MyEvent eList @=? map MyEvent eList2
132154 where
133155 filePath = "test/largest-string.yaml"
@@ -137,8 +159,8 @@ caseInterleave :: Assertion
137159caseInterleave = do
138160 removeFile' tmpPath
139161 removeFile' tmpPath2
140− () <- C.runResourceT $ decodeFile filePath C.$$ encodeFile tmpPath
141− () <- C.runResourceT $ decodeFile tmpPath C.$$ encodeFile tmpPath2
162+ () <- C.runResourceT $ Y.decodeFile filePath C.$$ Y.encodeFile tmpPath
163+ () <- C.runResourceT $ Y.decodeFile tmpPath C.$$ Y.encodeFile tmpPath2
142164 f1 <- readFile tmpPath
143165 f2 <- readFile tmpPath2
144166 f1 @=? f2
@@ -149,7 +171,7 @@ caseInterleave = do
149171
150172caseDecodeInvalidDocument :: Assertion
151173caseDecodeInvalidDocument = do
152− x <- try $ C.runResourceT $ decode yamlBS C.$$ CL.sinkNull
174+ x <- try $ C.runResourceT $ Y.decode yamlBS C.$$ CL.sinkNull
153175 case x of
154176 Left (_ :: SomeException) -> return ()
155177 Right y -> do
@@ -158,3 +180,130 @@ caseDecodeInvalidDocument = do
158180 where
159181 yamlString = " - foo\n - baz\nbuz"
160182 yamlBS = B8.pack yamlString
183+
184+mkFoldedScalar :: String -> D.YamlScalar
185+mkFoldedScalar s = D.YamlScalar (cs s) Y.StrTag Y.Folded
186+
187+mkScalar :: String -> D.YamlScalar
188+mkScalar s = D.YamlScalar (cs s) Y.NoTag Y.Plain
189+
190+mkStrScalar :: String -> D.YamlScalar
191+mkStrScalar s = D.YamlScalar (cs s) Y.StrTag Y.Plain
192+
193+mappingKey :: D.YamlObject -> String -> D.YamlObject
194+mappingKey (Mapping m) k = (fromJust . lookup (mkScalar k) $ m)
195+mappingKey _ _ = error "expected Mapping"
196+
197+decodeYaml :: String -> Maybe D.YamlObject
198+decodeYaml s = D.decode $ B8.pack s
199+
200+sample :: D.YamlObject
201+sample = Sequence
202+ [ Scalar $ mkFoldedScalar "foo"
203+ , Mapping
204+ [ (mkFoldedScalar "bar1", Scalar $ mkFoldedScalar "bar2")
205+ ]
206+ ]
207+
208+sampleStr :: Object String String
209+sampleStr = mapKeysValues D.fromYamlScalar D.fromYamlScalar sample
210+
211+caseEncodeDecodeData :: Assertion
212+caseEncodeDecodeData = do
213+ out <- D.decode $ D.encode sample
214+ out @?= sample
215+
216+caseEncodeDecodeFileData :: Assertion
217+caseEncodeDecodeFileData = do
218+ let fp = "tmp.yaml"
219+ D.encodeFile fp sample
220+ out <- join $ D.decodeFile fp
221+ out @?= sample
222+
223+caseEncodeDecodeStrings :: Assertion
224+caseEncodeDecodeStrings = do
225+ out <- D.decode $ D.encode $ D.toYamlObject sampleStr
226+ D.fromYamlObject out @?= sampleStr
227+
228+caseDecodeInvalid :: Assertion
229+caseDecodeInvalid = do
230+ let invalid = B8.pack "\tthis is 'not' valid :-)"
231+ Nothing @=? (D.decode invalid :: Maybe D.YamlObject)
232+
233+caseSimpleScalarAlias :: Assertion
234+caseSimpleScalarAlias = do
235+ let maybeRes = decodeYaml "- &anch foo\n- baz\n- *anch"
236+ isJust maybeRes @? "decoder should return Just YamlObject but returned Nothing"
237+ let res = fromJust maybeRes
238+ res @?= Sequence [Scalar (mkScalar "foo"), Scalar (mkScalar "baz"), Scalar (mkScalar "foo")]
239+
240+caseSimpleSequenceAlias :: Assertion
241+caseSimpleSequenceAlias = do
242+ let maybeRes = decodeYaml "seq: &anch\n - foo\n - baz\nseq2: *anch"
243+ isJust maybeRes @? "decoder should return Just YamlObject but returned Nothing"
244+ let res = fromJust maybeRes
245+ res @?= Mapping [(mkScalar "seq", Sequence [Scalar (mkScalar "foo"), Scalar (mkScalar "baz")]), (mkScalar "seq2", Sequence [Scalar (mkScalar "foo"), Scalar (mkScalar "baz")])]
246+
247+caseSimpleMappingAlias :: Assertion
248+caseSimpleMappingAlias = do
249+ let maybeRes = decodeYaml "map: &anch\n key1: foo\n key2: baz\nmap2: *anch"
250+ isJust maybeRes @? "decoder should return Just YamlObject but returned Nothing"
251+ let res = fromJust maybeRes
252+ res @?= Mapping [(mkScalar "map", Mapping [(mkScalar "key1", Scalar (mkScalar "foo")), (mkScalar "key2", Scalar (mkScalar "baz"))]), (mkScalar "map2", Mapping [(mkScalar "key1", Scalar (mkScalar "foo")), (mkScalar "key2", Scalar (mkScalar "baz"))])]
253+
254+caseMappingAliasBeforeAnchor :: Assertion
255+caseMappingAliasBeforeAnchor = do
256+ let res = decodeYaml "map: *anch\nmap2: &anch\n key1: foo\n key2: baz"
257+ isNothing res @? "decode should return Nothing due to unknown alias"
258+
259+caseMappingAliasInsideAnchor :: Assertion
260+caseMappingAliasInsideAnchor = do
261+ let res = decodeYaml "map: &anch\n key1: foo\n key2: *anch"
262+ isNothing res @? "decode should return Nothing due to unknown alias"
263+
264+caseScalarAliasOverriding :: Assertion
265+caseScalarAliasOverriding = do
266+ let maybeRes = decodeYaml "- &anch foo\n- baz\n- *anch\n- &anch boo\n- buz\n- *anch"
267+ isJust maybeRes @? "decoder should return Just YamlObject but returned Nothing"
268+ let res = fromJust maybeRes
269+ res @?= Sequence [Scalar (mkScalar "foo"), Scalar (mkScalar "baz"), Scalar (mkScalar "foo"), Scalar (mkScalar "boo"), Scalar (mkScalar "buz"), Scalar (mkScalar "boo")]
270+
271+caseAllKeysShouldBeUnique :: Assertion
272+caseAllKeysShouldBeUnique = do
273+ let maybeRes = decodeYaml "foo1: foo\nfoo2: baz\nfoo1: buz"
274+ isJust maybeRes @? "decoder should return Just YamlObject but returned Nothing"
275+ let res = fromJust maybeRes
276+ mappingKey res "foo1" @?= Scalar (mkScalar "buz")
277+
278+caseSimpleMappingMerge :: Assertion
279+caseSimpleMappingMerge = do
280+ let maybeRes = decodeYaml "foo1: foo\nfoo2: baz\n<<:\n foo1: buz\n foo3: fuz"
281+ isJust maybeRes @? "decoder should return Just YamlObject but returned Nothing"
282+ let res = fromJust maybeRes
283+ mappingKey res "foo1" @?= Scalar (mkScalar "foo")
284+ mappingKey res "foo3" @?= Scalar (mkScalar "fuz")
285+
286+caseMergeSequence :: Assertion
287+caseMergeSequence = do
288+ 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 ]"
289+ isJust maybeRes @? "decoder should return Just YamlObject but returned Nothing"
290+ let res = fromJust maybeRes
291+ mappingKey res "foo1" @?= Scalar (mkScalar "foo")
292+ mappingKey res "k1" @?= Scalar (mkStrScalar "1")
293+ mappingKey res "k2" @?= Scalar (mkStrScalar "2")
294+ mappingKey res "k3" @?= Scalar (mkStrScalar "4")
295+
296+inOrderData :: String
297+inOrderData = "'Fatal': 'Unknown variable \"bar\"'\n'Date': '2001-11-23 15:03:17 -5'\n'User': 'ed'\n'Stack':\n- 'line': '23'\n 'file': 'TopClass.py'\n 'code': 'x = MoreObject(\"345\\n\")\n\n'\n- 'line': '58'\n 'file': 'MoreClass.py'\n 'code': 'foo = bar'\n"
298+
299+inOrderData2 :: String
300+inOrderData2 =
301+ "'a': '1'\n'b': '2'\n'd': '4'\n'c': '3'\n"
302+ ++ "'g': '1'\n'n': '2'\n'q': '4'\n'f': '3'\n"
303+ ++ "'z': '1'\n'y': '2'\n'x': '4'\n'w': '3'\n"
304+
305+caseInOrder :: Assertion
306+caseInOrder = do
307+ Just (Mapping ((x, _):_)) <- return $ decodeYaml inOrderData
308+ x @?= mkScalar "Fatal"
309+ fmap (B8.unpack . D.encode) (decodeYaml inOrderData2) @?= Just inOrderData2