Skip to content

fix(pytest_plugin): reject negative advance in _RecordingProgresser - #467

Open
GreyViperTooth wants to merge 2 commits into
canonical:mainfrom
GreyViperTooth:fix/issue-466-recording-progresser-negative-advance
Open

fix(pytest_plugin): reject negative advance in _RecordingProgresser#467
GreyViperTooth wants to merge 2 commits into
canonical:mainfrom
GreyViperTooth:fix/issue-466-recording-progresser-negative-advance

Conversation

@GreyViperTooth

Copy link
Copy Markdown

What

The emitter pytest fixture swaps the real progress bar for _RecordingProgresser, but that mock did not enforce a constraint the real _Progresser.advance does: it raises ValueError when amount < 0. As a result, tests using the fixture silently accepted negative advances that would crash in production, which can mask real bugs (this was noticed in canonical/craft-application#994).

How

  • Give _RecordingProgresser.advance the same single-positional amount: float signature as the real _Progresser.advance.
  • Add the same negative-amount guard (raise ValueError on amount < 0).
  • The recorded-call format is unchanged (call(advance, 100)), so existing fixture assertions still hold.
  • Add a regression test asserting the fixture now rejects a negative advance.

Fixes #466

🤖 Generated with Claude Code

@GreyViperTooth
GreyViperTooth requested a review from bepri as a code owner August 3, 2026 02:06
The `emitter` fixture swaps the real progress bar for `_RecordingProgresser`,
but that mock did not enforce a constraint the real `_Progresser.advance`
does: it raises `ValueError` when `amount < 0`. As a result, tests using the
fixture silently accepted negative advances that crash in production, masking
real bugs (see canonical/craft-application#994).

Give the mock the same single-positional `amount` signature and the same
negative-amount guard as the real method. The recorded-call format is
unchanged (`call("advance", 100)`), so existing assertions still hold.

Fixes canonical#466

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@GreyViperTooth
GreyViperTooth force-pushed the fix/issue-466-recording-progresser-negative-advance branch from 9ffba1c to 42d5f89 Compare August 3, 2026 02:09

@bepri bepri left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! I left a little feedback below. Could you also add this as a bugfix in the changelog at docs/changelog.rst?

Comment thread craft_cli/pytest_plugin.py Outdated
Comment on lines +243 to +245

Mirrors the validation done by the real ``_Progresser.advance`` so that
tests using the ``emitter`` fixture don't silently accept invalid usage.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can skip this addition to the docstring, I think.

Comment thread craft_cli/pytest_plugin.py Outdated
def advance(self, *a: Any, **k: Any) -> None:
"""Record the advance usage."""
self.recording_emitter.record("advance", a, k)
def advance(self, amount: float) -> None:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This breaks the API of this fixture, I would do this instead:

Suggested change
def advance(self, amount: float) -> None:
def advance(self, *a: Any, amount: float, **k: Any) -> None:

(and update line 249 accordingly)

- Restore the generic *a/**k passthrough on _RecordingProgresser.advance
  (with amount first so positional calls keep working) instead of narrowing
  the signature, and drop the docstring expansion.
- Add a bugfix entry to docs/changelog.rst.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@GreyViperTooth
GreyViperTooth requested a review from a team as a code owner August 3, 2026 19:46
@GreyViperTooth

Copy link
Copy Markdown
Author

Thanks @bepri! Kept the *a/**k passthrough and dropped the docstring as suggested. One tweak: I put amount first (def advance(self, amount, *a, **k)) instead of keyword-only, since *a, amount, **k would break the existing positional call progress_bar.advance(100). Also added the changelog entry.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: _RecordingProgresser.advance accepts negatives the real progresser rejects

2 participants