Skip to content

Commit

Permalink
function/stdlib: ReverseListFunc handling marks
Browse files Browse the repository at this point in the history
Add precise mark handling to ReverseList func, plus some basic tests.
  • Loading branch information
mildwonkey authored and apparentlymart committed Apr 30, 2021
1 parent c79753d commit 5f71236
Show file tree
Hide file tree
Showing 2 changed files with 114 additions and 8 deletions.
19 changes: 11 additions & 8 deletions cty/function/stdlib/collection.go
Original file line number Diff line number Diff line change
Expand Up @@ -843,8 +843,9 @@ var MergeFunc = function.New(&function.Spec{
var ReverseListFunc = function.New(&function.Spec{
Params: []function.Parameter{
{
Name: "list",
Type: cty.DynamicPseudoType,
Name: "list",
Type: cty.DynamicPseudoType,
AllowMarked: true,
},
},
Type: func(args []cty.Value) (cty.Type, error) {
Expand All @@ -864,19 +865,21 @@ var ReverseListFunc = function.New(&function.Spec{
}
},
Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
in := args[0].AsValueSlice()
outVals := make([]cty.Value, len(in))
for i, v := range in {
in, marks := args[0].Unmark()
inVals := in.AsValueSlice()
outVals := make([]cty.Value, len(inVals))

for i, v := range inVals {
outVals[len(outVals)-i-1] = v
}
switch {
case retType.IsTupleType():
return cty.TupleVal(outVals), nil
return cty.TupleVal(outVals).WithMarks(marks), nil
default:
if len(outVals) == 0 {
return cty.ListValEmpty(retType.ElementType()), nil
return cty.ListValEmpty(retType.ElementType()).WithMarks(marks), nil
}
return cty.ListVal(outVals), nil
return cty.ListVal(outVals).WithMarks(marks), nil
}
},
})
Expand Down
103 changes: 103 additions & 0 deletions cty/function/stdlib/collection_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2244,3 +2244,106 @@ func TestSetproduct(t *testing.T) {
})
}
}

func TestReverseList(t *testing.T) {
tests := []struct {
Input cty.Value
Want cty.Value
Err string
}{
{
cty.NilVal,
cty.NilVal,
`argument must not be null`,
},
{
cty.ListValEmpty(cty.String),
cty.ListValEmpty(cty.String),
``,
},
{
cty.ListValEmpty(cty.String).Mark("foo"),
cty.ListValEmpty(cty.String).Mark("foo"),
``,
},
{
cty.UnknownVal(cty.List(cty.String)),
cty.UnknownVal(cty.List(cty.String)),
``,
},
{ // marks on list elements
cty.ListVal([]cty.Value{
cty.StringVal("beep").Mark("boop"),
cty.StringVal("bop"),
cty.StringVal("bloop"),
}),
cty.ListVal([]cty.Value{
cty.StringVal("bloop"),
cty.StringVal("bop"),
cty.StringVal("beep").Mark("boop"),
}),
``,
},
{ // marks on the entire input are preserved
cty.ListVal([]cty.Value{
cty.StringVal("beep").Mark("boop"),
cty.StringVal("bop"),
cty.StringVal("bloop"),
}).Mark("outer"),
cty.ListVal([]cty.Value{
cty.StringVal("bloop"),
cty.StringVal("bop"),
cty.StringVal("beep").Mark("boop"),
}).Mark("outer"),
``,
},
{ // marks on tuple elements
cty.TupleVal([]cty.Value{
cty.StringVal("beep").Mark("boop"),
cty.StringVal("bop"),
cty.StringVal("bloop"),
}),
cty.TupleVal([]cty.Value{
cty.StringVal("bloop"),
cty.StringVal("bop"),
cty.StringVal("beep").Mark("boop"),
}),
``,
},
{ // Set elements don't support individual marks; any marks on elements get propegated to the entire set.
cty.SetVal([]cty.Value{
cty.StringVal("beep").Mark("boop"),
cty.StringVal("bop"),
cty.StringVal("bloop"),
}),
// sets end up sorted alphabetically when converted to lists
cty.ListVal([]cty.Value{
cty.StringVal("bop"),
cty.StringVal("bloop"),
cty.StringVal("beep"),
}).Mark("boop"),
``,
},
}

for _, test := range tests {
t.Run(fmt.Sprintf("ReverseList(%#v)", test.Input), func(t *testing.T) {
got, err := ReverseList(test.Input)
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 5f71236

Please sign in to comment.