Release 0.8.0
[pylit.git] / test / pylit_ui_test.py
blob229c11a715fb0b49e2a5db9dff5c226f5e6cfc3a
1 #!/usr/bin/env python3
3 ## Test the pylit.py literal python module's user interface
4 ## ========================================================
5 ##
6 ## :Date: $Date: 2007-05-17 $
7 ## :Version: SVN-Revision $Revision: 45 $
8 ## :URL: $URL: svn+ssh://svn.berlios.de/svnroot/repos/pylit/trunk/test/pylit_ui_test.py $
9 ## :Copyright: 2006 Guenter Milde.
10 ## Released under the terms of the GNU General Public License
11 ## (v. 2 or later)
13 ## .. contents::
15 ## ::
17 """pylit_test.py: test the "literal python" module's user interface"""
19 import argparse
20 import copy
21 from pprint import pprint
23 from pylit import *
24 from pylit_test import (text, stripped_text, textdata,
25 code, stripped_code, codedata)
27 import nose
29 ## Global defaults
30 ## ===============
32 ## ::
34 def test_global_option_defaults():
35 """dictionary of programming languages and extensions"""
36 assert defaults.languages[".py"] == "python"
37 assert defaults.languages[".sl"] == "slang"
38 assert defaults.languages[".cc"] == "c++"
39 assert defaults.languages[".c"] == "c"
42 ## Command line use
43 ## ================
45 ## Test the option parsing::
47 class test_PylitOptions:
48 """Test the PylitOption class"""
49 def setUp(self):
50 self.options = PylitOptions()
52 def test_args_parsing(self):
53 """parse cmd line args with `ArgumentParser.parse_args()`"""
54 # "1st non option arg is infile, 2nd is outfile"
55 values = self.options.parser.parse_args(["--txt2code", "text.txt", "code.py"])
56 print(values.infile)
57 assert values.infile == "text.txt"
58 assert values.outfile == "code.py"
59 # option with argument
60 values = self.options.parser.parse_args(['in.py', '--language', 'slang'])
61 assert values.language == "slang"
63 def test_args_comment_string(self):
64 """command line arg should appear in values"""
65 values = self.options(['in.py', '--comment-string=% '])
66 pprint(vars(values))
67 assert values.comment_string == "% "
69 def test_args_code_block_marker(self):
70 """command line option --code-block-marker should set option value"""
71 values = self.options(['in.py', '--code-block-marker=.. test-dir::'])
72 pprint(vars(values))
73 assert values.code_block_marker == '.. test-dir::'
75 def test_get_outfile_name(self):
76 """should return a sensible outfile name given an infile name"""
77 # return stdout for stdin
78 values = copy.copy(defaults)
79 values.infile = '-'
80 assert "-" == self.options._get_outfile_name(values)
81 # return with ".txt" stripped
82 values = copy.copy(defaults)
83 values.infile = 'foo.py.txt'
84 assert "foo.py" == self.options._get_outfile_name(values)
85 # return with ".txt" added if extension marks code file
86 values = copy.copy(defaults)
87 values.infile = 'foo.py'
88 assert "foo.py.txt" == self.options._get_outfile_name(values)
89 values = copy.copy(defaults)
90 values.infile = 'foo.sl'
91 assert "foo.sl.txt" == self.options._get_outfile_name(values)
92 values = copy.copy(defaults)
93 values.infile = 'foo.c'
94 assert "foo.c.txt" == self.options._get_outfile_name(values)
95 # return with ".txt" added if txt2code == False (not None!)
96 values = copy.copy(defaults)
97 values.infile = 'foo.py'
98 values.txt2code = False
99 assert "foo.py.txt" == self.options._get_outfile_name(values)
100 # catchall: add ".out" if no other guess possible
101 values = copy.copy(defaults)
102 values.infile = 'foo'
103 values.txt2code = None
104 print(self.options._get_outfile_name(values))
105 assert "foo.out" == self.options._get_outfile_name(values)
107 def test_complete_values(self):
108 """Basic test of the option completion"""
109 values = copy.copy(defaults)
110 values.infile = "foo"
111 values = self.options.complete_values(values)
112 # the following options should be set:
113 print('txt2code after:', values.txt2code)
114 print(values.outfile)
115 assert values.outfile == "foo.out" # fallback extension .out added
116 print(values.txt2code)
117 assert values.txt2code == True # the default
118 print(values.language)
119 assert values.language == "python" # the default
121 def test_complete_values_txt(self):
122 """Test the option completion with a text input file"""
123 values = copy.copy(defaults)
124 values.infile = "foo.txt"
125 values = self.options.complete_values(values)
126 # should set outfile (see also `test_get_outfile_name`)
127 assert values.outfile == "foo"
128 # should set conversion direction according to extension
129 assert values.txt2code == True
131 def test_complete_values_code(self):
132 """Test the option completion with a code input file"""
133 values = copy.copy(defaults)
134 values.infile = "foo.py"
135 values = self.options.complete_values(values)
136 # should set outfile name
137 assert values.outfile == "foo.py.txt"
138 # should set conversion directions according to extension
139 print(values.txt2code)
140 assert values.txt2code == False, "set conversion according to extension"
142 def test_complete_values_dont_overwrite(self):
143 """The option completion must not overwrite existing option values"""
144 values = copy.copy(defaults)
145 values.infile = "foo.py"
146 values.outfile = "bar.txt"
147 values.txt2code = True
148 values = self.options.complete_values(values)
149 pprint(values)
150 assert values.outfile == "bar.txt"
151 assert values.txt2code == True
153 def test_complete_values_language_infile(self):
154 """set the language from the infile extension"""
155 values = copy.copy(defaults)
156 values.infile = "foo.cc"
157 values = self.options.complete_values(values)
158 pprint(values)
159 assert values.language == "c++"
161 def test_complete_values_language_outfile(self):
162 """set the language from the outfile extension"""
163 values = copy.copy(defaults)
164 values.txt2code = True
165 values.infile = 'in-file'
166 values.outfile = "foo.sl"
167 values = self.options.complete_values(values)
168 pprint(values)
169 assert values.language == "slang"
171 def test_complete_values_language_fallback(self):
172 """set the language from the fallback language"""
173 values = copy.copy(defaults)
174 values.infile = 'in-file' # required
175 values = self.options.complete_values(values)
176 pprint(values)
177 print("fallback language:", defaults.languages[''])
178 assert values.language == defaults.languages['']
180 def test_call(self):
181 # if setting is not specified, use fallback from module `defaults`
182 values = self.options(infile='in-file')
183 assert values.txt2code == True
184 # default should appear in options
185 values = self.options(infile='in-file', txt2code=False)
186 # print(values, type(values), dir(values))
187 assert values.txt2code == False
188 # "cmd line arg should appear as option overwriting default"
189 values = self.options(["--txt2code", "foo.sl"], txt2code=False)
190 pprint(values)
191 assert values.txt2code == True
192 assert values.infile == "foo.sl"
193 # "cmd line arg should appear as option overwriting default"
194 values = self.options(['in-file', '--comment-string=% '],
195 comment_string="##")
196 assert values.comment_string == '% '
198 def test_call_language(self):
199 """test the language setting from filename"""
200 values = self.options(["foo.sl"])
201 pprint(values)
202 assert values.language == "slang"
204 def test_call_language_outfile(self):
205 """test the language setting from filename"""
206 values = self.options(["foo, foo.sl"])
207 pprint(values)
208 assert values.language == "slang"
210 ## Input and Output streams
211 ## ------------------------
213 ## ::
215 class IOTests:
216 """base class for IO tests, sets up and tears down example files in /tmp
218 txtpath = "/tmp/pylit_test.py.txt"
219 codepath = "/tmp/pylit_test.py"
220 outpath = "/tmp/pylit_test.out"
222 def setUp(self):
223 """Set up the test files"""
224 txtfile = open(self.txtpath, 'w')
225 txtfile.write(text)
226 # txtfile.flush() # is this needed if we close?
227 txtfile.close()
229 codefile = open(self.codepath, 'w')
230 codefile.write(code)
231 # codefile.flush() # is this needed if we close?
232 codefile.close()
234 def tearDown(self):
235 """clean up after all member tests are done"""
236 try:
237 os.unlink(self.txtpath)
238 os.unlink(self.codepath)
239 os.unlink(self.outpath)
240 except OSError:
241 pass
243 def get_output(self):
244 """read and return the content of the output file"""
245 with open(self.outpath, 'r') as outstream:
246 return outstream.read()
250 class test_Streams(IOTests):
251 def test_is_newer(self):
252 # this __file__ is older, than code file
253 print(__file__, os.path.getmtime(__file__))
254 print(self.codepath, os.path.getmtime(self.codepath))
256 assert is_newer(self.codepath, __file__) is True, "file1 is newer"
257 assert is_newer(__file__, self.codepath) is False, "file2 is newer"
258 assert is_newer(__file__, "fffo") is True, "file2 doesnot exist"
259 assert is_newer("fflo", __file__) is False, "file1 doesnot exist"
261 assert is_newer(__file__, __file__) is None, "equal is not newer"
262 assert is_newer("fflo", "fffo") is None, "no file exists -> equal"
264 def test_open_streams(self):
265 # default should return stdin and -out:
266 (instream, outstream) = open_streams()
267 assert instream is sys.stdin
268 assert outstream is sys.stdout
270 # open input and output file
271 (instream, outstream) = open_streams(self.txtpath, self.outpath)
272 print(type(instream), type(outstream))
273 assert type(instream) == type(open(self.txtpath))
274 assert type(outstream) == type(open(self.outpath))
275 # read something from the input
276 assert instream.read() == text
277 # write something to the output
278 outstream.write(text)
279 # check the output, we have to flush first
280 outstream.flush()
281 outfile = open(self.outpath, 'r')
282 assert outfile.read() == text
284 def test_open_streams_no_infile(self):
285 """should exit with usage info if no infile given"""
286 try:
287 (instream, outstream) = open_streams("")
288 assert False, "should rise IOError"
289 except IOError:
290 pass
292 ## get_converter
293 ## ~~~~~~~~~~~~~
295 ## Return "right" converter instance (Text2Code or Code2Text instance)::
297 def test_get_converter():
298 # with default or txt2code
299 converter = get_converter(textdata)
300 print(converter.__class__)
301 assert converter.__class__ == Text2Code
302 converter = get_converter(textdata, txt2code=False)
303 assert converter.__class__ == Code2Text
305 # the run_doctest runs a doctest on the text version (as doc-string)
306 class test_Run_Doctest(IOTests):
307 """Doctest should run on the text source"""
308 def test_doctest_txt2code(self):
309 (failures, tests) = run_doctest(self.txtpath, txt2code=True)
310 assert (failures, tests) == (0, 0)
311 def test_doctest_code2txt(self):
312 (failures, tests) = run_doctest(self.codepath, txt2code=False)
313 assert (failures, tests) == (0, 0)
315 ## The main() function is called if the script is run from the command line
317 ## ::
319 class test_Main(IOTests):
320 """test default operation from command line
322 def test_text_to_code(self):
323 """test conversion of text file to code file"""
324 main(infile=self.txtpath, outfile=self.outpath)
325 output = self.get_output()
326 print(repr(output))
327 assert output == code
329 def test_text_to_code_strip(self):
330 """test conversion of text file to stripped code file"""
331 main(infile=self.txtpath, outfile=self.outpath, strip=True)
332 output = self.get_output()
333 print(repr(output))
334 assert output == stripped_code
336 def test_text_to_code_twice(self):
337 """conversion should work a second time"""
338 main(infile=self.txtpath, outfile=self.outpath)
339 main(infile=self.txtpath, outfile=self.outpath, overwrite='yes')
340 output = self.get_output()
341 print(repr(output))
342 assert output == code
344 def test_code_to_text(self):
345 """test conversion of code file to text file"""
346 main(infile=self.codepath, outfile=self.outpath)
347 output = self.get_output()
348 assert output == text
350 def test_code_to_text_strip(self):
351 """test conversion of code file to stripped text file"""
352 main(infile=self.codepath, outfile=self.outpath, strip=True)
353 output = self.get_output()
354 assert output == stripped_text
356 def test_code_to_text_twice(self):
357 """conversion should work also a second time"""
358 main(infile=self.codepath, outfile=self.outpath)
359 main(infile=self.codepath, outfile=self.outpath, overwrite='yes')
360 output = self.get_output()
361 assert output == text
363 def test_diff(self):
364 result = main(infile=self.codepath, diff=True)
365 print("diff return value", result)
366 assert result is False # no differences found
368 def test_diff_with_differences(self):
369 """diffing a file to itself should fail, as the input is converted"""
370 result = main(infile=self.codepath, outfile=self.codepath, diff=True)
371 print("diff return value", result)
372 assert result is True # differences found
374 def test_execute(self):
375 result = main(infile=self.txtpath, execute=True)
376 print(result)
378 def test_execute_code(self):
379 result = main(infile=self.codepath, execute=True)
382 class test_Programmatic_Use(IOTests):
383 """test various aspects of programmatic use"""
385 def test_conversion(self):
386 (data, out_stream) = open_streams(self.txtpath)
387 print("data: %r"%data)
388 print("out_stream: %r"%out_stream)
389 converter = get_converter(data)
390 lines = converter()
391 print("output: %r"%lines)
392 # lines = converter()
393 assert lines == codedata
396 if __name__ == "__main__":
397 nose.runmodule() # requires nose 0.9.1
398 sys.exit()