test_with.py 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. import unittest
  2. class CtxMgr:
  3. def __init__(self, swallow_exception=False):
  4. self.n_enter = self.n_exit = 0
  5. self.exc_info = None
  6. self.swallow_exception = swallow_exception
  7. def __enter__(self):
  8. self.n_enter += 1
  9. return 42
  10. def __exit__(self, x, y, z):
  11. self.n_exit += 1
  12. if x is not None:
  13. self.exc_info = (x, y, z)
  14. return self.swallow_exception
  15. def check_inside(self, testcase):
  16. testcase.assertEqual(self.n_enter, 1, "__enter__ not called before body")
  17. testcase.assertEqual(self.n_exit, 0, "__exit__ called before body")
  18. def check(self, testcase, expect_exception = False):
  19. testcase.assertEqual(self.n_enter, 1, "__enter__ called wrong number of times")
  20. testcase.assertEqual(self.n_exit, 1, "__exit__ called wrong number of times")
  21. if expect_exception:
  22. testcase.assertIsNotNone(self.exc_info, "No exception passed to __exit__")
  23. else:
  24. testcase.assertIsNone(self.exc_info, "Unexpected exception passed to __exit__")
  25. class WithTest(unittest.TestCase):
  26. def test_with(self):
  27. # Straightforward execution
  28. ctxmgr = CtxMgr()
  29. with ctxmgr as foo:
  30. self.assertEqual(foo, 42)
  31. ctxmgr.check_inside(self)
  32. ctxmgr.check(self)
  33. # Exception handling
  34. ctxmgr = CtxMgr()
  35. def with_exc():
  36. with ctxmgr:
  37. raise Exception
  38. self.assertFalse(True, "Execution continued after raise-within-with")
  39. self.assertRaises(Exception, with_exc)
  40. ctxmgr.check(self, expect_exception=True)
  41. self.assertEqual(ctxmgr.exc_info[0], Exception)
  42. # Exception swallowing
  43. ctxmgr = CtxMgr(swallow_exception=True)
  44. with ctxmgr:
  45. raise Exception()
  46. ctxmgr.check(self, expect_exception=True)
  47. # Break from within 'with'
  48. ctxmgr = CtxMgr()
  49. while True:
  50. with ctxmgr:
  51. break
  52. ctxmgr.check(self)
  53. # Chain correctly to and from other 'finally' clauses
  54. # (also test 'continue' while we're at it)
  55. ctxmgr = CtxMgr()
  56. finally_ran = [False, False, False]
  57. code_continued = False
  58. try:
  59. while not finally_ran[0]:
  60. try:
  61. with ctxmgr:
  62. try:
  63. continue
  64. finally:
  65. finally_ran[0] = True
  66. self.assertFalse(True, "Execution got past 'continue' statement (within 'with')")
  67. self.assertFalse(True, "Execution got past 'continue' statement (outside 'with')")
  68. finally:
  69. finally_ran[1] = True
  70. code_continued = True
  71. finally:
  72. pass
  73. ctxmgr.check(self)
  74. self.assertTrue(code_continued)
  75. if __name__ == "__main__":
  76. unittest.main()