| 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 | |
|---|
| 103 | def 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 | |
|---|
| 124 | class 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_(emitter.output.getvalue().find('---') != -1) |
|---|
| 166 | emitter = _syck.Emitter(StringIO.StringIO(), headless=True) |
|---|
| 167 | emitter.emit(CYCLE) |
|---|
| 168 | self.assert_(emitter.output.getvalue().find('---') == -1) |
|---|
| 169 | |
|---|
| 170 | def testUseHeader(self): |
|---|
| 171 | emitter = _syck.Emitter(StringIO.StringIO(), headless=True) |
|---|
| 172 | emitter.emit(EXAMPLE) |
|---|
| 173 | self.assert_(emitter.output.getvalue().find('---') == -1) |
|---|
| 174 | emitter = _syck.Emitter(StringIO.StringIO(), use_header=True) |
|---|
| 175 | emitter.emit(EXAMPLE) |
|---|
| 176 | self.assert_(emitter.output.getvalue().find('---') != -1) |
|---|
| 177 | |
|---|
| 178 | def testExplicitTyping(self): |
|---|
| 179 | pass # anyway it's Syck's responsibility to interpret correctly the parameters. |
|---|
| 180 | |
|---|
| 181 | class 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 | |
|---|
| 217 | class 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 | |
|---|
| 226 | class 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 in range(len(document.value)): |
|---|
| 238 | node = document.value[index] |
|---|
| 239 | self.assertEqual(node.tag, TAGS[index]) |
|---|
| 240 | |
|---|
| 241 | class TestInvalidNodes(unittest.TestCase): |
|---|
| 242 | |
|---|
| 243 | def testRoot(self): |
|---|
| 244 | emitter = _syck.Emitter(StringIO.StringIO()) |
|---|
| 245 | self.assertRaises(TypeError, lambda: emitter.emit(INVALID_ROOT)) |
|---|
| 246 | |
|---|
| 247 | def testSeq(self): |
|---|
| 248 | for invalid in INVALID_SEQ: |
|---|
| 249 | emitter = _syck.Emitter(StringIO.StringIO()) |
|---|
| 250 | self.assertRaises(TypeError, lambda: emitter.emit(invalid)) |
|---|
| 251 | |
|---|
| 252 | def testMap(self): |
|---|
| 253 | for invalid in INVALID_MAP: |
|---|
| 254 | emitter = _syck.Emitter(StringIO.StringIO()) |
|---|
| 255 | self.assertRaises(TypeError, lambda: emitter.emit(invalid)) |
|---|
| 256 | |
|---|
| 257 | class TestOutput(unittest.TestCase): |
|---|
| 258 | |
|---|
| 259 | def testBadOutput(self): |
|---|
| 260 | emitter = _syck.Emitter(None) |
|---|
| 261 | self.assertRaises(AttributeError, lambda: emitter.emit(EXAMPLE)) |
|---|
| 262 | |
|---|
| 263 | def testDouble(self): |
|---|
| 264 | class Stream: |
|---|
| 265 | def __init__(self): |
|---|
| 266 | self.emitter = None |
|---|
| 267 | def write(self, data): |
|---|
| 268 | if self.emitter: |
|---|
| 269 | self.emitter.emit(EXAMPLE) |
|---|
| 270 | emitter = _syck.Emitter(Stream()) |
|---|
| 271 | emitter.output.emitter = emitter |
|---|
| 272 | self.assertRaises(RuntimeError, lambda: emitter.emit(EXAMPLE)) |
|---|
| 273 | |
|---|
| 274 | class TestGarbage(unittest.TestCase): |
|---|
| 275 | |
|---|
| 276 | def testGarbage(self): |
|---|
| 277 | gc.collect() |
|---|
| 278 | output = [] |
|---|
| 279 | emitter = _syck.Emitter(output) |
|---|
| 280 | output.append(emitter) |
|---|
| 281 | del output, emitter |
|---|
| 282 | self.assertEqual(gc.collect(), 2) |
|---|
| 283 | |
|---|
| 284 | |
|---|
| 285 | #class TestSyckBugWithTrailingSpace(unittest.TestCase): |
|---|
| 286 | # |
|---|
| 287 | # def testSyckBugWithTrailingSpace(self): |
|---|
| 288 | # emitter = _syck.Emitter(StringIO.StringIO()) |
|---|
| 289 | # emitter.emit(_syck.Scalar('foo ', tag="tag:yaml.org,2002:str")) |
|---|
| 290 | # parser = _syck.Parser(emitter.output.getvalue()) |
|---|
| 291 | # self.assertEqual(parser.parse().value, 'foo ') |
|---|
| 292 | |
|---|
| 293 | |
|---|