Testing Contracts API
pathlib_next.testing
Test-suite building blocks for verifying custom Path/UriPath implementations satisfy the library's filesystem contract.
Not imported by pathlib_next/__init__.py -- this module requires pytest,
which is a test-only dependency. Import it explicitly. Example::
import pytest
from pathlib_next import LocalPath as MyPath # your Path subclass here
from pathlib_next.testing import PathContract, populate_fixture_tree
class TestMyPath(PathContract):
@pytest.fixture
def root(self, tmp_path):
root = MyPath(tmp_path)
populate_fixture_tree(root)
return root
root must be a fresh, function-scoped directory holding exactly the
standard tree (populate_fixture_tree() builds it through the path's own
API): the write tests create fixed names and assert their absence first, so
two contract classes sharing one root fail each other.
Rules pathlib guarantees are asserted with pathlib's exception types. Where
pathlib itself differs by OS (reading or unlinking a directory raises
IsADirectoryError on Linux and PermissionError on Windows/macOS), the
contract accepts that documented set. A backend that genuinely cannot meet a
rule sets the matching capability attribute to False on its test class; the
affected tests then report as skipped, never as passed:
ReadPathContract.supports_listing--iterdir(),glob(),walk().ReadPathContract.supports_empty_directories--empty_dir/lists as empty (git trees cannot hold an empty directory, so a placeholder file lives there).ReadPathContract.distinguishes_file_types-- listing a file raisesNotADirectoryErrorand reading a directory raises (plain HTTP cannot tell: one URL serves an index page or a file).PathContract.supports_rename--rename().PathContract.supports_append--open("a")/open("ab").PathContract.supports_exclusive_create--open("x").PathContract.enforces_directory_hierarchy--mkdir()and writes below a missing parent raiseFileNotFoundError, and writing a file over a directory raises (object stores, whose directories are key prefixes, cannot).
PathContract
Bases: ReadPathContract
Mixin of filesystem-contract tests every writable Path implementation
(custom Path subclass, or UriPath scheme) must satisfy.
Subclasses must provide a root fixture pointing to a fresh, writable,
function-scoped directory pre-populated with the standard tree (see
populate_fixture_tree()). Tests create fixed names under it without
cleaning up.
Capability attributes (all default True; set one False only for a
documented gap): supports_rename, supports_append,
supports_exclusive_create, enforces_directory_hierarchy.
PurePathContract
Contract tests for pure path (logical) operations, not requiring any I/O.
ReadPathContract
Bases: PurePathContract
Contract tests for read-only path operations.
Subclasses must provide a root fixture pointing to a fresh directory
pre-populated with the standard tree -- see populate_fixture_tree() and
FIXTURE_TREE:
- a.txt (content: "a")
- b.py (content: "b")
- .hidden.txt (content: "hidden")
- sub/c.py (content: "c")
- sub/nested/d.py (content: "d")
- empty_dir/
Capability attributes (all default True; set one False only for a
documented gap, and the affected tests skip): supports_listing,
supports_empty_directories, distinguishes_file_types.
populate_fixture_tree(root)
Create the standard contract tree (FIXTURE_TREE) under root, an
existing empty directory, through the path's own mkdir() and
write_text() -- works for any Path implementation (or a stdlib
pathlib.Path). Returns root.
Source code in src/pathlib_next/testing.py
75 76 77 78 79 80 81 82 83 84 85 86 | |