Skip to content

Commit e46a0a7

Browse files
committed
tests: add validation URL tests
1 parent de3cf09 commit e46a0a7

File tree

2 files changed

+168
-2
lines changed

2 files changed

+168
-2
lines changed

provider/helpers/validation.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,18 @@ import (
55
"net/url"
66
)
77

8-
// ValidateURL checks that the given value is a valid URL string.
8+
// ValidateURL validates that value is a valid URL string.
9+
// Accepts empty strings, local file paths, file:// URLs, and http/https URLs.
910
// Example: for `icon = "/icon/region.svg"`, value is `/icon/region.svg` and label is `icon`.
10-
func ValidateURL(value interface{}, label string) ([]string, []error) {
11+
func ValidateURL(value any, label string) ([]string, []error) {
1112
val, ok := value.(string)
1213
if !ok {
1314
return nil, []error{fmt.Errorf("expected %q to be a string", label)}
1415
}
16+
1517
if _, err := url.Parse(val); err != nil {
1618
return nil, []error{err}
1719
}
20+
1821
return nil, nil
1922
}

provider/helpers/validation_test.go

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
package helpers
2+
3+
import (
4+
"strings"
5+
"testing"
6+
)
7+
8+
func TestValidateURL(t *testing.T) {
9+
tests := []struct {
10+
name string
11+
value any
12+
label string
13+
expectError bool
14+
errorContains string
15+
}{
16+
// Valid cases
17+
{
18+
name: "empty string",
19+
value: "",
20+
label: "url",
21+
expectError: false,
22+
},
23+
{
24+
name: "valid http URL",
25+
value: "http://example.com",
26+
label: "url",
27+
expectError: false,
28+
},
29+
{
30+
name: "valid https URL",
31+
value: "https://example.com/path",
32+
label: "url",
33+
expectError: false,
34+
},
35+
{
36+
name: "absolute file path",
37+
value: "/path/to/file",
38+
label: "url",
39+
expectError: false,
40+
},
41+
{
42+
name: "relative file path",
43+
value: "./file.txt",
44+
label: "url",
45+
expectError: false,
46+
},
47+
{
48+
name: "relative path up directory",
49+
value: "../config.json",
50+
label: "url",
51+
expectError: false,
52+
},
53+
{
54+
name: "simple filename",
55+
value: "file.txt",
56+
label: "url",
57+
expectError: false,
58+
},
59+
{
60+
name: "URL with query params",
61+
value: "https://example.com/search?q=test",
62+
label: "url",
63+
expectError: false,
64+
},
65+
{
66+
name: "URL with fragment",
67+
value: "https://example.com/page#section",
68+
label: "url",
69+
expectError: false,
70+
},
71+
72+
// Various URL schemes that url.Parse accepts
73+
{
74+
name: "file URL scheme",
75+
value: "file:///path/to/file",
76+
label: "url",
77+
expectError: false,
78+
},
79+
{
80+
name: "ftp scheme",
81+
value: "ftp://files.example.com/file.txt",
82+
label: "url",
83+
expectError: false,
84+
},
85+
{
86+
name: "mailto scheme",
87+
value: "mailto:user@example.com",
88+
label: "url",
89+
expectError: false,
90+
},
91+
{
92+
name: "tel scheme",
93+
value: "tel:+1234567890",
94+
label: "url",
95+
expectError: false,
96+
},
97+
{
98+
name: "data scheme",
99+
value: "data:text/plain;base64,SGVsbG8=",
100+
label: "url",
101+
expectError: false,
102+
},
103+
104+
// Invalid cases
105+
{
106+
name: "non-string type - int",
107+
value: 123,
108+
label: "url",
109+
expectError: true,
110+
errorContains: "expected \"url\" to be a string",
111+
},
112+
{
113+
name: "non-string type - nil",
114+
value: nil,
115+
label: "config_url",
116+
expectError: true,
117+
errorContains: "expected \"config_url\" to be a string",
118+
},
119+
{
120+
name: "invalid URL with spaces",
121+
value: "http://example .com",
122+
label: "url",
123+
expectError: true,
124+
errorContains: "invalid character",
125+
},
126+
{
127+
name: "malformed URL",
128+
value: "http://[::1:80",
129+
label: "endpoint",
130+
expectError: true,
131+
errorContains: "missing ']'",
132+
},
133+
}
134+
135+
for _, tt := range tests {
136+
t.Run(tt.name, func(t *testing.T) {
137+
warnings, errors := ValidateURL(tt.value, tt.label)
138+
139+
if tt.expectError {
140+
if len(errors) == 0 {
141+
t.Errorf("expected an error but got none")
142+
return
143+
}
144+
145+
if tt.errorContains != "" {
146+
errorStr := errors[0].Error()
147+
if !strings.Contains(errorStr, tt.errorContains) {
148+
t.Errorf("expected error to contain %q, got %q", tt.errorContains, errorStr)
149+
}
150+
}
151+
} else {
152+
if len(errors) > 0 {
153+
t.Errorf("expected no errors but got: %v", errors)
154+
}
155+
156+
// Should always return nil for warnings
157+
if warnings != nil {
158+
t.Errorf("expected warnings to be nil, got %v", warnings)
159+
}
160+
}
161+
})
162+
}
163+
}

0 commit comments

Comments
 (0)