Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
bears/general: Add RegexLintBear
Browse files Browse the repository at this point in the history
Closes coala#1532
bkhanale committed Aug 22, 2019
1 parent c3ae6bc commit d6e6daa
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
@@ -329,6 +329,7 @@ RadonBear:
- Python
- Python 2
- Python 3
RegexLintBear:
RuboCopBear:
- Ruby
RubyFastererBear:
1 change: 1 addition & 0 deletions bear-requirements.txt
Original file line number Diff line number Diff line change
@@ -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
2 changes: 2 additions & 0 deletions bear-requirements.yaml
Original file line number Diff line number Diff line change
@@ -68,6 +68,8 @@ pip_requirements:
version: ~=3.12
radon:
version: ==1.4.0
regexlint:
version: ~=1.6
restructuredtext-lint:
version: ~=1.0
rstcheck:
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 d6e6daa

Please sign in to comment.