def test_parse_errors(self): test_string = """\ <?xml version="1.0" encoding="UTF-8"?> <pmd version="5.5.0" timestamp="2016-07-06T11:29:03.360"> <file name="{0}/DriverRideDrivingToWaypointController.java"> <violation beginline="287" endline="287" begincolumn="58" endcolumn="61" rule="UnusedFormalParameter" ruleset="Unused Code" package="me.lyft.android.ui.driver.ridescreens" class="DriverRideDrivingToWaypointController" method="displayWaypointAddress" variable="ride" externalInfoUrl="https://pmd.github.io/pmd-5.5.0/pmd-java/rules/java/unusedcode.html#UnusedFormalParameter" priority="3"> Avoid unused method parameters such as 'ride'. </violation> </file> <file name="{0}/AddCouponView.java"> <violation beginline="24" endline="24" begincolumn="1" endcolumn="38" rule="UnusedImports" ruleset="Import Statements" package="me.lyft.android.ui.payment" externalInfoUrl="https://pmd.github.io/pmd-5.5.0/pmd-java/rules/java/imports.html#UnusedImports" priority="4"> Avoid unused imports such as 'me.lyft.android.common.Strings' </violation> </file> </pmd> """.format(os.path.curdir) result = pmd.parse(test_string) self.assertEqual(2, len(result)) self.assertIn( Problem( './DriverRideDrivingToWaypointController.java', 287, 'UnusedFormalParameter: Avoid unused method' " parameters such as 'ride'."), result) self.assertIn( Problem( './AddCouponView.java', 24, 'UnusedImports: Avoid unused imports such as' " 'me.lyft.android.common.Strings'"), result)
def test_parse_errors(self): test_string = """\ <?xml version='1.0' encoding='UTF-8'?> <checkstyle version='4.3'> <file name='scripts/run_tests.sh' > <error line='31' column='26' severity='info' message='Double quote to prevent globbing and word splitting.' source='ShellCheck.SC2086' /> </file> <file name='scripts/setup.sh' > <error line='3' column='1' severity='warning' message='FOO appears unused. Verify it or export it.' source='ShellCheck.SC2034' /> </file> </checkstyle> """ result = checkstyle.parse(test_string) self.assertEqual(2, len(result)) self.assertIn( Problem( 'scripts/run_tests.sh', 31, 'ShellCheck.SC2086: Double quote to prevent ' 'globbing and word splitting.'), result) self.assertIn( Problem( 'scripts/setup.sh', 3, 'ShellCheck.SC2034: FOO appears unused. ' 'Verify it or export it.'), result)
def test_parse_errors(self): test_string = [ '{}/Classes/Foo + Bar/Foo + Menu/Controllers/' 'SomeController.swift:42: warning: ' 'Documentation Comment Violation: Needs documentation ' 'comment'.format(os.path.curdir), '{}/Classes/Foo + Bar/Foo + Menu/Controllers/' 'AnotherController.swift:50:5: warning: ' 'Documentation Comment Violation: Needs documentation ' 'comment'.format(os.path.curdir) ] result = swiftlint.parse('\n'.join(test_string)) self.assertEqual(2, len(result)) self.assertIn( Problem( 'Classes/Foo + Bar/Foo + Menu/Controllers/' 'SomeController.swift', 42, 'Documentation Comment Violation: ' 'Needs documentation comment'), result) self.assertIn( Problem( 'Classes/Foo + Bar/Foo + Menu/Controllers/' 'AnotherController.swift', 50, 'Documentation Comment Violation: ' 'Needs documentation comment'), result)
def test_parse_errors(self): test_string = [ 'Something happened!', "More stuff 'happened'", ] result = passthrough.parse('\n'.join(test_string)) self.assertEqual(2, len(result)) self.assertIn(Problem('', 0, 'Something happened!'), result) self.assertIn(Problem('', 0, "More stuff 'happened'"), result)
def test_parse_errors(self): test_string = ''' src/linters/pylint.py:10: [E302] expected 2 blank lines, found 1 tests/linters/pylint.py:42: [E302] expected 2 blank lines, found 1 ''' result = pylint.parse(test_string) self.assertEqual(2, len(result)) self.assertIn( Problem('src/linters/pylint.py', 10, '[E302] expected 2 blank lines, found 1'), result) self.assertIn( Problem('tests/linters/pylint.py', 42, '[E302] expected 2 blank lines, found 1'), result)
def test_comment_overflow(self, mock_getenv, mock_client_session): mock_args, fake_client_session = self.create_mock_pr( mock_getenv, mock_client_session) reporter = github_reporter.create_reporter(mock_args) problems = [Problem('another_file', x, 'Wat') for x in range(1, 13)] async_report = reporter.report('unit-test-linter', problems) loop = asyncio.get_event_loop() loop.run_until_complete(async_report) overflow_message = textwrap.dedent('''\ unit-test-linter says: Too many lint errors to report inline! 12 lines have a problem. Only reporting the first 10.''') overflow_call = call.post( 'https://api.github.com/repos/foo/bar/issues/1234/comments', headers={'Authorization': 'token MY_TOKEN'}, data=json.dumps({ 'body': overflow_message, }, sort_keys=True)) self.assertIn(overflow_call, fake_client_session.calls) self.assertEqual(3 + github_reporter.MAX_LINT_ERROR_REPORTS, len(fake_client_session.calls))
def test_parse_errors(self): test_string = ''' src/linters/pylint.py: note: expected 2 blank lines, found 1 tests/linters/pylint.py:42: error: "module" has no attribute "foo" tests/linters/pylint.py:33: error: "module" has no attribute "bar" ''' result = mypy.parse(test_string) self.assertEqual(2, len(result)) self.assertIn( Problem('tests/linters/pylint.py', 42, 'error: "module" has no attribute "foo"'), result) self.assertIn( Problem('tests/linters/pylint.py', 33, 'error: "module" has no attribute "bar"'), result)
def test_parse_all(self): result = android.parse(test_string, pass_warnings=False) self.assertEqual(2, len(result)) self.assertIn(Problem('scripts/run_tests.sh', 15, 'ScrollView size validation: This LinearLayout ' 'should use ' '`android:layout_height="wrap_content"`'), result) self.assertIn(Problem('scripts/setup.sh', 238, 'Implied default locale in case conversion: ' 'Implicitly using the default locale is a ' 'common source of bugs: Use ' '`toLowerCase(Locale)` instead'), result)
def parse(contents: str, **kwargs) -> Set[Problem]: result = set() # type: Set[Problem] for line in contents.splitlines(): match = PYLINT_LINE_REGEX.match(line) if match: groups = match.groupdict() result.add( Problem(groups['path'], groups['line'], groups['message'])) return result
def test_parse_errors_only(self): result = android.parse(test_string, pass_warnings=True) self.assertEqual(1, len(result)) self.assertIn(Problem('scripts/run_tests.sh', 15, 'ScrollView size validation: This LinearLayout ' 'should use ' '`android:layout_height="wrap_content"`'), result)
def test_parse_errors(self): test_string = [ "<unknown>:0: error: no such file or directory: 'foo.swift'", "<unknown>:0: ERROR: no such file or directory: 'case.swift'", "{}/Classes/foo/bar baz/qux.swift:201:21: " "error: use of unresolved identifier 'FooBar'".format( os.path.curdir), "{}/Classes/foo/bar/Protocols/SomeProtocol.swift:7:10: " "note: did you mean 'SomeOtherProtocol'?".format(os.path.curdir), "{}/Resources/Storyboards & XIBs/Foo.storyboard:kB7-Bl-wC0: " "warning: Unsupported configuration of constraint attributes. " "This may produce unexpected results at runtime before Xcode 5.1". format(os.path.curdir), ] result = xcodebuild.parse('\n'.join(test_string)) self.assertEqual(5, len(result)) self.assertIn( Problem('<unknown>', 0, "no such file or directory: 'foo.swift'"), result) self.assertIn( Problem('<unknown>', 0, "no such file or directory: 'case.swift'"), result) self.assertIn( Problem('Classes/foo/bar baz/' 'qux.swift', 201, "use of unresolved identifier 'FooBar'"), result) self.assertIn( Problem('Classes/foo/bar/Protocols/' 'SomeProtocol.swift', 7, "did you mean 'SomeOtherProtocol'?"), result) self.assertIn( Problem( 'Resources/Storyboards & XIBs/' 'Foo.storyboard', 0, 'kB7-Bl-wC0: Unsupported configuration of ' 'constraint attributes. This may produce unexpected ' 'results at runtime before Xcode 5.1'), result)
def parse(contents: str) -> Set[Problem]: result = set() # type: Set[Problem] for line in contents.splitlines(): match = MYPY_LINE_REGEX.match(line) if match: groups = match.groupdict() if groups['code'] != 'note': result.add( Problem(groups['path'], groups['line'], '{}: {}'.format(groups['code'], groups['message']))) return result
def parse(contents: str) -> Set[Problem]: result = set() # type: Set[Problem] try: root = ElementTree.fromstring(contents) except ElementTree.ParseError: return result for file in root.findall('file'): file_name = file.get('name') for error in file.findall('error'): result.add( Problem( file_name, error.get('line'), '{}: {}'.format(error.get('source'), error.get('message')))) return result
def parse(contents: str, **kwargs) -> Set[Problem]: result = set() # type: Set[Problem] try: root = ElementTree.fromstring(contents) except ElementTree.ParseError: return result for file in root.findall('file'): file_name = file.get('name') for violation in file.findall('violation'): result.add( Problem( file_name, violation.get('beginline'), '{}: {}'.format(violation.get('rule'), violation.text.strip()))) return result
def parse(contents: str, **kwargs) -> Set[Problem]: result = set() # type: Set[Problem] for line in contents.splitlines(): match = XCODEBUILD_LINE_REGEX.match(line) if match: groups = match.groupdict() line = groups['line'] or 0 message = groups['message'] reference = groups['reference'] if reference: message = '{}: {}'.format(reference, message) result.add(Problem(os.path.relpath(groups['path']), line, message)) return result
def test_comment_on_pr(self, mock_getenv, mock_client_session): mock_args, fake_client_session = self.create_mock_pr( mock_getenv, mock_client_session) reporter = github_reporter.create_reporter(mock_args) async_report = reporter.report('unit-test-linter', [ Problem('some_dir/some_file', 40, 'this made me sad'), Problem('some_dir/some_file', 40, 'really sad'), Problem('another_file', 2, 'This is OK'), Problem('another_file', 2, 'This is OK'), Problem('another_file', 3, 'I am a duplicate!'), Problem('another_file', 52, "#close_enough!!!"), Problem('missing_file', 42, "Missing file comment!!!"), ]) loop = asyncio.get_event_loop() loop.run_until_complete(async_report) diff_request = call.get( 'https://api.github.com/repos/foo/bar/pulls/1234', headers={ 'Accept': 'application/vnd.github.diff', 'Authorization': 'token MY_TOKEN' }) existing_comments_request = call.get( 'https://api.github.com/repos/foo/bar/pulls/1234/comments', headers={'Authorization': 'token MY_TOKEN'}) first_comment = call.post( 'https://api.github.com/repos/foo/bar/pulls/1234/comments', headers={'Authorization': 'token MY_TOKEN'}, data=json.dumps( { 'commit_id': 'abc123', 'path': 'another_file', 'body': textwrap.dedent('''\ unit-test-linter says: ``` This is OK ```'''), 'position': 2 }, sort_keys=True)) second_comment = call.post( 'https://api.github.com/repos/foo/bar/pulls/1234/comments', headers={'Authorization': 'token MY_TOKEN'}, data=json.dumps( { 'commit_id': 'abc123', 'path': 'some_dir/some_file', 'body': textwrap.dedent('''\ unit-test-linter says: ``` this made me sad really sad ```'''), 'position': 3 }, sort_keys=True)) close_enough_comment = call.post( 'https://api.github.com/repos/foo/bar/pulls/1234/comments', headers={'Authorization': 'token MY_TOKEN'}, data=json.dumps( { 'commit_id': 'abc123', 'path': 'another_file', 'body': textwrap.dedent('''\ unit-test-linter says: (From line 52) ``` #close_enough!!! ```'''), 'position': 12 }, sort_keys=True)) missing_file_call = call.post( 'https://api.github.com/repos/foo/bar/issues/1234/comments', headers={'Authorization': 'token MY_TOKEN'}, data=json.dumps( { 'body': textwrap.dedent('''\ unit-test-linter found some problems with lines not modified by this commit: ``` missing_file:42: \tMissing file comment!!! ```'''), }, sort_keys=True)) self.assertEqual(6, len(fake_client_session.calls)) self.assertIn(diff_request, fake_client_session.calls) self.assertIn(existing_comments_request, fake_client_session.calls) self.assertIn(first_comment, fake_client_session.calls) self.assertIn(second_comment, fake_client_session.calls) self.assertIn(close_enough_comment, fake_client_session.calls) self.assertIn(missing_file_call, fake_client_session.calls)
def parse(contents: str, **kwargs) -> Set[Problem]: if contents: return set([Problem('', 0, contents.strip())]) else: return set()
def test_comment_on_pr(self, mock_getenv, mock_client_session): mock_args, fake_client_session = self.create_mock_pr( mock_getenv, mock_client_session) reporter = github_reporter.create_reporter(mock_args) async_report = reporter.report([ Problem('some_dir/some_file', 40, 'this made me sad'), Problem('some_dir/some_file', 40, 'really sad'), Problem('another_file', 2, 'This is OK'), Problem('another_file', 2, 'This is OK'), Problem('another_file', 3, 'I am a duplicate!'), Problem('missing_file', 42, "Don't report me!!!"), ]) loop = asyncio.get_event_loop() loop.run_until_complete(async_report) diff_request = call.get( 'https://api.github.com/repos/foo/bar/pulls/1234', headers={ 'Accept': 'application/vnd.github.diff', 'Authorization': 'token MY_TOKEN' }) existing_comments_request = call.get( 'https://api.github.com/repos/foo/bar/pulls/1234/comments', headers={'Authorization': 'token MY_TOKEN'}) first_comment = call.post( 'https://api.github.com/repos/foo/bar/pulls/1234/comments', headers={'Authorization': 'token MY_TOKEN'}, data=json.dumps( { 'commit_id': 'abc123', 'path': 'another_file', 'body': textwrap.dedent('''\ :sparkles:Linty Fresh Says:sparkles:: ``` This is OK ```'''), 'position': 2 }, sort_keys=True)) second_comment = call.post( 'https://api.github.com/repos/foo/bar/pulls/1234/comments', headers={'Authorization': 'token MY_TOKEN'}, data=json.dumps( { 'commit_id': 'abc123', 'path': 'some_dir/some_file', 'body': textwrap.dedent('''\ :sparkles:Linty Fresh Says:sparkles:: ``` this made me sad really sad ```'''), 'position': 3 }, sort_keys=True)) self.assertEqual(4, len(fake_client_session.calls)) self.assertIn(diff_request, fake_client_session.calls) self.assertIn(existing_comments_request, fake_client_session.calls) self.assertIn(first_comment, fake_client_session.calls) self.assertIn(second_comment, fake_client_session.calls)
def parse(contents: str, **kwargs) -> Set[Problem]: return set(Problem('', 0, x) for x in contents.splitlines())