From 5d9d8d5917aaaeb8590e89183de2da3d9f441be5 Mon Sep 17 00:00:00 2001 From: aq17 Date: Thu, 1 Dec 2022 11:20:33 -0800 Subject: [PATCH] update, add test --- pkg/codegen/dotnet/gen_program_expressions.go | 7 ++-- pkg/codegen/go/gen_program_expressions.go | 7 ++-- pkg/codegen/nodejs/gen_program_expressions.go | 7 ++-- pkg/codegen/pcl/binder_schema.go | 35 +++++++++++-------- pkg/codegen/pcl/binder_schema_test.go | 34 ++++++++++++++++++ pkg/codegen/python/gen_program_expressions.go | 7 ++-- 6 files changed, 74 insertions(+), 23 deletions(-) diff --git a/pkg/codegen/dotnet/gen_program_expressions.go b/pkg/codegen/dotnet/gen_program_expressions.go index 65b04e40841c..4f9f88cdb081 100644 --- a/pkg/codegen/dotnet/gen_program_expressions.go +++ b/pkg/codegen/dotnet/gen_program_expressions.go @@ -335,9 +335,12 @@ func (g *generator) genIntrensic(w io.Writer, from model.Expression, to model.Ty if isOutput { g.Fgenf(w, "%.v.Apply(%s)", from, convertFn) } else { - pcl.GenEnum(to, from, g.genSafeEnum(w, to), func(from model.Expression) { + diag := pcl.GenEnum(to, from, g.genSafeEnum(w, to), func(from model.Expression) { g.Fgenf(w, "%s(%v)", convertFn, from) - }, &g.diagnostics) + }) + if diag != nil { + g.diagnostics = append(g.diagnostics, diag) + } } default: g.Fgenf(w, "%.v", from) // <- probably wrong w.r.t. precedence diff --git a/pkg/codegen/go/gen_program_expressions.go b/pkg/codegen/go/gen_program_expressions.go index 7743fa15ec99..6660137df39d 100644 --- a/pkg/codegen/go/gen_program_expressions.go +++ b/pkg/codegen/go/gen_program_expressions.go @@ -205,9 +205,12 @@ func (g *generator) GenFunctionCallExpression(w io.Writer, expr *model.FunctionC from, enumTag, underlyingType) return } - pcl.GenEnum(to, from, g.genSafeEnum(w, to), func(from model.Expression) { + diag := pcl.GenEnum(to, from, g.genSafeEnum(w, to), func(from model.Expression) { g.Fgenf(w, "%s(%v)", enumTag, from) - }, &g.diagnostics) + }) + if diag != nil { + g.diagnostics = append(g.diagnostics, diag) + } return } switch arg := from.(type) { diff --git a/pkg/codegen/nodejs/gen_program_expressions.go b/pkg/codegen/nodejs/gen_program_expressions.go index 83a56f0d7b28..c4b142f6c195 100644 --- a/pkg/codegen/nodejs/gen_program_expressions.go +++ b/pkg/codegen/nodejs/gen_program_expressions.go @@ -336,13 +336,16 @@ func (g *generator) GenFunctionCallExpression(w io.Writer, expr *model.FunctionC if isOutput { g.Fgenf(w, "%.v.apply((x) => %s[x])", from, enum) } else { - pcl.GenEnum(to, from, func(member *schema.Enum) { + diag := pcl.GenEnum(to, from, func(member *schema.Enum) { memberTag, err := enumMemberName(tokenToName(to.Token), member) contract.AssertNoErrorf(err, "Failed to get member name on enum '%s'", enum) g.Fgenf(w, "%s.%s", enum, memberTag) }, func(from model.Expression) { g.Fgenf(w, "%s[%.v]", enum, from) - }, &g.diagnostics) + }) + if diag != nil { + g.diagnostics = append(g.diagnostics, diag) + } } } else { g.Fgenf(w, "%v", from) diff --git a/pkg/codegen/pcl/binder_schema.go b/pkg/codegen/pcl/binder_schema.go index 73dfb146d880..fd8a5565ee76 100644 --- a/pkg/codegen/pcl/binder_schema.go +++ b/pkg/codegen/pcl/binder_schema.go @@ -499,10 +499,11 @@ func getDiscriminatedUnionObjectItem(t model.Type) (string, model.Type) { // no member if found, (nil, true) returned. If the query is nonsensical, either // because no schema is associated with the EnumMember or if the type of value // mismatches the type of the schema, (nil, false) is returned. -func EnumMember(t *model.EnumType, value cty.Value) (*schema.Enum, bool) { +func EnumMember(t *model.EnumType, value cty.Value) (*schema.Enum, []interface{}, bool) { + validMembers := make([]interface{}, 0) srcBase, ok := GetSchemaForType(t) if !ok { - return nil, false + return nil, validMembers, false } src := srcBase.(*schema.EnumType) @@ -512,28 +513,31 @@ func EnumMember(t *model.EnumType, value cty.Value) (*schema.Enum, bool) { for _, el := range src.Elements { v := el.Value.(string) if v == s { - return el, true + return el, validMembers, true } + validMembers = append(validMembers, v) } - return nil, true + return nil, validMembers, true case t.Type.Equals(model.NumberType): f, _ := value.AsBigFloat().Float64() for _, el := range src.Elements { if el.Value.(float64) == f { - return el, true + return el, validMembers, true } + validMembers = append(validMembers, f) } - return nil, true + return nil, validMembers, true case t.Type.Equals(model.IntType): f, _ := value.AsBigFloat().Int64() for _, el := range src.Elements { if el.Value.(int64) == f { - return el, true + return el, validMembers, true } + validMembers = append(validMembers, f) } - return nil, true + return nil, validMembers, true default: - return nil, false + return nil, validMembers, false } } @@ -549,8 +553,7 @@ func GenEnum( from model.Expression, safeEnum func(member *schema.Enum), unsafeEnum func(from model.Expression), - diags *hcl.Diagnostics, -) { +) *hcl.Diagnostic { known := cty.NilVal if from, ok := from.(*model.TemplateExpression); ok && len(from.Parts) == 1 { if from, ok := from.Parts[0].(*model.LiteralValueExpression); ok { @@ -563,7 +566,7 @@ func GenEnum( if known != cty.NilVal { // If the value is known, but we can't find a member, we should have // indicated a conversion is impossible when type checking. - member, ok := EnumMember(t, known) + member, validMembers, ok := EnumMember(t, known) contract.Assertf(ok, "We have determined %s is a safe enum, which we define as "+ "being able to calculate a member for", t) @@ -571,12 +574,14 @@ func GenEnum( safeEnum(member) } else { unsafeEnum(from) - *diags = append(*diags, &hcl.Diagnostic{ + return &hcl.Diagnostic{ Severity: hcl.DiagError, - Summary: fmt.Sprintf("\"%v\" is an invalid enum value.", known.AsString()), - }) + Summary: fmt.Sprintf("\"%v\" is not a valid value of the enum \"%v\"", known.GoString(), t.Token), + Detail: fmt.Sprintf("Valid members are: %v", validMembers), + } } } else { unsafeEnum(from) } + return nil } diff --git a/pkg/codegen/pcl/binder_schema_test.go b/pkg/codegen/pcl/binder_schema_test.go index d3abf853ea4a..9594d35a2752 100644 --- a/pkg/codegen/pcl/binder_schema_test.go +++ b/pkg/codegen/pcl/binder_schema_test.go @@ -4,9 +4,12 @@ import ( "path/filepath" "testing" + "github.com/pulumi/pulumi/pkg/v3/codegen/hcl2/model" "github.com/pulumi/pulumi/pkg/v3/codegen/schema" "github.com/pulumi/pulumi/pkg/v3/codegen/testing/utils" "github.com/pulumi/pulumi/sdk/v3/go/common/util/contract" + "github.com/stretchr/testify/assert" + "github.com/zclconf/go-cty/cty" ) var testdataPath = filepath.Join("..", "testing", "test", "testdata") @@ -19,3 +22,34 @@ func BenchmarkLoadPackage(b *testing.B) { contract.AssertNoError(err) } } + +func TestGenEnum(t *testing.T) { + t.Parallel() + enum := &model.EnumType{ + Elements: []cty.Value{ + cty.StringVal("foo"), + cty.StringVal("bar"), + }, + Type: model.StringType, + Token: "my:enum", + Annotations: []interface{}{ + enumSchemaType{ + Type: &schema.EnumType{Elements: []*schema.Enum{{Value: "foo"}, {Value: "bar"}}}, + }, + }, + } + safeEnumFunc := func(member *schema.Enum) {} + unsafeEnumFunc := func(from model.Expression) {} + + d := GenEnum(enum, &model.LiteralValueExpression{ + Value: cty.StringVal("foo"), + }, safeEnumFunc, unsafeEnumFunc) + assert.Nil(t, d) + + d = GenEnum(enum, &model.LiteralValueExpression{ + Value: cty.StringVal("Bar"), + }, safeEnumFunc, unsafeEnumFunc) + assert.Equal(t, d.Summary, "\"cty.StringVal(\"Bar\")\" is not a valid value of the enum \"my:enum\"") + assert.Equal(t, d.Detail, "Valid members are: [foo bar]") + +} diff --git a/pkg/codegen/python/gen_program_expressions.go b/pkg/codegen/python/gen_program_expressions.go index 59f75d83319f..fc12aec67287 100644 --- a/pkg/codegen/python/gen_program_expressions.go +++ b/pkg/codegen/python/gen_program_expressions.go @@ -247,7 +247,7 @@ func (g *generator) GenFunctionCallExpression(w io.Writer, expr *model.FunctionC if isOutput { g.Fgenf(w, "%.v.apply(lambda x: %s.%s(x))", from, pkg, enumName) } else { - pcl.GenEnum(to, from, func(member *schema.Enum) { + diag := pcl.GenEnum(to, from, func(member *schema.Enum) { tag := member.Name if tag == "" { tag = fmt.Sprintf("%v", member.Value) @@ -257,7 +257,10 @@ func (g *generator) GenFunctionCallExpression(w io.Writer, expr *model.FunctionC g.Fgenf(w, "%s.%s.%s", pkg, enumName, tag) }, func(from model.Expression) { g.Fgenf(w, "%s.%s(%.v)", pkg, enumName, from) - }, &g.diagnostics) + }) + if diag != nil { + g.diagnostics = append(g.diagnostics, diag) + } } default: switch arg := from.(type) {