Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
26 changes: 14 additions & 12 deletions tests/_dependency_gates.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,10 +115,11 @@
'ambiguous_satisfactions', 'describe_ambiguous_satisfaction',
]

#: The workflow holding every job that runs :program:`pytest`, and the only one
#: that runs it at all. Five of the other seven install ``.[all]`` somewhere --
#: a docs build, a conda recipe, a vendor crawl, the lint pass, and the release
#: packaging workflow -- and none of them invokes the suite;
#: The workflow holding every blocking job that runs :program:`pytest`.
#: :file:`experimental.yml` runs the unit tier as well, on legs nothing waits on
#: (#1732), and is not read here. Five other workflows install ``.[all]``
#: somewhere -- a docs build, a conda recipe, a vendor crawl, the lint pass,
#: and the release packaging workflow -- and none of them invokes the suite;
#: :file:`python-compatibility.yml` installs a bare ``.`` and only compiles and
#: imports, and :file:`codeql-analysis.yml` installs nothing explicitly at all
#: (CodeQL's own autobuild step). That is exactly why this module keys on *jobs that
Expand Down Expand Up @@ -200,7 +201,7 @@
# distribution, so ``beautifulsoup4`` alone does not provide it. That
# distinction is the whole reason ``HAS_CRAWLER_DEPS`` is satisfied in CI
# and ``HAS_VENDOR_DEPS`` is not: the ``test`` extra carries plain
# ``beautifulsoup4``, and only ``vendor`` and ``all`` carry
# ``beautifulsoup4``, and only ``vendor`` and ``dev`` carry
# ``beautifulsoup4[html5lib]``. The second alternative below is not a
# second *distribution* -- pyproject.toml never declares bare
# ``html5lib`` -- so this is one distribution reached two ways, not the
Expand Down Expand Up @@ -1156,8 +1157,8 @@ def flag_requirements() -> 'dict[tuple[str, str], frozenset[str]]':
every module but one, and in
:file:`tests/foundation/engines/test_runtime_engines.py` it names those four
plus ``dpkt``, ``scapy`` and ``pyshark``. Keyed on the name alone, that one
module's requirements would be demanded of the 130 others, or the 130 would
excuse it.
module's requirements would be demanded of every other module that gates on
it, or they would excuse it.

A module that gates on a flag it imports resolves through the import, so
``tests/integration/test_cli_subprocess.py`` gets ``HAS_EMOJI``'s
Expand Down Expand Up @@ -1222,10 +1223,11 @@ def gated_scopes() -> 'tuple[Gate, ...]':
scan: ``python_files`` in :file:`pyproject.toml` is what pytest collects, so
a gate in a helper module gates nothing. Class-level and method-level
decorators are both collected, and the class-level ones are the majority --
``HAS_DPKT`` reaches 20 methods through 6 class decorators and 8 through a
method decorator -- counted by exact-match AST identifiers the way this
function itself matches them, not by a substring search, which would
(elsewhere) fold ``HAS_PYPCAP`` together with ``HAS_PYPCAPFILE``.
when #745 was fixed, ``HAS_DPKT`` reached 20 methods through 6 class
decorators and 8 through a method decorator -- counted by exact-match AST
identifiers the way this function itself matches them, not by a substring
search, which would (elsewhere) fold ``HAS_PYPCAP`` together with
``HAS_PYPCAPFILE``.

"""
gates = [] # type: list[Gate]
Expand Down Expand Up @@ -1406,7 +1408,7 @@ def _engine_matrix_variants(name: 'str', section: 'str') -> 'Optional[tuple[Job,
def pytest_jobs(workflow: 'Optional[pathlib.Path]' = None) -> 'tuple[Job, ...]':
"""The jobs of ``workflow`` that run :program:`pytest`.

Keyed on running the suite, not on holding an install line: seven other
Keyed on running the suite, not on holding an install line: five other
workflows install ``.[all]`` somewhere, three of them as ``.[all,dev]`` --
which does carry ``pypcapfile``, through the ``dev`` extra #910 added when
it narrowed ``all`` to core addons only -- and never invoke
Expand Down
2 changes: 1 addition & 1 deletion tests/_support.py
Original file line number Diff line number Diff line change
Expand Up @@ -960,7 +960,7 @@ def purge_modules(prefixes: Iterable[str]) -> None:
change another test can observe: the next one that wants it imports it again and
gets an *equivalent* thing from the same source. Binding something *else* over
the name is what cannot be undone by re-importing, so restoration is owed by the
helpers that bind, not by this one. Making ~120 call sites pay for a restore none
helpers that bind, not by this one. Making every call site pay for a restore none
of them needs would also cost a re-import each, which
:func:`tests.conftest.pytest_sessionstart` exists to avoid.

Expand Down
10 changes: 5 additions & 5 deletions tests/_tiers.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,8 +204,8 @@
'Exception', 'BaseException',
})

#: ``try`` statement node types. :class:`ast.TryStar` is 3.11+, and CI still runs
#: 3.8-3.10 (#1633), so it is looked up rather than named.
#: ``try`` statement node types. :class:`ast.TryStar` is 3.11+, and CI runs
#: older interpreters as well (#1633), so it is looked up rather than named.
_TRY_NODES = (ast.Try,) + ((ast.TryStar,) if hasattr(ast, 'TryStar') else ()) # type: ignore[attr-defined]


Expand Down Expand Up @@ -887,9 +887,9 @@ def fixture_tier_paths() -> 'tuple[str, ...]':
added by :func:`skip_idiom_test_ids` rather than by
:func:`skip_idiom_modules` directly, so that pulling in one skip-idiom test
does not also pull in every unrelated method the same module happens to
hold. Without that, the two files this suite has today would add roughly a
hundred tests back into this selection to reach the two or three that
actually need it.
hold. Without that, the skip-idiom modules would add every one of their
tests back into this selection -- well over a hundred -- to reach the
handful that actually need it.

This is deliberately *not* "the complement of :func:`is_unit_tier`"
expressed as a single predicate the way :func:`is_unit_tier` itself is: the
Expand Down
21 changes: 12 additions & 9 deletions tests/const/test_const_apptype_split_unit.py
Original file line number Diff line number Diff line change
Expand Up @@ -223,10 +223,12 @@ def test_repr_and_str_grow_an_alias_suffix_only_when_there_is_one(self) -> None:

The suffix is display-only: it never reaches ``_value_``, which is the
live lookup key in ``_value2member_map_`` and is built once when the
class is created -- see ``test_the_new_dunders_are_byte_identical_to_the_percent_form``
and ``test_every_member_renders_its_own_registrys_transport_protocol``
for the sweep over all 12,391 members that pins this for every one of
them, aliased or not.
class is created -- see
``test_every_member_renders_its_own_registrys_transport_protocol`` for
the sweep over all 12,391 members that pins this for every one of them,
aliased or not, and
``test_the_new_dunders_are_byte_identical_to_the_percent_form`` for the
sample #1062 formats against the pre-#798 form.
"""
from pcapkit.const.reg.apptype import TCP

Expand Down Expand Up @@ -390,7 +392,7 @@ def test_register_alias_refuses_a_port_with_no_canonical_member_yet(self) -> Non
"""Aliasing names a second service on a port that already has one.

A port with nothing there yet is what the generator and ``get``'s own
mint-on-miss are for, not this -- so this refuses rather than quietly
fallback on a miss are for, not this -- so this refuses rather than quietly
becoming the port's first and only member.
"""
from pcapkit.const.reg.apptype import TCP
Expand Down Expand Up @@ -483,7 +485,8 @@ def test_a_service_name_is_not_a_port_lookup(self) -> None:
by transport protocol, so a name never matched and
``AppType.get('ssh')`` returned a **new** member with port ``-1`` instead
of the one at 22. Nothing in :mod:`pcapkit` resolves a service by name, so
it now raises; #734 stays open for whether a real name lookup is wanted.
it now raises; #734 was closed on that, with the name lookup removed
rather than repaired.
"""
from pcapkit.const.reg.apptype import TCP

Expand Down Expand Up @@ -567,7 +570,7 @@ def test_get_rejects_an_out_of_range_port_as_the_constructor_does(self) -> None:
cls.__members__)

# Paid for by narrowing nothing: a valid but unassigned port is what the
# mint is *for*, and it still answers with one.
# fallback member is *for*, and it still answers with one.
minted = AppType.get(59000, proto=TransportProtocol.tcp)
self.addCleanup(self._purge_member, TCP, 'PORT_59000_tcp', 59000)
self.assertEqual(minted.svc, 'unknown')
Expand Down Expand Up @@ -601,8 +604,8 @@ def test_a_span_on_two_transports_answers_each_with_its_own_row(self) -> None:
self.assertIs(resolved.proto, cls.__transport__)

# A span IANA assigns to TCP and UDP assigns nothing to SCTP, so the third
# registry mints rather than inheriting the TCP row -- which it did, as
# ``<SCTP.x11: 6010 [tcp]>``.
# registry answers with an ``unknown`` member of its own rather than
# inheriting the TCP row -- which it did, as ``<SCTP.x11: 6010 [tcp]>``.
resolved = AppType.get(6010, proto='sctp')
self.addCleanup(self._purge_member, SCTP, 'PORT_6010_sctp', 6010)
self.assertEqual(resolved.svc, 'unknown')
Expand Down
3 changes: 2 additions & 1 deletion tests/const/test_const_enum_builtin_parity.py
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,8 @@ def test_the_sweep_size_is_pinned(self) -> None:
# 112 became 114 with GitHub issue #880's ngap.ProcedureCode and
# ngap.ProtocolIE, moved onto EnumRegistry from hand-rolled IntEnum
# classes in pcapkit.protocols.application.ngap -- two more IntEnum
# registries, two more modules, no change to the flag or str counts.
# registries, two more modules, no change to the flag or str counts --
# and the sum in tests.const.test_const_enum_get became 120 with them.
self.assertEqual(len(ints), 114)
self.assertEqual(len(flags), 6)
self.assertEqual(len(strs), 10)
Expand Down
4 changes: 2 additions & 2 deletions tests/const/test_const_enum_get.py
Original file line number Diff line number Diff line change
Expand Up @@ -475,8 +475,8 @@ def test_the_vendor_template_still_emits_the_fix(self) -> None:

GitHub issue #775's tier 3 moved #584's fix off the per-file generated
``get()`` entirely: it now lives permanently in
:meth:`~pcapkit.corekit.enum.EnumRegistry.get`, which every one of the
105 default-template registries *inherits* rather than copies, so
:meth:`~pcapkit.corekit.enum.EnumRegistry.get`, which every
default-template registry *inherits* rather than copies, so
there is no longer a ``get()`` block here for a regeneration to drop
the fix from -- the block this test used to extract and compare no
longer exists in either the template's output or the generated
Expand Down
33 changes: 16 additions & 17 deletions tests/const/test_const_enum_no_mint.py
Original file line number Diff line number Diff line change
Expand Up @@ -1045,9 +1045,9 @@ def is_manufactured(name_arg: 'Optional[ast.expr]') -> 'bool':
# safe one (a false positive is loud and gets a fixture; a false
# negative ships quietly), and no real call site under
# ``pcapkit/const``/``pcapkit/vendor`` is affected either way
# (measured: the sweep stays at 1012/0). It genuinely does over-flag:
# ``value.upper()`` alone is exempt (it is the receiver case just
# above), but the exact same expression as an *argument* --
# (measured at round 5: the sweep stayed at 1012/0). It genuinely
# does over-flag: ``value.upper()`` alone is exempt (it is the
# receiver case just above), but the exact same expression as an *argument* --
# ``str(value.upper())``, ``helper(value.upper())`` -- flags, so
# wrapping an already-exempt transform in one more call changes the
# verdict. ``NAMES.get(value, 'unknown')`` flags while the
Expand Down Expand Up @@ -1346,7 +1346,7 @@ def test_every_unregistered_member_call_passes_a_non_manufactured_name(self) ->
# and the one ``super()._unregistered_member(...)`` forward its own
# override makes -- 768 more, in one file, for 1012 total. #775's
# final round then added the 52 on EtherType and the 1 on Socket --
# 53 more, for 1065 total measured on this tree.
# 53 more, for 1065 total when that round landed.
self.assertGreaterEqual(call_count, 1065,
f'expected at least 1065 _unregistered_member call sites, found {call_count}')
# And that the exemption is actually earning its keep, rather than a
Expand Down Expand Up @@ -1882,16 +1882,15 @@ class BespokeOpenVocabularyUnmintConvertedTests(unittest.TestCase):
converted, since the owner's reasoning names ``get`` explicitly and
leaving it minting while ``_missing_`` did not would have been a
direct contradiction. ``Command``/``Method``'s ``_unregistered_member``
override canonicalises the constructed value to the same upper-case
``name`` used for the lookup (rather than the caller's incidental input
casing), which is also what makes ``get('frob')`` and ``get('FROB')``
compare *equal* even though, with nothing cached any more, they can
never again be *identical* -- see the two production regression tests
this forced: ``tests/protocols/application/test_ftp_unit.py::
FTPTestCase::test_command_get_is_case_insensitive`` and
``tests/protocols/application/test_http_unit.py::HTTPTestCase::
test_method_get_is_case_insensitive``, both updated from ``assertIs`` to
``assertEqual`` + ``assertIsNot`` for exactly this reason.
override canonicalises the member's *name* to upper case and keeps the
caller's own casing as its value, so ``get('frob')`` and ``get('FROB')``
are unequal, and a repeated ``get('frob')`` is equal but, with nothing
cached any more, never again *identical* -- see the production
regression test this forced,
``tests/protocols/application/test_ftp_unit.py::FTPUnitTests::test_command_get_is_case_insensitive``,
which pins exactly that with ``assertEqual``, ``assertIsNot`` and
``assertNotEqual``. Its HTTP twin was replaced under #896 by
``tests/protocols/application/test_http_unit.py::HTTPUnitTests::test_method_get_is_now_case_sensitive``.

"""

Expand Down Expand Up @@ -2250,7 +2249,7 @@ class BespokeGetUnchangedTests(unittest.TestCase):
:class:`Method` used to resolve case-insensitively the same way (#583),
but GitHub issue #896 retired that: RFC 9110 Section 9.1 makes the HTTP
method token case-sensitive, unlike FTP's command codes (RFC 959 Section
4.1), so ``Method.get('Get')`` no longer returns :attr:`Method.GET` --
5.3), so ``Method.get('Get')`` no longer returns :attr:`Method.GET` --
see ``test_method_get_is_now_case_sensitive`` below, which replaces the
case-insensitive pin this class used to carry for it. ``Method`` still
keeps its own ``get()`` rather than the base's, because it still needs to
Expand Down Expand Up @@ -2609,8 +2608,8 @@ def test_apptype_get_dispatches_via_proto_without_minting(self) -> None:
def test_apptype_unrecognised_proto_is_still_refused(self) -> None:
"""A ``proto`` naming no registry at all -- not one of the two real
collision cases ``auto()`` introduced, just an ordinary invalid value
-- is still refused by :meth:`AppType._dispatch`, unaffected by this
PR. (Deliberately not a composite like ``tcp | udp``: under
-- is still refused by :meth:`AppType._dispatch`, unaffected by
#874. (Deliberately not a composite like ``tcp | udp``: under
``auto()`` that now equals ``sctp`` numerically and dispatches
there rather than raising, which is the one accepted, explicitly
untested consequence of the ``auto()`` change -- see
Expand Down
13 changes: 7 additions & 6 deletions tests/const/test_const_linktype_209_unit.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,13 +76,13 @@
#: parse its fixture. Spelled exactly as
#: :data:`tests.vendor.test_request_prompt_unit.VENDOR_DEPS` so this file reaches
#: the **existing** ``HAS_VENDOR_DEPS`` dependency gate rather than minting a new
#: one -- ``tests/_dependency_gates.py:315`` already accounts for that gate, with
#: ``dark={'test': ('html5lib',), 'gate': ('html5lib',)}``, and ``engine-tests``
#: closes it by installing the ``vendor`` extra.
#: one -- its entry in :data:`tests._dependency_gates.DEPENDENCY_GATE_EXCLUSIONS`
#: already accounts for that gate, with
#: ``dark={'test': ('html5lib',), 'gate': ('html5lib',)}``.
#:
#: ``html5lib`` is the one that is actually missing on ``test``: ``requests`` and
#: ``bs4`` have shipped in the ``test`` extra since #507, but only
#: ``beautifulsoup4[html5lib]`` -- the ``vendor`` and ``all`` extras -- provides a
#: ``beautifulsoup4[html5lib]`` -- the ``vendor`` and ``dev`` extras -- provides a
#: parser (``pyproject.toml:234``, and the note at ``:313-320`` saying so
#: deliberately).
VENDOR_DEPS = ('requests', 'bs4', 'html5lib')
Expand All @@ -92,8 +92,9 @@
#: rather than making the whole unit tier depend on the crawlers'.
#:
#: Consequence worth knowing: :class:`LinkTypeGeneratorLegacyOrderingTests` is the
#: root-cause pin, and it runs only where the ``vendor`` extra is installed --
#: ``engine-tests`` per-PR, and locally. :class:`LinkType209ConstResolutionTests`
#: root-cause pin, and it runs only where the ``vendor`` extra is installed,
#: which no CI job does since #849 -- so locally only.
#: :class:`LinkType209ConstResolutionTests`
#: needs no parser and so still guards the reported symptom everywhere.
HAS_VENDOR_DEPS = all(importlib.util.find_spec(name) is not None for name in VENDOR_DEPS)

Expand Down
12 changes: 8 additions & 4 deletions tests/const/test_const_str_payload_870_unit.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,14 @@
comparison of a :class:`~pcapkit.const.http.method.Method` member against its
own wire string now succeeds where it used to fail silently (no exception --
just an unexpected :data:`False`). Nothing under :mod:`pcapkit.protocols`
compared a member this way before the fix (the one caller,
:meth:`pcapkit.protocols.application.httpv1.HTTP._read_http_header`, only ever
reads ``.value`` indirectly through :meth:`~pcapkit.const.http.method.Method.
get`, never ``str()`` or ``==`` against the member itself), so the change is
compared a member this way before the fix (the one caller of
:meth:`~pcapkit.const.http.method.Method.get`,
:meth:`pcapkit.protocols.application.httpv1.HTTP._read_start_line`, reached
through :meth:`~pcapkit.protocols.application.httpv1.HTTP._read_http_header`
and :meth:`~pcapkit.protocols.application.httpv1.HTTP.make`, only builds a
member from the wire string, and
:meth:`~pcapkit.protocols.application.httpv1.HTTP._make_start_line` reads
``.value``; neither calls ``str()`` or ``==`` on the member itself), so the change is
observable only to external callers and to this module's own dunders
(``__repr__``, which reads ``_value_`` and was already correct).

Expand Down
13 changes: 7 additions & 6 deletions tests/corekit/test_enum_get_exception_provenance_923_unit.py
Original file line number Diff line number Diff line change
Expand Up @@ -239,10 +239,11 @@ def test_nothing_is_minted_on_either_path(self) -> 'None':
class BaseGetQuietnessTests(unittest.TestCase):
"""The name miss is raised with ``quiet=True``, and that is load-bearing.

:meth:`~pcapkit.const.http.method.Method.get` catches it in order to mint,
so a loud error there would put one :data:`logging.CRITICAL` record on the
logger -- and set :data:`sys.tracebacklimit` to ``0`` process-wide -- for
every *successful* ``Method.get`` call that mints. That is the GitHub issue
:meth:`~pcapkit.const.http.method.Method.get` catches it in order to build
an unregistered member, so a loud error there would put one
:data:`logging.CRITICAL` record on the logger -- and, until #983, set
:data:`sys.tracebacklimit` to ``0`` process-wide -- for every *successful*
``Method.get`` call that misses. That is the GitHub issue
#362 defect :class:`~pcapkit.utilities.exceptions.BaseError` documents
``quiet`` for, and :mod:`pcapkit.protocols.protocol` states the same rule
inline: *"A pcapkit exception here would log at CRITICAL for something that
Expand Down Expand Up @@ -275,8 +276,8 @@ def test_a_name_miss_leaves_tracebacklimit_alone(self) -> 'None':
self.assertFalse(hasattr(sys, 'tracebacklimit'))

def test_the_minting_override_stays_silent_end_to_end(self) -> 'None':
"""The call this is actually for: a ``Method.get`` that mints is a
successful call and must emit nothing at all."""
"""The call this is actually for: a ``Method.get`` that misses and builds
an unregistered member is a successful call and must emit nothing at all."""
from pcapkit.const.http.method import Method

with capture(logger) as recorder:
Expand Down
Loading
Loading