removed more tests

This commit is contained in:
Shreyas Goenka 2024-08-20 19:57:57 +02:00
parent b89928513e
commit b023ba0dd4
No known key found for this signature in database
GPG Key ID: 92A07DF49CCB0622
3 changed files with 40 additions and 463 deletions

View File

@ -404,198 +404,6 @@ func TestErrorWithTrace(t *testing.T) {
assert.ErrorContains(t, err, "with depth = 4. traversal trace: root -> resources -> pipelines -> datasets") assert.ErrorContains(t, err, "with depth = 4. traversal trace: root -> resources -> pipelines -> datasets")
} }
func TestNonAnnotatedFieldsAreSkipped(t *testing.T) {
type MyStruct struct {
Foo string
Bar int `json:"bar"`
}
elem := MyStruct{}
schema, err := New(reflect.TypeOf(elem), nil)
require.NoError(t, err)
jsonSchema, err := json.MarshalIndent(schema, " ", " ")
assert.NoError(t, err)
expectedSchema :=
`{
"type": "object",
"properties": {
"bar": {
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"pattern": "\\$\\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\[[0-9]+\\])*)*(\\[[0-9]+\\])*)\\}"
}
]
}
},
"additionalProperties": false,
"required": [
"bar"
]
}`
t.Log("[DEBUG] actual: ", string(jsonSchema))
t.Log("[DEBUG] expected: ", expectedSchema)
assert.Equal(t, expectedSchema, string(jsonSchema))
}
func TestDashFieldsAreSkipped(t *testing.T) {
type MyStruct struct {
Foo string `json:"-"`
Bar int `json:"bar"`
}
elem := MyStruct{}
schema, err := New(reflect.TypeOf(elem), nil)
require.NoError(t, err)
jsonSchema, err := json.MarshalIndent(schema, " ", " ")
assert.NoError(t, err)
expectedSchema :=
`{
"type": "object",
"properties": {
"bar": {
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"pattern": "\\$\\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\[[0-9]+\\])*)*(\\[[0-9]+\\])*)\\}"
}
]
}
},
"additionalProperties": false,
"required": [
"bar"
]
}`
t.Log("[DEBUG] actual: ", string(jsonSchema))
t.Log("[DEBUG] expected: ", expectedSchema)
assert.Equal(t, expectedSchema, string(jsonSchema))
}
func TestPointerInStructSchema(t *testing.T) {
type Bar struct {
PtrVal2 *int `json:"ptr_val2"`
}
type Foo struct {
PtrInt *int `json:"ptr_int"`
PtrString *string `json:"ptr_string"`
FloatVal float32 `json:"float_val"`
PtrBar *Bar `json:"ptr_bar"`
Bar *Bar `json:"bar"`
}
elem := Foo{}
schema, err := New(reflect.TypeOf(elem), nil)
require.NoError(t, err)
jsonSchema, err := json.MarshalIndent(schema, " ", " ")
assert.NoError(t, err)
expectedSchema :=
`{
"type": "object",
"properties": {
"bar": {
"type": "object",
"properties": {
"ptr_val2": {
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"pattern": "\\$\\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\[[0-9]+\\])*)*(\\[[0-9]+\\])*)\\}"
}
]
}
},
"additionalProperties": false,
"required": [
"ptr_val2"
]
},
"float_val": {
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"pattern": "\\$\\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\[[0-9]+\\])*)*(\\[[0-9]+\\])*)\\}"
}
]
},
"ptr_bar": {
"type": "object",
"properties": {
"ptr_val2": {
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"pattern": "\\$\\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\[[0-9]+\\])*)*(\\[[0-9]+\\])*)\\}"
}
]
}
},
"additionalProperties": false,
"required": [
"ptr_val2"
]
},
"ptr_int": {
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"pattern": "\\$\\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\[[0-9]+\\])*)*(\\[[0-9]+\\])*)\\}"
}
]
},
"ptr_string": {
"type": "string"
}
},
"additionalProperties": false,
"required": [
"ptr_int",
"ptr_string",
"float_val",
"ptr_bar",
"bar"
]
}`
t.Log("[DEBUG] actual: ", string(jsonSchema))
t.Log("[DEBUG] expected: ", expectedSchema)
assert.Equal(t, expectedSchema, string(jsonSchema))
}
func TestGenericSchema(t *testing.T) { func TestGenericSchema(t *testing.T) {
type Person struct { type Person struct {
Name string `json:"name"` Name string `json:"name"`
@ -824,93 +632,6 @@ func TestGenericSchema(t *testing.T) {
assert.Equal(t, expected, string(jsonSchema)) assert.Equal(t, expected, string(jsonSchema))
} }
func TestFieldsWithoutOmitEmptyAreRequired(t *testing.T) {
type Papaya struct {
A int `json:"a,string,omitempty"`
B string `json:"b"`
}
type MyStruct struct {
Foo string `json:"-,omitempty"`
Bar int `json:"bar"`
Apple int `json:"apple,omitempty"`
Mango int `json:",omitempty"`
Guava int `json:","`
Papaya *Papaya `json:"papaya,"`
}
elem := MyStruct{}
schema, err := New(reflect.TypeOf(elem), nil)
require.NoError(t, err)
jsonSchema, err := json.MarshalIndent(schema, " ", " ")
assert.NoError(t, err)
expectedSchema :=
`{
"type": "object",
"properties": {
"apple": {
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"pattern": "\\$\\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\[[0-9]+\\])*)*(\\[[0-9]+\\])*)\\}"
}
]
},
"bar": {
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"pattern": "\\$\\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\[[0-9]+\\])*)*(\\[[0-9]+\\])*)\\}"
}
]
},
"papaya": {
"type": "object",
"properties": {
"a": {
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"pattern": "\\$\\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\[[0-9]+\\])*)*(\\[[0-9]+\\])*)\\}"
}
]
},
"b": {
"type": "string"
}
},
"additionalProperties": false,
"required": [
"b"
]
}
},
"additionalProperties": false,
"required": [
"bar",
"papaya"
]
}`
t.Log("[DEBUG] actual: ", string(jsonSchema))
t.Log("[DEBUG] expected: ", expectedSchema)
assert.Equal(t, expectedSchema, string(jsonSchema))
}
func TestDocIngestionForObject(t *testing.T) { func TestDocIngestionForObject(t *testing.T) {
docs := &Docs{ docs := &Docs{
Description: "docs for root", Description: "docs for root",
@ -1272,166 +993,3 @@ func TestErrorIfStructHasLoop(t *testing.T) {
_, err := New(reflect.TypeOf(elem), nil) _, err := New(reflect.TypeOf(elem), nil)
assert.ErrorContains(t, err, "cycle detected. traversal trace: root -> my_mango -> my_guava -> my_papaya -> my_apple") assert.ErrorContains(t, err, "cycle detected. traversal trace: root -> my_mango -> my_guava -> my_papaya -> my_apple")
} }
func TestInterfaceGeneratesEmptySchema(t *testing.T) {
type Foo struct {
Apple int `json:"apple"`
Mango interface{} `json:"mango"`
}
elem := Foo{}
schema, err := New(reflect.TypeOf(elem), nil)
assert.NoError(t, err)
jsonSchema, err := json.MarshalIndent(schema, " ", " ")
assert.NoError(t, err)
expected :=
`{
"type": "object",
"properties": {
"apple": {
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"pattern": "\\$\\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\[[0-9]+\\])*)*(\\[[0-9]+\\])*)\\}"
}
]
},
"mango": {}
},
"additionalProperties": false,
"required": [
"apple",
"mango"
]
}`
t.Log("[DEBUG] actual: ", string(jsonSchema))
t.Log("[DEBUG] expected: ", expected)
assert.Equal(t, expected, string(jsonSchema))
}
func TestBundleReadOnlytag(t *testing.T) {
type Pokemon struct {
Pikachu string `json:"pikachu" bundle:"readonly"`
Raichu string `json:"raichu"`
}
type Foo struct {
Pokemon *Pokemon `json:"pokemon"`
Apple int `json:"apple"`
Mango string `json:"mango" bundle:"readonly"`
}
elem := Foo{}
schema, err := New(reflect.TypeOf(elem), nil)
assert.NoError(t, err)
jsonSchema, err := json.MarshalIndent(schema, " ", " ")
assert.NoError(t, err)
expected :=
`{
"type": "object",
"properties": {
"apple": {
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"pattern": "\\$\\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\[[0-9]+\\])*)*(\\[[0-9]+\\])*)\\}"
}
]
},
"pokemon": {
"type": "object",
"properties": {
"raichu": {
"type": "string"
}
},
"additionalProperties": false,
"required": [
"raichu"
]
}
},
"additionalProperties": false,
"required": [
"pokemon",
"apple"
]
}`
t.Log("[DEBUG] actual: ", string(jsonSchema))
t.Log("[DEBUG] expected: ", expected)
assert.Equal(t, expected, string(jsonSchema))
}
func TestBundleInternalTag(t *testing.T) {
type Pokemon struct {
Pikachu string `json:"pikachu" bundle:"internal"`
Raichu string `json:"raichu"`
}
type Foo struct {
Pokemon *Pokemon `json:"pokemon"`
Apple int `json:"apple"`
Mango string `json:"mango" bundle:"internal"`
}
elem := Foo{}
schema, err := New(reflect.TypeOf(elem), nil)
assert.NoError(t, err)
jsonSchema, err := json.MarshalIndent(schema, " ", " ")
assert.NoError(t, err)
expected :=
`{
"type": "object",
"properties": {
"apple": {
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"pattern": "\\$\\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\[[0-9]+\\])*)*(\\[[0-9]+\\])*)\\}"
}
]
},
"pokemon": {
"type": "object",
"properties": {
"raichu": {
"type": "string"
}
},
"additionalProperties": false,
"required": [
"raichu"
]
}
},
"additionalProperties": false,
"required": [
"pokemon",
"apple"
]
}`
t.Log("[DEBUG] actual: ", string(jsonSchema))
t.Log("[DEBUG] expected: ", expected)
assert.Equal(t, expected, string(jsonSchema))
}

View File

@ -77,7 +77,7 @@ func FromType(typ reflect.Type, fn func(s Schema) Schema) (Schema, error) {
fn: fn, fn: fn,
} }
err := c.walk(typ) _, err := c.walk(typ)
if err != nil { if err != nil {
return InvalidSchema, err return InvalidSchema, err
} }
@ -90,6 +90,11 @@ func FromType(typ reflect.Type, fn func(s Schema) Schema) (Schema, error) {
} }
func typePath(typ reflect.Type) string { func typePath(typ reflect.Type) string {
// typ.Name() resolves to "" for any type.
if typ.Kind() == reflect.Interface {
return "interface"
}
// For built-in types, return the type name directly. // For built-in types, return the type name directly.
if typ.PkgPath() == "" { if typ.PkgPath() == "" {
return typ.Name() return typ.Name()
@ -100,7 +105,7 @@ func typePath(typ reflect.Type) string {
// TODO: would a worked based model fit better here? Is this internal API not // TODO: would a worked based model fit better here? Is this internal API not
// the right fit? // the right fit?
func (c *constructor) walk(typ reflect.Type) error { func (c *constructor) walk(typ reflect.Type) (string, error) {
// Dereference pointers if necessary. // Dereference pointers if necessary.
for typ.Kind() == reflect.Ptr { for typ.Kind() == reflect.Ptr {
typ = typ.Elem() typ = typ.Elem()
@ -110,7 +115,7 @@ func (c *constructor) walk(typ reflect.Type) error {
// Return value directly if it's already been processed. // Return value directly if it's already been processed.
if _, ok := c.definitions[typPath]; ok { if _, ok := c.definitions[typPath]; ok {
return nil return "", nil
} }
var s Schema var s Schema
@ -139,10 +144,10 @@ func (c *constructor) walk(typ reflect.Type) error {
// set to null and disallowed in the schema. // set to null and disallowed in the schema.
s = Schema{Type: NullType} s = Schema{Type: NullType}
default: default:
return fmt.Errorf("unsupported type: %s", typ.Kind()) return "", fmt.Errorf("unsupported type: %s", typ.Kind())
} }
if err != nil { if err != nil {
return err return "", err
} }
if c.fn != nil { if c.fn != nil {
@ -153,7 +158,7 @@ func (c *constructor) walk(typ reflect.Type) error {
// TODO: Apply transformation at the end, to all definitions instead of // TODO: Apply transformation at the end, to all definitions instead of
// during recursive traversal? // during recursive traversal?
c.definitions[typPath] = s c.definitions[typPath] = s
return nil return typPath, nil
} }
// This function returns all member fields of the provided type. // This function returns all member fields of the provided type.
@ -230,12 +235,11 @@ func (c *constructor) fromTypeStruct(typ reflect.Type) (Schema, error) {
// Trigger call to fromType, to recursively generate definitions for // Trigger call to fromType, to recursively generate definitions for
// the struct field. // the struct field.
err := c.walk(structField.Type) typPath, err := c.walk(structField.Type)
if err != nil { if err != nil {
return InvalidSchema, err return InvalidSchema, err
} }
typPath := typePath(structField.Type)
refPath := path.Join("#/$defs", typPath) refPath := path.Join("#/$defs", typPath)
// For non-built-in types, refer to the definition. // For non-built-in types, refer to the definition.
res.Properties[jsonTags[0]] = &Schema{ res.Properties[jsonTags[0]] = &Schema{
@ -259,12 +263,11 @@ func (c *constructor) fromTypeSlice(typ reflect.Type) (Schema, error) {
// Trigger call to fromType, to recursively generate definitions for // Trigger call to fromType, to recursively generate definitions for
// the slice element. // the slice element.
err := c.walk(typ.Elem()) typPath, err := c.walk(typ.Elem())
if err != nil { if err != nil {
return InvalidSchema, err return InvalidSchema, err
} }
typPath := typePath(typ.Elem())
refPath := path.Join("#/$defs", typPath) refPath := path.Join("#/$defs", typPath)
// For non-built-in types, refer to the definition // For non-built-in types, refer to the definition
@ -289,12 +292,11 @@ func (c *constructor) fromTypeMap(typ reflect.Type) (Schema, error) {
// Trigger call to fromType, to recursively generate definitions for // Trigger call to fromType, to recursively generate definitions for
// the map value. // the map value.
err := c.walk(typ.Elem()) typPath, err := c.walk(typ.Elem())
if err != nil { if err != nil {
return InvalidSchema, err return InvalidSchema, err
} }
typPath := typePath(typ.Elem())
refPath := path.Join("#/$defs", typPath) refPath := path.Join("#/$defs", typPath)
// For non-built-in types, refer to the definition // For non-built-in types, refer to the definition

View File

@ -1,6 +1,7 @@
package jsonschema package jsonschema
import ( import (
"encoding/json"
"reflect" "reflect"
"testing" "testing"
@ -10,12 +11,22 @@ import (
func TestFromTypeBasic(t *testing.T) { func TestFromTypeBasic(t *testing.T) {
type myStruct struct { type myStruct struct {
S string `json:"s"` S string `json:"s"`
I int `json:"i"` I *int `json:"i,omitempty"`
V interface{} `json:"v,omitempty"`
// These fields should be ignored in the resulting schema.
NotAnnotated string
DashedTag string `json:"-"`
notExported string `json:"not_exported"`
InternalTagged string `json:"internal_tagged" bundle:"internal"`
DeprecatedTagged string `json:"deprecated_tagged" bundle:"deprecated"`
ReadOnlyTagged string `json:"readonly_tagged" bundle:"readonly"`
} }
strRef := "#/$defs/string" strRef := "#/$defs/string"
boolRef := "#/$defs/bool" boolRef := "#/$defs/bool"
intRef := "#/$defs/int" intRef := "#/$defs/int"
interfaceRef := "#/$defs/interface"
tcases := []struct { tcases := []struct {
name string name string
@ -56,6 +67,9 @@ func TestFromTypeBasic(t *testing.T) {
expected: Schema{ expected: Schema{
Type: "object", Type: "object",
Definitions: map[string]any{ Definitions: map[string]any{
"interface": Schema{
Type: "null",
},
"string": Schema{ "string": Schema{
Type: "string", Type: "string",
}, },
@ -70,9 +84,12 @@ func TestFromTypeBasic(t *testing.T) {
"i": { "i": {
Reference: &intRef, Reference: &intRef,
}, },
"v": {
Reference: &interfaceRef,
},
}, },
AdditionalProperties: false, AdditionalProperties: false,
Required: []string{"s", "i"}, Required: []string{"s"},
}, },
}, },
{ {
@ -113,14 +130,14 @@ func TestFromTypeBasic(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, tc.expected, s) assert.Equal(t, tc.expected, s)
// jsonSchema, err := json.MarshalIndent(s, " ", " ") jsonSchema, err := json.MarshalIndent(s, " ", " ")
// assert.NoError(t, err) assert.NoError(t, err)
// expectedJson, err := json.MarshalIndent(tc.expected, " ", " ") expectedJson, err := json.MarshalIndent(tc.expected, " ", " ")
// assert.NoError(t, err) assert.NoError(t, err)
// t.Log("[DEBUG] actual: ", string(jsonSchema)) t.Log("[DEBUG] actual: ", string(jsonSchema))
// t.Log("[DEBUG] expected: ", string(expectedJson)) t.Log("[DEBUG] expected: ", string(expectedJson))
}) })
} }
} }