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

tipjar_test.gno

3.59 Kb · 137 lines
  1package tipjar
  2
  3import (
  4	"strings"
  5	"testing"
  6
  7	"chain"
  8	"chain/banker"
  9
 10	"gno.land/p/nt/avl/v0"
 11	"gno.land/p/nt/testutils/v0"
 12)
 13
 14var realmAddr = chain.PackageAddress("gno.land/r/moul/x/daily/tipjar/v1")
 15
 16// reset clears package globals between tests, pinning owner to a known test
 17// address rather than whatever init() captured from the test harness.
 18func reset() {
 19	owner = testutils.TestAddress("owner")
 20	tippers = avl.Tree{}
 21	recent = nil
 22	totalReceived = 0
 23	withdrawn = 0
 24	tipCount = 0
 25}
 26
 27// fund simulates a tipper sending `amount` ugnot alongside the tx: the
 28// runtime deposits it at the realm's address first, then unsafe.OriginSend
 29// reports it to the crossing function. SetRealm is call-frame scoped (see
 30// build.md), so the caller must still SetRealm directly before crossing.
 31func fund(amount int64) {
 32	testing.IssueCoins(realmAddr, chain.Coins{{denom, amount}})
 33	testing.SetOriginSend(chain.Coins{{denom, amount}})
 34}
 35
 36func TestTipCreditsAndTracks(cur realm, t *testing.T) {
 37	reset()
 38	alice := testutils.TestAddress("alice")
 39
 40	fund(500)
 41	testing.SetRealm(testing.NewUserRealm(alice))
 42	Tip(cross(cur), "gm")
 43
 44	if got := Balance(); got != 500 {
 45		t.Fatalf("Balance() = %d, want 500", got)
 46	}
 47	if tipCount != 1 {
 48		t.Fatalf("tipCount = %d, want 1", tipCount)
 49	}
 50	ts := get(alice)
 51	if ts.total != 500 || ts.count != 1 || ts.lastMessage != "gm" {
 52		t.Fatalf("unexpected tipper stats: %+v", ts)
 53	}
 54
 55	fund(250)
 56	testing.SetRealm(testing.NewUserRealm(alice))
 57	Tip(cross(cur), "again")
 58	if got := get(alice).total; got != 750 {
 59		t.Fatalf("cumulative total = %d, want 750", got)
 60	}
 61	if got := Balance(); got != 750 {
 62		t.Fatalf("Balance() after second tip = %d, want 750", got)
 63	}
 64}
 65
 66func TestTipRejectsZeroAmount(cur realm, t *testing.T) {
 67	reset()
 68	alice := testutils.TestAddress("alice")
 69	testing.SetRealm(testing.NewUserRealm(alice))
 70
 71	rec := revive(func() { Tip(cross(cur), "freeloading") })
 72	if rec == nil {
 73		t.Fatal("expected panic when tipping with no ugnot sent")
 74	}
 75}
 76
 77func TestTipRejectsNonUserCall(cur realm, t *testing.T) {
 78	reset()
 79	testing.SetRealm(testing.NewCodeRealm("gno.land/r/g1attacker/relay"))
 80
 81	rec := revive(func() { Tip(cross(cur), "sneaky") })
 82	if rec == nil {
 83		t.Fatal("expected panic when the caller isn't an EOA via MsgCall")
 84	}
 85}
 86
 87func TestWithdrawOwnerOnly(cur realm, t *testing.T) {
 88	reset()
 89	alice := testutils.TestAddress("alice")
 90	mallory := testutils.TestAddress("mallory")
 91
 92	fund(1000)
 93	testing.SetRealm(testing.NewUserRealm(alice))
 94	Tip(cross(cur), "for the jar")
 95
 96	testing.SetRealm(testing.NewUserRealm(mallory))
 97	rec := revive(func() { Withdraw(cross(cur), 100) })
 98	if rec == nil {
 99		t.Fatal("expected panic when a non-owner withdraws")
100	}
101
102	testing.SetRealm(testing.NewUserRealm(owner))
103	Withdraw(cross(cur), 400)
104
105	if got := Balance(); got != 600 {
106		t.Fatalf("Balance() after withdraw = %d, want 600", got)
107	}
108	ro := banker.NewReadonlyBanker()
109	if got := ro.GetCoins(owner).AmountOf(denom); got != 400 {
110		t.Fatalf("owner received = %d, want 400", got)
111	}
112
113	rec = revive(func() { Withdraw(cross(cur), 10000) })
114	if rec == nil {
115		t.Fatal("expected panic when withdrawing more than the balance")
116	}
117}
118
119func TestRenderShowsLeaderboardAndFeed(cur realm, t *testing.T) {
120	reset()
121	if !strings.Contains(Render(""), "No tips yet") {
122		t.Fatal("expected empty-jar placeholder")
123	}
124
125	alice := testutils.TestAddress("alice")
126	fund(300)
127	testing.SetRealm(testing.NewUserRealm(alice))
128	Tip(cross(cur), "nice work")
129
130	out := Render("")
131	if !strings.Contains(out, "Leaderboard") {
132		t.Fatal("expected leaderboard section")
133	}
134	if !strings.Contains(out, "nice work") {
135		t.Fatal("expected the tip message in the recent-tips feed")
136	}
137}