aboutsummaryrefslogtreecommitdiffstats
path: root/scripts/gmock_doctor.py
diff options
context:
space:
mode:
authorshiqian <shiqian@8415998a-534a-0410-bf83-d39667b30386>2008-12-10 05:08:54 +0000
committershiqian <shiqian@8415998a-534a-0410-bf83-d39667b30386>2008-12-10 05:08:54 +0000
commite35fdd936d133bf8a48de140a3c666897588a053 (patch)
tree4e1dbda63ddea04bab288b1f2999896103bac4c3 /scripts/gmock_doctor.py
downloadgoogletest-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-xscripts/gmock_doctor.py376
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()