source: trunk/tests/test_emitter.py @ 35

Revision 35, 13.0 KB checked in by xi, 8 years ago (diff)

Add tests for complex key bugs.

Line 
1
2import unittest
3
4import _syck
5
6import StringIO, gc
7
8EXAMPLE = _syck.Seq([
9        _syck.Scalar('Mark McGwire'),
10        _syck.Scalar('Sammy Sosa'),
11        _syck.Scalar('Ken Griffey'),
12])
13
14COMPLEX_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
58PAIRS = _syck.Map([
59    (_syck.Scalar('foo'), _syck.Scalar('bar')),
60    (_syck.Scalar('bar'), _syck.Scalar('baz')),
61])
62
63CYCLE = _syck.Seq()
64CYCLE.value.append(CYCLE)
65
66ALIASED_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
72ALIASES = _syck.Seq([ALIASED_OBJECT, ALIASED_OBJECT])
73
74TAGS = [
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
82INVALID_ROOT = 'break me'
83
84INVALID_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
92INVALID_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
102COMPLEX_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
118def 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
140class 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
197class 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
233class 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
242class 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
257class 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
273class 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
290class 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
301class 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
311class 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
Note: See TracBrowser for help on using the repository browser.