3220 lines
68 KiB
Go
3220 lines
68 KiB
Go
package funcs
|
|
|
|
import (
|
|
"fmt"
|
|
"testing"
|
|
|
|
"github.com/zclconf/go-cty/cty"
|
|
)
|
|
|
|
func TestElement(t *testing.T) {
|
|
tests := []struct {
|
|
List cty.Value
|
|
Index cty.Value
|
|
Want cty.Value
|
|
}{
|
|
{
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("hello"),
|
|
}),
|
|
cty.NumberIntVal(0),
|
|
cty.StringVal("hello"),
|
|
},
|
|
{
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("hello"),
|
|
}),
|
|
cty.NumberIntVal(1),
|
|
cty.StringVal("hello"),
|
|
},
|
|
{
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("hello"),
|
|
cty.StringVal("bonjour"),
|
|
}),
|
|
cty.NumberIntVal(0),
|
|
cty.StringVal("hello"),
|
|
},
|
|
{
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("hello"),
|
|
cty.StringVal("bonjour"),
|
|
}),
|
|
cty.NumberIntVal(1),
|
|
cty.StringVal("bonjour"),
|
|
},
|
|
{
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("hello"),
|
|
cty.StringVal("bonjour"),
|
|
}),
|
|
cty.NumberIntVal(2),
|
|
cty.StringVal("hello"),
|
|
},
|
|
|
|
{
|
|
cty.TupleVal([]cty.Value{
|
|
cty.StringVal("hello"),
|
|
}),
|
|
cty.NumberIntVal(0),
|
|
cty.StringVal("hello"),
|
|
},
|
|
{
|
|
cty.TupleVal([]cty.Value{
|
|
cty.StringVal("hello"),
|
|
}),
|
|
cty.NumberIntVal(1),
|
|
cty.StringVal("hello"),
|
|
},
|
|
{
|
|
cty.TupleVal([]cty.Value{
|
|
cty.StringVal("hello"),
|
|
cty.StringVal("bonjour"),
|
|
}),
|
|
cty.NumberIntVal(0),
|
|
cty.StringVal("hello"),
|
|
},
|
|
{
|
|
cty.TupleVal([]cty.Value{
|
|
cty.StringVal("hello"),
|
|
cty.StringVal("bonjour"),
|
|
}),
|
|
cty.NumberIntVal(1),
|
|
cty.StringVal("bonjour"),
|
|
},
|
|
{
|
|
cty.TupleVal([]cty.Value{
|
|
cty.StringVal("hello"),
|
|
cty.StringVal("bonjour"),
|
|
}),
|
|
cty.NumberIntVal(2),
|
|
cty.StringVal("hello"),
|
|
},
|
|
{
|
|
cty.TupleVal([]cty.Value{
|
|
cty.StringVal("hello"),
|
|
cty.StringVal("bonjour"),
|
|
}),
|
|
cty.UnknownVal(cty.Number),
|
|
cty.DynamicVal,
|
|
},
|
|
{
|
|
cty.UnknownVal(cty.Tuple([]cty.Type{cty.String, cty.Bool})),
|
|
cty.NumberIntVal(1),
|
|
cty.UnknownVal(cty.Bool),
|
|
},
|
|
{
|
|
cty.UnknownVal(cty.Tuple([]cty.Type{cty.String, cty.String})),
|
|
cty.UnknownVal(cty.Number),
|
|
cty.DynamicVal,
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(fmt.Sprintf("Element(%#v, %#v)", test.List, test.Index), func(t *testing.T) {
|
|
got, err := Element(test.List, test.Index)
|
|
|
|
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)
|
|
}
|
|
})
|
|
}
|
|
|
|
}
|
|
|
|
func TestLength(t *testing.T) {
|
|
tests := []struct {
|
|
Value cty.Value
|
|
Want cty.Value
|
|
}{
|
|
{
|
|
cty.ListValEmpty(cty.Number),
|
|
cty.NumberIntVal(0),
|
|
},
|
|
{
|
|
cty.ListVal([]cty.Value{cty.True}),
|
|
cty.NumberIntVal(1),
|
|
},
|
|
{
|
|
cty.ListVal([]cty.Value{cty.UnknownVal(cty.Bool)}),
|
|
cty.NumberIntVal(1),
|
|
},
|
|
{
|
|
cty.SetValEmpty(cty.Number),
|
|
cty.NumberIntVal(0),
|
|
},
|
|
{
|
|
cty.SetVal([]cty.Value{cty.True}),
|
|
cty.NumberIntVal(1),
|
|
},
|
|
{
|
|
cty.MapValEmpty(cty.Bool),
|
|
cty.NumberIntVal(0),
|
|
},
|
|
{
|
|
cty.MapVal(map[string]cty.Value{"hello": cty.True}),
|
|
cty.NumberIntVal(1),
|
|
},
|
|
{
|
|
cty.EmptyTupleVal,
|
|
cty.NumberIntVal(0),
|
|
},
|
|
{
|
|
cty.UnknownVal(cty.EmptyTuple),
|
|
cty.NumberIntVal(0),
|
|
},
|
|
{
|
|
cty.TupleVal([]cty.Value{cty.True}),
|
|
cty.NumberIntVal(1),
|
|
},
|
|
{
|
|
cty.EmptyObjectVal,
|
|
cty.NumberIntVal(0),
|
|
},
|
|
{
|
|
cty.UnknownVal(cty.EmptyObject),
|
|
cty.NumberIntVal(0),
|
|
},
|
|
{
|
|
cty.ObjectVal(map[string]cty.Value{"true": cty.True}),
|
|
cty.NumberIntVal(1),
|
|
},
|
|
{
|
|
cty.UnknownVal(cty.List(cty.Bool)),
|
|
cty.UnknownVal(cty.Number),
|
|
},
|
|
{
|
|
cty.DynamicVal,
|
|
cty.UnknownVal(cty.Number),
|
|
},
|
|
{
|
|
cty.StringVal("hello"),
|
|
cty.NumberIntVal(5),
|
|
},
|
|
{
|
|
cty.StringVal(""),
|
|
cty.NumberIntVal(0),
|
|
},
|
|
{
|
|
cty.StringVal("1"),
|
|
cty.NumberIntVal(1),
|
|
},
|
|
{
|
|
cty.StringVal("Живой Журнал"),
|
|
cty.NumberIntVal(12),
|
|
},
|
|
{
|
|
// note that the dieresis here is intentionally a combining
|
|
// ligature.
|
|
cty.StringVal("noël"),
|
|
cty.NumberIntVal(4),
|
|
},
|
|
{
|
|
// The Es in this string has three combining acute accents.
|
|
// This tests something that NFC-normalization cannot collapse
|
|
// into a single precombined codepoint, since otherwise we might
|
|
// be cheating and relying on the single-codepoint forms.
|
|
cty.StringVal("wé́́é́́é́́!"),
|
|
cty.NumberIntVal(5),
|
|
},
|
|
{
|
|
// Go's normalization forms don't handle this ligature, so we
|
|
// will produce the wrong result but this is now a compatibility
|
|
// constraint and so we'll test it.
|
|
cty.StringVal("baffle"),
|
|
cty.NumberIntVal(4),
|
|
},
|
|
{
|
|
cty.StringVal("😸😾"),
|
|
cty.NumberIntVal(2),
|
|
},
|
|
{
|
|
cty.UnknownVal(cty.String),
|
|
cty.UnknownVal(cty.Number),
|
|
},
|
|
{
|
|
cty.DynamicVal,
|
|
cty.UnknownVal(cty.Number),
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(fmt.Sprintf("Length(%#v)", test.Value), func(t *testing.T) {
|
|
got, err := Length(test.Value)
|
|
|
|
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)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCoalesce(t *testing.T) {
|
|
tests := []struct {
|
|
Values []cty.Value
|
|
Want cty.Value
|
|
Err bool
|
|
}{
|
|
{
|
|
[]cty.Value{cty.StringVal("first"), cty.StringVal("second"), cty.StringVal("third")},
|
|
cty.StringVal("first"),
|
|
false,
|
|
},
|
|
{
|
|
[]cty.Value{cty.StringVal(""), cty.StringVal("second"), cty.StringVal("third")},
|
|
cty.StringVal("second"),
|
|
false,
|
|
},
|
|
{
|
|
[]cty.Value{cty.StringVal(""), cty.StringVal("")},
|
|
cty.NilVal,
|
|
true,
|
|
},
|
|
{
|
|
[]cty.Value{cty.True},
|
|
cty.True,
|
|
false,
|
|
},
|
|
{
|
|
[]cty.Value{cty.NullVal(cty.Bool), cty.True},
|
|
cty.True,
|
|
false,
|
|
},
|
|
{
|
|
[]cty.Value{cty.NullVal(cty.Bool), cty.False},
|
|
cty.False,
|
|
false,
|
|
},
|
|
{
|
|
[]cty.Value{cty.NullVal(cty.Bool), cty.False, cty.StringVal("hello")},
|
|
cty.StringVal("false"),
|
|
false,
|
|
},
|
|
{
|
|
[]cty.Value{cty.True, cty.UnknownVal(cty.Bool)},
|
|
cty.True,
|
|
false,
|
|
},
|
|
{
|
|
[]cty.Value{cty.UnknownVal(cty.Bool), cty.True},
|
|
cty.UnknownVal(cty.Bool),
|
|
false,
|
|
},
|
|
{
|
|
[]cty.Value{cty.UnknownVal(cty.Bool), cty.StringVal("hello")},
|
|
cty.UnknownVal(cty.String),
|
|
false,
|
|
},
|
|
{
|
|
[]cty.Value{cty.DynamicVal, cty.True},
|
|
cty.UnknownVal(cty.Bool),
|
|
false,
|
|
},
|
|
{
|
|
[]cty.Value{cty.DynamicVal},
|
|
cty.DynamicVal,
|
|
false,
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(fmt.Sprintf("Coalesce(%#v...)", test.Values), func(t *testing.T) {
|
|
got, err := Coalesce(test.Values...)
|
|
|
|
if test.Err {
|
|
if err == nil {
|
|
t.Fatal("succeeded; want error")
|
|
}
|
|
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)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCoalesceList(t *testing.T) {
|
|
tests := []struct {
|
|
Values []cty.Value
|
|
Want cty.Value
|
|
Err bool
|
|
}{
|
|
{
|
|
[]cty.Value{
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("first"), cty.StringVal("second"),
|
|
}),
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("third"), cty.StringVal("fourth"),
|
|
}),
|
|
},
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("first"), cty.StringVal("second"),
|
|
}),
|
|
false,
|
|
},
|
|
{
|
|
[]cty.Value{
|
|
cty.ListValEmpty(cty.String),
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("third"), cty.StringVal("fourth"),
|
|
}),
|
|
},
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("third"), cty.StringVal("fourth"),
|
|
}),
|
|
false,
|
|
},
|
|
{
|
|
[]cty.Value{
|
|
cty.ListValEmpty(cty.Number),
|
|
cty.ListVal([]cty.Value{
|
|
cty.NumberIntVal(1),
|
|
cty.NumberIntVal(2),
|
|
}),
|
|
},
|
|
cty.ListVal([]cty.Value{
|
|
cty.NumberIntVal(1),
|
|
cty.NumberIntVal(2),
|
|
}),
|
|
false,
|
|
},
|
|
{ // lists with mixed types
|
|
[]cty.Value{
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("first"), cty.StringVal("second"),
|
|
}),
|
|
cty.ListVal([]cty.Value{
|
|
cty.NumberIntVal(1),
|
|
cty.NumberIntVal(2),
|
|
}),
|
|
},
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("first"), cty.StringVal("second"),
|
|
}),
|
|
false,
|
|
},
|
|
{ // lists with mixed types
|
|
[]cty.Value{
|
|
cty.ListVal([]cty.Value{
|
|
cty.NumberIntVal(1),
|
|
cty.NumberIntVal(2),
|
|
}),
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("first"), cty.StringVal("second"),
|
|
}),
|
|
},
|
|
cty.ListVal([]cty.Value{
|
|
cty.NumberIntVal(1), cty.NumberIntVal(2),
|
|
}),
|
|
false,
|
|
},
|
|
{ // list with unknown values
|
|
[]cty.Value{
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("first"), cty.StringVal("second"),
|
|
}),
|
|
cty.ListVal([]cty.Value{
|
|
cty.UnknownVal(cty.String),
|
|
}),
|
|
},
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("first"), cty.StringVal("second"),
|
|
}),
|
|
false,
|
|
},
|
|
{ // list with unknown values
|
|
[]cty.Value{
|
|
cty.ListVal([]cty.Value{
|
|
cty.UnknownVal(cty.String),
|
|
}),
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("third"), cty.StringVal("fourth"),
|
|
}),
|
|
},
|
|
cty.ListVal([]cty.Value{
|
|
cty.UnknownVal(cty.String),
|
|
}),
|
|
false,
|
|
},
|
|
{
|
|
[]cty.Value{
|
|
cty.MapValEmpty(cty.DynamicPseudoType),
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("third"), cty.StringVal("fourth"),
|
|
}),
|
|
},
|
|
cty.NilVal,
|
|
true,
|
|
},
|
|
{ // unknown list
|
|
[]cty.Value{
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("third"), cty.StringVal("fourth"),
|
|
}),
|
|
cty.UnknownVal(cty.List(cty.String)),
|
|
},
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("third"), cty.StringVal("fourth"),
|
|
}),
|
|
false,
|
|
},
|
|
{ // unknown list
|
|
[]cty.Value{
|
|
cty.ListValEmpty(cty.String),
|
|
cty.UnknownVal(cty.List(cty.String)),
|
|
},
|
|
cty.DynamicVal,
|
|
false,
|
|
},
|
|
{ // unknown list
|
|
[]cty.Value{
|
|
cty.UnknownVal(cty.List(cty.String)),
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("third"), cty.StringVal("fourth"),
|
|
}),
|
|
},
|
|
cty.DynamicVal,
|
|
false,
|
|
},
|
|
{ // unknown tuple
|
|
[]cty.Value{
|
|
cty.UnknownVal(cty.Tuple([]cty.Type{cty.String})),
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("third"), cty.StringVal("fourth"),
|
|
}),
|
|
},
|
|
cty.DynamicVal,
|
|
false,
|
|
},
|
|
{ // empty tuple
|
|
[]cty.Value{
|
|
cty.EmptyTupleVal,
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("third"), cty.StringVal("fourth"),
|
|
}),
|
|
},
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("third"), cty.StringVal("fourth"),
|
|
}),
|
|
false,
|
|
},
|
|
{ // tuple value
|
|
[]cty.Value{
|
|
cty.TupleVal([]cty.Value{
|
|
cty.StringVal("a"),
|
|
cty.NumberIntVal(2),
|
|
}),
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("third"), cty.StringVal("fourth"),
|
|
}),
|
|
},
|
|
cty.TupleVal([]cty.Value{
|
|
cty.StringVal("a"),
|
|
cty.NumberIntVal(2),
|
|
}),
|
|
false,
|
|
},
|
|
{ // reject set value
|
|
[]cty.Value{
|
|
cty.SetVal([]cty.Value{
|
|
cty.StringVal("a"),
|
|
}),
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("third"), cty.StringVal("fourth"),
|
|
}),
|
|
},
|
|
cty.NilVal,
|
|
true,
|
|
},
|
|
}
|
|
|
|
for i, test := range tests {
|
|
t.Run(fmt.Sprintf("%d-coalescelist(%#v)", i, test.Values), func(t *testing.T) {
|
|
got, err := CoalesceList(test.Values...)
|
|
|
|
if test.Err {
|
|
if err == nil {
|
|
t.Fatal("succeeded; want error")
|
|
}
|
|
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)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCompact(t *testing.T) {
|
|
tests := []struct {
|
|
List cty.Value
|
|
Want cty.Value
|
|
Err bool
|
|
}{
|
|
{
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("test"),
|
|
cty.StringVal(""),
|
|
cty.StringVal("test"),
|
|
cty.NullVal(cty.String),
|
|
}),
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("test"),
|
|
cty.StringVal("test"),
|
|
}),
|
|
false,
|
|
},
|
|
{
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal(""),
|
|
cty.StringVal(""),
|
|
cty.StringVal(""),
|
|
}),
|
|
cty.ListValEmpty(cty.String),
|
|
false,
|
|
},
|
|
{
|
|
cty.ListVal([]cty.Value{
|
|
cty.NullVal(cty.String),
|
|
cty.NullVal(cty.String),
|
|
}),
|
|
cty.ListValEmpty(cty.String),
|
|
false,
|
|
},
|
|
{
|
|
cty.ListValEmpty(cty.String),
|
|
cty.ListValEmpty(cty.String),
|
|
false,
|
|
},
|
|
{
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("test"),
|
|
cty.StringVal("test"),
|
|
cty.StringVal(""),
|
|
}),
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("test"),
|
|
cty.StringVal("test"),
|
|
}),
|
|
false,
|
|
},
|
|
{
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("test"),
|
|
cty.UnknownVal(cty.String),
|
|
cty.StringVal(""),
|
|
cty.NullVal(cty.String),
|
|
}),
|
|
cty.UnknownVal(cty.List(cty.String)),
|
|
false,
|
|
},
|
|
{ // errors on list of lists
|
|
cty.ListVal([]cty.Value{
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("test"),
|
|
}),
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal(""),
|
|
}),
|
|
}),
|
|
cty.NilVal,
|
|
true,
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(fmt.Sprintf("compact(%#v)", test.List), func(t *testing.T) {
|
|
got, err := Compact(test.List)
|
|
|
|
if test.Err {
|
|
if err == nil {
|
|
t.Fatal("succeeded; want error")
|
|
}
|
|
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)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestContains(t *testing.T) {
|
|
listOfStrings := cty.ListVal([]cty.Value{
|
|
cty.StringVal("the"),
|
|
cty.StringVal("quick"),
|
|
cty.StringVal("brown"),
|
|
cty.StringVal("fox"),
|
|
})
|
|
listOfInts := cty.ListVal([]cty.Value{
|
|
cty.NumberIntVal(1),
|
|
cty.NumberIntVal(2),
|
|
cty.NumberIntVal(3),
|
|
cty.NumberIntVal(4),
|
|
})
|
|
listWithUnknown := cty.ListVal([]cty.Value{
|
|
cty.StringVal("the"),
|
|
cty.StringVal("quick"),
|
|
cty.StringVal("brown"),
|
|
cty.UnknownVal(cty.String),
|
|
})
|
|
|
|
tests := []struct {
|
|
List cty.Value
|
|
Value cty.Value
|
|
Want cty.Value
|
|
Err bool
|
|
}{
|
|
{
|
|
listOfStrings,
|
|
cty.StringVal("the"),
|
|
cty.BoolVal(true),
|
|
false,
|
|
},
|
|
{
|
|
listWithUnknown,
|
|
cty.StringVal("the"),
|
|
cty.BoolVal(true),
|
|
false,
|
|
},
|
|
{
|
|
listOfStrings,
|
|
cty.StringVal("penguin"),
|
|
cty.BoolVal(false),
|
|
false,
|
|
},
|
|
{
|
|
listOfInts,
|
|
cty.NumberIntVal(1),
|
|
cty.BoolVal(true),
|
|
false,
|
|
},
|
|
{
|
|
listOfInts,
|
|
cty.NumberIntVal(42),
|
|
cty.BoolVal(false),
|
|
false,
|
|
},
|
|
{ // And now we mix and match
|
|
listOfInts,
|
|
cty.StringVal("1"),
|
|
cty.BoolVal(false),
|
|
false,
|
|
},
|
|
{ // Check a list with an unknown value
|
|
cty.ListVal([]cty.Value{
|
|
cty.UnknownVal(cty.String),
|
|
cty.StringVal("quick"),
|
|
cty.StringVal("brown"),
|
|
cty.StringVal("fox"),
|
|
}),
|
|
cty.StringVal("quick"),
|
|
cty.BoolVal(true),
|
|
false,
|
|
},
|
|
{ // set val
|
|
cty.SetVal([]cty.Value{
|
|
cty.StringVal("quick"),
|
|
cty.StringVal("brown"),
|
|
cty.StringVal("fox"),
|
|
}),
|
|
cty.StringVal("quick"),
|
|
cty.BoolVal(true),
|
|
false,
|
|
},
|
|
{ // tuple val
|
|
cty.TupleVal([]cty.Value{
|
|
cty.StringVal("quick"),
|
|
cty.StringVal("brown"),
|
|
cty.NumberIntVal(3),
|
|
}),
|
|
cty.NumberIntVal(3),
|
|
cty.BoolVal(true),
|
|
false,
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(fmt.Sprintf("contains(%#v, %#v)", test.List, test.Value), func(t *testing.T) {
|
|
got, err := Contains(test.List, test.Value)
|
|
|
|
if test.Err {
|
|
if err == nil {
|
|
t.Fatal("succeeded; want error")
|
|
}
|
|
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)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestIndex(t *testing.T) {
|
|
tests := []struct {
|
|
List cty.Value
|
|
Value cty.Value
|
|
Want cty.Value
|
|
Err bool
|
|
}{
|
|
{
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("a"),
|
|
cty.StringVal("b"),
|
|
cty.StringVal("c"),
|
|
}),
|
|
cty.StringVal("a"),
|
|
cty.NumberIntVal(0),
|
|
false,
|
|
},
|
|
{
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("a"),
|
|
cty.StringVal("b"),
|
|
cty.UnknownVal(cty.String),
|
|
}),
|
|
cty.StringVal("a"),
|
|
cty.NumberIntVal(0),
|
|
false,
|
|
},
|
|
{
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("a"),
|
|
cty.StringVal("b"),
|
|
cty.StringVal("c"),
|
|
}),
|
|
cty.StringVal("b"),
|
|
cty.NumberIntVal(1),
|
|
false,
|
|
},
|
|
{
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("a"),
|
|
cty.StringVal("b"),
|
|
cty.StringVal("c"),
|
|
}),
|
|
cty.StringVal("z"),
|
|
cty.NilVal,
|
|
true,
|
|
},
|
|
{
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("1"),
|
|
cty.StringVal("2"),
|
|
cty.StringVal("3"),
|
|
}),
|
|
cty.NumberIntVal(1),
|
|
cty.NumberIntVal(0),
|
|
true,
|
|
},
|
|
{
|
|
cty.ListVal([]cty.Value{
|
|
cty.NumberIntVal(1),
|
|
cty.NumberIntVal(2),
|
|
cty.NumberIntVal(3),
|
|
}),
|
|
cty.NumberIntVal(2),
|
|
cty.NumberIntVal(1),
|
|
false,
|
|
},
|
|
{
|
|
cty.ListVal([]cty.Value{
|
|
cty.NumberIntVal(1),
|
|
cty.NumberIntVal(2),
|
|
cty.NumberIntVal(3),
|
|
}),
|
|
cty.NumberIntVal(4),
|
|
cty.NilVal,
|
|
true,
|
|
},
|
|
{
|
|
cty.ListVal([]cty.Value{
|
|
cty.NumberIntVal(1),
|
|
cty.NumberIntVal(2),
|
|
cty.NumberIntVal(3),
|
|
}),
|
|
cty.StringVal("1"),
|
|
cty.NumberIntVal(0),
|
|
true,
|
|
},
|
|
{
|
|
cty.TupleVal([]cty.Value{
|
|
cty.NumberIntVal(1),
|
|
cty.NumberIntVal(2),
|
|
cty.NumberIntVal(3),
|
|
}),
|
|
cty.NumberIntVal(1),
|
|
cty.NumberIntVal(0),
|
|
false,
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(fmt.Sprintf("index(%#v, %#v)", test.List, test.Value), func(t *testing.T) {
|
|
got, err := Index(test.List, test.Value)
|
|
|
|
if test.Err {
|
|
if err == nil {
|
|
t.Fatal("succeeded; want error")
|
|
}
|
|
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)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDistinct(t *testing.T) {
|
|
tests := []struct {
|
|
List cty.Value
|
|
Want cty.Value
|
|
Err bool
|
|
}{
|
|
{
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("a"),
|
|
cty.StringVal("b"),
|
|
cty.StringVal("a"),
|
|
cty.StringVal("b"),
|
|
}),
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("a"),
|
|
cty.StringVal("b"),
|
|
}),
|
|
false,
|
|
},
|
|
{
|
|
cty.ListValEmpty(cty.String),
|
|
cty.ListValEmpty(cty.String),
|
|
false,
|
|
},
|
|
{
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("a"),
|
|
cty.StringVal("b"),
|
|
cty.StringVal("a"),
|
|
cty.UnknownVal(cty.String),
|
|
}),
|
|
cty.UnknownVal(cty.List(cty.String)),
|
|
false,
|
|
},
|
|
{
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("a"),
|
|
cty.StringVal("b"),
|
|
cty.StringVal("c"),
|
|
cty.StringVal("d"),
|
|
}),
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("a"),
|
|
cty.StringVal("b"),
|
|
cty.StringVal("c"),
|
|
cty.StringVal("d"),
|
|
}),
|
|
false,
|
|
},
|
|
{
|
|
cty.ListVal([]cty.Value{
|
|
cty.NumberIntVal(1),
|
|
cty.NumberIntVal(2),
|
|
cty.NumberIntVal(1),
|
|
cty.NumberIntVal(2),
|
|
}),
|
|
cty.ListVal([]cty.Value{
|
|
cty.NumberIntVal(1),
|
|
cty.NumberIntVal(2),
|
|
}),
|
|
false,
|
|
},
|
|
{
|
|
cty.ListVal([]cty.Value{
|
|
cty.ListVal([]cty.Value{
|
|
cty.NumberIntVal(1),
|
|
cty.NumberIntVal(2),
|
|
}),
|
|
cty.ListVal([]cty.Value{
|
|
cty.NumberIntVal(1),
|
|
cty.NumberIntVal(2),
|
|
}),
|
|
}),
|
|
cty.ListVal([]cty.Value{
|
|
cty.ListVal([]cty.Value{
|
|
cty.NumberIntVal(1),
|
|
cty.NumberIntVal(2),
|
|
}),
|
|
}),
|
|
false,
|
|
},
|
|
{
|
|
cty.ListVal([]cty.Value{
|
|
cty.ListVal([]cty.Value{
|
|
cty.NumberIntVal(1),
|
|
cty.NumberIntVal(2),
|
|
}),
|
|
cty.ListVal([]cty.Value{
|
|
cty.NumberIntVal(3),
|
|
cty.NumberIntVal(4),
|
|
}),
|
|
}),
|
|
cty.ListVal([]cty.Value{
|
|
cty.ListVal([]cty.Value{
|
|
cty.NumberIntVal(1),
|
|
cty.NumberIntVal(2),
|
|
}),
|
|
cty.ListVal([]cty.Value{
|
|
cty.NumberIntVal(3),
|
|
cty.NumberIntVal(4),
|
|
}),
|
|
}),
|
|
false,
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(fmt.Sprintf("distinct(%#v)", test.List), func(t *testing.T) {
|
|
got, err := Distinct(test.List)
|
|
|
|
if test.Err {
|
|
if err == nil {
|
|
t.Fatal("succeeded; want error")
|
|
}
|
|
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)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestChunklist(t *testing.T) {
|
|
tests := []struct {
|
|
List cty.Value
|
|
Size cty.Value
|
|
Want cty.Value
|
|
Err bool
|
|
}{
|
|
{
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("a"),
|
|
cty.StringVal("b"),
|
|
cty.StringVal("c"),
|
|
}),
|
|
cty.NumberIntVal(1),
|
|
cty.ListVal([]cty.Value{
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("a"),
|
|
}),
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("b"),
|
|
}),
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("c"),
|
|
}),
|
|
}),
|
|
false,
|
|
},
|
|
{
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("a"),
|
|
cty.StringVal("b"),
|
|
cty.StringVal("c"),
|
|
}),
|
|
cty.NumberIntVal(-1),
|
|
cty.NilVal,
|
|
true,
|
|
},
|
|
{
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("a"),
|
|
cty.StringVal("b"),
|
|
cty.StringVal("c"),
|
|
}),
|
|
cty.NumberIntVal(0),
|
|
cty.ListVal([]cty.Value{
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("a"),
|
|
cty.StringVal("b"),
|
|
cty.StringVal("c"),
|
|
}),
|
|
}),
|
|
false,
|
|
},
|
|
{
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("a"),
|
|
cty.StringVal("b"),
|
|
cty.UnknownVal(cty.String),
|
|
}),
|
|
cty.NumberIntVal(1),
|
|
cty.ListVal([]cty.Value{
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("a"),
|
|
}),
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("b"),
|
|
}),
|
|
cty.ListVal([]cty.Value{
|
|
cty.UnknownVal(cty.String),
|
|
}),
|
|
}),
|
|
false,
|
|
},
|
|
{
|
|
cty.UnknownVal(cty.List(cty.String)),
|
|
cty.NumberIntVal(1),
|
|
cty.UnknownVal(cty.List(cty.List(cty.String))),
|
|
false,
|
|
},
|
|
{
|
|
cty.ListValEmpty(cty.String),
|
|
cty.NumberIntVal(3),
|
|
cty.ListValEmpty(cty.List(cty.String)),
|
|
false,
|
|
},
|
|
}
|
|
|
|
for i, test := range tests {
|
|
t.Run(fmt.Sprintf("%d-chunklist(%#v, %#v)", i, test.List, test.Size), func(t *testing.T) {
|
|
got, err := Chunklist(test.List, test.Size)
|
|
|
|
if test.Err {
|
|
if err == nil {
|
|
t.Fatal("succeeded; want error")
|
|
}
|
|
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)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestFlatten(t *testing.T) {
|
|
tests := []struct {
|
|
List cty.Value
|
|
Want cty.Value
|
|
Err bool
|
|
}{
|
|
{
|
|
cty.ListVal([]cty.Value{
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("a"),
|
|
cty.StringVal("b"),
|
|
}),
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("c"),
|
|
cty.StringVal("d"),
|
|
}),
|
|
}),
|
|
cty.TupleVal([]cty.Value{
|
|
cty.StringVal("a"),
|
|
cty.StringVal("b"),
|
|
cty.StringVal("c"),
|
|
cty.StringVal("d"),
|
|
}),
|
|
false,
|
|
},
|
|
// handle single elements as arguments
|
|
{
|
|
cty.TupleVal([]cty.Value{
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("a"),
|
|
cty.StringVal("b"),
|
|
}),
|
|
cty.StringVal("c"),
|
|
}),
|
|
cty.TupleVal([]cty.Value{
|
|
cty.StringVal("a"),
|
|
cty.StringVal("b"),
|
|
cty.StringVal("c"),
|
|
}), false,
|
|
},
|
|
// handle single elements and mixed primitive types as arguments
|
|
{
|
|
cty.TupleVal([]cty.Value{
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("a"),
|
|
cty.StringVal("b"),
|
|
}),
|
|
cty.StringVal("c"),
|
|
cty.TupleVal([]cty.Value{
|
|
cty.StringVal("x"),
|
|
cty.NumberIntVal(1),
|
|
}),
|
|
}),
|
|
cty.TupleVal([]cty.Value{
|
|
cty.StringVal("a"),
|
|
cty.StringVal("b"),
|
|
cty.StringVal("c"),
|
|
cty.StringVal("x"),
|
|
cty.NumberIntVal(1),
|
|
}),
|
|
false,
|
|
},
|
|
// Primitive unknowns should still be flattened to a tuple
|
|
{
|
|
cty.ListVal([]cty.Value{
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("a"),
|
|
cty.StringVal("b"),
|
|
}),
|
|
cty.ListVal([]cty.Value{
|
|
cty.UnknownVal(cty.String),
|
|
cty.StringVal("d"),
|
|
}),
|
|
}),
|
|
cty.TupleVal([]cty.Value{
|
|
cty.StringVal("a"),
|
|
cty.StringVal("b"),
|
|
cty.UnknownVal(cty.String),
|
|
cty.StringVal("d"),
|
|
}), false,
|
|
},
|
|
// An unknown series should return an unknown dynamic value
|
|
{
|
|
cty.TupleVal([]cty.Value{
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("a"),
|
|
cty.StringVal("b"),
|
|
}),
|
|
cty.TupleVal([]cty.Value{
|
|
cty.UnknownVal(cty.List(cty.String)),
|
|
cty.StringVal("d"),
|
|
}),
|
|
}),
|
|
cty.UnknownVal(cty.DynamicPseudoType), false,
|
|
},
|
|
{
|
|
cty.ListValEmpty(cty.String),
|
|
cty.EmptyTupleVal,
|
|
false,
|
|
},
|
|
{
|
|
cty.SetVal([]cty.Value{
|
|
cty.SetVal([]cty.Value{
|
|
cty.StringVal("a"),
|
|
cty.StringVal("b"),
|
|
}),
|
|
cty.SetVal([]cty.Value{
|
|
cty.StringVal("c"),
|
|
cty.StringVal("d"),
|
|
}),
|
|
}),
|
|
cty.TupleVal([]cty.Value{
|
|
cty.StringVal("a"),
|
|
cty.StringVal("b"),
|
|
cty.StringVal("c"),
|
|
cty.StringVal("d"),
|
|
}),
|
|
false,
|
|
},
|
|
{
|
|
cty.TupleVal([]cty.Value{
|
|
cty.SetVal([]cty.Value{
|
|
cty.StringVal("a"),
|
|
cty.StringVal("b"),
|
|
}),
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("c"),
|
|
cty.StringVal("d"),
|
|
}),
|
|
}),
|
|
cty.TupleVal([]cty.Value{
|
|
cty.StringVal("a"),
|
|
cty.StringVal("b"),
|
|
cty.StringVal("c"),
|
|
cty.StringVal("d"),
|
|
}),
|
|
false,
|
|
},
|
|
}
|
|
|
|
for i, test := range tests {
|
|
t.Run(fmt.Sprintf("%d-flatten(%#v)", i, test.List), func(t *testing.T) {
|
|
got, err := Flatten(test.List)
|
|
|
|
if test.Err {
|
|
if err == nil {
|
|
t.Fatal("succeeded; want error")
|
|
}
|
|
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)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestKeys(t *testing.T) {
|
|
tests := []struct {
|
|
Map cty.Value
|
|
Want cty.Value
|
|
Err bool
|
|
}{
|
|
{
|
|
cty.MapVal(map[string]cty.Value{
|
|
"hello": cty.NumberIntVal(1),
|
|
"goodbye": cty.NumberIntVal(42),
|
|
}),
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("goodbye"),
|
|
cty.StringVal("hello"),
|
|
}),
|
|
false,
|
|
},
|
|
{ // same as above, but an object type
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"hello": cty.NumberIntVal(1),
|
|
"goodbye": cty.StringVal("adieu"),
|
|
}),
|
|
cty.TupleVal([]cty.Value{
|
|
cty.StringVal("goodbye"),
|
|
cty.StringVal("hello"),
|
|
}),
|
|
false,
|
|
},
|
|
{ // for an unknown object we can still return the keys, since they are part of the type
|
|
cty.UnknownVal(cty.Object(map[string]cty.Type{
|
|
"hello": cty.Number,
|
|
"goodbye": cty.String,
|
|
})),
|
|
cty.TupleVal([]cty.Value{
|
|
cty.StringVal("goodbye"),
|
|
cty.StringVal("hello"),
|
|
}),
|
|
false,
|
|
},
|
|
{ // an empty object has no keys
|
|
cty.EmptyObjectVal,
|
|
cty.EmptyTupleVal,
|
|
false,
|
|
},
|
|
{ // an empty map has no keys, but the result should still be properly typed
|
|
cty.MapValEmpty(cty.Number),
|
|
cty.ListValEmpty(cty.String),
|
|
false,
|
|
},
|
|
{ // Unknown map has unknown keys
|
|
cty.UnknownVal(cty.Map(cty.String)),
|
|
cty.UnknownVal(cty.List(cty.String)),
|
|
false,
|
|
},
|
|
{ // Not a map at all, so invalid
|
|
cty.StringVal("foo"),
|
|
cty.NilVal,
|
|
true,
|
|
},
|
|
{ // Can't get keys from a null object
|
|
cty.NullVal(cty.Object(map[string]cty.Type{
|
|
"hello": cty.Number,
|
|
"goodbye": cty.String,
|
|
})),
|
|
cty.NilVal,
|
|
true,
|
|
},
|
|
{ // Can't get keys from a null map
|
|
cty.NullVal(cty.Map(cty.Number)),
|
|
cty.NilVal,
|
|
true,
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(fmt.Sprintf("keys(%#v)", test.Map), func(t *testing.T) {
|
|
got, err := Keys(test.Map)
|
|
|
|
if test.Err {
|
|
if err == nil {
|
|
t.Fatal("succeeded; want error")
|
|
}
|
|
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)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestList(t *testing.T) {
|
|
tests := []struct {
|
|
Values []cty.Value
|
|
Want cty.Value
|
|
Err bool
|
|
}{
|
|
{
|
|
[]cty.Value{
|
|
cty.NilVal,
|
|
},
|
|
cty.NilVal,
|
|
true,
|
|
},
|
|
{
|
|
[]cty.Value{
|
|
cty.StringVal("Hello"),
|
|
},
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("Hello"),
|
|
}),
|
|
false,
|
|
},
|
|
{
|
|
[]cty.Value{
|
|
cty.StringVal("Hello"),
|
|
cty.StringVal("World"),
|
|
},
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("Hello"),
|
|
cty.StringVal("World"),
|
|
}),
|
|
false,
|
|
},
|
|
{
|
|
[]cty.Value{
|
|
cty.StringVal("Hello"),
|
|
cty.NumberIntVal(42),
|
|
},
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("Hello"),
|
|
cty.StringVal("42"),
|
|
}),
|
|
false,
|
|
},
|
|
{
|
|
[]cty.Value{
|
|
cty.StringVal("Hello"),
|
|
cty.UnknownVal(cty.String),
|
|
},
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("Hello"),
|
|
cty.UnknownVal(cty.String),
|
|
}),
|
|
false,
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(fmt.Sprintf("list(%#v)", test.Values), func(t *testing.T) {
|
|
got, err := List(test.Values...)
|
|
|
|
if test.Err {
|
|
if err == nil {
|
|
t.Fatal("succeeded; want error")
|
|
}
|
|
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)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestLookup(t *testing.T) {
|
|
simpleMap := cty.MapVal(map[string]cty.Value{
|
|
"foo": cty.StringVal("bar"),
|
|
})
|
|
intsMap := cty.MapVal(map[string]cty.Value{
|
|
"foo": cty.NumberIntVal(42),
|
|
})
|
|
mapOfLists := cty.MapVal(map[string]cty.Value{
|
|
"foo": cty.ListVal([]cty.Value{
|
|
cty.StringVal("bar"),
|
|
cty.StringVal("baz"),
|
|
}),
|
|
})
|
|
mapOfMaps := cty.MapVal(map[string]cty.Value{
|
|
"foo": cty.MapVal(map[string]cty.Value{
|
|
"a": cty.StringVal("bar"),
|
|
}),
|
|
"baz": cty.MapVal(map[string]cty.Value{
|
|
"b": cty.StringVal("bat"),
|
|
}),
|
|
})
|
|
mapOfTuples := cty.MapVal(map[string]cty.Value{
|
|
"foo": cty.TupleVal([]cty.Value{cty.StringVal("bar")}),
|
|
"baz": cty.TupleVal([]cty.Value{cty.StringVal("bat")}),
|
|
})
|
|
objectOfMaps := cty.ObjectVal(map[string]cty.Value{
|
|
"foo": cty.MapVal(map[string]cty.Value{
|
|
"a": cty.StringVal("bar"),
|
|
}),
|
|
"baz": cty.MapVal(map[string]cty.Value{
|
|
"b": cty.StringVal("bat"),
|
|
}),
|
|
})
|
|
mapWithUnknowns := cty.MapVal(map[string]cty.Value{
|
|
"foo": cty.StringVal("bar"),
|
|
"baz": cty.UnknownVal(cty.String),
|
|
})
|
|
mapWithObjects := cty.ObjectVal(map[string]cty.Value{
|
|
"foo": cty.StringVal("bar"),
|
|
"baz": cty.NumberIntVal(42),
|
|
})
|
|
|
|
tests := []struct {
|
|
Values []cty.Value
|
|
Want cty.Value
|
|
Err bool
|
|
}{
|
|
{
|
|
[]cty.Value{
|
|
simpleMap,
|
|
cty.StringVal("foo"),
|
|
},
|
|
cty.StringVal("bar"),
|
|
false,
|
|
},
|
|
{
|
|
[]cty.Value{
|
|
mapWithObjects,
|
|
cty.StringVal("foo"),
|
|
},
|
|
cty.StringVal("bar"),
|
|
false,
|
|
},
|
|
{
|
|
[]cty.Value{
|
|
intsMap,
|
|
cty.StringVal("foo"),
|
|
},
|
|
cty.NumberIntVal(42),
|
|
false,
|
|
},
|
|
{
|
|
[]cty.Value{
|
|
mapOfMaps,
|
|
cty.StringVal("foo"),
|
|
},
|
|
cty.MapVal(map[string]cty.Value{
|
|
"a": cty.StringVal("bar"),
|
|
}),
|
|
false,
|
|
},
|
|
{
|
|
[]cty.Value{
|
|
objectOfMaps,
|
|
cty.StringVal("foo"),
|
|
},
|
|
cty.MapVal(map[string]cty.Value{
|
|
"a": cty.StringVal("bar"),
|
|
}),
|
|
false,
|
|
},
|
|
{
|
|
[]cty.Value{
|
|
mapOfTuples,
|
|
cty.StringVal("foo"),
|
|
},
|
|
cty.TupleVal([]cty.Value{cty.StringVal("bar")}),
|
|
false,
|
|
},
|
|
{ // Invalid key
|
|
[]cty.Value{
|
|
simpleMap,
|
|
cty.StringVal("bar"),
|
|
},
|
|
cty.NilVal,
|
|
true,
|
|
},
|
|
{ // Invalid key
|
|
[]cty.Value{
|
|
mapWithObjects,
|
|
cty.StringVal("bar"),
|
|
},
|
|
cty.NilVal,
|
|
true,
|
|
},
|
|
{ // Supplied default with valid key
|
|
[]cty.Value{
|
|
simpleMap,
|
|
cty.StringVal("foo"),
|
|
cty.StringVal(""),
|
|
},
|
|
cty.StringVal("bar"),
|
|
false,
|
|
},
|
|
{ // Supplied default with valid (int) key
|
|
[]cty.Value{
|
|
simpleMap,
|
|
cty.StringVal("foo"),
|
|
cty.NumberIntVal(-1),
|
|
},
|
|
cty.StringVal("bar"),
|
|
false,
|
|
},
|
|
{ // Supplied default with valid (int) key
|
|
[]cty.Value{
|
|
simpleMap,
|
|
cty.StringVal("foobar"),
|
|
cty.NumberIntVal(-1),
|
|
},
|
|
cty.StringVal("-1"),
|
|
false,
|
|
},
|
|
{ // Supplied default with valid key
|
|
[]cty.Value{
|
|
mapWithObjects,
|
|
cty.StringVal("foobar"),
|
|
cty.StringVal(""),
|
|
},
|
|
cty.StringVal(""),
|
|
false,
|
|
},
|
|
{ // Supplied default with invalid key
|
|
[]cty.Value{
|
|
simpleMap,
|
|
cty.StringVal("baz"),
|
|
cty.StringVal(""),
|
|
},
|
|
cty.StringVal(""),
|
|
false,
|
|
},
|
|
{ // Supplied default with type mismatch: expects a map return
|
|
[]cty.Value{
|
|
mapOfMaps,
|
|
cty.StringVal("foo"),
|
|
cty.StringVal(""),
|
|
},
|
|
cty.NilVal,
|
|
true,
|
|
},
|
|
{ // Supplied non-empty default with invalid key
|
|
[]cty.Value{
|
|
simpleMap,
|
|
cty.StringVal("bar"),
|
|
cty.StringVal("xyz"),
|
|
},
|
|
cty.StringVal("xyz"),
|
|
false,
|
|
},
|
|
{ // too many args
|
|
[]cty.Value{
|
|
simpleMap,
|
|
cty.StringVal("foo"),
|
|
cty.StringVal("bar"),
|
|
cty.StringVal("baz"),
|
|
},
|
|
cty.NilVal,
|
|
true,
|
|
},
|
|
{ // cannot search a map of lists
|
|
[]cty.Value{
|
|
mapOfLists,
|
|
cty.StringVal("baz"),
|
|
},
|
|
cty.NilVal,
|
|
true,
|
|
},
|
|
{
|
|
[]cty.Value{
|
|
mapWithUnknowns,
|
|
cty.StringVal("baz"),
|
|
},
|
|
cty.UnknownVal(cty.String),
|
|
false,
|
|
},
|
|
{
|
|
[]cty.Value{
|
|
simpleMap,
|
|
cty.UnknownVal(cty.String),
|
|
},
|
|
cty.UnknownVal(cty.String),
|
|
false,
|
|
},
|
|
{
|
|
[]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"foo": cty.StringVal("a"),
|
|
"bar": cty.StringVal("b"),
|
|
}),
|
|
cty.UnknownVal(cty.String),
|
|
},
|
|
cty.DynamicVal, // if the key is unknown then we don't know which object attribute and thus can't know the type
|
|
false,
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(fmt.Sprintf("lookup(%#v)", test.Values), func(t *testing.T) {
|
|
got, err := Lookup(test.Values...)
|
|
|
|
if test.Err {
|
|
if err == nil {
|
|
t.Fatal("succeeded; want error")
|
|
}
|
|
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)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestMap(t *testing.T) {
|
|
tests := []struct {
|
|
Values []cty.Value
|
|
Want cty.Value
|
|
Err bool
|
|
}{
|
|
{
|
|
[]cty.Value{
|
|
cty.StringVal("hello"),
|
|
cty.StringVal("world"),
|
|
},
|
|
cty.MapVal(map[string]cty.Value{
|
|
"hello": cty.StringVal("world"),
|
|
}),
|
|
false,
|
|
},
|
|
{
|
|
[]cty.Value{
|
|
cty.StringVal("hello"),
|
|
cty.UnknownVal(cty.String),
|
|
},
|
|
cty.UnknownVal(cty.Map(cty.String)),
|
|
false,
|
|
},
|
|
{
|
|
[]cty.Value{
|
|
cty.StringVal("hello"),
|
|
cty.StringVal("world"),
|
|
cty.StringVal("what's"),
|
|
cty.StringVal("up"),
|
|
},
|
|
cty.MapVal(map[string]cty.Value{
|
|
"hello": cty.StringVal("world"),
|
|
"what's": cty.StringVal("up"),
|
|
}),
|
|
false,
|
|
},
|
|
{
|
|
[]cty.Value{
|
|
cty.StringVal("hello"),
|
|
cty.NumberIntVal(1),
|
|
cty.StringVal("goodbye"),
|
|
cty.NumberIntVal(42),
|
|
},
|
|
cty.MapVal(map[string]cty.Value{
|
|
"hello": cty.NumberIntVal(1),
|
|
"goodbye": cty.NumberIntVal(42),
|
|
}),
|
|
false,
|
|
},
|
|
{ // convert numbers to strings
|
|
[]cty.Value{
|
|
cty.StringVal("hello"),
|
|
cty.NumberIntVal(1),
|
|
cty.StringVal("goodbye"),
|
|
cty.StringVal("42"),
|
|
},
|
|
cty.MapVal(map[string]cty.Value{
|
|
"hello": cty.StringVal("1"),
|
|
"goodbye": cty.StringVal("42"),
|
|
}),
|
|
false,
|
|
},
|
|
{ // map of lists is okay
|
|
[]cty.Value{
|
|
cty.StringVal("hello"),
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("world"),
|
|
}),
|
|
cty.StringVal("what's"),
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("up"),
|
|
}),
|
|
},
|
|
cty.MapVal(map[string]cty.Value{
|
|
"hello": cty.ListVal([]cty.Value{cty.StringVal("world")}),
|
|
"what's": cty.ListVal([]cty.Value{cty.StringVal("up")}),
|
|
}),
|
|
false,
|
|
},
|
|
{ // map of maps is okay
|
|
[]cty.Value{
|
|
cty.StringVal("hello"),
|
|
cty.MapVal(map[string]cty.Value{
|
|
"there": cty.StringVal("world"),
|
|
}),
|
|
cty.StringVal("what's"),
|
|
cty.MapVal(map[string]cty.Value{
|
|
"really": cty.StringVal("up"),
|
|
}),
|
|
},
|
|
cty.MapVal(map[string]cty.Value{
|
|
"hello": cty.MapVal(map[string]cty.Value{
|
|
"there": cty.StringVal("world"),
|
|
}),
|
|
"what's": cty.MapVal(map[string]cty.Value{
|
|
"really": cty.StringVal("up"),
|
|
}),
|
|
}),
|
|
false,
|
|
},
|
|
{ // single argument returns an error
|
|
[]cty.Value{
|
|
cty.StringVal("hello"),
|
|
},
|
|
cty.NilVal,
|
|
true,
|
|
},
|
|
{ // duplicate keys returns an error
|
|
[]cty.Value{
|
|
cty.StringVal("hello"),
|
|
cty.StringVal("world"),
|
|
cty.StringVal("hello"),
|
|
cty.StringVal("universe"),
|
|
},
|
|
cty.NilVal,
|
|
true,
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(fmt.Sprintf("map(%#v)", test.Values), func(t *testing.T) {
|
|
got, err := Map(test.Values...)
|
|
if test.Err {
|
|
if err == nil {
|
|
t.Fatal("succeeded; want error")
|
|
}
|
|
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)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestMatchkeys(t *testing.T) {
|
|
tests := []struct {
|
|
Keys cty.Value
|
|
Values cty.Value
|
|
Searchset cty.Value
|
|
Want cty.Value
|
|
Err bool
|
|
}{
|
|
{ // normal usage
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("a"),
|
|
cty.StringVal("b"),
|
|
cty.StringVal("c"),
|
|
}),
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("ref1"),
|
|
cty.StringVal("ref2"),
|
|
cty.StringVal("ref3"),
|
|
}),
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("ref1"),
|
|
}),
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("a"),
|
|
}),
|
|
false,
|
|
},
|
|
{ // normal usage 2, check the order
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("a"),
|
|
cty.StringVal("b"),
|
|
cty.StringVal("c"),
|
|
}),
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("ref1"),
|
|
cty.StringVal("ref2"),
|
|
cty.StringVal("ref3"),
|
|
}),
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("ref2"),
|
|
cty.StringVal("ref1"),
|
|
}),
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("a"),
|
|
cty.StringVal("b"),
|
|
}),
|
|
false,
|
|
},
|
|
{ // no matches
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("a"),
|
|
cty.StringVal("b"),
|
|
cty.StringVal("c"),
|
|
}),
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("ref1"),
|
|
cty.StringVal("ref2"),
|
|
cty.StringVal("ref3"),
|
|
}),
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("ref4"),
|
|
}),
|
|
cty.ListValEmpty(cty.String),
|
|
false,
|
|
},
|
|
{ // no matches 2
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("a"),
|
|
cty.StringVal("b"),
|
|
cty.StringVal("c"),
|
|
}),
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("ref1"),
|
|
cty.StringVal("ref2"),
|
|
cty.StringVal("ref3"),
|
|
}),
|
|
cty.ListValEmpty(cty.String),
|
|
cty.ListValEmpty(cty.String),
|
|
false,
|
|
},
|
|
{ // zero case
|
|
cty.ListValEmpty(cty.String),
|
|
cty.ListValEmpty(cty.String),
|
|
cty.ListVal([]cty.Value{cty.StringVal("nope")}),
|
|
cty.ListValEmpty(cty.String),
|
|
false,
|
|
},
|
|
{ // complex values
|
|
cty.ListVal([]cty.Value{
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("a"),
|
|
cty.StringVal("a"),
|
|
}),
|
|
}),
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("a"),
|
|
}),
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("a"),
|
|
}),
|
|
cty.ListVal([]cty.Value{
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("a"),
|
|
cty.StringVal("a"),
|
|
}),
|
|
}),
|
|
false,
|
|
},
|
|
{ // unknowns
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("a"),
|
|
cty.StringVal("b"),
|
|
cty.UnknownVal(cty.String),
|
|
}),
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("ref1"),
|
|
cty.StringVal("ref2"),
|
|
cty.UnknownVal(cty.String),
|
|
}),
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("ref1"),
|
|
}),
|
|
cty.UnknownVal(cty.List(cty.String)),
|
|
false,
|
|
},
|
|
{ // different types that can be unified
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("a"),
|
|
}),
|
|
cty.ListVal([]cty.Value{
|
|
cty.NumberIntVal(1),
|
|
}),
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("a"),
|
|
}),
|
|
cty.ListValEmpty(cty.String),
|
|
false,
|
|
},
|
|
{ // complex values: values is a different type from keys and searchset
|
|
cty.ListVal([]cty.Value{
|
|
cty.MapVal(map[string]cty.Value{
|
|
"foo": cty.StringVal("bar"),
|
|
}),
|
|
cty.MapVal(map[string]cty.Value{
|
|
"foo": cty.StringVal("baz"),
|
|
}),
|
|
cty.MapVal(map[string]cty.Value{
|
|
"foo": cty.StringVal("beep"),
|
|
}),
|
|
}),
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("a"),
|
|
cty.StringVal("b"),
|
|
cty.StringVal("c"),
|
|
}),
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("a"),
|
|
cty.StringVal("c"),
|
|
}),
|
|
cty.ListVal([]cty.Value{
|
|
cty.MapVal(map[string]cty.Value{
|
|
"foo": cty.StringVal("bar"),
|
|
}),
|
|
cty.MapVal(map[string]cty.Value{
|
|
"foo": cty.StringVal("beep"),
|
|
}),
|
|
}),
|
|
false,
|
|
},
|
|
// errors
|
|
{ // different types
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("a"),
|
|
}),
|
|
cty.ListVal([]cty.Value{
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("a"),
|
|
}),
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("a"),
|
|
}),
|
|
}),
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("a"),
|
|
}),
|
|
cty.NilVal,
|
|
true,
|
|
},
|
|
{ // lists of different length
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("a"),
|
|
}),
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("a"),
|
|
cty.StringVal("b"),
|
|
}),
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("a"),
|
|
}),
|
|
cty.NilVal,
|
|
true,
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(fmt.Sprintf("matchkeys(%#v, %#v, %#v)", test.Keys, test.Values, test.Searchset), func(t *testing.T) {
|
|
got, err := Matchkeys(test.Keys, test.Values, test.Searchset)
|
|
|
|
if test.Err {
|
|
if err == nil {
|
|
t.Fatal("succeeded; want error")
|
|
}
|
|
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)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestMerge(t *testing.T) {
|
|
tests := []struct {
|
|
Values []cty.Value
|
|
Want cty.Value
|
|
Err bool
|
|
}{
|
|
{
|
|
[]cty.Value{
|
|
cty.MapVal(map[string]cty.Value{
|
|
"a": cty.StringVal("b"),
|
|
}),
|
|
cty.MapVal(map[string]cty.Value{
|
|
"c": cty.StringVal("d"),
|
|
}),
|
|
},
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"a": cty.StringVal("b"),
|
|
"c": cty.StringVal("d"),
|
|
}),
|
|
false,
|
|
},
|
|
{ // handle unknowns
|
|
[]cty.Value{
|
|
cty.MapVal(map[string]cty.Value{
|
|
"a": cty.UnknownVal(cty.String),
|
|
}),
|
|
cty.MapVal(map[string]cty.Value{
|
|
"c": cty.StringVal("d"),
|
|
}),
|
|
},
|
|
cty.DynamicVal,
|
|
false,
|
|
},
|
|
{ // merge with conflicts is ok, last in wins
|
|
[]cty.Value{
|
|
cty.MapVal(map[string]cty.Value{
|
|
"a": cty.StringVal("b"),
|
|
"c": cty.StringVal("d"),
|
|
}),
|
|
cty.MapVal(map[string]cty.Value{
|
|
"a": cty.StringVal("x"),
|
|
}),
|
|
},
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"a": cty.StringVal("x"),
|
|
"c": cty.StringVal("d"),
|
|
}),
|
|
false,
|
|
},
|
|
{ // only accept maps
|
|
[]cty.Value{
|
|
cty.MapVal(map[string]cty.Value{
|
|
"a": cty.StringVal("b"),
|
|
"c": cty.StringVal("d"),
|
|
}),
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("a"),
|
|
cty.StringVal("x"),
|
|
}),
|
|
},
|
|
cty.NilVal,
|
|
true,
|
|
},
|
|
|
|
{ // argument error, for a null type
|
|
[]cty.Value{
|
|
cty.MapVal(map[string]cty.Value{
|
|
"a": cty.StringVal("b"),
|
|
}),
|
|
cty.NullVal(cty.String),
|
|
},
|
|
cty.NilVal,
|
|
true,
|
|
},
|
|
{ // merge maps of maps
|
|
[]cty.Value{
|
|
cty.MapVal(map[string]cty.Value{
|
|
"a": cty.MapVal(map[string]cty.Value{
|
|
"b": cty.StringVal("c"),
|
|
}),
|
|
}),
|
|
cty.MapVal(map[string]cty.Value{
|
|
"d": cty.MapVal(map[string]cty.Value{
|
|
"e": cty.StringVal("f"),
|
|
}),
|
|
}),
|
|
},
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"a": cty.MapVal(map[string]cty.Value{
|
|
"b": cty.StringVal("c"),
|
|
}),
|
|
"d": cty.MapVal(map[string]cty.Value{
|
|
"e": cty.StringVal("f"),
|
|
}),
|
|
}),
|
|
false,
|
|
},
|
|
{ // map of lists
|
|
[]cty.Value{
|
|
cty.MapVal(map[string]cty.Value{
|
|
"a": cty.ListVal([]cty.Value{
|
|
cty.StringVal("b"),
|
|
cty.StringVal("c"),
|
|
}),
|
|
}),
|
|
cty.MapVal(map[string]cty.Value{
|
|
"d": cty.ListVal([]cty.Value{
|
|
cty.StringVal("e"),
|
|
cty.StringVal("f"),
|
|
}),
|
|
}),
|
|
},
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"a": cty.ListVal([]cty.Value{
|
|
cty.StringVal("b"),
|
|
cty.StringVal("c"),
|
|
}),
|
|
"d": cty.ListVal([]cty.Value{
|
|
cty.StringVal("e"),
|
|
cty.StringVal("f"),
|
|
}),
|
|
}),
|
|
false,
|
|
},
|
|
{ // merge map of various kinds
|
|
[]cty.Value{
|
|
cty.MapVal(map[string]cty.Value{
|
|
"a": cty.ListVal([]cty.Value{
|
|
cty.StringVal("b"),
|
|
cty.StringVal("c"),
|
|
}),
|
|
}),
|
|
cty.MapVal(map[string]cty.Value{
|
|
"d": cty.MapVal(map[string]cty.Value{
|
|
"e": cty.StringVal("f"),
|
|
}),
|
|
}),
|
|
},
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"a": cty.ListVal([]cty.Value{
|
|
cty.StringVal("b"),
|
|
cty.StringVal("c"),
|
|
}),
|
|
"d": cty.MapVal(map[string]cty.Value{
|
|
"e": cty.StringVal("f"),
|
|
}),
|
|
}),
|
|
false,
|
|
},
|
|
{ // argument error: non map type
|
|
[]cty.Value{
|
|
cty.MapVal(map[string]cty.Value{
|
|
"a": cty.ListVal([]cty.Value{
|
|
cty.StringVal("b"),
|
|
cty.StringVal("c"),
|
|
}),
|
|
}),
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("d"),
|
|
cty.StringVal("e"),
|
|
}),
|
|
},
|
|
cty.NilVal,
|
|
true,
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(fmt.Sprintf("merge(%#v)", test.Values), func(t *testing.T) {
|
|
got, err := Merge(test.Values...)
|
|
|
|
if test.Err {
|
|
if err == nil {
|
|
t.Fatal("succeeded; want error")
|
|
}
|
|
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)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestReverse(t *testing.T) {
|
|
tests := []struct {
|
|
List cty.Value
|
|
Want cty.Value
|
|
Err string
|
|
}{
|
|
{
|
|
cty.ListValEmpty(cty.String),
|
|
cty.ListValEmpty(cty.String),
|
|
"",
|
|
},
|
|
{
|
|
cty.ListVal([]cty.Value{cty.StringVal("a")}),
|
|
cty.ListVal([]cty.Value{cty.StringVal("a")}),
|
|
"",
|
|
},
|
|
{
|
|
cty.ListVal([]cty.Value{cty.StringVal("a"), cty.StringVal("b")}),
|
|
cty.ListVal([]cty.Value{cty.StringVal("b"), cty.StringVal("a")}),
|
|
"",
|
|
},
|
|
{
|
|
cty.ListVal([]cty.Value{cty.StringVal("a"), cty.StringVal("b"), cty.StringVal("c")}),
|
|
cty.ListVal([]cty.Value{cty.StringVal("c"), cty.StringVal("b"), cty.StringVal("a")}),
|
|
"",
|
|
},
|
|
{
|
|
cty.ListVal([]cty.Value{cty.UnknownVal(cty.String), cty.StringVal("b"), cty.StringVal("c")}),
|
|
cty.ListVal([]cty.Value{cty.StringVal("c"), cty.StringVal("b"), cty.UnknownVal(cty.String)}),
|
|
"",
|
|
},
|
|
{
|
|
cty.EmptyTupleVal,
|
|
cty.EmptyTupleVal,
|
|
"",
|
|
},
|
|
{
|
|
cty.TupleVal([]cty.Value{cty.StringVal("a")}),
|
|
cty.TupleVal([]cty.Value{cty.StringVal("a")}),
|
|
"",
|
|
},
|
|
{
|
|
cty.TupleVal([]cty.Value{cty.StringVal("a"), cty.True}),
|
|
cty.TupleVal([]cty.Value{cty.True, cty.StringVal("a")}),
|
|
"",
|
|
},
|
|
{
|
|
cty.TupleVal([]cty.Value{cty.StringVal("a"), cty.True, cty.Zero}),
|
|
cty.TupleVal([]cty.Value{cty.Zero, cty.True, cty.StringVal("a")}),
|
|
"",
|
|
},
|
|
{
|
|
cty.SetValEmpty(cty.String),
|
|
cty.ListValEmpty(cty.String),
|
|
"",
|
|
},
|
|
{
|
|
cty.SetVal([]cty.Value{cty.StringVal("a")}),
|
|
cty.ListVal([]cty.Value{cty.StringVal("a")}),
|
|
"",
|
|
},
|
|
{
|
|
cty.SetVal([]cty.Value{cty.StringVal("a"), cty.StringVal("b")}),
|
|
cty.ListVal([]cty.Value{cty.StringVal("b"), cty.StringVal("a")}), // set-of-string iterates in lexicographical order
|
|
"",
|
|
},
|
|
{
|
|
cty.SetVal([]cty.Value{cty.StringVal("b"), cty.StringVal("a"), cty.StringVal("c")}),
|
|
cty.ListVal([]cty.Value{cty.StringVal("c"), cty.StringVal("b"), cty.StringVal("a")}), // set-of-string iterates in lexicographical order
|
|
"",
|
|
},
|
|
{
|
|
cty.StringVal("no"),
|
|
cty.NilVal,
|
|
"can only reverse list or tuple values, not string",
|
|
},
|
|
{
|
|
cty.True,
|
|
cty.NilVal,
|
|
"can only reverse list or tuple values, not bool",
|
|
},
|
|
{
|
|
cty.MapValEmpty(cty.String),
|
|
cty.NilVal,
|
|
"can only reverse list or tuple values, not map of string",
|
|
},
|
|
{
|
|
cty.NullVal(cty.List(cty.String)),
|
|
cty.NilVal,
|
|
"argument must not be null",
|
|
},
|
|
{
|
|
cty.UnknownVal(cty.List(cty.String)),
|
|
cty.UnknownVal(cty.List(cty.String)),
|
|
"",
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(fmt.Sprintf("reverse(%#v)", test.List), func(t *testing.T) {
|
|
got, err := Reverse(test.List)
|
|
|
|
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)
|
|
}
|
|
})
|
|
}
|
|
|
|
}
|
|
|
|
func TestSetProduct(t *testing.T) {
|
|
tests := []struct {
|
|
Sets []cty.Value
|
|
Want cty.Value
|
|
Err string
|
|
}{
|
|
{
|
|
nil,
|
|
cty.DynamicVal,
|
|
"at least two arguments are required",
|
|
},
|
|
{
|
|
[]cty.Value{
|
|
cty.SetValEmpty(cty.String),
|
|
},
|
|
cty.DynamicVal,
|
|
"at least two arguments are required",
|
|
},
|
|
{
|
|
[]cty.Value{
|
|
cty.SetValEmpty(cty.String),
|
|
cty.StringVal("hello"),
|
|
},
|
|
cty.DynamicVal,
|
|
"a set or a list is required", // this is an ArgError, so is presented against the second argument in particular
|
|
},
|
|
{
|
|
[]cty.Value{
|
|
cty.SetValEmpty(cty.String),
|
|
cty.SetValEmpty(cty.String),
|
|
},
|
|
cty.SetValEmpty(cty.Tuple([]cty.Type{cty.String, cty.String})),
|
|
"",
|
|
},
|
|
{
|
|
[]cty.Value{
|
|
cty.SetVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("stg"), cty.StringVal("prd")}),
|
|
cty.SetVal([]cty.Value{cty.StringVal("foo"), cty.StringVal("bar")}),
|
|
},
|
|
cty.SetVal([]cty.Value{
|
|
cty.TupleVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("foo")}),
|
|
cty.TupleVal([]cty.Value{cty.StringVal("stg"), cty.StringVal("foo")}),
|
|
cty.TupleVal([]cty.Value{cty.StringVal("prd"), cty.StringVal("foo")}),
|
|
cty.TupleVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("bar")}),
|
|
cty.TupleVal([]cty.Value{cty.StringVal("stg"), cty.StringVal("bar")}),
|
|
cty.TupleVal([]cty.Value{cty.StringVal("prd"), cty.StringVal("bar")}),
|
|
}),
|
|
"",
|
|
},
|
|
{
|
|
[]cty.Value{
|
|
cty.ListVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("stg"), cty.StringVal("prd")}),
|
|
cty.SetVal([]cty.Value{cty.StringVal("foo"), cty.StringVal("bar")}),
|
|
},
|
|
cty.SetVal([]cty.Value{
|
|
cty.TupleVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("foo")}),
|
|
cty.TupleVal([]cty.Value{cty.StringVal("stg"), cty.StringVal("foo")}),
|
|
cty.TupleVal([]cty.Value{cty.StringVal("prd"), cty.StringVal("foo")}),
|
|
cty.TupleVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("bar")}),
|
|
cty.TupleVal([]cty.Value{cty.StringVal("stg"), cty.StringVal("bar")}),
|
|
cty.TupleVal([]cty.Value{cty.StringVal("prd"), cty.StringVal("bar")}),
|
|
}),
|
|
"",
|
|
},
|
|
{
|
|
[]cty.Value{
|
|
cty.TupleVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("stg"), cty.StringVal("prd")}),
|
|
cty.SetVal([]cty.Value{cty.StringVal("foo"), cty.StringVal("bar")}),
|
|
},
|
|
cty.SetVal([]cty.Value{
|
|
cty.TupleVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("foo")}),
|
|
cty.TupleVal([]cty.Value{cty.StringVal("stg"), cty.StringVal("foo")}),
|
|
cty.TupleVal([]cty.Value{cty.StringVal("prd"), cty.StringVal("foo")}),
|
|
cty.TupleVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("bar")}),
|
|
cty.TupleVal([]cty.Value{cty.StringVal("stg"), cty.StringVal("bar")}),
|
|
cty.TupleVal([]cty.Value{cty.StringVal("prd"), cty.StringVal("bar")}),
|
|
}),
|
|
"",
|
|
},
|
|
{
|
|
[]cty.Value{
|
|
cty.ListVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("stg"), cty.StringVal("prd")}),
|
|
cty.ListVal([]cty.Value{cty.StringVal("foo"), cty.StringVal("bar")}),
|
|
},
|
|
cty.ListVal([]cty.Value{
|
|
cty.TupleVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("foo")}),
|
|
cty.TupleVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("bar")}),
|
|
cty.TupleVal([]cty.Value{cty.StringVal("stg"), cty.StringVal("foo")}),
|
|
cty.TupleVal([]cty.Value{cty.StringVal("stg"), cty.StringVal("bar")}),
|
|
cty.TupleVal([]cty.Value{cty.StringVal("prd"), cty.StringVal("foo")}),
|
|
cty.TupleVal([]cty.Value{cty.StringVal("prd"), cty.StringVal("bar")}),
|
|
}),
|
|
"",
|
|
},
|
|
{
|
|
[]cty.Value{
|
|
cty.ListVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("stg"), cty.StringVal("prd")}),
|
|
cty.TupleVal([]cty.Value{cty.StringVal("foo"), cty.StringVal("bar")}),
|
|
},
|
|
cty.ListVal([]cty.Value{
|
|
cty.TupleVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("foo")}),
|
|
cty.TupleVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("bar")}),
|
|
cty.TupleVal([]cty.Value{cty.StringVal("stg"), cty.StringVal("foo")}),
|
|
cty.TupleVal([]cty.Value{cty.StringVal("stg"), cty.StringVal("bar")}),
|
|
cty.TupleVal([]cty.Value{cty.StringVal("prd"), cty.StringVal("foo")}),
|
|
cty.TupleVal([]cty.Value{cty.StringVal("prd"), cty.StringVal("bar")}),
|
|
}),
|
|
"",
|
|
},
|
|
{
|
|
[]cty.Value{
|
|
cty.ListVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("stg"), cty.StringVal("prd")}),
|
|
cty.TupleVal([]cty.Value{cty.StringVal("foo"), cty.True}),
|
|
},
|
|
cty.ListVal([]cty.Value{
|
|
cty.TupleVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("foo")}),
|
|
cty.TupleVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("true")}),
|
|
cty.TupleVal([]cty.Value{cty.StringVal("stg"), cty.StringVal("foo")}),
|
|
cty.TupleVal([]cty.Value{cty.StringVal("stg"), cty.StringVal("true")}),
|
|
cty.TupleVal([]cty.Value{cty.StringVal("prd"), cty.StringVal("foo")}),
|
|
cty.TupleVal([]cty.Value{cty.StringVal("prd"), cty.StringVal("true")}),
|
|
}),
|
|
"",
|
|
},
|
|
{
|
|
[]cty.Value{
|
|
cty.ListVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("stg"), cty.StringVal("prd")}),
|
|
cty.EmptyTupleVal,
|
|
},
|
|
cty.ListValEmpty(cty.Tuple([]cty.Type{cty.String, cty.DynamicPseudoType})),
|
|
"",
|
|
},
|
|
{
|
|
[]cty.Value{
|
|
cty.ListVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("stg"), cty.StringVal("prd")}),
|
|
cty.TupleVal([]cty.Value{cty.StringVal("foo"), cty.EmptyObjectVal}),
|
|
},
|
|
cty.DynamicVal,
|
|
"all elements must be of the same type", // this is an ArgError for the second argument
|
|
},
|
|
{
|
|
[]cty.Value{
|
|
cty.SetVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("stg"), cty.StringVal("prd")}),
|
|
cty.SetVal([]cty.Value{cty.StringVal("foo"), cty.StringVal("bar")}),
|
|
cty.SetVal([]cty.Value{cty.StringVal("baz")}),
|
|
},
|
|
cty.SetVal([]cty.Value{
|
|
cty.TupleVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("foo"), cty.StringVal("baz")}),
|
|
cty.TupleVal([]cty.Value{cty.StringVal("stg"), cty.StringVal("foo"), cty.StringVal("baz")}),
|
|
cty.TupleVal([]cty.Value{cty.StringVal("prd"), cty.StringVal("foo"), cty.StringVal("baz")}),
|
|
cty.TupleVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("bar"), cty.StringVal("baz")}),
|
|
cty.TupleVal([]cty.Value{cty.StringVal("stg"), cty.StringVal("bar"), cty.StringVal("baz")}),
|
|
cty.TupleVal([]cty.Value{cty.StringVal("prd"), cty.StringVal("bar"), cty.StringVal("baz")}),
|
|
}),
|
|
"",
|
|
},
|
|
{
|
|
[]cty.Value{
|
|
cty.SetVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("stg"), cty.StringVal("prd")}),
|
|
cty.SetValEmpty(cty.String),
|
|
},
|
|
cty.SetValEmpty(cty.Tuple([]cty.Type{cty.String, cty.String})),
|
|
"",
|
|
},
|
|
{
|
|
[]cty.Value{
|
|
cty.SetVal([]cty.Value{cty.StringVal("foo")}),
|
|
cty.SetVal([]cty.Value{cty.StringVal("bar")}),
|
|
},
|
|
cty.SetVal([]cty.Value{
|
|
cty.TupleVal([]cty.Value{cty.StringVal("foo"), cty.StringVal("bar")}),
|
|
}),
|
|
"",
|
|
},
|
|
{
|
|
[]cty.Value{
|
|
cty.TupleVal([]cty.Value{cty.StringVal("foo")}),
|
|
cty.TupleVal([]cty.Value{cty.StringVal("bar")}),
|
|
},
|
|
cty.ListVal([]cty.Value{
|
|
cty.TupleVal([]cty.Value{cty.StringVal("foo"), cty.StringVal("bar")}),
|
|
}),
|
|
"",
|
|
},
|
|
{
|
|
[]cty.Value{
|
|
cty.SetVal([]cty.Value{cty.StringVal("foo")}),
|
|
cty.SetVal([]cty.Value{cty.DynamicVal}),
|
|
},
|
|
cty.SetVal([]cty.Value{
|
|
cty.TupleVal([]cty.Value{cty.StringVal("foo"), cty.DynamicVal}),
|
|
}),
|
|
"",
|
|
},
|
|
{
|
|
[]cty.Value{
|
|
cty.SetVal([]cty.Value{cty.StringVal("foo")}),
|
|
cty.SetVal([]cty.Value{cty.True, cty.DynamicVal}),
|
|
},
|
|
cty.SetVal([]cty.Value{
|
|
cty.TupleVal([]cty.Value{cty.StringVal("foo"), cty.True}),
|
|
cty.TupleVal([]cty.Value{cty.StringVal("foo"), cty.UnknownVal(cty.Bool)}),
|
|
}),
|
|
"",
|
|
},
|
|
{
|
|
[]cty.Value{
|
|
cty.UnknownVal(cty.Set(cty.String)),
|
|
cty.SetVal([]cty.Value{cty.True, cty.False}),
|
|
},
|
|
cty.UnknownVal(cty.Set(cty.Tuple([]cty.Type{cty.String, cty.Bool}))),
|
|
"",
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(fmt.Sprintf("setproduct(%#v)", test.Sets), func(t *testing.T) {
|
|
got, err := SetProduct(test.Sets...)
|
|
|
|
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)
|
|
}
|
|
})
|
|
}
|
|
|
|
}
|
|
|
|
func TestSlice(t *testing.T) {
|
|
listOfStrings := cty.ListVal([]cty.Value{
|
|
cty.StringVal("a"),
|
|
cty.StringVal("b"),
|
|
})
|
|
listOfInts := cty.ListVal([]cty.Value{
|
|
cty.NumberIntVal(1),
|
|
cty.NumberIntVal(2),
|
|
})
|
|
listWithUnknowns := cty.ListVal([]cty.Value{
|
|
cty.StringVal("a"),
|
|
cty.UnknownVal(cty.String),
|
|
})
|
|
tuple := cty.TupleVal([]cty.Value{
|
|
cty.StringVal("a"),
|
|
cty.NumberIntVal(1),
|
|
cty.UnknownVal(cty.List(cty.String)),
|
|
})
|
|
tests := []struct {
|
|
List cty.Value
|
|
StartIndex cty.Value
|
|
EndIndex cty.Value
|
|
Want cty.Value
|
|
Err bool
|
|
}{
|
|
{ // normal usage
|
|
listOfStrings,
|
|
cty.NumberIntVal(1),
|
|
cty.NumberIntVal(2),
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("b"),
|
|
}),
|
|
false,
|
|
},
|
|
{ // slice only an unknown value
|
|
listWithUnknowns,
|
|
cty.NumberIntVal(1),
|
|
cty.NumberIntVal(2),
|
|
cty.ListVal([]cty.Value{cty.UnknownVal(cty.String)}),
|
|
false,
|
|
},
|
|
{ // slice multiple values, which contain an unknown
|
|
listWithUnknowns,
|
|
cty.NumberIntVal(0),
|
|
cty.NumberIntVal(2),
|
|
listWithUnknowns,
|
|
false,
|
|
},
|
|
{ // an unknown list should be slicable, returning an unknown list
|
|
cty.UnknownVal(cty.List(cty.String)),
|
|
cty.NumberIntVal(0),
|
|
cty.NumberIntVal(2),
|
|
cty.UnknownVal(cty.List(cty.String)),
|
|
false,
|
|
},
|
|
{ // normal usage
|
|
listOfInts,
|
|
cty.NumberIntVal(1),
|
|
cty.NumberIntVal(2),
|
|
cty.ListVal([]cty.Value{
|
|
cty.NumberIntVal(2),
|
|
}),
|
|
false,
|
|
},
|
|
{ // empty result
|
|
listOfStrings,
|
|
cty.NumberIntVal(1),
|
|
cty.NumberIntVal(1),
|
|
cty.ListValEmpty(cty.String),
|
|
false,
|
|
},
|
|
{ // index out of bounds
|
|
listOfStrings,
|
|
cty.NumberIntVal(1),
|
|
cty.NumberIntVal(4),
|
|
cty.NilVal,
|
|
true,
|
|
},
|
|
{ // StartIndex index > EndIndex
|
|
listOfStrings,
|
|
cty.NumberIntVal(2),
|
|
cty.NumberIntVal(1),
|
|
cty.NilVal,
|
|
true,
|
|
},
|
|
{ // negative StartIndex
|
|
listOfStrings,
|
|
cty.NumberIntVal(-1),
|
|
cty.NumberIntVal(0),
|
|
cty.NilVal,
|
|
true,
|
|
},
|
|
{ // sets are not slice-able
|
|
cty.SetVal([]cty.Value{
|
|
cty.StringVal("x"),
|
|
cty.StringVal("y"),
|
|
}),
|
|
cty.NumberIntVal(0),
|
|
cty.NumberIntVal(0),
|
|
cty.NilVal,
|
|
true,
|
|
},
|
|
{ // tuple slice
|
|
tuple,
|
|
cty.NumberIntVal(1),
|
|
cty.NumberIntVal(3),
|
|
cty.TupleVal([]cty.Value{
|
|
cty.NumberIntVal(1),
|
|
cty.UnknownVal(cty.List(cty.String)),
|
|
}),
|
|
false,
|
|
},
|
|
{ // unknown tuple slice
|
|
cty.UnknownVal(tuple.Type()),
|
|
cty.NumberIntVal(1),
|
|
cty.NumberIntVal(3),
|
|
cty.UnknownVal(cty.Tuple([]cty.Type{
|
|
cty.Number,
|
|
cty.List(cty.String),
|
|
})),
|
|
false,
|
|
},
|
|
{ // empty list slice
|
|
listOfStrings,
|
|
cty.NumberIntVal(2),
|
|
cty.NumberIntVal(2),
|
|
cty.ListValEmpty(cty.String),
|
|
false,
|
|
},
|
|
{ // empty tuple slice
|
|
tuple,
|
|
cty.NumberIntVal(3),
|
|
cty.NumberIntVal(3),
|
|
cty.EmptyTupleVal,
|
|
false,
|
|
},
|
|
{ // list with unknown start offset
|
|
listOfStrings,
|
|
cty.UnknownVal(cty.Number),
|
|
cty.NumberIntVal(2),
|
|
cty.UnknownVal(cty.List(cty.String)),
|
|
false,
|
|
},
|
|
{ // list with unknown start offset but end out of bounds
|
|
listOfStrings,
|
|
cty.UnknownVal(cty.Number),
|
|
cty.NumberIntVal(200),
|
|
cty.UnknownVal(cty.List(cty.String)),
|
|
true,
|
|
},
|
|
{ // list with unknown start offset but end < 0
|
|
listOfStrings,
|
|
cty.UnknownVal(cty.Number),
|
|
cty.NumberIntVal(-4),
|
|
cty.UnknownVal(cty.List(cty.String)),
|
|
true,
|
|
},
|
|
{ // list with unknown end offset
|
|
listOfStrings,
|
|
cty.UnknownVal(cty.Number),
|
|
cty.NumberIntVal(0),
|
|
cty.UnknownVal(cty.List(cty.String)),
|
|
false,
|
|
},
|
|
{ // list with unknown end offset but start out of bounds
|
|
listOfStrings,
|
|
cty.UnknownVal(cty.Number),
|
|
cty.NumberIntVal(200),
|
|
cty.UnknownVal(cty.List(cty.String)),
|
|
true,
|
|
},
|
|
{ // list with unknown end offset but start < 0
|
|
listOfStrings,
|
|
cty.UnknownVal(cty.Number),
|
|
cty.NumberIntVal(-3),
|
|
cty.UnknownVal(cty.List(cty.String)),
|
|
true,
|
|
},
|
|
{ // tuple slice with unknown start offset
|
|
tuple,
|
|
cty.UnknownVal(cty.Number),
|
|
cty.NumberIntVal(3),
|
|
cty.DynamicVal,
|
|
false,
|
|
},
|
|
{ // tuple slice with unknown start offset but end out of bounds
|
|
tuple,
|
|
cty.UnknownVal(cty.Number),
|
|
cty.NumberIntVal(200),
|
|
cty.DynamicVal,
|
|
true,
|
|
},
|
|
{ // tuple slice with unknown start offset but end < 0
|
|
tuple,
|
|
cty.UnknownVal(cty.Number),
|
|
cty.NumberIntVal(-20),
|
|
cty.DynamicVal,
|
|
true,
|
|
},
|
|
{ // tuple slice with unknown end offset
|
|
tuple,
|
|
cty.NumberIntVal(0),
|
|
cty.UnknownVal(cty.Number),
|
|
cty.DynamicVal,
|
|
false,
|
|
},
|
|
{ // tuple slice with unknown end offset but start < 0
|
|
tuple,
|
|
cty.NumberIntVal(-2),
|
|
cty.UnknownVal(cty.Number),
|
|
cty.DynamicVal,
|
|
true,
|
|
},
|
|
{ // tuple slice with unknown end offset but start out of bounds
|
|
tuple,
|
|
cty.NumberIntVal(200),
|
|
cty.UnknownVal(cty.Number),
|
|
cty.DynamicVal,
|
|
true,
|
|
},
|
|
}
|
|
|
|
for i, test := range tests {
|
|
t.Run(fmt.Sprintf("%d-slice(%#v, %#v, %#v)", i, test.List, test.StartIndex, test.EndIndex), func(t *testing.T) {
|
|
got, err := Slice(test.List, test.StartIndex, test.EndIndex)
|
|
|
|
if test.Err {
|
|
if err == nil {
|
|
t.Fatal("succeeded; want error")
|
|
}
|
|
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)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestTranspose(t *testing.T) {
|
|
tests := []struct {
|
|
Values cty.Value
|
|
Want cty.Value
|
|
Err bool
|
|
}{
|
|
{
|
|
cty.MapVal(map[string]cty.Value{
|
|
"key1": cty.ListVal([]cty.Value{
|
|
cty.StringVal("a"),
|
|
cty.StringVal("b"),
|
|
}),
|
|
"key2": cty.ListVal([]cty.Value{
|
|
cty.StringVal("a"),
|
|
cty.StringVal("b"),
|
|
cty.StringVal("c"),
|
|
}),
|
|
"key3": cty.ListVal([]cty.Value{
|
|
cty.StringVal("c"),
|
|
}),
|
|
"key4": cty.ListValEmpty(cty.String),
|
|
}),
|
|
cty.MapVal(map[string]cty.Value{
|
|
"a": cty.ListVal([]cty.Value{
|
|
cty.StringVal("key1"),
|
|
cty.StringVal("key2"),
|
|
}),
|
|
"b": cty.ListVal([]cty.Value{
|
|
cty.StringVal("key1"),
|
|
cty.StringVal("key2"),
|
|
}),
|
|
"c": cty.ListVal([]cty.Value{
|
|
cty.StringVal("key2"),
|
|
cty.StringVal("key3"),
|
|
}),
|
|
}),
|
|
false,
|
|
},
|
|
{ // map - unknown value
|
|
cty.MapVal(map[string]cty.Value{
|
|
"key1": cty.UnknownVal(cty.List(cty.String)),
|
|
}),
|
|
cty.UnknownVal(cty.Map(cty.List(cty.String))),
|
|
false,
|
|
},
|
|
{ // bad map - empty value
|
|
cty.MapVal(map[string]cty.Value{
|
|
"key1": cty.ListValEmpty(cty.String),
|
|
}),
|
|
cty.MapValEmpty(cty.List(cty.String)),
|
|
false,
|
|
},
|
|
{ // bad map - value not a list
|
|
cty.MapVal(map[string]cty.Value{
|
|
"key1": cty.StringVal("a"),
|
|
}),
|
|
cty.NilVal,
|
|
true,
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(fmt.Sprintf("transpose(%#v)", test.Values), func(t *testing.T) {
|
|
got, err := Transpose(test.Values)
|
|
|
|
if test.Err {
|
|
if err == nil {
|
|
t.Fatal("succeeded; want error")
|
|
}
|
|
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)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestValues(t *testing.T) {
|
|
tests := []struct {
|
|
Values cty.Value
|
|
Want cty.Value
|
|
Err bool
|
|
}{
|
|
{
|
|
cty.MapVal(map[string]cty.Value{
|
|
"hello": cty.StringVal("world"),
|
|
"what's": cty.StringVal("up"),
|
|
}),
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("world"),
|
|
cty.StringVal("up"),
|
|
}),
|
|
false,
|
|
},
|
|
{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"what's": cty.StringVal("up"),
|
|
"hello": cty.StringVal("world"),
|
|
}),
|
|
cty.TupleVal([]cty.Value{
|
|
cty.StringVal("world"),
|
|
cty.StringVal("up"),
|
|
}),
|
|
false,
|
|
},
|
|
{ // empty object
|
|
cty.EmptyObjectVal,
|
|
cty.EmptyTupleVal,
|
|
false,
|
|
},
|
|
{
|
|
cty.UnknownVal(cty.Object(map[string]cty.Type{
|
|
"what's": cty.String,
|
|
"hello": cty.Bool,
|
|
})),
|
|
cty.UnknownVal(cty.Tuple([]cty.Type{
|
|
cty.Bool,
|
|
cty.String,
|
|
})),
|
|
false,
|
|
},
|
|
{ // note ordering: keys are sorted first
|
|
cty.MapVal(map[string]cty.Value{
|
|
"hello": cty.NumberIntVal(1),
|
|
"goodbye": cty.NumberIntVal(42),
|
|
}),
|
|
cty.ListVal([]cty.Value{
|
|
cty.NumberIntVal(42),
|
|
cty.NumberIntVal(1),
|
|
}),
|
|
false,
|
|
},
|
|
{ // map of lists
|
|
cty.MapVal(map[string]cty.Value{
|
|
"hello": cty.ListVal([]cty.Value{cty.StringVal("world")}),
|
|
"what's": cty.ListVal([]cty.Value{cty.StringVal("up")}),
|
|
}),
|
|
cty.ListVal([]cty.Value{
|
|
cty.ListVal([]cty.Value{cty.StringVal("world")}),
|
|
cty.ListVal([]cty.Value{cty.StringVal("up")}),
|
|
}),
|
|
false,
|
|
},
|
|
{ // map with unknowns
|
|
cty.MapVal(map[string]cty.Value{
|
|
"hello": cty.ListVal([]cty.Value{cty.StringVal("world")}),
|
|
"what's": cty.UnknownVal(cty.List(cty.String)),
|
|
}),
|
|
cty.ListVal([]cty.Value{
|
|
cty.ListVal([]cty.Value{cty.StringVal("world")}),
|
|
cty.UnknownVal(cty.List(cty.String)),
|
|
}),
|
|
false,
|
|
},
|
|
{ // empty m
|
|
cty.MapValEmpty(cty.DynamicPseudoType),
|
|
cty.ListValEmpty(cty.DynamicPseudoType),
|
|
false,
|
|
},
|
|
{ // unknown m
|
|
cty.UnknownVal(cty.Map(cty.String)),
|
|
cty.UnknownVal(cty.List(cty.String)),
|
|
false,
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(fmt.Sprintf("values(%#v)", test.Values), func(t *testing.T) {
|
|
got, err := Values(test.Values)
|
|
|
|
if test.Err {
|
|
if err == nil {
|
|
t.Fatal("succeeded; want error")
|
|
}
|
|
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)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestZipmap(t *testing.T) {
|
|
list1 := cty.ListVal([]cty.Value{
|
|
cty.StringVal("hello"),
|
|
cty.StringVal("world"),
|
|
})
|
|
list2 := cty.ListVal([]cty.Value{
|
|
cty.StringVal("bar"),
|
|
cty.StringVal("baz"),
|
|
})
|
|
list3 := cty.ListVal([]cty.Value{
|
|
cty.StringVal("hello"),
|
|
cty.StringVal("there"),
|
|
cty.StringVal("world"),
|
|
})
|
|
list4 := cty.ListVal([]cty.Value{
|
|
cty.NumberIntVal(1),
|
|
cty.NumberIntVal(42),
|
|
})
|
|
list5 := cty.ListVal([]cty.Value{
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("bar"),
|
|
}),
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("baz"),
|
|
}),
|
|
})
|
|
tests := []struct {
|
|
Keys cty.Value
|
|
Values cty.Value
|
|
Want cty.Value
|
|
Err bool
|
|
}{
|
|
{
|
|
list1,
|
|
list2,
|
|
cty.MapVal(map[string]cty.Value{
|
|
"hello": cty.StringVal("bar"),
|
|
"world": cty.StringVal("baz"),
|
|
}),
|
|
false,
|
|
},
|
|
{
|
|
list1,
|
|
list4,
|
|
cty.MapVal(map[string]cty.Value{
|
|
"hello": cty.NumberIntVal(1),
|
|
"world": cty.NumberIntVal(42),
|
|
}),
|
|
false,
|
|
},
|
|
{ // length mismatch
|
|
list1,
|
|
list3,
|
|
cty.NilVal,
|
|
true,
|
|
},
|
|
{ // map of lists
|
|
list1,
|
|
list5,
|
|
cty.MapVal(map[string]cty.Value{
|
|
"hello": cty.ListVal([]cty.Value{cty.StringVal("bar")}),
|
|
"world": cty.ListVal([]cty.Value{cty.StringVal("baz")}),
|
|
}),
|
|
false,
|
|
},
|
|
{ // tuple values produce object
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("hello"),
|
|
cty.StringVal("world"),
|
|
}),
|
|
cty.TupleVal([]cty.Value{
|
|
cty.StringVal("bar"),
|
|
cty.UnknownVal(cty.Bool),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"hello": cty.StringVal("bar"),
|
|
"world": cty.UnknownVal(cty.Bool),
|
|
}),
|
|
false,
|
|
},
|
|
{ // empty tuple produces empty object
|
|
cty.ListValEmpty(cty.String),
|
|
cty.EmptyTupleVal,
|
|
cty.EmptyObjectVal,
|
|
false,
|
|
},
|
|
{ // tuple with any unknown keys produces DynamicVal
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("hello"),
|
|
cty.UnknownVal(cty.String),
|
|
}),
|
|
cty.TupleVal([]cty.Value{
|
|
cty.StringVal("bar"),
|
|
cty.True,
|
|
}),
|
|
cty.DynamicVal,
|
|
false,
|
|
},
|
|
{ // tuple with all keys unknown produces DynamicVal
|
|
cty.UnknownVal(cty.List(cty.String)),
|
|
cty.TupleVal([]cty.Value{
|
|
cty.StringVal("bar"),
|
|
cty.True,
|
|
}),
|
|
cty.DynamicVal,
|
|
false,
|
|
},
|
|
{ // list with all keys unknown produces correctly-typed unknown map
|
|
cty.UnknownVal(cty.List(cty.String)),
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("bar"),
|
|
cty.StringVal("baz"),
|
|
}),
|
|
cty.UnknownVal(cty.Map(cty.String)),
|
|
false,
|
|
},
|
|
{ // unknown tuple as values produces correctly-typed unknown object
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("hello"),
|
|
cty.StringVal("world"),
|
|
}),
|
|
cty.UnknownVal(cty.Tuple([]cty.Type{
|
|
cty.String,
|
|
cty.Bool,
|
|
})),
|
|
cty.UnknownVal(cty.Object(map[string]cty.Type{
|
|
"hello": cty.String,
|
|
"world": cty.Bool,
|
|
})),
|
|
false,
|
|
},
|
|
{ // unknown list as values produces correctly-typed unknown map
|
|
cty.ListVal([]cty.Value{
|
|
cty.StringVal("hello"),
|
|
cty.StringVal("world"),
|
|
}),
|
|
cty.UnknownVal(cty.List(cty.String)),
|
|
cty.UnknownVal(cty.Map(cty.String)),
|
|
false,
|
|
},
|
|
{ // empty input returns an empty map
|
|
cty.ListValEmpty(cty.String),
|
|
cty.ListValEmpty(cty.String),
|
|
cty.MapValEmpty(cty.String),
|
|
false,
|
|
},
|
|
{ // keys cannot be a list of lists
|
|
list5,
|
|
list1,
|
|
cty.NilVal,
|
|
true,
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(fmt.Sprintf("zipmap(%#v, %#v)", test.Keys, test.Values), func(t *testing.T) {
|
|
got, err := Zipmap(test.Keys, test.Values)
|
|
|
|
if test.Err {
|
|
if err == nil {
|
|
t.Fatal("succeeded; want error")
|
|
}
|
|
return
|
|
} else if err != nil {
|
|
t.Fatalf("unexpected error: %s", err)
|
|
}
|
|
|
|
if !got.RawEquals(test.Want) {
|
|
t.Errorf("wrong result\n\nkeys: %#v\nvalues: %#v\ngot: %#v\nwant: %#v", test.Keys, test.Values, got, test.Want)
|
|
}
|
|
})
|
|
}
|
|
}
|