Skip to content

Commit

Permalink
bugfix: avoid duplicate enum values
Browse files Browse the repository at this point in the history
  • Loading branch information
alexzielenski committed Feb 23, 2024
1 parent b64ee37 commit 649db69
Show file tree
Hide file tree
Showing 3 changed files with 171 additions and 4 deletions.
12 changes: 10 additions & 2 deletions pkg/generators/enum.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,15 +121,23 @@ func parseEnums(c *generator.Context) enumMap {
Value: *c.ConstValue,
Comment: strings.Join(c.CommentLines, " "),
}
enumTypes[enumType.Name].appendValue(value)
enumTypes[enumType.Name].addIfNotPresent(value)
}
}
}

return enumTypes
}

func (et *enumType) appendValue(value *enumValue) {
func (et *enumType) addIfNotPresent(value *enumValue) {
// If we already have an enum case with the same value, then ignore this new
// one. This can happen if an enum aliases one from another package and
// re-exports the cases.
for _, existing := range et.Values {
if existing.Value == value.Value {
return
}
}
et.Values = append(et.Values, value)
}

Expand Down
85 changes: 85 additions & 0 deletions pkg/generators/enum_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,91 @@ func TestParseEnums(t *testing.T) {
"foo.Foo": {"different", "same"},
},
},
{
name: "aliasing and re-exporting enum from different package",
universe: types.Universe{
"foo": &types.Package{
Name: "foo",
Types: map[string]*types.Type{
"Foo": {
Name: types.Name{
Package: "foo",
Name: "Foo",
},
Kind: types.Alias,
Underlying: types.String,
CommentLines: []string{"+enum"},
},
},
Constants: map[string]*types.Type{
"FooCase1": {
Name: types.Name{
Package: "foo",
Name: "FooCase1",
},
Kind: types.DeclarationOf,
Underlying: &types.Type{
Name: types.Name{
Package: "foo",
Name: "Foo",
},
},
ConstValue: &[]string{"case1"}[0],
},
"FooCase2": {
Name: types.Name{
Package: "foo",
Name: "FooCase2",
},
Kind: types.DeclarationOf,
Underlying: &types.Type{
Name: types.Name{
Package: "foo",
Name: "Foo",
},
},
ConstValue: &[]string{"case2"}[0],
},
},
},
"bar": &types.Package{
Name: "bar",
Constants: map[string]*types.Type{
"FooCase1": {
Name: types.Name{
Package: "foo",
Name: "FooCase1",
},
Kind: types.DeclarationOf,
Underlying: &types.Type{
Name: types.Name{
Package: "foo",
Name: "Foo",
},
},
ConstValue: &[]string{"case1"}[0],
},
"FooCase2": {
Name: types.Name{
Package: "foo",
Name: "FooCase2",
},
Kind: types.DeclarationOf,
Underlying: &types.Type{
Name: types.Name{
Package: "foo",
Name: "Foo",
},
},
ConstValue: &[]string{"case2"}[0],
},
},
},
},
expected: map[string][]string{
"foo.Foo": {"case1", "case2"},
},
},
} {
t.Run(tc.name, func(t *testing.T) {
enums := parseEnums(&generator.Context{Universe: tc.universe})
Expand Down
78 changes: 76 additions & 2 deletions pkg/generators/openapi_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,15 @@ func construct(t *testing.T, files map[string]string, testNamer namer.Namer) (*p
}

func testOpenAPITypeWriter(t *testing.T, code string) (error, error, *assert.Assertions, *bytes.Buffer, *bytes.Buffer, []string) {
return testOpenAPITypeWriterWithFiles(t, code, nil)
}

func testOpenAPITypeWriterWithFiles(t *testing.T, code string, testFiles map[string]string) (error, error, *assert.Assertions, *bytes.Buffer, *bytes.Buffer, []string) {
assert := assert.New(t)
var testFiles = map[string]string{
"base/foo/bar.go": code,
if testFiles == nil {
testFiles = map[string]string{}
}
testFiles["base/foo/bar.go"] = code
outputPackage := "base/output"
imports := generator.NewImportTrackerForPackage(outputPackage)
rawNamer := namer.NewRawNamer(outputPackage, imports)
Expand Down Expand Up @@ -1618,6 +1623,75 @@ map[string]interface{}{
`, funcBuffer.String())
}

func TestEnumAlias(t *testing.T) {
callErr, funcErr, assert, _, funcBuffer, _ := testOpenAPITypeWriterWithFiles(t, `
package foo
import "base/bar"
// EnumType is the enumType.
// +enum
type EnumType = bar.EnumType
// EnumA is a.
const EnumA EnumType = bar.EnumA
// EnumB is b.
const EnumB EnumType = bar.EnumB
// Blah is a test.
// +k8s:openapi-gen=true
type Blah struct {
// Value is the value.
Value EnumType
}
`, map[string]string{"base/bar/foo.go": `
package bar
// EnumType is the enumType.
// +enum
type EnumType string
// EnumA is a.
const EnumA EnumType = "a"
// EnumB is b.
const EnumB EnumType = "b"
`})

if callErr != nil {
t.Fatal(callErr)
}
if funcErr != nil {
t.Fatal(funcErr)
}
_ = assert
assert.Equal(`func schema_base_foo_Blah(ref common.ReferenceCallback) common.OpenAPIDefinition {
return common.OpenAPIDefinition{
Schema: spec.Schema{
SchemaProps: spec.SchemaProps{
Description: "Blah is a test.",
Type: []string{"object"},
Properties: map[string]spec.Schema{
"Value": {
SchemaProps: spec.SchemaProps{`+"\n"+
"Description: \"Value is the value.\\n\\nPossible enum values:\\n - `\\\"a\\\"` is a.\\n - `\\\"b\\\"` is b.\","+`
Default: "",
Type: []string{"string"},
Format: "",
Enum: []interface{}{"a", "b"},
},
},
},
Required: []string{"Value"},
},
},
}
}
`, funcBuffer.String())

}

func TestEnum(t *testing.T) {
callErr, funcErr, assert, _, funcBuffer, _ := testOpenAPITypeWriter(t, `
package foo
Expand Down

0 comments on commit 649db69

Please sign in to comment.