~kaijanmaki/+junk/indicators-ng

« back to all changes in this revision

Viewing changes to zinc/python/zinc/util/Markdown-2.6.2/tests/test_apis.py

  • Committer: Antti Kaijanmäki
  • Date: 2015-09-21 20:43:11 UTC
  • Revision ID: antti.kaijanmaki@canonical.com-20150921204311-bnmu8s14n6ovobyu
foo

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/python
 
2
"""
 
3
Python-Markdown Regression Tests
 
4
================================
 
5
 
 
6
Tests of the various APIs with the python markdown lib.
 
7
 
 
8
"""
 
9
 
 
10
from __future__ import unicode_literals
 
11
import unittest
 
12
import sys
 
13
import os
 
14
import types
 
15
import markdown
 
16
import warnings
 
17
from markdown.__main__ import parse_options
 
18
from logging import DEBUG, WARNING, CRITICAL
 
19
import yaml
 
20
import tempfile
 
21
 
 
22
PY3 = sys.version_info[0] == 3
 
23
 
 
24
 
 
25
class TestMarkdownBasics(unittest.TestCase):
 
26
    """ Tests basics of the Markdown class. """
 
27
 
 
28
    def setUp(self):
 
29
        """ Create instance of Markdown. """
 
30
        self.md = markdown.Markdown()
 
31
 
 
32
    def testBlankInput(self):
 
33
        """ Test blank input. """
 
34
        self.assertEqual(self.md.convert(''), '')
 
35
 
 
36
    def testWhitespaceOnly(self):
 
37
        """ Test input of only whitespace. """
 
38
        self.assertEqual(self.md.convert(' '), '')
 
39
 
 
40
    def testSimpleInput(self):
 
41
        """ Test simple input. """
 
42
        self.assertEqual(self.md.convert('foo'), '<p>foo</p>')
 
43
 
 
44
    def testInstanceExtension(self):
 
45
        """ Test Extension loading with a class instance. """
 
46
        from markdown.extensions.footnotes import FootnoteExtension
 
47
        markdown.Markdown(extensions=[FootnoteExtension()])
 
48
 
 
49
    def testNamedExtension(self):
 
50
        """ Test Extension loading with Name (`path.to.module`). """
 
51
        markdown.Markdown(extensions=['markdown.extensions.footnotes'])
 
52
 
 
53
    def TestNamedExtensionWithClass(self):
 
54
        """ Test Extension loading with class name (`path.to.module:Class`). """
 
55
        markdown.Markdown(extensions=['markdown.extensions.footnotes:FootnoteExtension'])
 
56
 
 
57
 
 
58
class TestBlockParser(unittest.TestCase):
 
59
    """ Tests of the BlockParser class. """
 
60
 
 
61
    def setUp(self):
 
62
        """ Create instance of BlockParser. """
 
63
        self.parser = markdown.Markdown().parser
 
64
 
 
65
    def testParseChunk(self):
 
66
        """ Test BlockParser.parseChunk. """
 
67
        root = markdown.util.etree.Element("div")
 
68
        text = 'foo'
 
69
        self.parser.parseChunk(root, text)
 
70
        self.assertEqual(
 
71
            markdown.serializers.to_xhtml_string(root),
 
72
            "<div><p>foo</p></div>"
 
73
        )
 
74
 
 
75
    def testParseDocument(self):
 
76
        """ Test BlockParser.parseDocument. """
 
77
        lines = ['#foo', '', 'bar', '', '    baz']
 
78
        tree = self.parser.parseDocument(lines)
 
79
        self.assertTrue(isinstance(tree, markdown.util.etree.ElementTree))
 
80
        self.assertTrue(markdown.util.etree.iselement(tree.getroot()))
 
81
        self.assertEqual(
 
82
            markdown.serializers.to_xhtml_string(tree.getroot()),
 
83
            "<div><h1>foo</h1><p>bar</p><pre><code>baz\n</code></pre></div>"
 
84
        )
 
85
 
 
86
 
 
87
class TestBlockParserState(unittest.TestCase):
 
88
    """ Tests of the State class for BlockParser. """
 
89
 
 
90
    def setUp(self):
 
91
        self.state = markdown.blockparser.State()
 
92
 
 
93
    def testBlankState(self):
 
94
        """ Test State when empty. """
 
95
        self.assertEqual(self.state, [])
 
96
 
 
97
    def testSetSate(self):
 
98
        """ Test State.set(). """
 
99
        self.state.set('a_state')
 
100
        self.assertEqual(self.state, ['a_state'])
 
101
        self.state.set('state2')
 
102
        self.assertEqual(self.state, ['a_state', 'state2'])
 
103
 
 
104
    def testIsSate(self):
 
105
        """ Test State.isstate(). """
 
106
        self.assertEqual(self.state.isstate('anything'), False)
 
107
        self.state.set('a_state')
 
108
        self.assertEqual(self.state.isstate('a_state'), True)
 
109
        self.state.set('state2')
 
110
        self.assertEqual(self.state.isstate('state2'), True)
 
111
        self.assertEqual(self.state.isstate('a_state'), False)
 
112
        self.assertEqual(self.state.isstate('missing'), False)
 
113
 
 
114
    def testReset(self):
 
115
        """ Test State.reset(). """
 
116
        self.state.set('a_state')
 
117
        self.state.reset()
 
118
        self.assertEqual(self.state, [])
 
119
        self.state.set('state1')
 
120
        self.state.set('state2')
 
121
        self.state.reset()
 
122
        self.assertEqual(self.state, ['state1'])
 
123
 
 
124
 
 
125
class TestHtmlStash(unittest.TestCase):
 
126
    """ Test Markdown's HtmlStash. """
 
127
 
 
128
    def setUp(self):
 
129
        self.stash = markdown.util.HtmlStash()
 
130
        self.placeholder = self.stash.store('foo')
 
131
 
 
132
    def testSimpleStore(self):
 
133
        """ Test HtmlStash.store. """
 
134
        self.assertEqual(self.placeholder, self.stash.get_placeholder(0))
 
135
        self.assertEqual(self.stash.html_counter, 1)
 
136
        self.assertEqual(self.stash.rawHtmlBlocks, [('foo', False)])
 
137
 
 
138
    def testStoreMore(self):
 
139
        """ Test HtmlStash.store with additional blocks. """
 
140
        placeholder = self.stash.store('bar')
 
141
        self.assertEqual(placeholder, self.stash.get_placeholder(1))
 
142
        self.assertEqual(self.stash.html_counter, 2)
 
143
        self.assertEqual(
 
144
            self.stash.rawHtmlBlocks,
 
145
            [('foo', False), ('bar', False)]
 
146
        )
 
147
 
 
148
    def testSafeStore(self):
 
149
        """ Test HtmlStash.store with 'safe' html. """
 
150
        self.stash.store('bar', True)
 
151
        self.assertEqual(
 
152
            self.stash.rawHtmlBlocks,
 
153
            [('foo', False), ('bar', True)]
 
154
        )
 
155
 
 
156
    def testReset(self):
 
157
        """ Test HtmlStash.reset. """
 
158
        self.stash.reset()
 
159
        self.assertEqual(self.stash.html_counter, 0)
 
160
        self.assertEqual(self.stash.rawHtmlBlocks, [])
 
161
 
 
162
    def testUnsafeHtmlInSafeMode(self):
 
163
        """ Test that unsafe HTML gets escaped in safe_mode. """
 
164
        output = markdown.markdown('foo', extensions=[self.build_extension()], safe_mode='escape')
 
165
        self.assertEqual(output, '<p>&lt;script&gt;print(&quot;evil&quot;)&lt;/script&gt;</p>')
 
166
 
 
167
    def build_extension(self):
 
168
        """ Build an extention that addes unsafe html to Stash in same_mode. """
 
169
        class Unsafe(markdown.treeprocessors.Treeprocessor):
 
170
            def run(self, root):
 
171
                el = root.find('p')
 
172
                el.text = self.markdown.htmlStash.store('<script>print("evil")</script>', safe=False)
 
173
                return root
 
174
 
 
175
        class StoreUnsafeHtml(markdown.extensions.Extension):
 
176
            def extendMarkdown(self, md, md_globals):
 
177
                md.treeprocessors.add('unsafe', Unsafe(md), '_end')
 
178
 
 
179
        return StoreUnsafeHtml()
 
180
 
 
181
 
 
182
class TestOrderedDict(unittest.TestCase):
 
183
    """ Test OrderedDict storage class. """
 
184
 
 
185
    def setUp(self):
 
186
        self.odict = markdown.odict.OrderedDict()
 
187
        self.odict['first'] = 'This'
 
188
        self.odict['third'] = 'a'
 
189
        self.odict['fourth'] = 'self'
 
190
        self.odict['fifth'] = 'test'
 
191
 
 
192
    def testValues(self):
 
193
        """ Test output of OrderedDict.values(). """
 
194
        self.assertEqual(list(self.odict.values()), ['This', 'a', 'self', 'test'])
 
195
 
 
196
    def testKeys(self):
 
197
        """ Test output of OrderedDict.keys(). """
 
198
        self.assertEqual(
 
199
            list(self.odict.keys()),
 
200
            ['first', 'third', 'fourth', 'fifth']
 
201
        )
 
202
 
 
203
    def testItems(self):
 
204
        """ Test output of OrderedDict.items(). """
 
205
        self.assertEqual(
 
206
            list(self.odict.items()), [
 
207
                ('first', 'This'),
 
208
                ('third', 'a'),
 
209
                ('fourth', 'self'),
 
210
                ('fifth', 'test')
 
211
            ]
 
212
        )
 
213
 
 
214
    def testAddBefore(self):
 
215
        """ Test adding an OrderedDict item before a given key. """
 
216
        self.odict.add('second', 'is', '<third')
 
217
        self.assertEqual(
 
218
            list(self.odict.items()), [
 
219
                ('first', 'This'),
 
220
                ('second', 'is'),
 
221
                ('third', 'a'),
 
222
                ('fourth', 'self'),
 
223
                ('fifth', 'test')
 
224
            ]
 
225
        )
 
226
 
 
227
    def testAddAfter(self):
 
228
        """ Test adding an OrderDict item after a given key. """
 
229
        self.odict.add('second', 'is', '>first')
 
230
        self.assertEqual(
 
231
            list(self.odict.items()), [
 
232
                ('first', 'This'),
 
233
                ('second', 'is'),
 
234
                ('third', 'a'),
 
235
                ('fourth', 'self'),
 
236
                ('fifth', 'test')
 
237
            ]
 
238
        )
 
239
 
 
240
    def testAddAfterEnd(self):
 
241
        """ Test adding an OrderedDict item after the last key. """
 
242
        self.odict.add('sixth', '.', '>fifth')
 
243
        self.assertEqual(
 
244
            list(self.odict.items()), [
 
245
                ('first', 'This'),
 
246
                ('third', 'a'),
 
247
                ('fourth', 'self'),
 
248
                ('fifth', 'test'),
 
249
                ('sixth', '.')
 
250
            ]
 
251
        )
 
252
 
 
253
    def testAdd_begin(self):
 
254
        """ Test adding an OrderedDict item using "_begin". """
 
255
        self.odict.add('zero', 'CRAZY', '_begin')
 
256
        self.assertEqual(
 
257
            list(self.odict.items()), [
 
258
                ('zero', 'CRAZY'),
 
259
                ('first', 'This'),
 
260
                ('third', 'a'),
 
261
                ('fourth', 'self'),
 
262
                ('fifth', 'test')
 
263
            ]
 
264
        )
 
265
 
 
266
    def testAdd_end(self):
 
267
        """ Test adding an OrderedDict item using "_end". """
 
268
        self.odict.add('sixth', '.', '_end')
 
269
        self.assertEqual(
 
270
            list(self.odict.items()), [
 
271
                ('first', 'This'),
 
272
                ('third', 'a'),
 
273
                ('fourth', 'self'),
 
274
                ('fifth', 'test'),
 
275
                ('sixth', '.')
 
276
            ]
 
277
        )
 
278
 
 
279
    def testAddBadLocation(self):
 
280
        """ Test Error on bad location in OrderedDict.add(). """
 
281
        self.assertRaises(ValueError, self.odict.add, 'sixth', '.', '<seventh')
 
282
        self.assertRaises(ValueError, self.odict.add, 'second', 'is', 'third')
 
283
 
 
284
    def testDeleteItem(self):
 
285
        """ Test deletion of an OrderedDict item. """
 
286
        del self.odict['fourth']
 
287
        self.assertEqual(
 
288
            list(self.odict.items()),
 
289
            [('first', 'This'), ('third', 'a'), ('fifth', 'test')]
 
290
        )
 
291
 
 
292
    def testChangeValue(self):
 
293
        """ Test OrderedDict change value. """
 
294
        self.odict['fourth'] = 'CRAZY'
 
295
        self.assertEqual(
 
296
            list(self.odict.items()), [
 
297
                ('first', 'This'),
 
298
                ('third', 'a'),
 
299
                ('fourth', 'CRAZY'),
 
300
                ('fifth', 'test')
 
301
            ]
 
302
        )
 
303
 
 
304
    def testChangeOrder(self):
 
305
        """ Test OrderedDict change order. """
 
306
        self.odict.link('fourth', '<third')
 
307
        self.assertEqual(
 
308
            list(self.odict.items()), [
 
309
                ('first', 'This'),
 
310
                ('fourth', 'self'),
 
311
                ('third', 'a'),
 
312
                ('fifth', 'test')
 
313
            ]
 
314
        )
 
315
 
 
316
    def textBadLink(self):
 
317
        """ Test OrderedDict change order with bad location. """
 
318
        self.assertRaises(ValueError, self.odict.link('fourth', '<bad'))
 
319
        # Check for data integrity ("fourth" wasn't deleted).'
 
320
        self.assertEqual(
 
321
            list(self.odict.items()), [
 
322
                ('first', 'This'),
 
323
                ('third', 'a'),
 
324
                ('fourth', 'self'),
 
325
                ('fifth', 'test')
 
326
            ]
 
327
        )
 
328
 
 
329
 
 
330
class TestErrors(unittest.TestCase):
 
331
    """ Test Error Reporting. """
 
332
 
 
333
    def setUp(self):
 
334
        # Set warnings to be raised as errors
 
335
        warnings.simplefilter('error')
 
336
 
 
337
    def tearDown(self):
 
338
        # Reset warning behavior back to default
 
339
        warnings.simplefilter('default')
 
340
 
 
341
    def testNonUnicodeSource(self):
 
342
        """ Test falure on non-unicode source text. """
 
343
        if sys.version_info < (3, 0):
 
344
            source = "foo".encode('utf-16')
 
345
            self.assertRaises(UnicodeDecodeError, markdown.markdown, source)
 
346
 
 
347
    def testBadOutputFormat(self):
 
348
        """ Test failure on bad output_format. """
 
349
        self.assertRaises(KeyError, markdown.Markdown, output_format='invalid')
 
350
 
 
351
    def testLoadExtensionFailure(self):
 
352
        """ Test failure of an extension to load. """
 
353
        self.assertRaises(
 
354
            ImportError,
 
355
            markdown.Markdown, extensions=['non_existant_ext']
 
356
        )
 
357
 
 
358
    def testLoadBadExtension(self):
 
359
        """ Test loading of an Extension with no makeExtension function. """
 
360
        self.assertRaises(AttributeError, markdown.Markdown, extensions=['markdown.util'])
 
361
 
 
362
    def testNonExtension(self):
 
363
        """ Test loading a non Extension object as an extension. """
 
364
        self.assertRaises(TypeError, markdown.Markdown, extensions=[object])
 
365
 
 
366
    def testBaseExtention(self):
 
367
        """ Test that the base Extension class will raise NotImplemented. """
 
368
        self.assertRaises(
 
369
            NotImplementedError,
 
370
            markdown.Markdown, extensions=[markdown.extensions.Extension()]
 
371
        )
 
372
 
 
373
    def testMdxExtention(self):
 
374
        """ Test that prepending mdx_ raises a DeprecationWarning. """
 
375
        _create_fake_extension(name='fake', use_old_style=True)
 
376
        self.assertRaises(
 
377
            DeprecationWarning,
 
378
            markdown.Markdown, extensions=['fake']
 
379
        )
 
380
 
 
381
    def testShortNameExtention(self):
 
382
        """ Test that using a short name raises a DeprecationWarning. """
 
383
        self.assertRaises(
 
384
            DeprecationWarning,
 
385
            markdown.Markdown, extensions=['footnotes']
 
386
        )
 
387
 
 
388
    def testStringConfigExtention(self):
 
389
        """ Test that passing configs to an Extension in the name raises a DeprecationWarning. """
 
390
        self.assertRaises(
 
391
            DeprecationWarning,
 
392
            markdown.Markdown, extensions=['markdown.extension.footnotes(PLACE_MARKER=FOO)']
 
393
        )
 
394
 
 
395
 
 
396
def _create_fake_extension(name, has_factory_func=True, is_wrong_type=False, use_old_style=False):
 
397
    """ Create a fake extension module for testing. """
 
398
    if use_old_style:
 
399
        mod_name = '_'.join(['mdx', name])
 
400
    else:
 
401
        mod_name = name
 
402
    if not PY3:
 
403
        # mod_name must be bytes in Python 2.x
 
404
        mod_name = bytes(mod_name)
 
405
    ext_mod = types.ModuleType(mod_name)
 
406
 
 
407
    def makeExtension(*args, **kwargs):
 
408
        if is_wrong_type:
 
409
            return object
 
410
        else:
 
411
            return markdown.extensions.Extension(*args, **kwargs)
 
412
 
 
413
    if has_factory_func:
 
414
        ext_mod.makeExtension = makeExtension
 
415
    # Warning: this brute forces the extenson module onto the system. Either
 
416
    # this needs to be specificly overriden or a new python session needs to
 
417
    # be started to get rid of this. This should be ok in a testing context.
 
418
    sys.modules[mod_name] = ext_mod
 
419
 
 
420
 
 
421
class testETreeComments(unittest.TestCase):
 
422
    """
 
423
    Test that ElementTree Comments work.
 
424
 
 
425
    These tests should only be a concern when using cElementTree with third
 
426
    party serializers (including markdown's (x)html serializer). While markdown
 
427
    doesn't use ElementTree.Comment itself, we should certainly support any
 
428
    third party extensions which may. Therefore, these tests are included to
 
429
    ensure such support is maintained.
 
430
    """
 
431
 
 
432
    def setUp(self):
 
433
        # Create comment node
 
434
        self.comment = markdown.util.etree.Comment('foo')
 
435
        if hasattr(markdown.util.etree, 'test_comment'):
 
436
            self.test_comment = markdown.util.etree.test_comment
 
437
        else:
 
438
            self.test_comment = markdown.util.etree.Comment
 
439
 
 
440
    def testCommentIsComment(self):
 
441
        """ Test that an ElementTree Comment passes the `is Comment` test. """
 
442
        self.assertTrue(self.comment.tag is markdown.util.etree.test_comment)
 
443
 
 
444
    def testCommentIsBlockLevel(self):
 
445
        """ Test that an ElementTree Comment is recognized as BlockLevel. """
 
446
        self.assertFalse(markdown.util.isBlockLevel(self.comment.tag))
 
447
 
 
448
    def testCommentSerialization(self):
 
449
        """ Test that an ElementTree Comment serializes properly. """
 
450
        self.assertEqual(
 
451
            markdown.serializers.to_html_string(self.comment),
 
452
            '<!--foo-->'
 
453
        )
 
454
 
 
455
    def testCommentPrettify(self):
 
456
        """ Test that an ElementTree Comment is prettified properly. """
 
457
        pretty = markdown.treeprocessors.PrettifyTreeprocessor()
 
458
        pretty.run(self.comment)
 
459
        self.assertEqual(
 
460
            markdown.serializers.to_html_string(self.comment),
 
461
            '<!--foo-->\n'
 
462
        )
 
463
 
 
464
 
 
465
class testElementTailTests(unittest.TestCase):
 
466
    """ Element Tail Tests """
 
467
    def setUp(self):
 
468
        self.pretty = markdown.treeprocessors.PrettifyTreeprocessor()
 
469
 
 
470
    def testBrTailNoNewline(self):
 
471
        """ Test that last <br> in tree has a new line tail """
 
472
        root = markdown.util.etree.Element('root')
 
473
        br = markdown.util.etree.SubElement(root, 'br')
 
474
        self.assertEqual(br.tail, None)
 
475
        self.pretty.run(root)
 
476
        self.assertEqual(br.tail, "\n")
 
477
 
 
478
 
 
479
class testSerializers(unittest.TestCase):
 
480
    """ Test the html and xhtml serializers. """
 
481
 
 
482
    def testHtml(self):
 
483
        """ Test HTML serialization. """
 
484
        el = markdown.util.etree.Element('div')
 
485
        p = markdown.util.etree.SubElement(el, 'p')
 
486
        p.text = 'foo'
 
487
        markdown.util.etree.SubElement(el, 'hr')
 
488
        self.assertEqual(
 
489
            markdown.serializers.to_html_string(el),
 
490
            '<div><p>foo</p><hr></div>'
 
491
        )
 
492
 
 
493
    def testXhtml(self):
 
494
        """" Test XHTML serialization. """
 
495
        el = markdown.util.etree.Element('div')
 
496
        p = markdown.util.etree.SubElement(el, 'p')
 
497
        p.text = 'foo'
 
498
        markdown.util.etree.SubElement(el, 'hr')
 
499
        self.assertEqual(
 
500
            markdown.serializers.to_xhtml_string(el),
 
501
            '<div><p>foo</p><hr /></div>'
 
502
        )
 
503
 
 
504
    def testMixedCaseTags(self):
 
505
        """" Test preservation of tag case. """
 
506
        el = markdown.util.etree.Element('MixedCase')
 
507
        el.text = 'not valid '
 
508
        em = markdown.util.etree.SubElement(el, 'EMPHASIS')
 
509
        em.text = 'html'
 
510
        markdown.util.etree.SubElement(el, 'HR')
 
511
        self.assertEqual(
 
512
            markdown.serializers.to_xhtml_string(el),
 
513
            '<MixedCase>not valid <EMPHASIS>html</EMPHASIS><HR /></MixedCase>'
 
514
        )
 
515
 
 
516
    def buildExtension(self):
 
517
        """ Build an extension which registers fakeSerializer. """
 
518
        def fakeSerializer(elem):
 
519
            # Ignore input and return hardcoded output
 
520
            return '<div><p>foo</p></div>'
 
521
 
 
522
        class registerFakeSerializer(markdown.extensions.Extension):
 
523
            def extendMarkdown(self, md, md_globals):
 
524
                md.output_formats['fake'] = fakeSerializer
 
525
 
 
526
        return registerFakeSerializer()
 
527
 
 
528
    def testRegisterSerializer(self):
 
529
        self.assertEqual(
 
530
            markdown.markdown(
 
531
                'baz', extensions=[self.buildExtension()], output_format='fake'
 
532
            ),
 
533
            '<p>foo</p>'
 
534
        )
 
535
 
 
536
 
 
537
class testAtomicString(unittest.TestCase):
 
538
    """ Test that AtomicStrings are honored (not parsed). """
 
539
 
 
540
    def setUp(self):
 
541
        md = markdown.Markdown()
 
542
        self.inlineprocessor = md.treeprocessors['inline']
 
543
 
 
544
    def testString(self):
 
545
        """ Test that a regular string is parsed. """
 
546
        tree = markdown.util.etree.Element('div')
 
547
        p = markdown.util.etree.SubElement(tree, 'p')
 
548
        p.text = 'some *text*'
 
549
        new = self.inlineprocessor.run(tree)
 
550
        self.assertEqual(
 
551
            markdown.serializers.to_html_string(new),
 
552
            '<div><p>some <em>text</em></p></div>'
 
553
        )
 
554
 
 
555
    def testSimpleAtomicString(self):
 
556
        """ Test that a simple AtomicString is not parsed. """
 
557
        tree = markdown.util.etree.Element('div')
 
558
        p = markdown.util.etree.SubElement(tree, 'p')
 
559
        p.text = markdown.util.AtomicString('some *text*')
 
560
        new = self.inlineprocessor.run(tree)
 
561
        self.assertEqual(
 
562
            markdown.serializers.to_html_string(new),
 
563
            '<div><p>some *text*</p></div>'
 
564
        )
 
565
 
 
566
    def testNestedAtomicString(self):
 
567
        """ Test that a nested AtomicString is not parsed. """
 
568
        tree = markdown.util.etree.Element('div')
 
569
        p = markdown.util.etree.SubElement(tree, 'p')
 
570
        p.text = markdown.util.AtomicString('*some* ')
 
571
        span1 = markdown.util.etree.SubElement(p, 'span')
 
572
        span1.text = markdown.util.AtomicString('*more* ')
 
573
        span2 = markdown.util.etree.SubElement(span1, 'span')
 
574
        span2.text = markdown.util.AtomicString('*text* ')
 
575
        span3 = markdown.util.etree.SubElement(span2, 'span')
 
576
        span3.text = markdown.util.AtomicString('*here*')
 
577
        span3.tail = markdown.util.AtomicString(' *to*')
 
578
        span2.tail = markdown.util.AtomicString(' *test*')
 
579
        span1.tail = markdown.util.AtomicString(' *with*')
 
580
        new = self.inlineprocessor.run(tree)
 
581
        self.assertEqual(
 
582
            markdown.serializers.to_html_string(new),
 
583
            '<div><p>*some* <span>*more* <span>*text* <span>*here*</span> '
 
584
            '*to*</span> *test*</span> *with*</p></div>'
 
585
        )
 
586
 
 
587
 
 
588
class TestConfigParsing(unittest.TestCase):
 
589
    def assertParses(self, value, result):
 
590
        self.assertTrue(markdown.util.parseBoolValue(value, False) is result)
 
591
 
 
592
    def testBooleansParsing(self):
 
593
        self.assertParses(True, True)
 
594
        self.assertParses('novalue', None)
 
595
        self.assertParses('yES', True)
 
596
        self.assertParses('FALSE', False)
 
597
        self.assertParses(0., False)
 
598
        self.assertParses('none', False)
 
599
 
 
600
    def testPreserveNone(self):
 
601
        self.assertTrue(markdown.util.parseBoolValue('None', preserve_none=True) is None)
 
602
        self.assertTrue(markdown.util.parseBoolValue(None, preserve_none=True) is None)
 
603
 
 
604
    def testInvalidBooleansParsing(self):
 
605
        self.assertRaises(ValueError, markdown.util.parseBoolValue, 'novalue')
 
606
 
 
607
 
 
608
class TestCliOptionParsing(unittest.TestCase):
 
609
    """ Test parsing of Command Line Interface Options. """
 
610
 
 
611
    def setUp(self):
 
612
        self.default_options = {
 
613
            'input': None,
 
614
            'output': None,
 
615
            'encoding': None,
 
616
            'output_format': 'xhtml1',
 
617
            'lazy_ol': True,
 
618
            'extensions': [],
 
619
            'extension_configs': {},
 
620
        }
 
621
        self.tempfile = ''
 
622
 
 
623
    def tearDown(self):
 
624
        if os.path.isfile(self.tempfile):
 
625
            os.remove(self.tempfile)
 
626
 
 
627
    def testNoOptions(self):
 
628
        options, logging_level = parse_options([])
 
629
        self.assertEqual(options, self.default_options)
 
630
        self.assertEqual(logging_level, CRITICAL)
 
631
 
 
632
    def testQuietOption(self):
 
633
        options, logging_level = parse_options(['-q'])
 
634
        self.assertTrue(logging_level > CRITICAL)
 
635
 
 
636
    def testVerboseOption(self):
 
637
        options, logging_level = parse_options(['-v'])
 
638
        self.assertEqual(logging_level, WARNING)
 
639
 
 
640
    def testNoisyOption(self):
 
641
        options, logging_level = parse_options(['--noisy'])
 
642
        self.assertEqual(logging_level, DEBUG)
 
643
 
 
644
    def testInputFileOption(self):
 
645
        options, logging_level = parse_options(['foo.txt'])
 
646
        self.default_options['input'] = 'foo.txt'
 
647
        self.assertEqual(options, self.default_options)
 
648
 
 
649
    def testOutputFileOption(self):
 
650
        options, logging_level = parse_options(['-f', 'foo.html'])
 
651
        self.default_options['output'] = 'foo.html'
 
652
        self.assertEqual(options, self.default_options)
 
653
 
 
654
    def testInputAndOutputFileOptions(self):
 
655
        options, logging_level = parse_options(['-f', 'foo.html', 'foo.txt'])
 
656
        self.default_options['output'] = 'foo.html'
 
657
        self.default_options['input'] = 'foo.txt'
 
658
        self.assertEqual(options, self.default_options)
 
659
 
 
660
    def testEncodingOption(self):
 
661
        options, logging_level = parse_options(['-e', 'utf-8'])
 
662
        self.default_options['encoding'] = 'utf-8'
 
663
        self.assertEqual(options, self.default_options)
 
664
 
 
665
    def testSafeModeOption(self):
 
666
        options, logging_level = parse_options(['-s', 'escape'])
 
667
        self.default_options['safe_mode'] = 'escape'
 
668
        self.assertEqual(options, self.default_options)
 
669
 
 
670
    def testOutputFormatOption(self):
 
671
        options, logging_level = parse_options(['-o', 'html5'])
 
672
        self.default_options['output_format'] = 'html5'
 
673
        self.assertEqual(options, self.default_options)
 
674
 
 
675
    def testNoLazyOlOption(self):
 
676
        options, logging_level = parse_options(['-n'])
 
677
        self.default_options['lazy_ol'] = False
 
678
        self.assertEqual(options, self.default_options)
 
679
 
 
680
    def testExtensionOption(self):
 
681
        options, logging_level = parse_options(['-x', 'markdown.extensions.footnotes'])
 
682
        self.default_options['extensions'] = ['markdown.extensions.footnotes']
 
683
        self.assertEqual(options, self.default_options)
 
684
 
 
685
    def testMultipleExtensionOptions(self):
 
686
        options, logging_level = parse_options([
 
687
            '-x', 'markdown.extensions.footnotes',
 
688
            '-x', 'markdown.extensions.smarty'
 
689
        ])
 
690
        self.default_options['extensions'] = [
 
691
            'markdown.extensions.footnotes',
 
692
            'markdown.extensions.smarty'
 
693
        ]
 
694
        self.assertEqual(options, self.default_options)
 
695
 
 
696
    def create_config_file(self, config):
 
697
        """ Helper to create temp config files. """
 
698
        if not isinstance(config, markdown.util.string_type):
 
699
            # convert to string
 
700
            config = yaml.dump(config)
 
701
        fd, self.tempfile = tempfile.mkstemp('.yml')
 
702
        with os.fdopen(fd, 'w') as fp:
 
703
            fp.write(config)
 
704
 
 
705
    def testExtensionConfigOption(self):
 
706
        config = {
 
707
            'markdown.extensions.wikilinks': {
 
708
                'base_url': 'http://example.com/',
 
709
                'end_url': '.html',
 
710
                'html_class': 'test',
 
711
            },
 
712
            'markdown.extensions.footnotes:FootnotesExtension': {
 
713
                'PLACE_MARKER': '~~~footnotes~~~'
 
714
            }
 
715
        }
 
716
        self.create_config_file(config)
 
717
        options, logging_level = parse_options(['-c', self.tempfile])
 
718
        self.default_options['extension_configs'] = config
 
719
        self.assertEqual(options, self.default_options)
 
720
 
 
721
    def textBoolExtensionConfigOption(self):
 
722
        config = {
 
723
            'markdown.extensions.toc': {
 
724
                'title': 'Some Title',
 
725
                'anchorlink': True,
 
726
                'permalink': True
 
727
            }
 
728
        }
 
729
        self.create_config_file(config)
 
730
        options, logging_level = parse_options(['-c', self.tempfile])
 
731
        self.default_options['extension_configs'] = config
 
732
        self.assertEqual(options, self.default_options)
 
733
 
 
734
    def testExtensonConfigOptionAsJSON(self):
 
735
        config = {
 
736
            'markdown.extensions.wikilinks': {
 
737
                'base_url': 'http://example.com/',
 
738
                'end_url': '.html',
 
739
                'html_class': 'test',
 
740
            },
 
741
            'markdown.extensions.footnotes:FootnotesExtension': {
 
742
                'PLACE_MARKER': '~~~footnotes~~~'
 
743
            }
 
744
        }
 
745
        import json
 
746
        self.create_config_file(json.dumps(config))
 
747
        options, logging_level = parse_options(['-c', self.tempfile])
 
748
        self.default_options['extension_configs'] = config
 
749
        self.assertEqual(options, self.default_options)
 
750
 
 
751
    def testExtensonConfigOptionMissingFile(self):
 
752
        self.assertRaises(IOError, parse_options, ['-c', 'missing_file.yaml'])
 
753
 
 
754
    def testExtensonConfigOptionBadFormat(self):
 
755
        config = """
 
756
[footnotes]
 
757
PLACE_MARKER= ~~~footnotes~~~
 
758
"""
 
759
        self.create_config_file(config)
 
760
        self.assertRaises(yaml.YAMLError, parse_options, ['-c', self.tempfile])