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
2 changes: 1 addition & 1 deletion tests/_dependency_gates.py
Original file line number Diff line number Diff line change
Expand Up @@ -1392,7 +1392,7 @@ def pytest_jobs(workflow: 'Optional[pathlib.Path]' = None) -> 'tuple[Job, ...]':
def job_reaches(job: 'Job', gate: 'Gate') -> 'bool':
"""Whether ``job``'s selection would collect the tests ``gate`` guards.

The five selection shapes are answered five ways, and none of them
Each selection shape is answered its own way, and none of them
reimplements the workflow's own list:

* ``'whole-suite'`` reaches everything under :file:`tests/`.
Expand Down
11 changes: 6 additions & 5 deletions tests/_tiers.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
# -*- coding: utf-8 -*-
"""The test suite's tier rule, and the machinery that enforces it.

The suite runs in two tiers, and the split is a property of a module's *path*
rather than of the command that happens to collect it:
The suite is split into tiers by what a module may read, and the split is a
property of a module's *path* rather than of the command that happens to collect
it:

=================================== ==========================================
Tier Modules
Expand Down Expand Up @@ -50,8 +51,8 @@
``ALL``, on every leg, or ``LATEST``, on ``latest`` alone? ``ALL`` is opt-in:
a module is in it only when it says so with ``__tier__ = 'ALL'``
(:func:`declared_tier`), and :data:`DEFAULT_TIER`, ``LATEST``, otherwise.
:func:`all_tier_paths` and :func:`latest_tier_paths` list the two tiers; every
leg but ``latest`` leaves the second out. See "The curated ``ALL`` tier" below
:func:`all_tier_paths` and :func:`latest_tier_paths` list them; every
leg but ``latest`` leaves the ``LATEST`` one out. See "The curated ``ALL`` tier" below
for which modules opt in.
* :func:`is_project_pin` and :func:`project_pin_paths` -- which
:file:`tests/project` modules give one answer on every interpreter, and so run
Expand All @@ -68,7 +69,7 @@
its own copy of the selection: the job calls this module at run time (``python
-c "from tests._tiers import fixture_tier_paths; ..."``, see
:data:`FIXTURE_TIER_SELECTOR`) instead of spelling out ``tests/integration``
and the two globs itself. That closes the same gap :data:`UNIT_TIER_SELECTION`
and the globs itself. That closes the same gap :data:`UNIT_TIER_SELECTION`
leaves open in the other direction: a workflow that asks this module for the
answer cannot drift from it, whereas one that repeats the answer as literal
flags always can. See :func:`fixture_tier_paths`'s docstring for why the
Expand Down
6 changes: 3 additions & 3 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -253,8 +253,8 @@ def restore_module_table() -> 'Iterator[None]':
Issue #660 is what that costs. A stand-in ``ProtocolBase`` that is not
:class:`~typing.Generic` stayed bound after the test that installed it, and
the next test to import :mod:`pcapkit` died on ``TypeError: type
'ProtocolBase' is not subscriptable`` at
``pcapkit/protocols/misc/pcap/frame.py:69`` -- a run of tests in
'ProtocolBase' is not subscriptable`` at the :class:`Frame` class statement
in :mod:`pcapkit.protocols.misc.pcap.frame` -- a run of tests in
:mod:`tests.project`, and only when the polluting file happened to be
collected first. Several files turned out to leak this way, one of
which -- :mod:`tests.cli.test_main` -- did not import :mod:`tests._support`
Expand Down Expand Up @@ -523,7 +523,7 @@ def pytest_collection_modifyitems(session: 'pytest.Session', config: 'pytest.Con
#: shared hold (spanning the whole test, including the blocking
#: ``subprocess.run``) would wait on an inner exclusive request that cannot be
#: granted until the outer test finishes: the same deadlock shape as above, one
#: level removed. Today it never selects either; a future change to that
#: level removed. It selects neither; a future change to that
#: selection should keep it that way, or add the module in question here too.
#: The nested run's own *shared* holds are a different matter, and
#: :data:`TIER_GUARD_HELD_ENV` covers them.
Expand Down
2 changes: 1 addition & 1 deletion tests/const/test_const_apptype_split_unit.py
Original file line number Diff line number Diff line change
Expand Up @@ -674,7 +674,7 @@ def test_every_transport_named_span_is_claimed_by_one_registry(self) -> None:
``cls.__transport__`` claims nothing, since IANA's unassigned and reserved
markers belong to whichever registry was asked. Such a branch answered
``undefined`` until GitHub issue #2048, which made it answer with the
asking registry's own transport, so none answers ``undefined`` now.
asking registry's own transport, so none answers ``undefined``.

"Every branch" is checked against the same source parsed with :mod:`ast`:
the pattern has to find one branch per ``_unregistered_member`` call in
Expand Down
2 changes: 1 addition & 1 deletion tests/const/test_const_ethertype_862_unit.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ def test_both_ranges_still_render_with_their_own_body(self) -> None:
class EtherTypeGeneratorGeneralOrderingTests(unittest.TestCase):
"""Pins :meth:`~pcapkit.vendor.reg.ethertype.EtherType._insert_range` itself.

#862's own pair is the only containment among the 56 ranges in today's
#862's own pair is the only containment among the ranges in the
committed file, so this exercises the general rule -- narrower range
before any wider range that contains it -- against synthetic nested
ranges the live registry does not (yet) happen to contain.
Expand Down
4 changes: 2 additions & 2 deletions tests/const/test_const_linktype_209_unit.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,8 @@
#: ``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 ``dev`` extras -- provides a
#: parser (``pyproject.toml:238``, and the note at ``:325-332`` saying so
#: deliberately).
#: parser (their entries in :file:`pyproject.toml`, and the ``test`` extra's comment
#: on ``beautifulsoup4`` saying so deliberately).
VENDOR_DEPS = ('requests', 'bs4', 'html5lib')

#: Whether all of :data:`VENDOR_DEPS` are importable. Guarded the way
Expand Down
4 changes: 2 additions & 2 deletions tests/corekit/test_fields_bytearray_pack_2004_unit.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
the ``s`` and ``p`` formats, but PyPy's takes :obj:`bytes` alone and raises
``TypeError: expected bytes, got bytearray object``, so a :obj:`bytearray` value
packed by :meth:`Field.pack <pcapkit.corekit.fields.field.Field.pack>` failed on
PyPy. The field now hands :func:`struct.pack` a :obj:`bytes` copy.
PyPy. The field hands :func:`struct.pack` a :obj:`bytes` copy.

The PyPy behaviour is reproduced on any interpreter with a :mod:`struct`
stand-in that refuses a :obj:`bytearray`, as PyPy's does. The real
Expand Down Expand Up @@ -114,7 +114,7 @@ def test_bytearray_output_matches_bytes(self) -> None:

def test_refused_values_stay_refused(self) -> None:
# CPython raises struct.error for these and PyPy TypeError; neither may
# start packing because a bytearray now does.
# start packing because a bytearray does.
for label, field in self._fields().items():
for value in (memoryview(OCTETS), True, OCTETS.decode('latin-1'), list(OCTETS)):
with self.subTest(field=label, value=type(value).__name__):
Expand Down
16 changes: 8 additions & 8 deletions tests/corekit/test_fields_copy_dispatch_unit.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ def assertCallReachesCopyDunderOnly(self, field: 'FieldBase[Any]') -> None:
self.assertIsInstance(new_field, type(field))

def test_field_base_call_field_py_294(self) -> None:
""":meth:`FieldBase.__call__` (``field.py:274``), reached via :class:`NoValueField`.
""":meth:`FieldBase.__call__`, reached via :class:`NoValueField`.

:class:`~pcapkit.corekit.fields.misc.NoValueField` is the one concrete
class in this package that never overrides ``__call__``, so it is the
Expand All @@ -102,41 +102,41 @@ class in this package that never overrides ``__call__``, so it is the
self.assertCallReachesCopyDunderOnly(NoValueField())

def test_field_call_field_py_579(self) -> None:
""":meth:`Field.__call__` (``field.py:580``)."""
""":meth:`Field.__call__`."""
from pcapkit.corekit.fields.field import Field

self.assertCallReachesCopyDunderOnly(Field(length=4))

def test_list_field_call_collections_py_84(self) -> None:
""":meth:`ListField.__call__` (``collections.py:124``)."""
""":meth:`ListField.__call__`."""
from pcapkit.corekit.fields.collections import ListField

self.assertCallReachesCopyDunderOnly(ListField(length=4))

def test_conditional_field_call_misc_py_148(self) -> None:
""":meth:`ConditionalField.__call__` (``misc.py:150``)."""
""":meth:`ConditionalField.__call__`."""
from pcapkit.corekit.fields.field import Field
from pcapkit.corekit.fields.misc import ConditionalField

field = ConditionalField(field=Field(length=1), condition=lambda packet: True)
self.assertCallReachesCopyDunderOnly(field)

def test_payload_field_call_misc_py_299(self) -> None:
""":meth:`PayloadField.__call__` (``misc.py:351``)."""
""":meth:`PayloadField.__call__`."""
from pcapkit.corekit.fields.misc import PayloadField

self.assertCallReachesCopyDunderOnly(PayloadField(length=4))

def test_switch_field_call_misc_py_427(self) -> None:
""":meth:`SwitchField.__call__` (``misc.py:479``)."""
""":meth:`SwitchField.__call__`."""
from pcapkit.corekit.fields.field import Field
from pcapkit.corekit.fields.misc import SwitchField

field = SwitchField(selector=lambda packet: Field(length=1))
self.assertCallReachesCopyDunderOnly(field)

def test_schema_field_call_misc_py_650(self) -> None:
""":meth:`SchemaField.__call__` (``misc.py:694``)."""
""":meth:`SchemaField.__call__`."""
from pcapkit.corekit.fields.misc import SchemaField
from pcapkit.corekit.fields.numbers import UInt8Field
from pcapkit.protocols.schema.schema import Schema, schema_final
Expand All @@ -148,7 +148,7 @@ class OneField(Schema):
self.assertCallReachesCopyDunderOnly(SchemaField(schema=OneField))

def test_forward_match_field_call_misc_py_782(self) -> None:
""":meth:`ForwardMatchField.__call__` (``misc.py:849``)."""
""":meth:`ForwardMatchField.__call__`."""
from pcapkit.corekit.fields.field import Field
from pcapkit.corekit.fields.misc import ForwardMatchField

Expand Down
4 changes: 2 additions & 2 deletions tests/corekit/test_fields_misc_packet_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,10 +179,10 @@ def test_nested_schema_reads_enclosing_field_by_name_and_does_not_leak_writes(se
def test_pcapng_byteorder_consumer_still_works_with_both_shapes(self) -> None:
"""The one existing, hand-rolled ``__packet__`` fallback is unaffected.

``packet_byteorder`` (``pcapkit/corekit/fields/byteorder.py:33``)
``packet_byteorder`` (:mod:`pcapkit.corekit.fields.byteorder`)
is called both with a plain dict built by hand -- as several tests and
:func:`~pcapkit.foundation.engines.pcapng` construct -- and with what
``SchemaField`` now actually builds. Both must keep working, and
``SchemaField`` actually builds. Both must keep working, and
neither is expected to change: the site already implements the
fallback itself and does not route through
:func:`~pcapkit.corekit.fields.misc.nested_packet_context`.
Expand Down
6 changes: 3 additions & 3 deletions tests/corekit/test_fields_numbers_negative_length.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ def test_the_real_callable_shape_from_hip_py_also_raises_protocolerror(self) ->
"""``lambda pkt: pkt['len'] - 4`` against a truncated ``len``, verbatim.

This is the exact shape at ``pcapkit/protocols/schema/internet/
hip.py``'s ``PuzzleParameter.random`` field (line 734 as of
hip.py``'s ``PuzzleParameter.random`` field (as of
``21e9588af``): a wire ``len`` of ``3`` -- one octet short of the
4-octet header this parameter always carries -- resolves the
remaining ``random`` payload to ``-1`` octets, negative because the
Expand Down Expand Up @@ -181,7 +181,7 @@ class NegativeBitLengthTests(unittest.TestCase):
whenever one is supplied, and shifts by it immediately:
``(1 << bit_length) - 1``. #829 guarded the *resolved-length* shift in
:meth:`~pcapkit.corekit.fields.numbers.NumberField.__call__` but left this
one, at ``pcapkit/corekit/fields/numbers.py:88`` on ``5576708d4``, open --
one, in ``NumberField.__init__`` on ``5576708d4``, open --
a negative ``bit_length`` still raised a bare, uncatchable
:exc:`ValueError` (``negative shift count``) rather than a
:class:`~pcapkit.utilities.exceptions.ProtocolError`.
Expand Down Expand Up @@ -261,7 +261,7 @@ def test_a_positive_bit_length_is_unaffected(self) -> None:
"""The control: the ordinary, well-formed case is not touched.

The exact shape at ``pcapkit/protocols/schema/link/vlan.py``'s
``TCI.pcp``/``dei``/``vid`` fields (lines 47, 49, 51 on
``TCI.pcp``/``dei``/``vid`` fields (on
``5576708d4``): a positive literal ``bit_length`` alongside a fixed
byte ``length``.

Expand Down
2 changes: 1 addition & 1 deletion tests/corekit/test_graalpy_semantics_1963_unit.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
"""GraalPy behaviours :mod:`pcapkit.corekit` no longer depends on (#1963).
"""GraalPy behaviours :mod:`pcapkit.corekit` does not depend on (#1963).

Each was measured on GraalPy 25.4 and does not happen on CPython, so each class
here stands in for GraalPy's behaviour and checks the module does not lean on
Expand Down
2 changes: 1 addition & 1 deletion tests/corekit/test_sentinel_py_abc_1960_unit.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
``_abc_negative_cache_version`` on the class once any ABC has registered a
virtual subclass since the class was built. :class:`~pcapkit.corekit.sentinels.SentinelMeta`
refused every write to a built sentinel type, so ``isinstance(1, NullType)``
raised :exc:`TypeError` there. It now lets those two names through, and no
raised :exc:`TypeError` there. It lets those two names through, and no
other.

:class:`PyABCFallbackTests` runs the checks in a child interpreter that really
Expand Down
2 changes: 1 addition & 1 deletion tests/dumpkit/test_common_unit.py
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ def test_make_dumper_escapes_strings_only_for_plist_like_output(self) -> None:
def test_make_dumper_escapes_mapping_keys_for_plist_like_output(self) -> None:
"""GitHub issue #772, the half the hook above cannot reach.

``dictdumper/plist.py:202`` writes a key as
``PLIST._append_dict`` in :mod:`dictdumper.plist` writes a key as
``'<key>{item}</key>'.format(item=item)`` and calls ``_encode_value`` on
the *value* two lines down, never on the key -- so
:meth:`object_hook` is handed every value the writer interpolates and no
Expand Down
2 changes: 1 addition & 1 deletion tests/dumpkit/test_make_dumper_subclass_2144_unit.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
``super(type(self), self).object_hook(o)``. In a subclass of the class it
returns, ``type(self)`` is the subclass, so the call resolved back to that same
``object_hook`` and recursed until :exc:`RecursionError`. A value no branch
recognises now falls through to the output class's own ``object_hook``.
recognises falls through to the output class's own ``object_hook``.

:mod:`pcapkit` is imported inside each test, after
:func:`~tests._support.reimport_once_per_class`.
Expand Down
16 changes: 8 additions & 8 deletions tests/foundation/engines/test_engine_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,16 +77,16 @@ def test_engine_subclass_registration_is_opt_in(self) -> None:

The ``Default`` case is the load-bearing half: it sets
``__engine_name__``, so under the old fallback it registered under
``'defaultengine'``. A class attribute is not a registry key, and now it
``'defaultengine'``. A class attribute is not a registry key, and it
registers nothing.

No version guard, and that is the point of the rename. The keyword was
``name`` when opt-in registration landed, which made this half of the test
unrunnable on Python 3.10 -- ``mcls``/``name``/``bases``/``namespace``
unrunnable below Python 3.11 -- ``mcls``/``name``/``bases``/``namespace``
collide with :meth:`abc.ABCMeta.__new__`'s own parameters, which are
positional-or-keyword before 3.11 and positional-only from 3.11, so the
class statement failed in the metaclass before ``__init_subclass__`` ran.
``engine`` is outside that set, so this now runs everywhere. Verified on
``engine`` is outside that set, so this runs everywhere. Verified on
3.10.21 and 3.14.7.

"""
Expand Down Expand Up @@ -129,13 +129,13 @@ def test_engine_subclass_rejects_unrecognised_keyword(self) -> None:
would instead skip registration silently, which is quieter still.

Unguarded by version on purpose: ``protocol`` is not one of the four
names that collide with :meth:`abc.ABCMeta.__new__` on Python 3.10, so
names that collide with :meth:`abc.ABCMeta.__new__` below Python 3.11, so
the guard is reached on every supported version. Verified against this
tree on 3.10.21, where it raises ``UnsupportedCall`` as it does on 3.14.

``name`` is now an unrecognised keyword here too, and is checked
``name`` is an unrecognised keyword here too, and is checked
separately below because it is the one typo whose exception *type* is
version-dependent: on 3.10 the metaclass collision fires before the
version-dependent: below 3.11 the metaclass collision fires before the
guard, so it is a :exc:`TypeError` rather than an
:exc:`~pcapkit.utilities.exceptions.UnsupportedCall`. Loud either way,
which is why the rename did not need to chase it.
Expand All @@ -156,9 +156,9 @@ def read_frame(self) -> str:
register.assert_not_called()
self.assertIn('protocol', str(caught.exception))

# ``name=`` is no longer the registry keyword, so it is a typo now. It is
# ``name=`` is not the registry keyword, so it is a typo. It is
# the one whose exception type is version-dependent: the metaclass
# collision fires before the guard on 3.10.
# collision fires before the guard below 3.11.
expected = UnsupportedCall if sys.version_info >= (3, 11) else TypeError
with mock.patch('pcapkit.foundation.extraction.Extractor.register_engine') as register:
with self.assertRaises(expected):
Expand Down
2 changes: 1 addition & 1 deletion tests/foundation/engines/test_pcap_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ def test_finds_a_dist_info_without_reading_its_metadata(self) -> None:

# From Python 3.15 ``importlib.metadata.distribution`` parses every
# candidate's METADATA, which ran on each pcap_ct extraction (#2110).
# Existence is all that is asked, so a METADATA read is now an error.
# Existence is all that is asked, so here a METADATA read is an error.
def unread(self, filename):
raise AssertionError(f'read {filename} of {self}')

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<pcapkit.foundation.extraction.Extractor.import_test>` lets that through, so the
engine's ``unsupported_reason()`` has to report it. ``PCAP_CT`` did and ``PyPCAP``
did not, so ``extract(engine='pypcap')`` raised the loader's error where
``engine='pcap_ct'`` warned and fell back. Both now ask
``engine='pcap_ct'`` warned and fell back. Both ask
:func:`pcapkit.foundation.engines._pcap_backend.engine_reason`.

"""
Expand All @@ -31,7 +31,7 @@

#: What the fake ``pcap`` package raises on import: the libpcap loader's message.
LOADER_ERROR = 'Cannot find libpcap.so library'
#: The verdict ``PCAP_CT`` already gave on that failure, which ``PyPCAP`` now shares.
#: The verdict ``PCAP_CT`` already gave on that failure, which ``PyPCAP`` shares.
REASON = f'the `pcap` module is installed but unusable -- OSError: {LOADER_ERROR}'
#: Hang guard for the child interpreter, in seconds.
TIMEOUT = 120
Expand Down
2 changes: 1 addition & 1 deletion tests/foundation/engines/test_pyshark_non_packet_unit.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ def _record(number: int, frame: 'tuple[str, ...] | None', root: str) -> types.Si
'custom block (4.6.9)': ('DATA', ('section_number', 'interface_id', 'time', 'number', 'len')),
'sysdig event (4.6.9)': ('sysdig', RECORD_FRAME),
# 4.2.2 roots a Sysdig event at ``syscall`` and a Netflix custom block at
# ``bblog`` instead of ``frame`` (epan/dissectors/packet-frame.c:858-869, :884-890).
# ``bblog`` instead of ``frame`` (``dissect_frame`` in epan/dissectors/packet-frame.c).
'sysdig event (4.2.2)': ('syscall', None),
'black box log (4.2.2)': ('bblog', None),
}
Expand Down
Loading
Loading