def run(self, test_range=None): """ Run the tests for this plugin. Returns a list of :py:class:`Result` objects which represent the results from the test run. :param list test_range: None or the parsed range from :function:`parse_range` """ # Use an empty config, we are not going to save this to disk pm = PluginManager(SafeConfigParser()) # Add the plugin we are testing pm.add(self.plugin_dir) # The instance of our plugin we will run the pre_commit test on plugin = pm.plugins[0] # Capture the default plugin config for resets while testing default_settings = plugin.config results = [] for exp in self.expectations: # Make sure that the range is off by 1 assert exp.range[1] == exp.range[0] + 1 # Is this expectation in the specified test range? if test_range and (exp.range not in test_range): # Skip this one, it's not one of the tests we should be running continue # Update the plugin config (settings) if available if exp.settings: plugin.config = exp.settings else: plugin.config = default_settings # View to help us create the output view = ConsoleView(collect_output=True, exit_on_exception=False) # Get a GitDiffIndex object from gdi = InstrumentedGitDiffIndex( self.timeline.repo.working_dir, self.timeline.diffs()[exp.range[0] - 1]) # What is the numbered test directory reprsenting our commit? wd = abspath( join(self.plugin_dir, PLUGIN_TESTS_DIRECTORY, '{0:02d}'.format(exp.range[1]))) with cwd_bounce(wd): # Patch up the filename to be within our numbered directory # instead of the Git repository gdi.replace_path = (self.timeline.repo.working_dir, wd) # Gather up the input to the plugin for logging stdin = json.dumps({ 'config': plugin.config, 'files': gdi }, indent=2, cls=PluginDataJSONEncoder) # Now run the actual pre_commit hook for this plugin res = plugin.pre_commit(gdi) # Break apart into its pieces retcode, stdout, stderr = res # pragma: no branch try: # Is it JSON data? data = json.loads(stdout) except ValueError: # Not JSON data = stdout if retcode == 0: # Format the results according to what you normally see in the # console. view.print_results({plugin: (retcode, data, stderr)}) else: results.append( FailureResult( exp, 'Exit code: {0}\n\nStd out:\n{1}\n\nStd err:\n{2}'. format(retcode, stdout or '(none)', stderr or '(none)'), plugin)) continue # Now remove the color character sequences to make things a little # easier to read, copy, and paste. actual = strip_paint(view._collect['stdout'].getvalue() or view._collect['stderr'].getvalue()) # Also remove the summary and count at the end, these are not # really all that useful to test and just end up making the # expect.rst files overly verbose actual = RESULTS_SUMMARY_SIGNATURE_RE.sub('', actual) actual = RESULTS_SUMMARY_COUNT_RE.sub('', actual) resargs = (exp, actual, plugin, stdin, stdout) if actual.strip() != exp.output.strip(): results.append(FailureResult(*resargs)) else: results.append(SuccessResult(*resargs)) return results
def run(self, test_range=None): """ Run the tests for this plugin. Returns a list of :py:class:`Result` objects which represent the results from the test run. :param list test_range: None or the parsed range from :function:`parse_range` """ # Use an empty config, we are not going to save this to disk pm = PluginManager(SafeConfigParser()) # Add the plugin we are testing pm.add(self.plugin_dir) # The instance of our plugin we will run the pre_commit test on plugin = pm.plugins[0] # Capture the default plugin config for resets while testing default_settings = plugin.config results = [] for exp in self.expectations: # Make sure that the range is off by 1 assert exp.range[1] == exp.range[0] + 1 # Is this expectation in the specified test range? if test_range and (exp.range not in test_range): # Skip this one, it's not one of the tests we should be running continue # Update the plugin config (settings) if available if exp.settings: plugin.config = exp.settings else: plugin.config = default_settings # View to help us create the output view = ConsoleView(collect_output=True, exit_on_exception=False) # Get a GitDiffIndex object from gdi = InstrumentedGitDiffIndex( self.timeline.repo.working_dir, self.timeline.diffs()[exp.range[0] - 1]) # What is the numbered test directory reprsenting our commit? wd = abspath(join( self.plugin_dir, PLUGIN_TESTS_DIRECTORY, '{0:02d}'.format(exp.range[1]))) with cwd_bounce(wd): # Patch up the filename to be within our numbered directory # instead of the Git repository gdi.replace_path = (self.timeline.repo.working_dir, wd) # Gather up the input to the plugin for logging stdin = json.dumps({ 'config': plugin.config, 'files': gdi}, indent=2, cls=PluginDataJSONEncoder) # Now run the actual pre_commit hook for this plugin res = plugin.pre_commit(gdi) # Break apart into its pieces retcode, stdout, stderr = res # pragma: no branch try: # Is it JSON data? data = json.loads(stdout) except ValueError: # Not JSON data = stdout if retcode == 0: # Format the results according to what you normally see in the # console. view.print_results({plugin: (retcode, data, stderr)}) else: results.append(FailureResult( exp, 'Exit code: {0}\n\nStd out:\n{1}\n\nStd err:\n{2}'.format( retcode, stdout or '(none)', stderr or '(none)'), plugin)) continue # Now remove the color character sequences to make things a little # easier to read, copy, and paste. actual = strip_paint( view._collect['stdout'].getvalue() or view._collect['stderr'].getvalue()) # Also remove the summary and count at the end, these are not # really all that useful to test and just end up making the # expect.rst files overly verbose actual = RESULTS_SUMMARY_SIGNATURE_RE.sub('', actual) actual = RESULTS_SUMMARY_COUNT_RE.sub('', actual) resargs = (exp, actual, plugin, stdin, stdout) if actual.strip() != exp.output.strip(): results.append(FailureResult(*resargs)) else: results.append(SuccessResult(*resargs)) return results
class TestConsoleView(ViewTestCase): """ With plugin results we can format them to the console. """ def setUp(self): self.view = ConsoleView() self.view.collect_output = True self.view.exit_on_exception = False def test_error(self): """ The plugin exits with something other than 0. """ plugin = MockPlugin() plugin.name = 'Plugin 1' counts = self.view.print_results({ plugin: (1, '', 'An error occurred')}) self.assertEqual((0, 0, 0), counts) self.assertResults(u''' ▾ Plugin 1 ✕ An error occurred {0} Jig ran 1 plugin Info 0 Warn 0 Stop 0 (1 plugin reported errors) '''.format(ATTENTION), self.output) def test_commit_specific_message(self): """ Messages generalized for the entire commit. """ plugin = MockPlugin() plugin.name = 'Plugin 1' counts = self.view.print_results({ plugin: (0, 'commit', '')}) self.assertEqual((1, 0, 0), counts) self.assertResults(u""" ▾ Plugin 1 ✓ commit {0} Jig ran 1 plugin Info 1 Warn 0 Stop 0 """.format(ATTENTION), self.output) def test_file_specific_message(self): """ Messages specific to the file being committed. """ plugin = MockPlugin() plugin.name = 'Plugin 1' counts = self.view.print_results({ plugin: (0, {u'a.txt': [[None, u'w', 'file']]}, '')}) self.assertEqual((0, 1, 0), counts) self.assertResults(u""" ▾ Plugin 1 ⚠ a.txt file {0} Jig ran 1 plugin Info 0 Warn 1 Stop 0 """.format(ATTENTION), self.output) def test_line_specific_message(self): """ Messages specific to a single line. """ plugin = MockPlugin() plugin.name = 'Plugin 1' counts = self.view.print_results({ plugin: (0, {u'a.txt': [[1, 's', 'stop']]}, '')}) self.assertEqual((0, 0, 1), counts) self.assertResults(u""" ▾ Plugin 1 ✕ line 1: a.txt stop {0} Jig ran 1 plugin Info 0 Warn 0 Stop 1 """.format(EXPLODE), self.output) def test_two_plugins(self): """ Formats messages (more than one) correctly. """ plugin1 = MockPlugin() plugin1.name = 'Plugin 1' plugin2 = MockPlugin() plugin2.name = 'Plugin 2' results = OrderedDict() results[plugin1] = (0, ['a', 'b'], '') results[plugin2] = (0, ['a', 'b'], '') counts = self.view.print_results(results) self.assertEqual((4, 0, 0), counts) self.assertResults(u""" ▾ Plugin 1 ✓ a ✓ b ▾ Plugin 2 ✓ a ✓ b {0} Jig ran 2 plugins Info 4 Warn 0 Stop 0 """.format(ATTENTION), self.output)
class TestConsoleView(ViewTestCase): """ With plugin results we can format them to the console. """ def setUp(self): self.view = ConsoleView() self.view.collect_output = True self.view.exit_on_exception = False def test_error(self): """ The plugin exits with something other than 0. """ plugin = MockPlugin() plugin.name = 'Plugin 1' counts = self.view.print_results( {plugin: (1, '', 'An error occurred')}) self.assertEqual((0, 0, 0), counts) self.assertResults( u''' ▾ Plugin 1 ✕ An error occurred {0} Jig ran 1 plugin Info 0 Warn 0 Stop 0 (1 plugin reported errors) '''.format(ATTENTION), self.output) def test_commit_specific_message(self): """ Messages generalized for the entire commit. """ plugin = MockPlugin() plugin.name = 'Plugin 1' counts = self.view.print_results({plugin: (0, 'commit', '')}) self.assertEqual((1, 0, 0), counts) self.assertResults( u""" ▾ Plugin 1 ✓ commit {0} Jig ran 1 plugin Info 1 Warn 0 Stop 0 """.format(ATTENTION), self.output) def test_file_specific_message(self): """ Messages specific to the file being committed. """ plugin = MockPlugin() plugin.name = 'Plugin 1' counts = self.view.print_results( {plugin: (0, { u'a.txt': [[None, u'w', 'file']] }, '')}) self.assertEqual((0, 1, 0), counts) self.assertResults( u""" ▾ Plugin 1 ⚠ a.txt file {0} Jig ran 1 plugin Info 0 Warn 1 Stop 0 """.format(ATTENTION), self.output) def test_line_specific_message(self): """ Messages specific to a single line. """ plugin = MockPlugin() plugin.name = 'Plugin 1' counts = self.view.print_results( {plugin: (0, { u'a.txt': [[1, 's', 'stop']] }, '')}) self.assertEqual((0, 0, 1), counts) self.assertResults( u""" ▾ Plugin 1 ✕ line 1: a.txt stop {0} Jig ran 1 plugin Info 0 Warn 0 Stop 1 """.format(EXPLODE), self.output) def test_two_plugins(self): """ Formats messages (more than one) correctly. """ plugin1 = MockPlugin() plugin1.name = 'Plugin 1' plugin2 = MockPlugin() plugin2.name = 'Plugin 2' results = OrderedDict() results[plugin1] = (0, ['a', 'b'], '') results[plugin2] = (0, ['a', 'b'], '') counts = self.view.print_results(results) self.assertEqual((4, 0, 0), counts) self.assertResults( u""" ▾ Plugin 1 ✓ a ✓ b ▾ Plugin 2 ✓ a ✓ b {0} Jig ran 2 plugins Info 4 Warn 0 Stop 0 """.format(ATTENTION), self.output)