Statistics
| Branch: | Tag: | Revision:

amiro-os / tools / cpplint / python / cpplint_unittest.py @ 53710ca3

History | View | Annotate | Download (216.815 KB)

1 e545e620 Thomas Schöpping
#!/usr/bin/python
2
# -*- coding: utf-8; -*-
3
#
4
# Copyright (c) 2009 Google Inc. All rights reserved.
5
#
6
# Redistribution and use in source and binary forms, with or without
7
# modification, are permitted provided that the following conditions are
8
# met:
9
#
10
#    * Redistributions of source code must retain the above copyright
11
# notice, this list of conditions and the following disclaimer.
12
#    * Redistributions in binary form must reproduce the above
13
# copyright notice, this list of conditions and the following disclaimer
14
# in the documentation and/or other materials provided with the
15
# distribution.
16
#    * Neither the name of Google Inc. nor the names of its
17
# contributors may be used to endorse or promote products derived from
18
# this software without specific prior written permission.
19
#
20
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
32
"""Unit test for cpplint.py."""
33
34
# TODO(unknown): Add a good test that tests UpdateIncludeState.
35
36
import codecs
37
import os
38
import random
39
import re
40
import sys
41
import unittest
42
43
import cpplint
44
45
46
# This class works as an error collector and replaces cpplint.Error
47
# function for the unit tests.  We also verify each category we see
48
# is in cpplint._ERROR_CATEGORIES, to help keep that list up to date.
49
class ErrorCollector(object):
50
  # These are a global list, covering all categories seen ever.
51
  _ERROR_CATEGORIES = cpplint._ERROR_CATEGORIES
52
  _SEEN_ERROR_CATEGORIES = {}
53
54
  def __init__(self, assert_fn):
55
    """assert_fn: a function to call when we notice a problem."""
56
    self._assert_fn = assert_fn
57
    self._errors = []
58
    cpplint.ResetNolintSuppressions()
59
60
  def __call__(self, unused_filename, linenum,
61
               category, confidence, message):
62
    self._assert_fn(category in self._ERROR_CATEGORIES,
63
                    'Message "%s" has category "%s",'
64
                    ' which is not in _ERROR_CATEGORIES' % (message, category))
65
    self._SEEN_ERROR_CATEGORIES[category] = 1
66
    if cpplint._ShouldPrintError(category, confidence, linenum):
67
      self._errors.append('%s  [%s] [%d]' % (message, category, confidence))
68
69
  def Results(self):
70
    if len(self._errors) < 2:
71
      return ''.join(self._errors)  # Most tests expect to have a string.
72
    else:
73
      return self._errors  # Let's give a list if there is more than one.
74
75
  def ResultList(self):
76
    return self._errors
77
78
  def VerifyAllCategoriesAreSeen(self):
79
    """Fails if there's a category in _ERROR_CATEGORIES~_SEEN_ERROR_CATEGORIES.
80

81
    This should only be called after all tests are run, so
82
    _SEEN_ERROR_CATEGORIES has had a chance to fully populate.  Since
83
    this isn't called from within the normal unittest framework, we
84
    can't use the normal unittest assert macros.  Instead we just exit
85
    when we see an error.  Good thing this test is always run last!
86
    """
87
    for category in self._ERROR_CATEGORIES:
88
      if category not in self._SEEN_ERROR_CATEGORIES:
89
        sys.exit('FATAL ERROR: There are no tests for category "%s"' % category)
90
91
  def RemoveIfPresent(self, substr):
92
    for (index, error) in enumerate(self._errors):
93
      if error.find(substr) != -1:
94
        self._errors = self._errors[0:index] + self._errors[(index + 1):]
95
        break
96
97
98
# This class is a lame mock of codecs. We do not verify filename, mode, or
99
# encoding, but for the current use case it is not needed.
100
class MockIo(object):
101
102
  def __init__(self, mock_file):
103
    self.mock_file = mock_file
104
105
  def open(self,  # pylint: disable-msg=C6409
106
           unused_filename, unused_mode, unused_encoding, _):
107
    return self.mock_file
108
109
110
class CpplintTestBase(unittest.TestCase):
111
  """Provides some useful helper functions for cpplint tests."""
112
113
  def setUp(self):
114
    # Allow subclasses to cheat os.path.abspath called in FileInfo class.
115
    self.os_path_abspath_orig = os.path.abspath
116
117
  def tearDown(self):
118
    os.path.abspath = self.os_path_abspath_orig
119
120
  # Perform lint on single line of input and return the error message.
121
  def PerformSingleLineLint(self, code):
122
    error_collector = ErrorCollector(self.assert_)
123
    lines = code.split('\n')
124
    cpplint.RemoveMultiLineComments('foo.h', lines, error_collector)
125
    clean_lines = cpplint.CleansedLines(lines)
126
    include_state = cpplint._IncludeState()
127
    function_state = cpplint._FunctionState()
128
    nesting_state = cpplint.NestingState()
129
    cpplint.ProcessLine('foo.cc', 'cc', clean_lines, 0,
130
                        include_state, function_state,
131
                        nesting_state, error_collector)
132
    # Single-line lint tests are allowed to fail the 'unlintable function'
133
    # check.
134
    error_collector.RemoveIfPresent(
135
        'Lint failed to find start of function body.')
136
    return error_collector.Results()
137
138
  # Perform lint over multiple lines and return the error message.
139
  def PerformMultiLineLint(self, code):
140
    error_collector = ErrorCollector(self.assert_)
141
    lines = code.split('\n')
142
    cpplint.RemoveMultiLineComments('foo.h', lines, error_collector)
143
    lines = cpplint.CleansedLines(lines)
144
    nesting_state = cpplint.NestingState()
145
    for i in xrange(lines.NumLines()):
146
      nesting_state.Update('foo.h', lines, i, error_collector)
147
      cpplint.CheckStyle('foo.h', lines, i, 'h', nesting_state,
148
                         error_collector)
149
      cpplint.CheckForNonStandardConstructs('foo.h', lines, i,
150
                                            nesting_state, error_collector)
151
    nesting_state.CheckCompletedBlocks('foo.h', error_collector)
152
    return error_collector.Results()
153
154
  # Similar to PerformMultiLineLint, but calls CheckLanguage instead of
155
  # CheckForNonStandardConstructs
156
  def PerformLanguageRulesCheck(self, file_name, code):
157
    error_collector = ErrorCollector(self.assert_)
158
    include_state = cpplint._IncludeState()
159
    nesting_state = cpplint.NestingState()
160
    lines = code.split('\n')
161
    cpplint.RemoveMultiLineComments(file_name, lines, error_collector)
162
    lines = cpplint.CleansedLines(lines)
163
    ext = file_name[file_name.rfind('.') + 1:]
164
    for i in xrange(lines.NumLines()):
165
      cpplint.CheckLanguage(file_name, lines, i, ext, include_state,
166
                            nesting_state, error_collector)
167
    return error_collector.Results()
168
169
  def PerformFunctionLengthsCheck(self, code):
170
    """Perform Lint function length check on block of code and return warnings.
171

172
    Builds up an array of lines corresponding to the code and strips comments
173
    using cpplint functions.
174

175
    Establishes an error collector and invokes the function length checking
176
    function following cpplint's pattern.
177

178
    Args:
179
      code: C++ source code expected to generate a warning message.
180

181
    Returns:
182
      The accumulated errors.
183
    """
184
    file_name = 'foo.cc'
185
    error_collector = ErrorCollector(self.assert_)
186
    function_state = cpplint._FunctionState()
187
    lines = code.split('\n')
188
    cpplint.RemoveMultiLineComments(file_name, lines, error_collector)
189
    lines = cpplint.CleansedLines(lines)
190
    for i in xrange(lines.NumLines()):
191
      cpplint.CheckForFunctionLengths(file_name, lines, i,
192
                                      function_state, error_collector)
193
    return error_collector.Results()
194
195
  def PerformIncludeWhatYouUse(self, code, filename='foo.h', io=codecs):
196
    # First, build up the include state.
197
    error_collector = ErrorCollector(self.assert_)
198
    include_state = cpplint._IncludeState()
199
    nesting_state = cpplint.NestingState()
200
    lines = code.split('\n')
201
    cpplint.RemoveMultiLineComments(filename, lines, error_collector)
202
    lines = cpplint.CleansedLines(lines)
203
    for i in xrange(lines.NumLines()):
204
      cpplint.CheckLanguage(filename, lines, i, '.h', include_state,
205
                            nesting_state, error_collector)
206
    # We could clear the error_collector here, but this should
207
    # also be fine, since our IncludeWhatYouUse unittests do not
208
    # have language problems.
209
210
    # Second, look for missing includes.
211
    cpplint.CheckForIncludeWhatYouUse(filename, lines, include_state,
212
                                      error_collector, io)
213
    return error_collector.Results()
214
215
  # Perform lint and compare the error message with "expected_message".
216
  def TestLint(self, code, expected_message):
217
    self.assertEquals(expected_message, self.PerformSingleLineLint(code))
218
219
  def TestMultiLineLint(self, code, expected_message):
220
    self.assertEquals(expected_message, self.PerformMultiLineLint(code))
221
222
  def TestMultiLineLintRE(self, code, expected_message_re):
223
    message =