Skip to content

Commit fc7906c

Browse files
fix: enhance test_checkers to cover new situations
1 parent 5a831bc commit fc7906c

File tree

2 files changed

+44
-96
lines changed

2 files changed

+44
-96
lines changed

cve_bin_tool/util.py

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -215,22 +215,22 @@ class VersionMatchInfo:
215215
attributes:
216216
matched_filename: bool
217217
matched_contains: bool
218-
versions: list[str]
218+
versions: set[str]
219219
"""
220220

221221
matched_filename: bool
222222
matched_contains: bool
223-
versions: list[str]
223+
versions: set[str]
224224

225225
def __init__(
226226
self,
227227
matched_filename: bool = False,
228228
matched_contains: bool = False,
229-
versions: list[str] = [],
229+
versions: set[str] | None = None,
230230
):
231231
self.matched_filename = matched_filename
232232
self.matched_contains = matched_contains
233-
self.versions = versions or []
233+
self.versions = versions if versions is not None else set()
234234

235235

236236
class VersionInfo(NamedTuple):
@@ -280,24 +280,21 @@ def __missing__(self, key: str) -> list[CVE] | set[str]:
280280

281281
def regex_find(
282282
lines: str, version_patterns: list[Pattern[str]], ignore: list[Pattern[str]]
283-
) -> list[str]:
283+
) -> set[str]:
284284
"""Search a set of lines to find all matches for the given regex"""
285-
versions = list()
285+
versions = set()
286286

287287
for pattern in version_patterns:
288288
version_matches = pattern.finditer(lines)
289289
for match in version_matches:
290-
# before collecting a potential version number, ensure the version string isn't on the ignore list
291-
if not check_ignored(match.string, ignore):
290+
matched_text = match.group(0)
291+
if not check_ignored(matched_text, ignore):
292292
version = match.group(1).strip()
293293
version = version.replace("_", ".").replace("-", ".")
294-
versions.append(version)
294+
versions.add(version)
295295

296-
# if we searched and found no matches, just return a one-element list containing "UNKNOWN"
297-
if not versions:
298-
versions.append("UNKNOWN")
299-
300-
return versions
296+
# return unknown if none found
297+
return versions if versions else {"UNKNOWN"}
301298

302299

303300
def check_ignored(possible_version_string: str, ignore: list[Pattern[str]]) -> bool:

test/test_checkers.py

Lines changed: 33 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -141,86 +141,37 @@ def test_filename_is(self, checker_name, file_name, expected_results):
141141
class MyFakeChecker(Checker):
142142
CONTAINS_PATTERNS: list[str] = []
143143
FILENAME_PATTERNS: list[str] = [r"checker"]
144-
VERSION_PATTERNS = [re.compile(r"mychecker-([0-9]+\.[0-9]+)")]
144+
VERSION_PATTERNS = [r"mychecker-([0-9].[0-9]+)"]
145145
VENDOR_PRODUCT = [("my", "checker")]
146-
IGNORE_PATTERNS = [re.compile(r"mychecker-5\.6")]
147-
148-
def get_versions(self, lines, filename):
149-
"""Processes all lines at once and returns detected versions."""
150-
from cve_bin_tool.util import VersionMatchInfo
151-
152-
result = VersionMatchInfo()
153-
154-
result.matched_filename = any(
155-
p.search(filename) for p in self.FILENAME_PATTERNS
156-
)
157-
158-
content = "\n".join(lines) if isinstance(lines, list) else lines
159-
160-
versions = {
161-
match.group(1)
162-
for pattern in self.VERSION_PATTERNS
163-
for match in pattern.finditer(content)
164-
if not any(
165-
ignore.search(f"mychecker-{match.group(1)}")
166-
for ignore in self.IGNORE_PATTERNS
167-
)
168-
}
169-
170-
result.matched_contains_pattern = bool(versions)
171-
result.versions = versions if versions else {"UNKNOWN"} # Now a set
172-
173-
return result
174-
175-
def test_checker_get_version_multiline(self):
176-
"""Test MyFakeChecker's ability to process multiple lines at once."""
177-
checker = self.MyFakeChecker()
178-
179-
multiline_valid = """
180-
Some other lines.
181-
Consider this version pattern mychecker-5.8.
182-
And this version pattern mychecker-6.0.
183-
Some more lines.
184-
"""
185-
multiline_ignored = """
186-
Some other lines.
187-
Ignore this version pattern mychecker-5.6.
188-
And this version pattern mychecker-5.6 again.
189-
Some more lines.
190-
"""
191-
multiline_mixed = """
192-
Some other lines.
193-
Consider this version pattern mychecker-5.8.
194-
Ignore this version pattern mychecker-5.6.
195-
And this version pattern mychecker-6.0.
196-
Some more lines.
197-
"""
198-
multiline_no_version = """
199-
Some random text.
200-
Nothing that matches a version pattern.
201-
Just some more lines.
202-
"""
203-
multiline_duplicates = """
204-
Some text before.
205-
Detected mychecker-5.8.
206-
Detected mychecker-5.8 again.
207-
Another valid version mychecker-6.0.
208-
Some text after.
209-
"""
210-
211-
result1 = checker.get_versions(multiline_valid, "")
212-
result2 = checker.get_versions(multiline_ignored, "")
213-
result3 = checker.get_versions(multiline_mixed, "")
214-
result4 = checker.get_versions(multiline_no_version, "")
215-
result5 = checker.get_versions(multiline_duplicates, "")
216-
217-
assert result1.versions == {"5.8", "6.0"}
218-
assert result2.versions == {"UNKNOWN"}
219-
assert not result2.matched_contains_pattern
220-
assert not result2.matched_filename
221-
assert result3.versions == {"5.8", "6.0"}
222-
assert "5.6" not in result3.versions
223-
assert result4.versions == {"UNKNOWN"}
224-
assert not result4.matched_contains_pattern
225-
assert not result4.matched_filename
226-
assert result5.versions == {"5.8", "6.0"}
146+
IGNORE_PATTERNS = [r"mychecker-5.6"]
147+
148+
class TestMyFakeChecker:
149+
"""Test suite for MyFakeChecker."""
150+
151+
@pytest.mark.parametrize(
152+
"description, input_text, expected_versions",
153+
[
154+
(
155+
"Multiple valid versions",
156+
"mychecker-5.8\nmychecker-6.0",
157+
{"5.8", "6.0"},
158+
),
159+
("All versions ignored", "mychecker-5.6\nmychecker-5.6", {"UNKNOWN"}),
160+
(
161+
"Mixed valid and ignored versions",
162+
"mychecker-5.8\nmychecker-5.6\nmychecker-6.0",
163+
{"5.8", "6.0"},
164+
),
165+
("No version pattern", "random text", set()),
166+
(
167+
"Duplicate versions",
168+
"mychecker-5.8\nmychecker-5.8\nmychecker-6.0",
169+
{"5.8", "6.0"},
170+
),
171+
],
172+
)
173+
def test_checker_version(self, description, input_text, expected_versions):
174+
"""Test get_versions logic using MyFakeChecker class, ensuring multiple versions are processed correctly."""
175+
checker = TestCheckerVersionParser.MyFakeChecker()
176+
result = checker.get_versions(input_text, "")
177+
assert result.versions == expected_versions, f"{description} failed"

0 commit comments

Comments
 (0)