Ticket #3353: lineReceiver-implementation-tests.patch

File lineReceiver-implementation-tests.patch, 11.6 KB (added by spiv, 13 years ago)

Work-in-progress experiment that shows the inconsistent behaviour via test failures.

  • twisted/test/test_protocols.py

    # Bazaar merge directive format 2 (Bazaar 0.90)
    # revision_id: andrew@puzzling.org-20080713141123-xgszytk2ns1u1lgr
    # target_branch: file:///home/andrew/code/twisted-import-trunk/trunk/
    # testament_sha1: 100e3d7842b9ab10673b7b31056b5e46f0196f70
    # timestamp: 2008-07-14 00:12:30 +1000
    # base_revision_id: andrew@puzzling.org-20080713084019-\
    #   hhqgv5d6pye8hgyw
    # 
    # Begin patch
    === modified file 'twisted/test/test_protocols.py'
     
    66Test cases for twisted.protocols package.
    77"""
    88
    9 from twisted.trial import unittest
     9from twisted.trial import unittest, runner
    1010from twisted.protocols import basic, wire, portforward
    1111from twisted.internet import reactor, protocol, defer, task, error
    1212from twisted.test import proto_helpers
     
    279279        self.assertEquals(a.received,
    280280                          ['produce', 'hello world', 'unproduce', 'goodbye'])
    281281
     282
     283class LineOnlyReceiverTestCase(unittest.TestCase):
     284    """
     285    Test line only receiver interface.
     286
     287    This test case is applied to both LineReceiver and LineOnlyReceiver by the
     288    test_suite function.
     289    """
     290    buffer = """foo
     291    bleakness
     292    desolation
     293    plastic forks
     294    """
     295
     296    lineReceiverClass = None  # see test_suite
     297
     298    def makeLineReceiver(self):
     299        """
     300        Construct a line receiver for testing with.
     301
     302        It will be a simple subclass of whatever self.lineReceiverClass is.
     303        The subclass will log calls to lineReceived and lineLengthExceeded to a
     304        '.calls' attribute.
     305        """
     306        transport = protocol.FileWrapper(StringIOWithoutClosing())
     307        class LoggingLineReceiver(self.lineReceiverClass):
     308            """
     309            A line receiver subclass that records calls made to it, but
     310            otherwise behaves like its base class.
     311            """
     312            delimiter = '\n'
     313            MAX_LENGTH = 64
     314            test = self
     315
     316            def connectionMade(self):
     317                self.calls = []
     318                return self.test.lineReceiverClass.connectionMade(self)
     319
     320            def lineReceived(self, line):
     321                self.calls.append(('lineReceived', line))
     322
     323            def lineLengthExceeded(self, line):
     324                self.calls.append(('lineLengthExceeded', line))
     325                return self.test.lineReceiverClass.lineLengthExceeded(
     326                    self, line)
     327           
     328        lineReceiver = LoggingLineReceiver()
     329        lineReceiver.makeConnection(transport)
     330        return lineReceiver
     331
     332    def testBuffer(self):
     333        """
     334        Test buffering over line protocol: data received should match buffer.
     335        """
     336        lineReceiver = self.makeLineReceiver()
     337        for c in self.buffer:
     338            lineReceiver.dataReceived(c)
     339        expectedLines = self.buffer.split('\n')[:-1]
     340        expectedCalls = [('lineReceived', line) for line in expectedLines]
     341        self.failUnlessEqual(expectedCalls, lineReceiver.calls)
     342
     343    def testLineTooLong(self):
     344        """
     345        When a line greater than MAX_LENGTH is received, lineLengthExceeded is
     346        called.  The default implementation lineLengthExceeded closes the
     347        connection.
     348        """
     349        lineReceiver = self.makeLineReceiver()
     350        res = lineReceiver.dataReceived('x'*200)
     351        self.failUnlessEqual(
     352            [('lineLengthExceeded', 'x'*200)], lineReceiver.calls)
     353        self.assertTrue(isinstance(res, error.ConnectionLost))
     354
    282355    def testLongLineWithDelimiter(self):
    283356        """
    284357        When MAX_LENGTH is exceeded *and* a delimiter has been received,
     
    288361        """
    289362        # Set up a line receiver with a short MAX_LENGTH that logs
    290363        # lineLengthExceeded events.
    291         class LineReceiverThatRecords(basic.LineReceiver):
    292             MAX_LENGTH = 10
    293             def connectionMade(self):
    294                 self.calls = []
    295             def lineReceived(self, line):
    296                 self.calls.append(('lineReceived', line))
    297             def lineLengthExceeded(self, line):
    298                 self.calls.append(('lineLengthExceeded', line))
    299         lineReceiver = LineReceiverThatRecords()
    300         t = StringIOWithoutClosing()
    301         lineReceiver.makeConnection(protocol.FileWrapper(t))
     364        lineReceiver = self.makeLineReceiver()
     365        lineReceiver.MAX_LENGTH = 10
    302366        # Call dataReceived with two lines, the first longer than MAX_LENGTH.
    303         longLine = ('x' * 11) + '\r\n'
    304         nextLine = 'next line\r\n'
     367        longLine = ('x' * 11) + '\n'
     368        nextLine = 'next line\n'
    305369        lineReceiver.dataReceived(longLine + nextLine)
    306370        # We expect lineLengthExceeded to be called with exactly what we just
    307371        # passed dataReceived.  lineReceived is not called.
     
    309373        self.assertEqual(expectedCalls, lineReceiver.calls)
    310374
    311375
    312 class LineOnlyReceiverTestCase(unittest.TestCase):
    313     """
    314     Test line only receiveer.
    315     """
    316     buffer = """foo
    317     bleakness
    318     desolation
    319     plastic forks
    320     """
    321 
    322     def testBuffer(self):
    323         """
    324         Test buffering over line protocol: data received should match buffer.
    325         """
    326         t = StringIOWithoutClosing()
    327         a = LineOnlyTester()
    328         a.makeConnection(protocol.FileWrapper(t))
    329         for c in self.buffer:
    330             a.dataReceived(c)
    331         self.failUnlessEqual(a.received, self.buffer.split('\n')[:-1])
    332 
    333     def testLineTooLong(self):
    334         """
    335         Test sending a line too long: it should close the connection.
    336         """
    337         t = StringIOWithoutClosing()
    338         a = LineOnlyTester()
    339         a.makeConnection(protocol.FileWrapper(t))
    340         res = a.dataReceived('x'*200)
    341         self.assertTrue(isinstance(res, error.ConnectionLost))
    342 
    343 
    344 
    345376class TestMixin:
    346377
    347378    def connectionMade(self):
     
    752783        """
    753784        s = proto_helpers.StringTransport()
    754785        self.assertRaises(TypeError, s.write, u'foo')
     786
     787
     788def test_suite():
     789    import twisted.test.test_protocols as this_module
     790    import copy
     791    suite = unittest.TestSuite()
     792    loader = runner.TestLoader()
     793    # Load all tests except LineOnlyReceiverTestCase.
     794    for testClass in loader.findTestClasses(this_module):
     795        if testClass is not LineOnlyReceiverTestCase:
     796            suite.addTest(loader.loadClass(testClass))
     797    # Add LineOnlyReceiverTestCase implementations tests.
     798    lineReceiverImplemenations = [basic.LineReceiver, basic.LineOnlyReceiver]
     799    lineReceiverImplemenationScenarios = [
     800        {'lineReceiverClass': klass} for klass in lineReceiverImplemenations]
     801    lineReceiverTests = loader.loadTestsFromTestCase(LineOnlyReceiverTestCase)
     802    for scenario in lineReceiverImplemenationScenarios:
     803        for test in lineReceiverTests:
     804            new_test = copy.deepcopy(test)
     805            new_test.id = lambda test=test, scenario=scenario: (
     806                '%s(%s)' % (test.id(), scenario['lineReceiverClass'].__name__))
     807            for key, value in scenario.items():
     808                setattr(new_test, key, value)
     809            suite.addTest(new_test)
     810    return suite