1package coins23import (4 "chain"5 "strings"6 "testing"78 "gno.land/p/leon/ctg/v0"9 "gno.land/p/nt/testutils/v0"10 "gno.land/p/nt/ufmt/v0"11)1213func TestBalanceChecker(t *testing.T) {14 denom1 := "testtoken1"15 denom2 := "testtoken2"16 addr1 := testutils.TestAddress("user1")17 addr2 := testutils.TestAddress("user2")1819 coinsRealm := testing.NewCodeRealm("gno.land/r/gnoland/coins")20 testing.SetRealm(coinsRealm)2122 testing.IssueCoins(addr1, chain.NewCoins(chain.NewCoin(denom1, 1000000)))23 testing.IssueCoins(addr2, chain.NewCoins(chain.NewCoin(denom1, 501)))2425 testing.IssueCoins(addr2, chain.NewCoins(chain.NewCoin(denom2, 12345)))2627 gnoAddr, _ := ctg.ConvertCosmosToGno("cosmos1s2v4tdskccx2p3yyvzem4mw5nn5fprwcku77hr")28 osmoAddr := "osmo1fl48vsnmsdzcv85q5d2q4z5ajdha8yu3aq6l09"29 gnoAddr1, _ := ctg.ConvertAnyToGno(osmoAddr)3031 testing.IssueCoins(gnoAddr1, chain.NewCoins(chain.NewCoin(denom2, 12345)))3233 tests := []struct {34 name string35 path string36 contains string37 wantPanic bool38 }{39 {40 name: "homepage",41 path: "",42 contains: "# Gno.land Coins Explorer",43 },44 // TODO: not supported yet45 // {46 // name: "total supply",47 // path: denom,48 // expected: "Balance: 1500000testtoken",49 // },50 {51 name: "addr1's coin balance",52 path: ufmt.Sprintf("balances?address=%s&coin=%s", addr1.String(), denom1),53 contains: ufmt.Sprintf("`%s` has `%d%s`", addr1.String(), 1000000, denom1),54 },55 {56 name: "addr2's full balances",57 path: ufmt.Sprintf("balances?address=%s", addr2.String()),58 contains: ufmt.Sprintf("This page shows full coin balances of `%s` at block", addr2.String()),59 },60 {61 name: "addr2's full balances",62 path: ufmt.Sprintf("balances?address=%s", addr2.String()),63 contains: `| testtoken1 | 501 |64| testtoken2 | 12345 |`,65 },66 {67 name: "addr2's coin balance",68 path: ufmt.Sprintf("balances?address=%s&coin=%s", addr2.String(), denom1),69 contains: ufmt.Sprintf("`%s` has `%d%s`", addr2.String(), 501, denom1),70 },71 {72 name: "cosmos addr conversion",73 path: "convert/cosmos1s2v4tdskccx2p3yyvzem4mw5nn5fprwcku77hr",74 contains: ufmt.Sprintf("`cosmos1s2v4tdskccx2p3yyvzem4mw5nn5fprwcku77hr` on Cosmos matches `%s`", gnoAddr),75 },76 {77 name: "balances bech32 auto convert",78 path: ufmt.Sprintf("balances?address=%s&coin=%s", osmoAddr, denom1),79 contains: "Automatically converted `osmo1fl48vsnmsdzcv85q5d2q4z5ajdha8yu3aq6l09`",80 },81 {82 name: "single coin balance bech32 auto convert",83 path: ufmt.Sprintf("balances?address=%s", osmoAddr),84 contains: "Automatically converted `osmo1fl48vsnmsdzcv85q5d2q4z5ajdha8yu3aq6l09`",85 },86 {87 // The "coin" parameter is whatever the URL says. banker.GetCoin panics on a88 // malformed denom where chain.Coins.AmountOf returns zero, so this page89 // must be rendered from the balances already read rather than by asking90 // the banker for an unvalidated denom — otherwise any visitor can 500 it.91 name: "malformed coin denom renders zero instead of panicking",92 path: ufmt.Sprintf("balances?address=%s&coin=UPPERCASE", addr1.String()),93 contains: ufmt.Sprintf("`%s` has `%d%s`", addr1.String(), 0, "UPPERCASE"),94 },95 {96 name: "no addr",97 path: "balances?address=",98 contains: "Please input a valid address",99 wantPanic: false,100 },101 {102 name: "no addr",103 path: "balances?address=&coin=",104 contains: "Please input a valid address and coin denomination.",105 wantPanic: false,106 },107 {108 name: "invalid path",109 path: "invalid",110 contains: "404",111 wantPanic: false,112 },113 }114115 for _, tt := range tests {116 t.Run(tt.name, func(t *testing.T) {117 if tt.wantPanic {118 defer func() {119 if r := recover(); r == nil {120 t.Errorf("expected panic for %s", tt.name)121 }122 }()123 }124125 result := Render(tt.path)126 if !tt.wantPanic {127 if !strings.Contains(result, tt.contains) {128 t.Errorf("expected %s to contain %s", result, tt.contains)129 }130 }131 })132 }133}134Render(path string) string
Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.
vm/qrender output, sanitized (docs/render-security.md) and displayed in an empty-sandbox iframe — scripts, forms and popups cannot run. Links stay inert in-preview; right-click to open.