From 746d9d771d2ed73a819caff025de94ba2ffb0d46 Mon Sep 17 00:00:00 2001
From: per1234 <accounts@perglass.com>
Date: Mon, 9 Nov 2020 21:23:00 -0800
Subject: [PATCH] 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.
---
 .../checkdata/schema/parsevalidationresult.go | 154 ++++++++++++++++++
 check/checkdata/schema/schema.go              | 130 ---------------
 2 files changed, 154 insertions(+), 130 deletions(-)
 create mode 100644 check/checkdata/schema/parsevalidationresult.go

diff --git a/check/checkdata/schema/parsevalidationresult.go b/check/checkdata/schema/parsevalidationresult.go
new file mode 100644
index 00000000..ea59f97b
--- /dev/null
+++ b/check/checkdata/schema/parsevalidationresult.go
@@ -0,0 +1,154 @@
+// This file is part of arduino-check.
+//
+// Copyright 2020 ARDUINO SA (http://www.arduino.cc/)
+//
+// This software is released under the GNU General Public License version 3,
+// which covers the main part of arduino-check.
+// The terms of this license can be found at:
+// https://www.gnu.org/licenses/gpl-3.0.en.html
+//
+// You can be released from the requirements of the above licenses by purchasing
+// a commercial license. Buying such a license is mandatory if you want to
+// modify or otherwise use the software for commercial activities involving the
+// Arduino software without disclosing the source code of your own applications.
+// To purchase a commercial license, send an email to license@arduino.cc.
+
+package schema
+
+import (
+	"encoding/json"
+	"regexp"
+
+	"github.com/arduino/go-paths-helper"
+	"github.com/ory/jsonschema/v3"
+	"github.com/sirupsen/logrus"
+)
+
+// RequiredPropertyMissing returns whether the given required property is missing from the document.
+func RequiredPropertyMissing(propertyName string, validationResult *jsonschema.ValidationError, schemasPath *paths.Path) bool {
+	return ValidationErrorMatch("#", "/required$", "", "^#/"+propertyName+"$", validationResult, schemasPath)
+}
+
+// PropertyPatternMismatch returns whether the given property did not match the regular expression defined in the JSON schema.
+func PropertyPatternMismatch(propertyName string, validationResult *jsonschema.ValidationError, schemasPath *paths.Path) bool {
+	return ValidationErrorMatch("#/"+propertyName, "/pattern$", "", "", validationResult, schemasPath)
+}
+
+// ValidationErrorMatch returns whether the given query matches against the JSON schema validation error.
+// See: https://godoc.org/github.com/ory/jsonschema#ValidationError
+func ValidationErrorMatch(
+	instancePointerQuery,
+	schemaPointerQuery,
+	schemaPointerValueQuery,
+	failureContextQuery string,
+	validationResult *jsonschema.ValidationError,
+	schemasPath *paths.Path,
+) bool {
+	if validationResult == nil {
+		// No error, so nothing to match
+		logrus.Trace("Schema validation passed. No match is possible.")
+		return false
+	}
+
+	instancePointerRegexp := regexp.MustCompile(instancePointerQuery)
+	schemaPointerRegexp := regexp.MustCompile(schemaPointerQuery)
+	schemaPointerValueRegexp := regexp.MustCompile(schemaPointerValueQuery)
+	failureContextRegexp := regexp.MustCompile(failureContextQuery)
+
+	return validationErrorMatch(
+		instancePointerRegexp,
+		schemaPointerRegexp,
+		schemaPointerValueRegexp,
+		failureContextRegexp,
+		validationResult,
+		schemasPath)
+}
+
+func validationErrorMatch(
+	instancePointerRegexp,
+	schemaPointerRegexp,
+	schemaPointerValueRegexp,
+	failureContextRegexp *regexp.Regexp,
+	validationError *jsonschema.ValidationError,
+	schemasPath *paths.Path,
+) bool {
+	logrus.Trace("--------Checking schema validation failure match--------")
+	logrus.Tracef("Checking instance pointer: %s match with regexp: %s", validationError.InstancePtr, instancePointerRegexp)
+	if instancePointerRegexp.MatchString(validationError.InstancePtr) {
+		logrus.Tracef("Matched!")
+		logrus.Tracef("Checking schema pointer: %s match with regexp: %s", validationError.SchemaPtr, schemaPointerRegexp)
+		if schemaPointerRegexp.MatchString(validationError.SchemaPtr) {
+			logrus.Tracef("Matched!")
+			if validationErrorSchemaPointerValueMatch(schemaPointerValueRegexp, validationError, schemasPath) {
+				logrus.Tracef("Matched!")
+				logrus.Tracef("Checking failure context: %v match with regexp: %s", validationError.Context, failureContextRegexp)
+				if validationErrorContextMatch(failureContextRegexp, validationError) {
+					logrus.Tracef("Matched!")
+					return true
+				}
+			}
+		}
+	}
+
+	// Recursively check all causes for a match.
+	for _, validationErrorCause := range validationError.Causes {
+		if validationErrorMatch(
+			instancePointerRegexp,
+			schemaPointerRegexp,
+			schemaPointerValueRegexp,
+			failureContextRegexp,
+			validationErrorCause,
+			schemasPath,
+		) {
+			return true
+		}
+	}
+
+	return false
+}
+
+// validationErrorSchemaPointerValueMatch marshalls the data in the schema at the given JSON pointer and returns whether
+// it matches against the given regular expression.
+func validationErrorSchemaPointerValueMatch(
+	schemaPointerValueRegexp *regexp.Regexp,
+	validationError *jsonschema.ValidationError,
+	schemasPath *paths.Path,
+) bool {
+	marshalledSchemaPointerValue, err := json.Marshal(schemaPointerValue(validationError, schemasPath))
+	logrus.Tracef("Checking schema pointer value: %s match with regexp: %s", marshalledSchemaPointerValue, schemaPointerValueRegexp)
+	if err != nil {
+		panic(err)
+	}
+	return schemaPointerValueRegexp.Match(marshalledSchemaPointerValue)
+}
+
+// validationErrorContextMatch parses the validation error context data and returns whether it matches against the given
+// regular expression.
+func validationErrorContextMatch(failureContextRegexp *regexp.Regexp, validationError *jsonschema.ValidationError) bool {
+	// This was added in the github.com/ory/jsonschema fork of github.com/santhosh-tekuri/jsonschema
+	// It currently only provides context about the `required` keyword.
+	switch contextObject := validationError.Context.(type) {
+	case nil:
+		return failureContextRegexp.MatchString("")
+	case *jsonschema.ValidationErrorContextRequired:
+		return validationErrorContextRequiredMatch(failureContextRegexp, contextObject)
+	default:
+		logrus.Errorf("Unhandled validation error context type: %T", validationError.Context)
+		return failureContextRegexp.MatchString("")
+	}
+}
+
+// validationErrorContextRequiredMatch returns whether any of the JSON pointers of missing required properties match
+// against the given regular expression.
+func validationErrorContextRequiredMatch(
+	failureContextRegexp *regexp.Regexp,
+	contextObject *jsonschema.ValidationErrorContextRequired,
+) bool {
+	// See: https://godoc.org/github.com/ory/jsonschema#ValidationErrorContextRequired
+	for _, requiredPropertyPointer := range contextObject.Missing {
+		if failureContextRegexp.MatchString(requiredPropertyPointer) {
+			return true
+		}
+	}
+	return false
+}
diff --git a/check/checkdata/schema/schema.go b/check/checkdata/schema/schema.go
index 674b1a7b..56af6150 100644
--- a/check/checkdata/schema/schema.go
+++ b/check/checkdata/schema/schema.go
@@ -22,7 +22,6 @@ import (
 	"net/url"
 	"path"
 	"path/filepath"
-	"regexp"
 
 	"github.com/arduino/go-paths-helper"
 	"github.com/arduino/go-properties-orderedmap"
@@ -77,46 +76,6 @@ func Validate(instanceObject *properties.Map, schemaObject *jsonschema.Schema, s
 	return result
 }
 
-// RequiredPropertyMissing returns whether the given required property is missing from the document.
-func RequiredPropertyMissing(propertyName string, validationResult *jsonschema.ValidationError, schemasPath *paths.Path) bool {
-	return ValidationErrorMatch("#", "/required$", "", "^#/"+propertyName+"$", validationResult, schemasPath)
-}
-
-// PropertyPatternMismatch returns whether the given property did not match the regular expression defined in the JSON schema.
-func PropertyPatternMismatch(propertyName string, validationResult *jsonschema.ValidationError, schemasPath *paths.Path) bool {
-	return ValidationErrorMatch("#/"+propertyName, "/pattern$", "", "", validationResult, schemasPath)
-}
-
-// ValidationErrorMatch returns whether the given query matches against the JSON schema validation error.
-// See: https://godoc.org/github.com/ory/jsonschema#ValidationError
-func ValidationErrorMatch(
-	instancePointerQuery,
-	schemaPointerQuery,
-	schemaPointerValueQuery,
-	failureContextQuery string,
-	validationResult *jsonschema.ValidationError,
-	schemasPath *paths.Path,
-) bool {
-	if validationResult == nil {
-		// No error, so nothing to match
-		logrus.Trace("Schema validation passed. No match is possible.")
-		return false
-	}
-
-	instancePointerRegexp := regexp.MustCompile(instancePointerQuery)
-	schemaPointerRegexp := regexp.MustCompile(schemaPointerQuery)
-	schemaPointerValueRegexp := regexp.MustCompile(schemaPointerValueQuery)
-	failureContextRegexp := regexp.MustCompile(failureContextQuery)
-
-	return validationErrorMatch(
-		instancePointerRegexp,
-		schemaPointerRegexp,
-		schemaPointerValueRegexp,
-		failureContextRegexp,
-		validationResult,
-		schemasPath)
-}
-
 // loadReferencedSchema adds a schema that is referenced by the parent schema to the compiler object.
 func loadReferencedSchema(compiler *jsonschema.Compiler, schemaFilename string, schemasPath *paths.Path) error {
 	schemaPath := schemasPath.Join(schemaFilename)
@@ -225,92 +184,3 @@ func jsonPointerValue(jsonPointer string, filePath *paths.Path) interface{} {
 	}
 	return jsonPointerValue
 }
-
-func validationErrorMatch(
-	instancePointerRegexp,
-	schemaPointerRegexp,
-	schemaPointerValueRegexp,
-	failureContextRegexp *regexp.Regexp,
-	validationError *jsonschema.ValidationError,
-	schemasPath *paths.Path,
-) bool {
-	logrus.Trace("--------Checking schema validation failure match--------")
-	logrus.Tracef("Checking instance pointer: %s match with regexp: %s", validationError.InstancePtr, instancePointerRegexp)
-	if instancePointerRegexp.MatchString(validationError.InstancePtr) {
-		logrus.Tracef("Matched!")
-		logrus.Tracef("Checking schema pointer: %s match with regexp: %s", validationError.SchemaPtr, schemaPointerRegexp)
-		if schemaPointerRegexp.MatchString(validationError.SchemaPtr) {
-			logrus.Tracef("Matched!")
-			if validationErrorSchemaPointerValueMatch(schemaPointerValueRegexp, validationError, schemasPath) {
-				logrus.Tracef("Matched!")
-				logrus.Tracef("Checking failure context: %v match with regexp: %s", validationError.Context, failureContextRegexp)
-				if validationErrorContextMatch(failureContextRegexp, validationError) {
-					logrus.Tracef("Matched!")
-					return true
-				}
-			}
-		}
-	}
-
-	// Recursively check all causes for a match.
-	for _, validationErrorCause := range validationError.Causes {
-		if validationErrorMatch(
-			instancePointerRegexp,
-			schemaPointerRegexp,
-			schemaPointerValueRegexp,
-			failureContextRegexp,
-			validationErrorCause,
-			schemasPath,
-		) {
-			return true
-		}
-	}
-
-	return false
-}
-
-// validationErrorSchemaPointerValueMatch marshalls the data in the schema at the given JSON pointer and returns whether
-// it matches against the given regular expression.
-func validationErrorSchemaPointerValueMatch(
-	schemaPointerValueRegexp *regexp.Regexp,
-	validationError *jsonschema.ValidationError,
-	schemasPath *paths.Path,
-) bool {
-	marshalledSchemaPointerValue, err := json.Marshal(schemaPointerValue(validationError, schemasPath))
-	logrus.Tracef("Checking schema pointer value: %s match with regexp: %s", marshalledSchemaPointerValue, schemaPointerValueRegexp)
-	if err != nil {
-		panic(err)
-	}
-	return schemaPointerValueRegexp.Match(marshalledSchemaPointerValue)
-}
-
-// validationErrorContextMatch parses the validation error context data and returns whether it matches against the given
-// regular expression.
-func validationErrorContextMatch(failureContextRegexp *regexp.Regexp, validationError *jsonschema.ValidationError) bool {
-	// This was added in the github.com/ory/jsonschema fork of github.com/santhosh-tekuri/jsonschema
-	// It currently only provides context about the `required` keyword.
-	switch contextObject := validationError.Context.(type) {
-	case nil:
-		return failureContextRegexp.MatchString("")
-	case *jsonschema.ValidationErrorContextRequired:
-		return validationErrorContextRequiredMatch(failureContextRegexp, contextObject)
-	default:
-		logrus.Errorf("Unhandled validation error context type: %T", validationError.Context)
-		return failureContextRegexp.MatchString("")
-	}
-}
-
-// validationErrorContextRequiredMatch returns whether any of the JSON pointers of missing required properties match
-// against the given regular expression.
-func validationErrorContextRequiredMatch(
-	failureContextRegexp *regexp.Regexp,
-	contextObject *jsonschema.ValidationErrorContextRequired,
-) bool {
-	// See: https://godoc.org/github.com/ory/jsonschema#ValidationErrorContextRequired
-	for _, requiredPropertyPointer := range contextObject.Missing {
-		if failureContextRegexp.MatchString(requiredPropertyPointer) {
-			return true
-		}
-	}
-	return false
-}