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}