Skip to content

Commit

Permalink
function/stdlib: SliceFunc mark handling
Browse files Browse the repository at this point in the history
SliceFunc will now preserve marks on the input list as a whole, and any individual elements.
  • Loading branch information
mildwonkey authored and apparentlymart committed Apr 30, 2021
1 parent 5f71236 commit eb5c7b7
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 10 deletions.
24 changes: 14 additions & 10 deletions cty/function/stdlib/collection.go
Original file line number Diff line number Diff line change
Expand Up @@ -1023,8 +1023,9 @@ var SetProductFunc = function.New(&function.Spec{
var SliceFunc = function.New(&function.Spec{
Params: []function.Parameter{
{
Name: "list",
Type: cty.DynamicPseudoType,
Name: "list",
Type: cty.DynamicPseudoType,
AllowMarked: true,
},
{
Name: "start_index",
Expand Down Expand Up @@ -1063,10 +1064,10 @@ var SliceFunc = function.New(&function.Spec{
return cty.Tuple(argTy.TupleElementTypes()[startIndex:endIndex]), nil
},
Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
inputList := args[0]
inputList, marks := args[0].Unmark()

if retType == cty.DynamicPseudoType {
return cty.DynamicVal, nil
return cty.DynamicVal.WithMarks(marks), nil
}

// we ignore idxsKnown return value here because the indices are always
Expand All @@ -1078,28 +1079,31 @@ var SliceFunc = function.New(&function.Spec{

if endIndex-startIndex == 0 {
if retType.IsTupleType() {
return cty.EmptyTupleVal, nil
return cty.EmptyTupleVal.WithMarks(marks), nil
}
return cty.ListValEmpty(retType.ElementType()), nil
return cty.ListValEmpty(retType.ElementType()).WithMarks(marks), nil
}

outputList := inputList.AsValueSlice()[startIndex:endIndex]

if retType.IsTupleType() {
return cty.TupleVal(outputList), nil
return cty.TupleVal(outputList).WithMarks(marks), nil
}

return cty.ListVal(outputList), nil
return cty.ListVal(outputList).WithMarks(marks), nil
},
})

func sliceIndexes(args []cty.Value) (int, int, bool, error) {
var startIndex, endIndex, length int
var startKnown, endKnown, lengthKnown bool

// remove marks from args[0]
list, _ := args[0].Unmark()

// If it's a tuple then we always know the length by the type, but collections might be unknown or have unknown length
if args[0].Type().IsTupleType() || args[0].Length().IsKnown() {
length = args[0].LengthInt()
if list.Type().IsTupleType() || list.Length().IsKnown() {
length = list.LengthInt()
lengthKnown = true
}

Expand Down
74 changes: 74 additions & 0 deletions cty/function/stdlib/collection_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2347,3 +2347,77 @@ func TestReverseList(t *testing.T) {
})
}
}

func TestSlice(t *testing.T) {
tests := []struct {
Input cty.Value
Start cty.Value
End cty.Value
Want cty.Value
Err string
}{
{
Input: cty.ListVal([]cty.Value{
cty.StringVal("a"),
cty.StringVal("b"),
cty.StringVal("c"),
}),
Start: cty.NumberIntVal(0),
End: cty.NumberIntVal(2),
Want: cty.ListVal([]cty.Value{
cty.StringVal("a"),
cty.StringVal("b"),
}),
Err: ``,
},
{ // The entire input list is marked, so the return should be marked
Input: cty.ListVal([]cty.Value{
cty.StringVal("a"),
cty.StringVal("b"),
cty.StringVal("c"),
}).Mark("bloop"),
Start: cty.NumberIntVal(0),
End: cty.NumberIntVal(2),
Want: cty.ListVal([]cty.Value{
cty.StringVal("a"),
cty.StringVal("b"),
}).Mark("bloop"),
Err: ``,
},
{ // individual element marks should be preserved
Input: cty.ListVal([]cty.Value{
cty.StringVal("a"),
cty.StringVal("b").Mark("bloop"),
cty.StringVal("c"),
}),
Start: cty.NumberIntVal(0),
End: cty.NumberIntVal(2),
Want: cty.ListVal([]cty.Value{
cty.StringVal("a"),
cty.StringVal("b").Mark("bloop"),
}),
Err: ``,
},
}

for _, test := range tests {
t.Run(fmt.Sprintf("Slice(%#v)", test.Input), func(t *testing.T) {
got, err := Slice(test.Input, test.Start, test.End)
if test.Err != "" {
if err == nil {
t.Fatal("succeeded; want error")
}
if got, want := err.Error(), test.Err; got != want {
t.Fatalf("wrong error\ngot: %s\nwant: %s", got, want)
}
return
} else if err != nil {
t.Fatalf("unexpected error: %s", err)
}

if !got.RawEquals(test.Want) {
t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want)
}
})
}
}

0 comments on commit eb5c7b7

Please sign in to comment.