Skip to content

Commit

Permalink
bears/general: Add RegexLintBear
Browse files Browse the repository at this point in the history
Closes coala#1532
  • Loading branch information
bkhanale committed Aug 23, 2019
1 parent f9aa8c3 commit 49cdf5a
Show file tree
Hide file tree
Showing 5 changed files with 140 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
55 changes: 55 additions & 0 deletions bears/general/RegexLintBear.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
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 = {'[email protected]'}
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':
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,
)
81 changes: 81 additions & 0 deletions tests/general/RegexLintBearTest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
from os.path import abspath
from queue import Queue

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)


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

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


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'))
self.check_validity(self.uut, test_good_py_file.splitlines())

def test_bad_python_file(self):
self.section.append(Setting('language', 'python 3'))
with execute_bear(self.uut, abspath('bad_python_file'),
test_bad_py_file.splitlines()) as results:
self.assertEqual(len(results), 1)
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'))
self.check_validity(self.uut, test_good_cpp_file.splitlines())

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(len(results), 1)
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'))
self.check_validity(self.uut, test_re_error_file.splitlines())

0 comments on commit 49cdf5a

Please sign in to comment.