Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support environment variables in the configuration for CoverityChecker #150

Merged
merged 22 commits into from
Nov 26, 2024
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
d1b3ff4
Fix error when env variable is used
JokeWaumans Nov 15, 2024
dcb292d
Use env variables for unclassified Coverity classification to test di…
JokeWaumans Nov 18, 2024
30871cb
Order imports
JokeWaumans Nov 18, 2024
62bf2dc
Unnecessary use of "r" when opening file
JokeWaumans Nov 18, 2024
70ab119
Use unittest.mock.patch.dict to set envvar
JokeWaumans Nov 18, 2024
00509e2
Add newline before class
JokeWaumans Nov 18, 2024
fd9c776
Revert "Add newline before class"
JokeWaumans Nov 18, 2024
6b16c6d
Add new line before class
JokeWaumans Nov 18, 2024
185700f
Merge branch 'master' of https://github.com/melexis/warnings-plugin i…
JasperCraeghs Nov 23, 2024
14790e6
Merge branch 'master' into fix-cov-var
JokeWaumans Nov 25, 2024
45fcc8a
Make sure that the code quality report always has the same order
JokeWaumans Nov 25, 2024
a3d2119
Merge branch 'fix-cov-var' of github.com:melexis/warnings-plugin into…
JokeWaumans Nov 25, 2024
01c0c39
Reorder checkers
JokeWaumans Nov 25, 2024
00ddb3c
Reorder code quality report of test
JokeWaumans Nov 25, 2024
dbff44b
Delete min/max from coverity since they are seen as "classifications"
JokeWaumans Nov 25, 2024
03dec47
Revert "Delete min/max from coverity since they are seen as "classifi…
JokeWaumans Nov 25, 2024
7912233
Add warning when Polyspace checker is used with other checkers
JokeWaumans Nov 25, 2024
00044dc
Fix tests by emptying fingerprints of Finding for each test
JokeWaumans Nov 25, 2024
62bb682
Fix test code quality
JokeWaumans Nov 25, 2024
feb643e
Update test_cq_description_format to check if warnings were printed
JokeWaumans Nov 25, 2024
575d372
Add test to catch error of using Polyspace checker together with othe…
JokeWaumans Nov 25, 2024
8dd1bbd
Simplify TC
JasperCraeghs Nov 26, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 12 additions & 18 deletions src/mlx/warnings/regex_checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,13 @@ class CoverityChecker(RegexChecker):
def __init__(self, verbose=False):
super().__init__(verbose)
self._cq_description_template = Template('Coverity: $checker')
self.checkers = {}
self.checkers = {
"unclassified": CoverityClassificationChecker("unclassified", verbose=self.verbose),
"pending": CoverityClassificationChecker("pending", verbose=self.verbose),
"bug": CoverityClassificationChecker("bug", verbose=self.verbose),
"intentional": CoverityClassificationChecker("intentional", verbose=self.verbose),
"false positive": CoverityClassificationChecker("false positive", verbose=self.verbose),
}
JasperCraeghs marked this conversation as resolved.
Show resolved Hide resolved

@property
def counted_warnings(self):
Expand Down Expand Up @@ -140,15 +146,14 @@ def check(self, content):
matches = re.finditer(self.pattern, content)
for match in matches:
if (classification := match.group("classification").lower()) in self.checkers:
self.checkers[classification].check(match)
else:
checker = CoverityClassificationChecker(classification=classification, verbose=self.verbose)
self.checkers[classification] = checker
checker = self.checkers[classification]
checker.cq_enabled = self.cq_enabled
checker.exclude_patterns = self.exclude_patterns
checker.cq_description_template = self.cq_description_template
checker.cq_default_path = self.cq_default_path
checker.check(match)
else:
print(f"WARNING: Unrecognized classification {match.group('classification')!r}")

def parse_config(self, config):
"""Process configuration
Expand All @@ -165,22 +170,11 @@ def parse_config(self, config):
self.add_patterns(value, self.exclude_patterns)
for classification, checker_config in config.items():
classification_key = classification.lower().replace("_", " ")
if classification_key in CoverityClassificationChecker.SEVERITY_MAP:
checker = CoverityClassificationChecker(classification=classification_key, verbose=self.verbose)
if maximum := checker_config.get("max", 0):
checker.maximum = int(maximum)
if minimum := checker_config.get("min", 0):
checker.minimum = int(minimum)
self.checkers[classification_key] = checker
if classification_key in self.checkers:
self.checkers[classification_key].parse_config(checker_config)
else:
print(f"WARNING: Unrecognized classification {classification!r}")

for checker in self.checkers.values():
checker.cq_enabled = self.cq_enabled
checker.exclude_patterns = self.exclude_patterns
checker.cq_description_template = self.cq_description_template
checker.cq_default_path = self.cq_default_path


class CoverityClassificationChecker(WarningsChecker):
SEVERITY_MAP = {
Expand Down
2 changes: 2 additions & 0 deletions src/mlx/warnings/warnings.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,8 @@ def check_logfile(self, file):
if not self.activated_checkers:
print("No checkers activated. Please use activate_checker function")
elif "polyspace" in self.activated_checkers:
if len(self.activated_checkers) > 1:
raise WarningsConfigError("Polyspace checker cannot be combined with other warnings checkers")
self.activated_checkers["polyspace"].check(file)
else:
content = file.read()
Expand Down
16 changes: 13 additions & 3 deletions tests/test_coverity.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import filecmp
import os
from io import StringIO
from unittest import TestCase
from pathlib import Path
import filecmp

from unittest import TestCase, mock
from unittest.mock import patch

from mlx.warnings import WarningsPlugin, warnings_wrapper, Finding
Expand All @@ -11,6 +11,16 @@
TEST_OUT_DIR = Path(__file__).parent / 'test_out'


def ordered(obj):
if isinstance(obj, dict):
return sorted((k, ordered(v)) for k, v in obj.items())
if isinstance(obj, list):
return sorted(ordered(x) for x in obj)
else:
return obj
JasperCraeghs marked this conversation as resolved.
Show resolved Hide resolved


@mock.patch.dict(os.environ, {"MIN_COV_WARNINGS": "1", "MAX_COV_WARNINGS": "2"})
class TestCoverityWarnings(TestCase):
def setUp(self):
Finding.fingerprints = {}
Expand Down
14 changes: 7 additions & 7 deletions tests/test_in/code_quality_format.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
}
}
},
"fingerprint": "8c59fc98f57e808819b5f04054aa5de3"
"fingerprint": "39030b49f58180c8172732f84d9d5fff"
},
{
"severity": "critical",
Expand All @@ -53,7 +53,7 @@
}
}
},
"fingerprint": "77c88c2e8519e4416776e8b96284e144"
"fingerprint": "e24313e32a3969502b2bc7c9ad9b1527"
},
{
"severity": "major",
Expand All @@ -67,7 +67,7 @@
}
}
},
"fingerprint": "a48d5550fd854f154597077dc51d1f8a"
"fingerprint": "bf26b89fc5898e957279a23a9540640f"
},
{
"severity": "critical",
Expand All @@ -81,7 +81,7 @@
}
}
},
"fingerprint": "22d31cc45bf8d96df2f1174df53d1adc"
"fingerprint": "6ca9fab3cdb5050ad01b2b02ec348180"
},
{
"severity": "critical",
Expand All @@ -95,7 +95,7 @@
}
}
},
"fingerprint": "041265549f9d63651d00019265a3ad90"
"fingerprint": "322c085b4098450c371da8c99046476b"
},
{
"severity": "major",
Expand All @@ -109,7 +109,7 @@
}
}
},
"fingerprint": "75e6473e0ee239e0f0b7094b12404afc"
"fingerprint": "bec264a0725556cfe0514b3aa168715c"
},
{
"severity": "major",
Expand All @@ -123,6 +123,6 @@
}
}
},
"fingerprint": "3c02f687278c969c497d8974994e8f76"
"fingerprint": "37dd4fe77518650ac6d416ea8e2e617f"
}
]
5 changes: 5 additions & 0 deletions tests/test_in/config_example_coverity.yml
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
coverity:
enabled: true
unclassified:
min: $MIN_COV_WARNINGS
max: '$MAX_COV_WARNINGS'
intentional:
min: 0
max: -1
bug:
min: 0
max: 0
pending:
min: 0
max: 0
false_positive:
min: 0
max: -1
sphinx:
enabled: false
Expand Down
43 changes: 43 additions & 0 deletions tests/test_in/config_example_polyspace_error.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
sphinx:
enabled: true
min: 0
max: 0
exclude:
- RemovedInSphinx\d+Warning
- 'WARNING: toctree'
doxygen:
enabled: false
junit:
enabled: false
xmlrunner:
enabled: false
coverity:
enabled: false
robot:
enabled: false
polyspace:
enabled: true
run-time check:
- color: red
min: 0
max: 0
- color: orange
min: 0
max: 10
global variable:
- color: red
min: 0
max: 0
- color: orange
min: 0
max: 10
defect:
- information: 'impact: high'
min: 0
max: 0
- information: 'impact: medium'
min: 0
max: 10
- information: 'impact: low'
min: 0
max: 30
84 changes: 42 additions & 42 deletions tests/test_in/coverity_cq.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,46 @@
[
{
"severity": "major",
"description": "Coverity: MISRA C-2012 Declarations and Definitions (MISRA C-2012 Rule 8.5, Required)",
"location": {
"path": "some/path/dummy_uncl.h",
"positions": {
"begin": {
"line": 194,
"column": 14
}
}
},
"fingerprint": "990f3714acdb07ca108f645285bacdf8"
},
{
"severity": "major",
"description": "Coverity: MISRA C-2012 Declarations and Definitions (MISRA C-2012 Rule 8.6, Required)",
"location": {
"path": "some/path/dummy_uncl.c",
"positions": {
"begin": {
"line": 1404,
"column": 14
}
}
},
"fingerprint": "c24f5c885dd07424839f347e7fb0cfd9"
},
{
"severity": "major",
"description": "Coverity: MISRA C-2012 Identifiers (MISRA C-2012 Rule 5.8, Required)",
"location": {
"path": "some/path/dummy_uncl.c",
"positions": {
"begin": {
"line": 923,
"column": 13
}
}
},
"fingerprint": "1f2f1b28535924cd9ab0dc2635aa70c7"
},
{
"severity": "info",
"description": "Coverity: MISRA C-2012 Standard C Environment (MISRA C-2012 Rule 1.2, Advisory)",
Expand Down Expand Up @@ -68,47 +110,5 @@
}
},
"fingerprint": "5dbd93275d026e6b77330c48eda8d964"
},
{
"severity": "major",
"description": "Coverity: MISRA C-2012 Declarations and Definitions (MISRA C-2012 Rule 8.5, Required)",
"location": {
"path": "some/path/dummy_uncl.h",
"positions": {
"begin": {
"line": 194,
"column": 14
}
}
},
"fingerprint": "990f3714acdb07ca108f645285bacdf8"
},
{
"severity": "major",
"description": "Coverity: MISRA C-2012 Declarations and Definitions (MISRA C-2012 Rule 8.6, Required)",
"location": {
"path": "some/path/dummy_uncl.c",
"positions": {
"begin": {
"line": 1404,
"column": 14
}
}
},
"fingerprint": "c24f5c885dd07424839f347e7fb0cfd9"
},
{
"severity": "major",
"description": "Coverity: MISRA C-2012 Identifiers (MISRA C-2012 Rule 5.8, Required)",
"location": {
"path": "some/path/dummy_uncl.c",
"positions": {
"begin": {
"line": 923,
"column": 13
}
}
},
"fingerprint": "1f2f1b28535924cd9ab0dc2635aa70c7"
}
]
30 changes: 24 additions & 6 deletions tests/test_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@

from unittest.mock import patch

from mlx.warnings import warnings_wrapper, WarningsConfigError
from mlx.warnings import exceptions, warnings_wrapper, WarningsConfigError, Finding

TEST_IN_DIR = Path(__file__).parent / 'test_in'
TEST_OUT_DIR = Path(__file__).parent / 'test_out'


class TestIntegration(TestCase):
def setUp(self):
Finding.fingerprints = {}
if not TEST_OUT_DIR.exists():
TEST_OUT_DIR.mkdir()

Expand Down Expand Up @@ -368,10 +369,27 @@ def test_cq_description_format(self, path_cwd_mock):
filename = 'code_quality_format.json'
out_file = str(TEST_OUT_DIR / filename)
ref_file = str(TEST_IN_DIR / filename)
retval = warnings_wrapper([
'--code-quality', out_file,
'--config', 'tests/test_in/config_cq_description_format.json',
'tests/test_in/mixed_warnings.txt',
])
with patch('sys.stdout', new=StringIO()) as fake_output:
retval = warnings_wrapper([
'--code-quality', out_file,
'--config', 'tests/test_in/config_cq_description_format.json',
'tests/test_in/mixed_warnings.txt',
])
output = fake_output.getvalue().splitlines(keepends=False)
self.assertIn("WARNING: Unrecognized classification 'max'", output)
self.assertIn("WARNING: Unrecognized classification 'min'", output)
self.assertEqual(2, retval)
self.assertTrue(filecmp.cmp(out_file, ref_file), '{} differs from {}'.format(out_file, ref_file))

@patch('pathlib.Path.cwd')
def test_polyspace_error(self, path_cwd_mock):
config_file = str(TEST_IN_DIR / 'config_example_polyspace_error.yml')
cq_file = str(TEST_IN_DIR / 'test.json')
with self.assertRaises(exceptions.WarningsConfigError) as context:
warnings_wrapper([
'--code-quality', cq_file,
JasperCraeghs marked this conversation as resolved.
Show resolved Hide resolved
'--config', config_file,
'tests/test_in/mixed_warnings.txt',
])
self.assertEqual(str(context.exception), 'Polyspace checker cannot be combined with other warnings checkers')

1 change: 1 addition & 0 deletions tests/test_polyspace.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

class TestCodeProverWarnings(unittest.TestCase):
def setUp(self):
Finding.fingerprints = {}
self.warnings = WarningsPlugin(verbose=True)
self.dut = self.warnings.activate_checker_name('polyspace')
self.dut.checkers = [
Expand Down