blob: 4b947d82e475eccb84ce366f5d62c00125566f71 [file] [log] [blame]
Tim Peters400cbc32006-02-28 18:44:41 +00001#!/usr/bin/env python
2
3"""Unit tests for the with statement specified in PEP 343."""
4
Thomas Wouters34aa7ba2006-02-28 19:02:24 +00005
Tim Peters400cbc32006-02-28 18:44:41 +00006__author__ = "Mike Bland"
7__email__ = "mbland at acm dot org"
8
Guido van Rossum1a5e21e2006-02-28 21:57:43 +00009import sys
Tim Peters400cbc32006-02-28 18:44:41 +000010import unittest
Guido van Rossum1a5e21e2006-02-28 21:57:43 +000011from collections import deque
Nick Coghlanafd5e632006-05-03 13:02:47 +000012from contextlib import GeneratorContextManager, contextmanager
Tim Peters400cbc32006-02-28 18:44:41 +000013from test.test_support import run_unittest
14
15
Nick Coghlanafd5e632006-05-03 13:02:47 +000016class MockContextManager(GeneratorContextManager):
Tim Peters400cbc32006-02-28 18:44:41 +000017 def __init__(self, gen):
Nick Coghlanafd5e632006-05-03 13:02:47 +000018 GeneratorContextManager.__init__(self, gen)
Tim Peters400cbc32006-02-28 18:44:41 +000019 self.enter_called = False
20 self.exit_called = False
21 self.exit_args = None
22
Tim Peters400cbc32006-02-28 18:44:41 +000023 def __enter__(self):
24 self.enter_called = True
Nick Coghlanafd5e632006-05-03 13:02:47 +000025 return GeneratorContextManager.__enter__(self)
Tim Peters400cbc32006-02-28 18:44:41 +000026
27 def __exit__(self, type, value, traceback):
28 self.exit_called = True
29 self.exit_args = (type, value, traceback)
Nick Coghlanafd5e632006-05-03 13:02:47 +000030 return GeneratorContextManager.__exit__(self, type,
31 value, traceback)
Tim Peters400cbc32006-02-28 18:44:41 +000032
33
34def mock_contextmanager(func):
35 def helper(*args, **kwds):
36 return MockContextManager(func(*args, **kwds))
37 return helper
38
39
40class MockResource(object):
41 def __init__(self):
42 self.yielded = False
43 self.stopped = False
44
45
46@mock_contextmanager
47def mock_contextmanager_generator():
48 mock = MockResource()
49 try:
50 mock.yielded = True
51 yield mock
52 finally:
53 mock.stopped = True
54
55
Guido van Rossum1a5e21e2006-02-28 21:57:43 +000056class Nested(object):
57
Guido van Rossumda5b7012006-05-02 19:47:52 +000058 def __init__(self, *managers):
59 self.managers = managers
Guido van Rossum1a5e21e2006-02-28 21:57:43 +000060 self.entered = None
61
Guido van Rossum1a5e21e2006-02-28 21:57:43 +000062 def __enter__(self):
63 if self.entered is not None:
64 raise RuntimeError("Context is not reentrant")
65 self.entered = deque()
66 vars = []
67 try:
Guido van Rossumda5b7012006-05-02 19:47:52 +000068 for mgr in self.managers:
Guido van Rossum1a5e21e2006-02-28 21:57:43 +000069 vars.append(mgr.__enter__())
70 self.entered.appendleft(mgr)
71 except:
Guido van Rossumf6694362006-03-10 02:28:35 +000072 if not self.__exit__(*sys.exc_info()):
73 raise
Guido van Rossum1a5e21e2006-02-28 21:57:43 +000074 return vars
75
76 def __exit__(self, *exc_info):
77 # Behave like nested with statements
78 # first in, last out
79 # New exceptions override old ones
80 ex = exc_info
81 for mgr in self.entered:
82 try:
Guido van Rossumf6694362006-03-10 02:28:35 +000083 if mgr.__exit__(*ex):
84 ex = (None, None, None)
Guido van Rossum1a5e21e2006-02-28 21:57:43 +000085 except:
86 ex = sys.exc_info()
87 self.entered = None
88 if ex is not exc_info:
89 raise ex[0], ex[1], ex[2]
90
91
92class MockNested(Nested):
Guido van Rossumda5b7012006-05-02 19:47:52 +000093 def __init__(self, *managers):
94 Nested.__init__(self, *managers)
Tim Peters400cbc32006-02-28 18:44:41 +000095 self.enter_called = False
96 self.exit_called = False
97 self.exit_args = None
98
Tim Peters400cbc32006-02-28 18:44:41 +000099 def __enter__(self):
100 self.enter_called = True
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000101 return Nested.__enter__(self)
Tim Peters400cbc32006-02-28 18:44:41 +0000102
103 def __exit__(self, *exc_info):
104 self.exit_called = True
105 self.exit_args = exc_info
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000106 return Nested.__exit__(self, *exc_info)
Tim Peters400cbc32006-02-28 18:44:41 +0000107
108
109class FailureTestCase(unittest.TestCase):
110 def testNameError(self):
111 def fooNotDeclared():
112 with foo: pass
113 self.assertRaises(NameError, fooNotDeclared)
114
Tim Peters400cbc32006-02-28 18:44:41 +0000115 def testEnterAttributeError(self):
116 class LacksEnter(object):
Tim Peters400cbc32006-02-28 18:44:41 +0000117 def __exit__(self, type, value, traceback):
118 pass
119
120 def fooLacksEnter():
121 foo = LacksEnter()
122 with foo: pass
123 self.assertRaises(AttributeError, fooLacksEnter)
124
125 def testExitAttributeError(self):
126 class LacksExit(object):
Tim Peters400cbc32006-02-28 18:44:41 +0000127 def __enter__(self):
128 pass
129
130 def fooLacksExit():
131 foo = LacksExit()
132 with foo: pass
133 self.assertRaises(AttributeError, fooLacksExit)
134
135 def assertRaisesSyntaxError(self, codestr):
136 def shouldRaiseSyntaxError(s):
137 compile(s, '', 'single')
138 self.assertRaises(SyntaxError, shouldRaiseSyntaxError, codestr)
139
140 def testAssignmentToNoneError(self):
141 self.assertRaisesSyntaxError('with mock as None:\n pass')
142 self.assertRaisesSyntaxError(
143 'with mock as (None):\n'
144 ' pass')
145
146 def testAssignmentToEmptyTupleError(self):
147 self.assertRaisesSyntaxError(
148 'with mock as ():\n'
149 ' pass')
150
151 def testAssignmentToTupleOnlyContainingNoneError(self):
152 self.assertRaisesSyntaxError('with mock as None,:\n pass')
153 self.assertRaisesSyntaxError(
154 'with mock as (None,):\n'
155 ' pass')
156
157 def testAssignmentToTupleContainingNoneError(self):
158 self.assertRaisesSyntaxError(
159 'with mock as (foo, None, bar):\n'
160 ' pass')
161
Tim Peters400cbc32006-02-28 18:44:41 +0000162 def testEnterThrows(self):
163 class EnterThrows(object):
Tim Peters400cbc32006-02-28 18:44:41 +0000164 def __enter__(self):
Guido van Rossumda5b7012006-05-02 19:47:52 +0000165 raise RuntimeError("Enter threw")
Tim Peters400cbc32006-02-28 18:44:41 +0000166 def __exit__(self, *args):
167 pass
168
169 def shouldThrow():
170 ct = EnterThrows()
171 self.foo = None
172 with ct as self.foo:
173 pass
174 self.assertRaises(RuntimeError, shouldThrow)
175 self.assertEqual(self.foo, None)
176
177 def testExitThrows(self):
178 class ExitThrows(object):
Tim Peters400cbc32006-02-28 18:44:41 +0000179 def __enter__(self):
180 return
181 def __exit__(self, *args):
182 raise RuntimeError(42)
183 def shouldThrow():
184 with ExitThrows():
185 pass
186 self.assertRaises(RuntimeError, shouldThrow)
187
188class ContextmanagerAssertionMixin(object):
189 TEST_EXCEPTION = RuntimeError("test exception")
190
191 def assertInWithManagerInvariants(self, mock_manager):
Tim Peters400cbc32006-02-28 18:44:41 +0000192 self.assertTrue(mock_manager.enter_called)
193 self.assertFalse(mock_manager.exit_called)
194 self.assertEqual(mock_manager.exit_args, None)
195
196 def assertAfterWithManagerInvariants(self, mock_manager, exit_args):
Tim Peters400cbc32006-02-28 18:44:41 +0000197 self.assertTrue(mock_manager.enter_called)
198 self.assertTrue(mock_manager.exit_called)
199 self.assertEqual(mock_manager.exit_args, exit_args)
200
201 def assertAfterWithManagerInvariantsNoError(self, mock_manager):
202 self.assertAfterWithManagerInvariants(mock_manager,
203 (None, None, None))
204
205 def assertInWithGeneratorInvariants(self, mock_generator):
206 self.assertTrue(mock_generator.yielded)
207 self.assertFalse(mock_generator.stopped)
208
209 def assertAfterWithGeneratorInvariantsNoError(self, mock_generator):
210 self.assertTrue(mock_generator.yielded)
211 self.assertTrue(mock_generator.stopped)
212
213 def raiseTestException(self):
214 raise self.TEST_EXCEPTION
215
Benjamin Peterson4a7ff1d2010-02-05 01:53:27 +0000216 def assertAfterWithManagerInvariantsWithError(self, mock_manager,
217 exc_type=None):
Tim Peters400cbc32006-02-28 18:44:41 +0000218 self.assertTrue(mock_manager.enter_called)
219 self.assertTrue(mock_manager.exit_called)
Benjamin Peterson4a7ff1d2010-02-05 01:53:27 +0000220 if exc_type is None:
221 self.assertEqual(mock_manager.exit_args[1], self.TEST_EXCEPTION)
222 exc_type = type(self.TEST_EXCEPTION)
223 self.assertEqual(mock_manager.exit_args[0], exc_type)
224 # Test the __exit__ arguments. Issue #7853
225 self.assertIsInstance(mock_manager.exit_args[1], exc_type)
226 self.assertIsNot(mock_manager.exit_args[2], None)
Tim Peters400cbc32006-02-28 18:44:41 +0000227
228 def assertAfterWithGeneratorInvariantsWithError(self, mock_generator):
229 self.assertTrue(mock_generator.yielded)
230 self.assertTrue(mock_generator.stopped)
231
232
233class NonexceptionalTestCase(unittest.TestCase, ContextmanagerAssertionMixin):
234 def testInlineGeneratorSyntax(self):
235 with mock_contextmanager_generator():
236 pass
237
238 def testUnboundGenerator(self):
239 mock = mock_contextmanager_generator()
240 with mock:
241 pass
242 self.assertAfterWithManagerInvariantsNoError(mock)
243
244 def testInlineGeneratorBoundSyntax(self):
245 with mock_contextmanager_generator() as foo:
246 self.assertInWithGeneratorInvariants(foo)
247 # FIXME: In the future, we'll try to keep the bound names from leaking
248 self.assertAfterWithGeneratorInvariantsNoError(foo)
249
250 def testInlineGeneratorBoundToExistingVariable(self):
251 foo = None
252 with mock_contextmanager_generator() as foo:
253 self.assertInWithGeneratorInvariants(foo)
254 self.assertAfterWithGeneratorInvariantsNoError(foo)
255
256 def testInlineGeneratorBoundToDottedVariable(self):
257 with mock_contextmanager_generator() as self.foo:
258 self.assertInWithGeneratorInvariants(self.foo)
259 self.assertAfterWithGeneratorInvariantsNoError(self.foo)
260
261 def testBoundGenerator(self):
262 mock = mock_contextmanager_generator()
263 with mock as foo:
264 self.assertInWithGeneratorInvariants(foo)
265 self.assertInWithManagerInvariants(mock)
266 self.assertAfterWithGeneratorInvariantsNoError(foo)
267 self.assertAfterWithManagerInvariantsNoError(mock)
268
269 def testNestedSingleStatements(self):
270 mock_a = mock_contextmanager_generator()
271 with mock_a as foo:
272 mock_b = mock_contextmanager_generator()
273 with mock_b as bar:
274 self.assertInWithManagerInvariants(mock_a)
275 self.assertInWithManagerInvariants(mock_b)
276 self.assertInWithGeneratorInvariants(foo)
277 self.assertInWithGeneratorInvariants(bar)
278 self.assertAfterWithManagerInvariantsNoError(mock_b)
279 self.assertAfterWithGeneratorInvariantsNoError(bar)
280 self.assertInWithManagerInvariants(mock_a)
281 self.assertInWithGeneratorInvariants(foo)
282 self.assertAfterWithManagerInvariantsNoError(mock_a)
283 self.assertAfterWithGeneratorInvariantsNoError(foo)
284
285
286class NestedNonexceptionalTestCase(unittest.TestCase,
287 ContextmanagerAssertionMixin):
288 def testSingleArgInlineGeneratorSyntax(self):
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000289 with Nested(mock_contextmanager_generator()):
Tim Peters400cbc32006-02-28 18:44:41 +0000290 pass
291
Tim Peters400cbc32006-02-28 18:44:41 +0000292 def testSingleArgBoundToNonTuple(self):
293 m = mock_contextmanager_generator()
294 # This will bind all the arguments to nested() into a single list
295 # assigned to foo.
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000296 with Nested(m) as foo:
Tim Peters400cbc32006-02-28 18:44:41 +0000297 self.assertInWithManagerInvariants(m)
298 self.assertAfterWithManagerInvariantsNoError(m)
299
300 def testSingleArgBoundToSingleElementParenthesizedList(self):
301 m = mock_contextmanager_generator()
302 # This will bind all the arguments to nested() into a single list
303 # assigned to foo.
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000304 with Nested(m) as (foo):
Tim Peters400cbc32006-02-28 18:44:41 +0000305 self.assertInWithManagerInvariants(m)
306 self.assertAfterWithManagerInvariantsNoError(m)
307
308 def testSingleArgBoundToMultipleElementTupleError(self):
309 def shouldThrowValueError():
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000310 with Nested(mock_contextmanager_generator()) as (foo, bar):
Tim Peters400cbc32006-02-28 18:44:41 +0000311 pass
312 self.assertRaises(ValueError, shouldThrowValueError)
313
314 def testSingleArgUnbound(self):
315 mock_contextmanager = mock_contextmanager_generator()
316 mock_nested = MockNested(mock_contextmanager)
317 with mock_nested:
318 self.assertInWithManagerInvariants(mock_contextmanager)
319 self.assertInWithManagerInvariants(mock_nested)
320 self.assertAfterWithManagerInvariantsNoError(mock_contextmanager)
321 self.assertAfterWithManagerInvariantsNoError(mock_nested)
322
323 def testMultipleArgUnbound(self):
324 m = mock_contextmanager_generator()
325 n = mock_contextmanager_generator()
326 o = mock_contextmanager_generator()
327 mock_nested = MockNested(m, n, o)
328 with mock_nested:
329 self.assertInWithManagerInvariants(m)
330 self.assertInWithManagerInvariants(n)
331 self.assertInWithManagerInvariants(o)
332 self.assertInWithManagerInvariants(mock_nested)
333 self.assertAfterWithManagerInvariantsNoError(m)
334 self.assertAfterWithManagerInvariantsNoError(n)
335 self.assertAfterWithManagerInvariantsNoError(o)
336 self.assertAfterWithManagerInvariantsNoError(mock_nested)
337
338 def testMultipleArgBound(self):
339 mock_nested = MockNested(mock_contextmanager_generator(),
340 mock_contextmanager_generator(), mock_contextmanager_generator())
341 with mock_nested as (m, n, o):
342 self.assertInWithGeneratorInvariants(m)
343 self.assertInWithGeneratorInvariants(n)
344 self.assertInWithGeneratorInvariants(o)
345 self.assertInWithManagerInvariants(mock_nested)
346 self.assertAfterWithGeneratorInvariantsNoError(m)
347 self.assertAfterWithGeneratorInvariantsNoError(n)
348 self.assertAfterWithGeneratorInvariantsNoError(o)
349 self.assertAfterWithManagerInvariantsNoError(mock_nested)
350
351
352class ExceptionalTestCase(unittest.TestCase, ContextmanagerAssertionMixin):
353 def testSingleResource(self):
354 cm = mock_contextmanager_generator()
355 def shouldThrow():
356 with cm as self.resource:
357 self.assertInWithManagerInvariants(cm)
358 self.assertInWithGeneratorInvariants(self.resource)
359 self.raiseTestException()
360 self.assertRaises(RuntimeError, shouldThrow)
361 self.assertAfterWithManagerInvariantsWithError(cm)
362 self.assertAfterWithGeneratorInvariantsWithError(self.resource)
363
Benjamin Peterson4a7ff1d2010-02-05 01:53:27 +0000364 @unittest.expectedFailure
365 def testExceptionNormalized(self):
366 cm = mock_contextmanager_generator()
367 def shouldThrow():
368 with cm as self.resource:
369 # Note this relies on the fact that 1 // 0 produces an exception
370 # that is not normalized immediately.
371 1 // 0
372 self.assertRaises(ZeroDivisionError, shouldThrow)
373 self.assertAfterWithManagerInvariantsWithError(cm, ZeroDivisionError)
374
Tim Peters400cbc32006-02-28 18:44:41 +0000375 def testNestedSingleStatements(self):
376 mock_a = mock_contextmanager_generator()
377 mock_b = mock_contextmanager_generator()
378 def shouldThrow():
379 with mock_a as self.foo:
380 with mock_b as self.bar:
381 self.assertInWithManagerInvariants(mock_a)
382 self.assertInWithManagerInvariants(mock_b)
383 self.assertInWithGeneratorInvariants(self.foo)
384 self.assertInWithGeneratorInvariants(self.bar)
385 self.raiseTestException()
386 self.assertRaises(RuntimeError, shouldThrow)
387 self.assertAfterWithManagerInvariantsWithError(mock_a)
388 self.assertAfterWithManagerInvariantsWithError(mock_b)
389 self.assertAfterWithGeneratorInvariantsWithError(self.foo)
390 self.assertAfterWithGeneratorInvariantsWithError(self.bar)
391
392 def testMultipleResourcesInSingleStatement(self):
393 cm_a = mock_contextmanager_generator()
394 cm_b = mock_contextmanager_generator()
395 mock_nested = MockNested(cm_a, cm_b)
396 def shouldThrow():
397 with mock_nested as (self.resource_a, self.resource_b):
398 self.assertInWithManagerInvariants(cm_a)
399 self.assertInWithManagerInvariants(cm_b)
400 self.assertInWithManagerInvariants(mock_nested)
401 self.assertInWithGeneratorInvariants(self.resource_a)
402 self.assertInWithGeneratorInvariants(self.resource_b)
403 self.raiseTestException()
404 self.assertRaises(RuntimeError, shouldThrow)
405 self.assertAfterWithManagerInvariantsWithError(cm_a)
406 self.assertAfterWithManagerInvariantsWithError(cm_b)
407 self.assertAfterWithManagerInvariantsWithError(mock_nested)
408 self.assertAfterWithGeneratorInvariantsWithError(self.resource_a)
409 self.assertAfterWithGeneratorInvariantsWithError(self.resource_b)
410
411 def testNestedExceptionBeforeInnerStatement(self):
412 mock_a = mock_contextmanager_generator()
413 mock_b = mock_contextmanager_generator()
414 self.bar = None
415 def shouldThrow():
416 with mock_a as self.foo:
417 self.assertInWithManagerInvariants(mock_a)
418 self.assertInWithGeneratorInvariants(self.foo)
419 self.raiseTestException()
420 with mock_b as self.bar:
421 pass
422 self.assertRaises(RuntimeError, shouldThrow)
423 self.assertAfterWithManagerInvariantsWithError(mock_a)
424 self.assertAfterWithGeneratorInvariantsWithError(self.foo)
425
426 # The inner statement stuff should never have been touched
427 self.assertEqual(self.bar, None)
Tim Peters400cbc32006-02-28 18:44:41 +0000428 self.assertFalse(mock_b.enter_called)
429 self.assertFalse(mock_b.exit_called)
430 self.assertEqual(mock_b.exit_args, None)
431
432 def testNestedExceptionAfterInnerStatement(self):
433 mock_a = mock_contextmanager_generator()
434 mock_b = mock_contextmanager_generator()
435 def shouldThrow():
436 with mock_a as self.foo:
437 with mock_b as self.bar:
438 self.assertInWithManagerInvariants(mock_a)
439 self.assertInWithManagerInvariants(mock_b)
440 self.assertInWithGeneratorInvariants(self.foo)
441 self.assertInWithGeneratorInvariants(self.bar)
442 self.raiseTestException()
443 self.assertRaises(RuntimeError, shouldThrow)
444 self.assertAfterWithManagerInvariantsWithError(mock_a)
445 self.assertAfterWithManagerInvariantsNoError(mock_b)
446 self.assertAfterWithGeneratorInvariantsWithError(self.foo)
447 self.assertAfterWithGeneratorInvariantsNoError(self.bar)
448
Phillip J. Eby9444bd52006-04-03 20:05:05 +0000449 def testRaisedStopIteration1(self):
Nick Coghlan3814a912007-11-02 10:09:12 +0000450 # From bug 1462485
Nick Coghlanafd5e632006-05-03 13:02:47 +0000451 @contextmanager
Phillip J. Eby9444bd52006-04-03 20:05:05 +0000452 def cm():
453 yield
454
455 def shouldThrow():
456 with cm():
457 raise StopIteration("from with")
458
459 self.assertRaises(StopIteration, shouldThrow)
460
461 def testRaisedStopIteration2(self):
Nick Coghlan3814a912007-11-02 10:09:12 +0000462 # From bug 1462485
Guido van Rossumda5b7012006-05-02 19:47:52 +0000463 class cm(object):
Phillip J. Eby9444bd52006-04-03 20:05:05 +0000464 def __enter__(self):
465 pass
Phillip J. Eby9444bd52006-04-03 20:05:05 +0000466 def __exit__(self, type, value, traceback):
467 pass
468
469 def shouldThrow():
470 with cm():
471 raise StopIteration("from with")
472
473 self.assertRaises(StopIteration, shouldThrow)
474
Nick Coghlan3814a912007-11-02 10:09:12 +0000475 def testRaisedStopIteration3(self):
476 # Another variant where the exception hasn't been instantiated
477 # From bug 1705170
478 @contextmanager
479 def cm():
480 yield
481
482 def shouldThrow():
483 with cm():
484 raise iter([]).next()
485
486 self.assertRaises(StopIteration, shouldThrow)
487
Phillip J. Eby9444bd52006-04-03 20:05:05 +0000488 def testRaisedGeneratorExit1(self):
Nick Coghlan3814a912007-11-02 10:09:12 +0000489 # From bug 1462485
Nick Coghlanafd5e632006-05-03 13:02:47 +0000490 @contextmanager
Phillip J. Eby9444bd52006-04-03 20:05:05 +0000491 def cm():
492 yield
493
494 def shouldThrow():
495 with cm():
496 raise GeneratorExit("from with")
497
498 self.assertRaises(GeneratorExit, shouldThrow)
499
500 def testRaisedGeneratorExit2(self):
Nick Coghlan3814a912007-11-02 10:09:12 +0000501 # From bug 1462485
Phillip J. Eby9444bd52006-04-03 20:05:05 +0000502 class cm (object):
Phillip J. Eby9444bd52006-04-03 20:05:05 +0000503 def __enter__(self):
504 pass
Phillip J. Eby9444bd52006-04-03 20:05:05 +0000505 def __exit__(self, type, value, traceback):
506 pass
507
508 def shouldThrow():
509 with cm():
510 raise GeneratorExit("from with")
511
512 self.assertRaises(GeneratorExit, shouldThrow)
513
Amaury Forgeot d'Arcad9b5992008-12-10 23:22:49 +0000514 def testErrorsInBool(self):
515 # issue4589: __exit__ return code may raise an exception
516 # when looking at its truth value.
517
518 class cm(object):
519 def __init__(self, bool_conversion):
520 class Bool:
521 def __nonzero__(self):
522 return bool_conversion()
523 self.exit_result = Bool()
524 def __enter__(self):
525 return 3
526 def __exit__(self, a, b, c):
527 return self.exit_result
528
529 def trueAsBool():
530 with cm(lambda: True):
531 self.fail("Should NOT see this")
532 trueAsBool()
533
534 def falseAsBool():
535 with cm(lambda: False):
536 self.fail("Should raise")
537 self.assertRaises(AssertionError, falseAsBool)
538
539 def failAsBool():
Ezio Melottidde5b942010-02-03 05:37:26 +0000540 with cm(lambda: 1 // 0):
Amaury Forgeot d'Arcad9b5992008-12-10 23:22:49 +0000541 self.fail("Should NOT see this")
542 self.assertRaises(ZeroDivisionError, failAsBool)
543
Tim Peters400cbc32006-02-28 18:44:41 +0000544
545class NonLocalFlowControlTestCase(unittest.TestCase):
546
547 def testWithBreak(self):
548 counter = 0
549 while True:
550 counter += 1
551 with mock_contextmanager_generator():
552 counter += 10
553 break
554 counter += 100 # Not reached
555 self.assertEqual(counter, 11)
556
557 def testWithContinue(self):
558 counter = 0
559 while True:
560 counter += 1
561 if counter > 2:
562 break
563 with mock_contextmanager_generator():
564 counter += 10
565 continue
566 counter += 100 # Not reached
567 self.assertEqual(counter, 12)
568
569 def testWithReturn(self):
570 def foo():
571 counter = 0
572 while True:
573 counter += 1
574 with mock_contextmanager_generator():
575 counter += 10
576 return counter
577 counter += 100 # Not reached
578 self.assertEqual(foo(), 11)
579
580 def testWithYield(self):
581 def gen():
582 with mock_contextmanager_generator():
583 yield 12
584 yield 13
585 x = list(gen())
586 self.assertEqual(x, [12, 13])
587
588 def testWithRaise(self):
589 counter = 0
590 try:
591 counter += 1
592 with mock_contextmanager_generator():
593 counter += 10
594 raise RuntimeError
595 counter += 100 # Not reached
596 except RuntimeError:
597 self.assertEqual(counter, 11)
598 else:
599 self.fail("Didn't raise RuntimeError")
600
601
602class AssignmentTargetTestCase(unittest.TestCase):
603
604 def testSingleComplexTarget(self):
605 targets = {1: [0, 1, 2]}
606 with mock_contextmanager_generator() as targets[1][0]:
607 self.assertEqual(targets.keys(), [1])
608 self.assertEqual(targets[1][0].__class__, MockResource)
609 with mock_contextmanager_generator() as targets.values()[0][1]:
610 self.assertEqual(targets.keys(), [1])
611 self.assertEqual(targets[1][1].__class__, MockResource)
612 with mock_contextmanager_generator() as targets[2]:
613 keys = targets.keys()
614 keys.sort()
615 self.assertEqual(keys, [1, 2])
616 class C: pass
617 blah = C()
618 with mock_contextmanager_generator() as blah.foo:
619 self.assertEqual(hasattr(blah, "foo"), True)
620
621 def testMultipleComplexTargets(self):
622 class C:
Tim Peters400cbc32006-02-28 18:44:41 +0000623 def __enter__(self): return 1, 2, 3
Guido van Rossumf6694362006-03-10 02:28:35 +0000624 def __exit__(self, t, v, tb): pass
Tim Peters400cbc32006-02-28 18:44:41 +0000625 targets = {1: [0, 1, 2]}
626 with C() as (targets[1][0], targets[1][1], targets[1][2]):
627 self.assertEqual(targets, {1: [1, 2, 3]})
628 with C() as (targets.values()[0][2], targets.values()[0][1], targets.values()[0][0]):
629 self.assertEqual(targets, {1: [3, 2, 1]})
630 with C() as (targets[1], targets[2], targets[3]):
631 self.assertEqual(targets, {1: 1, 2: 2, 3: 3})
632 class B: pass
633 blah = B()
634 with C() as (blah.one, blah.two, blah.three):
635 self.assertEqual(blah.one, 1)
636 self.assertEqual(blah.two, 2)
637 self.assertEqual(blah.three, 3)
638
639
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000640class ExitSwallowsExceptionTestCase(unittest.TestCase):
641
Guido van Rossumf6694362006-03-10 02:28:35 +0000642 def testExitTrueSwallowsException(self):
643 class AfricanSwallow:
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000644 def __enter__(self): pass
Guido van Rossumf6694362006-03-10 02:28:35 +0000645 def __exit__(self, t, v, tb): return True
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000646 try:
Guido van Rossumf6694362006-03-10 02:28:35 +0000647 with AfricanSwallow():
Ezio Melottidde5b942010-02-03 05:37:26 +0000648 1 // 0
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000649 except ZeroDivisionError:
650 self.fail("ZeroDivisionError should have been swallowed")
651
Guido van Rossumf6694362006-03-10 02:28:35 +0000652 def testExitFalseDoesntSwallowException(self):
653 class EuropeanSwallow:
Guido van Rossumf6694362006-03-10 02:28:35 +0000654 def __enter__(self): pass
655 def __exit__(self, t, v, tb): return False
656 try:
657 with EuropeanSwallow():
Ezio Melottidde5b942010-02-03 05:37:26 +0000658 1 // 0
Guido van Rossumf6694362006-03-10 02:28:35 +0000659 except ZeroDivisionError:
660 pass
661 else:
662 self.fail("ZeroDivisionError should have been raised")
663
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000664
Georg Brandl944f6842009-05-25 21:02:56 +0000665class NestedWith(unittest.TestCase):
666
667 class Dummy(object):
668 def __init__(self, value=None, gobble=False):
669 if value is None:
670 value = self
671 self.value = value
672 self.gobble = gobble
673 self.enter_called = False
674 self.exit_called = False
675
676 def __enter__(self):
677 self.enter_called = True
678 return self.value
679
680 def __exit__(self, *exc_info):
681 self.exit_called = True
682 self.exc_info = exc_info
683 if self.gobble:
684 return True
685
Georg Brandl46121e72009-06-04 10:10:41 +0000686 class InitRaises(object):
Georg Brandl944f6842009-05-25 21:02:56 +0000687 def __init__(self): raise RuntimeError()
688
689 class EnterRaises(object):
690 def __enter__(self): raise RuntimeError()
691 def __exit__(self, *exc_info): pass
692
693 class ExitRaises(object):
694 def __enter__(self): pass
695 def __exit__(self, *exc_info): raise RuntimeError()
696
697 def testNoExceptions(self):
698 with self.Dummy() as a, self.Dummy() as b:
699 self.assertTrue(a.enter_called)
700 self.assertTrue(b.enter_called)
701 self.assertTrue(a.exit_called)
702 self.assertTrue(b.exit_called)
703
704 def testExceptionInExprList(self):
705 try:
Georg Brandl46121e72009-06-04 10:10:41 +0000706 with self.Dummy() as a, self.InitRaises():
Georg Brandl944f6842009-05-25 21:02:56 +0000707 pass
708 except:
709 pass
710 self.assertTrue(a.enter_called)
711 self.assertTrue(a.exit_called)
712
713 def testExceptionInEnter(self):
714 try:
715 with self.Dummy() as a, self.EnterRaises():
716 self.fail('body of bad with executed')
717 except RuntimeError:
718 pass
719 else:
720 self.fail('RuntimeError not reraised')
721 self.assertTrue(a.enter_called)
722 self.assertTrue(a.exit_called)
723
724 def testExceptionInExit(self):
725 body_executed = False
726 with self.Dummy(gobble=True) as a, self.ExitRaises():
727 body_executed = True
728 self.assertTrue(a.enter_called)
729 self.assertTrue(a.exit_called)
Benjamin Peterson9c5e4112009-06-19 22:09:17 +0000730 self.assertTrue(body_executed)
Georg Brandl944f6842009-05-25 21:02:56 +0000731 self.assertNotEqual(a.exc_info[0], None)
732
733 def testEnterReturnsTuple(self):
734 with self.Dummy(value=(1,2)) as (a1, a2), \
735 self.Dummy(value=(10, 20)) as (b1, b2):
736 self.assertEquals(1, a1)
737 self.assertEquals(2, a2)
738 self.assertEquals(10, b1)
739 self.assertEquals(20, b2)
740
Tim Peters400cbc32006-02-28 18:44:41 +0000741def test_main():
742 run_unittest(FailureTestCase, NonexceptionalTestCase,
743 NestedNonexceptionalTestCase, ExceptionalTestCase,
744 NonLocalFlowControlTestCase,
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000745 AssignmentTargetTestCase,
Georg Brandl944f6842009-05-25 21:02:56 +0000746 ExitSwallowsExceptionTestCase,
747 NestedWith)
Tim Peters400cbc32006-02-28 18:44:41 +0000748
749
750if __name__ == '__main__':
751 test_main()