The user_with_custom_thresholds fixture used UserProfile.objects.get_or_create()
which returns a separate Python instance from the one cached in
user._state.fields_cache['profile']. When the fixture modified and saved
the get_or_create instance, the cached instance on the user object still
held default values (periodic=16, full=24). compute_fasting() accessed
u.profile which returned the stale cached object.
Fixed by modifying through u.profile directly, which operates on the
same cached instance. Also applied black formatting to fasting.py.
- Replace day-iteration algorithm with pair-based approach for fasting
detection. Iterate consecutive food scrobble pairs and mark foodless
days between them as fasting days.
- Handle consecutive-day periodic fasting: when two food scrobbles are on
consecutive days with a gap >= periodic_threshold but < full_threshold,
mark the later day as a periodic fast (user's original bug fix).
- Fix _dt test helper to use replace() instead of subtracting hours,
producing correct timestamps (e.g., '3 days ago at 18:46' instead of
'3 days + 18h46m ago').
- Fix total_days off-by-one: removed +1 from inclusive day count so a
'last_30' period correctly reports 30 days.
- Add _drinks_on_day() for per-day drink detection (replaces whole-
window _drinks_in_window for more accurate liquid fasting detection).
- Fix Beer test fixture to use styles M2M field instead of non-existent
beer_style attribute.
- Add 26 test cases covering: classification, short gaps, periodic/
full/liquid fasting, multi-day gaps, vacation exemptions, custom
thresholds, streaks, mixed types, edge cases.
Reasoning:
The original day-iteration algorithm had fundamental issues: it marked
days with food as fasting (since it only checked prev/next food times),
it didn't filter out normal (< periodic) gaps, and the _dt helper was
misinterpreting hour parameters. The new pair-based approach is cleaner:
for each consecutive food scrobble pair, we mark the foodless days
between them. This naturally handles multi-day fasts and correctly
avoids marking food-eating days as fasting. The consecutive-day periodic
rule preserves the user's original intent of detecting overnight fasts
between meals.