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.

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}