diff --git a/pkg/generators/enum.go b/pkg/generators/enum.go index 292a3c762..933d61690 100644 --- a/pkg/generators/enum.go +++ b/pkg/generators/enum.go @@ -121,7 +121,7 @@ func parseEnums(c *generator.Context) enumMap { Value: *c.ConstValue, Comment: strings.Join(c.CommentLines, " "), } - enumTypes[enumType.Name].appendValue(value) + enumTypes[enumType.Name].addIfNotPresent(value) } } } @@ -129,7 +129,15 @@ func parseEnums(c *generator.Context) enumMap { 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) } diff --git a/pkg/generators/enum_test.go b/pkg/generators/enum_test.go index 4be69febb..93c51a59e 100644 --- a/pkg/generators/enum_test.go +++ b/pkg/generators/enum_test.go @@ -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}) diff --git a/pkg/generators/openapi_test.go b/pkg/generators/openapi_test.go index 87d490c62..d29ba0830 100644 --- a/pkg/generators/openapi_test.go +++ b/pkg/generators/openapi_test.go @@ -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) @@ -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