Split the unit test in converter tests (pylit_test.py) and user interface
[pylit.git] / test / pylit_ui_test.py
bloba77c2d86a37b4bcb681e2c72bf8c8345b268c09c
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
24 import nose
26 ## Global defaults
27 ## ===============
28 ##
29 ## ::
31 def test_global_option_defaults():
32 """dictionary of programming languages and extensions"""
33 for ext in [".py", ".sl", ".c"]:
34 assert ext in defaults.code_extensions
35 assert defaults.languages[".py"] == "python"
36 assert defaults.languages[".sl"] == "slang"
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 # default should appear in options
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_get_outfile_name(self):
119 """should return a sensible outfile name given an infile name"""
120 # return stdout for stdin
121 values = OptionValues({"infile": "-"})
122 values.complete(**defaults.__dict__)
123 assert "-" == self.options._get_outfile_name(values)
124 # return with ".txt" stripped
125 values = OptionValues({"infile": "foo.py.txt"})
126 values.complete(**defaults.__dict__)
127 assert "foo.py" == self.options._get_outfile_name(values)
128 # return with ".txt" added if extension marks code file
129 values = OptionValues({"infile": "foo.py"})
130 values.complete(**defaults.__dict__)
131 assert "foo.py.txt" == self.options._get_outfile_name(values)
132 values = OptionValues({"infile": "foo.sl"})
133 values.complete(**defaults.__dict__)
134 assert "foo.sl.txt" == self.options._get_outfile_name(values)
135 values = OptionValues({"infile": "foo.c"})
136 values.complete(**defaults.__dict__)
137 assert "foo.c.txt" == self.options._get_outfile_name(values)
138 # return with ".txt" added if txt2code == False (not None!)
139 values = OptionValues({"infile": "foo.py", "txt2code": False})
140 values.complete(**defaults.__dict__)
141 assert "foo.py.txt" == self.options._get_outfile_name(values)
142 # catchall: add ".out" if no other guess possible
143 values = OptionValues({"infile": "foo", "txt2code": None})
144 values.complete(**defaults.__dict__)
145 assert "foo.out" == self.options._get_outfile_name(values)
147 def test_complete_values(self):
148 """Basic test of the option completion"""
149 values = OptionValues()
150 values.infile = "foo"
151 values = self.options.complete_values(values)
152 # the following options should be set:
153 print values.infile # logo, as we give it...
154 print values.outfile
155 assert values.outfile == "foo.out" # fallback extension .out added
156 print values.txt2code
157 assert values.txt2code == True # the default
158 print values.language
159 assert values.language == "python" # the default
161 def test_complete_values_txt(self):
162 """Test the option completion with a text input file"""
163 values = OptionValues()
164 values.infile = "foo.txt"
165 values = self.options.complete_values(values)
166 # should set outfile (see also `test_get_outfile_name`)
167 assert values.outfile == "foo"
168 # should set conversion direction according to extension
169 assert values.txt2code == True
171 def test_complete_values_code(self):
172 """Test the option completion with a code input file"""
173 values = OptionValues()
174 values.infile = "foo.py"
175 values = self.options.complete_values(values)
176 # should set outfile name
177 assert values.outfile == "foo.py.txt"
178 # should set conversion directions according to extension
179 print values.txt2code
180 assert values.txt2code == False, "set conversion according to extension"
182 def test_complete_values_dont_overwrite(self):
183 """The option completion must not overwrite existing option values"""
184 values = OptionValues()
185 values.infile = "foo.py"
186 values.outfile = "bar.txt"
187 values.txt2code = True
188 values = self.options.complete_values(values)
189 pprint(values)
190 assert values.outfile == "bar.txt"
191 assert values.txt2code == True
193 def test_complete_values_language_infile(self):
194 """set the language from the infile extension"""
195 values = OptionValues()
196 values.infile = "foo.c"
197 values = self.options.complete_values(values)
198 pprint(values)
199 assert values.language == "c++"
201 def test_complete_values_language_outfile(self):
202 """set the language from the outfile extension"""
203 values = OptionValues()
204 values.outfile = "foo.sl"
205 values = self.options.complete_values(values)
206 pprint(values)
207 assert values.language == "slang"
209 def test_complete_values_language_fallback(self):
210 """set the language from the fallback language"""
211 values = OptionValues()
212 values = self.options.complete_values(values)
213 pprint(values)
214 print "fallback language:", defaults.fallback_language
215 assert values.language == defaults.fallback_language
217 def test_call(self):
218 values = self.options(["--txt2code", "foo.sl"], txt2code=False)
219 pprint(values)
220 assert values.txt2code == True
221 assert values.infile == "foo.sl"
223 def test_call_language(self):
224 """test the language setting from filename"""
225 values = self.options(["foo.sl"])
226 pprint(values)
227 assert values.language == "slang"
229 def test_call_language_outfile(self):
230 """test the language setting from filename"""
231 values = self.options(["foo, foo.sl"])
232 pprint(values)
233 assert values.language == "slang"
235 ## Input and Output streams
236 ## ------------------------
238 ## ::
240 class IOTests:
241 """base class for IO tests, sets up and tears down example files in /tmp
243 txtpath = "/tmp/pylit_test.py.txt"
244 codepath = "/tmp/pylit_test.py"
245 outpath = "/tmp/pylit_test.out"
247 def setUp(self):
248 """Set up the test files"""
249 txtfile = file(self.txtpath, 'w')
250 txtfile.write(text)
251 # txtfile.flush() # is this needed if we close?
252 txtfile.close()
254 codefile = file(self.codepath, 'w')
255 codefile.write(code)
256 # codefile.flush() # is this needed if we close?
257 codefile.close()
259 def tearDown(self):
260 """clean up after all member tests are done"""
261 try:
262 os.unlink(self.txtpath)
263 os.unlink(self.codepath)
264 os.unlink(self.outpath)
265 except OSError:
266 pass
268 class test_Streams(IOTests):
269 def test_is_newer(self):
270 # this __file__ is older, than code file
271 print __file__, os.path.getmtime(__file__)
272 print self.codepath, os.path.getmtime(self.codepath)
274 assert is_newer(self.codepath, __file__) is True, "file1 is newer"
275 assert is_newer(__file__, self.codepath) is False, "file2 is newer"
276 assert is_newer(__file__, "fffo") is True, "file2 doesnot exist"
277 assert is_newer("fflo", __file__) is False, "file1 doesnot exist"
279 assert is_newer(__file__, __file__) is None, "equal is not newer"
280 assert is_newer("fflo", "fffo") is None, "no file exists -> equal"
282 def test_open_streams(self):
283 # default should return stdin and -out:
284 (instream, outstream) = open_streams()
285 assert instream is sys.stdin
286 assert outstream is sys.stdout
288 # open input and output file
289 (instream, outstream) = open_streams(self.txtpath, self.outpath)
290 assert type(instream) == file
291 assert type(outstream) == file
292 # read something from the input
293 assert instream.read() == text
294 # write something to the output
295 outstream.write(text)
296 # check the output, we have to flush first
297 outstream.flush()
298 outfile = file(self.outpath, 'r')
299 assert outfile.read() == text
301 def test_open_streams_no_infile(self):
302 """should exit with usage info if no infile given"""
303 try:
304 (instream, outstream) = open_streams("")
305 assert False, "should rise SystemExit"
306 except IOError:
307 pass
309 ## Another convenience function that returns a converter instance::
311 def test_get_converter():
312 # with default or txt2code
313 converter = get_converter(textdata)
314 print converter.__class__
315 assert converter.__class__ == Text2Code
316 converter = get_converter(textdata, txt2code=False)
317 assert converter.__class__ == Code2Text
319 # the run_doctest runs a doctest on the text version (as doc-string)
320 class test_Run_Doctest(IOTests):
321 """Doctest should run on the text source"""
322 def test_doctest_txt2code(self):
323 (failures, tests) = run_doctest(self.txtpath, txt2code=True)
324 assert (failures, tests) == (0, 0)
325 def test_doctest_code2txt(self):
326 (failures, tests) = run_doctest(self.codepath, txt2code=False)
327 assert (failures, tests) == (0, 0)
329 ## The main() function is called if the script is run from the command line
331 ## ::
333 class test_Main(IOTests):
334 """test default operation from command line
336 def get_output(self):
337 """read and return the content of the output file"""
338 outstream = file(self.outpath, 'r')
339 return outstream.read()
341 def test_text_to_code(self):
342 """test conversion of text file to code file"""
343 main(infile=self.txtpath, outfile=self.outpath)
344 output = self.get_output()
345 print repr(output)
346 assert output == code
348 def test_text_to_code_strip(self):
349 """test conversion of text file to stripped code file"""
350 main(infile=self.txtpath, outfile=self.outpath, strip=True)
351 output = self.get_output()
352 print repr(output)
353 assert output == stripped_code
355 def test_main_code_to_text(self):
356 """test conversion of code file to text file"""
357 main(infile=self.codepath, outfile=self.outpath)
358 output = self.get_output()
359 assert output == text
361 def test_main_code_to_text_strip(self):
362 """test conversion of code file to stripped text file"""
363 main(infile=self.codepath, outfile=self.outpath, strip=True)
364 output = self.get_output()
365 assert output == stripped_text
367 def test_main_diff(self):
368 result = main(infile=self.codepath, diff=True)
369 print "diff return value", result
370 assert result is False # no differences found
372 def test_main_diff_with_differences(self):
373 """diffing a file to itself should fail, as the input is converted"""
374 result = main(infile=self.codepath, outfile=self.codepath, diff=True)
375 print "diff return value", result
376 assert result is True # differences found
378 def test_main_execute(self):
379 result = main(infile=self.txtpath, execute=True)
380 print result
382 def test_main_execute_code(self):
383 result = main(infile=self.codepath, execute=True)
385 if __name__ == "__main__":
386 nose.runmodule() # requires nose 0.9.1
387 sys.exit()