Skip to content Search Apps Documentation Source Content File Folder Download Copy Actions State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

Community realm. Read the code first. Community realm, deployed by its author. Read the code before you interact or send coins.

rpgroom_test.gno

3.65 Kb · 138 lines
  1package rpgroom
  2
  3import (
  4	"testing"
  5
  6	"gno.land/p/nt/avl/v0"
  7	"gno.land/p/nt/testutils/v0"
  8)
  9
 10func resetState() {
 11	heroes = avl.Tree{}
 12	roomLevel = 1
 13	totalKills = 0
 14	monster = spawnMonster(roomLevel)
 15}
 16
 17func TestSpawnMonster(t *testing.T) {
 18	m1 := spawnMonster(1)
 19	m5 := spawnMonster(5)
 20	if m1.Level != 1 || m5.Level != 5 {
 21		t.Fatal("spawnMonster should carry the requested level")
 22	}
 23	if m5.HP <= m1.HP {
 24		t.Fatal("a higher-level monster should have more HP")
 25	}
 26	if m5.Attack <= m1.Attack {
 27		t.Fatal("a higher-level monster should hit harder")
 28	}
 29}
 30
 31func TestLevelUp(t *testing.T) {
 32	h := &Hero{Level: 1, XP: 0, HP: 30, MaxHP: 30, Attack: 5}
 33	h.XP = 50 // exactly the level-1 threshold
 34	levelUp(h)
 35	if h.Level != 2 {
 36		t.Fatalf("Level = %d, want 2", h.Level)
 37	}
 38	if h.XP != 0 {
 39		t.Fatalf("XP = %d, want 0 (fully consumed)", h.XP)
 40	}
 41	if h.MaxHP != 40 || h.HP != 40 {
 42		t.Fatalf("MaxHP/HP = %d/%d, want 40/40 (healed on level up)", h.MaxHP, h.HP)
 43	}
 44	if h.Attack != 8 {
 45		t.Fatalf("Attack = %d, want 8", h.Attack)
 46	}
 47}
 48
 49func TestLevelUpMultipleLevels(t *testing.T) {
 50	h := &Hero{Level: 1, XP: 200, HP: 30, MaxHP: 30, Attack: 5}
 51	levelUp(h)
 52	// level 1->2 costs 50, 2->3 costs 100: 200 - 50 - 100 = 50 left, still short of 150 for 3->4
 53	if h.Level != 3 {
 54		t.Fatalf("Level = %d, want 3", h.Level)
 55	}
 56	if h.XP != 50 {
 57		t.Fatalf("XP = %d, want 50 remaining", h.XP)
 58	}
 59}
 60
 61func TestHPBar(t *testing.T) {
 62	full := hpBar(10, 10)
 63	empty := hpBar(0, 10)
 64	if full == empty {
 65		t.Fatal("full and empty bars should render differently")
 66	}
 67}
 68
 69// Crossing: Spawn/Attack/Rest/Revive mutate realm state, so the test needs `cur realm`.
 70func TestFullHeroLifecycle(cur realm, t *testing.T) {
 71	resetState()
 72	alice := testutils.TestAddress("alice")
 73
 74	testing.SetRealm(testing.NewUserRealm(alice))
 75	Spawn(cross(cur), "Alice the Bold")
 76
 77	v := heroes.Get(alice.String())
 78	if v == nil {
 79		t.Fatal("expected a hero for alice")
 80	}
 81	hero := v.(*Hero)
 82	if hero.Level != 1 || !hero.Alive {
 83		t.Fatalf("fresh hero should be level 1 and alive, got level=%d alive=%v", hero.Level, hero.Alive)
 84	}
 85
 86	// Grind the starter monster down; it starts at 35 HP with our hero
 87	// hitting for 5 (ignoring the rare crit), so a handful of swings should
 88	// clear it without the hero dying (monster only hits for 5).
 89	startMonster := monster
 90	for i := 0; i < 20 && monster == startMonster; i++ {
 91		if !hero.Alive {
 92			testing.SetRealm(testing.NewUserRealm(alice))
 93			Revive(cross(cur))
 94		}
 95		testing.SetRealm(testing.NewUserRealm(alice))
 96		Attack(cross(cur))
 97	}
 98	if monster == startMonster {
 99		t.Fatal("expected the starter monster to be replaced after repeated attacks")
100	}
101	if hero.Kills < 1 {
102		t.Fatalf("Kills = %d, want at least 1", hero.Kills)
103	}
104	if hero.Gold < 1 {
105		t.Fatalf("Gold = %d, want at least 1", hero.Gold)
106	}
107	if roomLevel < 2 {
108		t.Fatalf("roomLevel = %d, want at least 2 after a kill", roomLevel)
109	}
110}
111
112func TestDoubleSpawnPanics(cur realm, t *testing.T) {
113	resetState()
114	bob := testutils.TestAddress("bob")
115	testing.SetRealm(testing.NewUserRealm(bob))
116	Spawn(cross(cur), "Bob")
117
118	testing.SetRealm(testing.NewUserRealm(bob))
119	// Spawn panics inside a cross-realm call; a plain defer/recover in this
120	// test does not catch a cross-boundary panic, so use revive().
121	rec := revive(func() { Spawn(cross(cur), "Bob Again") })
122	if rec == nil {
123		t.Fatal("expected a second Spawn for the same address to panic")
124	}
125}
126
127func TestRestRequiresDamage(cur realm, t *testing.T) {
128	resetState()
129	carol := testutils.TestAddress("carol")
130	testing.SetRealm(testing.NewUserRealm(carol))
131	Spawn(cross(cur), "Carol")
132
133	testing.SetRealm(testing.NewUserRealm(carol))
134	rec := revive(func() { Rest(cross(cur)) })
135	if rec == nil {
136		t.Fatal("expected Rest at full HP to panic")
137	}
138}