Skip to content

Commit 746d9d7

Browse files
committed
Move schema validation result parsing code to dedicated file
Additional JSON schema validation result parsing functions will be added so having them in a dedicated file, separate them from the schema compilation and validation code, will make the code base easier to navigate.
1 parent 99f300a commit 746d9d7

File tree

2 files changed

+154
-130
lines changed

2 files changed

+154
-130
lines changed

Diff for: check/checkdata/schema/parsevalidationresult.go

+154
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
// This file is part of arduino-check.
2+
//
3+
// Copyright 2020 ARDUINO SA (http://www.arduino.cc/)
4+
//
5+
// This software is released under the GNU General Public License version 3,
6+
// which covers the main part of arduino-check.
7+
// The terms of this license can be found at:
8+
// https://www.gnu.org/licenses/gpl-3.0.en.html
9+
//
10+
// You can be released from the requirements of the above licenses by purchasing
11+
// a commercial license. Buying such a license is mandatory if you want to
12+
// modify or otherwise use the software for commercial activities involving the
13+
// Arduino software without disclosing the source code of your own applications.
14+
// To purchase a commercial license, send an email to [email protected].
15+
16+
package schema
17+
18+
import (
19+
"encoding/json"
20+
"regexp"
21+
22+
"github.com/arduino/go-paths-helper"
23+
"github.com/ory/jsonschema/v3"
24+
"github.com/sirupsen/logrus"
25+
)
26+
27+
// RequiredPropertyMissing returns whether the given required property is missing from the document.
28+
func RequiredPropertyMissing(propertyName string, validationResult *jsonschema.ValidationError, schemasPath *paths.Path) bool {
29+
return ValidationErrorMatch("#", "/required$", "", "^#/"+propertyName+"$", validationResult, schemasPath)
30+
}
31+
32+
// PropertyPatternMismatch returns whether the given property did not match the regular expression defined in the JSON schema.
33+
func PropertyPatternMismatch(propertyName string, validationResult *jsonschema.ValidationError, schemasPath *paths.Path) bool {
34+
return ValidationErrorMatch("#/"+propertyName, "/pattern$", "", "", validationResult, schemasPath)
35+
}
36+
37+
// ValidationErrorMatch returns whether the given query matches against the JSON schema validation error.
38+
// See: https://godoc.org/github.com/ory/jsonschema#ValidationError
39+
func ValidationErrorMatch(
40+
instancePointerQuery,
41+
schemaPointerQuery,
42+
schemaPointerValueQuery,
43+
failureContextQuery string,
44+
validationResult *jsonschema.ValidationError,
45+
schemasPath *paths.Path,
46+
) bool {
47+
if validationResult == nil {
48+
// No error, so nothing to match
49+
logrus.Trace("Schema validation passed. No match is possible.")
50+
return false
51+
}
52+
53+
instancePointerRegexp := regexp.MustCompile(instancePointerQuery)
54+
schemaPointerRegexp := regexp.MustCompile(schemaPointerQuery)
55+
schemaPointerValueRegexp := regexp.MustCompile(schemaPointerValueQuery)
56+
failureContextRegexp := regexp.MustCompile(failureContextQuery)
57+
58+
return validationErrorMatch(
59+
instancePointerRegexp,
60+
schemaPointerRegexp,
61+
schemaPointerValueRegexp,
62+
failureContextRegexp,
63+
validationResult,
64+
schemasPath)
65+
}
66+
67+
func validationErrorMatch(
68+
instancePointerRegexp,
69+
schemaPointerRegexp,
70+
schemaPointerValueRegexp,
71+
failureContextRegexp *regexp.Regexp,
72+
validationError *jsonschema.ValidationError,
73+
schemasPath *paths.Path,
74+
) bool {
75+
logrus.Trace("--------Checking schema validation failure match--------")
76+
logrus.Tracef("Checking instance pointer: %s match with regexp: %s", validationError.InstancePtr, instancePointerRegexp)
77+
if instancePointerRegexp.MatchString(validationError.InstancePtr) {
78+
logrus.Tracef("Matched!")
79+
logrus.Tracef("Checking schema pointer: %s match with regexp: %s", validationError.SchemaPtr, schemaPointerRegexp)
80+
if schemaPointerRegexp.MatchString(validationError.SchemaPtr) {
81+
logrus.Tracef("Matched!")
82+
if validationErrorSchemaPointerValueMatch(schemaPointerValueRegexp, validationError, schemasPath) {
83+
logrus.Tracef("Matched!")
84+
logrus.Tracef("Checking failure context: %v match with regexp: %s", validationError.Context, failureContextRegexp)
85+
if validationErrorContextMatch(failureContextRegexp, validationError) {
86+
logrus.Tracef("Matched!")
87+
return true
88+
}
89+
}
90+
}
91+
}
92+
93+
// Recursively check all causes for a match.
94+
for _, validationErrorCause := range validationError.Causes {
95+
if validationErrorMatch(
96+
instancePointerRegexp,
97+
schemaPointerRegexp,
98+
schemaPointerValueRegexp,
99+
failureContextRegexp,
100+
validationErrorCause,
101+
schemasPath,
102+
) {
103+
return true
104+
}
105+
}
106+
107+
return false
108+
}
109+
110+
// validationErrorSchemaPointerValueMatch marshalls the data in the schema at the given JSON pointer and returns whether
111+
// it matches against the given regular expression.
112+
func validationErrorSchemaPointerValueMatch(
113+
schemaPointerValueRegexp *regexp.Regexp,
114+
validationError *jsonschema.ValidationError,
115+
schemasPath *paths.Path,
116+
) bool {
117+
marshalledSchemaPointerValue, err := json.Marshal(schemaPointerValue(validationError, schemasPath))
118+
logrus.Tracef("Checking schema pointer value: %s match with regexp: %s", marshalledSchemaPointerValue, schemaPointerValueRegexp)
119+
if err != nil {
120+
panic(err)
121+
}
122+
return schemaPointerValueRegexp.Match(marshalledSchemaPointerValue)
123+
}
124+
125+
// validationErrorContextMatch parses the validation error context data and returns whether it matches against the given
126+
// regular expression.
127+
func validationErrorContextMatch(failureContextRegexp *regexp.Regexp, validationError *jsonschema.ValidationError) bool {
128+
// This was added in the github.com/ory/jsonschema fork of github.com/santhosh-tekuri/jsonschema
129+
// It currently only provides context about the `required` keyword.
130+
switch contextObject := validationError.Context.(type) {
131+
case nil:
132+
return failureContextRegexp.MatchString("")
133+
case *jsonschema.ValidationErrorContextRequired:
134+
return validationErrorContextRequiredMatch(failureContextRegexp, contextObject)
135+
default:
136+
logrus.Errorf("Unhandled validation error context type: %T", validationError.Context)
137+
return failureContextRegexp.MatchString("")
138+
}
139+
}
140+
141+
// validationErrorContextRequiredMatch returns whether any of the JSON pointers of missing required properties match
142+
// against the given regular expression.
143+
func validationErrorContextRequiredMatch(
144+
failureContextRegexp *regexp.Regexp,
145+
contextObject *jsonschema.ValidationErrorContextRequired,
146+
) bool {
147+
// See: https://godoc.org/github.com/ory/jsonschema#ValidationErrorContextRequired
148+
for _, requiredPropertyPointer := range contextObject.Missing {
149+
if failureContextRegexp.MatchString(requiredPropertyPointer) {
150+
return true
151+
}
152+
}
153+
return false
154+
}

Diff for: check/checkdata/schema/schema.go

-130
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import (
2222
"net/url"
2323
"path"
2424
"path/filepath"
25-
"regexp"
2625

2726
"github.com/arduino/go-paths-helper"
2827
"github.com/arduino/go-properties-orderedmap"
@@ -77,46 +76,6 @@ func Validate(instanceObject *properties.Map, schemaObject *jsonschema.Schema, s
7776
return result
7877
}
7978

80-
// RequiredPropertyMissing returns whether the given required property is missing from the document.
81-
func RequiredPropertyMissing(propertyName string, validationResult *jsonschema.ValidationError, schemasPath *paths.Path) bool {
82-
return ValidationErrorMatch("#", "/required$", "", "^#/"+propertyName+"$", validationResult, schemasPath)
83-
}
84-
85-
// PropertyPatternMismatch returns whether the given property did not match the regular expression defined in the JSON schema.
86-
func PropertyPatternMismatch(propertyName string, validationResult *jsonschema.ValidationError, schemasPath *paths.Path) bool {
87-
return ValidationErrorMatch("#/"+propertyName, "/pattern$", "", "", validationResult, schemasPath)
88-
}
89-
90-
// ValidationErrorMatch returns whether the given query matches against the JSON schema validation error.
91-
// See: https://godoc.org/github.com/ory/jsonschema#ValidationError
92-
func ValidationErrorMatch(
93-
instancePointerQuery,
94-
schemaPointerQuery,
95-
schemaPointerValueQuery,
96-
failureContextQuery string,
97-
validationResult *jsonschema.ValidationError,
98-
schemasPath *paths.Path,
99-
) bool {
100-
if validationResult == nil {
101-
// No error, so nothing to match
102-
logrus.Trace("Schema validation passed. No match is possible.")
103-
return false
104-
}
105-
106-
instancePointerRegexp := regexp.MustCompile(instancePointerQuery)
107-
schemaPointerRegexp := regexp.MustCompile(schemaPointerQuery)
108-
schemaPointerValueRegexp := regexp.MustCompile(schemaPointerValueQuery)
109-
failureContextRegexp := regexp.MustCompile(failureContextQuery)
110-
111-
return validationErrorMatch(
112-
instancePointerRegexp,
113-
schemaPointerRegexp,
114-
schemaPointerValueRegexp,
115-
failureContextRegexp,
116-
validationResult,
117-
schemasPath)
118-
}
119-
12079
// loadReferencedSchema adds a schema that is referenced by the parent schema to the compiler object.
12180
func loadReferencedSchema(compiler *jsonschema.Compiler, schemaFilename string, schemasPath *paths.Path) error {
12281
schemaPath := schemasPath.Join(schemaFilename)
@@ -225,92 +184,3 @@ func jsonPointerValue(jsonPointer string, filePath *paths.Path) interface{} {
225184
}
226185
return jsonPointerValue
227186
}
228-
229-
func validationErrorMatch(
230-
instancePointerRegexp,
231-
schemaPointerRegexp,
232-
schemaPointerValueRegexp,
233-
failureContextRegexp *regexp.Regexp,
234-
validationError *jsonschema.ValidationError,
235-
schemasPath *paths.Path,
236-
) bool {
237-
logrus.Trace("--------Checking schema validation failure match--------")
238-
logrus.Tracef("Checking instance pointer: %s match with regexp: %s", validationError.InstancePtr, instancePointerRegexp)
239-
if instancePointerRegexp.MatchString(validationError.InstancePtr) {
240-
logrus.Tracef("Matched!")
241-
logrus.Tracef("Checking schema pointer: %s match with regexp: %s", validationError.SchemaPtr, schemaPointerRegexp)
242-
if schemaPointerRegexp.MatchString(validationError.SchemaPtr) {
243-
logrus.Tracef("Matched!")
244-
if validationErrorSchemaPointerValueMatch(schemaPointerValueRegexp, validationError, schemasPath) {
245-
logrus.Tracef("Matched!")
246-
logrus.Tracef("Checking failure context: %v match with regexp: %s", validationError.Context, failureContextRegexp)
247-
if validationErrorContextMatch(failureContextRegexp, validationError) {
248-
logrus.Tracef("Matched!")
249-
return true
250-
}
251-
}
252-
}
253-
}
254-
255-
// Recursively check all causes for a match.
256-
for _, validationErrorCause := range validationError.Causes {
257-
if validationErrorMatch(
258-
instancePointerRegexp,
259-
schemaPointerRegexp,
260-
schemaPointerValueRegexp,
261-
failureContextRegexp,
262-
validationErrorCause,
263-
schemasPath,
264-
) {
265-
return true
266-
}
267-
}
268-
269-
return false
270-
}
271-
272-
// validationErrorSchemaPointerValueMatch marshalls the data in the schema at the given JSON pointer and returns whether
273-
// it matches against the given regular expression.
274-
func validationErrorSchemaPointerValueMatch(
275-
schemaPointerValueRegexp *regexp.Regexp,
276-
validationError *jsonschema.ValidationError,
277-
schemasPath *paths.Path,
278-
) bool {
279-
marshalledSchemaPointerValue, err := json.Marshal(schemaPointerValue(validationError, schemasPath))
280-
logrus.Tracef("Checking schema pointer value: %s match with regexp: %s", marshalledSchemaPointerValue, schemaPointerValueRegexp)
281-
if err != nil {
282-
panic(err)
283-
}
284-
return schemaPointerValueRegexp.Match(marshalledSchemaPointerValue)
285-
}
286-
287-
// validationErrorContextMatch parses the validation error context data and returns whether it matches against the given
288-
// regular expression.
289-
func validationErrorContextMatch(failureContextRegexp *regexp.Regexp, validationError *jsonschema.ValidationError) bool {
290-
// This was added in the github.com/ory/jsonschema fork of github.com/santhosh-tekuri/jsonschema
291-
// It currently only provides context about the `required` keyword.
292-
switch contextObject := validationError.Context.(type) {
293-
case nil:
294-
return failureContextRegexp.MatchString("")
295-
case *jsonschema.ValidationErrorContextRequired:
296-
return validationErrorContextRequiredMatch(failureContextRegexp, contextObject)
297-
default:
298-
logrus.Errorf("Unhandled validation error context type: %T", validationError.Context)
299-
return failureContextRegexp.MatchString("")
300-
}
301-
}
302-
303-
// validationErrorContextRequiredMatch returns whether any of the JSON pointers of missing required properties match
304-
// against the given regular expression.
305-
func validationErrorContextRequiredMatch(
306-
failureContextRegexp *regexp.Regexp,
307-
contextObject *jsonschema.ValidationErrorContextRequired,
308-
) bool {
309-
// See: https://godoc.org/github.com/ory/jsonschema#ValidationErrorContextRequired
310-
for _, requiredPropertyPointer := range contextObject.Missing {
311-
if failureContextRegexp.MatchString(requiredPropertyPointer) {
312-
return true
313-
}
314-
}
315-
return false
316-
}

0 commit comments

Comments
 (0)