~ubuntu-branches/ubuntu/raring/qtwebkit-source/raring-proposed

« back to all changes in this revision

Viewing changes to Tools/Scripts/webkitpy/common/system/logtesting.py

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2013-02-18 14:24:18 UTC
  • Revision ID: package-import@ubuntu.com-20130218142418-eon0jmjg3nj438uy
Tags: upstream-2.3
ImportĀ upstreamĀ versionĀ 2.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2010 Chris Jerdonek (cjerdonek@webkit.org)
 
2
#
 
3
# Redistribution and use in source and binary forms, with or without
 
4
# modification, are permitted provided that the following conditions
 
5
# are met:
 
6
# 1.  Redistributions of source code must retain the above copyright
 
7
#     notice, this list of conditions and the following disclaimer.
 
8
# 2.  Redistributions in binary form must reproduce the above copyright
 
9
#     notice, this list of conditions and the following disclaimer in the
 
10
#     documentation and/or other materials provided with the distribution.
 
11
#
 
12
# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
 
13
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 
14
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 
15
# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR
 
16
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 
17
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 
18
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 
19
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 
20
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 
21
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
22
 
 
23
"""Supports the unit-testing of logging code.
 
24
 
 
25
Provides support for unit-testing messages logged using the built-in
 
26
logging module.
 
27
 
 
28
Inherit from the LoggingTestCase class for basic testing needs.  For
 
29
more advanced needs (e.g. unit-testing methods that configure logging),
 
30
see the TestLogStream class, and perhaps also the LogTesting class.
 
31
 
 
32
"""
 
33
 
 
34
import logging
 
35
import unittest
 
36
 
 
37
 
 
38
class TestLogStream(object):
 
39
 
 
40
    """Represents a file-like object for unit-testing logging.
 
41
 
 
42
    This is meant for passing to the logging.StreamHandler constructor.
 
43
    Log messages captured by instances of this object can be tested
 
44
    using self.assertMessages() below.
 
45
 
 
46
    """
 
47
 
 
48
    def __init__(self, test_case):
 
49
        """Create an instance.
 
50
 
 
51
        Args:
 
52
          test_case: A unittest.TestCase instance.
 
53
 
 
54
        """
 
55
        self._test_case = test_case
 
56
        self.messages = []
 
57
        """A list of log messages written to the stream."""
 
58
 
 
59
    # Python documentation says that any object passed to the StreamHandler
 
60
    # constructor should support write() and flush():
 
61
    #
 
62
    # http://docs.python.org/library/logging.html#module-logging.handlers
 
63
    def write(self, message):
 
64
        self.messages.append(message)
 
65
 
 
66
    def flush(self):
 
67
        pass
 
68
 
 
69
    def assertMessages(self, messages):
 
70
        """Assert that the given messages match the logged messages.
 
71
 
 
72
        messages: A list of log message strings.
 
73
 
 
74
        """
 
75
        self._test_case.assertEqual(messages, self.messages)
 
76
 
 
77
 
 
78
class LogTesting(object):
 
79
 
 
80
    """Supports end-to-end unit-testing of log messages.
 
81
 
 
82
        Sample usage:
 
83
 
 
84
          class SampleTest(unittest.TestCase):
 
85
 
 
86
              def setUp(self):
 
87
                  self._log = LogTesting.setUp(self)  # Turn logging on.
 
88
 
 
89
              def tearDown(self):
 
90
                  self._log.tearDown()  # Turn off and reset logging.
 
91
 
 
92
              def test_logging_in_some_method(self):
 
93
                  call_some_method()  # Contains calls to _log.info(), etc.
 
94
 
 
95
                  # Check the resulting log messages.
 
96
                  self._log.assertMessages(["INFO: expected message #1",
 
97
                                          "WARNING: expected message #2"])
 
98
 
 
99
    """
 
100
 
 
101
    def __init__(self, test_stream, handler):
 
102
        """Create an instance.
 
103
 
 
104
        This method should never be called directly.  Instances should
 
105
        instead be created using the static setUp() method.
 
106
 
 
107
        Args:
 
108
          test_stream: A TestLogStream instance.
 
109
          handler: The handler added to the logger.
 
110
 
 
111
        """
 
112
        self._test_stream = test_stream
 
113
        self._handler = handler
 
114
 
 
115
    @staticmethod
 
116
    def _getLogger():
 
117
        """Return the logger being tested."""
 
118
        # It is possible we might want to return something other than
 
119
        # the root logger in some special situation.  For now, the
 
120
        # root logger seems to suffice.
 
121
        return logging.getLogger()
 
122
 
 
123
    @staticmethod
 
124
    def setUp(test_case, logging_level=logging.INFO):
 
125
        """Configure logging for unit testing.
 
126
 
 
127
        Configures the root logger to log to a testing log stream.
 
128
        Only messages logged at or above the given level are logged
 
129
        to the stream.  Messages logged to the stream are formatted
 
130
        in the following way, for example--
 
131
 
 
132
        "INFO: This is a test log message."
 
133
 
 
134
        This method should normally be called in the setUp() method
 
135
        of a unittest.TestCase.  See the docstring of this class
 
136
        for more details.
 
137
 
 
138
        Returns:
 
139
          A LogTesting instance.
 
140
 
 
141
        Args:
 
142
          test_case: A unittest.TestCase instance.
 
143
          logging_level: An integer logging level that is the minimum level
 
144
                         of log messages you would like to test.
 
145
 
 
146
        """
 
147
        stream = TestLogStream(test_case)
 
148
        handler = logging.StreamHandler(stream)
 
149
        handler.setLevel(logging_level)
 
150
        formatter = logging.Formatter("%(levelname)s: %(message)s")
 
151
        handler.setFormatter(formatter)
 
152
 
 
153
        # Notice that we only change the root logger by adding a handler
 
154
        # to it.  In particular, we do not reset its level using
 
155
        # logger.setLevel().  This ensures that we have not interfered
 
156
        # with how the code being tested may have configured the root
 
157
        # logger.
 
158
        logger = LogTesting._getLogger()
 
159
        logger.addHandler(handler)
 
160
 
 
161
        return LogTesting(stream, handler)
 
162
 
 
163
    def tearDown(self):
 
164
        """Assert there are no remaining log messages, and reset logging.
 
165
 
 
166
        This method asserts that there are no more messages in the array of
 
167
        log messages, and then restores logging to its original state.
 
168
        This method should normally be called in the tearDown() method of a
 
169
        unittest.TestCase.  See the docstring of this class for more details.
 
170
 
 
171
        """
 
172
        self.assertMessages([])
 
173
        logger = LogTesting._getLogger()
 
174
        logger.removeHandler(self._handler)
 
175
 
 
176
    def messages(self):
 
177
        """Return the current list of log messages."""
 
178
        return self._test_stream.messages
 
179
 
 
180
    # FIXME: Add a clearMessages() method for cases where the caller
 
181
    #        deliberately doesn't want to assert every message.
 
182
 
 
183
    # We clear the log messages after asserting since they are no longer
 
184
    # needed after asserting.  This serves two purposes: (1) it simplifies
 
185
    # the calling code when we want to check multiple logging calls in a
 
186
    # single test method, and (2) it lets us check in the tearDown() method
 
187
    # that there are no remaining log messages to be asserted.
 
188
    #
 
189
    # The latter ensures that no extra log messages are getting logged that
 
190
    # the caller might not be aware of or may have forgotten to check for.
 
191
    # This gets us a bit more mileage out of our tests without writing any
 
192
    # additional code.
 
193
    def assertMessages(self, messages):
 
194
        """Assert the current array of log messages, and clear its contents.
 
195
 
 
196
        Args:
 
197
          messages: A list of log message strings.
 
198
 
 
199
        """
 
200
        try:
 
201
            self._test_stream.assertMessages(messages)
 
202
        finally:
 
203
            # We want to clear the array of messages even in the case of
 
204
            # an Exception (e.g. an AssertionError).  Otherwise, another
 
205
            # AssertionError can occur in the tearDown() because the
 
206
            # array might not have gotten emptied.
 
207
            self._test_stream.messages = []
 
208
 
 
209
 
 
210
# This class needs to inherit from unittest.TestCase.  Otherwise, the
 
211
# setUp() and tearDown() methods will not get fired for test case classes
 
212
# that inherit from this class -- even if the class inherits from *both*
 
213
# unittest.TestCase and LoggingTestCase.
 
214
#
 
215
# FIXME: Rename this class to LoggingTestCaseBase to be sure that
 
216
#        the unittest module does not interpret this class as a unittest
 
217
#        test case itself.
 
218
class LoggingTestCase(unittest.TestCase):
 
219
 
 
220
    """Supports end-to-end unit-testing of log messages.
 
221
 
 
222
        Sample usage:
 
223
 
 
224
          class SampleTest(LoggingTestCase):
 
225
 
 
226
              def test_logging_in_some_method(self):
 
227
                  call_some_method()  # Contains calls to _log.info(), etc.
 
228
 
 
229
                  # Check the resulting log messages.
 
230
                  self.assertLog(["INFO: expected message #1",
 
231
                                  "WARNING: expected message #2"])
 
232
 
 
233
    """
 
234
 
 
235
    def setUp(self):
 
236
        self._log = LogTesting.setUp(self)
 
237
 
 
238
    def tearDown(self):
 
239
        self._log.tearDown()
 
240
 
 
241
    def logMessages(self):
 
242
        """Return the current list of log messages."""
 
243
        return self._log.messages()
 
244
 
 
245
    # FIXME: Add a clearMessages() method for cases where the caller
 
246
    #        deliberately doesn't want to assert every message.
 
247
 
 
248
    # See the code comments preceding LogTesting.assertMessages() for
 
249
    # an explanation of why we clear the array of messages after
 
250
    # asserting its contents.
 
251
    def assertLog(self, messages):
 
252
        """Assert the current array of log messages, and clear its contents.
 
253
 
 
254
        Args:
 
255
          messages: A list of log message strings.
 
256
 
 
257
        """
 
258
        self._log.assertMessages(messages)