1// Copyright 2018 The Gitea Authors. All rights reserved.
2// SPDX-License-Identifier: MIT
3
4package validation
5
6import (
7 "testing"
8
9 "forgejo.org/modules/setting"
10
11 "github.com/stretchr/testify/assert"
12)
13
14func Test_IsValidURL(t *testing.T) {
15 cases := []struct {
16 description string
17 url string
18 valid bool
19 }{
20 {
21 description: "Empty URL",
22 url: "",
23 valid: false,
24 },
25 {
26 description: "Loopback IPv4 URL",
27 url: "http://127.0.1.1:5678/",
28 valid: true,
29 },
30 {
31 description: "Loopback IPv6 URL",
32 url: "https://[::1]/",
33 valid: true,
34 },
35 {
36 description: "Missing semicolon after schema",
37 url: "http//meh/",
38 valid: false,
39 },
40 }
41
42 for _, testCase := range cases {
43 t.Run(testCase.description, func(t *testing.T) {
44 assert.Equal(t, testCase.valid, IsValidURL(testCase.url))
45 })
46 }
47}
48
49func Test_IsValidExternalURL(t *testing.T) {
50 setting.AppURL = "https://try.gitea.io/"
51
52 cases := []struct {
53 description string
54 url string
55 valid bool
56 }{
57 {
58 description: "Current instance URL",
59 url: "https://try.gitea.io/test",
60 valid: true,
61 },
62 {
63 description: "Loopback IPv4 URL",
64 url: "http://127.0.1.1:5678/",
65 valid: false,
66 },
67 {
68 description: "Current instance API URL",
69 url: "https://try.gitea.io/api/v1/user/follow",
70 valid: false,
71 },
72 {
73 description: "Local network URL",
74 url: "http://192.168.1.2/api/v1/user/follow",
75 valid: true,
76 },
77 {
78 description: "Local URL",
79 url: "http://LOCALHOST:1234/whatever",
80 valid: false,
81 },
82 }
83
84 for _, testCase := range cases {
85 t.Run(testCase.description, func(t *testing.T) {
86 assert.Equal(t, testCase.valid, IsValidExternalURL(testCase.url))
87 })
88 }
89}
90
91func Test_IsValidExternalTrackerURLFormat(t *testing.T) {
92 setting.AppURL = "https://try.gitea.io/"
93
94 cases := []struct {
95 description string
96 url string
97 valid bool
98 }{
99 {
100 description: "Correct external tracker URL with all placeholders",
101 url: "https://github.com/{user}/{repo}/issues/{index}",
102 valid: true,
103 },
104 {
105 description: "Local external tracker URL with all placeholders",
106 url: "https://127.0.0.1/{user}/{repo}/issues/{index}",
107 valid: false,
108 },
109 {
110 description: "External tracker URL with typo placeholder",
111 url: "https://github.com/{user}/{repo/issues/{index}",
112 valid: false,
113 },
114 {
115 description: "External tracker URL with typo placeholder",
116 url: "https://github.com/[user}/{repo/issues/{index}",
117 valid: false,
118 },
119 {
120 description: "External tracker URL with typo placeholder",
121 url: "https://github.com/{user}/repo}/issues/{index}",
122 valid: false,
123 },
124 {
125 description: "External tracker URL missing optional placeholder",
126 url: "https://github.com/{user}/issues/{index}",
127 valid: true,
128 },
129 {
130 description: "External tracker URL missing optional placeholder",
131 url: "https://github.com/{repo}/issues/{index}",
132 valid: true,
133 },
134 {
135 description: "External tracker URL missing optional placeholder",
136 url: "https://github.com/issues/{index}",
137 valid: true,
138 },
139 {
140 description: "External tracker URL missing optional placeholder",
141 url: "https://github.com/issues/{user}",
142 valid: true,
143 },
144 {
145 description: "External tracker URL with similar placeholder names test",
146 url: "https://github.com/user/repo/issues/{index}",
147 valid: true,
148 },
149 }
150
151 for _, testCase := range cases {
152 t.Run(testCase.description, func(t *testing.T) {
153 assert.Equal(t, testCase.valid, IsValidExternalTrackerURLFormat(testCase.url))
154 })
155 }
156}
157
158func TestIsValidUsernameAllowDots(t *testing.T) {
159 setting.Service.AllowDotsInUsernames = true
160 tests := []struct {
161 arg string
162 want bool
163 }{
164 {arg: "a", want: true},
165 {arg: "abc", want: true},
166 {arg: "0.b-c", want: true},
167 {arg: "a.b-c_d", want: true},
168 {arg: "", want: false},
169 {arg: ".abc", want: false},
170 {arg: "abc.", want: false},
171 {arg: "a..bc", want: false},
172 {arg: "a...bc", want: false},
173 {arg: "a.-bc", want: false},
174 {arg: "a._bc", want: false},
175 {arg: "a_-bc", want: false},
176 {arg: "a/bc", want: false},
177 {arg: "☁️", want: false},
178 {arg: "-", want: false},
179 {arg: "--diff", want: false},
180 {arg: "-im-here", want: false},
181 {arg: "a space", want: false},
182 }
183 for _, tt := range tests {
184 t.Run(tt.arg, func(t *testing.T) {
185 assert.Equalf(t, tt.want, IsValidUsername(tt.arg), "IsValidUsername(%v)", tt.arg)
186 })
187 }
188}
189
190func TestIsValidUsernameBanDots(t *testing.T) {
191 setting.Service.AllowDotsInUsernames = false
192 defer func() {
193 setting.Service.AllowDotsInUsernames = true
194 }()
195
196 tests := []struct {
197 arg string
198 want bool
199 }{
200 {arg: "a", want: true},
201 {arg: "abc", want: true},
202 {arg: "0.b-c", want: false},
203 {arg: "a.b-c_d", want: false},
204 {arg: ".abc", want: false},
205 {arg: "abc.", want: false},
206 {arg: "a..bc", want: false},
207 {arg: "a...bc", want: false},
208 {arg: "a.-bc", want: false},
209 {arg: "a._bc", want: false},
210 }
211 for _, tt := range tests {
212 t.Run(tt.arg, func(t *testing.T) {
213 assert.Equalf(t, tt.want, IsValidUsername(tt.arg), "IsValidUsername[AllowDotsInUsernames=false](%v)", tt.arg)
214 })
215 }
216}