blob: e0933ad9e343600792f02211a3eedd675dffa806 [file] [log] [blame]
Tor Norbye3a2425a2013-11-04 10:16:08 -08001# encoding: utf-8
2"""
3Tests basic things that generator3 consists of.
4NOTE: does not work in Jython 2.2 or IronPython 1.x, because pyparsing does not.
5"""
6
7import unittest
8from generator3 import *
9
10M = ModuleRedeclarator
11
12import sys
13
14IS_CLI = sys.platform == 'cli'
15VERSION = sys.version_info[:2] # only (major, minor)
16
17class TestRestoreFuncByDocComment(unittest.TestCase):
18 """
19 Tries to restore function signatures by doc strings.
20 """
21
22 def setUp(self):
23 self.m = ModuleRedeclarator(None, None, '/dev/null')
24
25 def testTrivial(self):
26 result, ret_sig, note = self.m.parse_func_doc("blah f(a, b, c) ololo", "f", "f", None)
27 self.assertEquals(result, "f(a, b, c)")
28 self.assertEquals(note, M.SIG_DOC_NOTE)
29
30 def testTrivialNested(self):
31 result, ret_sig, note = self.m.parse_func_doc("blah f(a, (b, c), d) ololo", "f", "f", None)
32 self.assertEquals(result, "f(a, (b, c), d)")
33 self.assertEquals(note, M.SIG_DOC_NOTE)
34
35 def testWithDefault(self):
36 result, ret_sig, note = self.m.parse_func_doc("blah f(a, b, c=1) ololo", "f", "f", None)
37 self.assertEquals(result, "f(a, b, c=1)")
38 self.assertEquals(note, M.SIG_DOC_NOTE)
39
40 def testNestedWithDefault(self):
41 result, ret_sig, note = self.m.parse_func_doc("blah f(a, (b1, b2), c=1) ololo", "f", "f", None)
42 self.assertEquals(result, "f(a, (b1, b2), c=1)")
43 self.assertEquals(note, M.SIG_DOC_NOTE)
44
45 def testAbstractDefault(self):
46 # like new(S, ...)
47 result, ret_sig, note = self.m.parse_func_doc('blah f(a, b=obscuredefault) ololo', "f", "f", None)
48 self.assertEquals(result, "f(a, b=None)")
49 self.assertEquals(note, M.SIG_DOC_NOTE)
50
51 def testWithReserved(self):
52 result, ret_sig, note = self.m.parse_func_doc("blah f(class, object, def) ololo", "f", "f", None)
53 self.assertEquals(result, "f(p_class, p_object, p_def)")
54 self.assertEquals(note, M.SIG_DOC_NOTE)
55
56 def testWithReservedOpt(self):
57 result, ret_sig, note = self.m.parse_func_doc("blah f(foo, bar[, def]) ololo", "f", "f", None)
58 self.assertEquals(result, "f(foo, bar, p_def=None)")
59 self.assertEquals(note, M.SIG_DOC_NOTE)
60
61 def testPseudoNested(self):
62 result, ret_sig, note = self.m.parse_func_doc("blah f(a, (b1, b2, ...)) ololo", "f", "f", None)
63 self.assertEquals(result, "f(a, b_tuple)")
64 self.assertEquals(note, M.SIG_DOC_NOTE)
65
66 def testImportLike(self):
67 # __import__
68 result, ret_sig, note = self.m.parse_func_doc("blah f(name, globals={}, locals={}, fromlist=[], level=-1) ololo",
69 "f", "f", None)
70 self.assertEquals(result, "f(name, globals={}, locals={}, fromlist=[], level=-1)")
71 self.assertEquals(note, M.SIG_DOC_NOTE)
72
73 def testOptionalBracket(self):
74 # reduce
75 result, ret_sig, note = self.m.parse_func_doc("blah f(function, sequence[, initial]) ololo", "f", "f", None)
76 self.assertEquals(result, "f(function, sequence, initial=None)")
77 self.assertEquals(note, M.SIG_DOC_NOTE)
78
79 def testWithMore(self):
80 result, ret_sig, note = self.m.parse_func_doc("blah f(foo [, bar1, bar2, ...]) ololo", "f", "f", None)
81 self.assertEquals(result, "f(foo, *bar)")
82 self.assertEquals(note, M.SIG_DOC_NOTE)
83
84 def testNestedOptionals(self):
85 result, ret_sig, note = self.m.parse_func_doc("blah f(foo [, bar1 [, bar2]]) ololo", "f", "f", None)
86 self.assertEquals(result, "f(foo, bar1=None, bar2=None)")
87 self.assertEquals(note, M.SIG_DOC_NOTE)
88
89 def testInnerTuple(self):
90 result, ret_sig, note = self.m.parse_func_doc("blah load_module(name, file, filename, (suffix, mode, type)) ololo"
91 , "load_module", "load_module", None)
92 self.assertEquals(result, "load_module(name, file, filename, (suffix, mode, type))")
93 self.assertEquals(note, M.SIG_DOC_NOTE)
94
95 def testIncorrectInnerTuple(self):
96 result, ret_sig, note = self.m.parse_func_doc("blah f(a, (b=1, c=2)) ololo", "f", "f", None)
97 self.assertEquals(result, "f(a, p_b)")
98 self.assertEquals(note, M.SIG_DOC_NOTE)
99
100 def testNestedOnly(self):
101 result, ret_sig, note = self.m.parse_func_doc("blah f((foo, bar, baz)) ololo", "f", "f", None)
102 self.assertEquals(result, "f((foo, bar, baz))")
103 self.assertEquals(note, M.SIG_DOC_NOTE)
104
105 def testTwoPseudoNested(self):
106 result, ret_sig, note = self.m.parse_func_doc("blah f((a1, a2, ...), (b1, b2,..)) ololo", "f", "f", None)
107 self.assertEquals(result, "f(a_tuple, b_tuple)")
108 self.assertEquals(note, M.SIG_DOC_NOTE)
109
110 def testTwoPseudoNestedWithLead(self):
111 result, ret_sig, note = self.m.parse_func_doc("blah f(x, (a1, a2, ...), (b1, b2,..)) ololo", "f", "f", None)
112 self.assertEquals(result, "f(x, a_tuple, b_tuple)")
113 self.assertEquals(note, M.SIG_DOC_NOTE)
114
115 def testPseudoNestedRange(self):
116 result, ret_sig, note = self.m.parse_func_doc("blah f((a1, ..., an), b) ololo", "f", "f", None)
117 self.assertEquals(result, "f(a_tuple, b)")
118 self.assertEquals(note, M.SIG_DOC_NOTE)
119
120 def testIncorrectList(self):
121 result, ret_sig, note = self.m.parse_func_doc("blah f(x, y, 3, $) ololo", "f", "f", None)
122 self.assertEquals(result, "f(x, y, *args, **kwargs)")
123 self.assertEquals(note, M.SIG_DOC_UNRELIABLY)
124
125 def testIncorrectStarredList(self):
126 result, ret_sig, note = self.m.parse_func_doc("blah f(x, *y, 3, $) ololo", "f", "f", None)
127 self.assertEquals(result, "f(x, *y, **kwargs)")
128 self.assertEquals(note, M.SIG_DOC_UNRELIABLY)
129
130 def testClashingNames(self):
131 result, ret_sig, note = self.m.parse_func_doc("blah f(x, y, (x, y), z) ololo", "f", "f", None)
132 self.assertEquals(result, "f(x, y, (x_1, y_1), z)")
133 self.assertEquals(note, M.SIG_DOC_NOTE)
134
135 def testQuotedParam(self):
136 # like __delattr__
137 result, ret_sig, note = self.m.parse_func_doc("blah getattr('name') ololo", "getattr", "getattr", None)
138 self.assertEquals(result, "getattr(name)")
139 self.assertEquals(note, M.SIG_DOC_NOTE)
140
141 def testQuotedParam2(self):
142 # like __delattr__, too
143 result, ret_sig, note = self.m.parse_func_doc('blah getattr("name") ololo', "getattr", "getattr", None)
144 self.assertEquals(result, "getattr(name)")
145 self.assertEquals(note, M.SIG_DOC_NOTE)
146
147 def testOptionalTripleDot(self):
148 # like new(S, ...)
149 result, ret_sig, note = self.m.parse_func_doc('blah f(foo, ...) ololo', "f", "f", None)
150 self.assertEquals(result, "f(foo, *more)")
151 self.assertEquals(note, M.SIG_DOC_NOTE)
152
153 def testUnderscoredName(self):
154 # like new(S, ...)
155 result, ret_sig, note = self.m.parse_func_doc('blah f(foo_one, _bar_two) ololo', "f", "f", None)
156 self.assertEquals(result, "f(foo_one, _bar_two)")
157 self.assertEquals(note, M.SIG_DOC_NOTE)
158
159 def testDashedName(self):
160 # like new(S, ...)
161 result, ret_sig, note = self.m.parse_func_doc('blah f(something-else, for-a-change) ololo', "f", "f", None)
162 self.assertEquals(result, "f(something_else, for_a_change)")
163 self.assertEquals(note, M.SIG_DOC_NOTE)
164
165 def testSpacedDefault(self):
166 # like new(S, ...)
167 result, ret_sig, note = self.m.parse_func_doc('blah f(a, b = 1) ololo', "f", "f", None)
168 self.assertEquals(result, "f(a, b=1)")
169 self.assertEquals(note, M.SIG_DOC_NOTE)
170
171 def testSpacedName(self):
172 # like new(S, ...)
173 result, ret_sig, note = self.m.parse_func_doc('blah femme(skirt or pants) ololo', "femme", "femme", None)
174 self.assertEquals(result, "femme(skirt_or_pants)")
175 self.assertEquals(note, M.SIG_DOC_NOTE)
176
177
178class TestRestoreMethodByDocComment(unittest.TestCase):
179 """
180 Restoring with a class name set
181 """
182
183 def setUp(self):
184 self.m = ModuleRedeclarator(None, None, '/dev/null')
185
186 def testPlainMethod(self):
187 result, ret_sig, note = self.m.parse_func_doc("blah f(self, foo, bar) ololo", "f", "f", "SomeClass")
188 self.assertEquals(result, "f(self, foo, bar)")
189 self.assertEquals(note, M.SIG_DOC_NOTE)
190
191 def testInsertSelf(self):
192 result, ret_sig, note = self.m.parse_func_doc("blah f(foo, bar) ololo", "f", "f", "SomeClass")
193 self.assertEquals(result, "f(self, foo, bar)")
194 self.assertEquals(note, M.SIG_DOC_NOTE)
195
196
197class TestAnnotatedParameters(unittest.TestCase):
198 """
199 f(foo: int) and friends; in doc comments, happen in 2.x world, too.
200 """
201
202 def setUp(self):
203 self.m = ModuleRedeclarator(None, None, '/dev/null')
204
205 def testMixed(self):
206 result, ret_sig, note = self.m.parse_func_doc('blah f(i: int, foo) ololo', "f", "f", None)
207 self.assertEquals(result, "f(i, foo)")
208 self.assertEquals(note, M.SIG_DOC_NOTE)
209
210 def testNested(self):
211 result, ret_sig, note = self.m.parse_func_doc('blah f(i: int, (foo: bar, boo: Decimal)) ololo', "f", "f", None)
212 self.assertEquals(result, "f(i, (foo, boo))")
213 self.assertEquals(note, M.SIG_DOC_NOTE)
214
215 def testSpaced(self):
216 result, ret_sig, note = self.m.parse_func_doc('blah f(i: int, j :int, k : int) ololo', "f", "f", None)
217 self.assertEquals(result, "f(i, j, k)")
218 self.assertEquals(note, M.SIG_DOC_NOTE)
219
220
221if not IS_CLI and VERSION < (3, 0):
222 class TestInspect(unittest.TestCase):
223 """
224 See that inspect actually works if needed
225 """
226
227 def setUp(self):
228 self.m = ModuleRedeclarator(None, None, '/dev/null')
229
230 def testSimple(self):
231 def target(a, b, c=1, *d, **e):
232 return a, b, c, d, e
233
234 result = restore_by_inspect(target)
235 self.assertEquals(result, "(a, b, c=1, *d, **e)")
236
237 def testNested(self):
238 # NOTE: Py3k can't handle nested tuple args, thus we compile it conditionally
239 code = (
240 "def target(a, (b, c), d, e=1):\n"
241 " return a, b, c, d, e"
242 )
243 namespace = {}
244 eval(compile(code, "__main__", "single"), namespace)
245 target = namespace['target']
246
247 result = restore_by_inspect(target)
248 self.assertEquals(result, "(a, (b, c), d, e=1)")
249
250class _DiffPrintingTestCase(unittest.TestCase):
251 def assertEquals(self, etalon, specimen, msg=None):
252 if type(etalon) == str and type(specimen) == str and etalon != specimen:
253 print("%s" % "\n")
254 # print side by side
255 ei = iter(etalon.split("\n"))
256 si = iter(specimen.split("\n"))
257 if VERSION < (3, 0):
258 si_next = si.next
259 else:
260 si_next = si.__next__
261 for el in ei:
262 try: sl = si_next()
263 except StopIteration: break # I wish the exception would just work as break
264 if el != sl:
265 print("!%s" % el)
266 print("?%s" % sl)
267 else:
268 print(">%s" % sl)
269 # one of the iters might not end yet
270 for el in ei:
271 print("!%s" % el)
272 for sl in si:
273 print("?%s" % sl)
274 raise self.failureException(msg)
275 else:
276 self.failUnlessEqual(etalon, specimen, msg)
277
278
279class TestSpecialCases(unittest.TestCase):
280 """
281 Tests cases where predefined overrides kick in
282 """
283
284 def setUp(self):
285 import sys
286
287 if VERSION >= (3, 0):
288 import builtins as the_builtins
289
290 self.builtins_name = the_builtins.__name__
291 else:
292 import __builtin__ as the_builtins
293
294 self.builtins_name = the_builtins.__name__
295 self.m = ModuleRedeclarator(the_builtins, None, '/dev/null', doing_builtins=True)
296
297 def _testBuiltinFuncName(self, func_name, expected):
298 class_name = None
299 self.assertTrue(self.m.is_predefined_builtin(self.builtins_name, class_name, func_name))
300 result, note = restore_predefined_builtin(class_name, func_name)
301 self.assertEquals(result, func_name + expected)
302 self.assertEquals(note, "known special case of " + func_name)
303
304 def testZip(self):
305 self._testBuiltinFuncName("zip", "(seq1, seq2, *more_seqs)")
306
307 def testRange(self):
308 self._testBuiltinFuncName("range", "(start=None, stop=None, step=None)")
309
310 def testFilter(self):
311 self._testBuiltinFuncName("filter", "(function_or_none, sequence)")
312
313 # we caould want to test a calss without __dict__, but it takes a C extension to really create one,
314
315class TestDataOutput(_DiffPrintingTestCase):
316 """
317 Tests for sanity of output of data members
318 """
319
320 def setUp(self):
321 self.m = ModuleRedeclarator(self, None, 4) # Pass anything with __dict__ as module
322
323 def checkFmtValue(self, data, expected):
324 buf = Buf(self.m)
325 self.m.fmt_value(buf.out, data, 0)
326 result = "".join(buf.data).strip()
327 self.assertEquals(expected, result)
328
329 def testRecursiveDict(self):
330 data = {'a': 1}
331 data['b'] = data
332 expected = "\n".join((
333 "{",
334 " 'a': 1,",
335 " 'b': '<value is a self-reference, replaced by this string>',",
336 "}"
337 ))
338 self.checkFmtValue(data, expected)
339
340 def testRecursiveList(self):
341 data = [1]
342 data.append(data)
343 data.append(2)
344 data.append([10, data, 20])
345 expected = "\n".join((
346 "[",
347 " 1,",
348 " '<value is a self-reference, replaced by this string>',",
349 " 2,",
350 " [",
351 " 10,",
352 " '<value is a self-reference, replaced by this string>',",
353 " 20,",
354 " ],",
355 "]"
356 ))
357 self.checkFmtValue(data, expected)
358
359if not IS_CLI:
360 class TestReturnTypes(unittest.TestCase):
361 """
362 Tests for sanity of output of data members
363 """
364
365 def setUp(self):
366 self.m = ModuleRedeclarator(None, None, 4)
367
368 def checkRestoreFunction(self, doc, expected):
369 spec, ret_literal, note = self.m.parse_func_doc(doc, "foo", "foo", None)
370 self.assertEqual(expected, ret_literal, "%r != %r; spec=%r, note=%r" % (expected, ret_literal, spec, note))
371 pass
372
373 def testSimpleArrowInt(self):
374 doc = "This is foo(bar) -> int"
375 self.checkRestoreFunction(doc, "0")
376
377 def testSimpleArrowList(self):
378 doc = "This is foo(bar) -> list"
379 self.checkRestoreFunction(doc, "[]")
380
381 def testArrowListOf(self):
382 doc = "This is foo(bar) -> list of int"
383 self.checkRestoreFunction(doc, "[]")
384
385 # def testArrowTupleOf(self):
386 # doc = "This is foo(bar) -> (a, b,..)"
387 # self.checkRestoreFunction(doc, "()")
388
389 def testSimplePrefixInt(self):
390 doc = "This is int foo(bar)"
391 self.checkRestoreFunction(doc, "0")
392
393 def testSimplePrefixObject(self):
394 doc = "Makes an instance: object foo(bar)"
395 self.checkRestoreFunction(doc, "object()")
396
397 if VERSION < (3, 0):
398 # TODO: we only support it in 2.x; must update when we do it in 3.x, too
399 def testSimpleArrowFile(self):
400 doc = "Opens a file: foo(bar) -> file"
401 self.checkRestoreFunction(doc, "file('/dev/null')")
402
403 def testUnrelatedPrefix(self):
404 doc = """
405 Consumes a list of int
406 foo(bar)
407 """
408 self.checkRestoreFunction(doc, None)
409
410
411###
412if __name__ == '__main__':
413 unittest.main()