New version 0.7.6
[pylit.git] / test / pylit_ui_test.py
blob7f7b5d6af7e6e57ab25f825fdcc2c80db300ea7b
1 #!/usr/bin/env python
2 # -*- coding: iso-8859-1 -*-
4 ## Test the pylit.py literal python module's user interface
5 ## ========================================================
6 ##
7 ## :Date: $Date: 2007-05-17 $
8 ## :Version: SVN-Revision $Revision: 45 $
9 ## :URL: $URL: svn+ssh://svn.berlios.de/svnroot/repos/pylit/trunk/test/pylit_ui_test.py $
10 ## :Copyright: 2006 Guenter Milde.
11 ## Released under the terms of the GNU General Public License
12 ## (v. 2 or later)
13 ##
14 ## .. contents::
16 ## ::
18 """pylit_test.py: test the "literal python" module's user interface"""
20 from pprint import pprint
21 from pylit import *
22 from pylit_test import (text, stripped_text, textdata,
23 code, stripped_code, codedata)
25 import nose
27 ## Global defaults
28 ## ===============
29 ##
30 ## ::
32 def test_global_option_defaults():
33 """dictionary of programming languages and extensions"""
34 assert defaults.languages[".py"] == "python"
35 assert defaults.languages[".sl"] == "slang"
36 assert defaults.languages[".cc"] == "c++"
37 assert defaults.languages[".c"] == "c"
40 ## Command line use
41 ## ================
42 ##
43 ## Test the option parsing::
45 class test_OptionValues(object):
46 defaults = {"a1": 1, "a2": False}
47 def setUp(self):
48 self.values = OptionValues(self.defaults)
49 print self.values
51 def test_setup(self):
52 assert self.values.a1 == 1
53 assert self.values.a2 == False
55 def test_as_dict(self):
56 print "as_dict() ->", self.values.as_dict()
57 assert self.values.as_dict() == self.defaults
59 def test_complete(self):
60 """complete should update non-existing values only"""
61 self.values.complete(**{"a1": 2, "a2": 4, "a3": 3})
62 print "completed ->", self.values
63 assert self.values.a1 == 1, "must not overwrite existing value"
64 assert self.values.a2 == False, "must not overwrite existing value"
65 assert self.values.a3 == 3, "should set new attributes"
66 self.values.complete(a1=2, a4=20)
67 assert self.values.a1 == 1, "must not overwrite existing value"
68 assert self.values.a4 == 20, "should set new attributes"
70 def test_getattr(self):
71 """Attempt to get a non-existing argument should return None
73 This make the code more concise as a try: except: AttributeError
74 statement or the parent class method `ensure_value(name, default)`.
75 """
76 assert self.values.a3 == None
78 def test_getattr_ensure_value(self):
79 """Ensure value can be used to set a default different from None"""
80 assert self.values.a4 == None
81 self.values.ensure_value("a4", 32)
82 assert self.values.a4 == 32
85 class test_PylitOptions:
86 """Test the PylitOption class"""
87 def setUp(self):
88 self.options = PylitOptions()
90 def test_parse_args(self):
91 """parse cmd line args"""
92 # default should appear in options
93 values = self.options.parse_args(txt2code=False)
94 print values, type(values), dir(values)
95 assert values.txt2code == False
96 # "cmd line arg should appear as option overwriting default"
97 values = self.options.parse_args(["--txt2code"], txt2code=False)
98 assert values.txt2code == True
99 # "1st non option arg is infile, 2nd is outfile"
100 values = self.options.parse_args(["--txt2code", "text.txt", "code.py"])
101 print values.infile
102 assert values.infile == "text.txt"
103 assert values.outfile == "code.py"
104 # option with argument
105 values = self.options.parse_args(["--language", "slang"])
106 assert values.language == "slang"
108 def test_parse_args_comment_string(self):
109 # command line arg should appear in values
110 values = self.options.parse_args(["--comment-string=% "])
111 pprint(values.as_dict())
112 assert values.comment_string == "% "
113 # "cmd line arg should appear as option overwriting default"
114 values = self.options.parse_args(["--comment-string=% "],
115 comment_string="##")
116 assert values.comment_string == '% '
118 def test_parse_args_code_block_marker(self):
119 """command line option --code-block-marker should set option value"""
120 values = self.options.parse_args(
121 ["--code-block-marker=.. test-dir::"])
122 pprint(values.as_dict())
123 assert values.code_block_marker == '.. test-dir::'
125 def test_get_outfile_name(self):
126 """should return a sensible outfile name given an infile name"""
127 # return stdout for stdin
128 values = OptionValues({"infile": "-"})
129 values.complete(**defaults.__dict__)
130 assert "-" == self.options._get_outfile_name(values)
131 # return with ".txt" stripped
132 values = OptionValues({"infile": "foo.py.txt"})
133 values.complete(**defaults.__dict__)
134 assert "foo.py" == self.options._get_outfile_name(values)
135 # return with ".txt" added if extension marks code file
136 values = OptionValues({"infile": "foo.py"})
137 values.complete(**defaults.__dict__)
138 assert "foo.py.txt" == self.options._get_outfile_name(values)
139 values = OptionValues({"infile": "foo.sl"})
140 values.complete(**defaults.__dict__)
141 assert "foo.sl.txt" == self.options._get_outfile_name(values)
142 values = OptionValues({"infile": "foo.c"})
143 values.complete(**defaults.__dict__)
144 assert "foo.c.txt" == self.options._get_outfile_name(values)
145 # return with ".txt" added if txt2code == False (not None!)
146 values = OptionValues({"infile": "foo.py", "txt2code": False})
147 values.complete(**defaults.__dict__)
148 assert "foo.py.txt" == self.options._get_outfile_name(values)
149 # catchall: add ".out" if no other guess possible
150 values = OptionValues({"infile": "foo", "txt2code": None})
151 values.complete(**defaults.__dict__)
152 assert "foo.out" == self.options._get_outfile_name(values)
154 def test_complete_values(self):
155 """Basic test of the option completion"""
156 values = OptionValues()
157 values.infile = "foo"
158 values = self.options.complete_values(values)
159 # the following options should be set:
160 print values.infile # logo, as we give it...
161 print values.outfile
162 assert values.outfile == "foo.out" # fallback extension .out added
163 print values.txt2code
164 assert values.txt2code == True # the default
165 print values.language
166 assert values.language == "python" # the default
168 def test_complete_values_txt(self):
169 """Test the option completion with a text input file"""
170 values = OptionValues()
171 values.infile = "foo.txt"
172 values = self.options.complete_values(values)
173 # should set outfile (see also `test_get_outfile_name`)
174 assert values.outfile == "foo"
175 # should set conversion direction according to extension
176 assert values.txt2code == True
178 def test_complete_values_code(self):
179 """Test the option completion with a code input file"""
180 values = OptionValues()
181 values.infile = "foo.py"
182 values = self.options.complete_values(values)
183 # should set outfile name
184 assert values.outfile == "foo.py.txt"
185 # should set conversion directions according to extension
186 print values.txt2code
187 assert values.txt2code == False, "set conversion according to extension"
189 def test_complete_values_dont_overwrite(self):
190 """The option completion must not overwrite existing option values"""
191 values = OptionValues()
192 values.infile = "foo.py"
193 values.outfile = "bar.txt"
194 values.txt2code = True
195 values = self.options.complete_values(values)
196 pprint(values)
197 assert values.outfile == "bar.txt"
198 assert values.txt2code == True
200 def test_complete_values_language_infile(self):
201 """set the language from the infile extension"""
202 values = OptionValues()
203 values.infile = "foo.cc"
204 values = self.options.complete_values(values)
205 pprint(values)
206 assert values.language == "c++"
208 def test_complete_values_language_outfile(self):
209 """set the language from the outfile extension"""
210 values = OptionValues()
211 values.outfile = "foo.sl"
212 values = self.options.complete_values(values)
213 pprint(values)
214 assert values.language == "slang"
216 def test_complete_values_language_fallback(self):
217 """set the language from the fallback language"""
218 values = OptionValues()
219 values = self.options.complete_values(values)
220 pprint(values)
221 print "fallback language:", defaults.languages.default
222 assert values.language == defaults.languages.default
224 def test_call(self):
225 values = self.options(["--txt2code", "foo.sl"], txt2code=False)
226 pprint(values)
227 assert values.txt2code == True
228 assert values.infile == "foo.sl"
230 def test_call_language(self):
231 """test the language setting from filename"""
232 values = self.options(["foo.sl"])
233 pprint(values)
234 assert values.language == "slang"
236 def test_call_language_outfile(self):
237 """test the language setting from filename"""
238 values = self.options(["foo, foo.sl"])
239 pprint(values)
240 assert values.language == "slang"
242 ## Input and Output streams
243 ## ------------------------
245 ## ::
247 class IOTests:
248 """base class for IO tests, sets up and tears down example files in /tmp
250 txtpath = "/tmp/pylit_test.py.txt"
251 codepath = "/tmp/pylit_test.py"
252 outpath = "/tmp/pylit_test.out"
254 def setUp(self):
255 """Set up the test files"""
256 txtfile = file(self.txtpath, 'w')
257 txtfile.write(text)
258 # txtfile.flush() # is this needed if we close?
259 txtfile.close()
261 codefile = file(self.codepath, 'w')
262 codefile.write(code)
263 # codefile.flush() # is this needed if we close?
264 codefile.close()
266 def tearDown(self):
267 """clean up after all member tests are done"""
268 try:
269 os.unlink(self.txtpath)
270 os.unlink(self.codepath)
271 os.unlink(self.outpath)
272 except OSError:
273 pass
275 def get_output(self):
276 """read and return the content of the output file"""
277 outstream = file(self.outpath, 'r')
278 return outstream.read()
282 class test_Streams(IOTests):
283 def test_is_newer(self):
284 # this __file__ is older, than code file
285 print __file__, os.path.getmtime(__file__)
286 print self.codepath, os.path.getmtime(self.codepath)
288 assert is_newer(self.codepath, __file__) is True, "file1 is newer"
289 assert is_newer(__file__, self.codepath) is False, "file2 is newer"
290 assert is_newer(__file__, "fffo") is True, "file2 doesnot exist"
291 assert is_newer("fflo", __file__) is False, "file1 doesnot exist"
293 assert is_newer(__file__, __file__) is None, "equal is not newer"
294 assert is_newer("fflo", "fffo") is None, "no file exists -> equal"
296 def test_open_streams(self):
297 # default should return stdin and -out:
298 (instream, outstream) = open_streams()
299 assert instream is sys.stdin
300 assert outstream is sys.stdout
302 # open input and output file
303 (instream, outstream) = open_streams(self.txtpath, self.outpath)
304 assert type(instream) == file
305 assert type(outstream) == file
306 # read something from the input
307 assert instream.read() == text
308 # write something to the output
309 outstream.write(text)
310 # check the output, we have to flush first
311 outstream.flush()
312 outfile = file(self.outpath, 'r')
313 assert outfile.read() == text
315 def test_open_streams_no_infile(self):
316 """should exit with usage info if no infile given"""
317 try:
318 (instream, outstream) = open_streams("")
319 assert False, "should rise IOError"
320 except IOError:
321 pass
323 ## get_converter
324 ## ~~~~~~~~~~~~~
326 ## Return "right" converter instance (Text2Code or Code2Text instance)::
328 def test_get_converter():
329 # with default or txt2code
330 converter = get_converter(textdata)
331 print converter.__class__
332 assert converter.__class__ == Text2Code
333 converter = get_converter(textdata, txt2code=False)
334 assert converter.__class__ == Code2Text
336 # the run_doctest runs a doctest on the text version (as doc-string)
337 class test_Run_Doctest(IOTests):
338 """Doctest should run on the text source"""
339 def test_doctest_txt2code(self):
340 (failures, tests) = run_doctest(self.txtpath, txt2code=True)
341 assert (failures, tests) == (0, 0)
342 def test_doctest_code2txt(self):
343 (failures, tests) = run_doctest(self.codepath, txt2code=False)
344 assert (failures, tests) == (0, 0)
346 ## The main() function is called if the script is run from the command line
348 ## ::
350 class test_Main(IOTests):
351 """test default operation from command line
353 def test_text_to_code(self):
354 """test conversion of text file to code file"""
355 main(infile=self.txtpath, outfile=self.outpath)
356 output = self.get_output()
357 print repr(output)
358 assert output == code
360 def test_text_to_code_strip(self):
361 """test conversion of text file to stripped code file"""
362 main(infile=self.txtpath, outfile=self.outpath, strip=True)
363 output = self.get_output()
364 print repr(output)
365 assert output == stripped_code
367 def test_text_to_code_twice(self):
368 """conversion should work a second time"""
369 main(infile=self.txtpath, outfile=self.outpath)
370 main(infile=self.txtpath, outfile=self.outpath)
371 output = self.get_output()
372 print repr(output)
373 assert output == code
375 def test_code_to_text(self):
376 """test conversion of code file to text file"""
377 main(infile=self.codepath, outfile=self.outpath)
378 output = self.get_output()
379 assert output == text
381 def test_code_to_text_strip(self):
382 """test conversion of code file to stripped text file"""
383 main(infile=self.codepath, outfile=self.outpath, strip=True)
384 output = self.get_output()
385 assert output == stripped_text
387 def test_code_to_text_twice(self):
388 """conversion should work also a second time"""
389 main(infile=self.codepath, outfile=self.outpath)
390 main(infile=self.codepath, outfile=self.outpath)
391 output = self.get_output()
392 assert output == text
394 def test_diff(self):
395 result = main(infile=self.codepath, diff=True)
396 print "diff return value", result
397 assert result is False # no differences found
399 def test_diff_with_differences(self):
400 """diffing a file to itself should fail, as the input is converted"""
401 result = main(infile=self.codepath, outfile=self.codepath, diff=True)
402 print "diff return value", result
403 assert result is True # differences found
405 def test_execute(self):
406 result = main(infile=self.txtpath, execute=True)
407 print result
409 def test_execute_code(self):
410 result = main(infile=self.codepath, execute=True)
413 class test_Programmatic_Use(IOTests):
414 """test various aspects of programmatic use"""
416 def test_conversion(self):
417 (data, out_stream) = open_streams(self.txtpath)
418 print "data: %r"%data
419 print "out_stream: %r"%out_stream
420 converter = get_converter(data)
421 lines = converter()
422 print "output: %r"%lines
423 # lines = converter()
424 assert lines == codedata
427 if __name__ == "__main__":
428 nose.runmodule() # requires nose 0.9.1
429 sys.exit()