Skip to content

Commit

Permalink
bears/general: Add RegexLintBear
Browse files Browse the repository at this point in the history
Closes #1532
  • Loading branch information
bkhanale committed Jul 21, 2019
1 parent cbe1841 commit c8eceda
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 0 deletions.
1 change: 1 addition & 0 deletions bear-languages.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,7 @@ RadonBear:
- Python
- Python 2
- Python 3
RegexLintBear:
RuboCopBear:
- Ruby
RubyFastererBear:
Expand Down
1 change: 1 addition & 0 deletions bear-requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ pylint~=1.7.2
pyroma~=2.2.0
pyyaml~=3.12
radon==1.4.0
regexlint~=1.6
restructuredtext-lint~=1.0
rstcheck~=3.1
safety~=1.8.2
Expand Down
2 changes: 2 additions & 0 deletions bear-requirements.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ pip_requirements:
version: ~=3.12
radon:
version: ==1.4.0
regexlint:
version: ~=1.6
restructuredtext-lint:
version: ~=1.0
rstcheck:
Expand Down
54 changes: 54 additions & 0 deletions bears/general/RegexLintBear.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import re

from queue import Queue
from sarge import run, Capture
from contextlib import suppress

from bears.general.AnnotationBear import AnnotationBear

from coalib.bears.LocalBear import LocalBear
from coalib.results.Result import Result
from coalib.settings.Section import Section
from coalib.settings.Setting import Setting
from coalib.testing.LocalBearTestHelper import execute_bear

from dependency_management.requirements.PipRequirement import PipRequirement


class RegexLintBear(LocalBear):
LANGUAGES = {'All'}
REQUIREMENTS = {PipRequirement('regexlint', '1.6')}
AUTHORS = {'The coala developers'}
AUTHORS_EMAILS = {'coala-devel@googlegroups.com'}
LICENSE = 'AGPL-3.0'
CAN_DETECT = {'Formatting'}

def run(self, filename, file, language: str):
"""
Bear for linting regex through regexlint.
:param language:
The programming language of the file(s).
"""
section = Section('')
section.append(Setting('language', language))
bear = AnnotationBear(section, Queue())

with execute_bear(bear, filename, file) as result:
for src_range in result[0].contents['strings']:
src_line = src_range.affected_source({filename: file})[0]
regex = src_line[src_range.start.column:src_range.end.column-1]
with suppress(re.error):
re.compile(regex)
out = run('regexlint --regex "{}"'.format(regex),
stdout=Capture()).stdout.text
if out[-3:-1] != 'OK':
yield Result.from_values(
origin=self,
message=out,
file=filename,
line=src_range.start.line,
column=src_range.start.column,
end_line=src_range.end.line,
end_column=src_range.end.column,
)
84 changes: 84 additions & 0 deletions tests/general/RegexLintBearTest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
from os.path import abspath
from queue import Queue

from bears.general.RegexLintBear import RegexLintBear
from coalib.testing.LocalBearTestHelper import (
LocalBearTestHelper, execute_bear)
from coalib.results.Result import Result
from coalib.settings.Section import Section
from coalib.settings.Setting import Setting


test_good_python_file = """
some_regex = r'[a-zA-Z]]'
"""

test_bad_python_file = """
some_regex = r'(else|elseif)'
"""

test_good_cpp_file = """
char some_regex[] = "[a-zA-Z]]";
"""

test_bad_cpp_file = """
char some_regex[13] = "(else|elseif)";
"""

test_re_error_file = """
some_regex = r'*ab' # This should be skipped
some_other_regex = r'[a-z]'
"""

BAD_MESSAGE = ('E105:argv:root:0: Potential out of order alternation between '
'\'else\' and \'elseif\'\n'
' \'(else|elseif)\'\n'
' ^ here\n')


class RegexLintBearTest(LocalBearTestHelper):

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

def test_good_python_file(self):
self.section.append(Setting('language', 'python 3'))
with execute_bear(self.uut, abspath('good_python_file'),
test_good_python_file.splitlines(True)) as results:
self.assertEqual(results, [])

def test_bad_python_file(self):
self.section.append(Setting('language', 'python 3'))
with execute_bear(self.uut, abspath('bad_python_file'),
test_bad_python_file.splitlines()) as results:
self.assertEqual(results[0],
Result.from_values(origin=self.uut,
message=BAD_MESSAGE,
file='bad_python_file',
line=2, column=15,
end_line=2, end_column=29))

def test_good_cpp_file(self):
self.section.append(Setting('language', 'cpp'))
with execute_bear(self.uut, abspath('good_cpp_file'),
test_good_cpp_file.splitlines()) as results:
self.assertEqual(results, [])

def test_bad_cpp_file(self):
self.section.append(Setting('language', 'cpp'))
with execute_bear(self.uut, abspath('bad_cpp_file'),
test_bad_cpp_file.splitlines()) as results:
self.assertEqual(results[0],
Result.from_values(origin=self.uut,
message=BAD_MESSAGE,
file='bad_cpp_file',
line=2, column=23,
end_line=2, end_column=37))

def test_re_error_file(self):
self.section.append(Setting('language', 'cpp'))
with execute_bear(self.uut, abspath('re_error_file'),
test_re_error_file.splitlines()) as results:
self.assertEqual(results, [])

0 comments on commit c8eceda

Please sign in to comment.