Skip to content

Commit

Permalink
update, add test
Browse files Browse the repository at this point in the history
  • Loading branch information
aq17 committed Dec 1, 2022
1 parent 5cb5aba commit 5d9d8d5
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 23 deletions.
7 changes: 5 additions & 2 deletions pkg/codegen/dotnet/gen_program_expressions.go
Expand Up @@ -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
Expand Down
7 changes: 5 additions & 2 deletions pkg/codegen/go/gen_program_expressions.go
Expand Up @@ -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) {
Expand Down
7 changes: 5 additions & 2 deletions pkg/codegen/nodejs/gen_program_expressions.go
Expand Up @@ -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)
Expand Down
35 changes: 20 additions & 15 deletions pkg/codegen/pcl/binder_schema.go
Expand Up @@ -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)

Expand All @@ -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
}
}

Expand All @@ -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 {
Expand All @@ -563,20 +566,22 @@ 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)
if member != nil {
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
}
34 changes: 34 additions & 0 deletions pkg/codegen/pcl/binder_schema_test.go
Expand Up @@ -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")
Expand All @@ -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]")

}
7 changes: 5 additions & 2 deletions pkg/codegen/python/gen_program_expressions.go
Expand Up @@ -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)
Expand All @@ -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) {
Expand Down

0 comments on commit 5d9d8d5

Please sign in to comment.