Commit | Line | Data |
---|---|---|
86530b38 AT |
1 | "Test the functionality of Python classes implementing operators." |
2 | ||
3 | from test.test_support import TestFailed | |
4 | ||
5 | testmeths = [ | |
6 | ||
7 | # Binary operations | |
8 | "add", | |
9 | "radd", | |
10 | "sub", | |
11 | "rsub", | |
12 | "mul", | |
13 | "rmul", | |
14 | "div", | |
15 | "rdiv", | |
16 | "mod", | |
17 | "rmod", | |
18 | "divmod", | |
19 | "rdivmod", | |
20 | "pow", | |
21 | "rpow", | |
22 | "rshift", | |
23 | "rrshift", | |
24 | "lshift", | |
25 | "rlshift", | |
26 | "and", | |
27 | "rand", | |
28 | "or", | |
29 | "ror", | |
30 | "xor", | |
31 | "rxor", | |
32 | ||
33 | # List/dict operations | |
34 | "contains", | |
35 | "getitem", | |
36 | "getslice", | |
37 | "setitem", | |
38 | "setslice", | |
39 | "delitem", | |
40 | "delslice", | |
41 | ||
42 | # Unary operations | |
43 | "neg", | |
44 | "pos", | |
45 | "abs", | |
46 | ||
47 | # generic operations | |
48 | "init", | |
49 | ] | |
50 | ||
51 | # These need to return something other than None | |
52 | # "coerce", | |
53 | # "hash", | |
54 | # "str", | |
55 | # "repr", | |
56 | # "int", | |
57 | # "long", | |
58 | # "float", | |
59 | # "oct", | |
60 | # "hex", | |
61 | ||
62 | # These are separate because they can influence the test of other methods. | |
63 | # "getattr", | |
64 | # "setattr", | |
65 | # "delattr", | |
66 | ||
67 | class AllTests: | |
68 | def __coerce__(self, *args): | |
69 | print "__coerce__:", args | |
70 | return (self,) + args | |
71 | ||
72 | def __hash__(self, *args): | |
73 | print "__hash__:", args | |
74 | return hash(id(self)) | |
75 | ||
76 | def __str__(self, *args): | |
77 | print "__str__:", args | |
78 | return "AllTests" | |
79 | ||
80 | def __repr__(self, *args): | |
81 | print "__repr__:", args | |
82 | return "AllTests" | |
83 | ||
84 | def __int__(self, *args): | |
85 | print "__int__:", args | |
86 | return 1 | |
87 | ||
88 | def __float__(self, *args): | |
89 | print "__float__:", args | |
90 | return 1.0 | |
91 | ||
92 | def __long__(self, *args): | |
93 | print "__long__:", args | |
94 | return 1L | |
95 | ||
96 | def __oct__(self, *args): | |
97 | print "__oct__:", args | |
98 | return '01' | |
99 | ||
100 | def __hex__(self, *args): | |
101 | print "__hex__:", args | |
102 | return '0x1' | |
103 | ||
104 | def __cmp__(self, *args): | |
105 | print "__cmp__:", args | |
106 | return 0 | |
107 | ||
108 | def __del__(self, *args): | |
109 | print "__del__:", args | |
110 | ||
111 | # Synthesize AllTests methods from the names in testmeths. | |
112 | ||
113 | method_template = """\ | |
114 | def __%(method)s__(self, *args): | |
115 | print "__%(method)s__:", args | |
116 | """ | |
117 | ||
118 | for method in testmeths: | |
119 | exec method_template % locals() in AllTests.__dict__ | |
120 | ||
121 | del method, method_template | |
122 | ||
123 | # this also tests __init__ of course. | |
124 | testme = AllTests() | |
125 | ||
126 | # Binary operations | |
127 | ||
128 | testme + 1 | |
129 | 1 + testme | |
130 | ||
131 | testme - 1 | |
132 | 1 - testme | |
133 | ||
134 | testme * 1 | |
135 | 1 * testme | |
136 | ||
137 | if 1/2 == 0: | |
138 | testme / 1 | |
139 | 1 / testme | |
140 | else: | |
141 | # True division is in effect, so "/" doesn't map to __div__ etc; but | |
142 | # the canned expected-output file requires that __div__ etc get called. | |
143 | testme.__coerce__(1) | |
144 | testme.__div__(1) | |
145 | testme.__coerce__(1) | |
146 | testme.__rdiv__(1) | |
147 | ||
148 | testme % 1 | |
149 | 1 % testme | |
150 | ||
151 | divmod(testme,1) | |
152 | divmod(1, testme) | |
153 | ||
154 | testme ** 1 | |
155 | 1 ** testme | |
156 | ||
157 | testme >> 1 | |
158 | 1 >> testme | |
159 | ||
160 | testme << 1 | |
161 | 1 << testme | |
162 | ||
163 | testme & 1 | |
164 | 1 & testme | |
165 | ||
166 | testme | 1 | |
167 | 1 | testme | |
168 | ||
169 | testme ^ 1 | |
170 | 1 ^ testme | |
171 | ||
172 | ||
173 | # List/dict operations | |
174 | ||
175 | 1 in testme | |
176 | ||
177 | testme[1] | |
178 | testme[1] = 1 | |
179 | del testme[1] | |
180 | ||
181 | testme[:42] | |
182 | testme[:42] = "The Answer" | |
183 | del testme[:42] | |
184 | ||
185 | testme[2:1024:10] | |
186 | testme[2:1024:10] = "A lot" | |
187 | del testme[2:1024:10] | |
188 | ||
189 | testme[:42, ..., :24:, 24, 100] | |
190 | testme[:42, ..., :24:, 24, 100] = "Strange" | |
191 | del testme[:42, ..., :24:, 24, 100] | |
192 | ||
193 | ||
194 | # Now remove the slice hooks to see if converting normal slices to slice | |
195 | # object works. | |
196 | ||
197 | del AllTests.__getslice__ | |
198 | del AllTests.__setslice__ | |
199 | del AllTests.__delslice__ | |
200 | ||
201 | import sys | |
202 | if sys.platform[:4] != 'java': | |
203 | testme[:42] | |
204 | testme[:42] = "The Answer" | |
205 | del testme[:42] | |
206 | else: | |
207 | # This works under Jython, but the actual slice values are | |
208 | # different. | |
209 | print "__getitem__: (slice(0, 42, None),)" | |
210 | print "__setitem__: (slice(0, 42, None), 'The Answer')" | |
211 | print "__delitem__: (slice(0, 42, None),)" | |
212 | ||
213 | # Unary operations | |
214 | ||
215 | -testme | |
216 | +testme | |
217 | abs(testme) | |
218 | int(testme) | |
219 | long(testme) | |
220 | float(testme) | |
221 | oct(testme) | |
222 | hex(testme) | |
223 | ||
224 | # And the rest... | |
225 | ||
226 | hash(testme) | |
227 | repr(testme) | |
228 | str(testme) | |
229 | ||
230 | testme == 1 | |
231 | testme < 1 | |
232 | testme > 1 | |
233 | testme <> 1 | |
234 | testme != 1 | |
235 | 1 == testme | |
236 | 1 < testme | |
237 | 1 > testme | |
238 | 1 <> testme | |
239 | 1 != testme | |
240 | ||
241 | # This test has to be last (duh.) | |
242 | ||
243 | del testme | |
244 | if sys.platform[:4] == 'java': | |
245 | import java | |
246 | java.lang.System.gc() | |
247 | ||
248 | # Interfering tests | |
249 | ||
250 | class ExtraTests: | |
251 | def __getattr__(self, *args): | |
252 | print "__getattr__:", args | |
253 | return "SomeVal" | |
254 | ||
255 | def __setattr__(self, *args): | |
256 | print "__setattr__:", args | |
257 | ||
258 | def __delattr__(self, *args): | |
259 | print "__delattr__:", args | |
260 | ||
261 | testme = ExtraTests() | |
262 | testme.spam | |
263 | testme.eggs = "spam, spam, spam and ham" | |
264 | del testme.cardinal | |
265 | ||
266 | ||
267 | # return values of some method are type-checked | |
268 | class BadTypeClass: | |
269 | def __int__(self): | |
270 | return None | |
271 | __float__ = __int__ | |
272 | __long__ = __int__ | |
273 | __str__ = __int__ | |
274 | __repr__ = __int__ | |
275 | __oct__ = __int__ | |
276 | __hex__ = __int__ | |
277 | ||
278 | def check_exc(stmt, exception): | |
279 | """Raise TestFailed if executing 'stmt' does not raise 'exception' | |
280 | """ | |
281 | try: | |
282 | exec stmt | |
283 | except exception: | |
284 | pass | |
285 | else: | |
286 | raise TestFailed, "%s should raise %s" % (stmt, exception) | |
287 | ||
288 | check_exc("int(BadTypeClass())", TypeError) | |
289 | check_exc("float(BadTypeClass())", TypeError) | |
290 | check_exc("long(BadTypeClass())", TypeError) | |
291 | check_exc("str(BadTypeClass())", TypeError) | |
292 | check_exc("repr(BadTypeClass())", TypeError) | |
293 | check_exc("oct(BadTypeClass())", TypeError) | |
294 | check_exc("hex(BadTypeClass())", TypeError) | |
295 | ||
296 | # mixing up ints and longs is okay | |
297 | class IntLongMixClass: | |
298 | def __int__(self): | |
299 | return 0L | |
300 | ||
301 | def __long__(self): | |
302 | return 0 | |
303 | ||
304 | try: | |
305 | int(IntLongMixClass()) | |
306 | except TypeError: | |
307 | raise TestFailed, "TypeError should not be raised" | |
308 | ||
309 | try: | |
310 | long(IntLongMixClass()) | |
311 | except TypeError: | |
312 | raise TestFailed, "TypeError should not be raised" | |
313 | ||
314 | ||
315 | # Test correct errors from hash() on objects with comparisons but no __hash__ | |
316 | ||
317 | class C0: | |
318 | pass | |
319 | ||
320 | hash(C0()) # This should work; the next two should raise TypeError | |
321 | ||
322 | class C1: | |
323 | def __cmp__(self, other): return 0 | |
324 | ||
325 | check_exc("hash(C1())", TypeError) | |
326 | ||
327 | class C2: | |
328 | def __eq__(self, other): return 1 | |
329 | ||
330 | check_exc("hash(C2())", TypeError) | |
331 | ||
332 | # Test for SF bug 532646 | |
333 | ||
334 | class A: | |
335 | pass | |
336 | A.__call__ = A() | |
337 | a = A() | |
338 | try: | |
339 | a() # This should not segfault | |
340 | except RuntimeError: | |
341 | pass | |
342 | else: | |
343 | raise TestFailed, "how could this not have overflowed the stack?" | |
344 | ||
345 | ||
346 | # Tests for exceptions raised in instance_getattr2(). | |
347 | ||
348 | def booh(self): | |
349 | raise AttributeError, "booh" | |
350 | ||
351 | class A: | |
352 | a = property(booh) | |
353 | try: | |
354 | A().a # Raised AttributeError: A instance has no attribute 'a' | |
355 | except AttributeError, x: | |
356 | if str(x) != "booh": | |
357 | print "attribute error for A().a got masked:", str(x) | |
358 | ||
359 | class E: | |
360 | __eq__ = property(booh) | |
361 | E() == E() # In debug mode, caused a C-level assert() to fail | |
362 | ||
363 | class I: | |
364 | __init__ = property(booh) | |
365 | try: | |
366 | I() # In debug mode, printed XXX undetected error and raises AttributeError | |
367 | except AttributeError, x: | |
368 | pass | |
369 | else: | |
370 | print "attribute error for I.__init__ got masked" |