Skip to content

Commit 475f489

Browse files
committed
feat: add validations for URLs and more tests
1 parent a3ed936 commit 475f489

14 files changed

+422
-14
lines changed

go.mod

+2
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,6 @@ require (
2424
golang.org/x/text v0.14.0 // indirect
2525
)
2626

27+
replace github.com/go-playground/validator/v10 => /home/fabio/dev/validator
28+
2729
go 1.21

marshallers.go

+2-3
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,9 @@ func (u *URL) MarshalYAML() (interface{}, error) {
2626
return u.String(), nil
2727
}
2828

29-
func (u *URL) String() string {
30-
return (*url.URL)(u).String()
29+
func (u URL) String() string {
30+
return (*url.URL)(&u).String()
3131
}
32-
3332
type UrlOrUrlArray []*URL
3433

3534
func (a *UrlOrUrlArray) UnmarshalYAML(unmarshal func(interface{}) error) error {

parser.go

+2
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,8 @@ func (p *Parser) ParseBytes(in []byte) error {
241241
"date": "must be a date with format 'YYYY-MM-DD'",
242242
"umax": "must be less or equal than",
243243
"umin": "must be more or equal than",
244+
"url_http_url": "must be an HTTP URL",
245+
"url_url": "must be a valid URL",
244246
"is_category_v0_2": "must be a valid category",
245247
"is_scope_v0_2": "must be a valid scope",
246248
"is_italian_ipa_code": "must be a valid Italian Public Administration Code (iPA)",

parser_test.go

+31
Original file line numberDiff line numberDiff line change
@@ -98,20 +98,24 @@ func TestInvalidTestcasesV0_3(t *testing.T) {
9898
"url_missing.yml": ValidationResults{ValidationError{"url", "required", 1, 1}},
9999
"url_wrong_type.yml": ValidationResults{
100100
ValidationError{"url", "wrong type for this field", 6, 1},
101+
ValidationError{"url", "must be a valid URL", 6, 1},
101102
ValidationError{"url", "'' not reachable: missing URL scheme", 6, 1},
102103
ValidationError{"url", "is not a valid code repository", 6, 1},
103104
},
104105
"url_invalid.yml": ValidationResults{
106+
ValidationError{"url", "must be a valid URL", 6, 1},
105107
ValidationError{"url", "'foobar' not reachable: missing URL scheme", 6, 1},
106108
ValidationError{"url", "is not a valid code repository", 6, 1},
107109
},
108110

109111
// landingURL
110112
"landingURL_wrong_type.yml": ValidationResults{
111113
ValidationError{"landingURL", "wrong type for this field", 8, 1},
114+
ValidationError{"landingURL", "must be an HTTP URL", 8, 1},
112115
ValidationError{"landingURL", "'' not reachable: missing URL scheme", 8, 1},
113116
},
114117
"landingURL_invalid.yml": ValidationResults{
118+
ValidationError{"landingURL", "must be an HTTP URL", 8, 1},
115119
ValidationError{"landingURL", "'???' not reachable: missing URL scheme", 8, 1},
116120
},
117121

@@ -221,10 +225,12 @@ func TestInvalidTestcasesV0_3(t *testing.T) {
221225

222226
// roadmap
223227
"roadmap_invalid.yml": ValidationResults{
228+
ValidationError{"roadmap", "must be an HTTP URL", 4, 1},
224229
ValidationError{"roadmap", "'foobar' not reachable: missing URL scheme", 4, 1},
225230
},
226231
"roadmap_wrong_type.yml": ValidationResults{
227232
ValidationError{"roadmap", "wrong type for this field", 4, 1},
233+
ValidationError{"roadmap", "must be an HTTP URL", 4, 1},
228234
ValidationError{"roadmap", "'' not reachable: missing URL scheme", 4, 1},
229235
},
230236

@@ -309,6 +315,24 @@ func TestInvalidTestcasesV0_3(t *testing.T) {
309315
"description_eng_longDescription_too_short_grapheme_clusters.yml": ValidationResults{
310316
ValidationError{"description.eng.longDescription", "must be more or equal than 150", 28, 5},
311317
},
318+
"description_eng_documentation_invalid.yml": ValidationResults{
319+
ValidationError{"description.eng.documentation", "must be an HTTP URL", 25, 5},
320+
ValidationError{"description.eng.documentation", "'not_a_url' not reachable: missing URL scheme", 25, 5},
321+
},
322+
"description_eng_documentation_wrong_type.yml": ValidationResults{
323+
ValidationError{"description.eng.documentation", "wrong type for this field", 25, 1},
324+
ValidationError{"description.eng.documentation", "must be an HTTP URL", 25, 5},
325+
ValidationError{"description.eng.documentation", "'' not reachable: missing URL scheme", 25, 5},
326+
},
327+
"description_eng_apiDocumentation_invalid.yml": ValidationResults{
328+
ValidationError{"description.eng.apiDocumentation", "must be an HTTP URL", 41, 5},
329+
ValidationError{"description.eng.apiDocumentation", "'abc' not reachable: missing URL scheme", 41, 5},
330+
},
331+
"description_eng_apiDocumentation_wrong_type.yml": ValidationResults{
332+
ValidationError{"description.eng.apiDocumentation", "wrong type for this field", 43, 1},
333+
ValidationError{"description.eng.apiDocumentation", "must be an HTTP URL", 43, 5},
334+
ValidationError{"description.eng.apiDocumentation", "'' not reachable: missing URL scheme", 43, 5},
335+
},
312336
"description_eng_screenshots_missing_file.yml": ValidationResults{
313337
ValidationError{
314338
"description.eng.screenshots[0]",
@@ -321,6 +345,10 @@ func TestInvalidTestcasesV0_3(t *testing.T) {
321345
ValidationError{"description.eng.awards", "wrong type for this field", 40, 1},
322346
},
323347
"description_eng_videos_invalid.yml": ValidationResults{
348+
ValidationError{"description.eng.videos[0]", "must be an HTTP URL", 20, 5},
349+
ValidationError{"description.eng.videos[0]", "'ABC' is not a valid video URL supporting oEmbed: invalid oEmbed link: ABC", 20, 5},
350+
},
351+
"description_eng_videos_invalid_oembed.yml": ValidationResults{
324352
ValidationError{"description.eng.videos[0]", "'https://google.com' is not a valid video URL supporting oEmbed: invalid oEmbed link: https://google.com", 20, 5},
325353
},
326354

@@ -383,6 +411,9 @@ func TestInvalidTestcasesV0_3(t *testing.T) {
383411
"maintenance_contractors_email_invalid.yml": ValidationResults{
384412
ValidationError{"maintenance.contractors[0].email", "must be a valid email", 0, 0},
385413
},
414+
"maintenance_contractors_website_invalid.yml": ValidationResults{
415+
ValidationError{"maintenance.contractors[0].website", "must be an HTTP URL", 0, 0}, // TODO: line number
416+
},
386417

387418
// localisation
388419
"localisation_availableLanguages_missing.yml": ValidationResults{

publiccode.go

+7-7
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ type PublicCode struct {
1212

1313
Name string `yaml:"name" validate:"required"`
1414
ApplicationSuite string `yaml:"applicationSuite,omitempty"`
15-
URL *URL `yaml:"url" validate:"required"`
16-
LandingURL *URL `yaml:"landingURL,omitempty"`
15+
URL *URL `yaml:"url" validate:"required,url_url"`
16+
LandingURL *URL `yaml:"landingURL,omitempty" validate:"omitnil,url_http_url"`
1717

1818
IsBasedOn UrlOrUrlArray `yaml:"isBasedOn,omitempty"`
1919
SoftwareVersion string `yaml:"softwareVersion,omitempty"`
@@ -30,7 +30,7 @@ type PublicCode struct {
3030

3131
UsedBy *[]string `yaml:"usedBy,omitempty"`
3232

33-
Roadmap *URL `yaml:"roadmap,omitempty"`
33+
Roadmap *URL `yaml:"roadmap,omitempty" validate:"omitnil,url_http_url"`
3434

3535
DevelopmentStatus string `yaml:"developmentStatus" validate:"required,oneof=concept development beta stable obsolete"`
3636

@@ -77,19 +77,19 @@ type Desc struct {
7777
GenericName string `yaml:"genericName" validate:"umax=35"`
7878
ShortDescription string `yaml:"shortDescription" validate:"required,umax=150"`
7979
LongDescription string `yaml:"longDescription,omitempty" validate:"required,umin=150,umax=10000"`
80-
Documentation *URL `yaml:"documentation,omitempty"`
81-
APIDocumentation *URL `yaml:"apiDocumentation,omitempty"`
80+
Documentation *URL `yaml:"documentation,omitempty" validate:"omitnil,url_http_url"`
81+
APIDocumentation *URL `yaml:"apiDocumentation,omitempty" validate:"omitnil,url_http_url"`
8282
Features *[]string `yaml:"features,omitempty" validate:"gt=0,dive"`
8383
Screenshots []string `yaml:"screenshots,omitempty"`
84-
Videos []*URL `yaml:"videos,omitempty"`
84+
Videos []*URL `yaml:"videos,omitempty" validate:"dive,omitnil,url_http_url"`
8585
Awards []string `yaml:"awards,omitempty"`
8686
}
8787

8888
// Contractor is an entity or entities, if any, that are currently contracted for maintaining the software.
8989
type Contractor struct {
9090
Name string `yaml:"name" validate:"required"`
9191
Email *string `yaml:"email,omitempty" validate:"omitempty,email"`
92-
Website *URL `yaml:"website,omitempty"`
92+
Website *URL `yaml:"website,omitempty" validate:"omitnil,url_http_url"`
9393
Until string `yaml:"until" validate:"required,date"`
9494
}
9595

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
publiccodeYmlVersion: "0.3"
2+
3+
name: Medusa
4+
5+
url: "https://github.com/italia/developers.italia.it.git"
6+
7+
softwareVersion: "dev"
8+
releaseDate: "2017-04-15"
9+
10+
platforms:
11+
- web
12+
13+
categories:
14+
- cloud-management
15+
16+
developmentStatus: development
17+
18+
softwareType: "standalone/other"
19+
20+
description:
21+
eng:
22+
localisedName: Medusa
23+
shortDescription: >
24+
A rather short description which
25+
is probably useless
26+
longDescription: >
27+
Very long description of this software, also split
28+
on multiple rows. You should note what the software
29+
is and why one should need it. This is 158 characters.
30+
Very long description of this software, also split
31+
on multiple rows. You should note what the software
32+
is and why one should need it. This is 316 characters.
33+
Very long description of this software, also split
34+
on multiple rows. You should note what the software
35+
is and why one should need it. This is 474 characters.
36+
Very long description of this software, also split
37+
on multiple rows. You should note what the software
38+
is and why one should need it. This is 632 characters.
39+
40+
# Should NOT validate: must be a valid URL
41+
apiDocumentation: 'abc'
42+
43+
features:
44+
- Just one feature
45+
46+
legal:
47+
license: AGPL-3.0-or-later
48+
49+
maintenance:
50+
type: "community"
51+
52+
contacts:
53+
- name: Francesco Rossi
54+
55+
localisation:
56+
localisationReady: true
57+
availableLanguages:
58+
- eng
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
publiccodeYmlVersion: "0.3"
2+
3+
name: Medusa
4+
5+
url: "https://github.com/italia/developers.italia.it.git"
6+
7+
softwareVersion: "dev"
8+
releaseDate: "2017-04-15"
9+
10+
platforms:
11+
- web
12+
13+
categories:
14+
- cloud-management
15+
16+
developmentStatus: development
17+
18+
softwareType: "standalone/other"
19+
20+
description:
21+
eng:
22+
localisedName: Medusa
23+
shortDescription: >
24+
A rather short description which
25+
is probably useless
26+
longDescription: >
27+
Very long description of this software, also split
28+
on multiple rows. You should note what the software
29+
is and why one should need it. This is 158 characters.
30+
Very long description of this software, also split
31+
on multiple rows. You should note what the software
32+
is and why one should need it. This is 316 characters.
33+
Very long description of this software, also split
34+
on multiple rows. You should note what the software
35+
is and why one should need it. This is 474 characters.
36+
Very long description of this software, also split
37+
on multiple rows. You should note what the software
38+
is and why one should need it. This is 632 characters.
39+
features:
40+
- Just one feature
41+
42+
# Should NOT validate: apiDocumentation must be a string
43+
apiDocumentation: []
44+
45+
legal:
46+
license: AGPL-3.0-or-later
47+
48+
maintenance:
49+
type: "community"
50+
51+
contacts:
52+
- name: Francesco Rossi
53+
54+
localisation:
55+
localisationReady: true
56+
availableLanguages:
57+
- eng
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
publiccodeYmlVersion: "0.3"
2+
3+
name: Medusa
4+
5+
url: "https://github.com/italia/developers.italia.it.git"
6+
7+
softwareVersion: "dev"
8+
releaseDate: "2017-04-15"
9+
10+
platforms:
11+
- web
12+
13+
categories:
14+
- cloud-management
15+
16+
developmentStatus: development
17+
18+
softwareType: "standalone/other"
19+
20+
description:
21+
eng:
22+
localisedName: Medusa
23+
24+
# Should NOT validate: must be a valid URL
25+
documentation: 'not_a_url'
26+
27+
shortDescription: >
28+
A rather short description which
29+
is probably useless
30+
longDescription: >
31+
Very long description of this software, also split
32+
on multiple rows. You should note what the software
33+
is and why one should need it. This is 158 characters.
34+
Very long description of this software, also split
35+
on multiple rows. You should note what the software
36+
is and why one should need it. This is 316 characters.
37+
Very long description of this software, also split
38+
on multiple rows. You should note what the software
39+
is and why one should need it. This is 474 characters.
40+
Very long description of this software, also split
41+
on multiple rows. You should note what the software
42+
is and why one should need it. This is 632 characters.
43+
features:
44+
- Just one feature
45+
46+
legal:
47+
license: AGPL-3.0-or-later
48+
49+
maintenance:
50+
type: "community"
51+
52+
contacts:
53+
- name: Francesco Rossi
54+
55+
localisation:
56+
localisationReady: true
57+
availableLanguages:
58+
- eng
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
publiccodeYmlVersion: "0.3"
2+
3+
name: Medusa
4+
5+
url: "https://github.com/italia/developers.italia.it.git"
6+
7+
softwareVersion: "dev"
8+
releaseDate: "2017-04-15"
9+
10+
platforms:
11+
- web
12+
13+
categories:
14+
- cloud-management
15+
16+
developmentStatus: development
17+
18+
softwareType: "standalone/other"
19+
20+
description:
21+
eng:
22+
localisedName: Medusa
23+
24+
# Should NOT validate: documentation must be a string
25+
documentation: []
26+
27+
shortDescription: >
28+
A rather short description which
29+
is probably useless
30+
longDescription: >
31+
Very long description of this software, also split
32+
on multiple rows. You should note what the software
33+
is and why one should need it. This is 158 characters.
34+
Very long description of this software, also split
35+
on multiple rows. You should note what the software
36+
is and why one should need it. This is 316 characters.
37+
Very long description of this software, also split
38+
on multiple rows. You should note what the software
39+
is and why one should need it. This is 474 characters.
40+
Very long description of this software, also split
41+
on multiple rows. You should note what the software
42+
is and why one should need it. This is 632 characters.
43+
features:
44+
- Just one feature
45+
46+
legal:
47+
license: AGPL-3.0-or-later
48+
49+
maintenance:
50+
type: "community"
51+
52+
contacts:
53+
- name: Francesco Rossi
54+
55+
localisation:
56+
localisationReady: true
57+
availableLanguages:
58+
- eng

0 commit comments

Comments
 (0)