[3.10] bpo-13236: Flush the output stream more often in unittest (GH-29929) (GH-30039)

It can prevent some losses when output to buffered stream..
(cherry picked from commit 83fa1291fd)

Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
This commit is contained in:
Miss Islington (bot) 2021-12-10 16:34:46 -08:00 committed by GitHub
parent 9299e3a39c
commit d55a03e02e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 44 additions and 4 deletions

View file

@ -59,6 +59,7 @@ def addSuccess(self, test):
super(TextTestResult, self).addSuccess(test) super(TextTestResult, self).addSuccess(test)
if self.showAll: if self.showAll:
self.stream.writeln("ok") self.stream.writeln("ok")
self.stream.flush()
elif self.dots: elif self.dots:
self.stream.write('.') self.stream.write('.')
self.stream.flush() self.stream.flush()
@ -67,6 +68,7 @@ def addError(self, test, err):
super(TextTestResult, self).addError(test, err) super(TextTestResult, self).addError(test, err)
if self.showAll: if self.showAll:
self.stream.writeln("ERROR") self.stream.writeln("ERROR")
self.stream.flush()
elif self.dots: elif self.dots:
self.stream.write('E') self.stream.write('E')
self.stream.flush() self.stream.flush()
@ -75,6 +77,7 @@ def addFailure(self, test, err):
super(TextTestResult, self).addFailure(test, err) super(TextTestResult, self).addFailure(test, err)
if self.showAll: if self.showAll:
self.stream.writeln("FAIL") self.stream.writeln("FAIL")
self.stream.flush()
elif self.dots: elif self.dots:
self.stream.write('F') self.stream.write('F')
self.stream.flush() self.stream.flush()
@ -83,6 +86,7 @@ def addSkip(self, test, reason):
super(TextTestResult, self).addSkip(test, reason) super(TextTestResult, self).addSkip(test, reason)
if self.showAll: if self.showAll:
self.stream.writeln("skipped {0!r}".format(reason)) self.stream.writeln("skipped {0!r}".format(reason))
self.stream.flush()
elif self.dots: elif self.dots:
self.stream.write("s") self.stream.write("s")
self.stream.flush() self.stream.flush()
@ -91,6 +95,7 @@ def addExpectedFailure(self, test, err):
super(TextTestResult, self).addExpectedFailure(test, err) super(TextTestResult, self).addExpectedFailure(test, err)
if self.showAll: if self.showAll:
self.stream.writeln("expected failure") self.stream.writeln("expected failure")
self.stream.flush()
elif self.dots: elif self.dots:
self.stream.write("x") self.stream.write("x")
self.stream.flush() self.stream.flush()
@ -99,6 +104,7 @@ def addUnexpectedSuccess(self, test):
super(TextTestResult, self).addUnexpectedSuccess(test) super(TextTestResult, self).addUnexpectedSuccess(test)
if self.showAll: if self.showAll:
self.stream.writeln("unexpected success") self.stream.writeln("unexpected success")
self.stream.flush()
elif self.dots: elif self.dots:
self.stream.write("u") self.stream.write("u")
self.stream.flush() self.stream.flush()
@ -106,6 +112,7 @@ def addUnexpectedSuccess(self, test):
def printErrors(self): def printErrors(self):
if self.dots or self.showAll: if self.dots or self.showAll:
self.stream.writeln() self.stream.writeln()
self.stream.flush()
self.printErrorList('ERROR', self.errors) self.printErrorList('ERROR', self.errors)
self.printErrorList('FAIL', self.failures) self.printErrorList('FAIL', self.failures)
@ -115,6 +122,7 @@ def printErrorList(self, flavour, errors):
self.stream.writeln("%s: %s" % (flavour,self.getDescription(test))) self.stream.writeln("%s: %s" % (flavour,self.getDescription(test)))
self.stream.writeln(self.separator2) self.stream.writeln(self.separator2)
self.stream.writeln("%s" % err) self.stream.writeln("%s" % err)
self.stream.flush()
class TextTestRunner(object): class TextTestRunner(object):
@ -218,4 +226,5 @@ def run(self, test):
self.stream.writeln(" (%s)" % (", ".join(infos),)) self.stream.writeln(" (%s)" % (", ".join(infos),))
else: else:
self.stream.write("\n") self.stream.write("\n")
self.stream.flush()
return result return result

View file

@ -6,6 +6,7 @@
from test import support from test import support
import unittest import unittest
import unittest.test import unittest.test
from .test_result import BufferedWriter
class Test_TestProgram(unittest.TestCase): class Test_TestProgram(unittest.TestCase):
@ -104,30 +105,39 @@ def run(self, test):
program.testNames) program.testNames)
def test_NonExit(self): def test_NonExit(self):
stream = BufferedWriter()
program = unittest.main(exit=False, program = unittest.main(exit=False,
argv=["foobar"], argv=["foobar"],
testRunner=unittest.TextTestRunner(stream=io.StringIO()), testRunner=unittest.TextTestRunner(stream=stream),
testLoader=self.FooBarLoader()) testLoader=self.FooBarLoader())
self.assertTrue(hasattr(program, 'result')) self.assertTrue(hasattr(program, 'result'))
self.assertIn('\nFAIL: testFail ', stream.getvalue())
self.assertTrue(stream.getvalue().endswith('\n\nFAILED (failures=1)\n'))
def test_Exit(self): def test_Exit(self):
stream = BufferedWriter()
self.assertRaises( self.assertRaises(
SystemExit, SystemExit,
unittest.main, unittest.main,
argv=["foobar"], argv=["foobar"],
testRunner=unittest.TextTestRunner(stream=io.StringIO()), testRunner=unittest.TextTestRunner(stream=stream),
exit=True, exit=True,
testLoader=self.FooBarLoader()) testLoader=self.FooBarLoader())
self.assertIn('\nFAIL: testFail ', stream.getvalue())
self.assertTrue(stream.getvalue().endswith('\n\nFAILED (failures=1)\n'))
def test_ExitAsDefault(self): def test_ExitAsDefault(self):
stream = BufferedWriter()
self.assertRaises( self.assertRaises(
SystemExit, SystemExit,
unittest.main, unittest.main,
argv=["foobar"], argv=["foobar"],
testRunner=unittest.TextTestRunner(stream=io.StringIO()), testRunner=unittest.TextTestRunner(stream=stream),
testLoader=self.FooBarLoader()) testLoader=self.FooBarLoader())
self.assertIn('\nFAIL: testFail ', stream.getvalue())
self.assertTrue(stream.getvalue().endswith('\n\nFAILED (failures=1)\n'))
class InitialisableProgram(unittest.TestProgram): class InitialisableProgram(unittest.TestProgram):

View file

@ -34,6 +34,22 @@ def bad_cleanup2():
raise ValueError('bad cleanup2') raise ValueError('bad cleanup2')
class BufferedWriter:
def __init__(self):
self.result = ''
self.buffer = ''
def write(self, arg):
self.buffer += arg
def flush(self):
self.result += self.buffer
self.buffer = ''
def getvalue(self):
return self.result
class Test_TestResult(unittest.TestCase): class Test_TestResult(unittest.TestCase):
# Note: there are not separate tests for TestResult.wasSuccessful(), # Note: there are not separate tests for TestResult.wasSuccessful(),
# TestResult.errors, TestResult.failures, TestResult.testsRun or # TestResult.errors, TestResult.failures, TestResult.testsRun or
@ -445,10 +461,13 @@ def testFailFast(self):
self.assertTrue(result.shouldStop) self.assertTrue(result.shouldStop)
def testFailFastSetByRunner(self): def testFailFastSetByRunner(self):
runner = unittest.TextTestRunner(stream=io.StringIO(), failfast=True) stream = BufferedWriter()
runner = unittest.TextTestRunner(stream=stream, failfast=True)
def test(result): def test(result):
self.assertTrue(result.failfast) self.assertTrue(result.failfast)
result = runner.run(test) result = runner.run(test)
stream.flush()
self.assertTrue(stream.getvalue().endswith('\n\nOK\n'))
classDict = dict(unittest.TestResult.__dict__) classDict = dict(unittest.TestResult.__dict__)

View file

@ -0,0 +1,2 @@
:class:`unittest.TextTestResult` and :class:`unittest.TextTestRunner` flush
now the output stream more often.