testsAndMisc/python_pkg/brother_printer/tests/test_consumable_estimate.py
Krzysztof kuhy Rudnicki 2c01a0267e
Some checks are pending
Pre-commit checks / pre-commit (push) Waiting to run
Python tests / test (push) Waiting to run
Shell tests / shell-tests (push) Waiting to run
Shell tests / arch-tests (push) Waiting to run
Clear the last three brother_printer test modules over the cap
test_consumables_part2.py 273 -> 133 (renamed test_counter_scales.py),
test_consumables.py 272 -> 123, test_check_brother_printer.py 275 -> 112.
python_pkg/brother_printer is now entirely under the 250-line cap, from
fifteen violations at the start.

The consumables split lands exactly on the MOD/MOD_PD boundary an earlier
commit introduced, so the two-constant workaround dissolves instead of
being carried forward - each file has one module under test again.

Pass count is 402, unchanged across all eight commits of this pass.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011w2Pj4Ek3ZNMQVYcFHgXDY
2026-08-16 17:27:07 +02:00

168 lines
5.8 KiB
Python

"""Tests for brother_printer.consumables - the toner and drum life estimate.
Split from test_consumables.py under the 250-line cap. These cover which
counter the estimate is based on and how replacement resets rebase it.
"""
from __future__ import annotations
from unittest.mock import MagicMock, patch
from python_pkg.brother_printer.consumables import (
STATE_SCHEMA_CUPS_SCALE,
STATE_SCHEMA_PRINTER_SCALE,
estimate_consumable_life,
reset_consumable,
)
MOD = "python_pkg.brother_printer.consumables"
class TestEstimateConsumableLife:
@patch(f"{MOD}._load_consumable_state")
@patch(f"{MOD}._get_cups_total_pages", return_value=0)
def test_no_pages(self, p: MagicMock, mock_load: MagicMock) -> None:
result = estimate_consumable_life()
assert result.total_pages == 0
@patch(f"{MOD}._load_consumable_state")
@patch(f"{MOD}._get_cups_total_pages", return_value=500)
def test_mid_life(self, p: MagicMock, mock_load: MagicMock) -> None:
mock_load.return_value = {
"toner_replaced_at": 0,
"drum_replaced_at": 0,
"last_printer_count": 0,
"last_cups_total": 0,
}
result = estimate_consumable_life()
assert result.total_pages == 500
assert result.toner_pct_remaining == 50
assert result.toner_exhausted is False
assert result.toner_low is False
@patch(f"{MOD}._load_consumable_state")
@patch(f"{MOD}._get_cups_total_pages", return_value=1000)
def test_toner_exhausted(self, p: MagicMock, mock_load: MagicMock) -> None:
mock_load.return_value = {
"toner_replaced_at": 0,
"drum_replaced_at": 0,
"last_printer_count": 0,
"last_cups_total": 0,
}
result = estimate_consumable_life()
assert result.toner_exhausted is True
@patch(f"{MOD}._load_consumable_state")
@patch(f"{MOD}._get_cups_total_pages", return_value=800)
def test_toner_low(self, p: MagicMock, mock_load: MagicMock) -> None:
mock_load.return_value = {
"toner_replaced_at": 0,
"drum_replaced_at": 0,
"last_printer_count": 0,
"last_cups_total": 0,
}
result = estimate_consumable_life()
assert result.toner_low is True
@patch(f"{MOD}._load_consumable_state")
@patch(f"{MOD}._get_cups_total_pages", return_value=9000)
def test_drum_near_end(self, p: MagicMock, mock_load: MagicMock) -> None:
mock_load.return_value = {
"toner_replaced_at": 8500,
"drum_replaced_at": 0,
"last_printer_count": 0,
"last_cups_total": 0,
}
result = estimate_consumable_life()
assert result.drum_near_end is True
class TestEstimateConsumableLifeCounterSource:
"""Which counter the estimate came from, and whether it says so."""
@patch(f"{MOD}._migrate_state_to_printer_scale")
@patch(f"{MOD}._load_consumable_state")
@patch(f"{MOD}._get_cups_total_pages", return_value=1658)
def test_printer_counter_is_authoritative(
self,
mock_cups: MagicMock,
mock_load: MagicMock,
mock_migrate: MagicMock,
) -> None:
mock_load.return_value = {
"toner_replaced_at": 1767,
"drum_replaced_at": 0,
"last_printer_count": 0,
"last_cups_total": 0,
}
mock_migrate.side_effect = lambda state, total: state
estimate = estimate_consumable_life(2017)
assert estimate.total_pages == 2017
assert estimate.approximate is False
assert estimate.toner_pages == 250
@patch(f"{MOD}._load_consumable_state")
@patch(f"{MOD}._get_cups_total_pages", return_value=1658)
def test_falls_back_to_cups_log_and_flags_it(
self,
mock_cups: MagicMock,
mock_load: MagicMock,
) -> None:
"""Without the printer's counter, say the number is approximate."""
mock_load.return_value = {
"toner_replaced_at": 0,
"drum_replaced_at": 0,
"last_printer_count": 0,
"last_cups_total": 0,
}
estimate = estimate_consumable_life(0)
assert estimate.total_pages == 1658
assert estimate.approximate is True
@patch(f"{MOD}._get_cups_total_pages", return_value=0)
def test_no_counter_at_all(self, mock_cups: MagicMock) -> None:
assert estimate_consumable_life(0).total_pages == 0
class TestResetConsumableScale:
@patch(f"{MOD}._out")
@patch(f"{MOD}._save_consumable_state")
@patch(f"{MOD}._load_consumable_state")
def test_printer_total_marks_state_migrated(
self,
mock_load: MagicMock,
mock_save: MagicMock,
mock_out: MagicMock,
) -> None:
"""A baseline written from the printer is already on the new scale."""
mock_load.return_value = {
"toner_replaced_at": 0,
"drum_replaced_at": 0,
"schema": STATE_SCHEMA_CUPS_SCALE,
}
reset_consumable("toner", 2017)
saved = mock_save.call_args[0][0]
assert saved["toner_replaced_at"] == 2017
assert saved["schema"] == STATE_SCHEMA_PRINTER_SCALE
@patch(f"{MOD}._out")
@patch(f"{MOD}._save_consumable_state")
@patch(f"{MOD}._load_consumable_state")
@patch(f"{MOD}._get_cups_total_pages", return_value=1658)
def test_without_printer_total_uses_cups_log(
self,
mock_cups: MagicMock,
mock_load: MagicMock,
mock_save: MagicMock,
mock_out: MagicMock,
) -> None:
mock_load.return_value = {
"toner_replaced_at": 0,
"drum_replaced_at": 0,
"schema": STATE_SCHEMA_CUPS_SCALE,
}
reset_consumable("drum")
saved = mock_save.call_args[0][0]
assert saved["drum_replaced_at"] == 1658
assert saved["schema"] == STATE_SCHEMA_CUPS_SCALE