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.

toolbox_test.gno

4.88 Kb · 158 lines
  1package toolbox
  2
  3import (
  4	"testing"
  5
  6	"gno.land/p/nt/uassert/v0"
  7)
  8
  9func TestValidSlug(t *testing.T) {
 10	cases := []struct {
 11		name string
 12		slug string
 13		want bool
 14	}{
 15		{"plain", "usernames", true},
 16		{"dashed", "gov-dao", true},
 17		{"digits", "base64", true},
 18		{"all dashes", "--", true},
 19		{"empty", "", false},
 20		{"uppercase", "Usernames", false},
 21		{"underscore", "gov_dao", false},
 22		{"slash", "a/b", false},
 23		{"space", "gov dao", false},
 24		{"dot", "v0.1", false},
 25		{"percent", "a%2Fb", false},
 26	}
 27	for _, tc := range cases {
 28		t.Run(tc.name, func(t *testing.T) {
 29			uassert.Equal(t, tc.want, ValidSlug(tc.slug))
 30		})
 31	}
 32}
 33
 34func TestBasePath(t *testing.T) {
 35	cases := []struct {
 36		name string
 37		in   string
 38		want string
 39	}{
 40		{"versioned realm", "gno.land/r/moul/toolbox/v0", "gno.land/r/moul/toolbox"},
 41		{"two digit version", "gno.land/r/moul/toolbox/v12", "gno.land/r/moul/toolbox"},
 42		{"nested tool", "gno.land/r/moul/toolbox/usernames/v0", "gno.land/r/moul/toolbox/usernames"},
 43		{"unversioned", "gno.land/r/moul/home", "gno.land/r/moul/home"},
 44		{"idempotent", "gno.land/r/moul/toolbox", "gno.land/r/moul/toolbox"},
 45		{"v with no digit", "gno.land/r/moul/v", "gno.land/r/moul/v"},
 46		{"v with a letter", "gno.land/r/moul/v0a", "gno.land/r/moul/v0a"},
 47		{"no slash", "toolbox", "toolbox"},
 48		{"empty", "", ""},
 49	}
 50	for _, tc := range cases {
 51		t.Run(tc.name, func(t *testing.T) {
 52			uassert.Equal(t, tc.want, BasePath(tc.in))
 53		})
 54	}
 55}
 56
 57func TestIsUnderAndSlugOf(t *testing.T) {
 58	const hub = "gno.land/r/moul/toolbox/v0"
 59	cases := []struct {
 60		name      string
 61		path      string
 62		wantUnder bool
 63		wantSlug  string
 64	}{
 65		{"direct tool", "gno.land/r/moul/toolbox/usernames/v0", true, "usernames"},
 66		{"unversioned tool", "gno.land/r/moul/toolbox/usernames", true, "usernames"},
 67		{"tool at another version", "gno.land/r/moul/toolbox/usernames/v3", true, "usernames"},
 68		{"nested deeper", "gno.land/r/moul/toolbox/a/b/v0", true, ""},
 69		{"the hub itself", hub, false, ""},
 70		{"hub unversioned", "gno.land/r/moul/toolbox", false, ""},
 71		{"prefix sibling", "gno.land/r/moul/toolboxtwo/v0", false, ""},
 72		{"unrelated realm", "gno.land/r/moul/home", false, ""},
 73		{"empty", "", false, ""},
 74	}
 75	for _, tc := range cases {
 76		t.Run(tc.name, func(t *testing.T) {
 77			uassert.Equal(t, tc.wantUnder, IsUnder(hub, tc.path))
 78			uassert.Equal(t, tc.wantSlug, SlugOf(hub, tc.path))
 79		})
 80	}
 81}
 82
 83// TestIsUnderIgnoresEitherSideVersion is the claim the package doc makes: a
 84// hub and a tool may each carry a version or not, independently, and all four
 85// combinations answer the same. The live shape is the unversioned one, since a
 86// private realm is redeployable and its version could never increment.
 87func TestIsUnderIgnoresEitherSideVersion(t *testing.T) {
 88	hubs := []string{"gno.land/r/moul/toolbox", "gno.land/r/moul/toolbox/v0"}
 89	tools := []string{"gno.land/r/moul/toolbox/usernames", "gno.land/r/moul/toolbox/usernames/v2"}
 90	for _, hub := range hubs {
 91		for _, tool := range tools {
 92			t.Run(hub+" <- "+tool, func(t *testing.T) {
 93				uassert.True(t, IsUnder(hub, tool))
 94				uassert.Equal(t, "usernames", SlugOf(hub, tool))
 95				uassert.False(t, IsUnder(hub, hub))
 96			})
 97		}
 98	}
 99}
100
101// TestIsUnderEmptyHub pins the one input that would otherwise make every path
102// a tool: an empty hub path has no family to be below.
103func TestIsUnderEmptyHub(t *testing.T) {
104	uassert.False(t, IsUnder("", "gno.land/r/moul/toolbox/usernames/v0"))
105	uassert.Equal(t, "", SlugOf("", "gno.land/r/moul/toolbox/usernames/v0"))
106}
107
108func TestToolValidate(t *testing.T) {
109	ok := Tool{Slug: "usernames", Path: "gno.land/r/moul/toolbox/usernames/v0", Title: "Usernames"}
110	cases := []struct {
111		name string
112		tool Tool
113		want error
114	}{
115		{"complete", ok, nil},
116		{"no slug", Tool{Path: ok.Path, Title: ok.Title}, ErrEmptySlug},
117		{"bad slug", Tool{Slug: "User Names", Path: ok.Path, Title: ok.Title}, ErrBadSlug},
118		{"no path", Tool{Slug: ok.Slug, Title: ok.Title}, ErrEmptyPath},
119		{"no title", Tool{Slug: ok.Slug, Path: ok.Path}, ErrEmptyTitle},
120	}
121	for _, tc := range cases {
122		t.Run(tc.name, func(t *testing.T) {
123			got := tc.tool.Validate()
124			if tc.want == nil {
125				uassert.NoError(t, got)
126				return
127			}
128			uassert.ErrorIs(t, got, tc.want)
129		})
130	}
131}
132
133func TestToolURL(t *testing.T) {
134	cases := []struct {
135		name string
136		path string
137		want string
138	}{
139		{"chain path", "gno.land/r/moul/toolbox/usernames/v0", "/r/moul/toolbox/usernames/v0"},
140		{"other domain", "example.com/r/x/v0", "/r/x/v0"},
141		{"already a url", "/r/moul/toolbox/v0", "/r/moul/toolbox/v0"},
142		{"no slash", "toolbox", "toolbox"},
143	}
144	for _, tc := range cases {
145		t.Run(tc.name, func(t *testing.T) {
146			uassert.Equal(t, tc.want, Tool{Path: tc.path}.URL())
147		})
148	}
149}
150
151func TestToolHasTag(t *testing.T) {
152	tool := Tool{Tags: []string{"identity", "read"}}
153	uassert.True(t, tool.HasTag("identity"))
154	uassert.True(t, tool.HasTag("read"))
155	uassert.False(t, tool.HasTag("Identity"))
156	uassert.False(t, tool.HasTag(""))
157	uassert.False(t, Tool{}.HasTag("identity"))
158}