1 #!/usr/bin/env python 2 # 3 # Copyright 2008, Google Inc. 4 # 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 """Converts compiler's errors in code using Google Mock to plain English.""" 33 34 __author__ = 'wan (at] google.com (Zhanyong Wan)' 35 36 import re 37 import sys 38 39 _VERSION = '1.0.3' 40 41 _EMAIL = 'googlemock (at] googlegroups.com' 42 43 _COMMON_GMOCK_SYMBOLS = [ 44 # Matchers 45 '_', 46 'A', 47 'AddressSatisfies', 48 'AllOf', 49 'An', 50 'AnyOf', 51 'ContainerEq', 52 'Contains', 53 'ContainsRegex', 54 'DoubleEq', 55 'ElementsAre', 56 'ElementsAreArray', 57 'EndsWith', 58 'Eq', 59 'Field', 60 'FloatEq', 61 'Ge', 62 'Gt', 63 'HasSubstr', 64 'IsInitializedProto', 65 'Le', 66 'Lt', 67 'MatcherCast', 68 'Matches', 69 'MatchesRegex', 70 'NanSensitiveDoubleEq', 71 'NanSensitiveFloatEq', 72 'Ne', 73 'Not', 74 'NotNull', 75 'Pointee', 76 'Property', 77 'Ref', 78 'ResultOf', 79 'SafeMatcherCast', 80 'StartsWith', 81 'StrCaseEq', 82 'StrCaseNe', 83 'StrEq', 84 'StrNe', 85 'Truly', 86 'TypedEq', 87 'Value', 88 89 # Actions 90 'Assign', 91 'ByRef', 92 'DeleteArg', 93 'DoAll', 94 'DoDefault', 95 'IgnoreResult', 96 'Invoke', 97 'InvokeArgument', 98 'InvokeWithoutArgs', 99 'Return', 100 'ReturnNew', 101 'ReturnNull', 102 'ReturnRef', 103 'SaveArg', 104 'SetArgReferee', 105 'SetArgPointee', 106 'SetArgumentPointee', 107 'SetArrayArgument', 108 'SetErrnoAndReturn', 109 'Throw', 110 'WithArg', 111 'WithArgs', 112 'WithoutArgs', 113 114 # Cardinalities 115 'AnyNumber', 116 'AtLeast', 117 'AtMost', 118 'Between', 119 'Exactly', 120 121 # Sequences 122 'InSequence', 123 'Sequence', 124 125 # Misc 126 'DefaultValue', 127 'Mock', 128 ] 129 130 # Regex for matching source file path and line number in the compiler's errors. 131 _GCC_FILE_LINE_RE = r'(?P<file>.*):(?P<line>\d+):\s+' 132 _CLANG_FILE_LINE_RE = r'(?P<file>.*):(?P<line>\d+):(?P<column>\d+):\s+' 133 _CLANG_NON_GMOCK_FILE_LINE_RE = ( 134 r'(?P<file>.*[/\\^](?!gmock-)[^/\\]+):(?P<line>\d+):(?P<column>\d+):\s+') 135 136 137 def _FindAllMatches(regex, s): 138 """Generates all matches of regex in string s.""" 139 140 r = re.compile(regex) 141 return r.finditer(s) 142 143 144 def _GenericDiagnoser(short_name, long_name, diagnoses, msg): 145 """Diagnoses the given disease by pattern matching. 146 147 Can provide different diagnoses for different patterns. 148 149 Args: 150 short_name: Short name of the disease. 151 long_name: Long name of the disease. 152 diagnoses: A list of pairs (regex, pattern for formatting the diagnosis 153 for matching regex). 154 msg: Compiler's error messages. 155 Yields: 156 Tuples of the form 157 (short name of disease, long name of disease, diagnosis). 158 """ 159 for regex, diagnosis in diagnoses: 160 if re.search(regex, msg): 161 diagnosis = '%(file)s:%(line)s:' + diagnosis 162 for m in _FindAllMatches(regex, msg): 163 yield (short_name, long_name, diagnosis % m.groupdict()) 164 165 166 def _NeedToReturnReferenceDiagnoser(msg): 167 """Diagnoses the NRR disease, given the error messages by the compiler.""" 168 169 gcc_regex = (r'In member function \'testing::internal::ReturnAction<R>.*\n' 170 + _GCC_FILE_LINE_RE + r'instantiated from here\n' 171 r'.*gmock-actions\.h.*error: creating array with negative size') 172 clang_regex = (r'error:.*array.*negative.*\r?\n' 173 r'(.*\n)*?' + 174 _CLANG_NON_GMOCK_FILE_LINE_RE + 175 r'note: in instantiation of function template specialization ' 176 r'\'testing::internal::ReturnAction<(?P<type>).*>' 177 r'::operator Action<.*>\' requested here') 178 diagnosis = """ 179 You are using a Return() action in a function that returns a reference to 180 %(type)s. Please use ReturnRef() instead.""" 181 return _GenericDiagnoser('NRR', 'Need to Return Reference', 182 [(clang_regex, diagnosis), 183 (gcc_regex, diagnosis % {'type': 'a type'})], 184 msg) 185 186 187 def _NeedToReturnSomethingDiagnoser(msg): 188 """Diagnoses the NRS disease, given the error messages by the compiler.""" 189 190 gcc_regex = (_GCC_FILE_LINE_RE + r'(instantiated from here\n.' 191 r'*gmock.*actions\.h.*error: void value not ignored)' 192 r'|(error: control reaches end of non-void function)') 193 clang_regex1 = (_CLANG_FILE_LINE_RE + 194 r'error: cannot initialize return object ' 195 r'of type \'Result\' \(aka \'(?P<return_type>).*\'\) ' 196 r'with an rvalue of type \'void\'') 197 clang_regex2 = (_CLANG_FILE_LINE_RE + 198 r'error: cannot initialize return object ' 199 r'of type \'(?P<return_type>).*\' ' 200 r'with an rvalue of type \'void\'') 201 diagnosis = """ 202 You are using an action that returns void, but it needs to return 203 %(return_type)s. Please tell it *what* to return. Perhaps you can use 204 the pattern DoAll(some_action, Return(some_value))?""" 205 return _GenericDiagnoser( 206 'NRS', 207 'Need to Return Something', 208 [(gcc_regex, diagnosis % {'return_type': '*something*'}), 209 (clang_regex1, diagnosis), 210 (clang_regex2, diagnosis)], 211 msg) 212 213 214 def _NeedToReturnNothingDiagnoser(msg): 215 """Diagnoses the NRN disease, given the error messages by the compiler.""" 216 217 gcc_regex = (_GCC_FILE_LINE_RE + r'instantiated from here\n' 218 r'.*gmock-actions\.h.*error: instantiation of ' 219 r'\'testing::internal::ReturnAction<R>::Impl<F>::value_\' ' 220 r'as type \'void\'') 221 clang_regex1 = (r'error: field has incomplete type ' 222 r'\'Result\' \(aka \'void\'\)(\r)?\n' 223 r'(.*\n)*?' + 224 _CLANG_NON_GMOCK_FILE_LINE_RE + r'note: in instantiation ' 225 r'of function template specialization ' 226 r'\'testing::internal::ReturnAction<(?P<return_type>.*)>' 227 r'::operator Action<void \(.*\)>\' requested here') 228 clang_regex2 = (r'error: field has incomplete type ' 229 r'\'Result\' \(aka \'void\'\)(\r)?\n' 230 r'(.*\n)*?' + 231 _CLANG_NON_GMOCK_FILE_LINE_RE + r'note: in instantiation ' 232 r'of function template specialization ' 233 r'\'testing::internal::DoBothAction<.*>' 234 r'::operator Action<(?P<return_type>.*) \(.*\)>\' ' 235 r'requested here') 236 diagnosis = """ 237 You are using an action that returns %(return_type)s, but it needs to return 238 void. Please use a void-returning action instead. 239 240 All actions but the last in DoAll(...) must return void. Perhaps you need 241 to re-arrange the order of actions in a DoAll(), if you are using one?""" 242 return _GenericDiagnoser( 243 'NRN', 244 'Need to Return Nothing', 245 [(gcc_regex, diagnosis % {'return_type': '*something*'}), 246 (clang_regex1, diagnosis), 247 (clang_regex2, diagnosis)], 248 msg) 249 250 251 def _IncompleteByReferenceArgumentDiagnoser(msg): 252 """Diagnoses the IBRA disease, given the error messages by the compiler.""" 253 254 gcc_regex = (_GCC_FILE_LINE_RE + r'instantiated from here\n' 255 r'.*gtest-printers\.h.*error: invalid application of ' 256 r'\'sizeof\' to incomplete type \'(?P<type>.*)\'') 257 258 clang_regex = (r'.*gtest-printers\.h.*error: invalid application of ' 259 r'\'sizeof\' to an incomplete type ' 260 r'\'(?P<type>.*)( const)?\'\r?\n' 261 r'(.*\n)*?' + 262 _CLANG_NON_GMOCK_FILE_LINE_RE + 263 r'note: in instantiation of member function ' 264 r'\'testing::internal2::TypeWithoutFormatter<.*>::' 265 r'PrintValue\' requested here') 266 diagnosis = """ 267 In order to mock this function, Google Mock needs to see the definition 268 of type "%(type)s" - declaration alone is not enough. Either #include 269 the header that defines it, or change the argument to be passed 270 by pointer.""" 271 272 return _GenericDiagnoser('IBRA', 'Incomplete By-Reference Argument Type', 273 [(gcc_regex, diagnosis), 274 (clang_regex, diagnosis)], 275 msg) 276 277 278 def _OverloadedFunctionMatcherDiagnoser(msg): 279 """Diagnoses the OFM disease, given the error messages by the compiler.""" 280 281 gcc_regex = (_GCC_FILE_LINE_RE + r'error: no matching function for ' 282 r'call to \'Truly\(<unresolved overloaded function type>\)') 283 clang_regex = (_CLANG_FILE_LINE_RE + r'error: no matching function for ' 284 r'call to \'Truly') 285 diagnosis = """ 286 The argument you gave to Truly() is an overloaded function. Please tell 287 your compiler which overloaded version you want to use. 288 289 For example, if you want to use the version whose signature is 290 bool Foo(int n); 291 you should write 292 Truly(static_cast<bool (*)(int n)>(Foo))""" 293 return _GenericDiagnoser('OFM', 'Overloaded Function Matcher', 294 [(gcc_regex, diagnosis), 295 (clang_regex, diagnosis)], 296 msg) 297 298 299 def _OverloadedFunctionActionDiagnoser(msg): 300 """Diagnoses the OFA disease, given the error messages by the compiler.""" 301 302 gcc_regex = (_GCC_FILE_LINE_RE + r'error: no matching function for call to ' 303 r'\'Invoke\(<unresolved overloaded function type>') 304 clang_regex = (_CLANG_FILE_LINE_RE + r'error: no matching ' 305 r'function for call to \'Invoke\'\r?\n' 306 r'(.*\n)*?' 307 r'.*\bgmock-\w+-actions\.h:\d+:\d+:\s+' 308 r'note: candidate template ignored:\s+' 309 r'couldn\'t infer template argument \'FunctionImpl\'') 310 diagnosis = """ 311 Function you are passing to Invoke is overloaded. Please tell your compiler 312 which overloaded version you want to use. 313 314 For example, if you want to use the version whose signature is 315 bool MyFunction(int n, double x); 316 you should write something like 317 Invoke(static_cast<bool (*)(int n, double x)>(MyFunction))""" 318 return _GenericDiagnoser('OFA', 'Overloaded Function Action', 319 [(gcc_regex, diagnosis), 320 (clang_regex, diagnosis)], 321 msg) 322 323 324 def _OverloadedMethodActionDiagnoser(msg): 325 """Diagnoses the OMA disease, given the error messages by the compiler.""" 326 327 gcc_regex = (_GCC_FILE_LINE_RE + r'error: no matching function for ' 328 r'call to \'Invoke\(.+, <unresolved overloaded function ' 329 r'type>\)') 330 clang_regex = (_CLANG_FILE_LINE_RE + r'error: no matching function ' 331 r'for call to \'Invoke\'\r?\n' 332 r'(.*\n)*?' 333 r'.*\bgmock-\w+-actions\.h:\d+:\d+: ' 334 r'note: candidate function template not viable: ' 335 r'requires 1 argument, but 2 were provided') 336 diagnosis = """ 337 The second argument you gave to Invoke() is an overloaded method. Please 338 tell your compiler which overloaded version you want to use. 339 340 For example, if you want to use the version whose signature is 341 class Foo { 342 ... 343 bool Bar(int n, double x); 344 }; 345 you should write something like 346 Invoke(foo, static_cast<bool (Foo::*)(int n, double x)>(&Foo::Bar))""" 347 return _GenericDiagnoser('OMA', 'Overloaded Method Action', 348 [(gcc_regex, diagnosis), 349 (clang_regex, diagnosis)], 350 msg) 351 352 353 def _MockObjectPointerDiagnoser(msg): 354 """Diagnoses the MOP disease, given the error messages by the compiler.""" 355 356 gcc_regex = (_GCC_FILE_LINE_RE + r'error: request for member ' 357 r'\'gmock_(?P<method>.+)\' in \'(?P<mock_object>.+)\', ' 358 r'which is of non-class type \'(.*::)*(?P<class_name>.+)\*\'') 359 clang_regex = (_CLANG_FILE_LINE_RE + r'error: member reference type ' 360 r'\'(?P<class_name>.*?) *\' is a pointer; ' 361 r'maybe you meant to use \'->\'\?') 362 diagnosis = """ 363 The first argument to ON_CALL() and EXPECT_CALL() must be a mock *object*, 364 not a *pointer* to it. Please write '*(%(mock_object)s)' instead of 365 '%(mock_object)s' as your first argument. 366 367 For example, given the mock class: 368 369 class %(class_name)s : public ... { 370 ... 371 MOCK_METHOD0(%(method)s, ...); 372 }; 373 374 and the following mock instance: 375 376 %(class_name)s* mock_ptr = ... 377 378 you should use the EXPECT_CALL like this: 379 380 EXPECT_CALL(*mock_ptr, %(method)s(...));""" 381 382 return _GenericDiagnoser( 383 'MOP', 384 'Mock Object Pointer', 385 [(gcc_regex, diagnosis), 386 (clang_regex, diagnosis % {'mock_object': 'mock_object', 387 'method': 'method', 388 'class_name': '%(class_name)s'})], 389 msg) 390 391 392 def _NeedToUseSymbolDiagnoser(msg): 393 """Diagnoses the NUS disease, given the error messages by the compiler.""" 394 395 gcc_regex = (_GCC_FILE_LINE_RE + r'error: \'(?P<symbol>.+)\' ' 396 r'(was not declared in this scope|has not been declared)') 397 clang_regex = (_CLANG_FILE_LINE_RE + r'error: use of undeclared identifier ' 398 r'\'(?P<symbol>.+)\'') 399 diagnosis = """ 400 '%(symbol)s' is defined by Google Mock in the testing namespace. 401 Did you forget to write 402 using testing::%(symbol)s; 403 ?""" 404 for m in (list(_FindAllMatches(gcc_regex, msg)) + 405 list(_FindAllMatches(clang_regex, msg))): 406 symbol = m.groupdict()['symbol'] 407 if symbol in _COMMON_GMOCK_SYMBOLS: 408 yield ('NUS', 'Need to Use Symbol', diagnosis % m.groupdict()) 409 410 411 def _NeedToUseReturnNullDiagnoser(msg): 412 """Diagnoses the NRNULL disease, given the error messages by the compiler.""" 413 414 gcc_regex = ('instantiated from \'testing::internal::ReturnAction<R>' 415 '::operator testing::Action<Func>\(\) const.*\n' + 416 _GCC_FILE_LINE_RE + r'instantiated from here\n' 417 r'.*error: no matching function for call to \'ImplicitCast_\(' 418 r'long int&\)') 419 clang_regex = (r'\bgmock-actions.h:.* error: no matching function for ' 420 r'call to \'ImplicitCast_\'\r?\n' 421 r'(.*\n)*?' + 422 _CLANG_NON_GMOCK_FILE_LINE_RE + r'note: in instantiation ' 423 r'of function template specialization ' 424 r'\'testing::internal::ReturnAction<long>::operator ' 425 r'Action<(?P<type>.*)\(\)>\' requested here') 426 diagnosis = """ 427 You are probably calling Return(NULL) and the compiler isn't sure how to turn 428 NULL into %(type)s. Use ReturnNull() instead. 429 Note: the line number may be off; please fix all instances of Return(NULL).""" 430 return _GenericDiagnoser( 431 'NRNULL', 'Need to use ReturnNull', 432 [(clang_regex, diagnosis), 433 (gcc_regex, diagnosis % {'type': 'the right type'})], 434 msg) 435 436 437 def _TypeInTemplatedBaseDiagnoser(msg): 438 """Diagnoses the TTB disease, given the error messages by the compiler.""" 439 440 # This version works when the type is used as the mock function's return 441 # type. 442 gcc_4_3_1_regex_type_in_retval = ( 443 r'In member function \'int .*\n' + _GCC_FILE_LINE_RE + 444 r'error: a function call cannot appear in a constant-expression') 445 gcc_4_4_0_regex_type_in_retval = ( 446 r'error: a function call cannot appear in a constant-expression' 447 + _GCC_FILE_LINE_RE + r'error: template argument 1 is invalid\n') 448 # This version works when the type is used as the mock function's sole 449 # parameter type. 450 gcc_regex_type_of_sole_param = ( 451 _GCC_FILE_LINE_RE + 452 r'error: \'(?P<type>.+)\' was not declared in this scope\n' 453 r'.*error: template argument 1 is invalid\n') 454 # This version works when the type is used as a parameter of a mock 455 # function that has multiple parameters. 456 gcc_regex_type_of_a_param = ( 457 r'error: expected `;\' before \'::\' token\n' 458 + _GCC_FILE_LINE_RE + 459 r'error: \'(?P<type>.+)\' was not declared in this scope\n' 460 r'.*error: template argument 1 is invalid\n' 461 r'.*error: \'.+\' was not declared in this scope') 462 clang_regex_type_of_retval_or_sole_param = ( 463 _CLANG_FILE_LINE_RE + 464 r'error: use of undeclared identifier \'(?P<type>.*)\'\n' 465 r'(.*\n)*?' 466 r'(?P=file):(?P=line):\d+: error: ' 467 r'non-friend class member \'Result\' cannot have a qualified name' 468 ) 469 clang_regex_type_of_a_param = ( 470 _CLANG_FILE_LINE_RE + 471 r'error: C\+\+ requires a type specifier for all declarations\n' 472 r'(.*\n)*?' 473 r'(?P=file):(?P=line):(?P=column): error: ' 474 r'C\+\+ requires a type specifier for all declarations' 475 ) 476 477 diagnosis = """ 478 In a mock class template, types or typedefs defined in the base class 479 template are *not* automatically visible. This is how C++ works. Before 480 you can use a type or typedef named %(type)s defined in base class Base<T>, you 481 need to make it visible. One way to do it is: 482 483 typedef typename Base<T>::%(type)s %(type)s;""" 484 485 return _GenericDiagnoser( 486 'TTB', 'Type in Template Base', 487 [(gcc_4_3_1_regex_type_in_retval, diagnosis % {'type': 'Foo'}), 488 (gcc_4_4_0_regex_type_in_retval, diagnosis % {'type': 'Foo'}), 489 (gcc_regex_type_of_sole_param, diagnosis), 490 (gcc_regex_type_of_a_param, diagnosis), 491 (clang_regex_type_of_retval_or_sole_param, diagnosis), 492 (clang_regex_type_of_a_param, diagnosis % {'type': 'Foo'})], 493 msg) 494 495 496 def _WrongMockMethodMacroDiagnoser(msg): 497 """Diagnoses the WMM disease, given the error messages by the compiler.""" 498 499 gcc_regex = (_GCC_FILE_LINE_RE + 500 r'.*this_method_does_not_take_(?P<wrong_args>\d+)_argument.*\n' 501 r'.*\n' 502 r'.*candidates are.*FunctionMocker<[^>]+A(?P<args>\d+)\)>') 503 clang_regex = (_CLANG_NON_GMOCK_FILE_LINE_RE + 504 r'error:.*array.*negative.*r?\n' 505 r'(.*\n)*?' 506 r'(?P=file):(?P=line):(?P=column): error: too few arguments ' 507 r'to function call, expected (?P<args>\d+), ' 508 r'have (?P<wrong_args>\d+)') 509 diagnosis = """ 510 You are using MOCK_METHOD%(wrong_args)s to define a mock method that has 511 %(args)s arguments. Use MOCK_METHOD%(args)s (or MOCK_CONST_METHOD%(args)s, 512 MOCK_METHOD%(args)s_T, MOCK_CONST_METHOD%(args)s_T as appropriate) instead.""" 513 return _GenericDiagnoser('WMM', 'Wrong MOCK_METHODn Macro', 514 [(gcc_regex, diagnosis), 515 (clang_regex, diagnosis)], 516 msg) 517 518 519 def _WrongParenPositionDiagnoser(msg): 520 """Diagnoses the WPP disease, given the error messages by the compiler.""" 521 522 gcc_regex = (_GCC_FILE_LINE_RE + 523 r'error:.*testing::internal::MockSpec<.* has no member named \'' 524 r'(?P<method>\w+)\'') 525 clang_regex = (_CLANG_NON_GMOCK_FILE_LINE_RE + 526 r'error: no member named \'(?P<method>\w+)\' in ' 527 r'\'testing::internal::MockSpec<.*>\'') 528 diagnosis = """ 529 The closing parenthesis of ON_CALL or EXPECT_CALL should be *before* 530 ".%(method)s". For example, you should write: 531 EXPECT_CALL(my_mock, Foo(_)).%(method)s(...); 532 instead of: 533 EXPECT_CALL(my_mock, Foo(_).%(method)s(...));""" 534 return _GenericDiagnoser('WPP', 'Wrong Parenthesis Position', 535 [(gcc_regex, diagnosis), 536 (clang_regex, diagnosis)], 537 msg) 538 539 540 _DIAGNOSERS = [ 541 _IncompleteByReferenceArgumentDiagnoser, 542 _MockObjectPointerDiagnoser, 543 _NeedToReturnNothingDiagnoser, 544 _NeedToReturnReferenceDiagnoser, 545 _NeedToReturnSomethingDiagnoser, 546 _NeedToUseReturnNullDiagnoser, 547 _NeedToUseSymbolDiagnoser, 548 _OverloadedFunctionActionDiagnoser, 549 _OverloadedFunctionMatcherDiagnoser, 550 _OverloadedMethodActionDiagnoser, 551 _TypeInTemplatedBaseDiagnoser, 552 _WrongMockMethodMacroDiagnoser, 553 _WrongParenPositionDiagnoser, 554 ] 555 556 557 def Diagnose(msg): 558 """Generates all possible diagnoses given the compiler error message.""" 559 560 msg = re.sub(r'\x1b\[[^m]*m', '', msg) # Strips all color formatting. 561 562 diagnoses = [] 563 for diagnoser in _DIAGNOSERS: 564 for diag in diagnoser(msg): 565 diagnosis = '[%s - %s]\n%s' % diag 566 if not diagnosis in diagnoses: 567 diagnoses.append(diagnosis) 568 return diagnoses 569 570 571 def main(): 572 print ('Google Mock Doctor v%s - ' 573 'diagnoses problems in code using Google Mock.' % _VERSION) 574 575 if sys.stdin.isatty(): 576 print ('Please copy and paste the compiler errors here. Press c-D when ' 577 'you are done:') 578 else: 579 print 'Waiting for compiler errors on stdin . . .' 580 581 msg = sys.stdin.read().strip() 582 diagnoses = Diagnose(msg) 583 count = len(diagnoses) 584 if not count: 585 print (""" 586 Your compiler complained: 587 8<------------------------------------------------------------ 588 %s 589 ------------------------------------------------------------>8 590 591 Uh-oh, I'm not smart enough to figure out what the problem is. :-( 592 However... 593 If you send your source code and the compiler's error messages to 594 %s, you can be helped and I can get smarter -- 595 win-win for us!""" % (msg, _EMAIL)) 596 else: 597 print '------------------------------------------------------------' 598 print 'Your code appears to have the following', 599 if count > 1: 600 print '%s diseases:' % (count,) 601 else: 602 print 'disease:' 603 i = 0 604 for d in diagnoses: 605 i += 1 606 if count > 1: 607 print '\n#%s:' % (i,) 608 print d 609 print (""" 610 How did I do? If you think I'm wrong or unhelpful, please send your 611 source code and the compiler's error messages to %s. 612 Then you can be helped and I can get smarter -- I promise I won't be upset!""" % 613 _EMAIL) 614 615 616 if __name__ == '__main__': 617 main() 618