Repository: ogen-go/ogen
Pull request #463 (2022-07-07 03:02:22)

fix(parser): do not panic if `Example` is `nil`


Patch:
diff --git a/jsonschema/parser.go b/jsonschema/parser.go
index 1a51e031..c49ac5e8 100644
--- a/jsonschema/parser.go
+++ b/jsonschema/parser.go
@@ -277,9 +277,14 @@ func (p *Parser) parseSchema(schema *RawSchema, ctx *resolveCtx, hook func(*Sche
 				return nil, errors.Wrapf(err, "property %q", propSpec.Name)
 			}
 
+			var description string
+			if s := propSpec.Schema; s != nil {
+				description = s.Description
+			}
+
 			s.Properties = append(s.Properties, Property{
 				Name:        propSpec.Name,
-				Description: propSpec.Schema.Description,
+				Description: description,
 				Schema:      prop,
 				Required:    required(propSpec.Name),
 			})
diff --git a/openapi/parser/parser.go b/openapi/parser/parser.go
index 4a29c5d7..ea2f882a 100644
--- a/openapi/parser/parser.go
+++ b/openapi/parser/parser.go
@@ -33,6 +33,9 @@ type parser struct {
 
 // Parse parses raw Spec into
 func Parse(spec *ogen.Spec, s Settings) (*openapi.API, error) {
+	if spec == nil {
+		return nil, errors.New("spec is nil")
+	}
 	spec.Init()
 
 	s.setDefaults()
diff --git a/openapi/parser/resolve.go b/openapi/parser/resolve.go
index dead26ef..ee09a194 100644
--- a/openapi/parser/resolve.go
+++ b/openapi/parser/resolve.go
@@ -250,7 +250,9 @@ func (p *parser) resolveExample(ref string, ctx *resolveCtx) (*openapi.Example,
 		return nil, err
 	}
 
-	ex.Ref = ref
+	if ex != nil {
+		ex.Ref = ref
+	}
 	p.refs.examples[ref] = ex
 	return ex, nil
 }


Test patch:
diff --git a/openapi/parser/resolve_test.go b/openapi/parser/resolve_test.go
index a2f4520a..fe0ca615 100644
--- a/openapi/parser/resolve_test.go
+++ b/openapi/parser/resolve_test.go
@@ -2,6 +2,7 @@ package parser
 
 import (
 	"context"
+	"fmt"
 	"sort"
 	"testing"
 
@@ -503,3 +504,71 @@ func TestComplicatedReference(t *testing.T) {
 		},
 	}, spec)
 }
+
+func TestParserNoPanic(t *testing.T) {
+	schema := func(s *ogen.Schema) *ogen.Spec {
+		return &ogen.Spec{
+			Components: &ogen.Components{
+				Schemas: map[string]*ogen.Schema{
+					"schema": s,
+				},
+			},
+		}
+	}
+
+	inputs := []*ogen.Spec{
+		nil,
+		{},
+		{
+			Paths: ogen.Paths{},
+		},
+		{
+			Components: &ogen.Components{},
+		},
+		{
+			Components: &ogen.Components{
+				Examples: map[string]*ogen.Example{
+					"example": nil,
+				},
+			},
+		},
+		schema(nil),
+		schema(&ogen.Schema{}),
+		schema(&ogen.Schema{
+			AllOf: []*ogen.Schema{nil},
+		}),
+		schema(&ogen.Schema{
+			OneOf: []*ogen.Schema{nil},
+		}),
+		schema(&ogen.Schema{
+			AnyOf: []*ogen.Schema{nil},
+		}),
+		schema(&ogen.Schema{
+			Type: "array",
+		}),
+		schema(&ogen.Schema{
+			Type: "object",
+			Properties: ogen.Properties{
+				{Name: "foo", Schema: nil},
+			},
+		}),
+		schema(&ogen.Schema{
+			Type: "object",
+			PatternProperties: ogen.PatternProperties{
+				{Pattern: "foo", Schema: nil},
+			},
+		}),
+	}
+	for i, tt := range inputs {
+		t.Run(fmt.Sprintf("Test%d", i+1), func(t *testing.T) {
+			require.NotPanics(t, func() {
+				_, _ = Parse(tt, Settings{})
+			})
+			require.NotPanics(t, func() {
+				_, _ = Parse(tt, Settings{
+					InferTypes: true,
+				})
+			})
+		})
+	}
+}