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

coinflipduel_test.gno

2.96 Kb · 121 lines
  1package coinflipduel
  2
  3import (
  4	"testing"
  5
  6	"gno.land/p/nt/avl/v0"
  7	"gno.land/p/nt/testutils/v0"
  8)
  9
 10func resetState() {
 11	duels = avl.Tree{}
 12	players = avl.Tree{}
 13	nextID = 0
 14	flipNonce = 0
 15	totalDone = 0
 16	var zero address
 17	champion = zero
 18	championWins = 0
 19}
 20
 21func TestParseCall(t *testing.T) {
 22	for _, s := range []string{"heads", "Heads", " h ", "tails", "T"} {
 23		if _, ok := parseCall(s); !ok {
 24			t.Fatalf("parseCall(%q) should be valid", s)
 25		}
 26	}
 27	if _, ok := parseCall("sideways"); ok {
 28		t.Fatal(`parseCall("sideways") should be invalid`)
 29	}
 30}
 31
 32// Crossing: Challenge and Accept mutate realm state, so the test needs `cur realm`.
 33func TestChallengeAndAccept(cur realm, t *testing.T) {
 34	resetState()
 35	alice := testutils.TestAddress("alice")
 36	bob := testutils.TestAddress("bob")
 37
 38	testing.SetRealm(testing.NewUserRealm(alice))
 39	Challenge(cross(cur), bob.String(), "heads")
 40
 41	if !duels.Has("1") {
 42		t.Fatal("expected duel #1 to exist")
 43	}
 44
 45	testing.SetRealm(testing.NewUserRealm(bob))
 46	Accept(cross(cur), "1")
 47
 48	v := duels.Get("1")
 49	d := v.(*duel)
 50	if d.Status != statusResolved {
 51		t.Fatalf("Status = %v, want resolved", d.Status)
 52	}
 53	if d.Result != "heads" && d.Result != "tails" {
 54		t.Fatalf("Result = %q, want heads or tails", d.Result)
 55	}
 56	if totalDone != 1 {
 57		t.Fatalf("totalDone = %d, want 1", totalDone)
 58	}
 59
 60	winnerStats := getOrCreate(d.Winner)
 61	if winnerStats.Wins != 1 {
 62		t.Fatalf("winner Wins = %d, want 1", winnerStats.Wins)
 63	}
 64	if !champion.IsValid() || champion != d.Winner {
 65		t.Fatal("champion should be the duel winner")
 66	}
 67}
 68
 69func TestChallengeSelfRejected(cur realm, t *testing.T) {
 70	resetState()
 71	alice := testutils.TestAddress("alice")
 72	testing.SetRealm(testing.NewUserRealm(alice))
 73
 74	// Challenge panics inside a cross-realm call; a plain defer/recover in
 75	// this test does not catch a cross-boundary panic, so use revive().
 76	rec := revive(func() { Challenge(cross(cur), alice.String(), "heads") })
 77	if rec == nil {
 78		t.Fatal("expected panic when challenging yourself")
 79	}
 80}
 81
 82func TestOnlyOpponentCanAccept(cur realm, t *testing.T) {
 83	resetState()
 84	alice := testutils.TestAddress("alice")
 85	bob := testutils.TestAddress("bob")
 86	mallory := testutils.TestAddress("mallory")
 87
 88	testing.SetRealm(testing.NewUserRealm(alice))
 89	Challenge(cross(cur), bob.String(), "tails")
 90
 91	testing.SetRealm(testing.NewUserRealm(mallory))
 92	rec := revive(func() { Accept(cross(cur), "1") })
 93	if rec == nil {
 94		t.Fatal("expected panic when a non-opponent accepts")
 95	}
 96}
 97
 98func TestCancel(cur realm, t *testing.T) {
 99	resetState()
100	alice := testutils.TestAddress("alice")
101	bob := testutils.TestAddress("bob")
102
103	testing.SetRealm(testing.NewUserRealm(alice))
104	Challenge(cross(cur), bob.String(), "heads")
105	Cancel(cross(cur), "1")
106
107	v := duels.Get("1")
108	d := v.(*duel)
109	if d.Status != statusCancelled {
110		t.Fatalf("Status = %v, want cancelled", d.Status)
111	}
112}
113
114// Non-crossing: Render is a plain read.
115func TestRenderHome(t *testing.T) {
116	resetState()
117	out := Render("")
118	if out == "" {
119		t.Fatal(`Render("") should not be empty`)
120	}
121}