Skip to content

Commit

Permalink
improve coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
mfleader committed Feb 20, 2024
1 parent 9415a48 commit 5464419
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 57 deletions.
6 changes: 3 additions & 3 deletions schema/oneof.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ func (o OneOfSchema[KeyType]) UnserializeType(data any) (result any, err error)
if reflectedValue.Kind() != reflect.Map {
return result, &ConstraintError{
Message: fmt.Sprintf(
"Invalid type for one-of type: '%s'. Expected map.",
"Invalid type for one-of type: %q. Expected map.",
reflect.TypeOf(data).Name(),
),
}
Expand Down Expand Up @@ -114,7 +114,7 @@ func (o OneOfSchema[KeyType]) UnserializeType(data any) (result any, err error)
}
return result, &ConstraintError{
Message: fmt.Sprintf(
"Invalid value for '%s', expected one of: %s",
"Invalid value for %q, expected one of: %s",
o.DiscriminatorFieldNameValue,
strings.Join(validDiscriminators, ", "),
),
Expand Down Expand Up @@ -350,7 +350,7 @@ func (o OneOfSchema[KeyType]) findUnderlyingType(data any) (KeyType, Object, err

return nilKey, nil, &ConstraintError{
Message: fmt.Sprintf(
"Invalid type for one-of type: '%s' expected struct or map.",
"Invalid type for one-of type: %q expected struct or map.",
reflect.TypeOf(data).Name(),
),
}
Expand Down
69 changes: 21 additions & 48 deletions schema/oneof_string_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"encoding/json"
"fmt"
"go.arcalot.io/assert"
"reflect"
"testing"

"go.flow.arcalot.io/pluginsdk/schema"
Expand Down Expand Up @@ -266,54 +267,6 @@ var oneOfStringTestInlineObjectAProperties = map[string]*schema.PropertySchema{
),
}

var oneOfStringTestInlineObjectAType = schema.NewScopeSchema(
schema.NewStructMappedObjectSchema[oneOfTestObjectA](
"A",
oneOfStringTestInlineObjectAProperties,
),
oneOfTestInlineBMappedSchema,
oneOfTestInlineCMappedSchema,
)

var oneOfStringTestInlineObjectASchema = schema.NewScopeSchema(
schema.NewObjectSchema(
"A",
oneOfStringTestInlineObjectAProperties,
),
oneOfTestInlineBSchema,
oneOfTestInlineCSchema,
)

func TestOneOfStringInline_Unserialization(t *testing.T) {
data := `{
"s": {
"choice": "B",
"message": "Hello world!"
}
}`
var input any
assert.NoError(t, json.Unmarshal([]byte(data), &input))
unserializedData, err := oneOfStringTestInlineObjectAType.Unserialize(input)
assert.NoError(t, err)
assert.Equals(t, unserializedData.(oneOfTestObjectA).S.(oneOfTestInlineObjectB).Message, "Hello world!")
serialized, err := oneOfStringTestInlineObjectAType.Serialize(unserializedData)
assert.NoError(t, err)
unserialized2, err := oneOfStringTestInlineObjectAType.Unserialize(serialized)
assert.NoError(t, err)
assert.Equals(t, unserialized2, unserializedData)

// Not explicitly using a struct mapped object, but the type is inferred
// by the compiler when the oneOfTestBMappedSchema is in the test suite.
unserializedData, err = oneOfStringTestInlineObjectASchema.Unserialize(input)
assert.NoError(t, err)
assert.Equals(t, unserializedData.(map[string]any)["s"].(oneOfTestInlineObjectB).Message, "Hello world!")
serialized, err = oneOfStringTestInlineObjectASchema.Serialize(unserializedData)
assert.NoError(t, err)
unserialized2, err = oneOfStringTestInlineObjectASchema.Unserialize(serialized)
assert.NoError(t, err)
assert.Equals(t, unserialized2, unserializedData)
}

type inlinedTestObjectA struct {
DType string `json:"d_type"`
OtherFieldA string `json:"other_field_a"`
Expand Down Expand Up @@ -503,6 +456,26 @@ func TestOneOf_NonInlinedNonStructMapped(t *testing.T) {
reserializedData := assert.NoErrorR[any](t)(oneofSchema.Serialize(unserializedData))
assert.Equals[any](t, reserializedData, serializedData)

var input_mismatched_type any = struct{}{}
error_msg := fmt.Sprintf("Invalid type for one-of schema")
err := oneofSchema.Validate(input_mismatched_type)
assert.Error(t, err)
assert.Contains(t, err.Error(), error_msg)

var input_invalid_type any = true
error_msg = fmt.Sprintf("Invalid type for one-of type: %q. Expected map.", reflect.TypeOf(input_invalid_type).Kind())
_, err = oneofSchema.Unserialize(input_invalid_type)
assert.Error(t, err)
assert.Contains(t, err.Error(), error_msg)
error_msg = fmt.Sprintf("Invalid type for one-of type: %q expected struct or map.", reflect.TypeOf(input_invalid_type).Kind())
err = oneofSchema.Validate(input_invalid_type)
assert.Error(t, err)
assert.Contains(t, err.Error(), error_msg)

var input_nil any = nil
_, err = oneofSchema.Unserialize(input_nil)
assert.Error(t, err)
assert.Contains(t, err.Error(), "bug: data is nil")
}

type inlinedTestIntDiscriminatorA struct {
Expand Down
32 changes: 26 additions & 6 deletions schema/oneof_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package schema_test

import (
"fmt"
"testing"

"go.arcalot.io/assert"
Expand Down Expand Up @@ -206,8 +207,12 @@ var oneOfTestInlineCMappedSchema = schema.NewStructMappedObjectSchema[oneOfTestI
oneOfTestInlineObjectCProperties,
)

//nolint:funlen
func Test_OneOfString_ConstructorBypass(t *testing.T) {
// Test_OneOf_ConstructorBypass tests the behavior of a OneOf object created
// by the Scope Scope Schema through unserialization of data without using a
// New* constructor function, like NewOneOfStringSchema or NewOneOfIntSchema,
// behaves as one would expect from a OneOf object created from a constructor.
func Test_OneOf_ConstructorBypass(t *testing.T) { //nolint:funlen
discriminator_field := "_type"
input_schema := map[string]any{
"root": "InputParams",
"objects": map[string]any{
Expand All @@ -217,7 +222,7 @@ func Test_OneOfString_ConstructorBypass(t *testing.T) {
"name": map[string]any{
"required": true,
"type": map[string]any{
"discriminator_field_name": "_type",
"discriminator_field_name": discriminator_field,
"type_id": "one_of_string",
"types": map[string]any{
"fullname": map[string]any{
Expand Down Expand Up @@ -265,16 +270,31 @@ func Test_OneOfString_ConstructorBypass(t *testing.T) {
}
var input_data_fullname any = map[string]any{
"name": map[string]any{
"_type": "fullname",
"first_name": "Arca",
"last_name": "Lot",
discriminator_field: "fullname",
"first_name": "Arca",
"last_name": "Lot",
},
}

scopeAny := assert.NoErrorR[any](t)(schema.DescribeScope().Unserialize(input_schema))
scopeSchemaTyped := scopeAny.(*schema.ScopeSchema)
scopeSchemaTyped.ApplyScope(scopeSchemaTyped)
assert.NoError(t, scopeSchemaTyped.Validate(input_data_fullname))
unserialized := assert.NoErrorR[any](t)(scopeSchemaTyped.Unserialize(input_data_fullname))
serialized := assert.NoErrorR[any](t)(scopeSchemaTyped.Serialize(unserialized))
unserialized2 := assert.NoErrorR[any](t)(scopeSchemaTyped.Unserialize(serialized))
assert.Equals(t, unserialized2, unserialized)

var input_invalid_discriminator_value any = map[string]any{
"name": map[string]any{
discriminator_field: 1,
"first_name": "Arca",
"last_name": "Lot",
},
}
error_msg := fmt.Sprintf("Invalid value for %q", discriminator_field)
_, err := scopeSchemaTyped.Unserialize(input_invalid_discriminator_value)
assert.Error(t, err)
assert.Contains(t, err.Error(), error_msg)

}

0 comments on commit 5464419

Please sign in to comment.