Skip to content

Commit

Permalink
Add QuotesBear
Browse files Browse the repository at this point in the history
  • Loading branch information
sils committed Nov 17, 2016
1 parent f62d76b commit a430608
Show file tree
Hide file tree
Showing 2 changed files with 181 additions and 0 deletions.
82 changes: 82 additions & 0 deletions bears/general/QuotesBear.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
from coalib.bears.LocalBear import LocalBear
from bears.general.AnnotationBear import AnnotationBear
from coalib.results.Diff import Diff
from coalib.results.HiddenResult import HiddenResult
from coalib.results.Result import Result


class QuotesBear(LocalBear):

BEAR_DEPS = {AnnotationBear}
AUTHORS = {'The coala developers'}
AUTHORS_EMAILS = {'[email protected]'}
LICENSE = 'AGPL-3.0'
CAN_DETECT = {'Formatting'}

def correct_single_line_str(self, filename, file, sourcerange,
preferred_quotation):
"""
Corrects a given single line string assuming it does not use the
preferred quotation. If the preferred quotation mark is used inside the
string, no correction will be made.
This function will yield one or no Result objects.
:param filename:
The filename of the file to correct the line in.
:param file:
The file contents as list of lines.
:param sourcerange:
The sourcerange indicating where to find the string.
:param preferred_quotation:
``'`` or ``"`` respectively.
"""
str_contents = file[sourcerange.start.line - 1][
sourcerange.start.column:sourcerange.end.column-1]

if preferred_quotation in str_contents:
return

before = file[sourcerange.start.line - 1][:sourcerange.start.column-1]
after = file[sourcerange.end.line - 1][sourcerange.end.column:]

replacement = (before + preferred_quotation + str_contents +
preferred_quotation + after)

diff = Diff(file)
diff.change_line(sourcerange.start.line,
file[sourcerange.start.line - 1],
replacement)
yield Result(self, 'You do not use the preferred quotation marks.',
diff.affected_code(filename), diffs={filename: diff})

def run(self, filename, file, dependency_results,
preferred_quotation: str='"'):
"""
Checks and corrects your quotation style.
For all single line strings, this bear will correct the quotation to
your preferred quotation style if that kind of quote is not included
within the string. Multi line strings are not supported.
:param preferred_quotation: Your preferred quotation character, e.g.
``"`` or ``'``.
"""
if not isinstance(dependency_results[AnnotationBear.name][0],
HiddenResult):
return
if isinstance(dependency_results[AnnotationBear.name][0].contents,
str):
self.err(dependency_results[AnnotationBear.name][0].contents)
return

ranges = dependency_results[AnnotationBear.name][0].contents['strings']

for string_range in ranges:
if (file[string_range.start.line-1][string_range.start.column-1] ==
preferred_quotation):
continue

if string_range.start.line == string_range.end.line:
yield from self.correct_single_line_str(
filename, file, string_range, preferred_quotation)
99 changes: 99 additions & 0 deletions tests/general/QuotesBearTest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import unittest
from queue import Queue
from textwrap import dedent

from coalib.results.HiddenResult import HiddenResult, Result
from bears.general.QuotesBear import QuotesBear
from coalib.results.SourceRange import SourceRange
from coalib.settings.Section import Section
from coalib.testing.LocalBearTestHelper import verify_local_bear, execute_bear


class QuotesBearDiffTest(unittest.TestCase):

def setUp(self):
self.section = Section('')
self.uut = QuotesBear(self.section, Queue())

self.double_quote_file = dedent("""
'''
Multiline string
'''
"a string with double quotes!"
'A single quoted string with " in it'
""").splitlines(True)

self.single_quote_file = dedent("""
'''
Multiline string
'''
'a string with single quotes!'
"A double quoted string with ' in it"
""").splitlines(True)

self.filename = 'f'

self.dep_results = {
'AnnotationBear':
[HiddenResult(
'AnnotationBear',
{'comments': (), 'strings': (
SourceRange.from_values(self.filename, 2, 1, 4, 3),
SourceRange.from_values(self.filename, 5, 1, 5, 30),
SourceRange.from_values(self.filename, 6, 1, 6, 37))
}
)]
}

def test_error_handling(self):
dep_results = {'AnnotationBear': [Result("test", "test")]}
with execute_bear(self.uut, self.filename, self.double_quote_file,
dependency_results=dep_results) as results:
self.assertEqual(len(results), 0)

dep_results = {'AnnotationBear': [HiddenResult('a', 'error!')]}
with execute_bear(self.uut, self.filename, self.double_quote_file,
dependency_results=dep_results) as results:
self.assertEqual(len(results), 0)

def test_valid_quotes(self):
with execute_bear(self.uut, self.filename, self.double_quote_file,
dependency_results=self.dep_results) as results:
self.assertEqual(len(results), 0)

self.section['preferred_quotation'] = "'"
with execute_bear(self.uut, self.filename, self.single_quote_file,
dependency_results=self.dep_results) as results:
self.assertEqual(len(results), 0)

def test_invalid_quotes(self):
with execute_bear(self.uut, self.filename, self.single_quote_file,
dependency_results=self.dep_results) as results:
res_list = list(results)
self.assertEqual(len(res_list), 1)
self.assertEqual(res_list[0].diffs[self.filename].unified_diff,
'--- \n'
'+++ \n'
'@@ -2,5 +2,5 @@\n'
" '''\n"
" Multiline string\n"
" '''\n"
"-'a string with single quotes!'\n"
'+"a string with single quotes!"\n'
' "A double quoted string with \' in it"\n')

self.section['preferred_quotation'] = "'"
with execute_bear(self.uut, self.filename, self.double_quote_file,
dependency_results=self.dep_results) as results:
res_list = list(results)
self.assertEqual(len(res_list), 1)
self.assertEqual(res_list[0].diffs[self.filename].unified_diff,
'--- \n'
'+++ \n'
'@@ -2,5 +2,5 @@\n'
" '''\n"
" Multiline string\n"
" '''\n"
'-"a string with double quotes!"\n'
"+'a string with double quotes!'\n"
" 'A single quoted string with \" in it'\n")

0 comments on commit a430608

Please sign in to comment.