2{-# LANGUAGE PackageImports #-}
3{-# LANGUAGE ScopedTypeVariables #-}
4{-# LANGUAGE OverloadedStrings #-}
6import qualified Text.Libyaml as Y
7import qualified Data.ByteString.Char8 as B8
9import Test.HUnit hiding (Test, path)
11import qualified Data.Conduit as C
12import qualified Data.Conduit.List as CL
14import System.Directory
16import Control.Exception (try, SomeException)
17import Test.Hspec.Monadic
18import Test.Hspec.HUnit ()
20import qualified Data.Yaml as D
21import Data.Yaml (object, array)
23import qualified Data.HashMap.Strict as M
24import qualified Data.Text as T
28 describe "streaming" $ do
29 it "count scalars with anchor" caseCountScalarsWithAnchor
30 it "count sequences with anchor" caseCountSequencesWithAnchor
31 it "count mappings with anchor" caseCountMappingsWithAnchor
32 it "count aliases" caseCountAliases
33 it "count scalars" caseCountScalars
34 it "largest string" caseLargestString
35 it "encode/decode" caseEncodeDecode
36 it "encode/decode file" caseEncodeDecodeFile
37 it "interleaved encode/decode" caseInterleave
38 it "decode invalid document (without segfault)" caseDecodeInvalidDocument
39 describe "Data.Yaml" $ do
40 it "encode/decode" caseEncodeDecodeData
41 it "encode/decode file" caseEncodeDecodeFileData
42 it "encode/decode strings" caseEncodeDecodeStrings
43 it "decode invalid file" caseDecodeInvalid
44 describe "Data.Yaml aliases" $ do
45 it "simple scalar alias" caseSimpleScalarAlias
46 it "simple sequence alias" caseSimpleSequenceAlias
47 it "simple mapping alias" caseSimpleMappingAlias
48 it "mapping alias before anchor" caseMappingAliasBeforeAnchor
49 it "mapping alias inside anchor" caseMappingAliasInsideAnchor
50 it "scalar alias overriding" caseScalarAliasOverriding
51 describe "Data.Yaml merge keys" $ do
52 it "test uniqueness of keys" caseAllKeysShouldBeUnique
53 it "test mapping merge" caseSimpleMappingMerge
54 it "test sequence of mappings merging" caseMergeSequence
56counter :: (Y.Event -> Bool) -> C.Sink Y.Event IO Int
58 CL.fold (\cnt e -> (if pred' e then 1 else 0) + cnt) 0
64caseHelper yamlString pred' expRes = do
65 res <- C.runResourceT $ Y.decode (B8.pack yamlString) C.$$ counter pred'
68caseCountScalarsWithAnchor :: Assertion
69caseCountScalarsWithAnchor =
70 caseHelper yamlString isScalarA 1
72 yamlString = "foo:\n - &anchor bin1\n - bin2\n - bin3"
73 isScalarA (Y.EventScalar _ _ _ (Just _)) = True
76caseCountSequencesWithAnchor :: Assertion
77caseCountSequencesWithAnchor =
78 caseHelper yamlString isSequenceStartA 1
80 yamlString = "foo: &anchor\n - bin1\n - bin2\n - bin3"
81 isSequenceStartA (Y.EventSequenceStart (Just _)) = True
82 isSequenceStartA _ = False
84caseCountMappingsWithAnchor :: Assertion
85caseCountMappingsWithAnchor =
86 caseHelper yamlString isMappingA 1
88 yamlString = "foo: &anchor\n key1: bin1\n key2: bin2\n key3: bin3"
89 isMappingA (Y.EventMappingStart (Just _)) = True
92caseCountAliases :: Assertion
94 caseHelper yamlString isAlias 1
96 yamlString = "foo: &anchor\n key1: bin1\n key2: bin2\n key3: bin3\nboo: *anchor"
97 isAlias Y.EventAlias{} = True
100caseCountScalars :: Assertion
102 res <- C.runResourceT $ Y.decode yamlBS C.$$ CL.fold adder accum
105 yamlString = "foo:\n baz: [bin1, bin2, bin3]\nbaz: bazval"
106 yamlBS = B8.pack yamlString
107 adder (s, l, m) (Y.EventScalar{}) = (s + 1, l, m)
108 adder (s, l, m) (Y.EventSequenceStart{}) = (s, l + 1, m)
109 adder (s, l, m) (Y.EventMappingStart{}) = (s, l, m + 1)
111 accum = (0, 0, 0) :: (Int, Int, Int)
113caseLargestString :: Assertion
114caseLargestString = do
115 res <- C.runResourceT $ Y.decodeFile filePath C.$$ CL.fold adder accum
116 res @?= (length expected, expected)
118 expected = "this one is just a little bit bigger than the others"
119 filePath = "test/largest-string.yaml"
120 adder (i, s) (Y.EventScalar bs _ _ _) =
121 let s' = B8.unpack bs
123 in if i' > i then (i', s') else (i, s)
125 accum = (0, "no strings found")
127newtype MyEvent = MyEvent Y.Event deriving Show
128instance Eq MyEvent where
129 (MyEvent (Y.EventScalar s t _ _)) == (MyEvent (Y.EventScalar s' t' _ _)) =
131 MyEvent e1 == MyEvent e2 = e1 == e2
133caseEncodeDecode :: Assertion
135 eList <- C.runResourceT $ Y.decode yamlBS C.$$ CL.consume
136 bs <- C.runResourceT $ CL.sourceList eList C.$$ Y.encode
137 eList2 <- C.runResourceT $ Y.decode bs C.$$ CL.consume
138 map MyEvent eList @=? map MyEvent eList2
140 yamlString = "foo: bar\nbaz:\n - bin1\n - bin2\n"
141 yamlBS = B8.pack yamlString
143removeFile' :: FilePath -> IO ()
145 x <- doesFileExist fp
146 when x $ removeFile fp
148caseEncodeDecodeFile :: Assertion
149caseEncodeDecodeFile = do
151 eList <- C.runResourceT $ Y.decodeFile filePath C.$$ CL.consume
152 C.runResourceT $ CL.sourceList eList C.$$ Y.encodeFile tmpPath
153 eList2 <- C.runResourceT $ Y.decodeFile filePath C.$$ CL.consume
154 map MyEvent eList @=? map MyEvent eList2
156 filePath = "test/largest-string.yaml"
159caseInterleave :: Assertion
163 () <- C.runResourceT $ Y.decodeFile filePath C.$$ Y.encodeFile tmpPath
164 () <- C.runResourceT $ Y.decodeFile tmpPath C.$$ Y.encodeFile tmpPath2
165 f1 <- readFile tmpPath
166 f2 <- readFile tmpPath2
169 filePath = "test/largest-string.yaml"
171 tmpPath2 = "tmp2.yaml"
173caseDecodeInvalidDocument :: Assertion
174caseDecodeInvalidDocument = do
175 x <- try $ C.runResourceT $ Y.decode yamlBS C.$$ CL.sinkNull
177 Left (_ :: SomeException) -> return ()
179 putStrLn $ "bad return value: " ++ show y
180 assertFailure "expected parsing exception, but got no errors"
182 yamlString = " - foo\n - baz\nbuz"
183 yamlBS = B8.pack yamlString
185mkScalar :: String -> D.Value
186mkScalar = mkStrScalar
188mkStrScalar :: String -> D.Value
189mkStrScalar = D.String . T.pack
191mappingKey :: D.Value-> String -> D.Value
192mappingKey (D.Object m) k = (fromJust . M.lookup (T.pack k) $ m)
193mappingKey _ _ = error "expected Object"
195decodeYaml :: String -> Maybe D.Value
196decodeYaml s = D.decode $ B8.pack s
202 [ ("bar1", D.String "bar2")
206caseEncodeDecodeData :: Assertion
207caseEncodeDecodeData = do
208 let out = D.decode $ D.encode sample
211caseEncodeDecodeFileData :: Assertion
212caseEncodeDecodeFileData = do
214 D.encodeFile fp sample
215 out <- D.decodeFile fp
218caseEncodeDecodeStrings :: Assertion
219caseEncodeDecodeStrings = do
220 let out = D.decode $ D.encode sample
223caseDecodeInvalid :: Assertion
224caseDecodeInvalid = do
225 let invalid = B8.pack "\tthis is 'not' valid :-)"
226 Nothing @=? (D.decode invalid :: Maybe D.Value)
228caseSimpleScalarAlias :: Assertion
229caseSimpleScalarAlias = do
230 let maybeRes = decodeYaml "- &anch foo\n- baz\n- *anch"
231 isJust maybeRes @? "decoder should return Just YamlObject but returned Nothing"
232 let res = fromJust maybeRes
233 res @?= array [(mkScalar "foo"), (mkScalar "baz"), (mkScalar "foo")]
235caseSimpleSequenceAlias :: Assertion
236caseSimpleSequenceAlias = do
237 let maybeRes = decodeYaml "seq: &anch\n - foo\n - baz\nseq2: *anch"
238 isJust maybeRes @? "decoder should return Just YamlObject but returned Nothing"
239 let res = fromJust maybeRes
240 res @?= object [("seq", array [(mkScalar "foo"), (mkScalar "baz")]), ("seq2", array [(mkScalar "foo"), (mkScalar "baz")])]
242caseSimpleMappingAlias :: Assertion
243caseSimpleMappingAlias = do
244 let maybeRes = decodeYaml "map: &anch\n key1: foo\n key2: baz\nmap2: *anch"
245 isJust maybeRes @? "decoder should return Just YamlObject but returned Nothing"
246 let res = fromJust maybeRes
247 res @?= object [(T.pack "map", object [("key1", mkScalar "foo"), ("key2", (mkScalar "baz"))]), (T.pack "map2", object [("key1", (mkScalar "foo")), ("key2", mkScalar "baz")])]
249caseMappingAliasBeforeAnchor :: Assertion
250caseMappingAliasBeforeAnchor = do
251 let res = decodeYaml "map: *anch\nmap2: &anch\n key1: foo\n key2: baz"
252 isNothing res @? "decode should return Nothing due to unknown alias"
254caseMappingAliasInsideAnchor :: Assertion
255caseMappingAliasInsideAnchor = do
256 let res = decodeYaml "map: &anch\n key1: foo\n key2: *anch"
257 isNothing res @? "decode should return Nothing due to unknown alias"
259caseScalarAliasOverriding :: Assertion
260caseScalarAliasOverriding = do
261 let maybeRes = decodeYaml "- &anch foo\n- baz\n- *anch\n- &anch boo\n- buz\n- *anch"
262 isJust maybeRes @? "decoder should return Just YamlObject but returned Nothing"
263 let res = fromJust maybeRes
264 res @?= array [(mkScalar "foo"), (mkScalar "baz"), (mkScalar "foo"), (mkScalar "boo"), (mkScalar "buz"), (mkScalar "boo")]
266caseAllKeysShouldBeUnique :: Assertion
267caseAllKeysShouldBeUnique = do
268 let maybeRes = decodeYaml "foo1: foo\nfoo2: baz\nfoo1: buz"
269 isJust maybeRes @? "decoder should return Just YamlObject but returned Nothing"
270 let res = fromJust maybeRes
271 mappingKey res "foo1" @?= (mkScalar "buz")
273caseSimpleMappingMerge :: Assertion
274caseSimpleMappingMerge = do
275 let maybeRes = decodeYaml "foo1: foo\nfoo2: baz\n<<:\n foo1: buz\n foo3: fuz"
276 isJust maybeRes @? "decoder should return Just YamlObject but returned Nothing"
277 let res = fromJust maybeRes
278 mappingKey res "foo1" @?= (mkScalar "foo")
279 mappingKey res "foo3" @?= (mkScalar "fuz")
281caseMergeSequence :: Assertion
282caseMergeSequence = do
283 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 ]"
284 isJust maybeRes @? "decoder should return Just YamlObject but returned Nothing"
285 let res = fromJust maybeRes
286 mappingKey res "foo1" @?= (mkScalar "foo")
287 mappingKey res "k1" @?= (mkStrScalar "1")
288 mappingKey res "k2" @?= (mkStrScalar "2")
289 mappingKey res "k3" @?= (mkStrScalar "4")
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list