| 1 | |
|---|
| 2 | import unittest |
|---|
| 3 | |
|---|
| 4 | import _syck |
|---|
| 5 | |
|---|
| 6 | import StringIO, gc |
|---|
| 7 | |
|---|
| 8 | EXAMPLE = _syck.Seq([ |
|---|
| 9 | _syck.Scalar('Mark McGwire'), |
|---|
| 10 | _syck.Scalar('Sammy Sosa'), |
|---|
| 11 | _syck.Scalar('Ken Griffey'), |
|---|
| 12 | ]) |
|---|
| 13 | |
|---|
| 14 | COMPLEX_EXAMPLE = _syck.Map({ |
|---|
| 15 | _syck.Scalar('scalars') : _syck.Seq([ |
|---|
| 16 | _syck.Scalar(), |
|---|
| 17 | _syck.Scalar('on'), |
|---|
| 18 | _syck.Scalar('12345', tag="tag:yaml.org,2002:int"), |
|---|
| 19 | # Syck bug with trailing spaces. |
|---|
| 20 | # _syck.Scalar('long '*100, width=20, indent=5), |
|---|
| 21 | _syck.Scalar('long long long long long\n'*100, width=20, indent=5), |
|---|
| 22 | _syck.Scalar('"1quote"', style='1quote'), |
|---|
| 23 | _syck.Scalar("'2quote'", style='2quote'), |
|---|
| 24 | _syck.Scalar("folding\n"*10, style='fold'), |
|---|
| 25 | _syck.Scalar("literal\n"*10, style='literal'), |
|---|
| 26 | _syck.Scalar("plain text", style='plain'), |
|---|
| 27 | ]), |
|---|
| 28 | _syck.Scalar('sequences') : _syck.Seq([ |
|---|
| 29 | _syck.Seq([ |
|---|
| 30 | _syck.Seq([_syck.Scalar('foo'), _syck.Scalar('bar', style='literal')]), |
|---|
| 31 | ], inline=True), |
|---|
| 32 | _syck.Seq([ |
|---|
| 33 | _syck.Scalar('foo'), |
|---|
| 34 | _syck.Scalar('bar'), |
|---|
| 35 | ], tag="x-private:myprivatesequence") |
|---|
| 36 | ]), |
|---|
| 37 | _syck.Scalar('mappings') : _syck.Seq([ |
|---|
| 38 | _syck.Map({ |
|---|
| 39 | _syck.Seq([_syck.Scalar('1'), _syck.Scalar('2')]) : |
|---|
| 40 | _syck.Seq([_syck.Scalar('3'), _syck.Scalar('4')]), |
|---|
| 41 | _syck.Scalar('5') : _syck.Scalar('6'), |
|---|
| 42 | }), |
|---|
| 43 | _syck.Map({ |
|---|
| 44 | _syck.Scalar('foo') : |
|---|
| 45 | _syck.Seq([_syck.Scalar('bar')]) |
|---|
| 46 | }, inline=True, tag="x-private:myprivatemapping"), |
|---|
| 47 | ]), |
|---|
| 48 | _syck.Scalar('empty'): _syck.Seq([ |
|---|
| 49 | _syck.Scalar(), |
|---|
| 50 | _syck.Seq(), |
|---|
| 51 | _syck.Map(), |
|---|
| 52 | _syck.Map({_syck.Scalar(tag='tag:yaml.org,2002:str') : _syck.Scalar(tag='tag:yaml.org,2002:str')}), |
|---|
| 53 | _syck.Map({_syck.Scalar('foo') : _syck.Scalar()}), |
|---|
| 54 | _syck.Map({_syck.Scalar(tag='tag:yaml.org,2002:str') : _syck.Scalar('bar')}), |
|---|
| 55 | ]), |
|---|
| 56 | }) |
|---|
| 57 | |
|---|
| 58 | PAIRS = _syck.Map([ |
|---|
| 59 | (_syck.Scalar('foo'), _syck.Scalar('bar')), |
|---|
| 60 | (_syck.Scalar('bar'), _syck.Scalar('baz')), |
|---|
| 61 | ]) |
|---|
| 62 | |
|---|
| 63 | CYCLE = _syck.Seq() |
|---|
| 64 | CYCLE.value.append(CYCLE) |
|---|
| 65 | |
|---|
| 66 | ALIASED_OBJECT = _syck.Map({ |
|---|
| 67 | _syck.Scalar('key1'): _syck.Scalar('value1'), |
|---|
| 68 | _syck.Scalar('key2'): _syck.Scalar('value2'), |
|---|
| 69 | _syck.Scalar('key3'): _syck.Seq([_syck.Scalar('value3')]), |
|---|
| 70 | }) |
|---|
| 71 | |
|---|
| 72 | ALIASES = _syck.Seq([ALIASED_OBJECT, ALIASED_OBJECT]) |
|---|
| 73 | |
|---|
| 74 | TAGS = [ |
|---|
| 75 | 'tag:yaml.org,2002:str', |
|---|
| 76 | 'tag:yaml.org,2002:int', |
|---|
| 77 | 'tag:python.yaml.org,2002:object', |
|---|
| 78 | 'tag:domain.tld,2002:my/own/type#variant', |
|---|
| 79 | 'x-private:private', |
|---|
| 80 | ] |
|---|
| 81 | |
|---|
| 82 | INVALID_ROOT = 'break me' |
|---|
| 83 | |
|---|
| 84 | INVALID_SEQ = [ |
|---|
| 85 | _syck.Seq([1,2,3]), |
|---|
| 86 | _syck.Map({ |
|---|
| 87 | _syck.Scalar('valid'): _syck.Seq([_syck.Scalar('valid'), _syck.Scalar('valid')]), |
|---|
| 88 | _syck.Scalar('invalid'): _syck.Seq([_syck.Scalar('valid'), 'invalid', _syck.Scalar('valid')]), |
|---|
| 89 | }), |
|---|
| 90 | ] |
|---|
| 91 | |
|---|
| 92 | INVALID_MAP = [ |
|---|
| 93 | _syck.Map({'foo': 'bar'}), |
|---|
| 94 | _syck.Map({'foo': _syck.Scalar('valid')}), |
|---|
| 95 | _syck.Map({_syck.Scalar('valid'): 'bar'}), |
|---|
| 96 | _syck.Seq([ |
|---|
| 97 | _syck.Map({}), |
|---|
| 98 | _syck.Map({_syck.Scalar('valid'): 'invalid'}), |
|---|
| 99 | ]), |
|---|
| 100 | ] |
|---|
| 101 | |
|---|
| 102 | COMPLEX_ITEMS = [ |
|---|
| 103 | _syck.Scalar("foo"), |
|---|
| 104 | _syck.Scalar("foo", tag='x-private:complex'), |
|---|
| 105 | _syck.Scalar("foo bar baz", style='fold'), |
|---|
| 106 | _syck.Scalar("foo bar baz", style='fold', tag='x-private:complex'), |
|---|
| 107 | _syck.Seq([]), |
|---|
| 108 | _syck.Seq([], tag='x-private:complex'), |
|---|
| 109 | _syck.Seq([_syck.Scalar('alpha'), _syck.Scalar('beta'), _syck.Scalar('gamma')]), |
|---|
| 110 | _syck.Seq([_syck.Scalar('alpha'), _syck.Scalar('beta'), _syck.Scalar('gamma')], tag='x-private:complex'), |
|---|
| 111 | _syck.Seq([_syck.Scalar('alpha'), _syck.Scalar('beta'), _syck.Scalar('gamma')], inline=True, tag='x-private:complex'), |
|---|
| 112 | _syck.Map({}), |
|---|
| 113 | _syck.Map({}, tag='x-private:complex'), |
|---|
| 114 | _syck.Map([(_syck.Scalar('alpha'), _syck.Scalar('beta')), (_syck.Scalar('gamma'), _syck.Scalar('delta'))], tag='x-private:complex'), |
|---|
| 115 | _syck.Map([(_syck.Scalar('alpha'), _syck.Scalar('beta')), (_syck.Scalar('gamma'), _syck.Scalar('delta'))], inline=True, tag='x-private:complex'), |
|---|
| 116 | ] |
|---|
| 117 | |
|---|
| 118 | def strip(node, node_to_object=None): |
|---|
| 119 | if node_to_object is None: |
|---|
| 120 | node_to_object = {} |
|---|
| 121 | if node in node_to_object: |
|---|
| 122 | return node_to_object[node] |
|---|
| 123 | object = None |
|---|
| 124 | if node.kind == 'scalar': |
|---|
| 125 | object = node.value |
|---|
| 126 | elif node.kind == 'seq': |
|---|
| 127 | object = [] |
|---|
| 128 | for item in node.value: |
|---|
| 129 | object.append(strip(item, node_to_object)) |
|---|
| 130 | object = tuple(object) |
|---|
| 131 | elif node.kind == 'map': |
|---|
| 132 | object = [] |
|---|
| 133 | dict_value = dict(node.value) |
|---|
| 134 | for key in dict_value: |
|---|
| 135 | object.append((strip(key, node_to_object), strip(dict_value[key], node_to_object))) |
|---|
| 136 | object.sort() |
|---|
| 137 | node_to_object[node] = object |
|---|
| 138 | return object |
|---|
| 139 | |
|---|
| 140 | class TestAttributes(unittest.TestCase): |
|---|
| 141 | |
|---|
| 142 | def testAttributes(self): |
|---|
| 143 | output = StringIO.StringIO() |
|---|
| 144 | emitter = _syck.Emitter(output) |
|---|
| 145 | self.assertEqual(type(emitter), _syck.Emitter) |
|---|
| 146 | self.assertEqual(emitter.output, output) |
|---|
| 147 | self.assertEqual(emitter.headless, False) |
|---|
| 148 | self.assertEqual(emitter.use_header, False) |
|---|
| 149 | self.assertEqual(emitter.use_version, False) |
|---|
| 150 | self.assertEqual(emitter.explicit_typing, False) |
|---|
| 151 | self.assertEqual(emitter.style, None) |
|---|
| 152 | self.assertEqual(emitter.best_width, 80) |
|---|
| 153 | self.assertEqual(emitter.indent, 2) |
|---|
| 154 | emitter = _syck.Emitter(output, headless=True, use_header=True, |
|---|
| 155 | use_version=True, explicit_typing=True, style='fold', |
|---|
| 156 | best_width=100, indent=4) |
|---|
| 157 | self.assertEqual(emitter.headless, True) |
|---|
| 158 | self.assertEqual(emitter.use_header, True) |
|---|
| 159 | self.assertEqual(emitter.use_version, True) |
|---|
| 160 | self.assertEqual(emitter.explicit_typing, True) |
|---|
| 161 | self.assertEqual(emitter.style, 'fold') |
|---|
| 162 | self.assertEqual(emitter.best_width, 100) |
|---|
| 163 | self.assertEqual(emitter.indent, 4) |
|---|
| 164 | |
|---|
| 165 | def testInvalidTypesAndValues(self): |
|---|
| 166 | self.assertRaises(TypeError, lambda: _syck.Emitter(None, headless='on')) |
|---|
| 167 | self.assertRaises(TypeError, lambda: _syck.Emitter(None, use_header='on')) |
|---|
| 168 | self.assertRaises(TypeError, lambda: _syck.Emitter(None, use_version='on')) |
|---|
| 169 | self.assertRaises(TypeError, lambda: _syck.Emitter(None, explicit_typing='on')) |
|---|
| 170 | self.assertRaises(ValueError, lambda: _syck.Emitter(None, style='no_quote')) |
|---|
| 171 | self.assertRaises(TypeError, lambda: _syck.Emitter(None, best_width='100')) |
|---|
| 172 | self.assertRaises(ValueError, lambda: _syck.Emitter(None, best_width=0)) |
|---|
| 173 | self.assertRaises(ValueError, lambda: _syck.Emitter(None, best_width=-100)) |
|---|
| 174 | self.assertRaises(TypeError, lambda: _syck.Emitter(None, indent='2')) |
|---|
| 175 | self.assertRaises(ValueError, lambda: _syck.Emitter(None, indent=0)) |
|---|
| 176 | self.assertRaises(ValueError, lambda: _syck.Emitter(None, indent=-2)) |
|---|
| 177 | |
|---|
| 178 | def testHeadless(self): |
|---|
| 179 | emitter = _syck.Emitter(StringIO.StringIO(), headless=False) |
|---|
| 180 | emitter.emit(CYCLE) |
|---|
| 181 | self.assert_(emitter.output.getvalue().find('---') != -1) |
|---|
| 182 | emitter = _syck.Emitter(StringIO.StringIO(), headless=True) |
|---|
| 183 | emitter.emit(CYCLE) |
|---|
| 184 | self.assert_(emitter.output.getvalue().find('---') == -1) |
|---|
| 185 | |
|---|
| 186 | def testUseHeader(self): |
|---|
| 187 | emitter = _syck.Emitter(StringIO.StringIO(), headless=True) |
|---|
| 188 | emitter.emit(EXAMPLE) |
|---|
| 189 | self.assert_(emitter.output.getvalue().find('---') == -1) |
|---|
| 190 | emitter = _syck.Emitter(StringIO.StringIO(), use_header=True) |
|---|
| 191 | emitter.emit(EXAMPLE) |
|---|
| 192 | self.assert_(emitter.output.getvalue().find('---') != -1) |
|---|
| 193 | |
|---|
| 194 | def testExplicitTyping(self): |
|---|
| 195 | pass # anyway it's Syck's responsibility to interpret correctly the parameters. |
|---|
| 196 | |
|---|
| 197 | class TestExample(unittest.TestCase): |
|---|
| 198 | |
|---|
| 199 | def testExample(self): |
|---|
| 200 | emitter = _syck.Emitter(StringIO.StringIO()) |
|---|
| 201 | emitter.emit(EXAMPLE) |
|---|
| 202 | parser = _syck.Parser(emitter.output.getvalue()) |
|---|
| 203 | node = parser.parse() |
|---|
| 204 | self.assertEqual(strip(EXAMPLE), strip(node)) |
|---|
| 205 | |
|---|
| 206 | def testPairs(self): |
|---|
| 207 | emitter = _syck.Emitter(StringIO.StringIO()) |
|---|
| 208 | emitter.emit(PAIRS) |
|---|
| 209 | parser = _syck.Parser(emitter.output.getvalue()) |
|---|
| 210 | node = parser.parse() |
|---|
| 211 | self.assertEqual(strip(PAIRS), strip(node)) |
|---|
| 212 | |
|---|
| 213 | def testComplexExample(self): |
|---|
| 214 | emitter = _syck.Emitter(StringIO.StringIO()) |
|---|
| 215 | emitter.emit(COMPLEX_EXAMPLE) |
|---|
| 216 | parser = _syck.Parser(emitter.output.getvalue()) |
|---|
| 217 | node = parser.parse() |
|---|
| 218 | self.assertEqual(strip(COMPLEX_EXAMPLE), strip(node)) |
|---|
| 219 | |
|---|
| 220 | def testDocuments(self): |
|---|
| 221 | emitter = _syck.Emitter(StringIO.StringIO()) |
|---|
| 222 | emitter.emit(EXAMPLE) |
|---|
| 223 | emitter.emit(EXAMPLE) |
|---|
| 224 | emitter.emit(EXAMPLE) |
|---|
| 225 | parser = _syck.Parser(emitter.output.getvalue()) |
|---|
| 226 | self.assertEqual(strip(EXAMPLE), strip(parser.parse())) |
|---|
| 227 | self.assertEqual(strip(EXAMPLE), strip(parser.parse())) |
|---|
| 228 | self.assertEqual(strip(EXAMPLE), strip(parser.parse())) |
|---|
| 229 | self.assert_(not parser.eof) |
|---|
| 230 | parser.parse() |
|---|
| 231 | self.assert_(parser.eof) |
|---|
| 232 | |
|---|
| 233 | class TestAliases(unittest.TestCase): |
|---|
| 234 | |
|---|
| 235 | def testAliases(self): |
|---|
| 236 | emitter = _syck.Emitter(StringIO.StringIO()) |
|---|
| 237 | emitter.emit(ALIASES) |
|---|
| 238 | parser = _syck.Parser(emitter.output.getvalue()) |
|---|
| 239 | node = parser.parse() |
|---|
| 240 | self.assert_(node.value[0] is node.value[1]) |
|---|
| 241 | |
|---|
| 242 | class TestTags(unittest.TestCase): |
|---|
| 243 | |
|---|
| 244 | def testTags(self): |
|---|
| 245 | document = _syck.Seq() |
|---|
| 246 | for tag in TAGS: |
|---|
| 247 | document.value.append(_syck.Scalar('foo', tag=tag)) |
|---|
| 248 | emitter = _syck.Emitter(StringIO.StringIO()) |
|---|
| 249 | emitter.emit(document) |
|---|
| 250 | parser = _syck.Parser(emitter.output.getvalue()) |
|---|
| 251 | document = parser.parse() |
|---|
| 252 | self.assertEqual(len(document.value), len(TAGS)) |
|---|
| 253 | for index in range(len(document.value)): |
|---|
| 254 | node = document.value[index] |
|---|
| 255 | self.assertEqual(node.tag, TAGS[index]) |
|---|
| 256 | |
|---|
| 257 | class TestInvalidNodes(unittest.TestCase): |
|---|
| 258 | |
|---|
| 259 | def testRoot(self): |
|---|
| 260 | emitter = _syck.Emitter(StringIO.StringIO()) |
|---|
| 261 | self.assertRaises(TypeError, lambda: emitter.emit(INVALID_ROOT)) |
|---|
| 262 | |
|---|
| 263 | def testSeq(self): |
|---|
| 264 | for invalid in INVALID_SEQ: |
|---|
| 265 | emitter = _syck.Emitter(StringIO.StringIO()) |
|---|
| 266 | self.assertRaises(TypeError, lambda: emitter.emit(invalid)) |
|---|
| 267 | |
|---|
| 268 | def testMap(self): |
|---|
| 269 | for invalid in INVALID_MAP: |
|---|
| 270 | emitter = _syck.Emitter(StringIO.StringIO()) |
|---|
| 271 | self.assertRaises(TypeError, lambda: emitter.emit(invalid)) |
|---|
| 272 | |
|---|
| 273 | class TestOutput(unittest.TestCase): |
|---|
| 274 | |
|---|
| 275 | def testBadOutput(self): |
|---|
| 276 | emitter = _syck.Emitter(None) |
|---|
| 277 | self.assertRaises(AttributeError, lambda: emitter.emit(EXAMPLE)) |
|---|
| 278 | |
|---|
| 279 | def testDouble(self): |
|---|
| 280 | class Stream: |
|---|
| 281 | def __init__(self): |
|---|
| 282 | self.emitter = None |
|---|
| 283 | def write(self, data): |
|---|
| 284 | if self.emitter: |
|---|
| 285 | self.emitter.emit(EXAMPLE) |
|---|
| 286 | emitter = _syck.Emitter(Stream()) |
|---|
| 287 | emitter.output.emitter = emitter |
|---|
| 288 | self.assertRaises(RuntimeError, lambda: emitter.emit(EXAMPLE)) |
|---|
| 289 | |
|---|
| 290 | class TestGarbage(unittest.TestCase): |
|---|
| 291 | |
|---|
| 292 | def testGarbage(self): |
|---|
| 293 | gc.collect() |
|---|
| 294 | output = [] |
|---|
| 295 | emitter = _syck.Emitter(output) |
|---|
| 296 | output.append(emitter) |
|---|
| 297 | del output, emitter |
|---|
| 298 | self.assertEqual(gc.collect(), 2) |
|---|
| 299 | |
|---|
| 300 | |
|---|
| 301 | class TestSyckBugWithTrailingSpace(unittest.TestCase): |
|---|
| 302 | |
|---|
| 303 | def testSyckBugWithTrailingSpace(self): |
|---|
| 304 | emitter = _syck.Emitter(StringIO.StringIO()) |
|---|
| 305 | emitter.emit(_syck.Scalar('foo ', tag="tag:yaml.org,2002:str")) |
|---|
| 306 | parser = _syck.Parser(emitter.output.getvalue()) |
|---|
| 307 | self.assertEqual(parser.parse().value, 'foo ') |
|---|
| 308 | |
|---|
| 309 | |
|---|
| 310 | |
|---|
| 311 | class TestSyckComplexKeyBugs(unittest.TestCase): |
|---|
| 312 | |
|---|
| 313 | def testEmptyCollectionKeyBug(self): |
|---|
| 314 | tree1 = _syck.Map({_syck.Map(): _syck.Scalar('foo')}) |
|---|
| 315 | self._testTree(tree1) |
|---|
| 316 | tree2 = _syck.Map({_syck.Seq(): _syck.Scalar('foo')}) |
|---|
| 317 | self._testTree(tree2) |
|---|
| 318 | |
|---|
| 319 | def testCollectionWithTagKeyBug(self): |
|---|
| 320 | tree = _syck.Map({_syck.Seq([_syck.Scalar('foo')], tag='x-private:key'): |
|---|
| 321 | _syck.Scalar('bar')}) |
|---|
| 322 | self._testTree(tree) |
|---|
| 323 | |
|---|
| 324 | def testFlowCollectionKeyBug(self): |
|---|
| 325 | tree = _syck.Map({_syck.Seq([_syck.Scalar('foo')], inline=True): |
|---|
| 326 | _syck.Scalar('bar')}) |
|---|
| 327 | self._testTree(tree) |
|---|
| 328 | |
|---|
| 329 | def testEmptyCollectionWithAliasKeyBug(self): |
|---|
| 330 | node = _syck.Map() |
|---|
| 331 | tree = _syck.Map({node: node}) |
|---|
| 332 | self._testTree(tree) |
|---|
| 333 | |
|---|
| 334 | def testScalarWithAliasKeyBug(self): |
|---|
| 335 | node = _syck.Scalar('foo', tag='x-private:bug') |
|---|
| 336 | tree = _syck.Map({node: node}) |
|---|
| 337 | self._testTree(tree) |
|---|
| 338 | |
|---|
| 339 | def _testTree(self, tree): |
|---|
| 340 | emitter = _syck.Emitter(StringIO.StringIO()) |
|---|
| 341 | emitter.emit(tree) |
|---|
| 342 | #print emitter.output.getvalue() |
|---|
| 343 | parser = _syck.Parser(emitter.output.getvalue()) |
|---|
| 344 | self.assertEqual(strip(tree), strip(parser.parse())) |
|---|
| 345 | |
|---|
| 346 | def testSyckBugWithComplexKeys(self): |
|---|
| 347 | broken = 0 |
|---|
| 348 | for key in COMPLEX_ITEMS: |
|---|
| 349 | for value in COMPLEX_ITEMS: |
|---|
| 350 | node = _syck.Map({key: value}) |
|---|
| 351 | emitter = _syck.Emitter(StringIO.StringIO()) |
|---|
| 352 | emitter.emit(node) |
|---|
| 353 | parser = _syck.Parser(emitter.output.getvalue()) |
|---|
| 354 | self.assertEqual(strip(node), strip(parser.parse())) |
|---|
| 355 | |
|---|