github.com/hashicorp/terraform-plugin-sdk@v1.17.2/internal/lang/funcs/collection_test.go (about)

     1  package funcs
     2  
     3  import (
     4  	"fmt"
     5  	"testing"
     6  
     7  	"github.com/zclconf/go-cty/cty"
     8  )
     9  
    10  func TestElement(t *testing.T) {
    11  	tests := []struct {
    12  		List  cty.Value
    13  		Index cty.Value
    14  		Want  cty.Value
    15  	}{
    16  		{
    17  			cty.ListVal([]cty.Value{
    18  				cty.StringVal("hello"),
    19  			}),
    20  			cty.NumberIntVal(0),
    21  			cty.StringVal("hello"),
    22  		},
    23  		{
    24  			cty.ListVal([]cty.Value{
    25  				cty.StringVal("hello"),
    26  			}),
    27  			cty.NumberIntVal(1),
    28  			cty.StringVal("hello"),
    29  		},
    30  		{
    31  			cty.ListVal([]cty.Value{
    32  				cty.StringVal("hello"),
    33  				cty.StringVal("bonjour"),
    34  			}),
    35  			cty.NumberIntVal(0),
    36  			cty.StringVal("hello"),
    37  		},
    38  		{
    39  			cty.ListVal([]cty.Value{
    40  				cty.StringVal("hello"),
    41  				cty.StringVal("bonjour"),
    42  			}),
    43  			cty.NumberIntVal(1),
    44  			cty.StringVal("bonjour"),
    45  		},
    46  		{
    47  			cty.ListVal([]cty.Value{
    48  				cty.StringVal("hello"),
    49  				cty.StringVal("bonjour"),
    50  			}),
    51  			cty.NumberIntVal(2),
    52  			cty.StringVal("hello"),
    53  		},
    54  
    55  		{
    56  			cty.TupleVal([]cty.Value{
    57  				cty.StringVal("hello"),
    58  			}),
    59  			cty.NumberIntVal(0),
    60  			cty.StringVal("hello"),
    61  		},
    62  		{
    63  			cty.TupleVal([]cty.Value{
    64  				cty.StringVal("hello"),
    65  			}),
    66  			cty.NumberIntVal(1),
    67  			cty.StringVal("hello"),
    68  		},
    69  		{
    70  			cty.TupleVal([]cty.Value{
    71  				cty.StringVal("hello"),
    72  				cty.StringVal("bonjour"),
    73  			}),
    74  			cty.NumberIntVal(0),
    75  			cty.StringVal("hello"),
    76  		},
    77  		{
    78  			cty.TupleVal([]cty.Value{
    79  				cty.StringVal("hello"),
    80  				cty.StringVal("bonjour"),
    81  			}),
    82  			cty.NumberIntVal(1),
    83  			cty.StringVal("bonjour"),
    84  		},
    85  		{
    86  			cty.TupleVal([]cty.Value{
    87  				cty.StringVal("hello"),
    88  				cty.StringVal("bonjour"),
    89  			}),
    90  			cty.NumberIntVal(2),
    91  			cty.StringVal("hello"),
    92  		},
    93  		{
    94  			cty.TupleVal([]cty.Value{
    95  				cty.StringVal("hello"),
    96  				cty.StringVal("bonjour"),
    97  			}),
    98  			cty.UnknownVal(cty.Number),
    99  			cty.DynamicVal,
   100  		},
   101  		{
   102  			cty.UnknownVal(cty.Tuple([]cty.Type{cty.String, cty.Bool})),
   103  			cty.NumberIntVal(1),
   104  			cty.UnknownVal(cty.Bool),
   105  		},
   106  		{
   107  			cty.UnknownVal(cty.Tuple([]cty.Type{cty.String, cty.String})),
   108  			cty.UnknownVal(cty.Number),
   109  			cty.DynamicVal,
   110  		},
   111  	}
   112  
   113  	for _, test := range tests {
   114  		t.Run(fmt.Sprintf("Element(%#v, %#v)", test.List, test.Index), func(t *testing.T) {
   115  			got, err := Element(test.List, test.Index)
   116  
   117  			if err != nil {
   118  				t.Fatalf("unexpected error: %s", err)
   119  			}
   120  
   121  			if !got.RawEquals(test.Want) {
   122  				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
   123  			}
   124  		})
   125  	}
   126  
   127  }
   128  
   129  func TestLength(t *testing.T) {
   130  	tests := []struct {
   131  		Value cty.Value
   132  		Want  cty.Value
   133  	}{
   134  		{
   135  			cty.ListValEmpty(cty.Number),
   136  			cty.NumberIntVal(0),
   137  		},
   138  		{
   139  			cty.ListVal([]cty.Value{cty.True}),
   140  			cty.NumberIntVal(1),
   141  		},
   142  		{
   143  			cty.ListVal([]cty.Value{cty.UnknownVal(cty.Bool)}),
   144  			cty.NumberIntVal(1),
   145  		},
   146  		{
   147  			cty.SetValEmpty(cty.Number),
   148  			cty.NumberIntVal(0),
   149  		},
   150  		{
   151  			cty.SetVal([]cty.Value{cty.True}),
   152  			cty.NumberIntVal(1),
   153  		},
   154  		{
   155  			cty.MapValEmpty(cty.Bool),
   156  			cty.NumberIntVal(0),
   157  		},
   158  		{
   159  			cty.MapVal(map[string]cty.Value{"hello": cty.True}),
   160  			cty.NumberIntVal(1),
   161  		},
   162  		{
   163  			cty.EmptyTupleVal,
   164  			cty.NumberIntVal(0),
   165  		},
   166  		{
   167  			cty.UnknownVal(cty.EmptyTuple),
   168  			cty.NumberIntVal(0),
   169  		},
   170  		{
   171  			cty.TupleVal([]cty.Value{cty.True}),
   172  			cty.NumberIntVal(1),
   173  		},
   174  		{
   175  			cty.EmptyObjectVal,
   176  			cty.NumberIntVal(0),
   177  		},
   178  		{
   179  			cty.UnknownVal(cty.EmptyObject),
   180  			cty.NumberIntVal(0),
   181  		},
   182  		{
   183  			cty.ObjectVal(map[string]cty.Value{"true": cty.True}),
   184  			cty.NumberIntVal(1),
   185  		},
   186  		{
   187  			cty.UnknownVal(cty.List(cty.Bool)),
   188  			cty.UnknownVal(cty.Number),
   189  		},
   190  		{
   191  			cty.DynamicVal,
   192  			cty.UnknownVal(cty.Number),
   193  		},
   194  		{
   195  			cty.StringVal("hello"),
   196  			cty.NumberIntVal(5),
   197  		},
   198  		{
   199  			cty.StringVal(""),
   200  			cty.NumberIntVal(0),
   201  		},
   202  		{
   203  			cty.StringVal("1"),
   204  			cty.NumberIntVal(1),
   205  		},
   206  		{
   207  			cty.StringVal("Живой Журнал"),
   208  			cty.NumberIntVal(12),
   209  		},
   210  		{
   211  			// note that the dieresis here is intentionally a combining
   212  			// ligature.
   213  			cty.StringVal("noël"),
   214  			cty.NumberIntVal(4),
   215  		},
   216  		{
   217  			// The Es in this string has three combining acute accents.
   218  			// This tests something that NFC-normalization cannot collapse
   219  			// into a single precombined codepoint, since otherwise we might
   220  			// be cheating and relying on the single-codepoint forms.
   221  			cty.StringVal("wé́́é́́é́́!"),
   222  			cty.NumberIntVal(5),
   223  		},
   224  		{
   225  			// Go's normalization forms don't handle this ligature, so we
   226  			// will produce the wrong result but this is now a compatibility
   227  			// constraint and so we'll test it.
   228  			cty.StringVal("baffle"),
   229  			cty.NumberIntVal(4),
   230  		},
   231  		{
   232  			cty.StringVal("😸😾"),
   233  			cty.NumberIntVal(2),
   234  		},
   235  		{
   236  			cty.UnknownVal(cty.String),
   237  			cty.UnknownVal(cty.Number),
   238  		},
   239  		{
   240  			cty.DynamicVal,
   241  			cty.UnknownVal(cty.Number),
   242  		},
   243  	}
   244  
   245  	for _, test := range tests {
   246  		t.Run(fmt.Sprintf("Length(%#v)", test.Value), func(t *testing.T) {
   247  			got, err := Length(test.Value)
   248  
   249  			if err != nil {
   250  				t.Fatalf("unexpected error: %s", err)
   251  			}
   252  
   253  			if !got.RawEquals(test.Want) {
   254  				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
   255  			}
   256  		})
   257  	}
   258  }
   259  
   260  func TestCoalesce(t *testing.T) {
   261  	tests := []struct {
   262  		Values []cty.Value
   263  		Want   cty.Value
   264  		Err    bool
   265  	}{
   266  		{
   267  			[]cty.Value{cty.StringVal("first"), cty.StringVal("second"), cty.StringVal("third")},
   268  			cty.StringVal("first"),
   269  			false,
   270  		},
   271  		{
   272  			[]cty.Value{cty.StringVal(""), cty.StringVal("second"), cty.StringVal("third")},
   273  			cty.StringVal("second"),
   274  			false,
   275  		},
   276  		{
   277  			[]cty.Value{cty.StringVal(""), cty.StringVal("")},
   278  			cty.NilVal,
   279  			true,
   280  		},
   281  		{
   282  			[]cty.Value{cty.True},
   283  			cty.True,
   284  			false,
   285  		},
   286  		{
   287  			[]cty.Value{cty.NullVal(cty.Bool), cty.True},
   288  			cty.True,
   289  			false,
   290  		},
   291  		{
   292  			[]cty.Value{cty.NullVal(cty.Bool), cty.False},
   293  			cty.False,
   294  			false,
   295  		},
   296  		{
   297  			[]cty.Value{cty.NullVal(cty.Bool), cty.False, cty.StringVal("hello")},
   298  			cty.StringVal("false"),
   299  			false,
   300  		},
   301  		{
   302  			[]cty.Value{cty.True, cty.UnknownVal(cty.Bool)},
   303  			cty.True,
   304  			false,
   305  		},
   306  		{
   307  			[]cty.Value{cty.UnknownVal(cty.Bool), cty.True},
   308  			cty.UnknownVal(cty.Bool),
   309  			false,
   310  		},
   311  		{
   312  			[]cty.Value{cty.UnknownVal(cty.Bool), cty.StringVal("hello")},
   313  			cty.UnknownVal(cty.String),
   314  			false,
   315  		},
   316  		{
   317  			[]cty.Value{cty.DynamicVal, cty.True},
   318  			cty.UnknownVal(cty.Bool),
   319  			false,
   320  		},
   321  		{
   322  			[]cty.Value{cty.DynamicVal},
   323  			cty.DynamicVal,
   324  			false,
   325  		},
   326  	}
   327  
   328  	for _, test := range tests {
   329  		t.Run(fmt.Sprintf("Coalesce(%#v...)", test.Values), func(t *testing.T) {
   330  			got, err := Coalesce(test.Values...)
   331  
   332  			if test.Err {
   333  				if err == nil {
   334  					t.Fatal("succeeded; want error")
   335  				}
   336  				return
   337  			} else if err != nil {
   338  				t.Fatalf("unexpected error: %s", err)
   339  			}
   340  
   341  			if !got.RawEquals(test.Want) {
   342  				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
   343  			}
   344  		})
   345  	}
   346  }
   347  
   348  func TestCoalesceList(t *testing.T) {
   349  	tests := []struct {
   350  		Values []cty.Value
   351  		Want   cty.Value
   352  		Err    bool
   353  	}{
   354  		{
   355  			[]cty.Value{
   356  				cty.ListVal([]cty.Value{
   357  					cty.StringVal("first"), cty.StringVal("second"),
   358  				}),
   359  				cty.ListVal([]cty.Value{
   360  					cty.StringVal("third"), cty.StringVal("fourth"),
   361  				}),
   362  			},
   363  			cty.ListVal([]cty.Value{
   364  				cty.StringVal("first"), cty.StringVal("second"),
   365  			}),
   366  			false,
   367  		},
   368  		{
   369  			[]cty.Value{
   370  				cty.ListValEmpty(cty.String),
   371  				cty.ListVal([]cty.Value{
   372  					cty.StringVal("third"), cty.StringVal("fourth"),
   373  				}),
   374  			},
   375  			cty.ListVal([]cty.Value{
   376  				cty.StringVal("third"), cty.StringVal("fourth"),
   377  			}),
   378  			false,
   379  		},
   380  		{
   381  			[]cty.Value{
   382  				cty.ListValEmpty(cty.Number),
   383  				cty.ListVal([]cty.Value{
   384  					cty.NumberIntVal(1),
   385  					cty.NumberIntVal(2),
   386  				}),
   387  			},
   388  			cty.ListVal([]cty.Value{
   389  				cty.NumberIntVal(1),
   390  				cty.NumberIntVal(2),
   391  			}),
   392  			false,
   393  		},
   394  		{ // lists with mixed types
   395  			[]cty.Value{
   396  				cty.ListVal([]cty.Value{
   397  					cty.StringVal("first"), cty.StringVal("second"),
   398  				}),
   399  				cty.ListVal([]cty.Value{
   400  					cty.NumberIntVal(1),
   401  					cty.NumberIntVal(2),
   402  				}),
   403  			},
   404  			cty.ListVal([]cty.Value{
   405  				cty.StringVal("first"), cty.StringVal("second"),
   406  			}),
   407  			false,
   408  		},
   409  		{ // lists with mixed types
   410  			[]cty.Value{
   411  				cty.ListVal([]cty.Value{
   412  					cty.NumberIntVal(1),
   413  					cty.NumberIntVal(2),
   414  				}),
   415  				cty.ListVal([]cty.Value{
   416  					cty.StringVal("first"), cty.StringVal("second"),
   417  				}),
   418  			},
   419  			cty.ListVal([]cty.Value{
   420  				cty.NumberIntVal(1), cty.NumberIntVal(2),
   421  			}),
   422  			false,
   423  		},
   424  		{ // list with unknown values
   425  			[]cty.Value{
   426  				cty.ListVal([]cty.Value{
   427  					cty.StringVal("first"), cty.StringVal("second"),
   428  				}),
   429  				cty.ListVal([]cty.Value{
   430  					cty.UnknownVal(cty.String),
   431  				}),
   432  			},
   433  			cty.ListVal([]cty.Value{
   434  				cty.StringVal("first"), cty.StringVal("second"),
   435  			}),
   436  			false,
   437  		},
   438  		{ // list with unknown values
   439  			[]cty.Value{
   440  				cty.ListVal([]cty.Value{
   441  					cty.UnknownVal(cty.String),
   442  				}),
   443  				cty.ListVal([]cty.Value{
   444  					cty.StringVal("third"), cty.StringVal("fourth"),
   445  				}),
   446  			},
   447  			cty.ListVal([]cty.Value{
   448  				cty.UnknownVal(cty.String),
   449  			}),
   450  			false,
   451  		},
   452  		{
   453  			[]cty.Value{
   454  				cty.MapValEmpty(cty.DynamicPseudoType),
   455  				cty.ListVal([]cty.Value{
   456  					cty.StringVal("third"), cty.StringVal("fourth"),
   457  				}),
   458  			},
   459  			cty.NilVal,
   460  			true,
   461  		},
   462  		{ // unknown list
   463  			[]cty.Value{
   464  				cty.ListVal([]cty.Value{
   465  					cty.StringVal("third"), cty.StringVal("fourth"),
   466  				}),
   467  				cty.UnknownVal(cty.List(cty.String)),
   468  			},
   469  			cty.ListVal([]cty.Value{
   470  				cty.StringVal("third"), cty.StringVal("fourth"),
   471  			}),
   472  			false,
   473  		},
   474  		{ // unknown list
   475  			[]cty.Value{
   476  				cty.ListValEmpty(cty.String),
   477  				cty.UnknownVal(cty.List(cty.String)),
   478  			},
   479  			cty.DynamicVal,
   480  			false,
   481  		},
   482  		{ // unknown list
   483  			[]cty.Value{
   484  				cty.UnknownVal(cty.List(cty.String)),
   485  				cty.ListVal([]cty.Value{
   486  					cty.StringVal("third"), cty.StringVal("fourth"),
   487  				}),
   488  			},
   489  			cty.DynamicVal,
   490  			false,
   491  		},
   492  		{ // unknown tuple
   493  			[]cty.Value{
   494  				cty.UnknownVal(cty.Tuple([]cty.Type{cty.String})),
   495  				cty.ListVal([]cty.Value{
   496  					cty.StringVal("third"), cty.StringVal("fourth"),
   497  				}),
   498  			},
   499  			cty.DynamicVal,
   500  			false,
   501  		},
   502  		{ // empty tuple
   503  			[]cty.Value{
   504  				cty.EmptyTupleVal,
   505  				cty.ListVal([]cty.Value{
   506  					cty.StringVal("third"), cty.StringVal("fourth"),
   507  				}),
   508  			},
   509  			cty.ListVal([]cty.Value{
   510  				cty.StringVal("third"), cty.StringVal("fourth"),
   511  			}),
   512  			false,
   513  		},
   514  		{ // tuple value
   515  			[]cty.Value{
   516  				cty.TupleVal([]cty.Value{
   517  					cty.StringVal("a"),
   518  					cty.NumberIntVal(2),
   519  				}),
   520  				cty.ListVal([]cty.Value{
   521  					cty.StringVal("third"), cty.StringVal("fourth"),
   522  				}),
   523  			},
   524  			cty.TupleVal([]cty.Value{
   525  				cty.StringVal("a"),
   526  				cty.NumberIntVal(2),
   527  			}),
   528  			false,
   529  		},
   530  		{ // reject set value
   531  			[]cty.Value{
   532  				cty.SetVal([]cty.Value{
   533  					cty.StringVal("a"),
   534  				}),
   535  				cty.ListVal([]cty.Value{
   536  					cty.StringVal("third"), cty.StringVal("fourth"),
   537  				}),
   538  			},
   539  			cty.NilVal,
   540  			true,
   541  		},
   542  	}
   543  
   544  	for i, test := range tests {
   545  		t.Run(fmt.Sprintf("%d-coalescelist(%#v)", i, test.Values), func(t *testing.T) {
   546  			got, err := CoalesceList(test.Values...)
   547  
   548  			if test.Err {
   549  				if err == nil {
   550  					t.Fatal("succeeded; want error")
   551  				}
   552  				return
   553  			} else if err != nil {
   554  				t.Fatalf("unexpected error: %s", err)
   555  			}
   556  
   557  			if !got.RawEquals(test.Want) {
   558  				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
   559  			}
   560  		})
   561  	}
   562  }
   563  
   564  func TestCompact(t *testing.T) {
   565  	tests := []struct {
   566  		List cty.Value
   567  		Want cty.Value
   568  		Err  bool
   569  	}{
   570  		{
   571  			cty.ListVal([]cty.Value{
   572  				cty.StringVal("test"),
   573  				cty.StringVal(""),
   574  				cty.StringVal("test"),
   575  				cty.NullVal(cty.String),
   576  			}),
   577  			cty.ListVal([]cty.Value{
   578  				cty.StringVal("test"),
   579  				cty.StringVal("test"),
   580  			}),
   581  			false,
   582  		},
   583  		{
   584  			cty.ListVal([]cty.Value{
   585  				cty.StringVal(""),
   586  				cty.StringVal(""),
   587  				cty.StringVal(""),
   588  			}),
   589  			cty.ListValEmpty(cty.String),
   590  			false,
   591  		},
   592  		{
   593  			cty.ListVal([]cty.Value{
   594  				cty.NullVal(cty.String),
   595  				cty.NullVal(cty.String),
   596  			}),
   597  			cty.ListValEmpty(cty.String),
   598  			false,
   599  		},
   600  		{
   601  			cty.ListValEmpty(cty.String),
   602  			cty.ListValEmpty(cty.String),
   603  			false,
   604  		},
   605  		{
   606  			cty.ListVal([]cty.Value{
   607  				cty.StringVal("test"),
   608  				cty.StringVal("test"),
   609  				cty.StringVal(""),
   610  			}),
   611  			cty.ListVal([]cty.Value{
   612  				cty.StringVal("test"),
   613  				cty.StringVal("test"),
   614  			}),
   615  			false,
   616  		},
   617  		{
   618  			cty.ListVal([]cty.Value{
   619  				cty.StringVal("test"),
   620  				cty.UnknownVal(cty.String),
   621  				cty.StringVal(""),
   622  				cty.NullVal(cty.String),
   623  			}),
   624  			cty.UnknownVal(cty.List(cty.String)),
   625  			false,
   626  		},
   627  		{ // errors on list of lists
   628  			cty.ListVal([]cty.Value{
   629  				cty.ListVal([]cty.Value{
   630  					cty.StringVal("test"),
   631  				}),
   632  				cty.ListVal([]cty.Value{
   633  					cty.StringVal(""),
   634  				}),
   635  			}),
   636  			cty.NilVal,
   637  			true,
   638  		},
   639  	}
   640  
   641  	for _, test := range tests {
   642  		t.Run(fmt.Sprintf("compact(%#v)", test.List), func(t *testing.T) {
   643  			got, err := Compact(test.List)
   644  
   645  			if test.Err {
   646  				if err == nil {
   647  					t.Fatal("succeeded; want error")
   648  				}
   649  				return
   650  			} else if err != nil {
   651  				t.Fatalf("unexpected error: %s", err)
   652  			}
   653  
   654  			if !got.RawEquals(test.Want) {
   655  				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
   656  			}
   657  		})
   658  	}
   659  }
   660  
   661  func TestContains(t *testing.T) {
   662  	listOfStrings := cty.ListVal([]cty.Value{
   663  		cty.StringVal("the"),
   664  		cty.StringVal("quick"),
   665  		cty.StringVal("brown"),
   666  		cty.StringVal("fox"),
   667  	})
   668  	listOfInts := cty.ListVal([]cty.Value{
   669  		cty.NumberIntVal(1),
   670  		cty.NumberIntVal(2),
   671  		cty.NumberIntVal(3),
   672  		cty.NumberIntVal(4),
   673  	})
   674  	listWithUnknown := cty.ListVal([]cty.Value{
   675  		cty.StringVal("the"),
   676  		cty.StringVal("quick"),
   677  		cty.StringVal("brown"),
   678  		cty.UnknownVal(cty.String),
   679  	})
   680  
   681  	tests := []struct {
   682  		List  cty.Value
   683  		Value cty.Value
   684  		Want  cty.Value
   685  		Err   bool
   686  	}{
   687  		{
   688  			listOfStrings,
   689  			cty.StringVal("the"),
   690  			cty.BoolVal(true),
   691  			false,
   692  		},
   693  		{
   694  			listWithUnknown,
   695  			cty.StringVal("the"),
   696  			cty.BoolVal(true),
   697  			false,
   698  		},
   699  		{
   700  			listOfStrings,
   701  			cty.StringVal("penguin"),
   702  			cty.BoolVal(false),
   703  			false,
   704  		},
   705  		{
   706  			listOfInts,
   707  			cty.NumberIntVal(1),
   708  			cty.BoolVal(true),
   709  			false,
   710  		},
   711  		{
   712  			listOfInts,
   713  			cty.NumberIntVal(42),
   714  			cty.BoolVal(false),
   715  			false,
   716  		},
   717  		{ // And now we mix and match
   718  			listOfInts,
   719  			cty.StringVal("1"),
   720  			cty.BoolVal(false),
   721  			false,
   722  		},
   723  		{ // Check a list with an unknown value
   724  			cty.ListVal([]cty.Value{
   725  				cty.UnknownVal(cty.String),
   726  				cty.StringVal("quick"),
   727  				cty.StringVal("brown"),
   728  				cty.StringVal("fox"),
   729  			}),
   730  			cty.StringVal("quick"),
   731  			cty.BoolVal(true),
   732  			false,
   733  		},
   734  		{ // set val
   735  			cty.SetVal([]cty.Value{
   736  				cty.StringVal("quick"),
   737  				cty.StringVal("brown"),
   738  				cty.StringVal("fox"),
   739  			}),
   740  			cty.StringVal("quick"),
   741  			cty.BoolVal(true),
   742  			false,
   743  		},
   744  		{ // tuple val
   745  			cty.TupleVal([]cty.Value{
   746  				cty.StringVal("quick"),
   747  				cty.StringVal("brown"),
   748  				cty.NumberIntVal(3),
   749  			}),
   750  			cty.NumberIntVal(3),
   751  			cty.BoolVal(true),
   752  			false,
   753  		},
   754  	}
   755  
   756  	for _, test := range tests {
   757  		t.Run(fmt.Sprintf("contains(%#v, %#v)", test.List, test.Value), func(t *testing.T) {
   758  			got, err := Contains(test.List, test.Value)
   759  
   760  			if test.Err {
   761  				if err == nil {
   762  					t.Fatal("succeeded; want error")
   763  				}
   764  				return
   765  			} else if err != nil {
   766  				t.Fatalf("unexpected error: %s", err)
   767  			}
   768  
   769  			if !got.RawEquals(test.Want) {
   770  				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
   771  			}
   772  		})
   773  	}
   774  }
   775  
   776  func TestIndex(t *testing.T) {
   777  	tests := []struct {
   778  		List  cty.Value
   779  		Value cty.Value
   780  		Want  cty.Value
   781  		Err   bool
   782  	}{
   783  		{
   784  			cty.ListVal([]cty.Value{
   785  				cty.StringVal("a"),
   786  				cty.StringVal("b"),
   787  				cty.StringVal("c"),
   788  			}),
   789  			cty.StringVal("a"),
   790  			cty.NumberIntVal(0),
   791  			false,
   792  		},
   793  		{
   794  			cty.ListVal([]cty.Value{
   795  				cty.StringVal("a"),
   796  				cty.StringVal("b"),
   797  				cty.UnknownVal(cty.String),
   798  			}),
   799  			cty.StringVal("a"),
   800  			cty.NumberIntVal(0),
   801  			false,
   802  		},
   803  		{
   804  			cty.ListVal([]cty.Value{
   805  				cty.StringVal("a"),
   806  				cty.StringVal("b"),
   807  				cty.StringVal("c"),
   808  			}),
   809  			cty.StringVal("b"),
   810  			cty.NumberIntVal(1),
   811  			false,
   812  		},
   813  		{
   814  			cty.ListVal([]cty.Value{
   815  				cty.StringVal("a"),
   816  				cty.StringVal("b"),
   817  				cty.StringVal("c"),
   818  			}),
   819  			cty.StringVal("z"),
   820  			cty.NilVal,
   821  			true,
   822  		},
   823  		{
   824  			cty.ListVal([]cty.Value{
   825  				cty.StringVal("1"),
   826  				cty.StringVal("2"),
   827  				cty.StringVal("3"),
   828  			}),
   829  			cty.NumberIntVal(1),
   830  			cty.NumberIntVal(0),
   831  			true,
   832  		},
   833  		{
   834  			cty.ListVal([]cty.Value{
   835  				cty.NumberIntVal(1),
   836  				cty.NumberIntVal(2),
   837  				cty.NumberIntVal(3),
   838  			}),
   839  			cty.NumberIntVal(2),
   840  			cty.NumberIntVal(1),
   841  			false,
   842  		},
   843  		{
   844  			cty.ListVal([]cty.Value{
   845  				cty.NumberIntVal(1),
   846  				cty.NumberIntVal(2),
   847  				cty.NumberIntVal(3),
   848  			}),
   849  			cty.NumberIntVal(4),
   850  			cty.NilVal,
   851  			true,
   852  		},
   853  		{
   854  			cty.ListVal([]cty.Value{
   855  				cty.NumberIntVal(1),
   856  				cty.NumberIntVal(2),
   857  				cty.NumberIntVal(3),
   858  			}),
   859  			cty.StringVal("1"),
   860  			cty.NumberIntVal(0),
   861  			true,
   862  		},
   863  		{
   864  			cty.TupleVal([]cty.Value{
   865  				cty.NumberIntVal(1),
   866  				cty.NumberIntVal(2),
   867  				cty.NumberIntVal(3),
   868  			}),
   869  			cty.NumberIntVal(1),
   870  			cty.NumberIntVal(0),
   871  			false,
   872  		},
   873  	}
   874  
   875  	for _, test := range tests {
   876  		t.Run(fmt.Sprintf("index(%#v, %#v)", test.List, test.Value), func(t *testing.T) {
   877  			got, err := Index(test.List, test.Value)
   878  
   879  			if test.Err {
   880  				if err == nil {
   881  					t.Fatal("succeeded; want error")
   882  				}
   883  				return
   884  			} else if err != nil {
   885  				t.Fatalf("unexpected error: %s", err)
   886  			}
   887  
   888  			if !got.RawEquals(test.Want) {
   889  				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
   890  			}
   891  		})
   892  	}
   893  }
   894  
   895  func TestDistinct(t *testing.T) {
   896  	tests := []struct {
   897  		List cty.Value
   898  		Want cty.Value
   899  		Err  bool
   900  	}{
   901  		{
   902  			cty.ListVal([]cty.Value{
   903  				cty.StringVal("a"),
   904  				cty.StringVal("b"),
   905  				cty.StringVal("a"),
   906  				cty.StringVal("b"),
   907  			}),
   908  			cty.ListVal([]cty.Value{
   909  				cty.StringVal("a"),
   910  				cty.StringVal("b"),
   911  			}),
   912  			false,
   913  		},
   914  		{
   915  			cty.ListValEmpty(cty.String),
   916  			cty.ListValEmpty(cty.String),
   917  			false,
   918  		},
   919  		{
   920  			cty.ListVal([]cty.Value{
   921  				cty.StringVal("a"),
   922  				cty.StringVal("b"),
   923  				cty.StringVal("a"),
   924  				cty.UnknownVal(cty.String),
   925  			}),
   926  			cty.UnknownVal(cty.List(cty.String)),
   927  			false,
   928  		},
   929  		{
   930  			cty.ListVal([]cty.Value{
   931  				cty.StringVal("a"),
   932  				cty.StringVal("b"),
   933  				cty.StringVal("c"),
   934  				cty.StringVal("d"),
   935  			}),
   936  			cty.ListVal([]cty.Value{
   937  				cty.StringVal("a"),
   938  				cty.StringVal("b"),
   939  				cty.StringVal("c"),
   940  				cty.StringVal("d"),
   941  			}),
   942  			false,
   943  		},
   944  		{
   945  			cty.ListVal([]cty.Value{
   946  				cty.NumberIntVal(1),
   947  				cty.NumberIntVal(2),
   948  				cty.NumberIntVal(1),
   949  				cty.NumberIntVal(2),
   950  			}),
   951  			cty.ListVal([]cty.Value{
   952  				cty.NumberIntVal(1),
   953  				cty.NumberIntVal(2),
   954  			}),
   955  			false,
   956  		},
   957  		{
   958  			cty.ListVal([]cty.Value{
   959  				cty.ListVal([]cty.Value{
   960  					cty.NumberIntVal(1),
   961  					cty.NumberIntVal(2),
   962  				}),
   963  				cty.ListVal([]cty.Value{
   964  					cty.NumberIntVal(1),
   965  					cty.NumberIntVal(2),
   966  				}),
   967  			}),
   968  			cty.ListVal([]cty.Value{
   969  				cty.ListVal([]cty.Value{
   970  					cty.NumberIntVal(1),
   971  					cty.NumberIntVal(2),
   972  				}),
   973  			}),
   974  			false,
   975  		},
   976  		{
   977  			cty.ListVal([]cty.Value{
   978  				cty.ListVal([]cty.Value{
   979  					cty.NumberIntVal(1),
   980  					cty.NumberIntVal(2),
   981  				}),
   982  				cty.ListVal([]cty.Value{
   983  					cty.NumberIntVal(3),
   984  					cty.NumberIntVal(4),
   985  				}),
   986  			}),
   987  			cty.ListVal([]cty.Value{
   988  				cty.ListVal([]cty.Value{
   989  					cty.NumberIntVal(1),
   990  					cty.NumberIntVal(2),
   991  				}),
   992  				cty.ListVal([]cty.Value{
   993  					cty.NumberIntVal(3),
   994  					cty.NumberIntVal(4),
   995  				}),
   996  			}),
   997  			false,
   998  		},
   999  	}
  1000  
  1001  	for _, test := range tests {
  1002  		t.Run(fmt.Sprintf("distinct(%#v)", test.List), func(t *testing.T) {
  1003  			got, err := Distinct(test.List)
  1004  
  1005  			if test.Err {
  1006  				if err == nil {
  1007  					t.Fatal("succeeded; want error")
  1008  				}
  1009  				return
  1010  			} else if err != nil {
  1011  				t.Fatalf("unexpected error: %s", err)
  1012  			}
  1013  
  1014  			if !got.RawEquals(test.Want) {
  1015  				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
  1016  			}
  1017  		})
  1018  	}
  1019  }
  1020  
  1021  func TestChunklist(t *testing.T) {
  1022  	tests := []struct {
  1023  		List cty.Value
  1024  		Size cty.Value
  1025  		Want cty.Value
  1026  		Err  bool
  1027  	}{
  1028  		{
  1029  			cty.ListVal([]cty.Value{
  1030  				cty.StringVal("a"),
  1031  				cty.StringVal("b"),
  1032  				cty.StringVal("c"),
  1033  			}),
  1034  			cty.NumberIntVal(1),
  1035  			cty.ListVal([]cty.Value{
  1036  				cty.ListVal([]cty.Value{
  1037  					cty.StringVal("a"),
  1038  				}),
  1039  				cty.ListVal([]cty.Value{
  1040  					cty.StringVal("b"),
  1041  				}),
  1042  				cty.ListVal([]cty.Value{
  1043  					cty.StringVal("c"),
  1044  				}),
  1045  			}),
  1046  			false,
  1047  		},
  1048  		{
  1049  			cty.ListVal([]cty.Value{
  1050  				cty.StringVal("a"),
  1051  				cty.StringVal("b"),
  1052  				cty.StringVal("c"),
  1053  			}),
  1054  			cty.NumberIntVal(-1),
  1055  			cty.NilVal,
  1056  			true,
  1057  		},
  1058  		{
  1059  			cty.ListVal([]cty.Value{
  1060  				cty.StringVal("a"),
  1061  				cty.StringVal("b"),
  1062  				cty.StringVal("c"),
  1063  			}),
  1064  			cty.NumberIntVal(0),
  1065  			cty.ListVal([]cty.Value{
  1066  				cty.ListVal([]cty.Value{
  1067  					cty.StringVal("a"),
  1068  					cty.StringVal("b"),
  1069  					cty.StringVal("c"),
  1070  				}),
  1071  			}),
  1072  			false,
  1073  		},
  1074  		{
  1075  			cty.ListVal([]cty.Value{
  1076  				cty.StringVal("a"),
  1077  				cty.StringVal("b"),
  1078  				cty.UnknownVal(cty.String),
  1079  			}),
  1080  			cty.NumberIntVal(1),
  1081  			cty.ListVal([]cty.Value{
  1082  				cty.ListVal([]cty.Value{
  1083  					cty.StringVal("a"),
  1084  				}),
  1085  				cty.ListVal([]cty.Value{
  1086  					cty.StringVal("b"),
  1087  				}),
  1088  				cty.ListVal([]cty.Value{
  1089  					cty.UnknownVal(cty.String),
  1090  				}),
  1091  			}),
  1092  			false,
  1093  		},
  1094  		{
  1095  			cty.UnknownVal(cty.List(cty.String)),
  1096  			cty.NumberIntVal(1),
  1097  			cty.UnknownVal(cty.List(cty.List(cty.String))),
  1098  			false,
  1099  		},
  1100  		{
  1101  			cty.ListValEmpty(cty.String),
  1102  			cty.NumberIntVal(3),
  1103  			cty.ListValEmpty(cty.List(cty.String)),
  1104  			false,
  1105  		},
  1106  	}
  1107  
  1108  	for i, test := range tests {
  1109  		t.Run(fmt.Sprintf("%d-chunklist(%#v, %#v)", i, test.List, test.Size), func(t *testing.T) {
  1110  			got, err := Chunklist(test.List, test.Size)
  1111  
  1112  			if test.Err {
  1113  				if err == nil {
  1114  					t.Fatal("succeeded; want error")
  1115  				}
  1116  				return
  1117  			} else if err != nil {
  1118  				t.Fatalf("unexpected error: %s", err)
  1119  			}
  1120  
  1121  			if !got.RawEquals(test.Want) {
  1122  				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
  1123  			}
  1124  		})
  1125  	}
  1126  }
  1127  
  1128  func TestFlatten(t *testing.T) {
  1129  	tests := []struct {
  1130  		List cty.Value
  1131  		Want cty.Value
  1132  		Err  bool
  1133  	}{
  1134  		{
  1135  			cty.ListVal([]cty.Value{
  1136  				cty.ListVal([]cty.Value{
  1137  					cty.StringVal("a"),
  1138  					cty.StringVal("b"),
  1139  				}),
  1140  				cty.ListVal([]cty.Value{
  1141  					cty.StringVal("c"),
  1142  					cty.StringVal("d"),
  1143  				}),
  1144  			}),
  1145  			cty.TupleVal([]cty.Value{
  1146  				cty.StringVal("a"),
  1147  				cty.StringVal("b"),
  1148  				cty.StringVal("c"),
  1149  				cty.StringVal("d"),
  1150  			}),
  1151  			false,
  1152  		},
  1153  		// handle single elements as arguments
  1154  		{
  1155  			cty.TupleVal([]cty.Value{
  1156  				cty.ListVal([]cty.Value{
  1157  					cty.StringVal("a"),
  1158  					cty.StringVal("b"),
  1159  				}),
  1160  				cty.StringVal("c"),
  1161  			}),
  1162  			cty.TupleVal([]cty.Value{
  1163  				cty.StringVal("a"),
  1164  				cty.StringVal("b"),
  1165  				cty.StringVal("c"),
  1166  			}), false,
  1167  		},
  1168  		// handle single elements and mixed primitive types as arguments
  1169  		{
  1170  			cty.TupleVal([]cty.Value{
  1171  				cty.ListVal([]cty.Value{
  1172  					cty.StringVal("a"),
  1173  					cty.StringVal("b"),
  1174  				}),
  1175  				cty.StringVal("c"),
  1176  				cty.TupleVal([]cty.Value{
  1177  					cty.StringVal("x"),
  1178  					cty.NumberIntVal(1),
  1179  				}),
  1180  			}),
  1181  			cty.TupleVal([]cty.Value{
  1182  				cty.StringVal("a"),
  1183  				cty.StringVal("b"),
  1184  				cty.StringVal("c"),
  1185  				cty.StringVal("x"),
  1186  				cty.NumberIntVal(1),
  1187  			}),
  1188  			false,
  1189  		},
  1190  		// Primitive unknowns should still be flattened to a tuple
  1191  		{
  1192  			cty.ListVal([]cty.Value{
  1193  				cty.ListVal([]cty.Value{
  1194  					cty.StringVal("a"),
  1195  					cty.StringVal("b"),
  1196  				}),
  1197  				cty.ListVal([]cty.Value{
  1198  					cty.UnknownVal(cty.String),
  1199  					cty.StringVal("d"),
  1200  				}),
  1201  			}),
  1202  			cty.TupleVal([]cty.Value{
  1203  				cty.StringVal("a"),
  1204  				cty.StringVal("b"),
  1205  				cty.UnknownVal(cty.String),
  1206  				cty.StringVal("d"),
  1207  			}), false,
  1208  		},
  1209  		// An unknown series should return an unknown dynamic value
  1210  		{
  1211  			cty.TupleVal([]cty.Value{
  1212  				cty.ListVal([]cty.Value{
  1213  					cty.StringVal("a"),
  1214  					cty.StringVal("b"),
  1215  				}),
  1216  				cty.TupleVal([]cty.Value{
  1217  					cty.UnknownVal(cty.List(cty.String)),
  1218  					cty.StringVal("d"),
  1219  				}),
  1220  			}),
  1221  			cty.UnknownVal(cty.DynamicPseudoType), false,
  1222  		},
  1223  		{
  1224  			cty.ListValEmpty(cty.String),
  1225  			cty.EmptyTupleVal,
  1226  			false,
  1227  		},
  1228  		{
  1229  			cty.SetVal([]cty.Value{
  1230  				cty.SetVal([]cty.Value{
  1231  					cty.StringVal("a"),
  1232  					cty.StringVal("b"),
  1233  				}),
  1234  				cty.SetVal([]cty.Value{
  1235  					cty.StringVal("c"),
  1236  					cty.StringVal("d"),
  1237  				}),
  1238  			}),
  1239  			cty.TupleVal([]cty.Value{
  1240  				cty.StringVal("a"),
  1241  				cty.StringVal("b"),
  1242  				cty.StringVal("c"),
  1243  				cty.StringVal("d"),
  1244  			}),
  1245  			false,
  1246  		},
  1247  		{
  1248  			cty.TupleVal([]cty.Value{
  1249  				cty.SetVal([]cty.Value{
  1250  					cty.StringVal("a"),
  1251  					cty.StringVal("b"),
  1252  				}),
  1253  				cty.ListVal([]cty.Value{
  1254  					cty.StringVal("c"),
  1255  					cty.StringVal("d"),
  1256  				}),
  1257  			}),
  1258  			cty.TupleVal([]cty.Value{
  1259  				cty.StringVal("a"),
  1260  				cty.StringVal("b"),
  1261  				cty.StringVal("c"),
  1262  				cty.StringVal("d"),
  1263  			}),
  1264  			false,
  1265  		},
  1266  	}
  1267  
  1268  	for i, test := range tests {
  1269  		t.Run(fmt.Sprintf("%d-flatten(%#v)", i, test.List), func(t *testing.T) {
  1270  			got, err := Flatten(test.List)
  1271  
  1272  			if test.Err {
  1273  				if err == nil {
  1274  					t.Fatal("succeeded; want error")
  1275  				}
  1276  				return
  1277  			} else if err != nil {
  1278  				t.Fatalf("unexpected error: %s", err)
  1279  			}
  1280  
  1281  			if !got.RawEquals(test.Want) {
  1282  				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
  1283  			}
  1284  		})
  1285  	}
  1286  }
  1287  
  1288  func TestKeys(t *testing.T) {
  1289  	tests := []struct {
  1290  		Map  cty.Value
  1291  		Want cty.Value
  1292  		Err  bool
  1293  	}{
  1294  		{
  1295  			cty.MapVal(map[string]cty.Value{
  1296  				"hello":   cty.NumberIntVal(1),
  1297  				"goodbye": cty.NumberIntVal(42),
  1298  			}),
  1299  			cty.ListVal([]cty.Value{
  1300  				cty.StringVal("goodbye"),
  1301  				cty.StringVal("hello"),
  1302  			}),
  1303  			false,
  1304  		},
  1305  		{ // same as above, but an object type
  1306  			cty.ObjectVal(map[string]cty.Value{
  1307  				"hello":   cty.NumberIntVal(1),
  1308  				"goodbye": cty.StringVal("adieu"),
  1309  			}),
  1310  			cty.TupleVal([]cty.Value{
  1311  				cty.StringVal("goodbye"),
  1312  				cty.StringVal("hello"),
  1313  			}),
  1314  			false,
  1315  		},
  1316  		{ // for an unknown object we can still return the keys, since they are part of the type
  1317  			cty.UnknownVal(cty.Object(map[string]cty.Type{
  1318  				"hello":   cty.Number,
  1319  				"goodbye": cty.String,
  1320  			})),
  1321  			cty.TupleVal([]cty.Value{
  1322  				cty.StringVal("goodbye"),
  1323  				cty.StringVal("hello"),
  1324  			}),
  1325  			false,
  1326  		},
  1327  		{ // an empty object has no keys
  1328  			cty.EmptyObjectVal,
  1329  			cty.EmptyTupleVal,
  1330  			false,
  1331  		},
  1332  		{ // an empty map has no keys, but the result should still be properly typed
  1333  			cty.MapValEmpty(cty.Number),
  1334  			cty.ListValEmpty(cty.String),
  1335  			false,
  1336  		},
  1337  		{ // Unknown map has unknown keys
  1338  			cty.UnknownVal(cty.Map(cty.String)),
  1339  			cty.UnknownVal(cty.List(cty.String)),
  1340  			false,
  1341  		},
  1342  		{ // Not a map at all, so invalid
  1343  			cty.StringVal("foo"),
  1344  			cty.NilVal,
  1345  			true,
  1346  		},
  1347  		{ // Can't get keys from a null object
  1348  			cty.NullVal(cty.Object(map[string]cty.Type{
  1349  				"hello":   cty.Number,
  1350  				"goodbye": cty.String,
  1351  			})),
  1352  			cty.NilVal,
  1353  			true,
  1354  		},
  1355  		{ // Can't get keys from a null map
  1356  			cty.NullVal(cty.Map(cty.Number)),
  1357  			cty.NilVal,
  1358  			true,
  1359  		},
  1360  	}
  1361  
  1362  	for _, test := range tests {
  1363  		t.Run(fmt.Sprintf("keys(%#v)", test.Map), func(t *testing.T) {
  1364  			got, err := Keys(test.Map)
  1365  
  1366  			if test.Err {
  1367  				if err == nil {
  1368  					t.Fatal("succeeded; want error")
  1369  				}
  1370  				return
  1371  			} else if err != nil {
  1372  				t.Fatalf("unexpected error: %s", err)
  1373  			}
  1374  
  1375  			if !got.RawEquals(test.Want) {
  1376  				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
  1377  			}
  1378  		})
  1379  	}
  1380  }
  1381  
  1382  func TestList(t *testing.T) {
  1383  	tests := []struct {
  1384  		Values []cty.Value
  1385  		Want   cty.Value
  1386  		Err    bool
  1387  	}{
  1388  		{
  1389  			[]cty.Value{
  1390  				cty.NilVal,
  1391  			},
  1392  			cty.NilVal,
  1393  			true,
  1394  		},
  1395  		{
  1396  			[]cty.Value{
  1397  				cty.StringVal("Hello"),
  1398  			},
  1399  			cty.ListVal([]cty.Value{
  1400  				cty.StringVal("Hello"),
  1401  			}),
  1402  			false,
  1403  		},
  1404  		{
  1405  			[]cty.Value{
  1406  				cty.StringVal("Hello"),
  1407  				cty.StringVal("World"),
  1408  			},
  1409  			cty.ListVal([]cty.Value{
  1410  				cty.StringVal("Hello"),
  1411  				cty.StringVal("World"),
  1412  			}),
  1413  			false,
  1414  		},
  1415  		{
  1416  			[]cty.Value{
  1417  				cty.StringVal("Hello"),
  1418  				cty.NumberIntVal(42),
  1419  			},
  1420  			cty.ListVal([]cty.Value{
  1421  				cty.StringVal("Hello"),
  1422  				cty.StringVal("42"),
  1423  			}),
  1424  			false,
  1425  		},
  1426  		{
  1427  			[]cty.Value{
  1428  				cty.StringVal("Hello"),
  1429  				cty.UnknownVal(cty.String),
  1430  			},
  1431  			cty.ListVal([]cty.Value{
  1432  				cty.StringVal("Hello"),
  1433  				cty.UnknownVal(cty.String),
  1434  			}),
  1435  			false,
  1436  		},
  1437  	}
  1438  
  1439  	for _, test := range tests {
  1440  		t.Run(fmt.Sprintf("list(%#v)", test.Values), func(t *testing.T) {
  1441  			got, err := List(test.Values...)
  1442  
  1443  			if test.Err {
  1444  				if err == nil {
  1445  					t.Fatal("succeeded; want error")
  1446  				}
  1447  				return
  1448  			} else if err != nil {
  1449  				t.Fatalf("unexpected error: %s", err)
  1450  			}
  1451  
  1452  			if !got.RawEquals(test.Want) {
  1453  				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
  1454  			}
  1455  		})
  1456  	}
  1457  }
  1458  
  1459  func TestLookup(t *testing.T) {
  1460  	simpleMap := cty.MapVal(map[string]cty.Value{
  1461  		"foo": cty.StringVal("bar"),
  1462  	})
  1463  	intsMap := cty.MapVal(map[string]cty.Value{
  1464  		"foo": cty.NumberIntVal(42),
  1465  	})
  1466  	mapOfLists := cty.MapVal(map[string]cty.Value{
  1467  		"foo": cty.ListVal([]cty.Value{
  1468  			cty.StringVal("bar"),
  1469  			cty.StringVal("baz"),
  1470  		}),
  1471  	})
  1472  	mapOfMaps := cty.MapVal(map[string]cty.Value{
  1473  		"foo": cty.MapVal(map[string]cty.Value{
  1474  			"a": cty.StringVal("bar"),
  1475  		}),
  1476  		"baz": cty.MapVal(map[string]cty.Value{
  1477  			"b": cty.StringVal("bat"),
  1478  		}),
  1479  	})
  1480  	mapOfTuples := cty.MapVal(map[string]cty.Value{
  1481  		"foo": cty.TupleVal([]cty.Value{cty.StringVal("bar")}),
  1482  		"baz": cty.TupleVal([]cty.Value{cty.StringVal("bat")}),
  1483  	})
  1484  	objectOfMaps := cty.ObjectVal(map[string]cty.Value{
  1485  		"foo": cty.MapVal(map[string]cty.Value{
  1486  			"a": cty.StringVal("bar"),
  1487  		}),
  1488  		"baz": cty.MapVal(map[string]cty.Value{
  1489  			"b": cty.StringVal("bat"),
  1490  		}),
  1491  	})
  1492  	mapWithUnknowns := cty.MapVal(map[string]cty.Value{
  1493  		"foo": cty.StringVal("bar"),
  1494  		"baz": cty.UnknownVal(cty.String),
  1495  	})
  1496  	mapWithObjects := cty.ObjectVal(map[string]cty.Value{
  1497  		"foo": cty.StringVal("bar"),
  1498  		"baz": cty.NumberIntVal(42),
  1499  	})
  1500  
  1501  	tests := []struct {
  1502  		Values []cty.Value
  1503  		Want   cty.Value
  1504  		Err    bool
  1505  	}{
  1506  		{
  1507  			[]cty.Value{
  1508  				simpleMap,
  1509  				cty.StringVal("foo"),
  1510  			},
  1511  			cty.StringVal("bar"),
  1512  			false,
  1513  		},
  1514  		{
  1515  			[]cty.Value{
  1516  				mapWithObjects,
  1517  				cty.StringVal("foo"),
  1518  			},
  1519  			cty.StringVal("bar"),
  1520  			false,
  1521  		},
  1522  		{
  1523  			[]cty.Value{
  1524  				intsMap,
  1525  				cty.StringVal("foo"),
  1526  			},
  1527  			cty.NumberIntVal(42),
  1528  			false,
  1529  		},
  1530  		{
  1531  			[]cty.Value{
  1532  				mapOfMaps,
  1533  				cty.StringVal("foo"),
  1534  			},
  1535  			cty.MapVal(map[string]cty.Value{
  1536  				"a": cty.StringVal("bar"),
  1537  			}),
  1538  			false,
  1539  		},
  1540  		{
  1541  			[]cty.Value{
  1542  				objectOfMaps,
  1543  				cty.StringVal("foo"),
  1544  			},
  1545  			cty.MapVal(map[string]cty.Value{
  1546  				"a": cty.StringVal("bar"),
  1547  			}),
  1548  			false,
  1549  		},
  1550  		{
  1551  			[]cty.Value{
  1552  				mapOfTuples,
  1553  				cty.StringVal("foo"),
  1554  			},
  1555  			cty.TupleVal([]cty.Value{cty.StringVal("bar")}),
  1556  			false,
  1557  		},
  1558  		{ // Invalid key
  1559  			[]cty.Value{
  1560  				simpleMap,
  1561  				cty.StringVal("bar"),
  1562  			},
  1563  			cty.NilVal,
  1564  			true,
  1565  		},
  1566  		{ // Invalid key
  1567  			[]cty.Value{
  1568  				mapWithObjects,
  1569  				cty.StringVal("bar"),
  1570  			},
  1571  			cty.NilVal,
  1572  			true,
  1573  		},
  1574  		{ // Supplied default with valid key
  1575  			[]cty.Value{
  1576  				simpleMap,
  1577  				cty.StringVal("foo"),
  1578  				cty.StringVal(""),
  1579  			},
  1580  			cty.StringVal("bar"),
  1581  			false,
  1582  		},
  1583  		{ // Supplied default with valid (int) key
  1584  			[]cty.Value{
  1585  				simpleMap,
  1586  				cty.StringVal("foo"),
  1587  				cty.NumberIntVal(-1),
  1588  			},
  1589  			cty.StringVal("bar"),
  1590  			false,
  1591  		},
  1592  		{ // Supplied default with valid (int) key
  1593  			[]cty.Value{
  1594  				simpleMap,
  1595  				cty.StringVal("foobar"),
  1596  				cty.NumberIntVal(-1),
  1597  			},
  1598  			cty.StringVal("-1"),
  1599  			false,
  1600  		},
  1601  		{ // Supplied default with valid key
  1602  			[]cty.Value{
  1603  				mapWithObjects,
  1604  				cty.StringVal("foobar"),
  1605  				cty.StringVal(""),
  1606  			},
  1607  			cty.StringVal(""),
  1608  			false,
  1609  		},
  1610  		{ // Supplied default with invalid key
  1611  			[]cty.Value{
  1612  				simpleMap,
  1613  				cty.StringVal("baz"),
  1614  				cty.StringVal(""),
  1615  			},
  1616  			cty.StringVal(""),
  1617  			false,
  1618  		},
  1619  		{ // Supplied default with type mismatch: expects a map return
  1620  			[]cty.Value{
  1621  				mapOfMaps,
  1622  				cty.StringVal("foo"),
  1623  				cty.StringVal(""),
  1624  			},
  1625  			cty.NilVal,
  1626  			true,
  1627  		},
  1628  		{ // Supplied non-empty default with invalid key
  1629  			[]cty.Value{
  1630  				simpleMap,
  1631  				cty.StringVal("bar"),
  1632  				cty.StringVal("xyz"),
  1633  			},
  1634  			cty.StringVal("xyz"),
  1635  			false,
  1636  		},
  1637  		{ // too many args
  1638  			[]cty.Value{
  1639  				simpleMap,
  1640  				cty.StringVal("foo"),
  1641  				cty.StringVal("bar"),
  1642  				cty.StringVal("baz"),
  1643  			},
  1644  			cty.NilVal,
  1645  			true,
  1646  		},
  1647  		{ // cannot search a map of lists
  1648  			[]cty.Value{
  1649  				mapOfLists,
  1650  				cty.StringVal("baz"),
  1651  			},
  1652  			cty.NilVal,
  1653  			true,
  1654  		},
  1655  		{
  1656  			[]cty.Value{
  1657  				mapWithUnknowns,
  1658  				cty.StringVal("baz"),
  1659  			},
  1660  			cty.UnknownVal(cty.String),
  1661  			false,
  1662  		},
  1663  		{
  1664  			[]cty.Value{
  1665  				simpleMap,
  1666  				cty.UnknownVal(cty.String),
  1667  			},
  1668  			cty.UnknownVal(cty.String),
  1669  			false,
  1670  		},
  1671  		{
  1672  			[]cty.Value{
  1673  				cty.ObjectVal(map[string]cty.Value{
  1674  					"foo": cty.StringVal("a"),
  1675  					"bar": cty.StringVal("b"),
  1676  				}),
  1677  				cty.UnknownVal(cty.String),
  1678  			},
  1679  			cty.DynamicVal, // if the key is unknown then we don't know which object attribute and thus can't know the type
  1680  			false,
  1681  		},
  1682  	}
  1683  
  1684  	for _, test := range tests {
  1685  		t.Run(fmt.Sprintf("lookup(%#v)", test.Values), func(t *testing.T) {
  1686  			got, err := Lookup(test.Values...)
  1687  
  1688  			if test.Err {
  1689  				if err == nil {
  1690  					t.Fatal("succeeded; want error")
  1691  				}
  1692  				return
  1693  			} else if err != nil {
  1694  				t.Fatalf("unexpected error: %s", err)
  1695  			}
  1696  
  1697  			if !got.RawEquals(test.Want) {
  1698  				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
  1699  			}
  1700  		})
  1701  	}
  1702  }
  1703  
  1704  func TestMap(t *testing.T) {
  1705  	tests := []struct {
  1706  		Values []cty.Value
  1707  		Want   cty.Value
  1708  		Err    bool
  1709  	}{
  1710  		{
  1711  			[]cty.Value{
  1712  				cty.StringVal("hello"),
  1713  				cty.StringVal("world"),
  1714  			},
  1715  			cty.MapVal(map[string]cty.Value{
  1716  				"hello": cty.StringVal("world"),
  1717  			}),
  1718  			false,
  1719  		},
  1720  		{
  1721  			[]cty.Value{
  1722  				cty.StringVal("hello"),
  1723  				cty.UnknownVal(cty.String),
  1724  			},
  1725  			cty.UnknownVal(cty.Map(cty.String)),
  1726  			false,
  1727  		},
  1728  		{
  1729  			[]cty.Value{
  1730  				cty.StringVal("hello"),
  1731  				cty.StringVal("world"),
  1732  				cty.StringVal("what's"),
  1733  				cty.StringVal("up"),
  1734  			},
  1735  			cty.MapVal(map[string]cty.Value{
  1736  				"hello":  cty.StringVal("world"),
  1737  				"what's": cty.StringVal("up"),
  1738  			}),
  1739  			false,
  1740  		},
  1741  		{
  1742  			[]cty.Value{
  1743  				cty.StringVal("hello"),
  1744  				cty.NumberIntVal(1),
  1745  				cty.StringVal("goodbye"),
  1746  				cty.NumberIntVal(42),
  1747  			},
  1748  			cty.MapVal(map[string]cty.Value{
  1749  				"hello":   cty.NumberIntVal(1),
  1750  				"goodbye": cty.NumberIntVal(42),
  1751  			}),
  1752  			false,
  1753  		},
  1754  		{ // convert numbers to strings
  1755  			[]cty.Value{
  1756  				cty.StringVal("hello"),
  1757  				cty.NumberIntVal(1),
  1758  				cty.StringVal("goodbye"),
  1759  				cty.StringVal("42"),
  1760  			},
  1761  			cty.MapVal(map[string]cty.Value{
  1762  				"hello":   cty.StringVal("1"),
  1763  				"goodbye": cty.StringVal("42"),
  1764  			}),
  1765  			false,
  1766  		},
  1767  		{ // map of lists is okay
  1768  			[]cty.Value{
  1769  				cty.StringVal("hello"),
  1770  				cty.ListVal([]cty.Value{
  1771  					cty.StringVal("world"),
  1772  				}),
  1773  				cty.StringVal("what's"),
  1774  				cty.ListVal([]cty.Value{
  1775  					cty.StringVal("up"),
  1776  				}),
  1777  			},
  1778  			cty.MapVal(map[string]cty.Value{
  1779  				"hello":  cty.ListVal([]cty.Value{cty.StringVal("world")}),
  1780  				"what's": cty.ListVal([]cty.Value{cty.StringVal("up")}),
  1781  			}),
  1782  			false,
  1783  		},
  1784  		{ // map of maps is okay
  1785  			[]cty.Value{
  1786  				cty.StringVal("hello"),
  1787  				cty.MapVal(map[string]cty.Value{
  1788  					"there": cty.StringVal("world"),
  1789  				}),
  1790  				cty.StringVal("what's"),
  1791  				cty.MapVal(map[string]cty.Value{
  1792  					"really": cty.StringVal("up"),
  1793  				}),
  1794  			},
  1795  			cty.MapVal(map[string]cty.Value{
  1796  				"hello": cty.MapVal(map[string]cty.Value{
  1797  					"there": cty.StringVal("world"),
  1798  				}),
  1799  				"what's": cty.MapVal(map[string]cty.Value{
  1800  					"really": cty.StringVal("up"),
  1801  				}),
  1802  			}),
  1803  			false,
  1804  		},
  1805  		{ // single argument returns an error
  1806  			[]cty.Value{
  1807  				cty.StringVal("hello"),
  1808  			},
  1809  			cty.NilVal,
  1810  			true,
  1811  		},
  1812  		{ // duplicate keys returns an error
  1813  			[]cty.Value{
  1814  				cty.StringVal("hello"),
  1815  				cty.StringVal("world"),
  1816  				cty.StringVal("hello"),
  1817  				cty.StringVal("universe"),
  1818  			},
  1819  			cty.NilVal,
  1820  			true,
  1821  		},
  1822  	}
  1823  
  1824  	for _, test := range tests {
  1825  		t.Run(fmt.Sprintf("map(%#v)", test.Values), func(t *testing.T) {
  1826  			got, err := Map(test.Values...)
  1827  			if test.Err {
  1828  				if err == nil {
  1829  					t.Fatal("succeeded; want error")
  1830  				}
  1831  				return
  1832  			} else if err != nil {
  1833  				t.Fatalf("unexpected error: %s", err)
  1834  			}
  1835  
  1836  			if !got.RawEquals(test.Want) {
  1837  				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
  1838  			}
  1839  		})
  1840  	}
  1841  }
  1842  
  1843  func TestMatchkeys(t *testing.T) {
  1844  	tests := []struct {
  1845  		Keys      cty.Value
  1846  		Values    cty.Value
  1847  		Searchset cty.Value
  1848  		Want      cty.Value
  1849  		Err       bool
  1850  	}{
  1851  		{ // normal usage
  1852  			cty.ListVal([]cty.Value{
  1853  				cty.StringVal("a"),
  1854  				cty.StringVal("b"),
  1855  				cty.StringVal("c"),
  1856  			}),
  1857  			cty.ListVal([]cty.Value{
  1858  				cty.StringVal("ref1"),
  1859  				cty.StringVal("ref2"),
  1860  				cty.StringVal("ref3"),
  1861  			}),
  1862  			cty.ListVal([]cty.Value{
  1863  				cty.StringVal("ref1"),
  1864  			}),
  1865  			cty.ListVal([]cty.Value{
  1866  				cty.StringVal("a"),
  1867  			}),
  1868  			false,
  1869  		},
  1870  		{ // normal usage 2, check the order
  1871  			cty.ListVal([]cty.Value{
  1872  				cty.StringVal("a"),
  1873  				cty.StringVal("b"),
  1874  				cty.StringVal("c"),
  1875  			}),
  1876  			cty.ListVal([]cty.Value{
  1877  				cty.StringVal("ref1"),
  1878  				cty.StringVal("ref2"),
  1879  				cty.StringVal("ref3"),
  1880  			}),
  1881  			cty.ListVal([]cty.Value{
  1882  				cty.StringVal("ref2"),
  1883  				cty.StringVal("ref1"),
  1884  			}),
  1885  			cty.ListVal([]cty.Value{
  1886  				cty.StringVal("a"),
  1887  				cty.StringVal("b"),
  1888  			}),
  1889  			false,
  1890  		},
  1891  		{ // no matches
  1892  			cty.ListVal([]cty.Value{
  1893  				cty.StringVal("a"),
  1894  				cty.StringVal("b"),
  1895  				cty.StringVal("c"),
  1896  			}),
  1897  			cty.ListVal([]cty.Value{
  1898  				cty.StringVal("ref1"),
  1899  				cty.StringVal("ref2"),
  1900  				cty.StringVal("ref3"),
  1901  			}),
  1902  			cty.ListVal([]cty.Value{
  1903  				cty.StringVal("ref4"),
  1904  			}),
  1905  			cty.ListValEmpty(cty.String),
  1906  			false,
  1907  		},
  1908  		{ // no matches 2
  1909  			cty.ListVal([]cty.Value{
  1910  				cty.StringVal("a"),
  1911  				cty.StringVal("b"),
  1912  				cty.StringVal("c"),
  1913  			}),
  1914  			cty.ListVal([]cty.Value{
  1915  				cty.StringVal("ref1"),
  1916  				cty.StringVal("ref2"),
  1917  				cty.StringVal("ref3"),
  1918  			}),
  1919  			cty.ListValEmpty(cty.String),
  1920  			cty.ListValEmpty(cty.String),
  1921  			false,
  1922  		},
  1923  		{ // zero case
  1924  			cty.ListValEmpty(cty.String),
  1925  			cty.ListValEmpty(cty.String),
  1926  			cty.ListVal([]cty.Value{cty.StringVal("nope")}),
  1927  			cty.ListValEmpty(cty.String),
  1928  			false,
  1929  		},
  1930  		{ // complex values
  1931  			cty.ListVal([]cty.Value{
  1932  				cty.ListVal([]cty.Value{
  1933  					cty.StringVal("a"),
  1934  					cty.StringVal("a"),
  1935  				}),
  1936  			}),
  1937  			cty.ListVal([]cty.Value{
  1938  				cty.StringVal("a"),
  1939  			}),
  1940  			cty.ListVal([]cty.Value{
  1941  				cty.StringVal("a"),
  1942  			}),
  1943  			cty.ListVal([]cty.Value{
  1944  				cty.ListVal([]cty.Value{
  1945  					cty.StringVal("a"),
  1946  					cty.StringVal("a"),
  1947  				}),
  1948  			}),
  1949  			false,
  1950  		},
  1951  		{ // unknowns
  1952  			cty.ListVal([]cty.Value{
  1953  				cty.StringVal("a"),
  1954  				cty.StringVal("b"),
  1955  				cty.UnknownVal(cty.String),
  1956  			}),
  1957  			cty.ListVal([]cty.Value{
  1958  				cty.StringVal("ref1"),
  1959  				cty.StringVal("ref2"),
  1960  				cty.UnknownVal(cty.String),
  1961  			}),
  1962  			cty.ListVal([]cty.Value{
  1963  				cty.StringVal("ref1"),
  1964  			}),
  1965  			cty.UnknownVal(cty.List(cty.String)),
  1966  			false,
  1967  		},
  1968  		{ // different types that can be unified
  1969  			cty.ListVal([]cty.Value{
  1970  				cty.StringVal("a"),
  1971  			}),
  1972  			cty.ListVal([]cty.Value{
  1973  				cty.NumberIntVal(1),
  1974  			}),
  1975  			cty.ListVal([]cty.Value{
  1976  				cty.StringVal("a"),
  1977  			}),
  1978  			cty.ListValEmpty(cty.String),
  1979  			false,
  1980  		},
  1981  		{ // complex values: values is a different type from keys and searchset
  1982  			cty.ListVal([]cty.Value{
  1983  				cty.MapVal(map[string]cty.Value{
  1984  					"foo": cty.StringVal("bar"),
  1985  				}),
  1986  				cty.MapVal(map[string]cty.Value{
  1987  					"foo": cty.StringVal("baz"),
  1988  				}),
  1989  				cty.MapVal(map[string]cty.Value{
  1990  					"foo": cty.StringVal("beep"),
  1991  				}),
  1992  			}),
  1993  			cty.ListVal([]cty.Value{
  1994  				cty.StringVal("a"),
  1995  				cty.StringVal("b"),
  1996  				cty.StringVal("c"),
  1997  			}),
  1998  			cty.ListVal([]cty.Value{
  1999  				cty.StringVal("a"),
  2000  				cty.StringVal("c"),
  2001  			}),
  2002  			cty.ListVal([]cty.Value{
  2003  				cty.MapVal(map[string]cty.Value{
  2004  					"foo": cty.StringVal("bar"),
  2005  				}),
  2006  				cty.MapVal(map[string]cty.Value{
  2007  					"foo": cty.StringVal("beep"),
  2008  				}),
  2009  			}),
  2010  			false,
  2011  		},
  2012  		// errors
  2013  		{ // different types
  2014  			cty.ListVal([]cty.Value{
  2015  				cty.StringVal("a"),
  2016  			}),
  2017  			cty.ListVal([]cty.Value{
  2018  				cty.ListVal([]cty.Value{
  2019  					cty.StringVal("a"),
  2020  				}),
  2021  				cty.ListVal([]cty.Value{
  2022  					cty.StringVal("a"),
  2023  				}),
  2024  			}),
  2025  			cty.ListVal([]cty.Value{
  2026  				cty.StringVal("a"),
  2027  			}),
  2028  			cty.NilVal,
  2029  			true,
  2030  		},
  2031  		{ // lists of different length
  2032  			cty.ListVal([]cty.Value{
  2033  				cty.StringVal("a"),
  2034  			}),
  2035  			cty.ListVal([]cty.Value{
  2036  				cty.StringVal("a"),
  2037  				cty.StringVal("b"),
  2038  			}),
  2039  			cty.ListVal([]cty.Value{
  2040  				cty.StringVal("a"),
  2041  			}),
  2042  			cty.NilVal,
  2043  			true,
  2044  		},
  2045  	}
  2046  
  2047  	for _, test := range tests {
  2048  		t.Run(fmt.Sprintf("matchkeys(%#v, %#v, %#v)", test.Keys, test.Values, test.Searchset), func(t *testing.T) {
  2049  			got, err := Matchkeys(test.Keys, test.Values, test.Searchset)
  2050  
  2051  			if test.Err {
  2052  				if err == nil {
  2053  					t.Fatal("succeeded; want error")
  2054  				}
  2055  				return
  2056  			} else if err != nil {
  2057  				t.Fatalf("unexpected error: %s", err)
  2058  			}
  2059  
  2060  			if !got.RawEquals(test.Want) {
  2061  				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
  2062  			}
  2063  		})
  2064  	}
  2065  }
  2066  
  2067  func TestMerge(t *testing.T) {
  2068  	tests := []struct {
  2069  		Values []cty.Value
  2070  		Want   cty.Value
  2071  		Err    bool
  2072  	}{
  2073  		{
  2074  			[]cty.Value{
  2075  				cty.MapVal(map[string]cty.Value{
  2076  					"a": cty.StringVal("b"),
  2077  				}),
  2078  				cty.MapVal(map[string]cty.Value{
  2079  					"c": cty.StringVal("d"),
  2080  				}),
  2081  			},
  2082  			cty.ObjectVal(map[string]cty.Value{
  2083  				"a": cty.StringVal("b"),
  2084  				"c": cty.StringVal("d"),
  2085  			}),
  2086  			false,
  2087  		},
  2088  		{ // handle unknowns
  2089  			[]cty.Value{
  2090  				cty.MapVal(map[string]cty.Value{
  2091  					"a": cty.UnknownVal(cty.String),
  2092  				}),
  2093  				cty.MapVal(map[string]cty.Value{
  2094  					"c": cty.StringVal("d"),
  2095  				}),
  2096  			},
  2097  			cty.DynamicVal,
  2098  			false,
  2099  		},
  2100  		{ // merge with conflicts is ok, last in wins
  2101  			[]cty.Value{
  2102  				cty.MapVal(map[string]cty.Value{
  2103  					"a": cty.StringVal("b"),
  2104  					"c": cty.StringVal("d"),
  2105  				}),
  2106  				cty.MapVal(map[string]cty.Value{
  2107  					"a": cty.StringVal("x"),
  2108  				}),
  2109  			},
  2110  			cty.ObjectVal(map[string]cty.Value{
  2111  				"a": cty.StringVal("x"),
  2112  				"c": cty.StringVal("d"),
  2113  			}),
  2114  			false,
  2115  		},
  2116  		{ // only accept maps
  2117  			[]cty.Value{
  2118  				cty.MapVal(map[string]cty.Value{
  2119  					"a": cty.StringVal("b"),
  2120  					"c": cty.StringVal("d"),
  2121  				}),
  2122  				cty.ListVal([]cty.Value{
  2123  					cty.StringVal("a"),
  2124  					cty.StringVal("x"),
  2125  				}),
  2126  			},
  2127  			cty.NilVal,
  2128  			true,
  2129  		},
  2130  
  2131  		{ // argument error, for a null type
  2132  			[]cty.Value{
  2133  				cty.MapVal(map[string]cty.Value{
  2134  					"a": cty.StringVal("b"),
  2135  				}),
  2136  				cty.NullVal(cty.String),
  2137  			},
  2138  			cty.NilVal,
  2139  			true,
  2140  		},
  2141  		{ // merge maps of maps
  2142  			[]cty.Value{
  2143  				cty.MapVal(map[string]cty.Value{
  2144  					"a": cty.MapVal(map[string]cty.Value{
  2145  						"b": cty.StringVal("c"),
  2146  					}),
  2147  				}),
  2148  				cty.MapVal(map[string]cty.Value{
  2149  					"d": cty.MapVal(map[string]cty.Value{
  2150  						"e": cty.StringVal("f"),
  2151  					}),
  2152  				}),
  2153  			},
  2154  			cty.ObjectVal(map[string]cty.Value{
  2155  				"a": cty.MapVal(map[string]cty.Value{
  2156  					"b": cty.StringVal("c"),
  2157  				}),
  2158  				"d": cty.MapVal(map[string]cty.Value{
  2159  					"e": cty.StringVal("f"),
  2160  				}),
  2161  			}),
  2162  			false,
  2163  		},
  2164  		{ // map of lists
  2165  			[]cty.Value{
  2166  				cty.MapVal(map[string]cty.Value{
  2167  					"a": cty.ListVal([]cty.Value{
  2168  						cty.StringVal("b"),
  2169  						cty.StringVal("c"),
  2170  					}),
  2171  				}),
  2172  				cty.MapVal(map[string]cty.Value{
  2173  					"d": cty.ListVal([]cty.Value{
  2174  						cty.StringVal("e"),
  2175  						cty.StringVal("f"),
  2176  					}),
  2177  				}),
  2178  			},
  2179  			cty.ObjectVal(map[string]cty.Value{
  2180  				"a": cty.ListVal([]cty.Value{
  2181  					cty.StringVal("b"),
  2182  					cty.StringVal("c"),
  2183  				}),
  2184  				"d": cty.ListVal([]cty.Value{
  2185  					cty.StringVal("e"),
  2186  					cty.StringVal("f"),
  2187  				}),
  2188  			}),
  2189  			false,
  2190  		},
  2191  		{ // merge map of various kinds
  2192  			[]cty.Value{
  2193  				cty.MapVal(map[string]cty.Value{
  2194  					"a": cty.ListVal([]cty.Value{
  2195  						cty.StringVal("b"),
  2196  						cty.StringVal("c"),
  2197  					}),
  2198  				}),
  2199  				cty.MapVal(map[string]cty.Value{
  2200  					"d": cty.MapVal(map[string]cty.Value{
  2201  						"e": cty.StringVal("f"),
  2202  					}),
  2203  				}),
  2204  			},
  2205  			cty.ObjectVal(map[string]cty.Value{
  2206  				"a": cty.ListVal([]cty.Value{
  2207  					cty.StringVal("b"),
  2208  					cty.StringVal("c"),
  2209  				}),
  2210  				"d": cty.MapVal(map[string]cty.Value{
  2211  					"e": cty.StringVal("f"),
  2212  				}),
  2213  			}),
  2214  			false,
  2215  		},
  2216  		{ // argument error: non map type
  2217  			[]cty.Value{
  2218  				cty.MapVal(map[string]cty.Value{
  2219  					"a": cty.ListVal([]cty.Value{
  2220  						cty.StringVal("b"),
  2221  						cty.StringVal("c"),
  2222  					}),
  2223  				}),
  2224  				cty.ListVal([]cty.Value{
  2225  					cty.StringVal("d"),
  2226  					cty.StringVal("e"),
  2227  				}),
  2228  			},
  2229  			cty.NilVal,
  2230  			true,
  2231  		},
  2232  	}
  2233  
  2234  	for _, test := range tests {
  2235  		t.Run(fmt.Sprintf("merge(%#v)", test.Values), func(t *testing.T) {
  2236  			got, err := Merge(test.Values...)
  2237  
  2238  			if test.Err {
  2239  				if err == nil {
  2240  					t.Fatal("succeeded; want error")
  2241  				}
  2242  				return
  2243  			} else if err != nil {
  2244  				t.Fatalf("unexpected error: %s", err)
  2245  			}
  2246  
  2247  			if !got.RawEquals(test.Want) {
  2248  				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
  2249  			}
  2250  		})
  2251  	}
  2252  }
  2253  
  2254  func TestReverse(t *testing.T) {
  2255  	tests := []struct {
  2256  		List cty.Value
  2257  		Want cty.Value
  2258  		Err  string
  2259  	}{
  2260  		{
  2261  			cty.ListValEmpty(cty.String),
  2262  			cty.ListValEmpty(cty.String),
  2263  			"",
  2264  		},
  2265  		{
  2266  			cty.ListVal([]cty.Value{cty.StringVal("a")}),
  2267  			cty.ListVal([]cty.Value{cty.StringVal("a")}),
  2268  			"",
  2269  		},
  2270  		{
  2271  			cty.ListVal([]cty.Value{cty.StringVal("a"), cty.StringVal("b")}),
  2272  			cty.ListVal([]cty.Value{cty.StringVal("b"), cty.StringVal("a")}),
  2273  			"",
  2274  		},
  2275  		{
  2276  			cty.ListVal([]cty.Value{cty.StringVal("a"), cty.StringVal("b"), cty.StringVal("c")}),
  2277  			cty.ListVal([]cty.Value{cty.StringVal("c"), cty.StringVal("b"), cty.StringVal("a")}),
  2278  			"",
  2279  		},
  2280  		{
  2281  			cty.ListVal([]cty.Value{cty.UnknownVal(cty.String), cty.StringVal("b"), cty.StringVal("c")}),
  2282  			cty.ListVal([]cty.Value{cty.StringVal("c"), cty.StringVal("b"), cty.UnknownVal(cty.String)}),
  2283  			"",
  2284  		},
  2285  		{
  2286  			cty.EmptyTupleVal,
  2287  			cty.EmptyTupleVal,
  2288  			"",
  2289  		},
  2290  		{
  2291  			cty.TupleVal([]cty.Value{cty.StringVal("a")}),
  2292  			cty.TupleVal([]cty.Value{cty.StringVal("a")}),
  2293  			"",
  2294  		},
  2295  		{
  2296  			cty.TupleVal([]cty.Value{cty.StringVal("a"), cty.True}),
  2297  			cty.TupleVal([]cty.Value{cty.True, cty.StringVal("a")}),
  2298  			"",
  2299  		},
  2300  		{
  2301  			cty.TupleVal([]cty.Value{cty.StringVal("a"), cty.True, cty.Zero}),
  2302  			cty.TupleVal([]cty.Value{cty.Zero, cty.True, cty.StringVal("a")}),
  2303  			"",
  2304  		},
  2305  		{
  2306  			cty.SetValEmpty(cty.String),
  2307  			cty.ListValEmpty(cty.String),
  2308  			"",
  2309  		},
  2310  		{
  2311  			cty.SetVal([]cty.Value{cty.StringVal("a")}),
  2312  			cty.ListVal([]cty.Value{cty.StringVal("a")}),
  2313  			"",
  2314  		},
  2315  		{
  2316  			cty.SetVal([]cty.Value{cty.StringVal("a"), cty.StringVal("b")}),
  2317  			cty.ListVal([]cty.Value{cty.StringVal("b"), cty.StringVal("a")}), // set-of-string iterates in lexicographical order
  2318  			"",
  2319  		},
  2320  		{
  2321  			cty.SetVal([]cty.Value{cty.StringVal("b"), cty.StringVal("a"), cty.StringVal("c")}),
  2322  			cty.ListVal([]cty.Value{cty.StringVal("c"), cty.StringVal("b"), cty.StringVal("a")}), // set-of-string iterates in lexicographical order
  2323  			"",
  2324  		},
  2325  		{
  2326  			cty.StringVal("no"),
  2327  			cty.NilVal,
  2328  			"can only reverse list or tuple values, not string",
  2329  		},
  2330  		{
  2331  			cty.True,
  2332  			cty.NilVal,
  2333  			"can only reverse list or tuple values, not bool",
  2334  		},
  2335  		{
  2336  			cty.MapValEmpty(cty.String),
  2337  			cty.NilVal,
  2338  			"can only reverse list or tuple values, not map of string",
  2339  		},
  2340  		{
  2341  			cty.NullVal(cty.List(cty.String)),
  2342  			cty.NilVal,
  2343  			"argument must not be null",
  2344  		},
  2345  		{
  2346  			cty.UnknownVal(cty.List(cty.String)),
  2347  			cty.UnknownVal(cty.List(cty.String)),
  2348  			"",
  2349  		},
  2350  	}
  2351  
  2352  	for _, test := range tests {
  2353  		t.Run(fmt.Sprintf("reverse(%#v)", test.List), func(t *testing.T) {
  2354  			got, err := Reverse(test.List)
  2355  
  2356  			if test.Err != "" {
  2357  				if err == nil {
  2358  					t.Fatal("succeeded; want error")
  2359  				}
  2360  				if got, want := err.Error(), test.Err; got != want {
  2361  					t.Fatalf("wrong error\ngot:  %s\nwant: %s", got, want)
  2362  				}
  2363  				return
  2364  			} else if err != nil {
  2365  				t.Fatalf("unexpected error: %s", err)
  2366  			}
  2367  
  2368  			if !got.RawEquals(test.Want) {
  2369  				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
  2370  			}
  2371  		})
  2372  	}
  2373  
  2374  }
  2375  
  2376  func TestSetProduct(t *testing.T) {
  2377  	tests := []struct {
  2378  		Sets []cty.Value
  2379  		Want cty.Value
  2380  		Err  string
  2381  	}{
  2382  		{
  2383  			nil,
  2384  			cty.DynamicVal,
  2385  			"at least two arguments are required",
  2386  		},
  2387  		{
  2388  			[]cty.Value{
  2389  				cty.SetValEmpty(cty.String),
  2390  			},
  2391  			cty.DynamicVal,
  2392  			"at least two arguments are required",
  2393  		},
  2394  		{
  2395  			[]cty.Value{
  2396  				cty.SetValEmpty(cty.String),
  2397  				cty.StringVal("hello"),
  2398  			},
  2399  			cty.DynamicVal,
  2400  			"a set or a list is required", // this is an ArgError, so is presented against the second argument in particular
  2401  		},
  2402  		{
  2403  			[]cty.Value{
  2404  				cty.SetValEmpty(cty.String),
  2405  				cty.SetValEmpty(cty.String),
  2406  			},
  2407  			cty.SetValEmpty(cty.Tuple([]cty.Type{cty.String, cty.String})),
  2408  			"",
  2409  		},
  2410  		{
  2411  			[]cty.Value{
  2412  				cty.SetVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("stg"), cty.StringVal("prd")}),
  2413  				cty.SetVal([]cty.Value{cty.StringVal("foo"), cty.StringVal("bar")}),
  2414  			},
  2415  			cty.SetVal([]cty.Value{
  2416  				cty.TupleVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("foo")}),
  2417  				cty.TupleVal([]cty.Value{cty.StringVal("stg"), cty.StringVal("foo")}),
  2418  				cty.TupleVal([]cty.Value{cty.StringVal("prd"), cty.StringVal("foo")}),
  2419  				cty.TupleVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("bar")}),
  2420  				cty.TupleVal([]cty.Value{cty.StringVal("stg"), cty.StringVal("bar")}),
  2421  				cty.TupleVal([]cty.Value{cty.StringVal("prd"), cty.StringVal("bar")}),
  2422  			}),
  2423  			"",
  2424  		},
  2425  		{
  2426  			[]cty.Value{
  2427  				cty.ListVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("stg"), cty.StringVal("prd")}),
  2428  				cty.SetVal([]cty.Value{cty.StringVal("foo"), cty.StringVal("bar")}),
  2429  			},
  2430  			cty.SetVal([]cty.Value{
  2431  				cty.TupleVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("foo")}),
  2432  				cty.TupleVal([]cty.Value{cty.StringVal("stg"), cty.StringVal("foo")}),
  2433  				cty.TupleVal([]cty.Value{cty.StringVal("prd"), cty.StringVal("foo")}),
  2434  				cty.TupleVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("bar")}),
  2435  				cty.TupleVal([]cty.Value{cty.StringVal("stg"), cty.StringVal("bar")}),
  2436  				cty.TupleVal([]cty.Value{cty.StringVal("prd"), cty.StringVal("bar")}),
  2437  			}),
  2438  			"",
  2439  		},
  2440  		{
  2441  			[]cty.Value{
  2442  				cty.TupleVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("stg"), cty.StringVal("prd")}),
  2443  				cty.SetVal([]cty.Value{cty.StringVal("foo"), cty.StringVal("bar")}),
  2444  			},
  2445  			cty.SetVal([]cty.Value{
  2446  				cty.TupleVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("foo")}),
  2447  				cty.TupleVal([]cty.Value{cty.StringVal("stg"), cty.StringVal("foo")}),
  2448  				cty.TupleVal([]cty.Value{cty.StringVal("prd"), cty.StringVal("foo")}),
  2449  				cty.TupleVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("bar")}),
  2450  				cty.TupleVal([]cty.Value{cty.StringVal("stg"), cty.StringVal("bar")}),
  2451  				cty.TupleVal([]cty.Value{cty.StringVal("prd"), cty.StringVal("bar")}),
  2452  			}),
  2453  			"",
  2454  		},
  2455  		{
  2456  			[]cty.Value{
  2457  				cty.ListVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("stg"), cty.StringVal("prd")}),
  2458  				cty.ListVal([]cty.Value{cty.StringVal("foo"), cty.StringVal("bar")}),
  2459  			},
  2460  			cty.ListVal([]cty.Value{
  2461  				cty.TupleVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("foo")}),
  2462  				cty.TupleVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("bar")}),
  2463  				cty.TupleVal([]cty.Value{cty.StringVal("stg"), cty.StringVal("foo")}),
  2464  				cty.TupleVal([]cty.Value{cty.StringVal("stg"), cty.StringVal("bar")}),
  2465  				cty.TupleVal([]cty.Value{cty.StringVal("prd"), cty.StringVal("foo")}),
  2466  				cty.TupleVal([]cty.Value{cty.StringVal("prd"), cty.StringVal("bar")}),
  2467  			}),
  2468  			"",
  2469  		},
  2470  		{
  2471  			[]cty.Value{
  2472  				cty.ListVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("stg"), cty.StringVal("prd")}),
  2473  				cty.TupleVal([]cty.Value{cty.StringVal("foo"), cty.StringVal("bar")}),
  2474  			},
  2475  			cty.ListVal([]cty.Value{
  2476  				cty.TupleVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("foo")}),
  2477  				cty.TupleVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("bar")}),
  2478  				cty.TupleVal([]cty.Value{cty.StringVal("stg"), cty.StringVal("foo")}),
  2479  				cty.TupleVal([]cty.Value{cty.StringVal("stg"), cty.StringVal("bar")}),
  2480  				cty.TupleVal([]cty.Value{cty.StringVal("prd"), cty.StringVal("foo")}),
  2481  				cty.TupleVal([]cty.Value{cty.StringVal("prd"), cty.StringVal("bar")}),
  2482  			}),
  2483  			"",
  2484  		},
  2485  		{
  2486  			[]cty.Value{
  2487  				cty.ListVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("stg"), cty.StringVal("prd")}),
  2488  				cty.TupleVal([]cty.Value{cty.StringVal("foo"), cty.True}),
  2489  			},
  2490  			cty.ListVal([]cty.Value{
  2491  				cty.TupleVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("foo")}),
  2492  				cty.TupleVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("true")}),
  2493  				cty.TupleVal([]cty.Value{cty.StringVal("stg"), cty.StringVal("foo")}),
  2494  				cty.TupleVal([]cty.Value{cty.StringVal("stg"), cty.StringVal("true")}),
  2495  				cty.TupleVal([]cty.Value{cty.StringVal("prd"), cty.StringVal("foo")}),
  2496  				cty.TupleVal([]cty.Value{cty.StringVal("prd"), cty.StringVal("true")}),
  2497  			}),
  2498  			"",
  2499  		},
  2500  		{
  2501  			[]cty.Value{
  2502  				cty.ListVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("stg"), cty.StringVal("prd")}),
  2503  				cty.EmptyTupleVal,
  2504  			},
  2505  			cty.ListValEmpty(cty.Tuple([]cty.Type{cty.String, cty.DynamicPseudoType})),
  2506  			"",
  2507  		},
  2508  		{
  2509  			[]cty.Value{
  2510  				cty.ListVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("stg"), cty.StringVal("prd")}),
  2511  				cty.TupleVal([]cty.Value{cty.StringVal("foo"), cty.EmptyObjectVal}),
  2512  			},
  2513  			cty.DynamicVal,
  2514  			"all elements must be of the same type", // this is an ArgError for the second argument
  2515  		},
  2516  		{
  2517  			[]cty.Value{
  2518  				cty.SetVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("stg"), cty.StringVal("prd")}),
  2519  				cty.SetVal([]cty.Value{cty.StringVal("foo"), cty.StringVal("bar")}),
  2520  				cty.SetVal([]cty.Value{cty.StringVal("baz")}),
  2521  			},
  2522  			cty.SetVal([]cty.Value{
  2523  				cty.TupleVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("foo"), cty.StringVal("baz")}),
  2524  				cty.TupleVal([]cty.Value{cty.StringVal("stg"), cty.StringVal("foo"), cty.StringVal("baz")}),
  2525  				cty.TupleVal([]cty.Value{cty.StringVal("prd"), cty.StringVal("foo"), cty.StringVal("baz")}),
  2526  				cty.TupleVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("bar"), cty.StringVal("baz")}),
  2527  				cty.TupleVal([]cty.Value{cty.StringVal("stg"), cty.StringVal("bar"), cty.StringVal("baz")}),
  2528  				cty.TupleVal([]cty.Value{cty.StringVal("prd"), cty.StringVal("bar"), cty.StringVal("baz")}),
  2529  			}),
  2530  			"",
  2531  		},
  2532  		{
  2533  			[]cty.Value{
  2534  				cty.SetVal([]cty.Value{cty.StringVal("dev"), cty.StringVal("stg"), cty.StringVal("prd")}),
  2535  				cty.SetValEmpty(cty.String),
  2536  			},
  2537  			cty.SetValEmpty(cty.Tuple([]cty.Type{cty.String, cty.String})),
  2538  			"",
  2539  		},
  2540  		{
  2541  			[]cty.Value{
  2542  				cty.SetVal([]cty.Value{cty.StringVal("foo")}),
  2543  				cty.SetVal([]cty.Value{cty.StringVal("bar")}),
  2544  			},
  2545  			cty.SetVal([]cty.Value{
  2546  				cty.TupleVal([]cty.Value{cty.StringVal("foo"), cty.StringVal("bar")}),
  2547  			}),
  2548  			"",
  2549  		},
  2550  		{
  2551  			[]cty.Value{
  2552  				cty.TupleVal([]cty.Value{cty.StringVal("foo")}),
  2553  				cty.TupleVal([]cty.Value{cty.StringVal("bar")}),
  2554  			},
  2555  			cty.ListVal([]cty.Value{
  2556  				cty.TupleVal([]cty.Value{cty.StringVal("foo"), cty.StringVal("bar")}),
  2557  			}),
  2558  			"",
  2559  		},
  2560  		{
  2561  			[]cty.Value{
  2562  				cty.SetVal([]cty.Value{cty.StringVal("foo")}),
  2563  				cty.SetVal([]cty.Value{cty.DynamicVal}),
  2564  			},
  2565  			cty.SetVal([]cty.Value{
  2566  				cty.TupleVal([]cty.Value{cty.StringVal("foo"), cty.DynamicVal}),
  2567  			}),
  2568  			"",
  2569  		},
  2570  		{
  2571  			[]cty.Value{
  2572  				cty.SetVal([]cty.Value{cty.StringVal("foo")}),
  2573  				cty.SetVal([]cty.Value{cty.True, cty.DynamicVal}),
  2574  			},
  2575  			cty.SetVal([]cty.Value{
  2576  				cty.TupleVal([]cty.Value{cty.StringVal("foo"), cty.True}),
  2577  				cty.TupleVal([]cty.Value{cty.StringVal("foo"), cty.UnknownVal(cty.Bool)}),
  2578  			}),
  2579  			"",
  2580  		},
  2581  		{
  2582  			[]cty.Value{
  2583  				cty.UnknownVal(cty.Set(cty.String)),
  2584  				cty.SetVal([]cty.Value{cty.True, cty.False}),
  2585  			},
  2586  			cty.UnknownVal(cty.Set(cty.Tuple([]cty.Type{cty.String, cty.Bool}))),
  2587  			"",
  2588  		},
  2589  	}
  2590  
  2591  	for _, test := range tests {
  2592  		t.Run(fmt.Sprintf("setproduct(%#v)", test.Sets), func(t *testing.T) {
  2593  			got, err := SetProduct(test.Sets...)
  2594  
  2595  			if test.Err != "" {
  2596  				if err == nil {
  2597  					t.Fatal("succeeded; want error")
  2598  				}
  2599  				if got, want := err.Error(), test.Err; got != want {
  2600  					t.Fatalf("wrong error\ngot:  %s\nwant: %s", got, want)
  2601  				}
  2602  				return
  2603  			} else if err != nil {
  2604  				t.Fatalf("unexpected error: %s", err)
  2605  			}
  2606  
  2607  			if !got.RawEquals(test.Want) {
  2608  				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
  2609  			}
  2610  		})
  2611  	}
  2612  
  2613  }
  2614  
  2615  func TestSlice(t *testing.T) {
  2616  	listOfStrings := cty.ListVal([]cty.Value{
  2617  		cty.StringVal("a"),
  2618  		cty.StringVal("b"),
  2619  	})
  2620  	listOfInts := cty.ListVal([]cty.Value{
  2621  		cty.NumberIntVal(1),
  2622  		cty.NumberIntVal(2),
  2623  	})
  2624  	listWithUnknowns := cty.ListVal([]cty.Value{
  2625  		cty.StringVal("a"),
  2626  		cty.UnknownVal(cty.String),
  2627  	})
  2628  	tuple := cty.TupleVal([]cty.Value{
  2629  		cty.StringVal("a"),
  2630  		cty.NumberIntVal(1),
  2631  		cty.UnknownVal(cty.List(cty.String)),
  2632  	})
  2633  	tests := []struct {
  2634  		List       cty.Value
  2635  		StartIndex cty.Value
  2636  		EndIndex   cty.Value
  2637  		Want       cty.Value
  2638  		Err        bool
  2639  	}{
  2640  		{ // normal usage
  2641  			listOfStrings,
  2642  			cty.NumberIntVal(1),
  2643  			cty.NumberIntVal(2),
  2644  			cty.ListVal([]cty.Value{
  2645  				cty.StringVal("b"),
  2646  			}),
  2647  			false,
  2648  		},
  2649  		{ // slice only an unknown value
  2650  			listWithUnknowns,
  2651  			cty.NumberIntVal(1),
  2652  			cty.NumberIntVal(2),
  2653  			cty.ListVal([]cty.Value{cty.UnknownVal(cty.String)}),
  2654  			false,
  2655  		},
  2656  		{ // slice multiple values, which contain an unknown
  2657  			listWithUnknowns,
  2658  			cty.NumberIntVal(0),
  2659  			cty.NumberIntVal(2),
  2660  			listWithUnknowns,
  2661  			false,
  2662  		},
  2663  		{ // an unknown list should be slicable, returning an unknown list
  2664  			cty.UnknownVal(cty.List(cty.String)),
  2665  			cty.NumberIntVal(0),
  2666  			cty.NumberIntVal(2),
  2667  			cty.UnknownVal(cty.List(cty.String)),
  2668  			false,
  2669  		},
  2670  		{ // normal usage
  2671  			listOfInts,
  2672  			cty.NumberIntVal(1),
  2673  			cty.NumberIntVal(2),
  2674  			cty.ListVal([]cty.Value{
  2675  				cty.NumberIntVal(2),
  2676  			}),
  2677  			false,
  2678  		},
  2679  		{ // empty result
  2680  			listOfStrings,
  2681  			cty.NumberIntVal(1),
  2682  			cty.NumberIntVal(1),
  2683  			cty.ListValEmpty(cty.String),
  2684  			false,
  2685  		},
  2686  		{ // index out of bounds
  2687  			listOfStrings,
  2688  			cty.NumberIntVal(1),
  2689  			cty.NumberIntVal(4),
  2690  			cty.NilVal,
  2691  			true,
  2692  		},
  2693  		{ // StartIndex index > EndIndex
  2694  			listOfStrings,
  2695  			cty.NumberIntVal(2),
  2696  			cty.NumberIntVal(1),
  2697  			cty.NilVal,
  2698  			true,
  2699  		},
  2700  		{ // negative StartIndex
  2701  			listOfStrings,
  2702  			cty.NumberIntVal(-1),
  2703  			cty.NumberIntVal(0),
  2704  			cty.NilVal,
  2705  			true,
  2706  		},
  2707  		{ // sets are not slice-able
  2708  			cty.SetVal([]cty.Value{
  2709  				cty.StringVal("x"),
  2710  				cty.StringVal("y"),
  2711  			}),
  2712  			cty.NumberIntVal(0),
  2713  			cty.NumberIntVal(0),
  2714  			cty.NilVal,
  2715  			true,
  2716  		},
  2717  		{ // tuple slice
  2718  			tuple,
  2719  			cty.NumberIntVal(1),
  2720  			cty.NumberIntVal(3),
  2721  			cty.TupleVal([]cty.Value{
  2722  				cty.NumberIntVal(1),
  2723  				cty.UnknownVal(cty.List(cty.String)),
  2724  			}),
  2725  			false,
  2726  		},
  2727  		{ // unknown tuple slice
  2728  			cty.UnknownVal(tuple.Type()),
  2729  			cty.NumberIntVal(1),
  2730  			cty.NumberIntVal(3),
  2731  			cty.UnknownVal(cty.Tuple([]cty.Type{
  2732  				cty.Number,
  2733  				cty.List(cty.String),
  2734  			})),
  2735  			false,
  2736  		},
  2737  		{ // empty list slice
  2738  			listOfStrings,
  2739  			cty.NumberIntVal(2),
  2740  			cty.NumberIntVal(2),
  2741  			cty.ListValEmpty(cty.String),
  2742  			false,
  2743  		},
  2744  		{ // empty tuple slice
  2745  			tuple,
  2746  			cty.NumberIntVal(3),
  2747  			cty.NumberIntVal(3),
  2748  			cty.EmptyTupleVal,
  2749  			false,
  2750  		},
  2751  		{ // list with unknown start offset
  2752  			listOfStrings,
  2753  			cty.UnknownVal(cty.Number),
  2754  			cty.NumberIntVal(2),
  2755  			cty.UnknownVal(cty.List(cty.String)),
  2756  			false,
  2757  		},
  2758  		{ // list with unknown start offset but end out of bounds
  2759  			listOfStrings,
  2760  			cty.UnknownVal(cty.Number),
  2761  			cty.NumberIntVal(200),
  2762  			cty.UnknownVal(cty.List(cty.String)),
  2763  			true,
  2764  		},
  2765  		{ // list with unknown start offset but end < 0
  2766  			listOfStrings,
  2767  			cty.UnknownVal(cty.Number),
  2768  			cty.NumberIntVal(-4),
  2769  			cty.UnknownVal(cty.List(cty.String)),
  2770  			true,
  2771  		},
  2772  		{ // list with unknown end offset
  2773  			listOfStrings,
  2774  			cty.UnknownVal(cty.Number),
  2775  			cty.NumberIntVal(0),
  2776  			cty.UnknownVal(cty.List(cty.String)),
  2777  			false,
  2778  		},
  2779  		{ // list with unknown end offset but start out of bounds
  2780  			listOfStrings,
  2781  			cty.UnknownVal(cty.Number),
  2782  			cty.NumberIntVal(200),
  2783  			cty.UnknownVal(cty.List(cty.String)),
  2784  			true,
  2785  		},
  2786  		{ // list with unknown end offset but start < 0
  2787  			listOfStrings,
  2788  			cty.UnknownVal(cty.Number),
  2789  			cty.NumberIntVal(-3),
  2790  			cty.UnknownVal(cty.List(cty.String)),
  2791  			true,
  2792  		},
  2793  		{ // tuple slice with unknown start offset
  2794  			tuple,
  2795  			cty.UnknownVal(cty.Number),
  2796  			cty.NumberIntVal(3),
  2797  			cty.DynamicVal,
  2798  			false,
  2799  		},
  2800  		{ // tuple slice with unknown start offset but end out of bounds
  2801  			tuple,
  2802  			cty.UnknownVal(cty.Number),
  2803  			cty.NumberIntVal(200),
  2804  			cty.DynamicVal,
  2805  			true,
  2806  		},
  2807  		{ // tuple slice with unknown start offset but end < 0
  2808  			tuple,
  2809  			cty.UnknownVal(cty.Number),
  2810  			cty.NumberIntVal(-20),
  2811  			cty.DynamicVal,
  2812  			true,
  2813  		},
  2814  		{ // tuple slice with unknown end offset
  2815  			tuple,
  2816  			cty.NumberIntVal(0),
  2817  			cty.UnknownVal(cty.Number),
  2818  			cty.DynamicVal,
  2819  			false,
  2820  		},
  2821  		{ // tuple slice with unknown end offset but start < 0
  2822  			tuple,
  2823  			cty.NumberIntVal(-2),
  2824  			cty.UnknownVal(cty.Number),
  2825  			cty.DynamicVal,
  2826  			true,
  2827  		},
  2828  		{ // tuple slice with unknown end offset but start out of bounds
  2829  			tuple,
  2830  			cty.NumberIntVal(200),
  2831  			cty.UnknownVal(cty.Number),
  2832  			cty.DynamicVal,
  2833  			true,
  2834  		},
  2835  	}
  2836  
  2837  	for i, test := range tests {
  2838  		t.Run(fmt.Sprintf("%d-slice(%#v, %#v, %#v)", i, test.List, test.StartIndex, test.EndIndex), func(t *testing.T) {
  2839  			got, err := Slice(test.List, test.StartIndex, test.EndIndex)
  2840  
  2841  			if test.Err {
  2842  				if err == nil {
  2843  					t.Fatal("succeeded; want error")
  2844  				}
  2845  				return
  2846  			} else if err != nil {
  2847  				t.Fatalf("unexpected error: %s", err)
  2848  			}
  2849  
  2850  			if !got.RawEquals(test.Want) {
  2851  				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
  2852  			}
  2853  		})
  2854  	}
  2855  }
  2856  
  2857  func TestTranspose(t *testing.T) {
  2858  	tests := []struct {
  2859  		Values cty.Value
  2860  		Want   cty.Value
  2861  		Err    bool
  2862  	}{
  2863  		{
  2864  			cty.MapVal(map[string]cty.Value{
  2865  				"key1": cty.ListVal([]cty.Value{
  2866  					cty.StringVal("a"),
  2867  					cty.StringVal("b"),
  2868  				}),
  2869  				"key2": cty.ListVal([]cty.Value{
  2870  					cty.StringVal("a"),
  2871  					cty.StringVal("b"),
  2872  					cty.StringVal("c"),
  2873  				}),
  2874  				"key3": cty.ListVal([]cty.Value{
  2875  					cty.StringVal("c"),
  2876  				}),
  2877  				"key4": cty.ListValEmpty(cty.String),
  2878  			}),
  2879  			cty.MapVal(map[string]cty.Value{
  2880  				"a": cty.ListVal([]cty.Value{
  2881  					cty.StringVal("key1"),
  2882  					cty.StringVal("key2"),
  2883  				}),
  2884  				"b": cty.ListVal([]cty.Value{
  2885  					cty.StringVal("key1"),
  2886  					cty.StringVal("key2"),
  2887  				}),
  2888  				"c": cty.ListVal([]cty.Value{
  2889  					cty.StringVal("key2"),
  2890  					cty.StringVal("key3"),
  2891  				}),
  2892  			}),
  2893  			false,
  2894  		},
  2895  		{ // map - unknown value
  2896  			cty.MapVal(map[string]cty.Value{
  2897  				"key1": cty.UnknownVal(cty.List(cty.String)),
  2898  			}),
  2899  			cty.UnknownVal(cty.Map(cty.List(cty.String))),
  2900  			false,
  2901  		},
  2902  		{ // bad map - empty value
  2903  			cty.MapVal(map[string]cty.Value{
  2904  				"key1": cty.ListValEmpty(cty.String),
  2905  			}),
  2906  			cty.NilVal,
  2907  			true,
  2908  		},
  2909  		{ // bad map - value not a list
  2910  			cty.MapVal(map[string]cty.Value{
  2911  				"key1": cty.StringVal("a"),
  2912  			}),
  2913  			cty.NilVal,
  2914  			true,
  2915  		},
  2916  	}
  2917  
  2918  	for _, test := range tests {
  2919  		t.Run(fmt.Sprintf("transpose(%#v)", test.Values), func(t *testing.T) {
  2920  			got, err := Transpose(test.Values)
  2921  
  2922  			if test.Err {
  2923  				if err == nil {
  2924  					t.Fatal("succeeded; want error")
  2925  				}
  2926  				return
  2927  			} else if err != nil {
  2928  				t.Fatalf("unexpected error: %s", err)
  2929  			}
  2930  
  2931  			if !got.RawEquals(test.Want) {
  2932  				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
  2933  			}
  2934  		})
  2935  	}
  2936  }
  2937  
  2938  func TestValues(t *testing.T) {
  2939  	tests := []struct {
  2940  		Values cty.Value
  2941  		Want   cty.Value
  2942  		Err    bool
  2943  	}{
  2944  		{
  2945  			cty.MapVal(map[string]cty.Value{
  2946  				"hello":  cty.StringVal("world"),
  2947  				"what's": cty.StringVal("up"),
  2948  			}),
  2949  			cty.ListVal([]cty.Value{
  2950  				cty.StringVal("world"),
  2951  				cty.StringVal("up"),
  2952  			}),
  2953  			false,
  2954  		},
  2955  		{
  2956  			cty.ObjectVal(map[string]cty.Value{
  2957  				"what's": cty.StringVal("up"),
  2958  				"hello":  cty.StringVal("world"),
  2959  			}),
  2960  			cty.TupleVal([]cty.Value{
  2961  				cty.StringVal("world"),
  2962  				cty.StringVal("up"),
  2963  			}),
  2964  			false,
  2965  		},
  2966  		{ // empty object
  2967  			cty.EmptyObjectVal,
  2968  			cty.EmptyTupleVal,
  2969  			false,
  2970  		},
  2971  		{
  2972  			cty.UnknownVal(cty.Object(map[string]cty.Type{
  2973  				"what's": cty.String,
  2974  				"hello":  cty.Bool,
  2975  			})),
  2976  			cty.UnknownVal(cty.Tuple([]cty.Type{
  2977  				cty.Bool,
  2978  				cty.String,
  2979  			})),
  2980  			false,
  2981  		},
  2982  		{ // note ordering: keys are sorted first
  2983  			cty.MapVal(map[string]cty.Value{
  2984  				"hello":   cty.NumberIntVal(1),
  2985  				"goodbye": cty.NumberIntVal(42),
  2986  			}),
  2987  			cty.ListVal([]cty.Value{
  2988  				cty.NumberIntVal(42),
  2989  				cty.NumberIntVal(1),
  2990  			}),
  2991  			false,
  2992  		},
  2993  		{ // map of lists
  2994  			cty.MapVal(map[string]cty.Value{
  2995  				"hello":  cty.ListVal([]cty.Value{cty.StringVal("world")}),
  2996  				"what's": cty.ListVal([]cty.Value{cty.StringVal("up")}),
  2997  			}),
  2998  			cty.ListVal([]cty.Value{
  2999  				cty.ListVal([]cty.Value{cty.StringVal("world")}),
  3000  				cty.ListVal([]cty.Value{cty.StringVal("up")}),
  3001  			}),
  3002  			false,
  3003  		},
  3004  		{ // map with unknowns
  3005  			cty.MapVal(map[string]cty.Value{
  3006  				"hello":  cty.ListVal([]cty.Value{cty.StringVal("world")}),
  3007  				"what's": cty.UnknownVal(cty.List(cty.String)),
  3008  			}),
  3009  			cty.ListVal([]cty.Value{
  3010  				cty.ListVal([]cty.Value{cty.StringVal("world")}),
  3011  				cty.UnknownVal(cty.List(cty.String)),
  3012  			}),
  3013  			false,
  3014  		},
  3015  		{ // empty m
  3016  			cty.MapValEmpty(cty.DynamicPseudoType),
  3017  			cty.ListValEmpty(cty.DynamicPseudoType),
  3018  			false,
  3019  		},
  3020  		{ // unknown m
  3021  			cty.UnknownVal(cty.Map(cty.String)),
  3022  			cty.UnknownVal(cty.List(cty.String)),
  3023  			false,
  3024  		},
  3025  	}
  3026  
  3027  	for _, test := range tests {
  3028  		t.Run(fmt.Sprintf("values(%#v)", test.Values), func(t *testing.T) {
  3029  			got, err := Values(test.Values)
  3030  
  3031  			if test.Err {
  3032  				if err == nil {
  3033  					t.Fatal("succeeded; want error")
  3034  				}
  3035  				return
  3036  			} else if err != nil {
  3037  				t.Fatalf("unexpected error: %s", err)
  3038  			}
  3039  
  3040  			if !got.RawEquals(test.Want) {
  3041  				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
  3042  			}
  3043  		})
  3044  	}
  3045  }
  3046  
  3047  func TestZipmap(t *testing.T) {
  3048  	list1 := cty.ListVal([]cty.Value{
  3049  		cty.StringVal("hello"),
  3050  		cty.StringVal("world"),
  3051  	})
  3052  	list2 := cty.ListVal([]cty.Value{
  3053  		cty.StringVal("bar"),
  3054  		cty.StringVal("baz"),
  3055  	})
  3056  	list3 := cty.ListVal([]cty.Value{
  3057  		cty.StringVal("hello"),
  3058  		cty.StringVal("there"),
  3059  		cty.StringVal("world"),
  3060  	})
  3061  	list4 := cty.ListVal([]cty.Value{
  3062  		cty.NumberIntVal(1),
  3063  		cty.NumberIntVal(42),
  3064  	})
  3065  	list5 := cty.ListVal([]cty.Value{
  3066  		cty.ListVal([]cty.Value{
  3067  			cty.StringVal("bar"),
  3068  		}),
  3069  		cty.ListVal([]cty.Value{
  3070  			cty.StringVal("baz"),
  3071  		}),
  3072  	})
  3073  	tests := []struct {
  3074  		Keys   cty.Value
  3075  		Values cty.Value
  3076  		Want   cty.Value
  3077  		Err    bool
  3078  	}{
  3079  		{
  3080  			list1,
  3081  			list2,
  3082  			cty.MapVal(map[string]cty.Value{
  3083  				"hello": cty.StringVal("bar"),
  3084  				"world": cty.StringVal("baz"),
  3085  			}),
  3086  			false,
  3087  		},
  3088  		{
  3089  			list1,
  3090  			list4,
  3091  			cty.MapVal(map[string]cty.Value{
  3092  				"hello": cty.NumberIntVal(1),
  3093  				"world": cty.NumberIntVal(42),
  3094  			}),
  3095  			false,
  3096  		},
  3097  		{ // length mismatch
  3098  			list1,
  3099  			list3,
  3100  			cty.NilVal,
  3101  			true,
  3102  		},
  3103  		{ // map of lists
  3104  			list1,
  3105  			list5,
  3106  			cty.MapVal(map[string]cty.Value{
  3107  				"hello": cty.ListVal([]cty.Value{cty.StringVal("bar")}),
  3108  				"world": cty.ListVal([]cty.Value{cty.StringVal("baz")}),
  3109  			}),
  3110  			false,
  3111  		},
  3112  		{ // tuple values produce object
  3113  			cty.ListVal([]cty.Value{
  3114  				cty.StringVal("hello"),
  3115  				cty.StringVal("world"),
  3116  			}),
  3117  			cty.TupleVal([]cty.Value{
  3118  				cty.StringVal("bar"),
  3119  				cty.UnknownVal(cty.Bool),
  3120  			}),
  3121  			cty.ObjectVal(map[string]cty.Value{
  3122  				"hello": cty.StringVal("bar"),
  3123  				"world": cty.UnknownVal(cty.Bool),
  3124  			}),
  3125  			false,
  3126  		},
  3127  		{ // empty tuple produces empty object
  3128  			cty.ListValEmpty(cty.String),
  3129  			cty.EmptyTupleVal,
  3130  			cty.EmptyObjectVal,
  3131  			false,
  3132  		},
  3133  		{ // tuple with any unknown keys produces DynamicVal
  3134  			cty.ListVal([]cty.Value{
  3135  				cty.StringVal("hello"),
  3136  				cty.UnknownVal(cty.String),
  3137  			}),
  3138  			cty.TupleVal([]cty.Value{
  3139  				cty.StringVal("bar"),
  3140  				cty.True,
  3141  			}),
  3142  			cty.DynamicVal,
  3143  			false,
  3144  		},
  3145  		{ // tuple with all keys unknown produces DynamicVal
  3146  			cty.UnknownVal(cty.List(cty.String)),
  3147  			cty.TupleVal([]cty.Value{
  3148  				cty.StringVal("bar"),
  3149  				cty.True,
  3150  			}),
  3151  			cty.DynamicVal,
  3152  			false,
  3153  		},
  3154  		{ // list with all keys unknown produces correctly-typed unknown map
  3155  			cty.UnknownVal(cty.List(cty.String)),
  3156  			cty.ListVal([]cty.Value{
  3157  				cty.StringVal("bar"),
  3158  				cty.StringVal("baz"),
  3159  			}),
  3160  			cty.UnknownVal(cty.Map(cty.String)),
  3161  			false,
  3162  		},
  3163  		{ // unknown tuple as values produces correctly-typed unknown object
  3164  			cty.ListVal([]cty.Value{
  3165  				cty.StringVal("hello"),
  3166  				cty.StringVal("world"),
  3167  			}),
  3168  			cty.UnknownVal(cty.Tuple([]cty.Type{
  3169  				cty.String,
  3170  				cty.Bool,
  3171  			})),
  3172  			cty.UnknownVal(cty.Object(map[string]cty.Type{
  3173  				"hello": cty.String,
  3174  				"world": cty.Bool,
  3175  			})),
  3176  			false,
  3177  		},
  3178  		{ // unknown list as values produces correctly-typed unknown map
  3179  			cty.ListVal([]cty.Value{
  3180  				cty.StringVal("hello"),
  3181  				cty.StringVal("world"),
  3182  			}),
  3183  			cty.UnknownVal(cty.List(cty.String)),
  3184  			cty.UnknownVal(cty.Map(cty.String)),
  3185  			false,
  3186  		},
  3187  		{ // empty input returns an empty map
  3188  			cty.ListValEmpty(cty.String),
  3189  			cty.ListValEmpty(cty.String),
  3190  			cty.MapValEmpty(cty.String),
  3191  			false,
  3192  		},
  3193  		{ // keys cannot be a list of lists
  3194  			list5,
  3195  			list1,
  3196  			cty.NilVal,
  3197  			true,
  3198  		},
  3199  	}
  3200  
  3201  	for _, test := range tests {
  3202  		t.Run(fmt.Sprintf("zipmap(%#v, %#v)", test.Keys, test.Values), func(t *testing.T) {
  3203  			got, err := Zipmap(test.Keys, test.Values)
  3204  
  3205  			if test.Err {
  3206  				if err == nil {
  3207  					t.Fatal("succeeded; want error")
  3208  				}
  3209  				return
  3210  			} else if err != nil {
  3211  				t.Fatalf("unexpected error: %s", err)
  3212  			}
  3213  
  3214  			if !got.RawEquals(test.Want) {
  3215  				t.Errorf("wrong result\n\nkeys:   %#v\nvalues: %#v\ngot:    %#v\nwant:   %#v", test.Keys, test.Values, got, test.Want)
  3216  			}
  3217  		})
  3218  	}
  3219  }