Skip to content

Commit 6d5010d

Browse files
committed
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@gmail.com>
1 parent f51053d commit 6d5010d

2 files changed

Lines changed: 70 additions & 43 deletions

File tree

src/pkgcheck/reporters.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -345,8 +345,8 @@ def from_iter(iterable) -> typing.Generator[Result, None, None]:
345345
yield cls._create(**data)
346346
except (json.decoder.JSONDecodeError, UnicodeDecodeError, DeserializationError) as e:
347347
raise DeserializationError("failed loading") from e
348-
except (KeyError, InvalidResult):
349-
raise DeserializationError("unknown result")
348+
except (KeyError, InvalidResult) as e:
349+
raise DeserializationError("unknown result") from e
350350

351351
def _consume_reports_generator(self) -> T_process_report:
352352
while True:

tests/scripts/test_pkgcheck_scan.py

Lines changed: 68 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,20 @@
1+
import contextlib
2+
import io
13
import os
4+
import pathlib
25
import shlex
36
import shutil
47
import subprocess
5-
import tempfile
68
import textwrap
9+
import typing
710
from collections import defaultdict
11+
from dataclasses import dataclass
812
from functools import partial
913
from io import StringIO
1014
from operator import attrgetter
1115
from unittest.mock import patch
1216

1317
import pytest
14-
from pkgcheck import __title__ as project
15-
from pkgcheck import base
16-
from pkgcheck import checks as checks_mod
17-
from pkgcheck import const, objects, reporters, scan
18-
from pkgcheck.scripts import run
1918
from pkgcore import const as pkgcore_const
2019
from pkgcore.ebuild import atom, restricts
2120
from pkgcore.restrictions import packages
@@ -24,6 +23,12 @@
2423
from snakeoil.formatters import PlainTextFormatter
2524
from snakeoil.osutils import pjoin
2625

26+
from pkgcheck import __title__ as project
27+
from pkgcheck import base, const, objects, reporters, scan
28+
from pkgcheck import checks as checks_mod
29+
from pkgcheck.results import Result
30+
from pkgcheck.scripts import run
31+
2732
from ..misc import Profile
2833

2934

@@ -587,63 +592,85 @@ def _scan_results(self, repo, tmp_path, verbosity):
587592
assert len(results) == len(results_set)
588593
return results_set
589594

590-
def _get_results(self, path: str):
595+
@dataclass
596+
class _expected_data_result:
597+
expected: typing.Iterable[Result]
598+
expected_verbose: typing.Iterable[Result]
599+
600+
def _load_expected_data(self, path: str) -> _expected_data_result:
591601
"""Return the set of result objects from a given json stream file."""
592-
try:
593-
with (self.repos_data / path).open() as f:
594-
return set(reporters.JsonStream.from_iter(f))
595-
except FileNotFoundError:
596-
return set()
597602

598-
def _render_results(self, results, **kwargs):
603+
def boilerplate(path, allow_missing: bool) -> list[Result]:
604+
try:
605+
with path.open() as f:
606+
data = list(reporters.JsonStream.from_iter(f))
607+
608+
uniqued = set(data)
609+
duplicates = [
610+
x for x in data if (False, None) == (x in uniqued, uniqued.discard(x))
611+
]
612+
assert [] == duplicates, f"duplicate results exist in {path!r}"
613+
614+
# Remove this after cleaning the scan/fix logic up to not force duplicate
615+
# renders, and instead just work with a result stream directly.
616+
assert self._render_results(data), f"failed rendering results {data!r}"
617+
return data
618+
619+
except FileNotFoundError:
620+
if not allow_missing:
621+
raise
622+
return []
623+
624+
expected_path = self.repos_data / path / "expected.json"
625+
626+
expected = boilerplate(expected_path, False)
627+
assert expected, f"regular results must always exist if the file exists: {expected_path}"
628+
629+
expected_verbose_path = self.repos_data / path / "expected-verbose.json"
630+
expected_verbose = boilerplate(expected_verbose_path, True)
631+
632+
return self._expected_data_result(expected, expected_verbose=expected_verbose)
633+
634+
def _render_results(self, results, **kwargs) -> str:
599635
"""Render a given set of result objects into their related string form."""
600-
with tempfile.TemporaryFile() as f:
636+
with io.BytesIO() as f:
601637
with reporters.FancyReporter(out=PlainTextFormatter(f), **kwargs) as reporter:
602638
for result in sorted(results):
603639
reporter.report(result)
604-
f.seek(0)
605-
output = f.read().decode()
606-
return output
640+
return f.getvalue().decode()
607641

608642
@pytest.mark.parametrize("repo", repos)
609643
def test_scan_repo(self, repo, tmp_path_factory):
610644
"""Run pkgcheck against test pkgs in bundled repo, verifying result output."""
611-
results = set()
612-
verbose_results = set()
645+
expected_results = set()
613646
scan_results = self._scan_results(repo, tmp_path_factory.mktemp("scan"), verbosity=0)
647+
648+
expected_verbose_results = set()
614649
scan_verbose_results = self._scan_results(repo, tmp_path_factory.mktemp("ver"), verbosity=1)
650+
615651
for check, keywords in self._checks[repo].items():
616652
for keyword in keywords:
617-
# verify the expected results were seen during the repo scans
618-
expected_results = self._get_results(f"{repo}/{check}/{keyword}/expected.json")
619-
assert expected_results, "regular results must always exist"
620-
assert self._render_results(expected_results), "failed rendering results"
621-
results.update(expected_results)
622-
623-
# when expected verbose results exist use them, otherwise fallback to using the regular ones
624-
expected_verbose_results = self._get_results(
625-
f"{repo}/{check}/{keyword}/expected-verbose.json"
626-
)
627-
if expected_verbose_results:
628-
assert self._render_results(expected_verbose_results), (
629-
"failed rendering verbose results"
630-
)
631-
verbose_results.update(expected_verbose_results)
653+
data = self._load_expected_data(f"{repo}/{check}/{keyword}")
654+
expected_results.update(data.expected)
655+
656+
if data.expected_verbose:
657+
expected_verbose_results.update(data.expected_verbose)
632658
else:
633-
verbose_results.update(expected_results)
659+
expected_verbose_results.update(data.expected)
634660

635-
if results != scan_results:
636-
missing = self._render_results(results - scan_results)
637-
unknown = self._render_results(scan_results - results)
661+
if expected_results != scan_results:
662+
missing = self._render_results(expected_results - scan_results)
663+
unknown = self._render_results(scan_results - expected_results)
638664
error = ["unmatched repo scan results:\n\n"]
639665
if missing:
640666
error.append(f"{repo} repo missing expected results:\n{missing}")
641667
if unknown:
642668
error.append(f"{repo} repo unknown results:\n{unknown}")
643669
pytest.fail("\n".join(error), pytrace=False)
644-
if verbose_results != scan_verbose_results:
645-
missing = self._render_results(verbose_results - scan_verbose_results)
646-
unknown = self._render_results(scan_verbose_results - verbose_results)
670+
671+
if expected_verbose_results != scan_verbose_results:
672+
missing = self._render_results(expected_verbose_results - scan_verbose_results)
673+
unknown = self._render_results(scan_verbose_results - expected_verbose_results)
647674
error = ["unmatched verbose repo scan results:\n\n"]
648675
if missing:
649676
error.append(f"{repo} repo missing expected results:\n{missing}")

0 commit comments

Comments
 (0)