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.

dutchauction_test.gno

4.47 Kb · 175 lines
  1package dutchauction
  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/dutchauction/v0")
 15
 16func reset() {
 17	auctions = avl.Tree{}
 18	nextID = 0
 19	totalListed = 0
 20	totalSold = 0
 21	totalVolume = 0
 22}
 23
 24// fundBuy simulates a buyer sending `amount` ugnot alongside the tx: the
 25// runtime deposits it at the realm's address first, then unsafe.OriginSend
 26// reports it to the crossing function.
 27func fundBuy(buyer address, amount int64) {
 28	testing.IssueCoins(realmAddr, chain.Coins{{"ugnot", amount}})
 29	testing.SetOriginSend(chain.Coins{{"ugnot", amount}})
 30	testing.SetRealm(testing.NewUserRealm(buyer))
 31}
 32
 33func TestListAndPriceDecay(cur realm, t *testing.T) {
 34	reset()
 35	seller := testutils.TestAddress("seller")
 36
 37	testing.SetRealm(testing.NewUserRealm(seller))
 38	id := List(cross(cur), "vintage synth", 1000, 100, 100)
 39
 40	if got := CurrentPrice(id); got != 1000 {
 41		t.Fatalf("price at start = %d, want 1000", got)
 42	}
 43
 44	testing.SkipHeights(50)
 45	if got := CurrentPrice(id); got != 550 {
 46		t.Fatalf("price at midpoint = %d, want 550", got)
 47	}
 48
 49	testing.SkipHeights(100)
 50	if got := CurrentPrice(id); got != 100 {
 51		t.Fatalf("price past duration = %d, want floor 100", got)
 52	}
 53}
 54
 55func TestListRejectsBadInput(cur realm, t *testing.T) {
 56	reset()
 57	seller := testutils.TestAddress("seller")
 58	testing.SetRealm(testing.NewUserRealm(seller))
 59
 60	rec := revive(func() { List(cross(cur), "", 1000, 100, 100) })
 61	if rec == nil {
 62		t.Fatal("expected panic on empty item")
 63	}
 64	rec = revive(func() { List(cross(cur), "thing", 100, 1000, 100) })
 65	if rec == nil {
 66		t.Fatal("expected panic when floorPrice >= startPrice")
 67	}
 68	rec = revive(func() { List(cross(cur), "thing", 1000, 100, 0) })
 69	if rec == nil {
 70		t.Fatal("expected panic on non-positive duration")
 71	}
 72}
 73
 74func TestBuyExactSettlesToSeller(cur realm, t *testing.T) {
 75	reset()
 76	seller := testutils.TestAddress("seller")
 77	buyer := testutils.TestAddress("buyer")
 78
 79	testing.SetRealm(testing.NewUserRealm(seller))
 80	id := List(cross(cur), "vintage synth", 1000, 100, 100)
 81
 82	testing.SkipHeights(50) // price = 550
 83	fundBuy(buyer, 550)
 84	paid := Buy(cross(cur), id)
 85	if paid != 550 {
 86		t.Fatalf("paid = %d, want 550", paid)
 87	}
 88
 89	ro := banker.NewReadonlyBanker()
 90	sellerBal := ro.GetCoins(seller).AmountOf("ugnot")
 91	if sellerBal != 550 {
 92		t.Fatalf("seller balance = %d, want 550", sellerBal)
 93	}
 94
 95	_, _, status, price, _, _ := AuctionInfo(id)
 96	if status != "sold" {
 97		t.Fatalf("status = %q, want sold", status)
 98	}
 99	if price != 550 {
100		t.Fatalf("frozen price = %d, want 550", price)
101	}
102}
103
104func TestBuyOverpayIsRefunded(cur realm, t *testing.T) {
105	reset()
106	seller := testutils.TestAddress("seller2")
107	buyer := testutils.TestAddress("buyer2")
108
109	testing.SetRealm(testing.NewUserRealm(seller))
110	id := List(cross(cur), "arcade cabinet", 1000, 100, 100)
111
112	fundBuy(buyer, 1000) // pay the full start price up front
113	paid := Buy(cross(cur), id)
114	if paid != 1000 {
115		t.Fatalf("paid = %d, want 1000 (bought at block 0)", paid)
116	}
117
118	ro := banker.NewReadonlyBanker()
119	buyerBal := ro.GetCoins(buyer).AmountOf("ugnot")
120	if buyerBal != 0 {
121		t.Fatalf("buyer refund leftover = %d, want 0 (no overpay at price 1000)", buyerBal)
122	}
123}
124
125func TestBuyUnderpaidPanics(cur realm, t *testing.T) {
126	reset()
127	seller := testutils.TestAddress("seller3")
128	buyer := testutils.TestAddress("buyer3")
129
130	testing.SetRealm(testing.NewUserRealm(seller))
131	id := List(cross(cur), "amp", 1000, 100, 100)
132
133	fundBuy(buyer, 500)
134	rec := revive(func() { Buy(cross(cur), id) })
135	if rec == nil {
136		t.Fatal("expected panic when underpaying")
137	}
138}
139
140func TestCancelBySellerOnly(cur realm, t *testing.T) {
141	reset()
142	seller := testutils.TestAddress("seller4")
143	mallory := testutils.TestAddress("mallory")
144
145	testing.SetRealm(testing.NewUserRealm(seller))
146	id := List(cross(cur), "pedal", 1000, 100, 100)
147
148	testing.SetRealm(testing.NewUserRealm(mallory))
149	rec := revive(func() { Cancel(cross(cur), id) })
150	if rec == nil {
151		t.Fatal("expected panic when a non-seller cancels")
152	}
153
154	testing.SetRealm(testing.NewUserRealm(seller))
155	Cancel(cross(cur), id)
156
157	_, _, status, _, _, _ := AuctionInfo(id)
158	if status != "cancelled" {
159		t.Fatalf("status = %q, want cancelled", status)
160	}
161
162	fundBuy(mallory, 1000)
163	rec = revive(func() { Buy(cross(cur), id) })
164	if rec == nil {
165		t.Fatal("expected panic buying a cancelled auction")
166	}
167}
168
169func TestRenderHome(t *testing.T) {
170	reset()
171	out := Render("")
172	if !strings.Contains(out, "Dutch Auction") {
173		t.Fatalf("render output missing title\n%s", out)
174	}
175}