| 1 | import YamlTest |
|---|
| 2 | from yaml.dump import * |
|---|
| 3 | import yaml |
|---|
| 4 | from here import flushLeft |
|---|
| 5 | from test import assertEquals |
|---|
| 6 | |
|---|
| 7 | class SampleClass: |
|---|
| 8 | def expected(self, modname, classname): |
|---|
| 9 | """ |
|---|
| 10 | Tough to test, because this class may be in __main__ |
|---|
| 11 | namespace, may be in TestDumper, depending where you |
|---|
| 12 | run it |
|---|
| 13 | """ |
|---|
| 14 | return """ |
|---|
| 15 | --- !!%s.%s |
|---|
| 16 | bar: 4 |
|---|
| 17 | foo: 3 |
|---|
| 18 | items: |
|---|
| 19 | - apple |
|---|
| 20 | - banana |
|---|
| 21 | """ % (modname, classname) |
|---|
| 22 | |
|---|
| 23 | def __init__(self): |
|---|
| 24 | self.foo = 3 |
|---|
| 25 | self.bar = 4 |
|---|
| 26 | self.items = ['apple', 'banana'] |
|---|
| 27 | |
|---|
| 28 | |
|---|
| 29 | class SampleException(Exception): |
|---|
| 30 | def __init__(self, args): |
|---|
| 31 | self.args = args |
|---|
| 32 | |
|---|
| 33 | class Test(YamlTest.YamlTest): |
|---|
| 34 | def dumpTest(self, obj, expect): |
|---|
| 35 | assertEquals(yaml.dump(obj), flushLeft(expect)) |
|---|
| 36 | def dumpTestSort(self,sort): |
|---|
| 37 | obj = {'a':'aaaa','d':'dddd','b':'bbbb','c':'cccc'} |
|---|
| 38 | exp = flushLeft(\ |
|---|
| 39 | """ |
|---|
| 40 | --- |
|---|
| 41 | b: bbbb |
|---|
| 42 | d: dddd |
|---|
| 43 | a: aaaa |
|---|
| 44 | c: cccc |
|---|
| 45 | """) |
|---|
| 46 | dumper = yaml.Dumper().setSort(sort) |
|---|
| 47 | self.assertEquals(dumper.dump(obj),exp) |
|---|
| 48 | def testsort_map(self): |
|---|
| 49 | self.dumpTestSort({'a':4,'b':2,'d':3}) |
|---|
| 50 | def testsort_tuple(self): |
|---|
| 51 | self.dumpTestSort(('b','d','a')) |
|---|
| 52 | def testsort_list(self): |
|---|
| 53 | self.dumpTestSort(['b','d','a']) |
|---|
| 54 | def testsort_func(self): |
|---|
| 55 | self.dumpTestSort({'a':4,'b':2,'d':3}.get) |
|---|
| 56 | def test1(self): |
|---|
| 57 | self.dumpTest( |
|---|
| 58 | { 'foo': 'bar', 'yo': 'mama' }, |
|---|
| 59 | """ |
|---|
| 60 | --- |
|---|
| 61 | foo: bar |
|---|
| 62 | yo: mama |
|---|
| 63 | """, |
|---|
| 64 | ) |
|---|
| 65 | |
|---|
| 66 | def test2(self): |
|---|
| 67 | self.dumpTest( |
|---|
| 68 | { 'foo': {'bar': 3} }, |
|---|
| 69 | """ |
|---|
| 70 | --- |
|---|
| 71 | foo: |
|---|
| 72 | bar: 3 |
|---|
| 73 | """, |
|---|
| 74 | ) |
|---|
| 75 | |
|---|
| 76 | def test3(self): |
|---|
| 77 | self.dumpTest( |
|---|
| 78 | { |
|---|
| 79 | 'foo': 3, |
|---|
| 80 | 'fruits': { |
|---|
| 81 | 'apple': 'red', |
|---|
| 82 | 'banana': 'yellow', |
|---|
| 83 | } |
|---|
| 84 | }, |
|---|
| 85 | """ |
|---|
| 86 | --- |
|---|
| 87 | foo: 3 |
|---|
| 88 | fruits: |
|---|
| 89 | apple: red |
|---|
| 90 | banana: yellow |
|---|
| 91 | """ |
|---|
| 92 | ) |
|---|
| 93 | |
|---|
| 94 | def test4(self): |
|---|
| 95 | self.dumpTest( |
|---|
| 96 | { |
|---|
| 97 | 'foo': 3, |
|---|
| 98 | 'fruits': ['apple', 'orange'] |
|---|
| 99 | }, |
|---|
| 100 | """ |
|---|
| 101 | --- |
|---|
| 102 | foo: 3 |
|---|
| 103 | fruits: |
|---|
| 104 | - apple |
|---|
| 105 | - orange |
|---|
| 106 | """ |
|---|
| 107 | ) |
|---|
| 108 | |
|---|
| 109 | def testTuple(self): |
|---|
| 110 | self.dumpTest( |
|---|
| 111 | { |
|---|
| 112 | 'foo': 3, |
|---|
| 113 | 'fruits': ('apple', 'orange') |
|---|
| 114 | }, |
|---|
| 115 | """ |
|---|
| 116 | --- |
|---|
| 117 | foo: 3 |
|---|
| 118 | fruits: |
|---|
| 119 | - apple |
|---|
| 120 | - orange |
|---|
| 121 | """ |
|---|
| 122 | ) |
|---|
| 123 | |
|---|
| 124 | def testMultiLineBlock(self): |
|---|
| 125 | self.dumpTest( |
|---|
| 126 | { |
|---|
| 127 | 'foo': "a\nb\nc\n", |
|---|
| 128 | }, |
|---|
| 129 | """ |
|---|
| 130 | --- |
|---|
| 131 | foo: | |
|---|
| 132 | a |
|---|
| 133 | b |
|---|
| 134 | c |
|---|
| 135 | """ |
|---|
| 136 | ) |
|---|
| 137 | |
|---|
| 138 | def testDoubleQuote(self): |
|---|
| 139 | assertEquals(doubleUpQuotes("foo'bar"), "foo''bar") |
|---|
| 140 | assertEquals(doubleUpQuotes("''x'"), "''''x''") |
|---|
| 141 | |
|---|
| 142 | def testQuotingRules(self): |
|---|
| 143 | # Raw: |
|---|
| 144 | self.assertEquals(dump(None), "--- ~\n") |
|---|
| 145 | self.assertEquals(dump('simple'), "--- simple\n") |
|---|
| 146 | self.assertEquals(dump(''), "--- ''\n") |
|---|
| 147 | self.assertEquals(dump('two words'), "--- two words\n") |
|---|
| 148 | self.assertEquals(dump('single\'quote'), "--- single'quote\n") |
|---|
| 149 | self.assertEquals(dump('5.2'), "--- '5.2'\n") |
|---|
| 150 | self.assertEquals(dump(5.2), "--- 5.2\n") |
|---|
| 151 | self.assertEquals(dump(1234), "--- 1234\n") |
|---|
| 152 | self.assertEquals(dump('harmless-dash'), "--- harmless-dash\n") |
|---|
| 153 | self.assertEquals(dump('* harmless bullet'), "--- * harmless bullet\n") |
|---|
| 154 | self.dumpTest( |
|---|
| 155 | [ "a - b", "another-harmless-dash" ], |
|---|
| 156 | """ |
|---|
| 157 | --- |
|---|
| 158 | - a - b |
|---|
| 159 | - another-harmless-dash |
|---|
| 160 | """) |
|---|
| 161 | # Single Quoted: |
|---|
| 162 | self.assertEquals(dump(''), "--- ''\n") |
|---|
| 163 | self.assertEquals(dump('4.3.1.5.2'), "--- '4.3.1.5.2'\n") |
|---|
| 164 | self.assertEquals(dump("'leading quote"), '--- "\'leading quote"\n') |
|---|
| 165 | self.assertEquals(dump('4.3.'), "--- '4.3.'\n") |
|---|
| 166 | self.assertEquals(dump('12345'), "--- '12345'\n") |
|---|
| 167 | self.assertEquals(dump('-12345'), "--- '-12345'\n") |
|---|
| 168 | self.assertEquals(dump('key: value'), "--- 'key: value'\n") |
|---|
| 169 | self.assertEquals(dump('ending colon:'), "--- 'ending colon:'\n") |
|---|
| 170 | self.assertEquals(dump('&foo'), "--- '&foo'\n") |
|---|
| 171 | self.assertEquals(dump(' xx'), "--- ' xx'\n") |
|---|
| 172 | self.assertEquals(dump('*bar'), "--- '*bar'\n") |
|---|
| 173 | assertEquals(dump('"middle \'quote'), '--- \'"middle \'\'quote\'\n') |
|---|
| 174 | # Double quoted: |
|---|
| 175 | self.assertEquals(dump("\thas a tab"), "--- \"\\thas a tab\"\n") |
|---|
| 176 | self.dumpTest( |
|---|
| 177 | { "key: quote": 'normal value' }, |
|---|
| 178 | """ |
|---|
| 179 | --- |
|---|
| 180 | 'key: quote': normal value |
|---|
| 181 | """) |
|---|
| 182 | |
|---|
| 183 | def testArrayWithSingleQuoted(self): |
|---|
| 184 | self.dumpTest( |
|---|
| 185 | [ 'foo:', {'bar': 'colon:'}], |
|---|
| 186 | """ |
|---|
| 187 | --- |
|---|
| 188 | - 'foo:' |
|---|
| 189 | - |
|---|
| 190 | bar: 'colon:' |
|---|
| 191 | """ |
|---|
| 192 | ) |
|---|
| 193 | |
|---|
| 194 | def testDumpObject(self): |
|---|
| 195 | sample = SampleClass() |
|---|
| 196 | self.dumpTest(sample, |
|---|
| 197 | sample.expected(sample.__module__, 'SampleClass')) |
|---|
| 198 | |
|---|
| 199 | def testWithSpuriousToYaml(self): |
|---|
| 200 | class ClassWithSpuriousToYaml(SampleClass): |
|---|
| 201 | to_yaml = 1 # Shouldn't get invoked |
|---|
| 202 | x = ClassWithSpuriousToYaml() |
|---|
| 203 | self.dumpTest(x, |
|---|
| 204 | x.expected(x.__module__,'ClassWithSpuriousToYaml')) |
|---|
| 205 | |
|---|
| 206 | def testNormalToYamlUse(self): |
|---|
| 207 | class NormalYamlUse(SampleClass): |
|---|
| 208 | def to_yaml(self): |
|---|
| 209 | dict = {} |
|---|
| 210 | dict['bar'] = self.foo * 2 |
|---|
| 211 | return (dict, None) |
|---|
| 212 | self.dumpTest(NormalYamlUse(), |
|---|
| 213 | """ |
|---|
| 214 | --- |
|---|
| 215 | bar: 6 |
|---|
| 216 | """) |
|---|
| 217 | |
|---|
| 218 | def testDumpingPrivateTypes(self): |
|---|
| 219 | class Foobar(SampleClass): |
|---|
| 220 | def to_yaml(self): |
|---|
| 221 | dict = {'foo': 'bar'} |
|---|
| 222 | return (dict, '!!foobar') |
|---|
| 223 | self.dumpTest(Foobar(), |
|---|
| 224 | """ |
|---|
| 225 | --- !!foobar |
|---|
| 226 | foo: bar |
|---|
| 227 | """) |
|---|
| 228 | class OddList(SampleClass): |
|---|
| 229 | def to_yaml(self): |
|---|
| 230 | return ([1, 3, 5], '!!oddlist') |
|---|
| 231 | self.dumpTest(OddList(), |
|---|
| 232 | """ |
|---|
| 233 | --- !!oddlist |
|---|
| 234 | - 1 |
|---|
| 235 | - 3 |
|---|
| 236 | - 5 |
|---|
| 237 | """) |
|---|
| 238 | |
|---|
| 239 | |
|---|
| 240 | def testToYamlShouldBeAllowedToThrowIfItWants(self): |
|---|
| 241 | class ThrowsInsideToYaml: |
|---|
| 242 | def to_yaml(self): |
|---|
| 243 | raise SampleException('bla') |
|---|
| 244 | caught_exception = 'undef' |
|---|
| 245 | try: |
|---|
| 246 | dump(ThrowsInsideToYaml()) |
|---|
| 247 | except Exception, e: |
|---|
| 248 | caught_exception = e |
|---|
| 249 | self.assertEquals('bla', caught_exception.args) |
|---|
| 250 | |
|---|
| 251 | def testObjectWithListOfClasses(self): |
|---|
| 252 | class Foo: |
|---|
| 253 | def __init__(self, items): |
|---|
| 254 | self.items = items |
|---|
| 255 | |
|---|
| 256 | class Bar: |
|---|
| 257 | def __init__(self, data): |
|---|
| 258 | self.data = data |
|---|
| 259 | |
|---|
| 260 | foo = Foo([Bar('apple'), Bar('banana')]) |
|---|
| 261 | mod = foo.__module__ # depends where called |
|---|
| 262 | self.dumpTest(foo, |
|---|
| 263 | """ |
|---|
| 264 | --- !!%s.Foo |
|---|
| 265 | items: |
|---|
| 266 | - !!%s.Bar |
|---|
| 267 | data: apple |
|---|
| 268 | - !!%s.Bar |
|---|
| 269 | data: banana |
|---|
| 270 | """ % (mod, mod, mod)) |
|---|
| 271 | |
|---|
| 272 | def testHasMethod(self): |
|---|
| 273 | class ClassWithMethodA: |
|---|
| 274 | b = 1 |
|---|
| 275 | def a(): pass |
|---|
| 276 | |
|---|
| 277 | sc = ClassWithMethodA() |
|---|
| 278 | self.assertEquals(1, hasMethod(sc, 'a')) |
|---|
| 279 | self.assertEquals(0, hasMethod(sc, 'b')) |
|---|
| 280 | |
|---|
| 281 | def testComplexKey(self): |
|---|
| 282 | self.dumpTest( {(3,4): 4}, |
|---|
| 283 | """ |
|---|
| 284 | --- |
|---|
| 285 | ? |
|---|
| 286 | - 3 |
|---|
| 287 | - 4 |
|---|
| 288 | : 4 |
|---|
| 289 | """) |
|---|
| 290 | |
|---|
| 291 | def testApostrophe(self): |
|---|
| 292 | self.dumpTest( "Joe's hot dogs.\n", |
|---|
| 293 | """ |
|---|
| 294 | --- | |
|---|
| 295 | Joe's hot dogs. |
|---|
| 296 | """) |
|---|
| 297 | |
|---|
| 298 | def testCustomIndent(self): |
|---|
| 299 | self.assertEquals( |
|---|
| 300 | yaml.Dumper().setIndent('xx').dump( |
|---|
| 301 | { |
|---|
| 302 | 'foo': 3, |
|---|
| 303 | 'fruits': ('apple', 'orange') |
|---|
| 304 | }, |
|---|
| 305 | ), |
|---|
| 306 | flushLeft( |
|---|
| 307 | """ |
|---|
| 308 | --- |
|---|
| 309 | foo: 3 |
|---|
| 310 | fruits: |
|---|
| 311 | xx- apple |
|---|
| 312 | xx- orange |
|---|
| 313 | """ |
|---|
| 314 | ) |
|---|
| 315 | ) |
|---|
| 316 | |
|---|
| 317 | def testUnicode(self): |
|---|
| 318 | if YamlTest.hasUnicode: |
|---|
| 319 | self.dumpTest({'foo': u"Foo\u263A"}, |
|---|
| 320 | r""" |
|---|
| 321 | --- |
|---|
| 322 | foo: "Foo\u263a" |
|---|
| 323 | """) |
|---|
| 324 | |
|---|
| 325 | def testTab(self): |
|---|
| 326 | self.dumpTest({'tab': "foo\tbar"}, |
|---|
| 327 | r""" |
|---|
| 328 | --- |
|---|
| 329 | tab: "foo\tbar" |
|---|
| 330 | """) |
|---|
| 331 | |
|---|
| 332 | def testIsMulti(self): |
|---|
| 333 | self.failUnless(isMulti("foo\nbar")) |
|---|
| 334 | self.failIf(isMulti("foobar")) |
|---|
| 335 | self.failIf(isMulti("line\twith tab\nsecond line")) |
|---|
| 336 | self.failUnless(isMulti("foo\\slash\nbar")) |
|---|
| 337 | |
|---|
| 338 | def testHasSpecialChar(self): |
|---|
| 339 | self.failUnless(hasSpecialChar("foo\tbar")) |
|---|
| 340 | self.failIf(hasSpecialChar("foobar")) |
|---|
| 341 | |
|---|
| 342 | def testTabs(self): |
|---|
| 343 | self.dumpTest({'control': "\b1998\t1999\t2000\n"}, |
|---|
| 344 | r""" |
|---|
| 345 | --- |
|---|
| 346 | control: "\b1998\t1999\t2000\n" |
|---|
| 347 | """) |
|---|
| 348 | |
|---|
| 349 | def test12345(self): |
|---|
| 350 | self.dumpTest({'foo': 12345, 'bar': '12345'}, |
|---|
| 351 | r""" |
|---|
| 352 | --- |
|---|
| 353 | bar: '12345' |
|---|
| 354 | foo: 12345 |
|---|
| 355 | """) |
|---|
| 356 | |
|---|
| 357 | def testDataThatsCoincidentallyTheSame(self): |
|---|
| 358 | self.dumpTest([ {'foo': 'bar'}, {'foo': 'bar'} ], |
|---|
| 359 | """ |
|---|
| 360 | --- |
|---|
| 361 | - |
|---|
| 362 | foo: bar |
|---|
| 363 | - |
|---|
| 364 | foo: bar |
|---|
| 365 | """) |
|---|
| 366 | |
|---|
| 367 | def testAliasClass(self): |
|---|
| 368 | dup = {'foo': 'bar'} |
|---|
| 369 | dupList = [dup, dup] |
|---|
| 370 | myAnchors = YamlAnchors(dupList) |
|---|
| 371 | self.assertEquals(id(dup), myAnchors._anchorVisits.keys()[0]) |
|---|
| 372 | self.assertEquals(0,myAnchors.isAlias(dup)) |
|---|
| 373 | self.assertEquals(1,myAnchors.shouldAnchor(dup) ) |
|---|
| 374 | self.assertEquals(0,myAnchors.shouldAnchor('bar')) |
|---|
| 375 | self.assertEquals(0,myAnchors.shouldAnchor(dup['foo'])) |
|---|
| 376 | self.assertEquals(0,myAnchors.shouldAnchor(dup)) |
|---|
| 377 | self.assertEquals(1,myAnchors.isAlias(dup)) |
|---|
| 378 | |
|---|
| 379 | def testAliases(self): |
|---|
| 380 | dup = {'foo': 'bar'} |
|---|
| 381 | self.dumpTest([dup, dup], |
|---|
| 382 | """ |
|---|
| 383 | --- |
|---|
| 384 | - &1 |
|---|
| 385 | foo: bar |
|---|
| 386 | - *1 |
|---|
| 387 | """) |
|---|
| 388 | |
|---|
| 389 | def testHashAlias(self): |
|---|
| 390 | dup = {} |
|---|
| 391 | dup['foo'] = dup |
|---|
| 392 | self.dumpTest(dup, |
|---|
| 393 | """ |
|---|
| 394 | --- &1 |
|---|
| 395 | foo: *1 |
|---|
| 396 | """) |
|---|
| 397 | |
|---|
| 398 | def testEmptyArray(self): |
|---|
| 399 | self.dumpTest([], |
|---|
| 400 | """ |
|---|
| 401 | --- [] |
|---|
| 402 | """) |
|---|
| 403 | |
|---|
| 404 | def testEmptyHash(self): |
|---|
| 405 | self.dumpTest({}, |
|---|
| 406 | """ |
|---|
| 407 | --- {} |
|---|
| 408 | """) |
|---|
| 409 | |
|---|
| 410 | def testEmptyHashAsHashKey(self): |
|---|
| 411 | self.dumpTest({'foo': {} }, |
|---|
| 412 | """ |
|---|
| 413 | --- |
|---|
| 414 | foo: {} |
|---|
| 415 | """) |
|---|
| 416 | |
|---|
| 417 | def testEmptyArrrayAsHashKey(self): |
|---|
| 418 | self.dumpTest({'foo': [] }, |
|---|
| 419 | """ |
|---|
| 420 | --- |
|---|
| 421 | foo: [] |
|---|
| 422 | """) |
|---|
| 423 | |
|---|
| 424 | def testAliasNone(self): |
|---|
| 425 | foo = None |
|---|
| 426 | self.dumpTest([foo, foo, foo], |
|---|
| 427 | """ |
|---|
| 428 | --- |
|---|
| 429 | - ~ |
|---|
| 430 | - ~ |
|---|
| 431 | - ~ |
|---|
| 432 | """) |
|---|
| 433 | |
|---|
| 434 | def testDumpMany(self): |
|---|
| 435 | assertEquals( |
|---|
| 436 | yaml.dump({'foo': 1}, ['a', 'b', 'c']), |
|---|
| 437 | flushLeft( |
|---|
| 438 | """ |
|---|
| 439 | --- |
|---|
| 440 | foo: 1 |
|---|
| 441 | --- |
|---|
| 442 | - a |
|---|
| 443 | - b |
|---|
| 444 | - c |
|---|
| 445 | """)) |
|---|
| 446 | |
|---|
| 447 | def testDumpExtraNewLines(self): |
|---|
| 448 | self.dumpTest( "Joe's hot dogs.\n\n", |
|---|
| 449 | """ |
|---|
| 450 | --- |+ |
|---|
| 451 | Joe's hot dogs. |
|---|
| 452 | |
|---|
| 453 | """) |
|---|
| 454 | |
|---|
| 455 | |
|---|
| 456 | def testDumpExtraNewLinesInDict(self): |
|---|
| 457 | data = {'preserving': "extra new lines are kept\n\n\n"} |
|---|
| 458 | self.dumpTest(data, |
|---|
| 459 | """ |
|---|
| 460 | --- |
|---|
| 461 | preserving: |+ |
|---|
| 462 | extra new lines are kept |
|---|
| 463 | |
|---|
| 464 | |
|---|
| 465 | """) |
|---|
| 466 | |
|---|
| 467 | if __name__ == '__main__': |
|---|
| 468 | import unittest |
|---|
| 469 | unittest.main() |
|---|