Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

avoid panics with marked Index key values #451

Merged
merged 1 commit into from
Mar 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions ops.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ func Index(collection, key cty.Value, srcRange *Range) (cty.Value, Diagnostics)
// division rather than integer division.
if (ty.IsListType() || ty.IsTupleType()) && key.Type().Equals(cty.Number) {
if key.IsKnown() && !key.IsNull() {
key, _ := key.Unmark()
bf := key.AsBigFloat()
if _, acc := bf.Int(nil); acc != big.Exact {
return cty.DynamicVal, Diagnostics{
Expand Down Expand Up @@ -143,6 +144,7 @@ func Index(collection, key cty.Value, srcRange *Range) (cty.Value, Diagnostics)
return cty.DynamicVal, nil
}

key, _ = key.Unmark()
attrName := key.AsString()

if !ty.HasAttribute(attrName) {
Expand Down
121 changes: 121 additions & 0 deletions ops_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,3 +155,124 @@ func TestApplyPath(t *testing.T) {
})
}
}

func TestIndex(t *testing.T) {
tests := map[string]struct {
coll cty.Value
key cty.Value
want cty.Value
err string
}{
"marked key to maked value": {
coll: cty.ListVal([]cty.Value{
cty.StringVal("a"),
}),
key: cty.NumberIntVal(0).Mark("marked"),
want: cty.StringVal("a").Mark("marked"),
},
"missing list key": {
coll: cty.ListVal([]cty.Value{
cty.StringVal("a"),
}),
key: cty.NumberIntVal(1).Mark("marked"),
want: cty.DynamicVal,
err: "Invalid index",
},
"null marked key": {
coll: cty.ListVal([]cty.Value{
cty.StringVal("a"),
}),
key: cty.NullVal(cty.Number).Mark("marked"),
want: cty.DynamicVal,
err: "Invalid index",
},
"dynamic key": {
coll: cty.ListVal([]cty.Value{
cty.StringVal("a"),
}),
key: cty.DynamicVal,
want: cty.DynamicVal,
},
"invalid marked key type": {
coll: cty.ListVal([]cty.Value{
cty.StringVal("a"),
}),
key: cty.StringVal("foo").Mark("marked"),
want: cty.DynamicVal,
err: "Invalid index",
},
"marked map key": {
coll: cty.MapVal(map[string]cty.Value{
"foo": cty.StringVal("a"),
}),
key: cty.StringVal("foo").Mark("marked"),
want: cty.StringVal("a").Mark("marked"),
},
"missing marked map key": {
coll: cty.MapVal(map[string]cty.Value{
"foo": cty.StringVal("a"),
}),
key: cty.StringVal("bar").Mark("mark"),
want: cty.DynamicVal,
err: "Invalid index",
},
"marked object key": {
coll: cty.ObjectVal(map[string]cty.Value{
"foo": cty.StringVal("a"),
}),
key: cty.StringVal("foo").Mark("marked"),
// an object attribute is fetched by string index, and the marks
// are not maintained
want: cty.StringVal("a"),
},
"invalid marked object key type": {
coll: cty.ObjectVal(map[string]cty.Value{
"foo": cty.StringVal("a"),
}),
key: cty.ListVal([]cty.Value{cty.NullVal(cty.String)}).Mark("marked"),
want: cty.DynamicVal,
err: "Invalid index",
},
"invalid marked object key": {
coll: cty.ObjectVal(map[string]cty.Value{
"foo": cty.StringVal("a"),
}),
key: cty.NumberIntVal(0).Mark("marked"),
want: cty.DynamicVal,
err: "Invalid index",
},
}

for name, tc := range tests {
t.Run(name, func(t *testing.T) {
t.Logf("testing Index\ncollection: %#v\nkey: %#v", tc.coll, tc.key)

got, diags := Index(tc.coll, tc.key, nil)

for _, diag := range diags {
t.Logf(diag.Error())
}

if tc.err != "" {
if !diags.HasErrors() {
t.Fatalf("succeeded, but want error\nwant error: %s", tc.err)
}
if len(diags) != 1 {
t.Fatalf("wrong number of diagnostics %d; want 1", len(diags))
}

if gotErrStr := diags[0].Summary; gotErrStr != tc.err {
t.Fatalf("wrong error\ngot error: %s\nwant error: %s", gotErrStr, tc.err)
}
return
}

if diags.HasErrors() {
t.Fatalf("failed, but want success\ngot diagnostics:\n%s", diags.Error())
}
if !tc.want.RawEquals(got) {
t.Fatalf("wrong result\ngot: %#v\nwant: %#v", got, tc.want)
}
})
}
}