def test_2_matches(self): sub1 = substitution.Substitution( matched_spans={'x': (0, 1)}, replacements={'x': u'x'}, primary_label='x', ) sub2 = substitution.Substitution( matched_spans={'x': (2, 3)}, replacements={'x': u'x'}, primary_label='x', ) self.assertEqual( formatting.apply_substitutions('abc', [sub1, sub2]), 'xbx', )
def test_swapped_order_empty(self): """Test what 'shouldn't happen'.""" with self.assertRaises(AssertionError): list( substitution.labeled_spans( substitution.Substitution(matched_spans={'a': (10, 5)}, primary_label='a')))
def test_validate_category_failure(self, category): with self.assertRaises(ValueError): substitution.Substitution( primary_label='label', matched_spans={'label': (0, 0)}, category=category, )
def _substitution_with_span(start, end, **kwargs): kwargs.setdefault('message', '') kwargs.setdefault('url', '') return substitution.Substitution(matched_spans={'label': (start, end)}, primary_label='label', replacements={'label': u''}, **kwargs)
def find_iter_parsed( self, parsed: _matcher.PythonParsedFile ) -> Iterable[substitution.Substitution]: for match_dict, templates in self.find_dicts_parsed(parsed): try: replacements = formatting.rewrite_templates( parsed, match_dict, templates) except formatting.RewriteError as e: # TODO: Forward this up somehow. print('Skipped rewrite:', e, file=sys.stderr) continue yield substitution.Substitution( matched_spans={ label: s.span for label, s in match_dict.items() if s.span not in (None, (-1, -1)) }, replacements=replacements, primary_label=ROOT_LABEL, key_span=self.key_span_for_dict(parsed, match_dict), message=replacements.pop(MESSAGE_LABEL, None), url=replacements.pop(URL_LABEL, None), category=replacements.pop(CATEGORY_LABEL, None), significant=bool(replacements.pop(SIGNIFICANT_LABEL, '')), )
def test_empty_range(self): self.assertEqual( list( substitution.labeled_spans( substitution.Substitution(matched_spans={'a': (0, 0)}, primary_label='a'))), [substitution.LabeledSpan(labels={'a'}, span=(0, 0))])
def next_out(label): sub = substitution.Substitution( matched_spans={label: (0, 3)}, primary_label=label, ) is_diff, out = renderer.render('abc', sub, {}) self.assertFalse(is_diff) return out
def test_noreplacements(self): sub = substitution.Substitution( matched_spans={'x': (1, 2)}, primary_label='x', ) self.assertEqual( formatting.apply_substitutions('abc', [sub]), 'abc', )
def test_validate_span_replacements(self): with self.assertRaises(ValueError): substitution.Substitution( message='', matched_spans={'label': (0, 0)}, primary_label='label', replacements={'label_dne': u''}, url='', )
def test_validate_span_not_in_replacements(self): """It is OK to only replace a subset of matched spans.""" # does not raise: substitution.Substitution( message='', matched_spans={'label': (0, 0)}, primary_label='label', replacements={}, url='', )
def test_total_overlap(self): self.assertEqual( list( substitution.labeled_spans( substitution.Substitution(matched_spans={ 'a': (0, 10), 'b': (0, 10) }, primary_label='a'))), [substitution.LabeledSpan(labels={'a', 'b'}, span=(0, 10))])
def test_empty_style(self): """Tests that the empty string is unstyled. We want to preserve colors for the _non_ empty spans. """ sub = substitution.Substitution( matched_spans={'primary': (0, 0)}, primary_label='primary', ) self.assertEqual( formatting.Renderer(match_format='{match}').render('abc', sub, {}), (False, '\n'))
def test_diff(self): """Tests a basic diff rendering.""" sub = substitution.Substitution( matched_spans={'primary': (0, 3)}, replacements={'primary': u'new'}, primary_label='primary', ) renderer = formatting.Renderer(match_format='{match}', color=False) is_diff, out = renderer.render('old', sub, {}) self.assertTrue(is_diff) self.assertEqual(out, '-old\n+new\n')
def test_saves_style(self): """Tests that the same style is reused for the same label.""" renderer = formatting.Renderer(match_format='{match}') sub_x = substitution.Substitution( matched_spans={'x': (0, 3)}, primary_label='x', ) is_diff, out_1 = renderer.render('abc', sub_x, {}) self.assertFalse(is_diff) is_diff, out_2 = renderer.render('abc', sub_x, {}) self.assertFalse(is_diff) # The same labels always get the same styling: self.assertEqual(out_1, out_2) # But a different label gets a new styling: sub_y = substitution.Substitution( matched_spans={'y': (0, 3)}, primary_label='y', ) is_diff, out_3 = renderer.render('abc', sub_y, {}) self.assertFalse(is_diff) self.assertNotEqual(out_1, out_3)
def test_gap(self): self.assertEqual( list( substitution.labeled_spans( substitution.Substitution(matched_spans={ 'a': (0, 10), 'b': (20, 30) }, primary_label='a'))), [ substitution.LabeledSpan(labels={'a'}, span=(0, 10)), substitution.LabeledSpan(labels=set(), span=(10, 20)), substitution.LabeledSpan(labels={'b'}, span=(20, 30)) ])
def test_nonsolo_primary_style(self): # exploit a weird edge case for testing: if the other label has zero-width, # it is not styled, but this still affects how the primary label is treated. sub = substitution.Substitution( matched_spans={ 'primary': (0, 3), 'other': (3, 3) }, primary_label='primary', ) self.assertEqual( formatting.Renderer(match_format='{match}').render('abc', sub, {}), (False, '{colorama.Style.BRIGHT}abc{colorama.Style.RESET_ALL}\n'.format( colorama=colorama)))
def test_fixedpoint_drop_insignificant(self): fx = fixer.CombiningPythonFixer([ _search_replace_fixer('a', 'b', url='url_a', significant=False), _search_replace_fixer('b', 'c', url='url_b', significant=True), ]) self.assertEqual( list(search.find_iter(fx, 'a', 'foo.py', max_iterations=10)), [ substitution.Substitution( message='b', matched_spans={'fixedpoint': (0, 1)}, primary_label='fixedpoint', replacements={'fixedpoint': 'c'}, url='url_b', significant=True, category='refex.merged.significant', ) ])
def _substitution(**kwargs): """Match with a substitution that shares the provided fields. The rest are replaced with mock.ANY. Args: **kwargs: The arguments to Substitution(). Returns: A Substitution. """ for attribute in attr.fields(substitution.Substitution): if attribute.name not in kwargs: kwargs[attribute.name] = mock.ANY # temporarily disable input validation: with mock.patch.object(substitution.Substitution, '_validate', lambda self: None): return substitution.Substitution(**kwargs)
def test_fixedpoint_keep_insignificant(self): fx = fixer.CombiningPythonFixer([ _search_replace_fixer('a', 'b', url='url_a', significant=False), _search_replace_fixer('b', 'c', url='url_b', significant=False), ]) self.assertEqual( list(search.find_iter(fx, 'a', 'foo.py', max_iterations=10)), [ substitution.Substitution( message= 'There are a few findings here:\n\na\n(url_a)\n\nb\n(url_b)', matched_spans={'fixedpoint': (0, 1)}, primary_label='fixedpoint', replacements={'fixedpoint': 'c'}, url= 'https://refex.readthedocs.io/en/latest/guide/fixers/merged.html', significant=False, category='refex.merged.not-significant', ) ])
def _compile_substitutions(substitutions: Iterable[substitution.Substitution], primary_start: int, primary_end: int, new_primary_contents: Text): """Create one substitution out of many that were composed together.""" if not substitutions: return None significant = True significant_subs = [sub for sub in substitutions if sub.significant] if not significant_subs: significant_subs = substitutions significant = False # all subs were insignificant message_header = 'There are a few findings here:\n\n' urls = {sub.url for sub in significant_subs} if len(urls) == 1: [url] = urls messages = [sub.message for sub in significant_subs if sub.message] if len(set(messages)) == 1: # Present only one message, with no header. message_header = '' del messages[1:] else: # Can't give a better URL here :/ url = 'https://refex.readthedocs.io/en/latest/guide/fixers/merged.html' messages = [ '{message}\n({url})'.format(message=sub.message or '(no message)', url=sub.url) for sub in significant_subs ] if messages: message = message_header + '\n\n'.join(m for m in messages) else: message = None primary_label = 'fixedpoint' return substitution.Substitution( message=message, url=url, matched_spans={primary_label: (primary_start, primary_end)}, primary_label=primary_label, replacements={primary_label: new_primary_contents}, significant=significant, category='refex.merged.{}'.format( 'significant' if significant else 'not-significant'), )
def test_validate_no_replacements(self): substitution.Substitution( primary_label='label', matched_spans={'label': (0, 0)}, replacements=None, )
def test_validate_category_success(self, category): substitution.Substitution( primary_label='label', matched_spans={'label': (0, 0)}, category=category, )