def test_empty_results(self): """ Empty results do not generate empty messages. """ rc1 = ResultsCollater({}) rc2 = ResultsCollater({ MockPlugin(): (0, [''], ''), MockPlugin(): (0, { u'a.txt': u'F' }, '') }) rc3 = ResultsCollater({ MockPlugin(): (0, ['C'], ''), MockPlugin(): (0, { u'a.txt': u'F' }, ''), MockPlugin(): (0, { u'a.txt': [[1, None, u'L']] }, '') }) # First collator had no results self.assertEqual(0, len(rc1.plugins)) self.assertEqual(0, len(rc1.reporters)) # Second had a result with no meaningful content self.assertEqual(2, len(rc2.plugins)) self.assertEqual(1, len(rc2.reporters)) # Third had something to report for all plugins self.assertEqual(3, len(rc3.plugins)) self.assertEqual(3, len(rc3.reporters))
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)
def test_commit_specific_message(self): """ Results that are commit specific are collated correctly. """ results = OrderedDict() results[MockPlugin()] = (0, 'default', '') results[MockPlugin()] = (0, [[u'warn', u'warning']], '') rc = ResultsCollater(results) messages, fm, lm = rc.messages # Defaults to info type self.assertEqual(Message(None, type='info', body='default'), messages[0]) self.assertEqual(Message(None, type='warn', body='warning'), messages[1]) # And our type counts should be 1 info 1 warning self.assertEqual({u'info': 1, u'warn': 1, u'stop': 0}, rc.counts) # The rest of these should be empty self.assertEqual([], fm) self.assertEqual([], lm) # And we should have no errors self.assertEqual([], rc.errors)
def test_one_of_each(self): """ One of each type of message is captured. """ results = { MockPlugin(): (0, ['C'], ''), MockPlugin(): (0, { u'a.txt': u'F' }, ''), MockPlugin(): (0, { u'a.txt': [[1, None, u'L']] }, '') } rc = ResultsCollater(results) self.assertEqual({u'info': 3, u'warn': 0, u'stop': 0}, rc.counts) cm, fm, lm = rc.messages self.assertEqual(1, len(cm)) self.assertEqual(1, len(fm)) self.assertEqual(1, len(lm)) self.assertEqual(Message(None, type="info", body="C"), cm[0]) self.assertEqual(Message(None, type="info", body="F", file=u'a.txt'), fm[0]) self.assertEqual( Message(None, type="info", body="L", file=u'a.txt', line=1), lm[0])
def test_file_specific_errors(self): """ Exercise the errors related to file specific messages. """ anon_obj = object() results = {MockPlugin(): (0, {'a.txt': anon_obj}, '')} self.assertEqual([Error(None, type='s', file='a.txt', body=anon_obj)], ResultsCollater(results).errors) results = {MockPlugin(): (0, {'a.txt': [anon_obj]}, '')} self.assertEqual([Error(None, type='s', file='a.txt', body=anon_obj)], ResultsCollater(results).errors) results = {MockPlugin(): (0, {'a.txt': [1, None]}, '')} self.assertEqual([ Error(None, type='s', file='a.txt', body=1), Error(None, type='s', file='a.txt', body=None) ], ResultsCollater(results).errors) results = {MockPlugin(): (0, {'a.txt': [[1, 2, 3, 4, 5]]}, '')} self.assertEqual( [Error(None, type='s', body={'a.txt': [[1, 2, 3, 4, 5]]})], ResultsCollater(results).errors)
def test_change_name_later(self): """ Change a plugins name after it has been created. """ mp = MockPlugin() mp.name = 'Specific' self.assertEqual('Specific', mp.name)
def test_commit_specific_errors(self): """ Exercise the errors related to commit specific messages. """ anon_obj = object() results = {MockPlugin(): (0, anon_obj, '')} self.assertEqual([Error(None, type='s', body=anon_obj)], ResultsCollater(results).errors) results = {MockPlugin(): (0, [[1, 2, 3, 4, 5]], '')} self.assertEqual([Error(None, type='s', body=[1, 2, 3, 4, 5])], ResultsCollater(results).errors)
def test_line_specific_message(self): """ Results that are line-specific are collated correctly. """ stdout = OrderedDict() stdout[u'a.txt'] = [[1, None, 'Info A']] stdout[u'b.txt'] = [[2, u'warn', 'Warn B']] stdout[u'c.txt'] = [[3, u'stop', 'Stop C']] results = OrderedDict() results[MockPlugin()] = (0, stdout, '') rc = ResultsCollater(results) self.assertEqual({u'info': 1, u'warn': 1, u'stop': 1}, rc.counts) cm, fm, messages = rc.messages self.assertEqual( Message(None, type='info', body='Info A', file=u'a.txt', line=1), messages[0]) self.assertEqual( Message(None, type='warn', body='Warn B', file=u'b.txt', line=2), messages[1]) self.assertEqual( Message(None, type='stop', body='Stop C', file=u'c.txt', line=3), messages[2]) # The other messages should be empty self.assertEqual([], cm) self.assertEqual([], fm) # And we should have no errors self.assertEqual([], rc.errors)
def test_single_failure(self): """ Reports a single failure. """ expectation = Expectation((1, 2), None, u'aaa') results = [ FailureResult(actual=u'bbb', expectation=expectation, plugin=MockPlugin()) ] ptr = PluginTestReporter(results) self.assertResults( u''' 01 – 02 Fail Actual {0} bbb Diff {0} - aaa + bbb Pass 0, Fail 1'''.format(REPORTER_HORIZONTAL_DIVIDER), ptr.dumps())
def test_plugin_defaults_to_cwd(self): """ Running the plugins tests defaults to the current working directory. """ plugin_dir = create_plugin(mkdtemp(), template='python', bundle='bundle', name='name') expectation = Expectation((1, 2), None, u'aaa') results = [ SuccessResult(actual=u'aaa', expectation=expectation, plugin=MockPlugin()) ] with patch('jig.commands.plugin.PluginTestRunner') as ptr: ptr.return_value = Mock() ptr.return_value.run = Mock(return_value=results) with cwd_bounce(plugin_dir): self.run_command('test') self.assertResults( u''' 01 – 02 Pass Pass 1, Fail 0''', self.output)
def test_create_named_plugin(self): """ Create a mock plugin with a specific name. """ mp = MockPlugin(name='Specific') self.assertEqual('Specific', mp.name)
def test_formats_results(self): """ Will return test results. """ plugin_dir = create_plugin(mkdtemp(), template='python', bundle='bundle', name='name') expectation = Expectation((1, 2), None, u'aaa') results = [ SuccessResult(actual=u'aaa', expectation=expectation, plugin=MockPlugin()) ] with patch('jig.commands.plugin.PluginTestRunner') as ptr: ptr.return_value = Mock() ptr.return_value.run = Mock(return_value=results) self.run_command('test {0}'.format(plugin_dir)) self.assertResults( u''' 01 – 02 Pass Pass 1, Fail 0''', self.output)
def test_create_unnamed_mock_plugin(self): """ Create an unnamed mock plugin. """ mp = MockPlugin() self.assertEqual('Unnamed', mp.name)
def test_failure_within_success(self): """ Multiple results. """ expectation1 = Expectation((1, 2), None, u'aaa') expectation2 = Expectation((2, 3), None, u'b\nb\nb\n') expectation3 = Expectation((3, 4), None, u'ccc') results = [ SuccessResult(actual=u'aaa', expectation=expectation1, plugin=MockPlugin()), FailureResult(actual=u'b\nB\nb\n', expectation=expectation2, plugin=MockPlugin()), SuccessResult(actual=u'ccc', expectation=expectation3, plugin=MockPlugin()) ] ptr = PluginTestReporter(results) self.assertResults( u''' 01 – 02 Pass 02 – 03 Fail Actual {0} b B b Diff {0} b + B b - b 03 – 04 Pass Pass 2, Fail 1'''.format(REPORTER_HORIZONTAL_DIVIDER), ptr.dumps())
def test_children_are_normal_mocks(self): """ Calling an attribute returns a normal :py:class:`Mock`. """ mp = MockPlugin() mock = mp.testattr self.assertTrue(isinstance(mock, Mock)) self.assertFalse(isinstance(mock, MockPlugin))
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_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_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_plugin_error(self): """ Results with non-zero exit codes create error messages. """ results = {MockPlugin(): (1, '', 'Plugin failed')} rc = ResultsCollater(results) cm, fm, lm = rc.messages self.assertEqual([Error(None, type='stop', body='Plugin failed')], rc.errors)
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_no_results(self): """ We have results but no real content. """ results = { MockPlugin(): (0, None, ''), MockPlugin(): (0, '', ''), MockPlugin(): (0, [''], ''), MockPlugin(): (0, [['w', '']], ''), MockPlugin(): (0, { u'a.txt': u'' }, ''), MockPlugin(): (0, { u'a.txt': [[]] }, ''), MockPlugin(): (0, { u'a.txt': [[u'']] }, ''), MockPlugin(): (0, { u'a.txt': [['', u'']] }, ''), MockPlugin(): (0, { u'a.txt': [[None, '', u'']] }, ''), MockPlugin(): (0, { u'a.txt': [[1, '', u'']] }, '') } rc = ResultsCollater(results) cm, fm, lm = rc.messages # Should all be empty since nothing of interest was found self.assertEqual([], cm) self.assertEqual([], fm) self.assertEqual([], lm) # And we should have no errors self.assertEqual([], rc.errors)
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)
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_equality(self): """ Messages with the same content are considered equal. """ message1 = Message(MockPlugin(), type='w', file='a.txt', body='body', line=1) message2 = Message(MockPlugin(), type='w', file='a.txt', body='body', line=1) message3 = Message(MockPlugin(), type='w', file='b.txt', body='bbbb', line=9) self.assertTrue(message1 == message2) self.assertFalse(message2 == message3) self.assertFalse(message3 == {})
def test_simple_integration(self): """ Will run the hook. """ with patch.object(self.runner, 'results'): plugin = MockPlugin() # Empty results self.runner.results.return_value = {plugin: (0, '', '')} with self.assertRaises(SystemExit) as ec: self.runner.fromhook(self.gitrepodir) # pragma: no branch self.assertSystemExitCode(ec.exception, 0) self.assertEqual( u'\U0001f44c Jig ran 1 plugin, nothing to report\n', self.output)
def test_single_success(self): """ Report a single success. """ expectation = Expectation((1, 2), None, u'aaa') results = [ SuccessResult(actual=u'aaa', expectation=expectation, plugin=MockPlugin()) ] ptr = PluginTestReporter(results) self.assertResults( u''' 01 – 02 Pass Pass 1, Fail 0''', ptr.dumps())
def test_outputs_stdin_stdout(self): """ Will report the input and output of a plugin. """ stdin = json.dumps(['a', 'b', 'c']) stdout = json.dumps(['d', 'e', 'f']) expectation = Expectation((1, 2), None, u'aaa') results = [ SuccessResult(actual=u'aaa', expectation=expectation, plugin=MockPlugin(), stdin=stdin, stdout=stdout) ] ptr = PluginTestReporter(results) self.assertResults( u''' 01 – 02 Pass stdin (sent to the plugin) [ "a", "b", "c" ] stdout (received from the plugin) [ "d", "e", "f" ] {0} Pass 1, Fail 0'''.format(REPORTER_HORIZONTAL_DIVIDER), ptr.dumps(verbose=True))
def test_plugin_test_failure(self): """ Fails with exit code other than 0. """ plugin_dir = create_plugin(mkdtemp(), template='python', bundle='bundle', name='name') expectation = Expectation((1, 2), None, u'bbb') results = [ FailureResult(actual=u'aaa', expectation=expectation, plugin=MockPlugin()) ] with patch('jig.commands.plugin.PluginTestRunner') as ptr: ptr.return_value = Mock() ptr.return_value.run = Mock(return_value=results) with self.assertRaises(ForcedExit): self.run_command('test {0}'.format(plugin_dir)) self.assertResults( u''' 01 – 02 Fail Actual {0} aaa Diff {0} - bbb + aaa Pass 0, Fail 1'''.format(REPORTER_HORIZONTAL_DIVIDER), self.error)
def test_formats_results_verbose(self): """ Will return test results with stdin and stdout. """ plugin_dir = create_plugin(mkdtemp(), template='python', bundle='bundle', name='name') expectation = Expectation((1, 2), None, u'aaa') results = [ SuccessResult(actual=u'aaa', expectation=expectation, plugin=MockPlugin(), stdin='a\n', stdout='b\n') ] with patch('jig.commands.plugin.PluginTestRunner') as ptr: ptr.return_value = Mock() ptr.return_value.run = Mock(return_value=results) self.run_command('test -v {0}'.format(plugin_dir)) self.assertResults( u''' 01 – 02 Pass stdin (sent to the plugin) a stdout (received from the plugin) b {0} Pass 1, Fail 0'''.format(REPORTER_HORIZONTAL_DIVIDER), self.output)
def tests_outputs_stdout_not_json(self): """ Will report input and output, even if it's not JSON. """ stdin = 'a\nb\nc\n' stdout = 'd\ne\nf\n' expectation = Expectation((1, 2), None, u'aaa') results = [ SuccessResult(actual=u'aaa', expectation=expectation, plugin=MockPlugin(), stdin=stdin, stdout=stdout) ] ptr = PluginTestReporter(results) self.assertResults( u''' 01 – 02 Pass stdin (sent to the plugin) a b c stdout (received from the plugin) d e f {0} Pass 1, Fail 0'''.format(REPORTER_HORIZONTAL_DIVIDER), ptr.dumps(verbose=True))
def test_file_specific_message(self): """ Results that are file-specific are collated correctly. """ # Line number of None will be recognized as file-specific. stdout1 = {u'a.txt': [[None, u'warn', 'Problem with this file']]} # Will a length of 2 be recognized as file-specific? stdout2 = {u'a.txt': [[u'warn', 'Problem with this file']]} # Can we handle more than one file and different argument signatures # for the type? stdout3 = OrderedDict() stdout3[u'a.txt'] = [['Info A']] stdout3[u'b.txt'] = [[u'warn', 'Warn B']] stdout3[u'c.txt'] = [[u's', 'Stop C']] results = OrderedDict() results[MockPlugin()] = (0, stdout1, '') results[MockPlugin()] = (0, stdout2, '') results[MockPlugin()] = (0, stdout3, '') rc = ResultsCollater(results) self.assertEqual({u'info': 1, u'warn': 3, u'stop': 1}, rc.counts) cm, messages, lm = rc.messages for msg in messages: # They all lack a line number, making them file-specific. self.assertIsNone(msg.line) # But they have a file self.assertIsNotNone(msg.file) # First set's None get's recognized as file-specific self.assertEqual( Message(None, type='warn', body='Problem with this file', file='a.txt'), messages[0]) # Second set get's recognized as a warning self.assertEqual( Message(None, type='warn', body='Problem with this file', file='a.txt'), messages[1]) self.assertEqual( Message(None, type='info', body='Info A', file='a.txt'), messages[2]) self.assertEqual( Message(None, type='warn', body='Warn B', file='b.txt'), messages[3]) self.assertEqual( Message(None, type='stop', body='Stop C', file='c.txt'), messages[4]) # The other messages should be empty self.assertEqual([], cm) self.assertEqual([], lm) # And we should have no errors self.assertEqual([], rc.errors)