-
Notifications
You must be signed in to change notification settings - Fork 3
Fetch billtext index #625
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Fetch billtext index #625
Changes from all commits
addc19b
36bf310
5ffdadf
725de70
6a7f40d
e130d7b
740f100
7f88bcb
78ccfee
3aa8496
479fe60
c31841c
25c1e5e
98374a9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,66 @@ | ||
| """Shared test helpers.""" | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| import io | ||
| import re | ||
| import zipfile | ||
| from pathlib import Path | ||
|
|
||
| import respx | ||
|
|
||
| # Validation | ||
|
|
||
|
|
||
| def assert_files(folder: Path, files: set[str] | list[str]) -> None: | ||
| """Assert the folder contains exactly the given filenames.""" | ||
| __tracebackhide__ = True | ||
| actual = {path.name for path in folder.iterdir()} | ||
| expected = set(files) | ||
| if actual != expected: | ||
| extra = actual - expected | ||
| missing = expected - actual | ||
| raise AssertionError( | ||
| "\n".join( | ||
| filter( | ||
| None, | ||
| [ | ||
| f"Unexpected file contents in folder {folder}:", | ||
| f"expected: {expected}", | ||
| f"actual: {actual}", | ||
| f"extra: {extra}" if extra else None, | ||
| f"missing: {missing}" if missing else None, | ||
| ], | ||
| ) | ||
| ) | ||
| ) | ||
|
Comment on lines
+15
to
+36
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This new utility is key for testing - it checks the full contents of a folder and outputs intuitive error text if expectations mismatch reality. Fetch_bill_archives unit tests make liberal use of this utility now. Feel free to add a recursive option if needed, but I found it most intuitive to check one folder at a time instead. |
||
|
|
||
|
|
||
| # HTTP Mocking | ||
| def mock_http_requests( | ||
| url: re.Pattern[str] = re.compile(".*"), | ||
| status_code: int = 200, | ||
| content: bytes = b"", | ||
| **kwargs, | ||
| ) -> None: | ||
| """Mock matching GET requests with one response.""" | ||
| return respx.get(url).respond(status_code, content=content, **kwargs) | ||
|
|
||
|
|
||
| # Zip File Mocking | ||
| def archive_bytes(members: dict[str, bytes] = {}) -> Path: | ||
| """Write a well-formed ZIP named ``{name}.zip`` into source.""" | ||
| buf = io.BytesIO() | ||
| with zipfile.ZipFile(buf, "w") as zf: | ||
| for member, body in members.items(): | ||
| zf.writestr(member, body) | ||
| return buf.getvalue() | ||
|
|
||
|
|
||
| EMPTY_ZIP_BYTES = archive_bytes() | ||
|
|
||
|
|
||
| def write_archive(source: Path, name: str, members: dict[str, bytes] | None = None) -> Path: | ||
| """Write a well-formed ZIP named ``{name}.zip`` into source.""" | ||
| path = source / name | ||
| path.write_bytes(archive_bytes(name, members)) | ||
This file was deleted.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new model for unit tests:
Perform mocking. Ideally in a line or two using utilities
Invoke a function. In this case, a CLI command.
Check user-facing results. In this case, files created.
Aside from greatly simplifying the test, there is a behavioral change that required the rewrite: archive files now begin with BILLSTATUS to disambiguate them from BILLTEXT archives.
It is debatable whether we should verify zip files downloaded in any level of detail. They are an intermediate step, end their structure is not important. The important details to check are the extracted archive contents, the bill index file contents, cache behavior, and error handling.