commit: 6d5010db0ea3a1700cd34d760e3b687ddd0fd942
Author: Brian Harring <ferringb <AT> gmail <DOT> com>
AuthorDate: Mon Nov 24 17:16:34 2025 +0000
Commit: Brian Harring <ferringb <AT> gmail <DOT> com>
CommitDate: Mon Nov 24 17:26:40 2025 +0000
URL:
https://gitweb.gentoo.org/proj/pkgcore/pkgcheck.git/commit/?id=6d5010db
chore: simplify test_scan_repo
This is mostly so it's simpler to deal with since this
was opaque.
Additionally add a missing raise chain since I managed to flush
out that gap while mangling this code.
Signed-off-by: Brian Harring <ferringb <AT> gmail.com>
src/pkgcheck/reporters.py | 4 +-
tests/scripts/test_pkgcheck_scan.py | 109 ++++++++++++++++++++++--------------
2 files changed, 70 insertions(+), 43 deletions(-)
diff --git a/src/pkgcheck/reporters.py b/src/pkgcheck/reporters.py
index 6171cf75..0a6119cf 100644
--- a/src/pkgcheck/reporters.py
+++ b/src/pkgcheck/reporters.py
@@ -345,8 +345,8 @@ class JsonStream(StreamReporter):
yield cls._create(**data)
except (json.decoder.JSONDecodeError, UnicodeDecodeError,
DeserializationError) as e:
raise DeserializationError("failed loading") from e
- except (KeyError, InvalidResult):
- raise DeserializationError("unknown result")
+ except (KeyError, InvalidResult) as e:
+ raise DeserializationError("unknown result") from e
def _consume_reports_generator(self) -> T_process_report:
while True:
diff --git a/tests/scripts/test_pkgcheck_scan.py
b/tests/scripts/test_pkgcheck_scan.py
index ca8f37e5..b282d3da 100644
--- a/tests/scripts/test_pkgcheck_scan.py
+++ b/tests/scripts/test_pkgcheck_scan.py
@@ -1,21 +1,20 @@
+import contextlib
+import io
import os
+import pathlib
import shlex
import shutil
import subprocess
-import tempfile
import textwrap
+import typing
from collections import defaultdict
+from dataclasses import dataclass
from functools import partial
from io import StringIO
from operator import attrgetter
from unittest.mock import patch
import pytest
-from pkgcheck import __title__ as project
-from pkgcheck import base
-from pkgcheck import checks as checks_mod
-from pkgcheck import const, objects, reporters, scan
-from pkgcheck.scripts import run
from pkgcore import const as pkgcore_const
from pkgcore.ebuild import atom, restricts
from pkgcore.restrictions import packages
@@ -24,6 +23,12 @@ from snakeoil.fileutils import touch
from snakeoil.formatters import PlainTextFormatter
from snakeoil.osutils import pjoin
+from pkgcheck import __title__ as project
+from pkgcheck import base, const, objects, reporters, scan
+from pkgcheck import checks as checks_mod
+from pkgcheck.results import Result
+from pkgcheck.scripts import run
+
from ..misc import Profile
@@ -587,63 +592,85 @@ class TestPkgcheckScan:
assert len(results) == len(results_set)
return results_set
- def _get_results(self, path: str):
+ @dataclass
+ class _expected_data_result:
+ expected: typing.Iterable[Result]
+ expected_verbose: typing.Iterable[Result]
+
+ def _load_expected_data(self, path: str) -> _expected_data_result:
"""Return the set of result objects from a given json stream file."""
- try:
- with (self.repos_data / path).open() as f:
- return set(reporters.JsonStream.from_iter(f))
- except FileNotFoundError:
- return set()
- def _render_results(self, results, **kwargs):
+ def boilerplate(path, allow_missing: bool) -> list[Result]:
+ try:
+ with path.open() as f:
+ data = list(reporters.JsonStream.from_iter(f))
+
+ uniqued = set(data)
+ duplicates = [
+ x for x in data if (False, None) == (x in uniqued,
uniqued.discard(x))
+ ]
+ assert [] == duplicates, f"duplicate results exist in
{path!r}"
+
+ # Remove this after cleaning the scan/fix logic up to not
force duplicate
+ # renders, and instead just work with a result stream
directly.
+ assert self._render_results(data), f"failed rendering
results {data!r}"
+ return data
+
+ except FileNotFoundError:
+ if not allow_missing:
+ raise
+ return []
+
+ expected_path = self.repos_data / path / "expected.json"
+
+ expected = boilerplate(expected_path, False)
+ assert expected, f"regular results must always exist if the file
exists: {expected_path}"
+
+ expected_verbose_path = self.repos_data / path /
"expected-verbose.json"
+ expected_verbose = boilerplate(expected_verbose_path, True)
+
+ return self._expected_data_result(expected,
expected_verbose=expected_verbose)
+
+ def _render_results(self, results, **kwargs) -> str:
"""Render a given set of result objects into their related string
form."""
- with tempfile.TemporaryFile() as f:
+ with io.BytesIO() as f:
with reporters.FancyReporter(out=PlainTextFormatter(f), **kwargs)
as reporter:
for result in sorted(results):
reporter.report(result)
- f.seek(0)
- output = f.read().decode()
- return output
+ return f.getvalue().decode()
@pytest.mark.parametrize("repo", repos)
def test_scan_repo(self, repo, tmp_path_factory):
"""Run pkgcheck against test pkgs in bundled repo, verifying result
output."""
- results = set()
- verbose_results = set()
+ expected_results = set()
scan_results = self._scan_results(repo,
tmp_path_factory.mktemp("scan"), verbosity=0)
+
+ expected_verbose_results = set()
scan_verbose_results = self._scan_results(repo,
tmp_path_factory.mktemp("ver"), verbosity=1)
+
for check, keywords in self._checks[repo].items():
for keyword in keywords:
- # verify the expected results were seen during the repo scans
- expected_results =
self._get_results(f"{repo}/{check}/{keyword}/expected.json")
- assert expected_results, "regular results must always exist"
- assert self._render_results(expected_results), "failed
rendering results"
- results.update(expected_results)
-
- # when expected verbose results exist use them, otherwise
fallback to using the regular ones
- expected_verbose_results = self._get_results(
- f"{repo}/{check}/{keyword}/expected-verbose.json"
- )
- if expected_verbose_results:
- assert self._render_results(expected_verbose_results), (
- "failed rendering verbose results"
- )
- verbose_results.update(expected_verbose_results)
+ data = self._load_expected_data(f"{repo}/{check}/{keyword}")
+ expected_results.update(data.expected)
+
+ if data.expected_verbose:
+ expected_verbose_results.update(data.expected_verbose)
else:
- verbose_results.update(expected_results)
+ expected_verbose_results.update(data.expected)
- if results != scan_results:
- missing = self._render_results(results - scan_results)
- unknown = self._render_results(scan_results - results)
+ if expected_results != scan_results:
+ missing = self._render_results(expected_results - scan_results)
+ unknown = self._render_results(scan_results - expected_results)
error = ["unmatched repo scan results:\n\n"]
if missing:
error.append(f"{repo} repo missing expected
results:\n{missing}")
if unknown:
error.append(f"{repo} repo unknown results:\n{unknown}")
pytest.fail("\n".join(error), pytrace=False)
- if verbose_results != scan_verbose_results:
- missing = self._render_results(verbose_results -
scan_verbose_results)
- unknown = self._render_results(scan_verbose_results -
verbose_results)
+
+ if expected_verbose_results != scan_verbose_results:
+ missing = self._render_results(expected_verbose_results -
scan_verbose_results)
+ unknown = self._render_results(scan_verbose_results -
expected_verbose_results)
error = ["unmatched verbose repo scan results:\n\n"]
if missing:
error.append(f"{repo} repo missing expected
results:\n{missing}")