From 9e4aa4e43e48cec3c6db346500526dba8a99387e Mon Sep 17 00:00:00 2001 From: peefy Date: Wed, 29 Nov 2023 21:18:27 +0800 Subject: [PATCH] feat: add validate APIs Signed-off-by: peefy --- kclvm.go | 12 ++++-- pkg/tools/validate/test_data/data-failed.json | 13 +++++++ pkg/tools/validate/test_data/data.json | 13 +++++++ pkg/tools/validate/test_data/schema.k | 14 +++++++ pkg/tools/validate/validate.go | 38 +++++++++++++++++-- pkg/tools/validate/validate_test.go | 19 ++++++++++ 6 files changed, 102 insertions(+), 7 deletions(-) create mode 100644 pkg/tools/validate/test_data/data-failed.json create mode 100644 pkg/tools/validate/test_data/data.json create mode 100644 pkg/tools/validate/test_data/schema.k diff --git a/kclvm.go b/kclvm.go index 7ff9fcca..fece111c 100644 --- a/kclvm.go +++ b/kclvm.go @@ -178,9 +178,15 @@ func OverrideFile(file string, specs, importPaths []string) (bool, error) { return override.OverrideFile(file, specs, importPaths) } -// ValidateCode validate data match code -func ValidateCode(data, code string, opt *ValidateOptions) (ok bool, err error) { - return validate.ValidateCode(data, code, opt) +// ValidateCode validate data string match code string +func ValidateCode(data, code string, opts *ValidateOptions) (ok bool, err error) { + return validate.ValidateCode(data, code, opts) +} + +// Validate validates the given data file against the specified +// schema file with the provided options. +func Validate(dataFile, schemaFile string, opts *ValidateOptions) (ok bool, err error) { + return validate.Validate(dataFile, schemaFile, opts) } // Test calls the test tool to run uni tests in packages. diff --git a/pkg/tools/validate/test_data/data-failed.json b/pkg/tools/validate/test_data/data-failed.json new file mode 100644 index 00000000..40bdc89f --- /dev/null +++ b/pkg/tools/validate/test_data/data-failed.json @@ -0,0 +1,13 @@ +{ + "name": "Alice", + "age": 18, + "message": "This is Alice", + "data": { + "id": 1, + "value": "value1" + }, + "labels": { + "key": "value" + }, + "hc": [1, 2, 3, ""] +} diff --git a/pkg/tools/validate/test_data/data.json b/pkg/tools/validate/test_data/data.json new file mode 100644 index 00000000..d3e9b575 --- /dev/null +++ b/pkg/tools/validate/test_data/data.json @@ -0,0 +1,13 @@ +{ + "name": "Alice", + "age": 18, + "message": "This is Alice", + "data": { + "id": 1, + "value": "value1" + }, + "labels": { + "key": "value" + }, + "hc": [1, 2, 3] +} diff --git a/pkg/tools/validate/test_data/schema.k b/pkg/tools/validate/test_data/schema.k new file mode 100644 index 00000000..63d7e0ea --- /dev/null +++ b/pkg/tools/validate/test_data/schema.k @@ -0,0 +1,14 @@ +schema User: + name: str + age: int + message?: str + data: Data + labels: {str:} + hc: [int] + + check: + age > 10 + +schema Data: + id: int + value: str diff --git a/pkg/tools/validate/validate.go b/pkg/tools/validate/validate.go index 93b661ad..fb21e722 100644 --- a/pkg/tools/validate/validate.go +++ b/pkg/tools/validate/validate.go @@ -1,18 +1,48 @@ -// Copyright 2021 The KCL Authors. All rights reserved. +// Copyright The KCL Authors. All rights reserved. package validate import ( "errors" + "os" "kcl-lang.io/kcl-go/pkg/service" "kcl-lang.io/kcl-go/pkg/spec/gpyrpc" ) +// ValidateOptions represents the options for the Validate function. type ValidateOptions struct { - Schema string - AttributeName string - Format string + Schema string // The schema to validate against. + AttributeName string // The attribute name to validate. + Format string // The format of the data. +} + +// Validate validates the given data file against the specified +// schema file with the provided options. +func Validate(dataFile, schemaFile string, opts *ValidateOptions) (ok bool, err error) { + data, err := os.ReadFile(dataFile) + if err != nil { + return false, err + } + if opts == nil { + opts = &ValidateOptions{} + } + client := service.NewKclvmServiceClient() + resp, err := client.ValidateCode(&gpyrpc.ValidateCode_Args{ + File: schemaFile, + Data: string(data), + Schema: opts.Schema, + AttributeName: opts.AttributeName, + Format: opts.Format, + }) + if err != nil { + return false, err + } + var e error = nil + if resp.ErrMessage != "" { + e = errors.New(resp.ErrMessage) + } + return resp.Success, e } func ValidateCode(data, code string, opt *ValidateOptions) (ok bool, err error) { diff --git a/pkg/tools/validate/validate_test.go b/pkg/tools/validate/validate_test.go index 5537de3b..74627b0b 100644 --- a/pkg/tools/validate/validate_test.go +++ b/pkg/tools/validate/validate_test.go @@ -7,6 +7,25 @@ import ( "testing" ) +func TestValidate(t *testing.T) { + ok, err := Validate("./test_data/data.json", "./test_data/schema.k", nil) + if err != nil { + t.Fatal(err) + } + if !ok { + t.Fatalf("expect: %q, got False", "True") + } +} + +func TestValidateFailed(t *testing.T) { + ok, err := Validate("./test_data/data-failed.json", "./test_data/schema.k", nil) + if ok == false && err != nil && strings.Contains(err.Error(), "expected [int], got [int(1) | int(2) | int(3) | str()]") { + // Test Pass + } else { + t.Fatalf("expect: error, got (%v, %v)", ok, err) + } +} + func TestValidateCode(t *testing.T) { data := `{"key": "value"}` code := `