Skip to content

Commit

Permalink
Generate synthetic fixtures even for references (#451)
Browse files Browse the repository at this point in the history
* Generate synthetic fixtures even for references

* Fix format

* Update server/generator.go

Co-authored-by: anniel-stripe <[email protected]>

---------

Co-authored-by: anniel-stripe <[email protected]>
  • Loading branch information
richardm-stripe and anniel-stripe committed Sep 1, 2023
1 parent ee98add commit 66b4238
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 16 deletions.
25 changes: 19 additions & 6 deletions server/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ func (g *DataGenerator) generateInternal(params *GenerateParams) (interface{}, e
// a synthetic fixture if the user has requested expansions.
// Otherwise, we'll cause bugs like https://github.com/stripe/stripe-mock/issues/447
if example == nil || (params.Expansions != nil && example.value == nil) && schema.XResourceID == "" {
example = &valueWrapper{value: generateSyntheticFixture(schema, context, params.Expansions)}
example = &valueWrapper{value: g.generateSyntheticFixture(schema, context, params.Expansions)}

context = fmt.Sprintf("%sGenerated synthetic fixture: %+v\n", context, schema)

Expand Down Expand Up @@ -737,7 +737,7 @@ func distributeReplacedIDsInValue(pathParams *PathParamsMap, value interface{})
// This function calls itself recursively by initially iterating through every
// property in an object schema, then recursing and returning values for
// embedded objects and scalars.
func generateSyntheticFixture(schema *spec.Schema, context string, expansions *ExpansionLevel) interface{} {
func (g *DataGenerator) generateSyntheticFixture(schema *spec.Schema, context string, expansions *ExpansionLevel) interface{} {
context = fmt.Sprintf("%sGenerating synthetic fixture: %+v\n", context, schema)

// Return the minimum viable object by returning nil/null for a nullable
Expand All @@ -753,15 +753,28 @@ func generateSyntheticFixture(schema *spec.Schema, context string, expansions *E
}

if len(schema.AnyOf) > 0 {
// Try the non-references first.
for _, subSchema := range schema.AnyOf {
// We don't handle dereferencing here right now, but it's plausible
if subSchema.Ref != "" {
continue
}

return generateSyntheticFixture(subSchema, context, expansions)
return g.generateSyntheticFixture(subSchema, context, expansions)
}
panic(fmt.Sprintf("%sCouldn't find an anyOf branch to take", context))

// If no viable non-references, attempt to dereference the references
for _, subSchema := range schema.AnyOf {
if subSchema.Ref == "" {
continue
}

dereferencedSchema, context, err := g.maybeDereference(subSchema, context)
if err != nil {
panic(err)
}
return g.generateSyntheticFixture(dereferencedSchema, context, expansions)
}
panic("Unexpected: anyOf with length > 0 should have contained a ref or non ref")
}

switch schema.Type {
Expand Down Expand Up @@ -791,7 +804,7 @@ func generateSyntheticFixture(schema *spec.Schema, context string, expansions *E
propertyExpansions = expansions.expansions[property]
}

fixture[property] = generateSyntheticFixture(subSchema, context, propertyExpansions)
fixture[property] = g.generateSyntheticFixture(subSchema, context, propertyExpansions)
}
return fixture

Expand Down
21 changes: 11 additions & 10 deletions server/generator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -812,26 +812,27 @@ func TestFindAnyOfBranch(t *testing.T) {

func TestGenerateSyntheticFixture(t *testing.T) {
// Scalars (and an array, which is easy)
assert.Equal(t, []string{}, generateSyntheticFixture(&spec.Schema{Type: spec.TypeArray}, "", nil))
assert.Equal(t, true, generateSyntheticFixture(&spec.Schema{Type: spec.TypeBoolean}, "", nil))
assert.Equal(t, 0, generateSyntheticFixture(&spec.Schema{Type: spec.TypeInteger}, "", nil))
assert.Equal(t, 0.0, generateSyntheticFixture(&spec.Schema{Type: spec.TypeNumber}, "", nil))
assert.Equal(t, "", generateSyntheticFixture(&spec.Schema{Type: spec.TypeString}, "", nil))
g := DataGenerator{nil, nil, verbose}
assert.Equal(t, []string{}, g.generateSyntheticFixture(&spec.Schema{Type: spec.TypeArray}, "", nil))
assert.Equal(t, true, g.generateSyntheticFixture(&spec.Schema{Type: spec.TypeBoolean}, "", nil))
assert.Equal(t, 0, g.generateSyntheticFixture(&spec.Schema{Type: spec.TypeInteger}, "", nil))
assert.Equal(t, 0.0, g.generateSyntheticFixture(&spec.Schema{Type: spec.TypeNumber}, "", nil))
assert.Equal(t, "", g.generateSyntheticFixture(&spec.Schema{Type: spec.TypeString}, "", nil))

// Nullable property
assert.Equal(t, nil, generateSyntheticFixture(&spec.Schema{
assert.Equal(t, nil, g.generateSyntheticFixture(&spec.Schema{
Nullable: true,
Type: spec.TypeString,
}, "", nil))

// Property with enum
assert.Equal(t, "list", generateSyntheticFixture(&spec.Schema{
assert.Equal(t, "list", g.generateSyntheticFixture(&spec.Schema{
Enum: []interface{}{"list"},
Type: spec.TypeString,
}, "", nil))

// Takes the first non-reference branch of an anyOf
assert.Equal(t, "", generateSyntheticFixture(&spec.Schema{
assert.Equal(t, "", g.generateSyntheticFixture(&spec.Schema{
AnyOf: []*spec.Schema{
{Ref: "#/components/schemas/radar_rule"},
{Type: spec.TypeString},
Expand All @@ -845,7 +846,7 @@ func TestGenerateSyntheticFixture(t *testing.T) {
"object": "list",
"url": "",
},
generateSyntheticFixture(&spec.Schema{
g.generateSyntheticFixture(&spec.Schema{
Type: "object",
Properties: map[string]*spec.Schema{
"has_more": {
Expand Down Expand Up @@ -874,7 +875,7 @@ func TestGenerateSyntheticFixture(t *testing.T) {
map[string]interface{}{
"foo": "",
},
generateSyntheticFixture(&spec.Schema{
g.generateSyntheticFixture(&spec.Schema{
Type: "object",
Nullable: true,
Properties: map[string]*spec.Schema{
Expand Down

0 comments on commit 66b4238

Please sign in to comment.