Files
gogobee/internal/plugin/adventure_babysit_test.go
prosolis 1953eec3b5 Adv 2.0 Phase L1: Babysit pivot + legacy resolver retire
Babysit pivots from harvest service to pet-care + safe-rest perk:
- runBabysitDaily/runAutoBabysitDay/runBabysitAction deleted; replaced
  by runBabysitDailyTrickle (3 pet XP/day while subscribed).
- BabysitSafeRest predicate promotes Standard camps to Fortified-tier
  rest (HP+1d6, threat -5, resources refresh) and reduces wandering
  monster check campMod from 0 to -4. Hooks live in
  dnd_expedition_camp.go and dnd_expedition_night.go.
- !adventure babysit auto/focus subcommands removed; status/purchase
  DMs reflect the new perks.

Scheduler drops the auto-babysit fallback block (no more silent
debits + harvest-day for missed logins). Babysit subscribers still
skip the morning DM; trickle runs in the background.

TwinBee daily simulator self-contained: simulateTwinBeeOutcome +
simulateTwinBeeLoot replace the resolveAdvAction call against a
fake CombatLevel=35 character. Outcome distribution and reward
shape preserved; gold-share to active players unchanged.

Legacy activity resolver retired: resolveAdvAction,
advEligibleLocations, AdvEligibleLocation, resolveAdvEmptyOutcome
deleted from adventure_activities.go (zero production callers
post-babysit/twinbee). AdvActionResult kept — combat_bridge still
produces it for arena/dungeon flows; dies in L2/L3.

Migration plan doc gogobee_legacy_migration.md added: five-phase
L1-L5 plan covering arena (Adv 2.0 boss flow rebuild), co-op
deletion, perk-gate sweep, and final teardown of AdventureCharacter
+ CombatLevel + combat_engine.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 14:25:22 -07:00

109 lines
3.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package plugin
import (
"testing"
"time"
"maunium.net/go/mautrix/id"
)
// L1: babysit pivot from harvest to pet-care + safe-rest.
// These tests cover the pure pieces — DB-touching paths exercise via
// integration only.
func TestBabysitSafeRest_NoDB_ReturnsFalse(t *testing.T) {
// Tests run without db.Init(); BabysitSafeRest must recover and
// return false rather than panicking.
if BabysitSafeRest(id.UserID("@nodb:example")) {
t.Errorf("expected false for un-initialized DB")
}
}
func TestRunBabysitDailyTrickle_NoPetGrantsNothing(t *testing.T) {
// Without a pet, the trickle is a logging-only no-op for character
// state. Without DB, the log call panics inside db.Get; recover and
// assert that the in-memory char fields stay clean.
defer func() { _ = recover() }()
expires := time.Now().UTC().Add(7 * 24 * time.Hour)
char := &AdventureCharacter{
UserID: id.UserID("@nopet:example"),
BabysitActive: true,
BabysitExpiresAt: &expires,
}
p := &AdventurePlugin{}
p.runBabysitDailyTrickle(char)
if char.PetXP != 0 {
t.Errorf("char without pet should not gain PetXP, got %d", char.PetXP)
}
if char.PetLevel != 0 {
t.Errorf("char without pet should not change PetLevel, got %d", char.PetLevel)
}
}
func TestRunBabysitDailyTrickle_SkipsWhenInactive(t *testing.T) {
defer func() { _ = recover() }()
char := &AdventureCharacter{
UserID: id.UserID("@inactive:example"),
BabysitActive: false,
PetType: "dog",
PetName: "Rex",
PetLevel: 1,
PetXP: 0,
}
p := &AdventurePlugin{}
p.runBabysitDailyTrickle(char)
if char.PetXP != 0 {
t.Errorf("inactive babysit should grant no XP, got %d", char.PetXP)
}
}
func TestRunBabysitDailyTrickle_AccumulatesAndLevels(t *testing.T) {
// Pet at L9 with 49 XP needed → 1 day at +3 trickle should *not* level
// (49→52 in centi-XP / 100 = no, wait: petXPToNextLevel at L9 = 50 ×
// 100 = 5000 centi-XP). Verify we accumulate centi-XP correctly across
// multiple daily ticks and eventually level up.
defer func() { _ = recover() }()
char := &AdventureCharacter{
UserID: id.UserID("@accum:example"),
PetType: "dog",
PetName: "Rex",
PetLevel: 1, // needs 10 XP = 1000 centi-XP to L2
PetXP: 900,
BabysitActive: true,
}
expires := time.Now().UTC().Add(48 * time.Hour)
char.BabysitExpiresAt = &expires
p := &AdventurePlugin{}
// One trickle adds 3*100 = 300 centi-XP. 900 + 300 = 1200 >= 1000 →
// level to 2, carry 200 centi-XP.
p.runBabysitDailyTrickle(char)
if char.PetLevel != 2 {
t.Errorf("expected level 2 after trickle, got %d (xp=%d)", char.PetLevel, char.PetXP)
}
if char.PetXP != 200 {
t.Errorf("expected 200 carryover centi-XP, got %d", char.PetXP)
}
}
func TestBabysitLogStats_CountsPetCareDays(t *testing.T) {
logs := []babysitLogEntry{
{Activity: "pet_care", XPGained: 3},
{Activity: "pet_care", XPGained: 3},
{Activity: "pet_care", XPGained: 3, RivalRefused: ""},
{Activity: "rival_refused", RivalRefused: "Garth"},
}
xp, days, rivals := babysitLogStats(logs)
if days != 3 {
t.Errorf("petDays = %d, want 3", days)
}
if xp != 9 {
t.Errorf("totalXP = %d, want 9", xp)
}
if rivals != 1 {
t.Errorf("rivalsRefused = %d, want 1", rivals)
}
}