diff --git a/.run/build.run.xml b/.run/build.run.xml new file mode 100644 index 00000000..cc73411b --- /dev/null +++ b/.run/build.run.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.run/format.run.xml b/.run/format.run.xml index 64e3c038..6742b4d0 100644 --- a/.run/format.run.xml +++ b/.run/format.run.xml @@ -1,7 +1,8 @@ - - - - - + + + + + + \ No newline at end of file diff --git a/.run/gofmt.run.xml b/.run/gofmt.run.xml deleted file mode 100644 index dad3de0b..00000000 --- a/.run/gofmt.run.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - \ No newline at end of file diff --git a/go.mod b/go.mod index 2b681cc1..2cd8fdf9 100644 --- a/go.mod +++ b/go.mod @@ -22,6 +22,7 @@ require ( github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.19.0 github.com/stretchr/testify v1.9.0 + github.com/xeipuuv/gojsonschema v1.2.0 golang.org/x/net v0.26.0 ) @@ -34,6 +35,8 @@ require ( github.com/sagikazarmark/locafero v0.6.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/sourcegraph/conc v0.3.0 // indirect + github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect + github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect go.uber.org/multierr v1.11.0 // indirect ) @@ -53,5 +56,5 @@ require ( golang.org/x/sys v0.21.0 // indirect golang.org/x/text v0.16.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect + gopkg.in/yaml.v3 v3.0.1 ) diff --git a/go.sum b/go.sum index c52cba3e..515037f5 100644 --- a/go.sum +++ b/go.sum @@ -88,6 +88,7 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= @@ -95,6 +96,12 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 h1:yixxcjnhBmY0nkL253HFVIm0JsFHwrHdT3Yh6szTnfY= diff --git a/makefile b/makefile index df6cb34c..50345494 100644 --- a/makefile +++ b/makefile @@ -8,7 +8,7 @@ update_deps: go mod tidy test: - go test -v ./... + go test ./... test-cover: go test -tags release -timeout 1m -race -v -coverprofile=coverage.out ./... @@ -17,4 +17,7 @@ build: go build ./... build-release: - go build -tags release ./... \ No newline at end of file + go build -tags release ./... + +clean: + rm -rf ./uncors ./uncors.exe coverage.out \ No newline at end of file diff --git a/testing/testutils/fs.go b/testing/testutils/fs.go index 6dd2fff1..6fedb1f0 100644 --- a/testing/testutils/fs.go +++ b/testing/testutils/fs.go @@ -2,8 +2,12 @@ package testutils import ( "os" + "path/filepath" + "runtime" "testing" + "github.com/stretchr/testify/require" + "github.com/spf13/afero" ) @@ -22,3 +26,11 @@ func FsFromMap(t *testing.T, files map[string]string) afero.Fs { return fs } + +func CurrentDir(t *testing.T) string { + t.Helper() + _, callerFile, _, ok := runtime.Caller(1) + require.True(t, ok, "Failed to get caller information") + + return filepath.Dir(callerFile) +} diff --git a/tests/schema/helpers.go b/tests/schema/helpers.go new file mode 100644 index 00000000..d4b455e9 --- /dev/null +++ b/tests/schema/helpers.go @@ -0,0 +1,42 @@ +package schema + +import ( + "encoding/json" + "os" + "path/filepath" + "strings" + "testing" + + "github.com/evg4b/uncors/testing/testutils" + "github.com/stretchr/testify/require" + "gopkg.in/yaml.v3" +) + +func TransformToJSON(t *testing.T, dir string, file string) string { + t.Helper() + yamlFilePath := filepath.Join(testutils.CurrentDir(t), file) + jsonFilePath := filepath.Join(dir, strings.Replace(filepath.Base(file), ".yaml", ".json", 1)) + + yamlFile, err := os.OpenFile(yamlFilePath, os.O_RDONLY, os.ModePerm) + require.NoError(t, err, "Failed to open file: %v", err) + defer yamlFile.Close() + + jsonFile, err := os.OpenFile(jsonFilePath, os.O_CREATE|os.O_WRONLY, os.ModePerm) + require.NoError(t, err, "Failed to open file: %v", err) + defer yamlFile.Close() + + var data any + err = yaml.NewDecoder(yamlFile).Decode(&data) + require.NoError(t, err, "Failed to decode yaml: %v", err) + + err = json.NewEncoder(jsonFile).Encode(data) + require.NoError(t, err, "Failed to encode json: %v", err) + + return jsonFilePath +} + +func DirPredicate(dir string) func(string) string { + return func(file string) string { + return filepath.Join(dir, file) + } +} diff --git a/tests/schema/invalid/empty-mappings.yaml b/tests/schema/invalid/empty-mappings.yaml new file mode 100644 index 00000000..b20135dd --- /dev/null +++ b/tests/schema/invalid/empty-mappings.yaml @@ -0,0 +1 @@ +mappings: [] \ No newline at end of file diff --git a/tests/schema/invalid/not-full-mapping.yaml b/tests/schema/invalid/not-full-mapping.yaml new file mode 100644 index 00000000..7d42a511 --- /dev/null +++ b/tests/schema/invalid/not-full-mapping.yaml @@ -0,0 +1,3 @@ +mappings: + - from: http://localhost + to: diff --git a/tests/schema/invalid_test.go b/tests/schema/invalid_test.go new file mode 100644 index 00000000..b8620c60 --- /dev/null +++ b/tests/schema/invalid_test.go @@ -0,0 +1,61 @@ +package schema_test + +import ( + "path/filepath" + "testing" + + "github.com/evg4b/uncors/tests/schema" + + "github.com/evg4b/uncors/testing/testutils" + "github.com/samber/lo" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/xeipuuv/gojsonschema" +) + +func TestInvalidJsonSchema(t *testing.T) { + testdir := schema.DirPredicate("invalid") + + testTempDir := t.TempDir() + jsonSchemaPath := filepath.Join(testutils.CurrentDir(t), "../../schema.json") + + cases := []struct { + name string + file string + errors []string + }{ + { + name: "empty mappings", + file: testdir("empty-mappings.yaml"), + errors: []string{ + "mappings: Array must have at least 1 items", + }, + }, + { + name: "not full mapping", + file: testdir("not-full-mapping.yaml"), + errors: []string{ + "mappings.0: Must validate one and only one schema (oneOf)", + "mappings.0.to: Invalid type. Expected: string, given: null", + }, + }, + } + + for _, testCase := range cases { + t.Run(testCase.name, func(t *testing.T) { + targetJSONFile := schema.TransformToJSON(t, testTempDir, testCase.file) + + schemaLoader := gojsonschema.NewReferenceLoader("file://" + jsonSchemaPath) + documentLoader := gojsonschema.NewReferenceLoader("file://" + targetJSONFile) + + result, err := gojsonschema.Validate(schemaLoader, documentLoader) + require.NoError(t, err) + + errors := lo.Map(result.Errors(), func(err gojsonschema.ResultError, _ int) string { + return err.String() + }) + + assert.Equal(t, testCase.errors, errors, "The errors are not as expected") + }) + } +} diff --git a/tests/schema/valid/minimal-valid.yaml b/tests/schema/valid/minimal-valid.yaml new file mode 100644 index 00000000..7396b730 --- /dev/null +++ b/tests/schema/valid/minimal-valid.yaml @@ -0,0 +1,3 @@ +mappings: + - from: http://localhost + to: https://github.com \ No newline at end of file diff --git a/tests/schema/valid/short-mapping.yaml b/tests/schema/valid/short-mapping.yaml new file mode 100644 index 00000000..ef695731 --- /dev/null +++ b/tests/schema/valid/short-mapping.yaml @@ -0,0 +1,3 @@ +http-port: 3000 +mappings: + - http://localhost: https://github.com \ No newline at end of file diff --git a/tests/schema/valid_test.go b/tests/schema/valid_test.go new file mode 100644 index 00000000..03f5ffd8 --- /dev/null +++ b/tests/schema/valid_test.go @@ -0,0 +1,50 @@ +package schema_test + +import ( + "path/filepath" + "testing" + + "github.com/evg4b/uncors/tests/schema" + + "github.com/evg4b/uncors/testing/testutils" + + "github.com/stretchr/testify/assert" + + "github.com/stretchr/testify/require" + "github.com/xeipuuv/gojsonschema" +) + +func TestValidJsonSchema(t *testing.T) { + testdir := schema.DirPredicate("valid") + + testTempDir := t.TempDir() + jsonSchemaPath := filepath.Join(testutils.CurrentDir(t), "../../schema.json") + + cases := []struct { + name string + file string + }{ + { + name: "minimal valid file", + file: testdir("minimal-valid.yaml"), + }, + { + name: "short mapping", + file: testdir("short-mapping.yaml"), + }, + } + + for _, testCase := range cases { + t.Run(testCase.name, func(t *testing.T) { + targetJSONFile := schema.TransformToJSON(t, testTempDir, testCase.file) + + schemaLoader := gojsonschema.NewReferenceLoader("file://" + jsonSchemaPath) + documentLoader := gojsonschema.NewReferenceLoader("file://" + targetJSONFile) + + result, err := gojsonschema.Validate(schemaLoader, documentLoader) + require.NoError(t, err) + + assert.Empty(t, result.Errors(), "The document is not valid") + }) + } +}