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.

wiki_test.gno

10.25 Kb · 288 lines
  1package wiki
  2
  3import (
  4	"strings"
  5	"testing"
  6
  7	"gno.land/p/nym-moultest123/x/wiki/v0"
  8	"gno.land/p/nt/testutils/v0"
  9	"gno.land/p/nt/uassert/v0"
 10)
 11
 12var (
 13	alice = testutils.TestAddress("alice")
 14	bob   = testutils.TestAddress("bob")
 15	// carol edits only in TestCooldown: the cooldown is keyed by address and
 16	// by block height, and gno's testing.SkipHeights is relative, so a test
 17	// that reused an address another test already edited with would see a
 18	// zero-height delta and trip the cooldown before it meant to.
 19	carol = testutils.TestAddress("carol")
 20)
 21
 22// TestBasePathMatchesTheRealm pins the constant used to build every link
 23// against the realm's own path. A wrong basePath produces a page whose links
 24// all 404, and nothing else would catch it.
 25func TestBasePathMatchesTheRealm(t *testing.T) {
 26	uassert.True(t, strings.HasSuffix(basePath, "/r/nym-moultest123/x/wiki/v0"), basePath)
 27	out := Render("Gno_land")
 28	uassert.True(t, strings.Contains(out, "("+basePath+":Tendermint2)"), out)
 29}
 30
 31func TestRenderRoutes(t *testing.T) {
 32	cases := []struct {
 33		path string
 34		want string
 35	}{
 36		{"", "# Wiki"},
 37		{"Gno_land", "# Gno land"},
 38		{"gno_land", "# Gno land"},                      // titles normalize
 39		{"Gno_land/history", "# History of Gno land"},   //
 40		{"Gno_land/raw", "# Source of Gno land"},        //
 41		{"Gno_land/rev/1", "revision 1"},                //
 42		{"Nonexistent_page", "does not exist yet"},      //
 43		{"Special:AllPages", "# All pages"},             //
 44		{"Special:allpages", "# All pages"},             // case-insensitive
 45		{"Special:Categories", "# Categories"},          //
 46		{"Special:RecentChanges", "# Recent changes"},   //
 47		{"Special:Stats", "# Wiki stats"},               //
 48		{"Special:Backlinks?page=Gno", "Pages that link to Gno"},
 49		{"Special:Nope", "404"},
 50		{"Gno_land/nope", "404"},
 51		{"Gno_land/rev/999", "404"},
 52		{"Category:Chains", "Pages in this category"},
 53		{"Gno_land/talk", "# Discussion: Gno land"},
 54	}
 55	for _, c := range cases {
 56		out := Render(c.path)
 57		uassert.True(t, strings.Contains(out, c.want),
 58			"Render("+c.path+") should contain "+c.want+", got: "+first80(out))
 59	}
 60}
 61
 62func TestRenderIsTotal(t *testing.T) {
 63	// Render is reached from a URL, so malformed input must produce a page,
 64	// never an abort that makes the realm unreadable.
 65	for _, path := range []string{"Gno|land", "Special:Backlinks?page=", "Gno_land/diff?from=x&to=y", "//"} {
 66		uassert.NotEmpty(t, Render(path), path)
 67	}
 68}
 69
 70func TestEditAndRevert(cur realm, t *testing.T) {
 71	testing.SetRealm(testing.NewUserRealm(alice))
 72	rev := Edit(cross(cur), "Alice page", "First body.\n", "create")
 73	uassert.True(t, rev > 0)
 74
 75	testing.SetRealm(testing.NewUserRealm(bob))
 76	Edit(cross(cur), "Alice page", "Vandalized.\n", "oops")
 77	uassert.True(t, strings.Contains(Render("Alice_page"), "Vandalized."))
 78
 79	testing.SetRealm(testing.NewUserRealm(alice))
 80	Revert(cross(cur), "Alice page", rev, "rv")
 81	out := Render("Alice_page")
 82	uassert.True(t, strings.Contains(out, "First body."))
 83	// The vandalism is still in the history: that is the point of a wiki.
 84	uassert.True(t, strings.Contains(Render("Alice_page/history"), "oops"))
 85}
 86
 87func TestEditRejectsAnEmptyBody(cur realm, t *testing.T) {
 88	testing.SetRealm(testing.NewUserRealm(alice))
 89	uassert.AbortsContains(t, cur, "empty title", func() {
 90		Edit(cross(cur), "", "body\n", "")
 91	})
 92	uassert.AbortsContains(t, cur, "empty body", func() {
 93		Edit(cross(cur), "Some page", "", "")
 94	})
 95}
 96
 97func TestBannedAddressCannotEdit(cur realm, t *testing.T) {
 98	testing.SetRealm(testing.NewUserRealm(steward))
 99	Ban(cross(cur), bob)
100
101	testing.SetRealm(testing.NewUserRealm(bob))
102	uassert.AbortsContains(t, cur, "banned", func() {
103		Edit(cross(cur), "Ban test", "body\n", "")
104	})
105
106	testing.SetRealm(testing.NewUserRealm(steward))
107	Unban(cross(cur), bob)
108	testing.SetRealm(testing.NewUserRealm(bob))
109	uassert.True(t, Edit(cross(cur), "Ban test", "body\n", "") > 0)
110}
111
112func TestProtectionLevels(cur realm, t *testing.T) {
113	testing.SetRealm(testing.NewUserRealm(alice))
114	Edit(cross(cur), "Protected page", "body\n", "")
115
116	testing.SetRealm(testing.NewUserRealm(steward))
117	Protect(cross(cur), "Protected page", "semi")
118
119	testing.SetRealm(testing.NewUserRealm(alice))
120	uassert.AbortsContains(t, cur, "semi-protected", func() {
121		Edit(cross(cur), "Protected page", "sneaky\n", "")
122	})
123
124	testing.SetRealm(testing.NewUserRealm(steward))
125	AddEditor(cross(cur), alice)
126	testing.SetRealm(testing.NewUserRealm(alice))
127	uassert.True(t, Edit(cross(cur), "Protected page", "allowed\n", "") > 0)
128
129	testing.SetRealm(testing.NewUserRealm(steward))
130	Protect(cross(cur), "Protected page", "locked")
131	testing.SetRealm(testing.NewUserRealm(alice))
132	uassert.AbortsContains(t, cur, "caller is not owner", func() {
133		Edit(cross(cur), "Protected page", "still sneaky\n", "")
134	})
135}
136
137func TestStewardOnlyFunctionsRejectOthers(cur realm, t *testing.T) {
138	testing.SetRealm(testing.NewUserRealm(alice))
139	Edit(cross(cur), "Steward test", "body\n", "")
140
141	for _, call := range []struct {
142		name string
143		fn   func()
144	}{
145		{"Protect", func() { Protect(cross(cur), "Steward test", "locked") }},
146		{"Move", func() { Move(cross(cur), "Steward test", "Elsewhere", "") }},
147		{"Blank", func() { Blank(cross(cur), "Steward test", "") }},
148		{"Purge", func() { Purge(cross(cur), "Steward test") }},
149		{"Ban", func() { Ban(cross(cur), bob) }},
150		{"SetCooldown", func() { SetCooldown(cross(cur), 5) }},
151	} {
152		testing.SetRealm(testing.NewUserRealm(alice))
153		uassert.AbortsContains(t, cur, "caller is not owner", call.fn, call.name)
154	}
155}
156
157func TestCooldown(cur realm, t *testing.T) {
158	testing.SetRealm(testing.NewUserRealm(steward))
159	SetCooldown(cross(cur), 5)
160
161	testing.SetRealm(testing.NewUserRealm(carol))
162	Edit(cross(cur), "Cooldown page", "one\n", "")
163	uassert.AbortsContains(t, cur, "cooldown", func() {
164		Edit(cross(cur), "Cooldown page", "two\n", "")
165	})
166
167	testing.SkipHeights(6)
168	testing.SetRealm(testing.NewUserRealm(carol))
169	uassert.True(t, Edit(cross(cur), "Cooldown page", "two\n", "") > 0)
170
171	testing.SetRealm(testing.NewUserRealm(steward))
172	SetCooldown(cross(cur), 0)
173}
174
175func TestBlankAndPurgeReleaseBytes(cur realm, t *testing.T) {
176	testing.SetRealm(testing.NewUserRealm(alice))
177	Edit(cross(cur), "Purge page", "a body worth some bytes\n", "")
178
179	testing.SetRealm(testing.NewUserRealm(steward))
180	Blank(cross(cur), "Purge page", "policy")
181	uassert.True(t, strings.Contains(Render("Purge_page"), "was blanked"))
182
183	testing.SetRealm(testing.NewUserRealm(steward))
184	released := Purge(cross(cur), "Purge page")
185	uassert.True(t, released > 0, "purging a page with a retained body must release bytes")
186	uassert.True(t, strings.Contains(Render("Purge_page/history"), "body evicted"))
187}
188
189func TestMoveLeavesARedirect(cur realm, t *testing.T) {
190	testing.SetRealm(testing.NewUserRealm(alice))
191	Edit(cross(cur), "Before move", "the body\n", "")
192
193	testing.SetRealm(testing.NewUserRealm(steward))
194	Move(cross(cur), "Before move", "After move", "rename")
195
196	uassert.True(t, strings.Contains(Render("After_move"), "the body"))
197	// Reading the old title follows the redirect; its history does not.
198	uassert.True(t, strings.Contains(Render("Before_move"), "the body"))
199	uassert.True(t, strings.Contains(Render("Before_move/raw"), "#REDIRECT"))
200}
201
202// TestSeedIsLinkedTogether checks the deployed starting state renders as a
203// connected wiki rather than four orphans.
204func TestSeedIsLinkedTogether(t *testing.T) {
205	uassert.True(t, strings.Contains(Render("Gno_land"), "("+basePath+":Gno)"))
206	uassert.True(t, strings.Contains(Render("Special:Backlinks?page=Gno_land"), "[Gno]"))
207	uassert.True(t, strings.Contains(Render("Category:Chains"), "[Gno land]"))
208}
209
210// TestParseTitleIsTheSameOneTheLibraryUses guards against the realm and the
211// library disagreeing about what a title is, which would make a page
212// creatable but unreachable.
213func TestParseTitleIsTheSameOneTheLibraryUses(t *testing.T) {
214	tt := wiki.MustParseTitle("Gno land")
215	uassert.Equal(t, "Gno_land", tt.Slug())
216	uassert.True(t, strings.Contains(Render(tt.Slug()), "# Gno land"))
217}
218
219func first80(s string) string {
220	if len(s) > 80 {
221		return s[:80]
222	}
223	return s
224}
225
226func TestCommentOnALockedPage(cur realm, t *testing.T) {
227	testing.SetRealm(testing.NewUserRealm(alice))
228	Edit(cross(cur), "Locked talk", "body\n", "")
229
230	testing.SetRealm(testing.NewUserRealm(steward))
231	Protect(cross(cur), "Locked talk", "locked")
232
233	// Locking an article is how a steward stops an edit war; the discussion
234	// is where that war is supposed to move, so it stays open.
235	testing.SetRealm(testing.NewUserRealm(alice))
236	uassert.AbortsContains(t, cur, "caller is not owner", func() {
237		Edit(cross(cur), "Locked talk", "sneaky\n", "")
238	})
239	testing.SetRealm(testing.NewUserRealm(alice))
240	id := Comment(cross(cur), "Locked talk", "I disagree, and here is why.\n", 0)
241	uassert.True(t, id > 0)
242	uassert.True(t, strings.Contains(Render("Locked_talk/talk"), "I disagree"))
243}
244
245func TestCommentRepliesAndModeration(cur realm, t *testing.T) {
246	testing.SetRealm(testing.NewUserRealm(alice))
247	Edit(cross(cur), "Talk target", "body\n", "")
248	root := Comment(cross(cur), "Talk target", "First.\n", 0)
249
250	testing.SetRealm(testing.NewUserRealm(bob))
251	Comment(cross(cur), "Talk target", "Replying.\n", root)
252
253	out := Render("Talk_target/talk")
254	uassert.True(t, strings.Contains(out, "First."))
255	uassert.True(t, strings.Contains(out, "Replying."))
256
257	testing.SetRealm(testing.NewUserRealm(steward))
258	released := HideComment(cross(cur), "Talk target", root)
259	uassert.True(t, released > 0, "hiding a message releases its bytes")
260	out = Render("Talk_target/talk")
261	uassert.True(t, strings.Contains(out, "removed by a steward"))
262	uassert.False(t, strings.Contains(out, "First."))
263}
264
265func TestBannedAddressCannotComment(cur realm, t *testing.T) {
266	testing.SetRealm(testing.NewUserRealm(alice))
267	Edit(cross(cur), "Ban talk", "body\n", "")
268
269	testing.SetRealm(testing.NewUserRealm(steward))
270	Ban(cross(cur), bob)
271	testing.SetRealm(testing.NewUserRealm(bob))
272	uassert.AbortsContains(t, cur, "banned", func() {
273		Comment(cross(cur), "Ban talk", "spam\n", 0)
274	})
275	testing.SetRealm(testing.NewUserRealm(steward))
276	Unban(cross(cur), bob)
277}
278
279func TestHideCommentIsStewardOnly(cur realm, t *testing.T) {
280	testing.SetRealm(testing.NewUserRealm(alice))
281	Edit(cross(cur), "Mod talk", "body\n", "")
282	id := Comment(cross(cur), "Mod talk", "hello\n", 0)
283
284	testing.SetRealm(testing.NewUserRealm(bob))
285	uassert.AbortsContains(t, cur, "caller is not owner", func() {
286		HideComment(cross(cur), "Mod talk", id)
287	})
288}