diff options
author | shiqian <shiqian@8415998a-534a-0410-bf83-d39667b30386> | 2008-12-10 05:08:54 +0000 |
---|---|---|
committer | shiqian <shiqian@8415998a-534a-0410-bf83-d39667b30386> | 2008-12-10 05:08:54 +0000 |
commit | e35fdd936d133bf8a48de140a3c666897588a053 (patch) | |
tree | 4e1dbda63ddea04bab288b1f2999896103bac4c3 /scripts/gmock_doctor.py | |
download | googletest-e35fdd936d133bf8a48de140a3c666897588a053.tar.gz googletest-e35fdd936d133bf8a48de140a3c666897588a053.tar.bz2 googletest-e35fdd936d133bf8a48de140a3c666897588a053.zip |
Initial drop of Google Mock. The files are incomplete and thus may not build correctly yet.
Diffstat (limited to 'scripts/gmock_doctor.py')
-rwxr-xr-x | scripts/gmock_doctor.py | 376 |
1 files changed, 376 insertions, 0 deletions
diff --git a/scripts/gmock_doctor.py b/scripts/gmock_doctor.py new file mode 100755 index 00000000..ce8ec498 --- /dev/null +++ b/scripts/gmock_doctor.py @@ -0,0 +1,376 @@ +#!/usr/bin/python2.4 +# +# Copyright 2008, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Converts gcc errors in code using Google Mock to plain English.""" + +__author__ = 'wan@google.com (Zhanyong Wan)' + +import re +import sys + +_VERSION = '0.1.0.80421' + +_COMMON_GMOCK_SYMBOLS = [ + # Matchers + '_', + 'A', + 'AddressSatisfies', + 'AllOf', + 'An', + 'AnyOf', + 'ContainsRegex', + 'DoubleEq', + 'EndsWith', + 'Eq', + 'Field', + 'FloatEq', + 'Ge', + 'Gt', + 'HasSubstr', + 'Le', + 'Lt', + 'MatcherCast', + 'MatchesRegex', + 'Ne', + 'Not', + 'NotNull', + 'Pointee', + 'Property', + 'Ref', + 'StartsWith', + 'StrCaseEq', + 'StrCaseNe', + 'StrEq', + 'StrNe', + 'Truly', + 'TypedEq', + + # Actions + 'ByRef', + 'DoAll', + 'DoDefault', + 'IgnoreResult', + 'Invoke', + 'InvokeArgument', + 'InvokeWithoutArgs', + 'Return', + 'ReturnNull', + 'ReturnRef', + 'SetArgumentPointee', + 'SetArrayArgument', + 'WithArgs', + + # Cardinalities + 'AnyNumber', + 'AtLeast', + 'AtMost', + 'Between', + 'Exactly', + + # Sequences + 'InSequence', + 'Sequence', + + # Misc + 'DefaultValue', + 'Mock', + ] + + +def _FindAllMatches(regex, s): + """Generates all matches of regex in string s.""" + + r = re.compile(regex) + return r.finditer(s) + + +def _GenericDiagnoser(short_name, long_name, regex, diagnosis, msg): + """Diagnoses the given disease by pattern matching. + + Args: + short_name: Short name of the disease. + long_name: Long name of the disease. + regex: Regex for matching the symptoms. + diagnosis: Pattern for formatting the diagnosis. + msg: Gcc's error messages. + Yields: + Tuples of the form + (short name of disease, long name of disease, diagnosis). + """ + + for m in _FindAllMatches(regex, msg): + yield (short_name, long_name, diagnosis % m.groupdict()) + + +def _NeedToReturnReferenceDiagnoser(msg): + """Diagnoses the NRR disease, given the error messages by gcc.""" + + regex = (r'In member function \'testing::internal::ReturnAction<R>.*\n' + r'(?P<file>.*):(?P<line>\d+):\s+instantiated from here\n' + r'.*gmock-actions\.h.*error: creating array with negative size') + diagnosis = """%(file)s:%(line)s: +You are using an Return() action in a function that returns a reference. +Please use ReturnRef() instead.""" + return _GenericDiagnoser('NRR', 'Need to Return Reference', + regex, diagnosis, msg) + + +def _NeedToReturnSomethingDiagnoser(msg): + """Diagnoses the NRS disease, given the error messages by gcc.""" + + regex = (r'(?P<file>.*):(?P<line>\d+):\s+instantiated from here\n' + r'.*gmock-actions\.h.*error: void value not ignored') + diagnosis = """%(file)s:%(line)s: +You are using an action that returns void, but it needs to return +*something*. Please tell it *what* to return.""" + return _GenericDiagnoser('NRS', 'Need to Return Something', + regex, diagnosis, msg) + + +def _NeedToReturnNothingDiagnoser(msg): + """Diagnoses the NRN disease, given the error messages by gcc.""" + + regex = (r'(?P<file>.*):(?P<line>\d+):\s+instantiated from here\n' + r'.*gmock-actions\.h.*error: return-statement with a value, ' + r'in function returning \'void\'') + diagnosis = """%(file)s:%(line)s: +You are using an action that returns *something*, but it needs to return +void. Please use a void-returning action instead. + +All actions but the last in DoAll(...) must return void. Perhaps you need +to re-arrange the order of actions in a DoAll(), if you are using one?""" + return _GenericDiagnoser('NRN', 'Need to Return Nothing', + regex, diagnosis, msg) + + +def _IncompleteByReferenceArgumentDiagnoser(msg): + """Diagnoses the IBRA disease, given the error messages by gcc.""" + + regex = (r'(?P<file>.*):(?P<line>\d+):\s+instantiated from here\n' + r'.*gmock-printers\.h.*error: invalid application of ' + r'\'sizeof\' to incomplete type \'(?P<type>.*)\'') + diagnosis = """%(file)s:%(line)s: +In order to mock this function, Google Mock needs to see the definition +of type "%(type)s" - declaration alone is not enough. Either #include +the header that defines it, or change the argument to be passed +by pointer.""" + return _GenericDiagnoser('IBRA', 'Incomplete By-Reference Argument Type', + regex, diagnosis, msg) + + +def _OverloadedFunctionMatcherDiagnoser(msg): + """Diagnoses the OFM disease, given the error messages by gcc.""" + + regex = (r'(?P<file>.*):(?P<line>\d+): error: no matching function for ' + r'call to \'Truly\(<unresolved overloaded function type>\)') + diagnosis = """%(file)s:%(line)s: +The argument you gave to Truly() is an overloaded function. Please tell +gcc which overloaded version you want to use. + +For example, if you want to use the version whose signature is + bool Foo(int n); +you should write + Truly(static_cast<bool (*)(int n)>(Foo))""" + return _GenericDiagnoser('OFM', 'Overloaded Function Matcher', + regex, diagnosis, msg) + + +def _OverloadedFunctionActionDiagnoser(msg): + """Diagnoses the OFA disease, given the error messages by gcc.""" + + regex = (r'(?P<file>.*):(?P<line>\d+): error: ' + r'no matching function for call to \'Invoke\(' + r'<unresolved overloaded function type>') + diagnosis = """%(file)s:%(line)s: +You are passing an overloaded function to Invoke(). Please tell gcc +which overloaded version you want to use. + +For example, if you want to use the version whose signature is + bool MyFunction(int n, double x); +you should write something like + Invoke(static_cast<bool (*)(int n, double x)>(MyFunction))""" + return _GenericDiagnoser('OFA', 'Overloaded Function Action', + regex, diagnosis, msg) + + +def _OverloadedMethodActionDiagnoser1(msg): + """Diagnoses the OMA disease, given the error messages by gcc.""" + + regex = (r'(?P<file>.*):(?P<line>\d+): error: ' + r'.*no matching function for call to \'Invoke\(.*, ' + r'unresolved overloaded function type>') + diagnosis = """%(file)s:%(line)s: +The second argument you gave to Invoke() is an overloaded method. Please +tell gcc which overloaded version you want to use. + +For example, if you want to use the version whose signature is + class Foo { + ... + bool Bar(int n, double x); + }; +you should write something like + Invoke(foo, static_cast<bool (Foo::*)(int n, double x)>(&Foo::Bar))""" + return _GenericDiagnoser('OMA', 'Overloaded Method Action', + regex, diagnosis, msg) + + +def _MockObjectPointerDiagnoser(msg): + """Diagnoses the MOP disease, given the error messages by gcc.""" + + regex = (r'(?P<file>.*):(?P<line>\d+): error: request for member ' + r'\'gmock_(?P<method>.+)\' in \'(?P<mock_object>.+)\', ' + r'which is of non-class type \'(.*::)*(?P<class_name>.+)\*\'') + diagnosis = """%(file)s:%(line)s: +The first argument to ON_CALL() and EXPECT_CALL() must be a mock *object*, +not a *pointer* to it. Please write '*(%(mock_object)s)' instead of +'%(mock_object)s' as your first argument. + +For example, given the mock class: + + class %(class_name)s : public ... { + ... + MOCK_METHOD0(%(method)s, ...); + }; + +and the following mock instance: + + %(class_name)s* mock_ptr = ... + +you should use the EXPECT_CALL like this: + + EXPECT_CALL(*mock_ptr, %(method)s(...));""" + return _GenericDiagnoser('MOP', 'Mock Object Pointer', + regex, diagnosis, msg) + + +def _OverloadedMethodActionDiagnoser2(msg): + """Diagnoses the OMA disease, given the error messages by gcc.""" + + regex = (r'(?P<file>.*):(?P<line>\d+): error: no matching function for ' + r'call to \'Invoke\(.+, <unresolved overloaded function type>\)') + diagnosis = """%(file)s:%(line)s: +The second argument you gave to Invoke() is an overloaded method. Please +tell gcc which overloaded version you want to use. + +For example, if you want to use the version whose signature is + class Foo { + ... + bool Bar(int n, double x); + }; +you should write something like + Invoke(foo, static_cast<bool (Foo::*)(int n, double x)>(&Foo::Bar))""" + return _GenericDiagnoser('OMA', 'Overloaded Method Action', + regex, diagnosis, msg) + + +def _NeedToUseSymbolDiagnoser(msg): + """Diagnoses the NUS disease, given the error messages by gcc.""" + + regex = (r'(?P<file>.*):(?P<line>\d+): error: \'(?P<symbol>.+)\' ' + r'(was not declared in this scope|has not been declared)') + diagnosis = """%(file)s:%(line)s: +'%(symbol)s' is defined by Google Mock in the testing namespace. +Did you forget to write + using testing::%(symbol)s; +?""" + for m in _FindAllMatches(regex, msg): + symbol = m.groupdict()['symbol'] + if symbol in _COMMON_GMOCK_SYMBOLS: + yield ('NUS', 'Need to Use Symbol', diagnosis % m.groupdict()) + + +_DIAGNOSERS = [ + _IncompleteByReferenceArgumentDiagnoser, + _MockObjectPointerDiagnoser, + _NeedToReturnNothingDiagnoser, + _NeedToReturnReferenceDiagnoser, + _NeedToReturnSomethingDiagnoser, + _NeedToUseSymbolDiagnoser, + _OverloadedFunctionActionDiagnoser, + _OverloadedFunctionMatcherDiagnoser, + _OverloadedMethodActionDiagnoser1, + _OverloadedMethodActionDiagnoser2, + ] + + +def Diagnose(msg): + """Generates all possible diagnoses given the gcc error message.""" + + for diagnoser in _DIAGNOSERS: + for diagnosis in diagnoser(msg): + yield '[%s - %s]\n%s' % diagnosis + + +def main(): + print ('Google Mock Doctor v%s - ' + 'diagnoses problems in code using Google Mock.' % _VERSION) + + if sys.stdin.isatty(): + print ('Please copy and paste the compiler errors here. Press c-D when ' + 'you are done:') + else: + print 'Waiting for compiler errors on stdin . . .' + + msg = sys.stdin.read().strip() + diagnoses = list(Diagnose(msg)) + count = len(diagnoses) + if not count: + print '\nGcc complained:' + print '8<------------------------------------------------------------' + print msg + print '------------------------------------------------------------>8' + print """ +Uh-oh, I'm not smart enough to figure out what the problem is. :-( +However... +If you send your source code and gcc's error messages to +googlemock@googlegroups.com, you can be helped and I can get smarter -- +win-win for us!""" + else: + print '------------------------------------------------------------' + print 'Your code appears to have the following', + if count > 1: + print '%s diseases:' % (count,) + else: + print 'disease:' + i = 0 + for d in diagnoses: + i += 1 + if count > 1: + print '\n#%s:' % (i,) + print d + print """ +How did I do? If you think I'm wrong or unhelpful, please send your +source code and gcc's error messages to googlemock@googlegroups.com. Then +you can be helped and I can get smarter -- I promise I won't be upset!""" + + +if __name__ == '__main__': + main() |