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}