mirror of
https://github.com/kuhyx/utils.git
synced 2026-11-11 12:07:48 +01:00
Some checks are pending
dependency freshness / dependencies on newest stable (push) Waiting to run
earned_time pre-commit / pre-commit (push) Waiting to run
earned_time tests / test (push) Waiting to run
file length / file-length (push) Waiting to run
md-naming / markdown naming convention (push) Waiting to run
palette drift / palette (push) Waiting to run
repo-contract / repo contract (push) Waiting to run
shared gate tests / gate unit tests (push) Waiting to run
TUTOR_FROM = 2026-10-10 (the day after the deploy). The automation tutor keeps confirmed_on=None, so it stays "new". Ladder floor: a rung comes off the floor only for a pure bonus (no penalty_from) or an earner whose penalty has started -- the same _penalised() rule (first_credits -> penalty_start, confirmed_on fail-closed fallback, penalty_from without first_credits) the gaming base uses. Before this, a never-credited tutor would have lowered 2026-10-10's floor by its full 50-minute rung (19:50 -> 19:00) even with first_credits. Maturity can only raise time: new property test against the 0.6.0 floor formula. ruff 0.17.0 (dependency-freshness): CPY001 ignored -- personal repo, no copyright policy. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WdfmsGMht9ypyvxGPmNF1V
71 lines
2.4 KiB
Python
71 lines
2.4 KiB
Python
# Copyright (c) 2026 Krzysztof Rudnicki
|
|
"""The gap-day waiver: Anki and the old Automation, from ANKI_WAIVED_FROM."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from datetime import timedelta
|
|
|
|
import pytest
|
|
|
|
from earned_time import (
|
|
ANKI_WAIVED_FROM,
|
|
EARNERS,
|
|
LADDER_FROM,
|
|
TUTOR_EARNERS,
|
|
TUTOR_FROM,
|
|
earners_for,
|
|
resolve,
|
|
)
|
|
|
|
BEFORE = ANKI_WAIVED_FROM - timedelta(days=1)
|
|
NAMES = ("workout", "leetcode", "reading", "anki", "automation")
|
|
|
|
|
|
def test_the_waiver_sits_between_the_old_registry_and_the_tutor() -> None:
|
|
assert BEFORE < ANKI_WAIVED_FROM < TUTOR_FROM
|
|
assert earners_for(BEFORE) is EARNERS
|
|
assert [e.name for e in earners_for(ANKI_WAIVED_FROM)] == list(NAMES[:3])
|
|
assert earners_for(TUTOR_FROM) is TUTOR_EARNERS
|
|
|
|
|
|
def test_nothing_done_is_raised_by_exactly_what_the_two_paid() -> None:
|
|
zero = dict.fromkeys(NAMES, 0)
|
|
# TUTOR_FROM == LADDER_FROM: the waiver's only day is pre-ladder; the first
|
|
# ladder day's floor is in test_maturity_floor.py.
|
|
assert ANKI_WAIVED_FROM < LADDER_FROM == TUTOR_FROM
|
|
gap = resolve(zero, ANKI_WAIVED_FROM)
|
|
unwaived = resolve(zero, ANKI_WAIVED_FROM, EARNERS)
|
|
assert (gap.base.gaming_minutes, gap.gaming_minutes) == (240, 240)
|
|
assert gap.shutdown_minutes == 19 * 60 # 20:00 minus reading's 60
|
|
assert gap.gaming_minutes - unwaived.gaming_minutes == 30 + 30
|
|
assert gap.shutdown_minutes - unwaived.shutdown_minutes == 30 + 30
|
|
|
|
|
|
@pytest.mark.parametrize("workout", [0, 1])
|
|
@pytest.mark.parametrize("leetcode", [0, 1])
|
|
@pytest.mark.parametrize("reading", [0, 1])
|
|
@pytest.mark.parametrize("anki", [0, 1])
|
|
def test_raise_only_on_every_combination(
|
|
workout: int, leetcode: int, reading: int, anki: int
|
|
) -> None:
|
|
answers = {
|
|
"workout": workout,
|
|
"leetcode": leetcode,
|
|
"reading": reading,
|
|
"anki": anki,
|
|
"automation": anki,
|
|
}
|
|
day = ANKI_WAIVED_FROM
|
|
waived = resolve(answers, day)
|
|
unwaived = resolve(answers, day, EARNERS)
|
|
assert waived.gaming_minutes >= unwaived.gaming_minutes
|
|
assert waived.shutdown_minutes >= unwaived.shutdown_minutes
|
|
if anki:
|
|
assert waived.gaming_minutes == unwaived.gaming_minutes
|
|
assert waived.shutdown_minutes == unwaived.shutdown_minutes
|
|
|
|
|
|
def test_all_done_still_8h_and_23() -> None:
|
|
done = resolve(dict.fromkeys(NAMES, 1), ANKI_WAIVED_FROM)
|
|
assert (done.gaming_minutes, done.shutdown_minutes) == (480, 23 * 60)
|