Skip to content

Commit

Permalink
Merge pull request #1322 from tdakkota/fix/validate-enum-values
Browse files Browse the repository at this point in the history
fix(gen): check enum value type before generating
  • Loading branch information
ernado authored Oct 7, 2024
2 parents da8e211 + e2dc75e commit a4498a8
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 0 deletions.
30 changes: 30 additions & 0 deletions _testdata/negative/wrong_enum_type/string_value.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"openapi": "3.0.3",
"info": {
"title": "title",
"version": "v0.1.0"
},
"paths": {
"/foo": {
"get": {
"responses": {
"200": {
"description": "User info",
"content": {
"application/json": {
"schema": {
"type": "integer",
"enum": [
"1",
"2",
"3"
]
}
}
}
}
}
}
}
}
}
12 changes: 12 additions & 0 deletions gen/schema_gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,18 @@ func (g *schemaGen) generate2(name string, schema *jsonschema.Schema) (ret *ir.T
return nil, err
}
oneOf = t
case len(schema.Enum) > 0:
switch schema.Type {
case jsonschema.String,
jsonschema.Integer,
jsonschema.Number,
jsonschema.Boolean,
jsonschema.Null:
default:
return nil, &ErrNotImplemented{
Name: "non-primitive enum",
}
}
}

switch schema.Type {
Expand Down
62 changes: 62 additions & 0 deletions gen/schema_gen_primitive.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

"github.com/ogen-go/ogen/gen/ir"
"github.com/ogen-go/ogen/jsonschema"
"github.com/ogen-go/ogen/location"
)

func (g *schemaGen) primitive(name string, schema *jsonschema.Schema) (*ir.Type, error) {
Expand All @@ -28,6 +29,9 @@ func (g *schemaGen) enum(name string, t *ir.Type, schema *jsonschema.Schema) (*i
if f := schema.Format; f != "" && !t.IsNumeric() {
return nil, errors.Wrapf(&ErrNotImplemented{"enum format"}, "format %q", f)
}
if err := g.validateEnumValues(schema); err != nil {
return nil, errors.Wrap(err, "validate enum")
}

type namingStrategy int
const (
Expand Down Expand Up @@ -146,6 +150,64 @@ func (g *schemaGen) enum(name string, t *ir.Type, schema *jsonschema.Schema) (*i
}, nil
}

func (g *schemaGen) validateEnumValues(s *jsonschema.Schema) error {
reportErr := func(idx int, err error) error {
pos, ok := s.Pointer.Field("enum").Index(idx).Position()
if !ok {
return err
}
return &location.Error{
File: s.Pointer.File(),
Pos: pos,
Err: err,
}
}

switch typ := s.Type; typ {
case jsonschema.Object, jsonschema.Array, jsonschema.Empty:
return &ErrNotImplemented{Name: "non-primitive enum"}
case jsonschema.Integer:
for idx, val := range s.Enum {
if _, ok := val.(int64); !ok {
return reportErr(idx, errors.Errorf("enum value should be an integer, got %T", val))
}
}
return nil
case jsonschema.Number:
for idx, val := range s.Enum {
switch val.(type) {
case int64, float64:
default:
return reportErr(idx, errors.Errorf("enum value should be a number, got %T", val))
}
}
return nil
case jsonschema.String:
for idx, val := range s.Enum {
if _, ok := val.(string); !ok {
return reportErr(idx, errors.Errorf("enum value should be a string, got %T", val))
}
}
return nil
case jsonschema.Boolean:
for idx, val := range s.Enum {
if _, ok := val.(bool); !ok {
return reportErr(idx, errors.Errorf("enum value should be a boolean, got %T", val))
}
}
return nil
case jsonschema.Null:
for idx, val := range s.Enum {
if val != nil {
return reportErr(idx, errors.Errorf("enum value should be a null, got %T", val))
}
}
return nil
default:
panic(fmt.Sprintf("unexpected schema type %q", typ))
}
}

func (g *schemaGen) parseSimple(schema *jsonschema.Schema) *ir.Type {
mapping := TypeFormatMapping()

Expand Down

0 comments on commit a4498a8

Please sign in to comment.