338 lines
7.7 KiB
Go
338 lines
7.7 KiB
Go
package schema
|
|
|
|
import (
|
|
"reflect"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestModuleSchema_Validate(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
types []Type
|
|
errContains string
|
|
}{
|
|
{
|
|
name: "valid module schema",
|
|
types: []Type{
|
|
StateObjectType{
|
|
Name: "object1",
|
|
KeyFields: []Field{
|
|
{
|
|
Name: "field1",
|
|
Kind: StringKind,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
errContains: "",
|
|
},
|
|
{
|
|
name: "invalid object type",
|
|
types: []Type{
|
|
StateObjectType{
|
|
Name: "",
|
|
KeyFields: []Field{
|
|
{
|
|
Name: "field1",
|
|
Kind: StringKind,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
errContains: "invalid object type name",
|
|
},
|
|
{
|
|
name: "duplicate type name",
|
|
types: []Type{
|
|
StateObjectType{
|
|
Name: "type1",
|
|
ValueFields: []Field{
|
|
{
|
|
Name: "field1",
|
|
Kind: EnumKind,
|
|
ReferencedType: "type1",
|
|
},
|
|
},
|
|
},
|
|
EnumType{
|
|
Name: "type1",
|
|
Values: []EnumValueDefinition{{Name: "a", Value: 1}},
|
|
},
|
|
},
|
|
errContains: `duplicate type "type1"`,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
// because validate is called when calling CompileModuleSchema, we just call CompileModuleSchema
|
|
_, err := CompileModuleSchema(tt.types...)
|
|
if tt.errContains == "" {
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
} else {
|
|
if err == nil || !strings.Contains(err.Error(), tt.errContains) {
|
|
t.Fatalf("expected error to contain %q, got: %v", tt.errContains, err)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestModuleSchema_ValidateObjectUpdate(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
moduleSchema ModuleSchema
|
|
objectUpdate StateObjectUpdate
|
|
errContains string
|
|
}{
|
|
{
|
|
name: "valid object update",
|
|
moduleSchema: requireModuleSchema(t,
|
|
StateObjectType{
|
|
Name: "object1",
|
|
KeyFields: []Field{
|
|
{
|
|
Name: "field1",
|
|
Kind: StringKind,
|
|
},
|
|
},
|
|
},
|
|
),
|
|
objectUpdate: StateObjectUpdate{
|
|
TypeName: "object1",
|
|
Key: "abc",
|
|
},
|
|
errContains: "",
|
|
},
|
|
{
|
|
name: "object type not found",
|
|
moduleSchema: requireModuleSchema(t,
|
|
StateObjectType{
|
|
Name: "object1",
|
|
KeyFields: []Field{
|
|
{
|
|
Name: "field1",
|
|
Kind: StringKind,
|
|
},
|
|
},
|
|
},
|
|
),
|
|
objectUpdate: StateObjectUpdate{
|
|
TypeName: "object2",
|
|
Key: "abc",
|
|
},
|
|
errContains: "object type \"object2\" not found in module schema",
|
|
},
|
|
{
|
|
name: "type name refers to an enum",
|
|
moduleSchema: requireModuleSchema(t, StateObjectType{
|
|
Name: "obj1",
|
|
KeyFields: []Field{
|
|
{
|
|
Name: "field1",
|
|
Kind: EnumKind,
|
|
ReferencedType: "enum1",
|
|
},
|
|
},
|
|
},
|
|
EnumType{
|
|
Name: "enum1",
|
|
Values: []EnumValueDefinition{{Name: "a", Value: 1}, {Name: "b", Value: 2}},
|
|
},
|
|
),
|
|
objectUpdate: StateObjectUpdate{
|
|
TypeName: "enum1",
|
|
Key: "a",
|
|
},
|
|
errContains: "type \"enum1\" is not an object type",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
err := tt.moduleSchema.ValidateObjectUpdate(tt.objectUpdate)
|
|
if tt.errContains == "" {
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
} else {
|
|
if err == nil || !strings.Contains(err.Error(), tt.errContains) {
|
|
t.Fatalf("expected error to contain %q, got: %v", tt.errContains, err)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func requireModuleSchema(t *testing.T, types ...Type) ModuleSchema {
|
|
t.Helper()
|
|
moduleSchema, err := CompileModuleSchema(types...)
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
return moduleSchema
|
|
}
|
|
|
|
func TestModuleSchema_LookupType(t *testing.T) {
|
|
moduleSchema := requireModuleSchema(t, StateObjectType{
|
|
Name: "object1",
|
|
KeyFields: []Field{
|
|
{
|
|
Name: "field1",
|
|
Kind: StringKind,
|
|
},
|
|
},
|
|
})
|
|
|
|
objectType, ok := moduleSchema.LookupStateObjectType("object1")
|
|
if !ok {
|
|
t.Fatalf("expected to find object type \"object1\"")
|
|
}
|
|
|
|
if objectType.Name != "object1" {
|
|
t.Fatalf("expected object type name \"object1\", got %q", objectType.Name)
|
|
}
|
|
}
|
|
|
|
func exampleSchema(t *testing.T) ModuleSchema {
|
|
t.Helper()
|
|
return requireModuleSchema(t,
|
|
StateObjectType{
|
|
Name: "object1",
|
|
KeyFields: []Field{
|
|
{
|
|
Name: "field1",
|
|
Kind: EnumKind,
|
|
ReferencedType: "enum2",
|
|
},
|
|
},
|
|
},
|
|
StateObjectType{
|
|
Name: "object2",
|
|
KeyFields: []Field{
|
|
{
|
|
Name: "field1",
|
|
Kind: EnumKind,
|
|
ReferencedType: "enum1",
|
|
},
|
|
},
|
|
},
|
|
EnumType{
|
|
Name: "enum1",
|
|
Values: []EnumValueDefinition{{Name: "a", Value: 1}, {Name: "b", Value: 2}, {Name: "c", Value: 3}},
|
|
},
|
|
EnumType{
|
|
Name: "enum2",
|
|
Values: []EnumValueDefinition{{Name: "d", Value: 4}, {Name: "e", Value: 5}, {Name: "f", Value: 6}},
|
|
},
|
|
)
|
|
}
|
|
|
|
func TestModuleSchema_Types(t *testing.T) {
|
|
moduleSchema := exampleSchema(t)
|
|
|
|
var typeNames []string
|
|
moduleSchema.AllTypes(func(typ Type) bool {
|
|
typeNames = append(typeNames, typ.TypeName())
|
|
return true
|
|
})
|
|
|
|
expected := []string{"enum1", "enum2", "object1", "object2"}
|
|
if !reflect.DeepEqual(typeNames, expected) {
|
|
t.Fatalf("expected %v, got %v", expected, typeNames)
|
|
}
|
|
|
|
typeNames = nil
|
|
// scan just the first type and return false
|
|
moduleSchema.AllTypes(func(typ Type) bool {
|
|
typeNames = append(typeNames, typ.TypeName())
|
|
return false
|
|
})
|
|
|
|
expected = []string{"enum1"}
|
|
if !reflect.DeepEqual(typeNames, expected) {
|
|
t.Fatalf("expected %v, got %v", expected, typeNames)
|
|
}
|
|
}
|
|
|
|
func TestModuleSchema_ObjectTypes(t *testing.T) {
|
|
moduleSchema := exampleSchema(t)
|
|
|
|
var typeNames []string
|
|
moduleSchema.StateObjectTypes(func(typ StateObjectType) bool {
|
|
typeNames = append(typeNames, typ.Name)
|
|
return true
|
|
})
|
|
|
|
expected := []string{"object1", "object2"}
|
|
if !reflect.DeepEqual(typeNames, expected) {
|
|
t.Fatalf("expected %v, got %v", expected, typeNames)
|
|
}
|
|
|
|
typeNames = nil
|
|
// scan just the first type and return false
|
|
moduleSchema.StateObjectTypes(func(typ StateObjectType) bool {
|
|
typeNames = append(typeNames, typ.Name)
|
|
return false
|
|
})
|
|
|
|
expected = []string{"object1"}
|
|
if !reflect.DeepEqual(typeNames, expected) {
|
|
t.Fatalf("expected %v, got %v", expected, typeNames)
|
|
}
|
|
}
|
|
|
|
func TestModuleSchema_EnumTypes(t *testing.T) {
|
|
moduleSchema := exampleSchema(t)
|
|
|
|
var typeNames []string
|
|
moduleSchema.EnumTypes(func(typ EnumType) bool {
|
|
typeNames = append(typeNames, typ.Name)
|
|
return true
|
|
})
|
|
|
|
expected := []string{"enum1", "enum2"}
|
|
if !reflect.DeepEqual(typeNames, expected) {
|
|
t.Fatalf("expected %v, got %v", expected, typeNames)
|
|
}
|
|
|
|
typeNames = nil
|
|
// scan just the first type and return false
|
|
moduleSchema.EnumTypes(func(typ EnumType) bool {
|
|
typeNames = append(typeNames, typ.Name)
|
|
return false
|
|
})
|
|
|
|
expected = []string{"enum1"}
|
|
if !reflect.DeepEqual(typeNames, expected) {
|
|
t.Fatalf("expected %v, got %v", expected, typeNames)
|
|
}
|
|
}
|
|
|
|
func TestModuleSchemaJSON(t *testing.T) {
|
|
moduleSchema := exampleSchema(t)
|
|
|
|
b, err := moduleSchema.MarshalJSON()
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
|
|
const expectedJson = `{"object_types":[{"name":"object1","key_fields":[{"name":"field1","kind":"enum","referenced_type":"enum2"}]},{"name":"object2","key_fields":[{"name":"field1","kind":"enum","referenced_type":"enum1"}]}],"enum_types":[{"name":"enum1","values":[{"name":"a","value":1},{"name":"b","value":2},{"name":"c","value":3}]},{"name":"enum2","values":[{"name":"d","value":4},{"name":"e","value":5},{"name":"f","value":6}]}]}`
|
|
if string(b) != expectedJson {
|
|
t.Fatalf("expected %s\n, got %s", expectedJson, string(b))
|
|
}
|
|
|
|
var moduleSchema2 ModuleSchema
|
|
err = moduleSchema2.UnmarshalJSON(b)
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
|
|
if !reflect.DeepEqual(moduleSchema, moduleSchema2) {
|
|
t.Fatalf("expected %v, got %v", moduleSchema, moduleSchema2)
|
|
}
|
|
}
|