Prepare for Github,
[pylit.git] / doc / examples / pylit_test.py.txt
blob45514950cf3a53380998d2f7e054aa8db25c4172
1 ..  #!/usr/bin/env python
2   # -*- coding: iso-8859-1 -*-
3   
4 pylit_test.py 
5 *************
6 Test pylit.py Python Module
7 +++++++++++++++++++++++++++
9 :Date:      $Date: 2007-05-17 $
10 :Version:   SVN-Revision $Revision: 45 $
11 :URL:       $URL: svn+ssh://svn.berlios.de/svnroot/repos/pylit/trunk/test/pylit_test.py $
12 :Copyright: 2006 Guenter Milde.
13             Released under the terms of the GNU General Public License
14             (v. 2 or later)
16 .. contents::
19 A catalogue of errors
20 =====================
22 from file:///home/milde/Texte/Doc/Programmierung/Software-Carpentry/lec/unit.html
24 * Numbers: zero, largest, smallest magnitude, most negative
25 * Structures: empty, exactly one element, maximum number of elements
26   - Duplicate elements (e.g., letter "J" appears three times in a string)
27   - Aliased elements (e.g., a list contains two references to another list)
28   - Circular structures (e.g., a list that contains a reference to itself)
29 * Searching: no match found, one match found, multiple matches found, 
30   everything matches
31   - Code like x = find_all(structure)[0] is almost always wrong
32   - Should also check aliased matches (same thing found multiple times)
36   """pylit_test.py: test the "literal python" module"""
37   
38   from pprint import pprint
39   import operator
40   from pylit import *
41   import nose
42   
43 Text <-> Code conversion
44 ========================
46 Test strings
47 ============
49 Example of text, code and stripped code with typical features"::
51   text = """..  #!/usr/bin/env python
52     # -*- coding: iso-8859-1 -*-
53     
54   Leading text
55   
56   in several paragraphs followed by a literal block::
57   
58     block1 = 'first block'
59     
60   Some more text and the next block. ::
61   
62     block2 = 'second block'
63     print block1, block2
64     
65   Trailing text.
66   """
67   # print text
68   
69 The converter expects the data in separate lines (iterator or list)
70 with trailing newlines. We use the `splitlines` string method with
71 `keepends=True`::
73   textdata = text.splitlines(True)
74   # print textdata
75   
76 If a "code" source is converted with the `strip` option, only text blocks
77 are extracted, which leads to::
79   stripped_text = """Leading text
80   
81   in several paragraphs followed by a literal block:
82   
83   Some more text and the next block.
84   
85   Trailing text.
86   """
87   
88 The code corresponding to the text test string.
90 Using a triple-quoted string for the code (and stripped_code) can create
91 problems with the conversion of this test by pylit (as the text parts
92 would be converted to text).  
93 A workaround is using a different comment string for the text blocks and
94 converting with e.g. ``pylit --comment-string='## ' pylit_test.py``.
98   code = """#!/usr/bin/env python
99   # -*- coding: iso-8859-1 -*-
100   
101   # Leading text
102   # 
103   # in several paragraphs followed by a literal block::
104   
105   block1 = 'first block'
106   
107   # Some more text and the next block. ::
108   
109   block2 = 'second block'
110   print block1, block2
111   
112   # Trailing text.
113   """
114   # print code
115   
116   codedata = code.splitlines(True)
117   
118 Converting the text teststring with the `strip` option leads to::
120   stripped_code = """#!/usr/bin/env python
121   # -*- coding: iso-8859-1 -*-
122   
123   block1 = 'first block'
124   
125   block2 = 'second block'
126   print block1, block2
127   
128   """
129   
130 pprint(textdata)
131 pprint(stripped_code.splitlines(True))
133 Containers for special case examples:
135 1. Text2Code samples
136 ``textsamples["what"] = (<text data>, <output>, <output (with `strip`)``
139   textsamples = {}
140   
141 2. Code2Text samples
142 ``codesamples["what"] = (<code data>, <output>, <output (with `strip`)``
145   codesamples = {}
146   
147 Auxiliary function to test the textsamples and codesamples::
149   def check_converter(key, converter, output):
150       print "E:", key
151       extract = converter()
152       print(extract)
153       outstr = "".join(extract)
154       print "soll:", repr(output)
155       print "ist: ", repr(outstr)
156       assert output == outstr
157   
158 Test generator for textsample tests::
160   def test_Text2Code_samples():
161       for key, sample in textsamples.iteritems():
162           yield (check_converter, key,
163                  Text2Code(sample[0].splitlines(True)), sample[1])
164           if len(sample) == 3:
165               yield (check_converter, key,
166                      Text2Code(sample[0].splitlines(True), strip=True),
167                      sample[2])
168   
169 Test generator for codesample tests::
171   def test_Code2Text_samples():
172       for key, sample in codesamples.iteritems():
173           yield (check_converter, key,
174                  Code2Text(sample[0].splitlines(True)), sample[1])
175           if len(sample) == 3:
176               yield (check_converter, key,
177                      Code2Text(sample[0].splitlines(True), strip=True),
178                      sample[2])
179   
180   
181 Pre and postprocessing filters (for testing the filter hooks)
185   def r2l_filter(data):
186       print "applying r2l filter"
187       for line in data:
188           yield line.replace("r", "l")
189   
192   defaults.preprocessors["rl2text"] = r2l_filter
193   
196   def l2r_filter(data):
197       print "applying l2r filter"
198       for line in data:
199           yield line.replace("l", "r")
200   
203   defaults.preprocessors["text2rl"] = l2r_filter
204   
207   def x2u_filter(data):
208       print "applying x2u filter"
209       for line in data:
210           yield line.replace("x", "u")
211   
214   defaults.postprocessors["x2text"] = x2u_filter
215   
218   def u2x_filter(data):
219       print "applying u2x filter"
220       for line in data:
221           yield line.replace("u", "x")
222   
225   defaults.postprocessors["text2x"] = u2x_filter
226   
229   def test_x2u_filter():
230       soll = text.replace("x", "u")
231       result = "".join([line for line in x2u_filter(textdata)])
232       print "soll", repr(text)
233       print "ist", repr(result)
234       assert soll == result
235   
236   
237   
238 TextCodeConverter
239 =================
243   class test_TextCodeConverter(object):
244       """Test the TextCodeConverter parent class
245       """
246       
249       def check_marker_regexp_true(self, sample, converter):
250           match = converter.marker_regexp.search(sample)
251           print 'marker: %r; sample %r' %(converter.code_block_marker, sample)
252           print 'match %r'%match
253           assert match is not None
254   
257       def check_marker_regexp_false(self, sample, converter):
258           print 'marker: %r; sample %r' %(converter.code_block_marker, sample)
259           assert converter.marker_regexp.search(sample) is None
260           
263       def test_marker_regexp(self):
264           # Samples
265           literal = ['::',
266                      '  ::',
267                      't ::',
268                      'text::',
269                      ' indented::',
270                      ' indented ::',
271                      'more text :: ',
272                      ' indented text :: ',
273                      '. no-directive::',
274                      'a .. directive:: somewhere::']
275           directives = ['.. code-block:: python',
276                        '  .. code-block:: python',
277                        '.. code-block:: python listings',
278                        '  .. code-block:: python listings']
279           misses = ['.. comment string ::',
280                     '.. ::',
281                     'text:']
282           # default code_block_marker ('::')
283           self.converter = TextCodeConverter(textdata)
284           assert self.converter.code_block_marker == '::'
285           # self.converter is not seen by the check_marker_regexp_true() method
286           for sample in literal:
287               yield (self.check_marker_regexp_true, sample, self.converter)
288           for sample in directives+misses:
289               yield (self.check_marker_regexp_false, sample, self.converter)
290           # code-block directive as marker
291           self.converter = TextCodeConverter(textdata, 
292                                              code_block_marker='.. code-block::')
293           assert self.converter.code_block_marker == '.. code-block::'
294           for sample in directives:
295               yield (self.check_marker_regexp_true, sample, self.converter)
296           for sample in literal+misses:
297               yield (self.check_marker_regexp_false, sample, self.converter)
298           
301       def test_get_indent(self):
302           converter = TextCodeConverter(textdata)        
303           assert converter.get_indent("foo") == 0
304           assert converter.get_indent(" foo") == 1
305           assert converter.get_indent("  foo") == 2
306       
309       def test_collect_blocks(self):
310           converter = TextCodeConverter(textdata)
311           textblocks = [block for block in collect_blocks(textdata)]
312           print textblocks
313           assert len(textblocks) == 7, "text sample has 7 blocks"
314           assert reduce(operator.__add__, textblocks) == textdata
315   
316 Text2Code
317 =========
321   class test_Text2Code(object):
322       """Test the Text2Code class converting rst->code"""
323   
326       def setUp(self):
327           self.converter = Text2Code(textdata)
328   
329 test helper funs ::
331       def test_set_state_empty(self):
332           try:
333               self.converter.set_state([])
334               raise AssertionError, "should raise StopIteration"
335           except StopIteration:
336               pass
337   
338       def test_set_state_header(self):
339           """test for "header" or "documentation" for first block"""
340           self.converter.state = "" # normally set by the `convert` method
341           self.converter.set_state([".. header", " block"])
342           assert self.converter.state == "header"
343           self.converter.state = "" # normally set by the `convert` method
344           self.converter.set_state(["documentation", "block"])
345           assert self.converter.state == "documentation"
346   
347       def test_set_state_code_block(self):
348           """test for "header" or "documentation" for "code_block" """
349           # normally set by the `convert` method
350           self.converter._textindent = 0
351           self.converter.state = "code_block"
352           self.converter.set_state(["documentation", "  block"])
353           assert self.converter.state == "documentation"
354   
355           self.converter.state = "code_block"
356           self.converter.set_state(["  documentation", "block"])
357           assert self.converter.state == "documentation"
358           
359           self.converter.state = "code_block"
360           self.converter.set_state(["  code", "  block"])
361           print self.converter.state
362           assert self.converter.state == "code_block"
363   
364       def test_header_handler(self):
365           """should strip header-string from header"""
366           self.converter._codeindent = 0
367           sample = [".. header", " block"]
368           lines = [line for line in self.converter.header_handler(sample)]
369           print lines
370           assert lines == ["header", "block"]
371   
372       def test_documentation_handler(self):
373           """should add comment string to documentation"""
374           sample = ["doc", "block", ""]
375           lines = [line for line 
376                     in self.converter.documentation_handler(sample)]
377           print lines
378           assert lines == ["# doc", "# block", "# "]
379       
380       def test_documentation_handler_set_state(self):
381           """should add comment string to documentation"""
382           sample = ["doc", "block::", ""]
383           lines = [line for line 
384                     in self.converter.documentation_handler(sample)]
385           print lines
386           assert lines == ["# doc", "# block::", ""]
387           assert self.converter.state == "code_block"
388           
389       def test_code_block_handler(self):
390           """should un-indent code-blocks"""
391           self.converter._codeindent = 0 # normally set in `convert`
392           sample = ["  code", "  block", ""]
393           lines = [line for line 
394                     in self.converter.code_block_handler(sample)]
395           print lines
396           assert lines == ["code", "block", ""]
397       
398       
399 base tests on the "long" test data ::
401       def test_call(self):
402           """Calling a Text2Code instance should return the converted data as list of lines"""
403           output = self.converter()
404           print repr(codedata)
405           print repr(output)
406           assert codedata == output
407           
408       def test_call_strip(self):
409           """strip=True should strip text parts"""
410           self.converter.strip = True
411           output = self.converter()
412           print repr(stripped_code.splitlines(True))
413           print repr(output)
414           assert stripped_code.splitlines(True) == output
415           
416       def test_str(self):
417           outstr = str(self.converter)
418           print repr(code)
419           print repr(outstr)
420           assert code == outstr
421   
422       def test_str_strip1(self):
423           """strip=True should strip text parts.
424           
425           Version 1 with `strip` given as optional argument"""
426           outstr = str(Text2Code(textdata, strip=True))
427           print "ist ", repr(outstr)
428           print "soll", repr(stripped_code)
429           # pprint(outstr)
430           assert stripped_code == outstr
431       
432       def test_str_strip2(self):
433           """strip=True should strip text parts 
434           
435           Version 2 with `strip` set after instantiation"""
436           self.converter.strip = True
437           outstr = str(self.converter)
438           print "ist ", repr(outstr)
439           print "soll", repr(stripped_code)
440           # pprint(outstr)
441           assert stripped_code == outstr
442       
443       def test_malindented_code_line(self):
444           """raise error if code line is less indented than code-indent"""
445           data1 = ["..    #!/usr/bin/env python\n", # indent == 4 * " "
446                   "\n",
447                   "  print 'hello world'"]          # indent == 2 * " "
448           data2 = ["..\t#!/usr/bin/env python\n",   # indent == 8 * " "
449                   "\n",
450                   "  print 'hello world'"]          # indent == 2 * " "
451           for data in (data1, data2):
452               try:
453                   blocks = Text2Code(data)()
454                   assert False, "wrong indent did not raise ValueError"
455               except ValueError:
456                   pass
457       
458       def test_str_different_comment_string(self):
459           """Convert only comments with the specified comment string to text
460           """
461           data = ["..  #!/usr/bin/env python\n",
462                   '\n',
463                   '::\n',  # leading code block as header
464                   '\n',
465                   "  block1 = 'first block'\n",
466                   '  \n',
467                   'more text']
468           soll = "\n".join(["#!/usr/bin/env python",
469                             "",
470                             "##::",
471                             "",
472                             "block1 = 'first block'",
473                             "",
474                             "##more text"]
475                           )
476           outstr = str(Text2Code(data, comment_string="##"))
477           print "soll:", repr(soll)
478           print "ist: ", repr(outstr)
479           assert outstr == soll
480           
481       # Filters: test pre- and postprocessing of data
482       
483       def test_get_filter_preprocessor(self):
484           """should return filter from filter_set for language"""
485           preprocessor = self.converter.get_filter("preprocessors", "rl")
486           print preprocessor
487           assert preprocessor == l2r_filter
488   
489       def test_get_filter_postprocessor(self):
490           """should return filter from filter_set for language"""
491           postprocessor = self.converter.get_filter("postprocessors", "x")
492           print postprocessor
493           assert postprocessor == u2x_filter
494   
495       def test_get_css_postprocessor(self):
496           """should return filter from filter_set for language"""
497           postprocessor = self.converter.get_filter("postprocessors", "css")
498           print postprocessor
499           assert postprocessor == dumb_c_postprocessor
500           
501       def test_get_filter_nonexisting_language_filter(self):
502           """should return identity_filter if language has no filter in set"""
503           preprocessor = self.converter.get_filter("preprocessors", "foo")
504           print preprocessor
505           assert preprocessor == identity_filter
506   
507       def test_get_filter_nonexisting_filter_set(self):
508           """should return identity_filter if filter_set does not exist"""
509           processor = self.converter.get_filter("foo_filters", "foo")
510           print processor
511           assert processor == identity_filter
512           
513       def test_preprocessor(self):
514           """Preprocess data with registered preprocessor for language"""
515           output = Text2Code(textdata, language="x", comment_string="# ")()
516           soll = [line for line in u2x_filter(codedata)]
517           print "soll: ", repr(soll)
518           print "ist:  ", repr(output)
519           assert output == soll
520   
521       def test_postprocessor(self):
522           """Preprocess data with registered postprocessor for language"""
523           output = Text2Code(textdata, language="x", comment_string="# ")()
524           soll = [line for line in u2x_filter(codedata)]
525           print "soll:", repr(soll)
526           print "ist: ", repr(output)
527           assert output == soll
528   
529 Special Cases
530 -------------
532 Code follows text block without blank line
533 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
535 End of text block detected ('::') but no paragraph separator (blank line)
536 follows
538 It is an reStructuredText syntax error, if a "literal block
539 marker" is not followed by a blank line.
541 Assuming that no double colon at end of line occurs accidentally,
542 pylit could fix this and issue a warning::
544   # Do we need this feature? (Complicates code a lot)
545   # textsamples["ensure blank line after text"] = (
546   # """text followed by a literal block::
547   #   block1 = 'first block'
548   # """,
549   # """# text followed by a literal block::
550   # 
551   # block1 = 'first block'
552   # """)
553   
554 Text follows code block without blank line
555 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
557 End of code block detected (a line not more indented than the preceding text
558 block)
560 reStructuredText syntax demands a paragraph separator (blank line) before
563 Assuming that the unindent is not accidental, pylit could fix this and 
564 issues a warning::
566   # Do we need this feature? (Complicates code)
567   # textsamples["ensure blank line after code"] = (
568   # """::
569   # 
570   #   block1 = 'first block'
571   # more text
572   # """,
573   # """# ::
574   # 
575   # block1 = 'first block'
576   # 
577   # more text
578   # """)
579   
580 A double colon on a line on its own
581 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
583 As a double colon is added by the Code2Text conversion after a text block
584 (if not already present), it could be removed by the Text2Code conversion
585 to keep the source small and pretty.
587 However, this would put the text and code source line numbers out of sync,
588 which is bad for error reporting, failing doctests, and the JED editor
589 support with the `pylit_buffer()` function in
590 http://jedmodes.sourceforge.net/mode/pylit.
592 Maybe this could be left to a post-processing filter::
594   # textsamples["remove single double colon"] = (
595   #    ["text followed by a literal block\n",
596   #     "\n",
597   #     "::\n",
598   #     "\n",
599   #     "  foo = 'first'\n"]
600   #    ["", # empty header
601   #     "# text followed by a literal block\n\n",
602   #     "foo = 'first'\n"]
603   
604 header samples
605 ~~~~~~~~~~~~~~
606 Convert a leading reStructured text comment  (variant: only if there is
607 content on the first line) to a leading code block.  Return an empty list,
608 if there is no header. ::
610   textsamples["simple header"] = ("..  print 'hello world'",
611                                   "print 'hello world'")
612   
613   textsamples["no header (start with text)"] = (
614   """a classical example without header::
615   
616     print 'hello world'
617   """,
618   """# a classical example without header::
619   
620   print 'hello world'
621   """)
622   
623   
624   textsamples["no header (start with blank line)"] = (
625   """
626   a classical example without header::
627   
628     print 'hello world'
629   """,
630   """# 
631   # a classical example without header::
632   
633   print 'hello world'
634   """)
635   
636   
637   textsamples["standard header, followed by text"] = (
638   """..  #!/usr/bin/env python
639     # -*- coding: iso-8859-1 -*-
640   
641   a classical example with header::
642   
643     print 'hello world'
644   """,
645   """#!/usr/bin/env python
646   # -*- coding: iso-8859-1 -*-
647   
648   # a classical example with header::
649   
650   print 'hello world'
651   """)
652   
653   textsamples["standard header, followed by code"] = (
654   """..  #!/usr/bin/env python
655   
656     print 'hello world'
657   """,
658   """#!/usr/bin/env python
659   
660   print 'hello world'
661   """)
662   
663   textsamples["null string"] = ("", "", "")
664   
665 Code2Text
666 =========
670   class test_Code2Text(object):
671       
672       def setUp(self):
673           self.converter = Code2Text(codedata)
674       
675   ## Code2Text.strip_literal_marker
676   ## 
677   ## * strip `::`-line as well as preceding blank line if on a line on its own
678   ## * strip `::` if it is preceded by whitespace. 
679   ## * convert `::` to a single colon if preceded by text
680   ## 
681   ## ::
682       def check_strip_code_block_marker(self, sample):
683           """test Code2Text.strip_code_block_marker"""
684           ist = sample[0].splitlines(True)
685           soll = sample[1].splitlines(True)
686           print "before", ist
687           converter = Code2Text(codedata)
688           converter.strip_code_block_marker(ist)
689           print "soll:", repr(soll)
690           print "ist: ", repr(ist)
691           assert ist == soll
692   
693   
694       def test_strip_code_block_marker(self):
695           samples = (("text\n\n::\n\n", "text\n\n"),
696                      ("text\n::\n\n", "text\n\n"),
697                      ("text ::\n\n", "text\n\n"),
698                      ("text::\n\n", "text:\n\n"),
699                      ("text:\n\n", "text:\n\n"),
700                      ("text\n\n", "text\n\n"),
701                      ("text\n", "text\n")
702                      )
703           for sample in samples:
704               yield (self.check_strip_code_block_marker, sample)
705   
706 Code2Text.set_state
709       def test_set_state(self):
710           samples = (("code_block", ["code_block\n"], "code_block"),
711                      ("code_block", ["#code_block\n"], "code_block"),
712                      ("code_block", ["## code_block\n"], "code_block"),
713                      ("code_block", ["# documentation\n"], "documentation"),
714                      ("code_block", ["#  documentation\n"], "documentation"),
715                      ("code_block", ["# \n"], "documentation"),
716                      ("code_block", ["#\n"], "documentation"),
717                      ("code_block", ["\n"], "documentation"),
718                      ("", ["code_block\n"], "header"),
719                      ("", ["# documentation\n"], "documentation"),
720                      ("documentation", ["code_block\n"], "code_block"),
721                      ("documentation", ["# documentation\n"], "documentation"),
722                     )
723           print "comment string", repr(self.converter.comment_string)
724           for (old_state, lines, soll) in samples:
725               self.converter.state = old_state
726               self.converter.set_state(lines)
727               print repr(lines), "old state", old_state
728               print "soll", repr(soll), 
729               print "result", repr(self.converter.state)
730               assert soll == self.converter.state
731   
732 base tests on the "long" test strings ::
734       def test_call(self):
735           output = self.converter()
736           print repr(textdata)
737           print repr(output)
738           assert textdata == output
739   
740       def test_call_strip(self):
741           output = Code2Text(codedata, strip=True)()
742           print repr(stripped_text.splitlines(True))
743           print repr(output)
744           assert stripped_text.splitlines(True) == output
745   
746       def test_str(self):
747           """Test Code2Text class converting code->text"""
748           outstr = str(self.converter)
749           # print text
750           print "soll:", repr(text)
751           print "ist: ", repr(outstr)
752           assert text == outstr
753       
754       def test_str_strip(self):
755           """Test Code2Text class converting code->rst with strip=True
756       
757           Should strip code blocks
758           """
759           outstr = str(Code2Text(codedata, strip=True))
760           print repr(stripped_text)
761           print repr(outstr)
762           assert stripped_text == outstr
763       
764       def test_str_different_comment_string(self):
765           """Convert only comments with the specified comment string to text
766           """
767           outstr = str(Code2Text(codedata, comment_string="##", strip=True))
768           print outstr
769           assert outstr == ""
770           data = ["# ::\n",
771                   "\n",
772                   "block1 = 'first block'\n",
773                   "\n",
774                   "## more text"]
775           soll = "\n".join(['..  # ::',  # leading code block as header
776                             '  ',
777                             "  block1 = 'first block'",
778                             '  ',
779                             ' more text']   # keep space (not part of comment string)
780                           )
781           outstr = str(Code2Text(data, comment_string="##"))
782           print "soll:", repr(soll)
783           print "ist: ", repr(outstr)
784           assert outstr == soll
785   
786       def test_call_different_code_block_marker(self):
787           """recognize specified code-block marker
788           """
789           data = ["# .. code-block:: python\n",
790                   "\n",
791                   "block1 = 'first block'\n",
792                   "\n",
793                   "#  more text\n"]
794           soll = ['.. code-block:: python\n',
795                   '\n',
796                   "  block1 = 'first block'\n",
797                   '  \n',
798                   ' more text\n']   # keep space (not part of comment string)
799                   
800           converter = Code2Text(data, code_block_marker='.. code-block::')
801           output = converter()
802           print "soll:", repr(soll)
803           print "ist: ", repr(output)
804           assert output == soll
805   
806       # Filters: test pre- and postprocessing of Code2Text data conversion
807       
808       def test_get_filter_preprocessor(self):
809           """should return Code2Text preprocessor for language"""
810           preprocessor = self.converter.get_filter("preprocessors", "rl")
811           print preprocessor
812           assert preprocessor == r2l_filter
813   
814       def test_get_css_preprocessor(self):
815           """should return filter from filter_set for language"""
816           preprocessor = self.converter.get_filter("preprocessors", "css")
817           print preprocessor
818           assert preprocessor == dumb_c_preprocessor
819           
820       def test_get_filter_postprocessor(self):
821           """should return Code2Text postprocessor for language"""
822           postprocessor = self.converter.get_filter("postprocessors", "x")
823           print postprocessor
824           assert postprocessor == x2u_filter
825   
826       def test_get_filter_nonexisting_language_filter(self):
827           """should return identity_filter if language has no filter in set"""
828           preprocessor = self.converter.get_filter("preprocessors", "foo")
829           print preprocessor
830           assert preprocessor == identity_filter
831   
832       def test_get_filter_nonexisting_filter_set(self):
833           """should return identity_filter if filter_set does not exist"""
834           processor = self.converter.get_filter("foo_filters", "foo")
835           print processor
836           assert processor == identity_filter
837           
838       def test_preprocessor(self):
839           """Preprocess data with registered preprocessor for language"""
840           converter = Code2Text(codedata, language="rl", comment_string="# ")
841           print "preprocessor", converter.preprocessor
842           print "postprocessor", converter.postprocessor
843           output = converter()
844           soll = [line.replace("r", "l") for line in textdata]
845           print "ist: ", repr(output)
846           print "soll:", repr(soll)
847           assert output == soll
848   
849       def test_postprocessor(self):
850           """Postprocess data with registered postprocessor for language"""
851           output = Code2Text(codedata, language="x", comment_string="# ")()
852           soll = [line.replace("x", "u") for line in textdata]
853           print "soll:", repr(soll)
854           print "ist: ", repr(output)
855           assert output == soll
856   
857   
858 Special cases
859 -------------
861 blank comment line
862 ~~~~~~~~~~~~~~~~~~
864 Normally, whitespace in the comment string is significant, i.e. with
865 ``comment_string = "# "``, a line ``"#something\n"`` will count as code.
867 However, if a comment line is blank, trailing whitespace in the comment
868 string should be ignored, i.e. ``#\n`` is recognised as a blank text line::
870   codesamples["ignore trailing whitespace in comment string for blank line"] = (
871   """# ::
872   
873   block1 = 'first block'
874   
875   #
876   # more text
877   """,
878   """::
879   
880     block1 = 'first block'
881     
882   
883   more text
884   """)
885   
886 No blank line after text
887 ~~~~~~~~~~~~~~~~~~~~~~~~
889 If a matching comment precedes or follows a code line (i.e. any line
890 without matching comment) without a blank line in between, it counts as code
891 line.
893 This will keep small inline comments close to the code they comment on. It
894 will also keep blocks together where one commented line does not match the
895 comment string (the whole block will be kept as commented code)
898   codesamples["comment before code (without blank line)"] = (
899   """# this is text::
900   
901   # this is a comment
902   foo = 'first'
903   """,
904   """this is text::
905   
906     # this is a comment
907     foo = 'first'
908   """,
909   """this is text:
910   
911   """)
912   
913   codesamples["comment block before code (without blank line)"] = (
914   """# no text (watch the comment sign in the next line)::
915   #
916   # this is a comment
917   foo = 'first'
918   """,
919   """..  # no text (watch the comment sign in the next line)::
920     #
921     # this is a comment
922     foo = 'first'
923   """,
924   "")
925   
926   codesamples["comment after code (without blank line)"] = (
927   """# ::
928   
929   block1 = 'first block'
930   # commented code
931   
932   # text again
933   """,
934   """::
935   
936     block1 = 'first block'
937     # commented code
938     
939   text again
940   """,
941   """
942   text again
943   """)
944   
945   codesamples["comment block after code (without blank line)"] = (
946   """# ::
947   
948   block1 = 'first block'
949   # commented code
950   #
951   # still comment
952   """,
953   """::
954   
955     block1 = 'first block'
956     # commented code
957     #
958     # still comment
959   """,
960   """
961   """)
962   
963 missing literal block marker
964 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
966 If text (with matching comment string) is followed by code (line(s) without
967 matching comment string), but there is no double colon at the end, back
968 conversion would not recognise the end of text!
970 Therefore, pylit adds a paragraph containing only ``::`` -- the literal
971 block marker in expanded form. (While it would in many cases be nicer to
972 add the double colon to the last text line, this is not always valid rst
973 syntax, e.g. after a section header or a list. Therefore the automatic
974 insertion will use the save form, feel free to correct this by hand.)::
976   codesamples["insert missing double colon after text block"] = (
977   """# text followed by code without double colon
978   
979   foo = 'first'
980   """,
981   """text followed by code without double colon
982   
983   ::
984   
985     foo = 'first'
986   """,
987   """text followed by code without double colon
988   
989   """)
990   
991 header samples
992 ~~~~~~~~~~~~~~
994 Convert a header (leading code block) to a reStructured text comment. ::
996   codesamples["no matching comment, just code"] = (
997   """print 'hello world'
998   
999   print 'ende'
1000   """,
1001   """..  print 'hello world'
1002     
1003     print 'ende'
1004   """)
1005   
1006   codesamples["empty header (start with matching comment)"] = (
1007   """# a classical example without header::
1008   
1009   print 'hello world'
1010   """,
1011   """a classical example without header::
1012   
1013     print 'hello world'
1014   """,
1015   """a classical example without header:
1016   
1017   """)
1018   
1019   codesamples["standard header, followed by text"] = (
1020   """#!/usr/bin/env python
1021   # -*- coding: iso-8859-1 -*-
1022   
1023   # a classical example with header::
1024   
1025   print 'hello world'
1026   """,
1027   """..  #!/usr/bin/env python
1028     # -*- coding: iso-8859-1 -*-
1029     
1030   a classical example with header::
1031   
1032     print 'hello world'
1033   """,
1034   """a classical example with header:
1035   
1036   """)
1037   
1038   codesamples["standard header, followed by code"] = (
1039   """#!/usr/bin/env python
1040   
1041   print 'hello world'
1042   """,
1043   """..  #!/usr/bin/env python
1044     
1045     print 'hello world'
1046   """,
1047   "")
1048   
1049   
1050 Filter tests
1051 ============
1055   css_code = ['/* import the default Docutils style sheet */\n',
1056               '/* --------------------------------------- */\n',
1057               '\n',
1058               '/* :: */\n',
1059               '\n',
1060               '/*comment*/\n',
1061               '@import url("html4css1.css"); /* style */\n']
1062               
1065   css_filtered_code = ['// import the default Docutils style sheet\n',
1066                        '// ---------------------------------------\n',
1067                        '\n',
1068                        '// ::\n',
1069                        '\n',
1070                        '/*comment*/\n', 
1071                        '@import url("html4css1.css"); /* style */\n']
1072   
1075   def test_dumb_c_preprocessor():
1076       """convert `C` to `C++` comments"""
1077       output = [line for line in dumb_c_preprocessor(css_code)]
1078       print "ist:  %r"%output
1079       print "soll: %r"%css_filtered_code
1080       assert output == css_filtered_code
1081   
1084   def test_dumb_c_postprocessor():
1085       """convert `C++` to `C` comments"""
1086       output = [line for line in dumb_c_postprocessor(css_filtered_code)]
1087       print "ist:  %r"%output
1088       print "soll: %r"%css_code
1089       assert output == css_code
1090   
1091   
1092   
1095   if __name__ == "__main__":
1096       nose.runmodule() # requires nose 0.9.1
1097       sys.exit()