def test_publish_problems_remove_ok_label(self): problems = Problems() filename_1 = 'Console/Command/Task/AssetBuildTask.php' errors = ( (filename_1, 117, 'Something bad'), (filename_1, 119, 'Something bad'), ) problems.add_many(errors) sha = 'abc123' config = {'OK_LABEL': 'No lint'} review = Review(self.repo, self.pr, config) sha = 'abc123' review.publish_problems(problems, sha) assert self.pr.remove_label.called, 'Label should be removed' assert self.pr.create_review_comment.called, 'Comments should be added' eq_(2, self.pr.create_review_comment.call_count) self.pr.remove_label.assert_called_with(config['OK_LABEL']) assert_review_comments_created( self.pr.create_review_comment.call_args_list, errors, sha)
class TestFlake8(TestCase): fixtures = [ 'tests/fixtures/pep8/no_errors.py', 'tests/fixtures/pep8/has_errors.py', ] def setUp(self): self.problems = Problems() self.tool = Flake8(self.problems) def test_match_file(self): self.assertFalse(self.tool.match_file('test.php')) self.assertFalse(self.tool.match_file('test.js')) self.assertFalse(self.tool.match_file('dir/name/test.js')) self.assertTrue(self.tool.match_file('test.py')) self.assertTrue(self.tool.match_file('dir/name/test.py')) def test_process_files__one_file_pass(self): self.tool.process_files([self.fixtures[0]]) eq_([], self.problems.all(self.fixtures[0])) def test_process_files__one_file_fail(self): self.tool.process_files([self.fixtures[1]]) problems = self.problems.all(self.fixtures[1]) eq_(8, len(problems)) fname = self.fixtures[1] expected = Comment(fname, 2, 2, "F401 're' imported but unused") eq_(expected, problems[1]) expected = Comment(fname, 11, 11, "W603 '<>' is deprecated, use '!='") eq_(expected, problems[7]) def test_process_files_two_files(self): self.tool.process_files(self.fixtures) eq_([], self.problems.all(self.fixtures[0])) problems = self.problems.all(self.fixtures[1]) eq_(8, len(problems)) fname = self.fixtures[1] expected = Comment(fname, 2, 2, "F401 're' imported but unused") eq_(expected, problems[1]) expected = Comment(fname, 11, 11, "W603 '<>' is deprecated, use '!='") eq_(expected, problems[7]) def test_config_options_and_process_file(self): options = { 'ignore': 'F4,W603' } self.tool = Flake8(self.problems, options) self.tool.process_files([self.fixtures[1]]) problems = self.problems.all(self.fixtures[1]) eq_(6, len(problems)) for p in problems: self.assertFalse('F4' in p) self.assertFalse('W603' in p)
def test_publish_problems(self): gh = Mock() problems = Problems() filename_1 = 'Console/Command/Task/AssetBuildTask.php' errors = ( (filename_1, 117, 'Something bad'), (filename_1, 119, 'Something bad'), ) problems.add_many(errors) sha = 'abc123' review = Review(gh, 3) review.publish_problems(problems, sha) assert gh.pull_requests.comments.create.called eq_(2, gh.pull_requests.comments.create.call_count) calls = gh.pull_requests.comments.create.call_args_list expected = call(3, { 'commit_id': sha, 'path': errors[0][0], 'position': errors[0][1], 'body': errors[0][2] }) eq_(calls[0], expected) expected = call(3, { 'commit_id': sha, 'path': errors[1][0], 'position': errors[1][1], 'body': errors[1][2] }) eq_(calls[1], expected)
def test_publish_summary(self): gh = Mock() problems = Problems() filename_1 = 'Console/Command/Task/AssetBuildTask.php' errors = ( (filename_1, 117, 'Something bad'), (filename_1, 119, 'Something bad'), ) problems.add_many(errors) problems.set_changes([1]) sha = 'abc123' review = Review(gh, 3) review.publish_summary(problems) assert gh.issues.comments.create.called eq_(1, gh.issues.comments.create.call_count) calls = gh.issues.comments.create.call_args_list msg = """There are 2 errors: * Console/Command/Task/AssetBuildTask.php, line 117 - Something bad * Console/Command/Task/AssetBuildTask.php, line 119 - Something bad """ expected = call(3, msg) eq_(calls[0], expected)
def test_publish_checkrun(self): self.repo.create_checkrun = Mock() tst_config = build_review_config(fixer_ini, {'PULLREQUEST_STATUS': True}) problems = Problems() filename_1 = 'Console/Command/Task/AssetBuildTask.php' errors = ( Comment(filename_1, 117, 8, 'Something bad'), Comment(filename_1, 119, 9, 'Something worse'), ) problems.add_many(errors) run_id = 42 review = Review(self.repo, self.pr, tst_config) review.publish_checkrun(problems, run_id) assert self.repo.update_checkrun.called self.assertEqual(1, self.repo.update_checkrun.call_count) assert_checkrun( self, self.repo.update_checkrun.call_args, errors, run_id) assert self.repo.create_status.called is False, 'no status required'
class Processor(object): def __init__(self, client, number, head, target_path): self._client = client self._number = number self._head = head self._target_path = target_path self._changes = None self._problems = Problems(target_path) self._review = Review(client, number) def load_changes(self): log.info('Loading pull request patches from github.') files = self._client.pull_requests.list_files(self._number) pull_request_patches = files.all() self._changes = DiffCollection(pull_request_patches) self._problems.set_changes(self._changes) def run_tools(self, review_config): if self._changes is None: raise RuntimeError('No loaded changes, cannot run tools. ' 'Try calling load_changes first.') files_to_check = self._changes.get_files( append_base=self._target_path, ignore_patterns=review_config.ignore_patterns()) tools.run( review_config, self._problems, files_to_check, self._target_path) def publish(self, wait_time=0): self._problems.limit_to_changes() self._review.publish(self._problems, self._head, wait_time)
def test_publish_pull_review_remove_ok_label(self): problems = Problems() filename_1 = 'Console/Command/Task/AssetBuildTask.php' errors = ( Comment(filename_1, 117, 117, 'Something bad'), Comment(filename_1, 119, 119, 'Something bad'), ) problems.add_many(errors) tst_config = build_review_config(fixer_ini, {'OK_LABEL': 'No lint'}) review = Review(self.repo, self.pr, tst_config) sha = 'abc123' review.publish_pull_review(problems, sha) assert self.pr.remove_label.called, 'Label should be removed' assert self.pr.create_review.called, 'Review should be added' self.assertEqual(1, self.pr.create_review.call_count) self.pr.remove_label.assert_called_with(tst_config['OK_LABEL']) assert_review( self, self.pr.create_review.call_args, errors, sha)
def test_publish_summary(self): problems = Problems() filename_1 = 'Console/Command/Task/AssetBuildTask.php' errors = ( IssueComment('Terrible things'), Comment(filename_1, 117, 117, 'Something bad'), Comment(filename_1, 119, 119, 'Something bad'), ) problems.add_many(errors) problems.set_changes([1]) review = Review(self.repo, self.pr, self.config) review.publish_summary(problems) assert self.pr.create_comment.called self.assertEqual(1, self.pr.create_comment.call_count) msg = """There are 3 errors: * Terrible things * Console/Command/Task/AssetBuildTask.php, line 117 - Something bad * Console/Command/Task/AssetBuildTask.php, line 119 - Something bad """ self.pr.create_comment.assert_called_with(msg)
def test_publish_problems_remove_ok_label(self): problems = Problems() filename_1 = 'Console/Command/Task/AssetBuildTask.php' errors = ( (filename_1, 117, 'Something bad'), (filename_1, 119, 'Something bad'), ) problems.add_many(errors) sha = 'abc123' review = Review(self.gh, 3) label = 'No lint errors' with add_ok_label(self.gh, 3, review, label): sha = 'abc123' review.publish_problems(problems, sha) assert self.issue.remove_label.called, 'Label should be removed' assert self.pr.create_review_comment.called, 'Comments should be added' eq_(2, self.pr.create_review_comment.call_count) self.issue.remove_label.assert_called_with(label) assert_review_comments_created( self.pr.create_review_comment.call_args_list, errors, sha)
class TestSwiftlint(TestCase): def setUp(self): self.problems = Problems() options = {} self.tool = Swiftlint(self.problems, options, root_dir) def test_match_file(self): self.assertFalse(self.tool.match_file('test.php')) self.assertFalse(self.tool.match_file('dir/name/test.py')) self.assertFalse(self.tool.match_file('test.py')) self.assertTrue(self.tool.match_file('test.swift')) self.assertTrue(self.tool.match_file('dir/name/test.swift')) @requires_image('swiftlint') def test_check_dependencies(self): self.assertTrue(self.tool.check_dependencies()) @requires_image('swiftlint') def test_process_files_pass(self): self.tool.process_files(FILE_WITH_NO_ERRORS) self.assertEqual([], self.problems.all(FILE_WITH_NO_ERRORS)) @requires_image('swiftlint') def test_process_files_fail(self): self.tool.process_files([FILE_WITH_ERRORS]) problems = self.problems.all(FILE_WITH_ERRORS) self.assertEqual(1, len(problems)) msg = ("Colons should be next to the identifier when specifying " "a type and next to the key in dictionary literals.") expected = [Comment(FILE_WITH_ERRORS, 2, 2, msg)] self.assertEqual(expected, problems)
class TestSwiftlint(TestCase): needs_swiftlint = skipIf(swiftlint_missing, 'Needs swiftlint to run') def setUp(self): self.problems = Problems() options = {} self.tool = Swiftlint(self.problems, options) def test_match_file(self): self.assertFalse(self.tool.match_file('test.php')) self.assertFalse(self.tool.match_file('dir/name/test.py')) self.assertFalse(self.tool.match_file('test.py')) self.assertTrue(self.tool.match_file('test.swift')) self.assertTrue(self.tool.match_file('dir/name/test.swift')) @needs_swiftlint def test_check_dependencies(self): self.assertTrue(self.tool.check_dependencies()) @needs_swiftlint def test_process_files_pass(self): self.tool.process_files(FILE_WITH_NO_ERRORS) eq_([], self.problems.all(FILE_WITH_NO_ERRORS)) @needs_swiftlint def test_process_files_fail(self): self.tool.process_files([FILE_WITH_ERRORS]) problems = self.problems.all(FILE_WITH_ERRORS) eq_(1, len(problems)) msg = ("Colons should be next to the identifier when specifying " "a type and next to the key in dictionary literals.") expected = [Comment(FILE_WITH_ERRORS, 2, 2, msg)] eq_(expected, problems)
class TestFoodcritic(TestCase): needs_critic = skipIf(critic_missing, 'Missing foodcritic, cannot run') fixtures = [ 'tests/fixtures/foodcritic/noerrors', 'tests/fixtures/foodcritic/errors', ] def setUp(self): self.problems = Problems() @needs_critic def test_process_cookbook_pass(self): self.tool = Foodcritic(self.problems, None, self.fixtures[0]) self.tool.process_files(None) eq_([], self.problems.all()) @needs_critic def test_process_cookbook_fail(self): self.tool = Foodcritic(self.problems, None, self.fixtures[1]) self.tool.process_files(None) problems = self.problems.all() eq_(5, len(problems)) expected = Comment( 'tests/fixtures/foodcritic/errors/recipes/apache2.rb', 1, 1, 'FC007: Ensure recipe dependencies are reflected in cookbook ' 'metadata') eq_(expected, problems[1])
class TestEslint(TestCase): needs_eslint = skipIf(eslint_missing, 'Needs eslint to run') fixtures = [ 'tests/fixtures/eslint/no_errors.js', 'tests/fixtures/eslint/has_errors.js' ] def setUp(self): self.problems = Problems() self.tool = Eslint(self.problems) def test_match_file(self): self.assertFalse(self.tool.match_file('test.php')) self.assertFalse(self.tool.match_file('dir/name/test.py')) self.assertFalse(self.tool.match_file('test.py')) self.assertTrue(self.tool.match_file('test.js')) self.assertTrue(self.tool.match_file('dir/name/test.js')) @needs_eslint def test_check_dependencies(self): self.assertTrue(self.tool.check_dependencies()) @needs_eslint def test_process_files_pass(self): self.tool.process_files([self.fixtures[0]]) eq_([], self.problems.all(self.fixtures[0])) @needs_eslint def test_process_files_fail(self): self.tool.process_files([self.fixtures[1]]) problems = self.problems.all(self.fixtures[1]) eq_(2, len(problems)) fname = self.fixtures[1] msg = ("foo is defined but never used (no-unused-vars)\n" '"bar" is not defined. (no-undef)\n' 'Missing semicolon. (semi)') expected = Comment(fname, 2, 2, msg) eq_(expected, problems[0]) msg = ('Unexpected alert. (no-alert)\n' '"alert" is not defined. (no-undef)') expected = Comment(fname, 4, 4, msg) eq_(expected, problems[1]) @needs_eslint def test_process_files_with_config(self): config = { 'config': 'tests/fixtures/eslint/config.json' } tool = Eslint(self.problems, config) tool.process_files([self.fixtures[1]]) problems = self.problems.all(self.fixtures[1]) eq_(2, len(problems), 'Config file should lower error count.')
class TestPep8(TestCase): fixtures = [ 'tests/fixtures/pep8/no_errors.py', 'tests/fixtures/pep8/has_errors.py', ] def setUp(self): self.problems = Problems() self.tool = Pep8(self.problems) def test_match_file(self): self.assertFalse(self.tool.match_file('test.php')) self.assertFalse(self.tool.match_file('test.js')) self.assertFalse(self.tool.match_file('dir/name/test.js')) self.assertTrue(self.tool.match_file('test.py')) self.assertTrue(self.tool.match_file('dir/name/test.py')) def test_process_files__one_file_pass(self): self.tool.process_files([self.fixtures[0]]) eq_([], self.problems.all(self.fixtures[0])) def test_process_files__one_file_fail(self): self.tool.process_files([self.fixtures[1]]) problems = self.problems.all(self.fixtures[1]) eq_(6, len(problems)) fname = self.fixtures[1] expected = Comment(fname, 2, 2, 'E401 multiple imports on one line') eq_(expected, problems[0]) expected = Comment(fname, 11, 11, "W603 '<>' is deprecated, use '!='") eq_(expected, problems[5]) def test_process_files_two_files(self): self.tool.process_files(self.fixtures) eq_([], self.problems.all(self.fixtures[0])) problems = self.problems.all(self.fixtures[1]) eq_(6, len(problems)) expected = Comment(self.fixtures[1], 2, 2, 'E401 multiple imports on one line') eq_(expected, problems[0]) expected = Comment(self.fixtures[1], 11, 11, "W603 '<>' is deprecated, use '!='") eq_(expected, problems[5]) def test_config_options_and_process_file(self): options = { 'ignore': 'E2,W603' } self.tool = Pep8(self.problems, options) self.tool.process_files([self.fixtures[1]]) problems = self.problems.all(self.fixtures[1]) eq_(4, len(problems)) for p in problems: self.assertFalse('E2' in p.body) self.assertFalse('W603' in p.body)
class TestYamllint(TestCase): fixtures = [ 'tests/fixtures/yamllint/no_errors.yaml', 'tests/fixtures/yamllint/has_errors.yaml', ] def setUp(self): self.problems = Problems() self.tool = Yamllint(self.problems) def test_match_file(self): self.assertFalse(self.tool.match_file('test.php')) self.assertFalse(self.tool.match_file('test.js')) self.assertFalse(self.tool.match_file('dir/name/test.js')) self.assertTrue(self.tool.match_file('test.yaml')) self.assertTrue(self.tool.match_file('dir/name/test.yaml')) self.assertTrue(self.tool.match_file('test.yml')) self.assertTrue(self.tool.match_file('dir/name/test.yml')) def test_process_files__one_file_pass(self): self.tool.process_files([self.fixtures[0]]) eq_([], self.problems.all(self.fixtures[0])) def test_process_files__one_file_fail(self): self.tool.process_files([self.fixtures[1]]) problems = self.problems.all(self.fixtures[1]) eq_(5, len(problems)) fname = self.fixtures[1] msg = "[warning] missing starting space in comment (comments)" expected = Comment(fname, 1, 1, msg) eq_(expected, problems[0]) msg = ("[warning] missing document start \"---\" (document-start)\n" "[error] too many spaces inside braces (braces)") expected = Comment(fname, 2, 2, msg) eq_(expected, problems[1]) def test_process_files_two_files(self): self.tool.process_files(self.fixtures) eq_([], self.problems.all(self.fixtures[0])) problems = self.problems.all(self.fixtures[1]) eq_(5, len(problems)) fname = self.fixtures[1] msg = "[warning] missing starting space in comment (comments)" expected = Comment(fname, 1, 1, msg) eq_(expected, problems[0]) msg = ("[warning] missing document start \"---\" (document-start)\n" "[error] too many spaces inside braces (braces)") expected = Comment(fname, 2, 2, msg) eq_(expected, problems[1])
class TestJcs(TestCase): needs_jscs = skipIf(jscs_missing, "Needs jscs to run") fixtures = ["tests/fixtures/jscs/no_errors.js", "tests/fixtures/jscs/has_errors.js"] def setUp(self): self.problems = Problems() self.tool = Jscs(self.problems) def test_match_file(self): self.assertFalse(self.tool.match_file("test.php")) self.assertFalse(self.tool.match_file("dir/name/test.py")) self.assertFalse(self.tool.match_file("test.py")) self.assertTrue(self.tool.match_file("test.js")) self.assertTrue(self.tool.match_file("dir/name/test.js")) @needs_jscs def test_check_dependencies(self): self.assertTrue(self.tool.check_dependencies()) @needs_jscs def test_process_files__one_file_pass(self): self.tool.process_files([self.fixtures[0]]) eq_([], self.problems.all(self.fixtures[0])) @needs_jscs def test_process_files__one_file_fail(self): self.tool.process_files([self.fixtures[1]]) problems = self.problems.all(self.fixtures[1]) eq_(9, len(problems)) fname = self.fixtures[1] expected = Comment(fname, 1, 1, "Illegal space before opening round brace") eq_(expected, problems[0]) expected = Comment(fname, 7, 7, "Expected indentation of 4 characters") eq_(expected, problems[7]) @needs_jscs def test_process_files_two_files(self): self.tool.process_files(self.fixtures) eq_([], self.problems.all(self.fixtures[0])) problems = self.problems.all(self.fixtures[1]) eq_(9, len(problems)) @needs_jscs def test_process_files_with_config(self): config = {"preset": "airbnb"} tool = Jscs(self.problems, config) tool.process_files([self.fixtures[0]]) problems = self.problems.all(self.fixtures[0]) eq_(1, len(problems))
class TestRubocop(TestCase): needs_rubocop = skipIf(rubocop_missing, 'Missing rubocop, cannot run') fixtures = [ 'tests/fixtures/rubocop/no_errors.rb', 'tests/fixtures/rubocop/has_errors.rb', ] def setUp(self): self.problems = Problems() self.tool = Rubocop(self.problems) def test_match_file(self): self.assertFalse(self.tool.match_file('test.py')) self.assertFalse(self.tool.match_file('dir/name/test.py')) self.assertTrue(self.tool.match_file('test.rb')) self.assertTrue(self.tool.match_file('dir/name/test.rb')) @needs_rubocop def test_process_files__one_file_pass(self): self.tool.process_files([self.fixtures[0]]) eq_([], self.problems.all(self.fixtures[0])) @needs_rubocop def test_process_files__one_file_fail(self): linty_filename = abspath(self.fixtures[1]) self.tool.process_files([linty_filename]) problems = self.problems.all(linty_filename) expected = Comment(linty_filename, 4, 4, 'C: Trailing whitespace detected.') eq_(expected, problems[5]) @needs_rubocop def test_process_files_two_files(self): self.tool.process_files(self.fixtures) linty_filename = abspath(self.fixtures[1]) eq_(6, len(self.problems.all(linty_filename))) freshly_laundered_filename = abspath(self.fixtures[0]) eq_([], self.problems.all(freshly_laundered_filename)) @needs_rubocop def test_process_files_one_file_fail_display_cop_names(self): options = { 'display_cop_names': 'True', } self.tool = Rubocop(self.problems, options) linty_filename = abspath(self.fixtures[1]) self.tool.process_files([linty_filename]) problems = self.problems.all(linty_filename) expected = Comment(linty_filename, 3, 3, 'C: Metrics/LineLength: Line is too long. [82/80]') eq_(expected, problems[4])
class Processor(object): _client = None _number = None _head = None _target_path = None _changes = None _problems = None _review = None _config = None def __init__(self, client, number, head, target_path, config=None): self._client = client self._number = number self._head = head self._target_path = target_path self._problems = Problems(target_path) self._review = Review(client, number) if config is None: config = {} self._config = config def load_changes(self): log.info('Loading pull request patches from github.') files = self._client.pull_requests.list_files(self._number) pull_request_patches = files.all() self._changes = DiffCollection(pull_request_patches) self._problems.set_changes(self._changes) def run_tools(self, review_config): if self._changes is None: raise RuntimeError('No loaded changes, cannot run tools. ' 'Try calling load_changes first.') files_to_check = self._changes.get_files( append_base=self._target_path, ignore_patterns=review_config.ignore_patterns()) commits_to_check = self.get_commits(self._number) tools.run( review_config, self._problems, files_to_check, commits_to_check, self._target_path) def publish(self): self._problems.limit_to_changes() self._review.publish( self._problems, self._head, self._config.get('SUMMARY_THRESHOLD')) def get_commits(self, number): return self._client.pull_requests.list_commits(number).all()
def test_run_timeout_error(self, mock_docker): mock_docker.side_effect = TimeoutError("Read timed out. (read timeout=300)") config = build_review_config(simple_ini) problems = Problems() files = ['./tests/fixtures/pep8/has_errors.py'] tool_list = tools.factory(config, problems, root_dir) tools.run(tool_list, files, []) errors = problems.all() assert 1 == len(errors) assert 'timed out during' in errors[0].body assert 'run pep8 linter' in errors[0].body
def test_add__with_diff_containing_block_offset(self): res = Resource.loads(self.block_offset) changes = DiffCollection(res) problems = Problems(changes=changes) line_num = 32 problems.add('somefile.py', line_num, 'Not good') eq_(1, len(problems)) result = problems.all('somefile.py') eq_(changes.line_position('somefile.py', line_num), result[0].position, 'Offset should be transformed to match value in changes')
class TestPy3k(TestCase): needs_py2 = skipIf(not_python2, 'Cannot run in python3') class fixtures: no_errors = 'tests/fixtures/py3k/no_errors.py' has_errors = 'tests/fixtures/py3k/has_errors.py' def setUp(self): self.problems = Problems() self.tool = Py3k(self.problems) def test_match_file(self): self.assertFalse(self.tool.match_file('test.php')) self.assertFalse(self.tool.match_file('test.js')) self.assertFalse(self.tool.match_file('dir/name/test.js')) self.assertTrue(self.tool.match_file('test.py')) self.assertTrue(self.tool.match_file('dir/name/test.py')) def test_process_files__one_file_pass(self): self.tool.process_files([self.fixtures.no_errors]) eq_([], self.problems.all(self.fixtures.no_errors)) @needs_py2 def test_process_files__one_file_fail(self): self.tool.process_files([self.fixtures.has_errors]) problems = self.problems.all(self.fixtures.has_errors) eq_(2, len(problems)) fname = self.fixtures.has_errors eq_([ Comment(fname, 6, 6, 'E1601 print statement used'), Comment(fname, 11, 11, 'W1638 range built-in referenced when not iterating') ], problems) @needs_py2 def test_process_files_two_files(self): self.tool.process_files([self.fixtures.no_errors, self.fixtures.has_errors]) eq_([], self.problems.all(self.fixtures.no_errors)) problems = self.problems.all(self.fixtures.has_errors) eq_(2, len(problems)) fname = self.fixtures.has_errors eq_([ Comment(fname, 6, 6, 'E1601 print statement used'), Comment(fname, 11, 11, 'W1638 range built-in referenced when not iterating') ], problems)
class Processor(object): _repository = None _pull_request = None _target_path = None _changes = None _problems = None _review = None _config = None def __init__(self, repository, pull_request, target_path, config=None): config = config if config else {} self._config = config self._repository = repository self._pull_request = pull_request self._target_path = target_path self._problems = Problems(target_path) self._review = Review(repository, pull_request, config) def load_changes(self): log.info('Loading pull request patches from github.') files = self._pull_request.files() self._changes = DiffCollection(files) self._problems.set_changes(self._changes) def run_tools(self, review_config): if self._changes is None: raise RuntimeError('No loaded changes, cannot run tools. ' 'Try calling load_changes first.') files_to_check = self._changes.get_files( append_base=self._target_path, ignore_patterns=review_config.ignore_patterns()) commits_to_check = self._pull_request.commits() log.debug("_problems before tools: %s" % len(self._problems)) self._problems = tools.run( review_config, self._problems, files_to_check, commits_to_check, self._target_path) log.debug("_problems after tools: %s" % len(self._problems)) def publish(self): self._problems.limit_to_changes() self._review.publish( self._problems, self._pull_request.head, self._config.get('SUMMARY_THRESHOLD'))
class TestRubocop(TestCase): needs_rubocop = skipIf(rubocop_missing, "Missing rubocop, cannot run") fixtures = ["tests/fixtures/rubocop/no_errors.rb", "tests/fixtures/rubocop/has_errors.rb"] def setUp(self): self.problems = Problems() self.tool = Rubocop(self.problems) def test_match_file(self): self.assertFalse(self.tool.match_file("test.py")) self.assertFalse(self.tool.match_file("dir/name/test.py")) self.assertTrue(self.tool.match_file("test.rb")) self.assertTrue(self.tool.match_file("dir/name/test.rb")) @needs_rubocop def test_process_files__one_file_pass(self): self.tool.process_files([self.fixtures[0]]) eq_([], self.problems.all(self.fixtures[0])) @needs_rubocop def test_process_files__one_file_fail(self): linty_filename = abspath(self.fixtures[1]) self.tool.process_files([linty_filename]) problems = self.problems.all(linty_filename) expected = Comment(linty_filename, 4, 4, "C: Trailing whitespace detected.") eq_(expected, problems[1]) @needs_rubocop def test_process_files_two_files(self): self.tool.process_files(self.fixtures) linty_filename = abspath(self.fixtures[1]) eq_(2, len(self.problems.all(linty_filename))) freshly_laundered_filename = abspath(self.fixtures[0]) eq_([], self.problems.all(freshly_laundered_filename)) @needs_rubocop def test_process_files_one_file_fail_display_cop_names(self): options = {"display_cop_names": "True"} self.tool = Rubocop(self.problems, options) linty_filename = abspath(self.fixtures[1]) self.tool.process_files([linty_filename]) problems = self.problems.all(linty_filename) expected = Comment(linty_filename, 4, 4, "C: Style/TrailingWhitespace: Trailing whitespace detected.") eq_(expected, problems[1])
def test_publish_pull_review__only_issue_comment(self): problems = Problems() problems.add(IssueComment('Very bad')) sha = 'abc123' review = Review(self.repo, self.pr, self.config) review.publish_pull_review(problems, sha) assert self.pr.create_review.called assert_review( self, self.pr.create_review.call_args, [], sha, body='Very bad')
class TestCommitCheck(TestCase): fixture = load_fixture('commits.json') def setUp(self): self.fixture_data = create_commits(self.fixture) self.problems = Problems() self.tool = Commitcheck(self.problems) def test_execute_commits__no_pattern(self): self.tool.options['pattern'] = '' self.tool.execute_commits(self.fixture_data) eq_(0, len(self.problems), 'Empty pattern does not find issues') def test_execute_commits__broken_regex(self): self.tool.options['pattern'] = '(.*' self.tool.execute_commits(self.fixture_data) eq_(0, len(self.problems), 'Empty pattern does not find issues') def test_execute_commits__match(self): self.tool.options['pattern'] = '\w+' self.tool.execute_commits(self.fixture_data) eq_(0, len(self.problems), 'Commits that do match are ok') self.tool.options['pattern'] = 'bugs?' self.tool.execute_commits(self.fixture_data) eq_(0, len(self.problems), 'Commits that do match are ok') def test_execute_commits__no_match(self): self.tool.options['pattern'] = '\d+' self.tool.execute_commits(self.fixture_data) eq_(1, len(self.problems), 'Commits that do not match cause errors') msg = ( 'The following commits had issues. ' 'The pattern \d+ was not found in:\n' '* 6dcb09b5b57875f334f61aebed695e2e4193db5e\n') expected = IssueComment(msg) eq_(expected, self.problems.all()[0]) def test_execute_commits__custom_message(self): self.tool.options['pattern'] = '\d+' self.tool.options['message'] = 'You are bad.' self.tool.execute_commits(self.fixture_data) eq_(1, len(self.problems), 'Commits that do not match cause errors') msg = ('You are bad. The pattern \d+ was not found in:\n' '* 6dcb09b5b57875f334f61aebed695e2e4193db5e\n') expected = IssueComment(msg) eq_(expected, self.problems.all()[0])
class TestCredo(TestCase): fixtures = [ 'tests/fixtures/credo/no_errors.ex', 'tests/fixtures/credo/has_errors.ex', ] def setUp(self): self.problems = Problems() self.tool = Credo(self.problems, {}, root_dir) def test_match_file(self): self.assertFalse(self.tool.match_file('test.php')) self.assertFalse(self.tool.match_file('test.js')) self.assertFalse(self.tool.match_file('dir/name/test.js')) self.assertTrue(self.tool.match_file('test.ex')) self.assertTrue(self.tool.match_file('test.exs')) self.assertTrue(self.tool.match_file('dir/name/test.ex')) self.assertTrue(self.tool.match_file('dir/name/test.exs')) def test_create_command_types(self): self.tool.options = { 'all': True, 'all-priorities': 'yes', 'strict': 1, } command = self.tool.create_command() self.assertTrue('--all' in command) self.assertTrue('--all-priorities' in command) self.assertTrue('--strict' in command) @requires_image('credo') def test_process_files__one_file_pass(self): self.tool.process_files([self.fixtures[0]]) self.assertEqual([], self.problems.all(self.fixtures[0])) @requires_image('credo') def test_process_files__one_file_fail(self): self.tool.process_files([self.fixtures[1]]) problems = self.problems.all(self.fixtures[1]) self.assertEqual(2, len(problems)) fname = self.fixtures[1] expected = Comment(fname, 3, 3, 'Pipe chain should start with a raw value.') self.assertEqual(expected, problems[0]) expected = Comment(fname, 1, 1, 'Modules should have a @moduledoc tag.') self.assertEqual(expected, problems[1])
class TestCommitCheck(TestCase): fixture = load_fixture("commits.json") def setUp(self): self.fixture_data = Resource.loads(self.fixture) self.problems = Problems() self.tool = Commitcheck(self.problems) def test_execute_commits__no_pattern(self): self.tool.options["pattern"] = "" self.tool.execute_commits(self.fixture_data) eq_(0, len(self.problems), "Empty pattern does not find issues") def test_execute_commits__broken_regex(self): self.tool.options["pattern"] = "(.*" self.tool.execute_commits(self.fixture_data) eq_(0, len(self.problems), "Empty pattern does not find issues") def test_execute_commits__match(self): self.tool.options["pattern"] = "\w+" self.tool.execute_commits(self.fixture_data) eq_(0, len(self.problems), "Commits that do match are ok") self.tool.options["pattern"] = "bugs?" self.tool.execute_commits(self.fixture_data) eq_(0, len(self.problems), "Commits that do match are ok") def test_execute_commits__no_match(self): self.tool.options["pattern"] = "\d+" self.tool.execute_commits(self.fixture_data) eq_(1, len(self.problems), "Commits that do not match cause errors") msg = ( "The following commits had issues. " "The pattern \d+ was not found in:\n" "* 6dcb09b5b57875f334f61aebed695e2e4193db5e\n" ) expected = IssueComment(msg) eq_(expected, self.problems.all()[0]) def test_execute_commits__custom_message(self): self.tool.options["pattern"] = "\d+" self.tool.options["message"] = "You are bad." self.tool.execute_commits(self.fixture_data) eq_(1, len(self.problems), "Commits that do not match cause errors") msg = "You are bad. The pattern \d+ was not found in:\n" "* 6dcb09b5b57875f334f61aebed695e2e4193db5e\n" expected = IssueComment(msg) eq_(expected, self.problems.all()[0])
def __init__(self, repository, pull_request, target_path, config): self._config = config self._repository = repository self._pull_request = pull_request self._target_path = target_path self.problems = Problems() self._review = Review(repository, pull_request, config)
def __init__(self, repository, pull_request, target_path, config=None): config = config if config else {} self._config = config self._repository = repository self._pull_request = pull_request self._target_path = target_path self._problems = Problems(target_path) self._review = Review(repository, pull_request, config)
def test_publish_problems_add_ok_label(self): gh = Mock() problems = Problems() filename_1 = 'Console/Command/Task/AssetBuildTask.php' errors = ( (filename_1, 117, 'Something bad'), (filename_1, 119, 'Something bad'), ) problems.add_many(errors) sha = 'abc123' review = Review(gh, 3) label = config.get('OK_LABEL', 'No lint errors') with add_ok_label(gh, 3, label): sha = 'abc123' review.publish_problems(problems, sha) assert gh.issues.labels.remove_from_issue.called assert gh.pull_requests.comments.create.called eq_(2, gh.pull_requests.comments.create.call_count) assert_add_to_issue(gh) calls = gh.issues.labels.remove_from_issue.call_args_list expected = call(3, label) eq_(calls, [expected]) calls = gh.pull_requests.comments.create.call_args_list expected = call(3, { 'commit_id': sha, 'path': errors[0][0], 'position': errors[0][1], 'body': errors[0][2] }) eq_(calls[0], expected) expected = call(3, { 'commit_id': sha, 'path': errors[1][0], 'position': errors[1][1], 'body': errors[1][2] }) eq_(calls[1], expected)
def setUp(self): self.problems = Problems() self.tool = Jscs(self.problems, {}, root_dir)
def test_run(): config = ReviewConfig(simple_ini) problems = Problems() files = ['./tests/fixtures/pep8/has_errors.py'] tools.run(config, problems, files, [], '') eq_(6, len(problems))
def setUp(self): self.problems = Problems() self.tool = Yamllint(self.problems, {}, root_dir)
class TestFlake8(TestCase): fixtures = [ 'tests/fixtures/pep8/no_errors.py', 'tests/fixtures/pep8/has_errors.py', ] def setUp(self): self.problems = Problems() self.tool = Flake8(self.problems, options={'config': ''}) def test_match_file(self): self.assertFalse(self.tool.match_file('test.php')) self.assertFalse(self.tool.match_file('test.js')) self.assertFalse(self.tool.match_file('dir/name/test.js')) self.assertTrue(self.tool.match_file('test.py')) self.assertTrue(self.tool.match_file('dir/name/test.py')) def test_process_files__one_file_pass(self): self.tool.process_files([self.fixtures[0]]) eq_([], self.problems.all(self.fixtures[0])) def test_process_files__one_file_fail(self): self.tool.process_files([self.fixtures[1]]) problems = self.problems.all(self.fixtures[1]) assert len(problems) >= 6 eq_(2, problems[0].line) eq_(2, problems[0].position) assert_in('multiple imports on one line', problems[0].body) def test_process_files_two_files(self): self.tool.process_files(self.fixtures) eq_([], self.problems.all(self.fixtures[0])) problems = self.problems.all(self.fixtures[1]) assert len(problems) >= 6 eq_(2, problems[0].line) eq_(2, problems[0].position) assert_in('multiple imports on one line', problems[0].body) def test_config_options_and_process_file(self): options = { 'ignore': 'F4,W603', } self.tool = Flake8(self.problems, options) self.tool.process_files([self.fixtures[1]]) problems = self.problems.all(self.fixtures[1]) assert len(problems) >= 5 for p in problems: self.assertFalse('F4' in p.body) self.assertFalse('W603' in p.body) def test_make_command__config(self): options = { 'ignore': 'F4,W603', 'max-line-length': 120, 'max-complexity': 10 } tool = Flake8(self.problems, options) out = tool.make_command([self.fixtures[1]]) expected = [ 'flake8', '--isolated', '--ignore', 'F4,W603', '--max-complexity', 10, '--max-line-length', 120, self.fixtures[1] ] eq_(set(expected), set(out))
def test_tool_apply_base__no_base(): problems = Problems() tool = tools.Tool(problems, {}) result = tool.apply_base('comments_current.json') eq_(result, 'comments_current.json')
def test_filter_existing__removes_duplicates(self): fixture_data = load_fixture('comments_current.json') self.pr.review_comments.return_value = [ GhIssueComment(f) for f in json.loads(fixture_data) ] problems = Problems() review = Review(self.repo, self.pr) filename_1 = "Routing/Filter/AssetCompressor.php" filename_2 = "View/Helper/AssetCompressHelper.php" problems.add(filename_1, 87, 'A pithy remark') problems.add(filename_1, 87, 'Something different') problems.add(filename_2, 88, 'I <3 it') problems.add(filename_2, 89, 'Not such a good comment') review.load_comments() review.remove_existing(problems) res = problems.all(filename_1) eq_(1, len(res)) expected = Comment(filename_1, 87, 87, 'A pithy remark\nSomething different') eq_(res[0], expected) res = problems.all(filename_2) eq_(1, len(res)) expected = Comment(filename_2, 88, 88, 'I <3 it') eq_(res[0], expected)
class TestPep8(TestCase): fixtures = [ 'tests/fixtures/pep8/no_errors.py', 'tests/fixtures/pep8/has_errors.py', ] def setUp(self): self.problems = Problems() self.tool = Pep8(self.problems) def test_match_file(self): self.assertFalse(self.tool.match_file('test.php')) self.assertFalse(self.tool.match_file('test.js')) self.assertFalse(self.tool.match_file('dir/name/test.js')) self.assertTrue(self.tool.match_file('test.py')) self.assertTrue(self.tool.match_file('dir/name/test.py')) def test_process_files__one_file_pass(self): self.tool.process_files([self.fixtures[0]]) eq_([], self.problems.all(self.fixtures[0])) def test_process_files__one_file_fail(self): self.tool.process_files([self.fixtures[1]]) problems = self.problems.all(self.fixtures[1]) eq_(6, len(problems)) fname = self.fixtures[1] expected = Comment(fname, 2, 2, 'E401 multiple imports on one line') eq_(expected, problems[0]) expected = Comment(fname, 11, 11, "W603 '<>' is deprecated, use '!='") eq_(expected, problems[5]) def test_process_files_two_files(self): self.tool.process_files(self.fixtures) eq_([], self.problems.all(self.fixtures[0])) problems = self.problems.all(self.fixtures[1]) eq_(6, len(problems)) expected = Comment(self.fixtures[1], 2, 2, 'E401 multiple imports on one line') eq_(expected, problems[0]) expected = Comment(self.fixtures[1], 11, 11, "W603 '<>' is deprecated, use '!='") eq_(expected, problems[5]) def test_process_files__ignore(self): options = { 'ignore': 'E2,W603' } self.tool = Pep8(self.problems, options) self.tool.process_files([self.fixtures[1]]) problems = self.problems.all(self.fixtures[1]) eq_(4, len(problems)) for p in problems: assert_not_in('E2', p.body) assert_not_in('W603', p.body) def test_process_files__line_length(self): options = { 'max-line-length': '10' } self.tool = Pep8(self.problems, options) self.tool.process_files([self.fixtures[1]]) problems = self.problems.all(self.fixtures[1]) eq_(10, len(problems)) expected = Comment(self.fixtures[1], 1, 1, 'E501 line too long (23 > 10 characters)') eq_(expected, problems[0]) def test_process_files__select(self): options = { 'select': 'W603' } self.tool = Pep8(self.problems, options) self.tool.process_files([self.fixtures[1]]) problems = self.problems.all(self.fixtures[1]) eq_(1, len(problems)) for p in problems: assert_in('W603', p.body)
def setUp(self): self.problems = Problems() self.tool = Stylelint(self.problems, base_path=root_dir)
def setUp(self): self.problems = Problems() self.tool = Rubocop(self.problems)
def setUp(self): self.problems = Problems() self.tool = Phpcs(self.problems, base_path=root_dir)
class TestStylelint(TestCase): fixtures = [ 'tests/fixtures/stylelint/no_errors.scss', 'tests/fixtures/stylelint/has_errors.scss', 'tests/fixtures/stylelint/has_more_errors.scss', ] def setUp(self): self.problems = Problems() self.tool = Stylelint(self.problems, base_path=root_dir) def test_version(self): assert self.tool.version != '' def test_match_file(self): self.assertFalse(self.tool.match_file('test.php')) self.assertFalse(self.tool.match_file('dir/name/test.py')) self.assertFalse(self.tool.match_file('test.py')) self.assertTrue(self.tool.match_file('test.sass')) self.assertTrue(self.tool.match_file('dir/name/test.sass')) self.assertTrue(self.tool.match_file('dir/name/test.scss')) self.assertTrue(self.tool.match_file('dir/name/test.less')) self.assertTrue(self.tool.match_file('dir/name/test.css')) @requires_image('nodejs') def test_check_dependencies(self): self.assertTrue(self.tool.check_dependencies()) @requires_image('nodejs') def test_process_files__one_file_pass(self): self.tool.process_files([self.fixtures[0]]) self.assertEqual([], self.problems.all(self.fixtures[0])) @requires_image('nodejs') def test_process_files__one_file_fail(self): self.tool.process_files([self.fixtures[1]]) problems = self.problems.all(self.fixtures[1]) self.assertEqual(2, len(problems)) fname = self.fixtures[1] error = ('Unexpected unknown at-rule "@include" ' '(at-rule-no-unknown) [error]') expected = Comment(fname, 2, 2, error) self.assertEqual(expected, problems[0]) @requires_image('nodejs') def test_process_files__multiple_files(self): self.tool.process_files(self.fixtures) self.assertEqual([], self.problems.all(self.fixtures[0])) problems = self.problems.all(self.fixtures[1]) self.assertEqual(2, len(problems)) problems = self.problems.all(self.fixtures[2]) self.assertEqual(2, len(problems)) @requires_image('nodejs') def test_process_files_with_config(self): config = {'config': 'tests/fixtures/stylelint/stylelintrc.json'} tool = Stylelint(self.problems, config, root_dir) tool.process_files([self.fixtures[1]]) problems = self.problems.all() self.assertEqual(6, len(problems), 'Config file should change error count') @requires_image('nodejs') def test_process_files_with_invalid_config(self): config = {'config': 'tests/fixtures/stylelint/badconfig'} tool = Stylelint(self.problems, config, root_dir) tool.process_files([self.fixtures[1]]) problems = self.problems.all() self.assertEqual(1, len(problems), 'Should capture missing config error') self.assertIn('Your configuration file', problems[0].body) self.assertIn('ENOENT', problems[0].body) @requires_image('nodejs') def test_process_files_with_bad_json(self): config = {'config': 'tests/fixtures/stylelint/invalid.json'} tool = Stylelint(self.problems, config, root_dir) tool.process_files([self.fixtures[1]]) problems = self.problems.all() self.assertEqual(1, len(problems), 'Should capture missing config error') self.assertIn('Your configuration file', problems[0].body) self.assertIn('JSONError', problems[0].body) def test_has_fixer__not_enabled(self): tool = Stylelint(self.problems, {}) self.assertEqual(False, tool.has_fixer()) def test_has_fixer__enabled(self): tool = Stylelint(self.problems, {'fixer': True}, root_dir) self.assertEqual(True, tool.has_fixer()) @requires_image('nodejs') def test_execute_fixer(self): fixture = self.fixtures[1] tool = Stylelint(self.problems, { 'config': 'tests/fixtures/stylelint/stylelintrc.json', 'fixer': True, }, root_dir) original = read_file(fixture) tool.execute_fixer([fixture]) updated = read_and_restore_file(fixture, original) assert original != updated, 'File content should change.'
class TestRemarklint(TestCase): fixtures = [ 'tests/fixtures/remarklint/no_errors.md', 'tests/fixtures/remarklint/has_errors.md', ] def setUp(self): self.problems = Problems() self.tool = Remarklint(self.problems, {}, root_dir) def test_match_file(self): self.assertFalse(self.tool.match_file('test.txt')) self.assertFalse(self.tool.match_file('test.rst')) self.assertFalse(self.tool.match_file('dir/name/test.rst')) self.assertTrue(self.tool.match_file('test.md')) self.assertTrue(self.tool.match_file('dir/name/test.md')) @requires_image('nodejs') def test_process_files__one_file_pass(self): self.tool.process_files([self.fixtures[0]]) eq_([], self.problems.all(self.fixtures[0])) @requires_image('nodejs') def test_process_files__one_file_file(self): self.tool.process_files([self.fixtures[1]]) problems = self.problems.all() eq_(2, len(problems)) assert_in('Incorrect list-item', problems[0].body) @requires_image('nodejs') def test_process_files__missing_plugin(self): tool = Remarklint(self.problems, {'fixer': True}, root_dir) config = 'tests/fixtures/remarklint/.remarkrc' original = read_file(config) with open(config, 'w') as f: f.write('{"plugins": ["unknown-preset"]}') tool.process_files([self.fixtures[1]]) with open(config, 'w') as f: f.write(original) problems = self.problems.all() eq_(1, len(problems), 'Should have an error') assert_in('unknown-preset', problems[0].body) def test_process_files__config(self): pass def test_has_fixer__not_enabled(self): tool = Remarklint(self.problems) eq_(False, tool.has_fixer()) def test_has_fixer__enabled(self): tool = Remarklint(self.problems, {'fixer': True}) eq_(True, tool.has_fixer()) @requires_image('nodejs') def test_execute_fixer(self): tool = Remarklint(self.problems, {'fixer': True}, root_dir) original = read_file(self.fixtures[1]) tool.execute_fixer(self.fixtures) tool.process_files(self.fixtures) updated = read_and_restore_file(self.fixtures[1], original) assert original != updated, 'File content should change.' eq_(1, len(self.problems.all()), 'Fewer errors should be recorded')
def setUp(self): self.problems = Problems() self.tool = Remarklint(self.problems, {}, root_dir)
class Processor(object): _repository = None _pull_request = None _target_path = None _changes = None _review = None _config = None problems = None def __init__(self, repository, pull_request, target_path, config): self._config = config self._repository = repository self._pull_request = pull_request self._target_path = target_path self.problems = Problems() self._review = Review(repository, pull_request, config) def load_changes(self): log.debug('Loading pull request patches from github.') files = self._pull_request.files() self._changes = DiffCollection(files) self.problems.set_changes(self._changes) def run_tools(self): if self._changes is None: raise RuntimeError('No loaded changes, cannot run tools. ' 'Try calling load_changes first.') config = self._config files_to_check = self._changes.get_files( ignore_patterns=config.ignore_patterns()) commits_to_check = self._pull_request.commits() tool_list = tools.factory(config, self.problems, self._target_path) if config.fixers_enabled(): self.apply_fixers(tool_list, files_to_check) tools.run(tool_list, files_to_check, commits_to_check) def apply_fixers(self, tool_list, files_to_check): try: fixer_context = fixers.create_context( self._config, self._target_path, self._repository, self._pull_request, ) fixer_diff = fixers.run_fixers(tool_list, self._target_path, files_to_check) fixers.apply_fixer_diff(self._changes, fixer_diff, fixer_context) except (ConfigurationError, WorkflowError) as e: log.info('Fixer application failed. Got %s', e) message = u'Unable to apply fixers. {}'.format(e) self.problems.add(InfoComment(message)) fixers.rollback_changes(self._target_path, self._pull_request.head) except Exception as e: log.info( 'Fixer application failed, ' 'rolling back working tree. Got %s', e) fixers.rollback_changes(self._target_path, self._pull_request.head) def publish(self, check_run_id=None): self.problems.limit_to_changes() if check_run_id: self._review.publish_checkrun(self.problems, check_run_id) else: self._review.publish_review(self.problems, self._pull_request.head)
class TestKtlint(TestCase): fixtures = [ 'tests/fixtures/ktlint/no_errors.kt', 'tests/fixtures/ktlint/has_errors.kt', 'tests/fixtures/ktlint/android_has_errors.kt', ] def setUp(self): self.problems = Problems() options = {} self.tool = Ktlint(self.problems, options, root_dir) def test_match_file(self): self.assertFalse(self.tool.match_file('test.rb')) self.assertFalse(self.tool.match_file('dir/name/test.py')) self.assertFalse(self.tool.match_file('test.py')) self.assertTrue(self.tool.match_file('test.kt')) self.assertTrue(self.tool.match_file('dir/name/test.kt')) self.assertTrue(self.tool.match_file('test.kts')) @requires_image('ktlint') def test_check_dependencies(self): self.assertTrue(self.tool.check_dependencies()) @requires_image('ktlint') def test_process_files_pass(self): file_no_errors = self.fixtures[0] self.tool.process_files(file_no_errors) eq_([], self.problems.all(file_no_errors)) @requires_image('ktlint') def test_process_files_fail(self): file_has_errors = self.fixtures[1] self.tool.process_files([file_has_errors]) problems = self.problems.all(file_has_errors) eq_(2, len(problems)) expected = Comment(file_has_errors, 1, 1, 'Redundant "toString()" call in string template') eq_(expected, problems[0]) expected = Comment(file_has_errors, 2, 2, 'Redundant curly braces') eq_(expected, problems[1]) @requires_image('ktlint') def test_process_files_with_android(self): file_android_has_errors = self.fixtures[2] tool = Ktlint(self.problems, {'android': True}, root_dir) tool.process_files([file_android_has_errors]) problems = self.problems.all(file_android_has_errors) eq_(3, len(problems)) expected = Comment( file_android_has_errors, 1, 1, 'class AndroidActivity should be declared in a file named ' + 'AndroidActivity.kt (cannot be auto-corrected)') eq_(expected, problems[0]) expected = Comment(file_android_has_errors, 9, 9, 'Wildcard import (cannot be auto-corrected)') eq_(expected, problems[1]) # Android options should lint max line length in a file expected = Comment( file_android_has_errors, 51, 51, 'Exceeded max line length (100) (cannot be auto-corrected)') eq_(expected, problems[2]) @requires_image('ktlint') def test_process_files_multiple_files(self): self.tool.process_files(self.fixtures) eq_([], self.problems.all(self.fixtures[0])) eq_(2, len(self.problems.all(self.fixtures[1]))) # Without android options should only display 2 errors eq_(2, len(self.problems.all(self.fixtures[2]))) def test_has_fixer__not_enabled(self): tool = Ktlint(self.problems, {}, root_dir) eq_(False, tool.has_fixer()) def test_has_fixer__enabled(self): tool = Ktlint(self.problems, {'fixer': True}, root_dir) eq_(True, tool.has_fixer()) @requires_image('ktlint') def test_process_files__with_ruleset(self): tool = Ktlint(self.problems, {'ruleset': '/path/to/custom/rulseset.jar'}, root_dir) eq_([ 'ktlint', '--color', '--reporter=checkstyle', '-R', '/path/to/custom/rulseset.jar' ], tool._create_command()) @requires_image('ktlint') def test_process_files__valid_config(self): editor_config = 'tests/fixtures/ktlint/.editorconfig' tool = Ktlint(self.problems, {'config': editor_config}, root_dir) eq_([ 'ktlint', '--color', '--reporter=checkstyle', '--editorconfig=', editor_config ], tool._create_command()) @requires_image('ktlint') def test_execute_fixer(self): tool = Ktlint(self.problems, {'fixer': True}, root_dir) target = root_dir + '/' + self.fixtures[1] original = read_file(target) tool.execute_fixer(self.fixtures) updated = read_and_restore_file(target, original) assert original != updated, 'File content should change.' eq_(0, len(self.problems.all()), 'No errors should be recorded')
def setUp(self): self.problems = Problems() self.tool = Pep8(self.problems)
def setUp(self): self.problems = Problems() options = {} self.tool = Ktlint(self.problems, options, root_dir)
def setUp(self): self.problems = Problems() self.tool = Black(self.problems, {}, root_dir)
class TestBlack(TestCase): fixtures = [ 'tests/fixtures/black/no_errors.py', 'tests/fixtures/black/has_errors.py', ] def setUp(self): self.problems = Problems() self.tool = Black(self.problems, {}, root_dir) def test_match_file(self): self.assertFalse(self.tool.match_file('test.php')) self.assertFalse(self.tool.match_file('test.js')) self.assertFalse(self.tool.match_file('dir/name/test.js')) self.assertTrue(self.tool.match_file('test.py')) self.assertTrue(self.tool.match_file('dir/name/test.py')) @requires_image('python3') def test_process_files__one_file_pass(self): self.tool.process_files([self.fixtures[0]]) self.assertEqual([], self.problems.all(self.fixtures[0])) @requires_image('python3') def test_process_files__one_file_fail(self): self.tool.process_files([self.fixtures[1]]) problems = self.problems.all() self.assertEqual(1, len(problems)) self.assertIn('* ' + self.fixtures[1], problems[0].body) @requires_image('python3') def test_process_files_two_files(self): self.tool.process_files(self.fixtures) problems = self.problems.all() self.assertEqual(1, len(problems)) self.assertIn('do not match the `black` styleguide', problems[0].body) self.assertIn('* ' + self.fixtures[1], problems[0].body) self.assertNotIn(self.fixtures[0], problems[0].body) @requires_image('python3') def test_process_absolute_container_path(self): fixtures = ['/src/' + path for path in self.fixtures] self.tool.process_files(fixtures) self.assertEqual(1, len(self.problems.all())) @requires_image('python3') def test_process_files__config(self): options = { 'config': 'tests/fixtures/black/pyproject.toml' } self.tool = Black(self.problems, options, root_dir) self.tool.process_files([self.fixtures[1]]) problems = self.problems.all() self.assertEqual(1, len(problems)) self.assertIn(self.fixtures[1], problems[0].body) def test_has_fixer__not_enabled(self): tool = Black(self.problems, {}) self.assertEqual(False, tool.has_fixer()) def test_has_fixer__enabled(self): tool = Black(self.problems, {'fixer': True}) self.assertEqual(True, tool.has_fixer()) @requires_image('python3') def test_execute_fixer(self): tool = Black(self.problems, {'fixer': True}, root_dir) original = read_file(self.fixtures[1]) tool.execute_fixer(self.fixtures) tool.process_files(self.fixtures) updated = read_and_restore_file(self.fixtures[1], original) assert original != updated, 'File content should change.' self.assertEqual(0, len(self.problems.all()), 'No errors should be recorded')
def test_filter_existing__removes_duplicates(self, http): fixture_data = load_fixture('comments_current.json') response = Response() response._content = fixture_data http.return_value = response gh = Github() problems = Problems() review = Review(gh, 2) filename_1 = "Routing/Filter/AssetCompressor.php" filename_2 = "View/Helper/AssetCompressHelper.php" problems.add(filename_1, 87, 'A pithy remark') problems.add(filename_1, 87, 'Something different') problems.add(filename_2, 88, 'I <3 it') problems.add(filename_2, 89, 'Not such a good comment') review.load_comments() review.remove_existing(problems) res = problems.all(filename_1) eq_(1, len(res)) expected = Comment(filename_1, 87, 87, 'Something different') eq_(res[0], expected) res = problems.all(filename_2) eq_(1, len(res)) expected = Comment(filename_2, 88, 88, 'I <3 it') eq_(res[0], expected)
def setUp(self): self.problems = Problems()
def setUp(self): self.problems = Problems() options = {} self.tool = Standardjs(self.problems, options, root_dir)
def test_add__with_base_path_no_trailing_slash(self): problems = Problems('/some/path') problems.add('/some/path/file.py', 10, 'Not good') eq_([], problems.all('/some/path/file.py')) eq_(1, len(problems.all('file.py'))) eq_(1, len(problems))
def test_has_changes(self): problems = Problems(changes=None) self.assertFalse(problems.has_changes()) problems = Problems(changes=[1]) assert problems.has_changes()
class TestGolint(TestCase): needs_golint = skipIf(golint_missing, 'Needs phpcs') fixtures = [ 'tests/fixtures/golint/no_errors.go', 'tests/fixtures/golint/has_errors.go', 'tests/fixtures/golint/http.go', ] def setUp(self): self.problems = Problems() self.tool = Golint(self.problems) def test_match_file(self): self.assertTrue(self.tool.match_file('test.go')) self.assertTrue(self.tool.match_file('dir/name/test.go')) self.assertFalse(self.tool.match_file('dir/name/test.py')) self.assertFalse(self.tool.match_file('test.php')) self.assertFalse(self.tool.match_file('test.golp')) @needs_golint def test_check_dependencies(self): self.assertTrue(self.tool.check_dependencies()) @needs_golint def test_process_files__one_file_pass(self): self.tool.process_files([self.fixtures[0]]) eq_([], self.problems.all(self.fixtures[0])) @needs_golint def test_process_files__one_file_fail(self): self.tool.process_files([self.fixtures[1]]) problems = self.problems.all(self.fixtures[1]) eq_(2, len(problems)) fname = self.fixtures[1] expected = Comment( fname, 9, 9, 'exported function Foo should have comment or be unexported') eq_(expected, problems[0]) expected = Comment( fname, 14, 14, "if block ends with a return statement, " "so drop this else and outdent its block") eq_(expected, problems[1]) @needs_golint def test_process_files_two_files(self): self.tool.process_files([self.fixtures[0], self.fixtures[1]]) eq_([], self.problems.all(self.fixtures[0])) problems = self.problems.all(self.fixtures[1]) eq_(2, len(problems)) @needs_golint def test_process_files_in_different_packages(self): self.tool.process_files([self.fixtures[1], self.fixtures[2]]) problems = self.problems.all() eq_(3, len(problems)) eq_(2, len(self.problems.all(self.fixtures[1]))) eq_(1, len(self.problems.all(self.fixtures[2]))) @needs_golint @patch('lintreview.tools.golint.run_command') def test_process_files_with_config__mocked(self, mock_command): mock_command.return_value = [] config = { 'min_confidence': 0.95 } tool = Golint(self.problems, config) tool.process_files([self.fixtures[1]]) mock_command.assert_called_with( [ go_bin_path('golint'), '-min_confidence', 0.95, self.fixtures[1] ], ignore_error=True, split=True) @needs_golint def test_process_files_with_config(self): config = { 'min_confidence': 0.95 } tool = Golint(self.problems, config) tool.process_files([self.fixtures[1]]) eq_(2, len(self.problems))
class TestPhpcs(TestCase): fixtures = [ 'tests/fixtures/phpcs/no_errors.php', 'tests/fixtures/phpcs/has_errors.php', ] def setUp(self): self.problems = Problems() self.tool = Phpcs(self.problems, base_path=root_dir) def test_version(self): assert self.tool.version != '' def test_match_file(self): self.assertTrue(self.tool.match_file('test.php')) self.assertTrue(self.tool.match_file('dir/name/test.php')) self.assertFalse(self.tool.match_file('dir/name/test.py')) self.assertFalse(self.tool.match_file('test.py')) self.assertFalse(self.tool.match_file('test.js')) @requires_image('php') def test_check_dependencies(self): self.assertTrue(self.tool.check_dependencies()) @requires_image('php') def test_process_files__one_file_pass(self): self.tool.process_files([self.fixtures[0]]) self.assertEqual([], self.problems.all(self.fixtures[0])) @requires_image('php') def test_process_files__one_file_fail(self): self.tool.process_files([self.fixtures[1]]) problems = self.problems.all(self.fixtures[1]) self.assertEqual(3, len(problems)) fname = self.fixtures[1] expected = Comment( fname, 14, 14, 'Opening brace should be on a new line') self.assertEqual(expected, problems[0]) expected = Comment( fname, 16, 16, "Spaces must be used to indent lines; tabs are not allowed") self.assertEqual(expected, problems[2]) @requires_image('php') def test_process_files_two_files(self): self.tool.process_files(self.fixtures) self.assertEqual([], self.problems.all(self.fixtures[0])) problems = self.problems.all(self.fixtures[1]) self.assertEqual(3, len(problems)) @requires_image('php') def test_process_files__with_config(self): config = { 'standard': 'Zend' } tool = Phpcs(self.problems, config, root_dir) tool.process_files([self.fixtures[1]]) problems = self.problems.all(self.fixtures[1]) self.assertEqual(3, len(problems), 'Changing standards changes error counts') @requires_image('php') def test_process_files__with_optional_package(self): config = { 'standard': 'CakePHP3' } tool = Phpcs(self.problems, config, root_dir) tool.process_files([self.fixtures[1]]) problems = self.problems.all(self.fixtures[1]) assert 'strict_types' not in problems[0].body, 'Should use custom rules' for image in docker.images(): self.assertNotIn('phpcs-', image, 'no phpcs image remains') @requires_image('php') def test_process_files__with_ignore(self): config = { 'standard': 'PSR2', 'ignore': 'tests/fixtures/phpcs/*' } tool = Phpcs(self.problems, config, root_dir) tool.process_files([self.fixtures[1]]) problems = self.problems.all(self.fixtures[1]) self.assertEqual(0, len(problems), 'ignore option should exclude files') @requires_image('php') def test_process_files__with_exclude(self): config = { 'standard': 'PSR2', 'exclude': 'Generic.WhiteSpace.DisallowTabIndent' } tool = Phpcs(self.problems, config, root_dir) tool.process_files([self.fixtures[1]]) problems = self.problems.all(self.fixtures[1]) self.assertEqual(1, len(problems), 'exclude option should reduce errors.') @requires_image('php') def test_process_files__with_invalid_exclude(self): config = { 'standard': 'PSR2', 'exclude': 'Derpity.Derp' } tool = Phpcs(self.problems, config, root_dir) tool.process_files([self.fixtures[1]]) problems = self.problems.all() self.assertEqual(1, len(problems), 'A failure comment should be logged.') error = problems[0].body self.assertIn('Your PHPCS configuration output the following error', error) self.assertIn('Derpity.Derp', error) def test_create_command__with_builtin_standard(self): config = { 'standard': 'Zend', 'tab_width': 4, } tool = Phpcs(self.problems, config, root_dir) result = tool.create_command(['some/file.php']) expected = [ 'phpcs-run', 'phpcs', '--report=checkstyle', '--standard=Zend', '--extensions=php', '--tab-width=4', '/src/some/file.php' ] self.assertEqual(result, expected) def test_create_command__with_path_based_standard(self): config = { 'standard': 'test/CodeStandards', 'tab_width': 4, } tool = Phpcs(self.problems, config, root_dir) result = tool.create_command(['some/file.php']) expected = [ 'phpcs-run', 'phpcs', '--report=checkstyle', '--standard=/src/test/CodeStandards', '--extensions=php', '--tab-width=4', '/src/some/file.php' ] self.assertEqual(result, expected) def test_create_command__ignore_option_as_list(self): config = { 'standard': 'PSR2', 'extensions': ['php', 'ctp'], 'exclude': ['rule1', 'rule2'], 'ignore': ['tests/fixtures/phpcs/*', 'tests/fixtures/eslint/*'] } tool = Phpcs(self.problems, config, root_dir) result = tool.create_command(['some/file.php']) expected = [ 'phpcs-run', 'phpcs', '--report=checkstyle', '--standard=PSR2', '--ignore=tests/fixtures/phpcs/*,tests/fixtures/eslint/*', '--exclude=rule1,rule2', '--extensions=php,ctp', '/src/some/file.php' ] self.assertEqual(result, expected) def test_has_fixer__not_enabled(self): tool = Phpcs(self.problems, {}) self.assertEqual(False, tool.has_fixer()) def test_has_fixer__enabled(self): tool = Phpcs(self.problems, {'fixer': True}) self.assertEqual(True, tool.has_fixer()) @requires_image('php') def test_execute_fixer(self): tool = Phpcs(self.problems, {'fixer': True}, root_dir) original = read_file(self.fixtures[1]) tool.execute_fixer(self.fixtures) updated = read_and_restore_file(self.fixtures[1], original) assert original != updated, 'File content should change.' self.assertEqual(0, len(self.problems.all()), 'No errors should be recorded') @requires_image('php') def test_execute_fixer__no_problems_remain(self): tool = Phpcs(self.problems, {'fixer': True}, root_dir) # The fixture file can have all problems fixed by phpcs original = read_file(self.fixtures[1]) tool.execute_fixer(self.fixtures) tool.process_files(self.fixtures) read_and_restore_file(self.fixtures[1], original) self.assertEqual(0, len(self.problems.all()), 'All errors should be autofixed')
def setUp(self): self.problems = Problems() self.tool = Golint(self.problems)
class TestProblems(TestCase): two_files_json = load_fixture('two_file_pull_request.json') # Block offset so lines don't match offsets block_offset = load_fixture('pull_request_line_offset.json') def setUp(self): self.problems = Problems() def test_add(self): self.problems.add('file.py', 10, 'Not good') eq_(1, len(self.problems)) self.problems.add('file.py', 11, 'Not good') eq_(2, len(self.problems)) eq_(2, len(self.problems.all())) eq_(2, len(self.problems.all('file.py'))) eq_(0, len(self.problems.all('not there'))) def test_add__duplicate_is_ignored(self): self.problems.add('file.py', 10, 'Not good') eq_(1, len(self.problems)) self.problems.add('file.py', 10, 'Not good') eq_(1, len(self.problems)) def test_add__with_base_path(self): problems = Problems('/some/path/') problems.add('/some/path/file.py', 10, 'Not good') eq_([], problems.all('/some/path/file.py')) eq_(1, len(problems.all('file.py'))) eq_(1, len(problems)) def test_add__with_base_path_no_trailing_slash(self): problems = Problems('/some/path') problems.add('/some/path/file.py', 10, 'Not good') eq_([], problems.all('/some/path/file.py')) eq_(1, len(problems.all('file.py'))) eq_(1, len(problems)) def test_add__with_diff_containing_block_offset(self): res = Resource.loads(self.block_offset) changes = DiffCollection(res) problems = Problems(changes=changes) line_num = 32 problems.add('somefile.py', line_num, 'Not good') eq_(1, len(problems)) result = problems.all('somefile.py') eq_(changes.line_position('somefile.py', line_num), result[0].position, 'Offset should be transformed to match value in changes') def test_add_many(self): errors = [ ('some/file.py', 10, 'Thing is wrong'), ('some/file.py', 12, 'Not good'), ] self.problems.add_many(errors) result = self.problems.all('some/file.py') eq_(2, len(result)) expected = [ Comment(errors[0][0], errors[0][1], errors[0][1], errors[0][2]), Comment(errors[1][0], errors[1][1], errors[1][1], errors[1][2]), ] eq_(expected, result) def test_limit_to_changes__remove_problems(self): res = Resource.loads(self.two_files_json) changes = DiffCollection(res) # Setup some fake problems. filename_1 = 'Console/Command/Task/AssetBuildTask.php' errors = ( (None, None, 'This is a general comment'), (filename_1, 117, 'Something bad'), (filename_1, 119, 'Something else bad'), (filename_1, 130, 'Filtered out, as line is not changed'), ) self.problems.add_many(errors) filename_2 = 'Test/test_files/View/Parse/single.ctp' errors = ( (filename_2, 2, 'Filtered out'), (filename_2, 3, 'Something bad'), (filename_2, 7, 'Filtered out'), ) self.problems.add_many(errors) self.problems.set_changes(changes) self.problems.limit_to_changes() result = self.problems.all(filename_1) eq_(2, len(result)) expected = [(None, None, 'This is a general comment'), (filename_1, 117, 'Something bad'), (filename_1, 119, 'Something else bad')] eq_(result.sort(), expected.sort()) result = self.problems.all(filename_2) eq_(1, len(result)) expected = [Comment(filename_2, 3, 3, 'Something bad')] eq_(result, expected) def test_has_changes(self): problems = Problems(changes=None) self.assertFalse(problems.has_changes()) problems = Problems(changes=[1]) assert problems.has_changes()
def setUp(self): self.problems = Problems() self.tool = Flake8(self.problems, options={'config': ''})
class TestYamllint(TestCase): fixtures = [ 'tests/fixtures/yamllint/no_errors.yaml', 'tests/fixtures/yamllint/has_errors.yaml', ] def setUp(self): self.problems = Problems() self.tool = Yamllint(self.problems, {}, root_dir) def test_match_file(self): self.assertFalse(self.tool.match_file('test.php')) self.assertFalse(self.tool.match_file('test.js')) self.assertFalse(self.tool.match_file('dir/name/test.js')) self.assertTrue(self.tool.match_file('test.yaml')) self.assertTrue(self.tool.match_file('dir/name/test.yaml')) self.assertTrue(self.tool.match_file('test.yml')) self.assertTrue(self.tool.match_file('dir/name/test.yml')) @requires_image('python2') def test_process_files__one_file_pass(self): self.tool.process_files([self.fixtures[0]]) eq_([], self.problems.all(self.fixtures[0])) @requires_image('python2') def test_process_files__one_file_fail(self): self.tool.process_files([self.fixtures[1]]) problems = self.problems.all(self.fixtures[1]) eq_(5, len(problems)) fname = self.fixtures[1] msg = "[warning] missing starting space in comment (comments)" expected = Comment(fname, 1, 1, msg) eq_(expected, problems[0]) msg = ("[warning] missing document start \"---\" (document-start)\n" "[error] too many spaces inside braces (braces)") expected = Comment(fname, 2, 2, msg) eq_(expected, problems[1]) @requires_image('python2') def test_process_files_two_files(self): self.tool.process_files(self.fixtures) eq_([], self.problems.all(self.fixtures[0])) problems = self.problems.all(self.fixtures[1]) eq_(5, len(problems)) fname = self.fixtures[1] msg = "[warning] missing starting space in comment (comments)" expected = Comment(fname, 1, 1, msg) eq_(expected, problems[0]) msg = ("[warning] missing document start \"---\" (document-start)\n" "[error] too many spaces inside braces (braces)") expected = Comment(fname, 2, 2, msg) eq_(expected, problems[1]) @requires_image('python2') def test_process_files_with_config(self): config = {'config': 'tests/fixtures/yamllint/config.yaml'} tool = Yamllint(self.problems, config, root_dir) tool.process_files([self.fixtures[0]]) problems = self.problems.all(self.fixtures[0]) eq_(1, len(problems), 'Config file should cause errors on no_errors.yml')