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 Aug 26, 2019
1 parent f9aa8c3 commit 029df27
Show file tree
Hide file tree
Showing 5 changed files with 153 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
46 changes: 46 additions & 0 deletions bears/general/RegexLintBear.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import re

from sarge import run, Capture

from bears.general.AnnotationBear import AnnotationBear
from coalib.bears.LocalBear import LocalBear
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'}
BEAR_DEPS = {AnnotationBear}

def run(self, filename, file, dependency_results):
"""
Bear for linting regex through regexlint.
:param dependency_results:
Results given by the AnnotationBear.
"""
annotation_dict = dependency_results[AnnotationBear.name][0].contents
for src_range in annotation_dict['strings']:
src_line = src_range.affected_source({filename: file})[0]
regex = src_line[src_range.start.column:src_range.end.column-1]
try:
re.compile(regex)
except re.error:
continue
out = run('regexlint --regex "{}"'.format(regex),
stdout=Capture()).stdout.text
if out[-3:-1] == 'OK':
continue
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,
)
103 changes: 103 additions & 0 deletions tests/general/RegexLintBearTest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
from os.path import abspath
from queue import Queue

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


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

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

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

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

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'
'(else|elseif)'
^ here
""".lstrip()


class RegexLintBearTest(LocalBearTestHelper):

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

def test_good_python_file(self):
valid_file = good_py_file.splitlines()
self.section.append(Setting('language', 'python'))
dep_results = {AnnotationBear.name:
list(self.dep_uut.execute('file', valid_file))}
with execute_bear(self.uut, abspath('file'), valid_file,
dependency_results=dep_results) as results:
self.assertEqual(len(results), 0)

def test_bad_python_file(self):
invalid_file = bad_py_file.splitlines()
self.section.append(Setting('language', 'python'))
dep_results = {AnnotationBear.name:
list(self.dep_uut.execute('file', invalid_file))}
with execute_bear(self.uut, abspath('file'), invalid_file,
dependency_results=dep_results) as results:
self.assertEqual(len(results), 1)
self.assertEqual(results[0],
Result.from_values(origin=self.uut,
message=BAD_MESSAGE,
file='file',
line=2, column=15,
end_line=2, end_column=29))

def test_good_cpp_file(self):
valid_file = good_cpp_file.splitlines()
self.section.append(Setting('language', 'cpp'))
dep_results = {AnnotationBear.name:
list(self.dep_uut.execute('file', valid_file))}
with execute_bear(self.uut, abspath('file'), valid_file,
dependency_results=dep_results) as results:
self.assertEqual(len(results), 0)

def test_bad_cpp_file(self):
invalid_file = bad_cpp_file.splitlines()
self.section.append(Setting('language', 'cpp'))
dep_results = {AnnotationBear.name:
list(self.dep_uut.execute('file', invalid_file))}
with execute_bear(self.uut, abspath('file'), invalid_file,
dependency_results=dep_results) as results:
self.assertEqual(len(results), 1)
self.assertEqual(results[0],
Result.from_values(origin=self.uut,
message=BAD_MESSAGE,
file='file',
line=2, column=23,
end_line=2, end_column=37))

def test_re_error_file(self):
valid_file = re_error_file.splitlines()
self.section.append(Setting('language', 'python'))
dep_results = {AnnotationBear.name:
list(self.dep_uut.execute('file', valid_file))}
with execute_bear(self.uut, abspath('file'), valid_file,
dependency_results=dep_results) as results:
self.assertEqual(len(results), 0)

0 comments on commit 029df27

Please sign in to comment.