source: trunk/tests/test_emitter.py @ 17

Revision 17, 10.4 KB checked in by xi, 9 years ago (diff)

Add _syck.Emitter (finally closes #19).

RevLine 
[17]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
102
103def strip(node, node_to_object=None):
104    if node_to_object is None:
105        node_to_object = {}
106    if node in node_to_object:
107        return node_to_object[node]
108    object = None
109    if node.kind == 'scalar':
110        object = node.value
111    elif node.kind == 'seq':
112        object = []
113        for item in node.value:
114            object.append(strip(item, node_to_object))
115        object = tuple(object)
116    elif node.kind == 'map':
117        object = {}
118        dict_value = dict(node.value)
119        for key in dict_value:
120            object[strip(key, node_to_object)] = strip(dict_value[key], node_to_object)
121    node_to_object[node] = object
122    return object
123
124class TestAttributes(unittest.TestCase):
125
126    def testAttributes(self):
127        output = StringIO.StringIO()
128        emitter = _syck.Emitter(output)
129        self.assertEqual(type(emitter), _syck.Emitter)
130        self.assertEqual(emitter.output, output)
131        self.assertEqual(emitter.headless, False)
132        self.assertEqual(emitter.use_header, False)
133        self.assertEqual(emitter.use_version, False)
134        self.assertEqual(emitter.explicit_typing, False)
135        self.assertEqual(emitter.style, None)
136        self.assertEqual(emitter.best_width, 80)
137        self.assertEqual(emitter.indent, 2)
138        emitter = _syck.Emitter(output, headless=True, use_header=True,
139                use_version=True, explicit_typing=True, style='fold',
140                best_width=100, indent=4)
141        self.assertEqual(emitter.headless, True)
142        self.assertEqual(emitter.use_header, True)
143        self.assertEqual(emitter.use_version, True)
144        self.assertEqual(emitter.explicit_typing, True)
145        self.assertEqual(emitter.style, 'fold')
146        self.assertEqual(emitter.best_width, 100)
147        self.assertEqual(emitter.indent, 4)
148
149    def testInvalidTypesAndValues(self):
150        self.assertRaises(TypeError, lambda: _syck.Emitter(None, headless='on'))
151        self.assertRaises(TypeError, lambda: _syck.Emitter(None, use_header='on'))
152        self.assertRaises(TypeError, lambda: _syck.Emitter(None, use_version='on'))
153        self.assertRaises(TypeError, lambda: _syck.Emitter(None, explicit_typing='on'))
154        self.assertRaises(ValueError, lambda: _syck.Emitter(None, style='no_quote'))
155        self.assertRaises(TypeError, lambda: _syck.Emitter(None, best_width='100'))
156        self.assertRaises(ValueError, lambda: _syck.Emitter(None, best_width=0))
157        self.assertRaises(ValueError, lambda: _syck.Emitter(None, best_width=-100))
158        self.assertRaises(TypeError, lambda: _syck.Emitter(None, indent='2'))
159        self.assertRaises(ValueError, lambda: _syck.Emitter(None, indent=0))
160        self.assertRaises(ValueError, lambda: _syck.Emitter(None, indent=-2))
161
162    def testHeadless(self):
163        emitter = _syck.Emitter(StringIO.StringIO(), headless=False)
164        emitter.emit(CYCLE)
165        self.assert_('---' in emitter.output.getvalue())
166        emitter = _syck.Emitter(StringIO.StringIO(), headless=True)
167        emitter.emit(CYCLE)
168        self.assert_('---' not in emitter.output.getvalue())
169
170    def testUseHeader(self):
171        emitter = _syck.Emitter(StringIO.StringIO(), headless=True)
172        emitter.emit(EXAMPLE)
173        self.assert_('---' not in emitter.output.getvalue())
174        emitter = _syck.Emitter(StringIO.StringIO(), use_header=True)
175        emitter.emit(EXAMPLE)
176        self.assert_('---' in emitter.output.getvalue())
177
178    def testExplicitTyping(self):
179        pass    # anyway it's Syck's responsibility to interpret correctly the parameters.
180
181class TestExample(unittest.TestCase):
182
183    def testExample(self):
184        emitter = _syck.Emitter(StringIO.StringIO())
185        emitter.emit(EXAMPLE)
186        parser = _syck.Parser(emitter.output.getvalue())
187        node = parser.parse()
188        self.assertEqual(strip(EXAMPLE), strip(node))
189
190    def testPairs(self):
191        emitter = _syck.Emitter(StringIO.StringIO())
192        emitter.emit(PAIRS)
193        parser = _syck.Parser(emitter.output.getvalue())
194        node = parser.parse()
195        self.assertEqual(strip(PAIRS), strip(node))
196
197    def testComplexExample(self):
198        emitter = _syck.Emitter(StringIO.StringIO())
199        emitter.emit(COMPLEX_EXAMPLE)
200        parser = _syck.Parser(emitter.output.getvalue())
201        node = parser.parse()
202        self.assertEqual(strip(COMPLEX_EXAMPLE), strip(node))
203
204    def testDocuments(self):
205        emitter = _syck.Emitter(StringIO.StringIO())
206        emitter.emit(EXAMPLE)
207        emitter.emit(EXAMPLE)
208        emitter.emit(EXAMPLE)
209        parser = _syck.Parser(emitter.output.getvalue())
210        self.assertEqual(strip(EXAMPLE), strip(parser.parse()))
211        self.assertEqual(strip(EXAMPLE), strip(parser.parse()))
212        self.assertEqual(strip(EXAMPLE), strip(parser.parse()))
213        self.assert_(not parser.eof)
214        parser.parse()
215        self.assert_(parser.eof)
216
217class TestAliases(unittest.TestCase):
218
219    def testAliases(self):
220        emitter = _syck.Emitter(StringIO.StringIO())
221        emitter.emit(ALIASES)
222        parser = _syck.Parser(emitter.output.getvalue())
223        node = parser.parse()
224        self.assert_(node.value[0] is node.value[1])
225
226class TestTags(unittest.TestCase):
227
228    def testTags(self):
229        document = _syck.Seq()
230        for tag in TAGS:
231            document.value.append(_syck.Scalar('foo', tag=tag))
232        emitter = _syck.Emitter(StringIO.StringIO())
233        emitter.emit(document)
234        parser = _syck.Parser(emitter.output.getvalue())
235        document = parser.parse()
236        self.assertEqual(len(document.value), len(TAGS))
237        for index, node in enumerate(document.value):
238            self.assertEqual(node.tag, TAGS[index])
239
240class TestInvalidNodes(unittest.TestCase):
241
242    def testRoot(self):
243        emitter = _syck.Emitter(StringIO.StringIO())
244        self.assertRaises(TypeError, lambda: emitter.emit(INVALID_ROOT))
245
246    def testSeq(self):
247        for invalid in INVALID_SEQ:
248            emitter = _syck.Emitter(StringIO.StringIO())
249            self.assertRaises(TypeError, lambda: emitter.emit(invalid))
250
251    def testMap(self):
252        for invalid in INVALID_MAP:
253            emitter = _syck.Emitter(StringIO.StringIO())
254            self.assertRaises(TypeError, lambda: emitter.emit(invalid))
255
256class TestOutput(unittest.TestCase):
257
258    def testBadOutput(self):
259        emitter = _syck.Emitter(None)
260        self.assertRaises(AttributeError, lambda: emitter.emit(EXAMPLE))
261
262    def testDouble(self):
263        class Stream:
264            def __init__(self):
265                self.emitter = None
266            def write(self, data):
267                if self.emitter:
268                    self.emitter.emit(EXAMPLE)
269        emitter = _syck.Emitter(Stream())
270        emitter.output.emitter = emitter
271        self.assertRaises(RuntimeError, lambda: emitter.emit(EXAMPLE))
272
273class TestGarbage(unittest.TestCase):
274
275    def testGarbage(self):
276        gc.collect()
277        output = []
278        emitter = _syck.Emitter(output)
279        output.append(emitter)
280        del output, emitter
281        self.assertEqual(gc.collect(), 2)
282
283
284class TestSyckBugWithTrailingSpace(unittest.TestCase):
285
286    def testSyckBugWithTrailingSpace(self):
287        emitter = _syck.Emitter(StringIO.StringIO())
288        emitter.emit(_syck.Scalar('foo ', tag="tag:yaml.org,2002:str"))
289        parser = _syck.Parser(emitter.output.getvalue())
290        self.assertEqual(parser.parse().value, 'foo ')
291
292
Note: See TracBrowser for help on using the repository browser.