validate_test.gno
5.13 Kb · 174 lines
1package forge
2
3import (
4 "strings"
5 "testing"
6
7 "gno.land/p/nt/testutils/v0"
8 "gno.land/p/nt/uassert/v0"
9)
10
11func TestValidOID(t *testing.T) {
12 cases := []struct {
13 name string
14 in string
15 want bool
16 }{
17 {"sha1", strings.Repeat("a", 40), true},
18 {"sha256", strings.Repeat("0", 64), true},
19 {"mixed hex", "0123456789abcdef0123456789abcdef01234567", true},
20 {"empty", "", false},
21 {"too short", strings.Repeat("a", 39), false},
22 {"between lengths", strings.Repeat("a", 41), false},
23 {"uppercase", strings.Repeat("A", 40), false},
24 {"non hex", strings.Repeat("z", 40), false},
25 {"abbreviated", "deadbeef", false},
26 }
27 for _, tc := range cases {
28 uassert.Equal(t, tc.want, ValidOID(tc.in), tc.name)
29 }
30}
31
32func TestValidRefName(t *testing.T) {
33 cases := []struct {
34 name string
35 in string
36 want bool
37 }{
38 {"branch", "refs/heads/main", true},
39 {"nested branch", "refs/heads/feat/on-chain-log", true},
40 {"tag", "refs/tags/v1.0.0", true},
41 {"stash-like", "refs/stash", true},
42 {"unqualified", "main", false},
43 {"empty", "", false},
44 {"double slash", "refs/heads//main", false},
45 {"double dot", "refs/heads/a..b", false},
46 {"at brace", "refs/heads/a@{0}", false},
47 {"trailing slash", "refs/heads/", false},
48 {"trailing dot", "refs/heads/main.", false},
49 {"dot prefix", "refs/heads/.hidden", false},
50 {"lock suffix", "refs/heads/main.lock", false},
51 {"space", "refs/heads/my branch", false},
52 {"caret", "refs/heads/main^", false},
53 {"colon", "refs/heads/a:b", false},
54 {"tilde", "refs/heads/main~1", false},
55 {"question", "refs/heads/what?", false},
56 {"star", "refs/heads/*", false},
57 {"backslash", "refs/heads/a\\b", false},
58 {"control", "refs/heads/a\x01b", false},
59 {"too long", "refs/heads/" + strings.Repeat("a", 300), false},
60 }
61 for _, tc := range cases {
62 uassert.Equal(t, tc.want, ValidRefName(tc.in), tc.name)
63 }
64}
65
66func TestValidRepoID(t *testing.T) {
67 cases := []struct {
68 name string
69 in string
70 want bool
71 }{
72 {"simple", "moul/forge", true},
73 {"digits", "ns0/repo9", true},
74 {"dots and dashes", "moul/gno-contracts.x", true},
75 {"underscore", "moul/my_repo", true},
76 {"no slash", "forge", false},
77 {"two slashes", "a/b/c", false},
78 {"empty ns", "/forge", false},
79 {"empty name", "moul/", false},
80 {"uppercase", "Moul/forge", false},
81 {"leading dash", "moul/-forge", false},
82 {"trailing dot", "moul/forge.", false},
83 {"double dot", "moul/fo..rge", false},
84 {"double dash", "moul/fo--rge", false},
85 {"space", "moul/my forge", false},
86 {"too long", "moul/" + strings.Repeat("a", 40), false},
87 }
88 for _, tc := range cases {
89 uassert.Equal(t, tc.want, ValidRepoID(tc.in), tc.name)
90 }
91}
92
93func TestAddressNamespace(t *testing.T) {
94 addr := testutils.TestAddress("alice").String()
95 cases := []struct {
96 name string
97 in string
98 want bool
99 }{
100 {"a real address", addr, true},
101 {"wrong prefix", "x1" + addr[2:], false},
102 {"too short", addr[:39], false},
103 {"too long", addr + "a", false},
104 {"bech32 drops b i o 1", "g1" + strings.Repeat("b", 38), false},
105 {"uppercase", "G1" + addr[2:], false},
106 {"a slug is not an address", "moul", false},
107 }
108 for _, tc := range cases {
109 uassert.Equal(t, tc.want, AddressNamespace(tc.in), tc.name)
110 }
111
112 // An address namespace is a valid repo id, and it cannot collide with a
113 // claimed name: 40 characters is past the slug cap.
114 uassert.True(t, ValidRepoID(addr+"/forge"))
115 uassert.False(t, ValidRepoID(strings.Repeat("a", 40)+"/forge"))
116 uassert.False(t, ValidRepoID(addr+"/"+addr), "the name half is always a slug")
117}
118
119func TestSplitRepoID(t *testing.T) {
120 ns, name, ok := SplitRepoID("moul/forge")
121 uassert.True(t, ok)
122 uassert.Equal(t, "moul", ns)
123 uassert.Equal(t, "forge", name)
124
125 for _, bad := range []string{"", "moul", "/forge", "moul/", "a/b/c"} {
126 _, _, ok := SplitRepoID(bad)
127 uassert.False(t, ok, bad)
128 }
129}
130
131func TestValidTextAndLine(t *testing.T) {
132 uassert.True(t, ValidText("hello\nworld\ttab", 64))
133 uassert.False(t, ValidText("bell\x07", 64))
134 uassert.False(t, ValidText("too long", 3))
135 uassert.True(t, ValidText("", 3))
136
137 uassert.True(t, ValidLine("a single line", 64))
138 uassert.False(t, ValidLine("two\nlines", 64))
139 uassert.False(t, ValidLine("a\ttab", 64))
140}
141
142func TestValidMirrorAndLabel(t *testing.T) {
143 cases := []struct {
144 in string
145 want bool
146 }{
147 {"https://github.com/moul/gno-contracts.git", true},
148 {"[email protected]:moul/gno-contracts.git", true},
149 {"ipfs://bafybeihdwdcefgh4dqkjv67uzcmw7ojee6xedzdetojuzjevtenxquvyku", true},
150 {"rad://z3gqcJUoA1n9HaHKufZs5FCSGazv5", true},
151 {"ar://1QKPaf1AmsK_tSSdUgtVDEYGLuQBOKTNr", true},
152 {"ftp://example.com/repo.git", false},
153 {"not a url", false},
154 {"", false},
155 }
156 for _, tc := range cases {
157 uassert.Equal(t, tc.want, ValidMirror(tc.in), tc.in)
158 }
159
160 uassert.True(t, ValidLabel("bug"))
161 uassert.False(t, ValidLabel(""))
162 uassert.False(t, ValidLabel("a,b"))
163 uassert.False(t, ValidLabel(strings.Repeat("x", 33)))
164}
165
166func TestParseRoleRoundTrip(t *testing.T) {
167 for _, r := range []Role{RoleNone, RoleReader, RoleWriter, RoleMaintainer, RoleAdmin, RoleOwner} {
168 got, err := ParseRole(r.String())
169 uassert.NoError(t, err, r.String())
170 uassert.Equal(t, int(r), int(got), r.String())
171 }
172 _, err := ParseRole("root")
173 uassert.ErrorIs(t, err, ErrInvalidRole)
174}