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.

pausable_test.gno

5.71 Kb · 161 lines
  1package pausable
  2
  3import (
  4	"testing"
  5
  6	"gno.land/p/nt/uassert/v0"
  7)
  8
  9func TestParse(t *testing.T) {
 10	tests := []struct {
 11		raw        string
 12		wantLevel  Level
 13		wantReason string
 14		wantOK     bool
 15	}{
 16		{"", Running, "", true},
 17		{"   ", Running, "", true},
 18		{"running", Running, "", true},
 19		{"readonly", ReadOnly, "", true},
 20		{"paused", Paused, "", true},
 21		{"Paused", Paused, "", true},   // case-insensitive
 22		{"  paused  ", Paused, "", true},
 23		{"paused: migrating storage", Paused, "migrating storage", true},
 24		{"readonly:  spaced  ", ReadOnly, "spaced", true},
 25		{"running: nothing wrong", Running, "nothing wrong", true},
 26		// A reason containing the separator keeps everything after the first
 27		// one, so a URL or a time survives.
 28		{"paused: back at 14:00 UTC", Paused, "back at 14:00 UTC", true},
 29		// Not recognised. These are exactly the values that must NOT read as
 30		// Running.
 31		{"yes", Running, "", false},
 32		{"true", Running, "", false},
 33		{"1", Running, "", false},
 34		{"stop", Running, "", false},
 35		{"read-only", Running, "", false},
 36	}
 37	for _, tt := range tests {
 38		got, ok := Parse(tt.raw)
 39		uassert.Equal(t, tt.wantOK, ok, "Parse("+tt.raw+") ok")
 40		if !ok {
 41			continue
 42		}
 43		uassert.Equal(t, int(tt.wantLevel), int(got.Level), "Parse("+tt.raw+") level")
 44		uassert.Equal(t, tt.wantReason, got.Reason, "Parse("+tt.raw+") reason")
 45	}
 46}
 47
 48// TestMustParseFailsClosed is the whole safety argument of this package. Every
 49// value here is something a person might plausibly type, and every one of them
 50// has to stop the realm rather than quietly leave it running.
 51func TestMustParseFailsClosed(t *testing.T) {
 52	for _, raw := range []string{"yes", "true", "1", "on", "stop", "PAUSE", "pasued"} {
 53		got := MustParse(raw)
 54		uassert.Equal(t, int(Paused), int(got.Level), "MustParse("+raw+") must fail closed")
 55		uassert.False(t, got.AllowsWrite(), "MustParse("+raw+") must refuse writes")
 56		uassert.True(t, len(got.Reason) > 0, "MustParse("+raw+") must say why")
 57	}
 58
 59	// And the values it does understand are untouched.
 60	uassert.Equal(t, int(Running), int(MustParse("").Level))
 61	uassert.Equal(t, int(ReadOnly), int(MustParse("readonly").Level))
 62}
 63
 64func TestAllows(t *testing.T) {
 65	tests := []struct {
 66		level     Level
 67		read      bool
 68		write     bool
 69		isPaused  bool
 70	}{
 71		{Running, true, true, false},
 72		{ReadOnly, true, false, true},
 73		{Paused, false, false, true},
 74	}
 75	for _, tt := range tests {
 76		s := State{Level: tt.level}
 77		uassert.Equal(t, tt.read, s.AllowsRead(), tt.level.String()+" read")
 78		uassert.Equal(t, tt.write, s.AllowsWrite(), tt.level.String()+" write")
 79		uassert.Equal(t, tt.isPaused, s.IsPaused(), tt.level.String()+" isPaused")
 80	}
 81}
 82
 83func TestStrictest(t *testing.T) {
 84	run := State{Level: Running}
 85	ro := State{Level: ReadOnly, Reason: "scoped"}
 86	paused := State{Level: Paused, Reason: "global"}
 87
 88	uassert.Equal(t, int(ReadOnly), int(Strictest(run, ro).Level))
 89	uassert.Equal(t, int(ReadOnly), int(Strictest(ro, run).Level))
 90	uassert.Equal(t, int(Paused), int(Strictest(paused, ro).Level))
 91	uassert.Equal(t, int(Paused), int(Strictest(ro, paused).Level))
 92
 93	// A stale per-realm entry can never re-open a realm during a global halt.
 94	// This is the property the whole precedence rule exists for.
 95	uassert.Equal(t, int(Paused), int(Strictest(paused, run).Level),
 96		"a per-realm 'running' cannot defeat a global pause")
 97
 98	// The reason travels with the level that won.
 99	uassert.Equal(t, "global", Strictest(paused, ro).Reason)
100	uassert.Equal(t, "scoped", Strictest(run, ro).Reason)
101
102	// On a tie the first argument wins, so a caller passing (global, scoped)
103	// keeps the global explanation.
104	a := State{Level: Paused, Reason: "first"}
105	b := State{Level: Paused, Reason: "second"}
106	uassert.Equal(t, "first", Strictest(a, b).Reason)
107}
108
109func TestStringRoundTrips(t *testing.T) {
110	for _, raw := range []string{"", "readonly", "paused", "paused: migrating storage"} {
111		s, ok := Parse(raw)
112		uassert.True(t, ok, "Parse("+raw+")")
113		again, ok := Parse(s.String())
114		uassert.True(t, ok, "Parse(String()) for "+raw)
115		uassert.Equal(t, int(s.Level), int(again.Level), "level round-trip for "+raw)
116		uassert.Equal(t, s.Reason, again.Reason, "reason round-trip for "+raw)
117	}
118
119	// The zero State renders empty, so an unset setting stays unset rather
120	// than being written back as the word "running".
121	uassert.Equal(t, "", State{}.String())
122	uassert.Equal(t, "running: why", State{Reason: "why"}.String())
123}
124
125func TestAsserts(cur realm, t *testing.T) {
126	State{}.AssertWritable()
127	State{}.AssertReadable()
128	State{Level: ReadOnly}.AssertReadable()
129
130	uassert.PanicsWithMessage(t, cur, "writes are paused", func() {
131		State{Level: ReadOnly}.AssertWritable()
132	})
133	uassert.PanicsWithMessage(t, cur, "writes are paused: migrating", func() {
134		State{Level: Paused, Reason: "migrating"}.AssertWritable()
135	})
136	uassert.PanicsWithMessage(t, cur, "paused: migrating", func() {
137		State{Level: Paused, Reason: "migrating"}.AssertReadable()
138	})
139}
140
141func TestNotice(t *testing.T) {
142	uassert.Equal(t, "", State{}.Notice(), "a running realm shows no banner")
143
144	uassert.Equal(t,
145		"> **Read-only.** This realm is still readable, but not accepting changes.",
146		State{Level: ReadOnly}.Notice())
147
148	uassert.Equal(t,
149		"> **Paused.** This realm is not accepting anything right now. back in an hour",
150		State{Level: Paused, Reason: "back in an hour"}.Notice())
151}
152
153// TestNoticeStaysOneBlock covers the reason a manager typed. It lands inside a
154// markdown blockquote, where a newline ends the quote and lets the rest render
155// as ordinary page content, so it is folded to one line.
156func TestNoticeStaysOneBlock(t *testing.T) {
157	s := State{Level: Paused, Reason: "line one\n\nline two\n# not a heading"}
158	uassert.Equal(t,
159		"> **Paused.** This realm is not accepting anything right now. line one line two # not a heading",
160		s.Notice())
161}