registry_test.gno
7.29 Kb · 177 lines
1package bolo
2
3import (
4 "chain"
5 "strings"
6 "testing"
7
8 "gno.land/p/nt/testutils/v0"
9)
10
11func TestIsVersionPath(t *testing.T) {
12 for _, path := range []string{
13 "gno.land/r/g12yg9nh4ncma44emgm8msxe8aavzywt0p95tanv/bolo/v0",
14 "gno.land/r/g12yg9nh4ncma44emgm8msxe8aavzywt0p95tanv/bolo/v1",
15 "gno.land/r/g12yg9nh4ncma44emgm8msxe8aavzywt0p95tanv/bolo/v12",
16 "gno.land/r/g12yg9nh4ncma44emgm8msxe8aavzywt0p95tanv/bolo/v909",
17 // The longest path the chain deploys: 256 bytes.
18 versionPrefix + "1" + strings.Repeat("0", 256-len(versionPrefix)-1),
19 } {
20 if !isVersionPath(path) {
21 t.Errorf("%s refused", path)
22 }
23 }
24 for _, path := range []string{
25 "",
26 "gno.land/r/g12yg9nh4ncma44emgm8msxe8aavzywt0p95tanv/bolo",
27 "gno.land/r/g12yg9nh4ncma44emgm8msxe8aavzywt0p95tanv/bolo/",
28 "gno.land/r/g12yg9nh4ncma44emgm8msxe8aavzywt0p95tanv/bolo/v",
29 "gno.land/r/g12yg9nh4ncma44emgm8msxe8aavzywt0p95tanv/bolo/v1x",
30 "gno.land/r/g12yg9nh4ncma44emgm8msxe8aavzywt0p95tanv/bolo/v1/x",
31 "gno.land/r/g12yg9nh4ncma44emgm8msxe8aavzywt0p95tanv/bolo/V1",
32 "gno.land/r/g12yg9nh4ncma44emgm8msxe8aavzywt0p95tanv/bolo/v1/../x",
33 "gno.land/r/g12yg9nh4ncma44emgm8msxe8aavzywt0p95tanv/bolo/v012",
34 "gno.land/r/g12yg9nh4ncma44emgm8msxe8aavzywt0p95tanv/bolo/v00",
35 "gno.land/r/g12yg9nh4ncma44emgm8msxe8aavzywt0p95tanv/bolo/v-1",
36 "gno.land/r/g12yg9nh4ncma44emgm8msxe8aavzywt0p95tanv/bolo/v1 ",
37 " gno.land/r/g12yg9nh4ncma44emgm8msxe8aavzywt0p95tanv/bolo/v1",
38 "gno.land/r/g12yg9nh4ncma44emgm8msxe8aavzywt0p95tanv/bolov1",
39 "gno.land/r/other/bolo/v1",
40 "gno.land/p/g12yg9nh4ncma44emgm8msxe8aavzywt0p95tanv/bolo/v1",
41 // One byte too long for the chain to ever deploy.
42 versionPrefix + "1" + strings.Repeat("0", 256-len(versionPrefix)),
43 } {
44 if isVersionPath(path) {
45 t.Errorf("%q accepted", path)
46 }
47 }
48}
49
50func TestCheckNewVersion(t *testing.T) {
51 defer restoreVersions(versions)
52 checkNewVersion("gno.land/r/g12yg9nh4ncma44emgm8msxe8aavzywt0p95tanv/bolo/v3")
53 for name, path := range map[string]string{
54 "not a version": "gno.land/r/g12yg9nh4ncma44emgm8msxe8aavzywt0p95tanv/bolo/v3x",
55 "added already": "gno.land/r/g12yg9nh4ncma44emgm8msxe8aavzywt0p95tanv/bolo/v0",
56 } {
57 added.Set("gno.land/r/g12yg9nh4ncma44emgm8msxe8aavzywt0p95tanv/bolo/v0", true)
58 if !panicsWith(func() { checkNewVersion(path) }, ErrSetting) {
59 t.Errorf("%s: not refused", name)
60 }
61 }
62 // The 50th fits, the 51st doesn't (API §3.7, INV-9).
63 for len(versions) < 49 {
64 versions = append(versions, "filler")
65 }
66 checkNewVersion("gno.land/r/g12yg9nh4ncma44emgm8msxe8aavzywt0p95tanv/bolo/v50")
67 versions = append(versions, "gno.land/r/g12yg9nh4ncma44emgm8msxe8aavzywt0p95tanv/bolo/v50")
68 if !panicsWith(func() { checkNewVersion("gno.land/r/g12yg9nh4ncma44emgm8msxe8aavzywt0p95tanv/bolo/v51") }, ErrSetting) {
69 t.Errorf("a 51st version: not refused")
70 }
71}
72
73func TestCheckCandidate(t *testing.T) {
74 checkCandidate(testutils.TestAddress("dao"))
75 for name, a := range map[string]address{
76 "the registry": chain.PackageAddress("gno.land/r/g12yg9nh4ncma44emgm8msxe8aavzywt0p95tanv/bolo"),
77 "its storage deposit": chain.DeriveStorageDepositAddr("gno.land/r/g12yg9nh4ncma44emgm8msxe8aavzywt0p95tanv/bolo"),
78 "malformed": "g1notanaddress",
79 "in capitals": address(strings.ToUpper(string(testutils.TestAddress("dao")))),
80 } {
81 if !panicsWith(func() { checkCandidate(a) }, ErrSetting) {
82 t.Errorf("%s: not refused", name)
83 }
84 }
85}
86
87// TestRegistry walks a fresh registry, each write called straight from the test's
88// body as AssertOriginCall requires (plan §3.3). The writes' refusals are tested in
89// txtar (registry.txtar): a crossing call's panic can't be recovered here.
90func TestRegistry(cur realm, t *testing.T) {
91 defer restoreRegistry(admin, pendingAdmin, current, versions)
92 if Current() != "" || len(Versions()) != 0 || !strings.Contains(Render(""), "No version is registered yet.") {
93 t.Errorf("a fresh registry isn't empty")
94 }
95 if a, p := GetAdmin(); a != adminAddr || p != "" {
96 t.Errorf("GetAdmin() = %s, %q", a, p)
97 }
98
99 testing.SetRealm(testing.NewUserRealm(adminAddr))
100 AddVersion(cross(cur), "gno.land/r/g12yg9nh4ncma44emgm8msxe8aavzywt0p95tanv/bolo/v0")
101 AddVersion(cross(cur), "gno.land/r/g12yg9nh4ncma44emgm8msxe8aavzywt0p95tanv/bolo/v1")
102 // No version is current yet: the page links to none.
103 if got := Render(""); strings.Contains(got, "Open Bolo") || !strings.Contains(got, "- [gno.land/r/g12yg9nh4ncma44emgm8msxe8aavzywt0p95tanv/bolo/v1](/r/g12yg9nh4ncma44emgm8msxe8aavzywt0p95tanv/bolo/v1)\n") {
104 t.Errorf("Render before SetCurrent:\n%s", got)
105 }
106 SetCurrent(cross(cur), "gno.land/r/g12yg9nh4ncma44emgm8msxe8aavzywt0p95tanv/bolo/v1")
107 if Current() != "gno.land/r/g12yg9nh4ncma44emgm8msxe8aavzywt0p95tanv/bolo/v1" {
108 t.Errorf("Current() = %q", Current())
109 }
110 vs := Versions()
111 if len(vs) != 2 || vs[0] != "gno.land/r/g12yg9nh4ncma44emgm8msxe8aavzywt0p95tanv/bolo/v0" || vs[1] != "gno.land/r/g12yg9nh4ncma44emgm8msxe8aavzywt0p95tanv/bolo/v1" {
112 t.Errorf("Versions() = %v", vs)
113 }
114 // Versions hands out a copy (C6).
115 vs[0] = "changed"
116 if Versions()[0] != "gno.land/r/g12yg9nh4ncma44emgm8msxe8aavzywt0p95tanv/bolo/v0" {
117 t.Errorf("Versions shares its slice with the realm")
118 }
119 want := "# Bolo\n\nGive together. See where it goes.\n\n" +
120 "**[Open Bolo](/r/g12yg9nh4ncma44emgm8msxe8aavzywt0p95tanv/bolo/v1)**, where new campaigns start.\n\n" +
121 "## Versions\n\nEach campaign runs to its end on the version it started on: money never moves between versions.\n\n" +
122 "- [gno.land/r/g12yg9nh4ncma44emgm8msxe8aavzywt0p95tanv/bolo/v0](/r/g12yg9nh4ncma44emgm8msxe8aavzywt0p95tanv/bolo/v0)\n" +
123 "- [gno.land/r/g12yg9nh4ncma44emgm8msxe8aavzywt0p95tanv/bolo/v1](/r/g12yg9nh4ncma44emgm8msxe8aavzywt0p95tanv/bolo/v1) — current\n"
124 if got := Render(""); got != want {
125 t.Errorf("Render =\n%s\nwant\n%s", got, want)
126 }
127 // Render ignores its path.
128 if got := Render("<b>x</b>?page=2"); got != want {
129 t.Errorf("Render echoes its path:\n%s", got)
130 }
131
132 // The handover, to a realm, which then acts through C11's realm branch.
133 dao := chain.PackageAddress("gno.land/r/test/dao")
134 ProposeAdmin(cross(cur), testutils.TestAddress("someone"))
135 ProposeAdmin(cross(cur), dao)
136 if a, p := GetAdmin(); a != adminAddr || p != dao {
137 t.Errorf("after two proposals: GetAdmin() = %s, %s", a, p)
138 }
139 testing.SetRealm(testing.NewCodeRealm("gno.land/r/test/dao"))
140 AcceptAdmin(cross(cur))
141 if a, p := GetAdmin(); a != dao || p != "" {
142 t.Errorf("after accepting: GetAdmin() = %s, %q", a, p)
143 }
144 SetCurrent(cross(cur), "gno.land/r/g12yg9nh4ncma44emgm8msxe8aavzywt0p95tanv/bolo/v0")
145 if Current() != "gno.land/r/g12yg9nh4ncma44emgm8msxe8aavzywt0p95tanv/bolo/v0" {
146 t.Errorf("the realm admin's write didn't apply")
147 }
148}
149
150// restoreVersions puts back the versions list and its lookup tree.
151func restoreVersions(saved []string) {
152 for _, path := range versions[len(saved):] {
153 added.Remove(path)
154 }
155 added.Remove("gno.land/r/g12yg9nh4ncma44emgm8msxe8aavzywt0p95tanv/bolo/v0")
156 for _, path := range saved {
157 added.Set(path, true)
158 }
159 versions = saved
160}
161
162// restoreRegistry puts back what TestRegistry changes.
163func restoreRegistry(a, pending address, cur string, saved []string) {
164 admin, pendingAdmin, current = a, pending, cur
165 restoreVersions(saved)
166}
167
168// panicsWith reports whether f panics with err.
169func panicsWith(f func(), err Error) (ok bool) {
170 defer func() {
171 r := recover()
172 e, isErr := r.(Error)
173 ok = isErr && e == err
174 }()
175 f()
176 return false
177}