github.com/terramate-io/tf@v0.0.0-20230830114523-fce866b4dfcd/configs/hcl2shim/values_equiv_test.go (about)

     1  // Copyright (c) HashiCorp, Inc.
     2  // SPDX-License-Identifier: MPL-2.0
     3  
     4  package hcl2shim
     5  
     6  import (
     7  	"fmt"
     8  	"math/big"
     9  	"testing"
    10  
    11  	"github.com/zclconf/go-cty/cty"
    12  )
    13  
    14  func TestValuesSDKEquivalent(t *testing.T) {
    15  	piBig, _, err := big.ParseFloat("3.14159265358979323846264338327950288419716939937510582097494459", 10, 512, big.ToZero)
    16  	if err != nil {
    17  		t.Fatal(err)
    18  	}
    19  	pi64, _ := piBig.Float64()
    20  
    21  	tests := []struct {
    22  		A, B cty.Value
    23  		Want bool
    24  	}{
    25  		// Strings
    26  		{
    27  			cty.StringVal("hello"),
    28  			cty.StringVal("hello"),
    29  			true,
    30  		},
    31  		{
    32  			cty.StringVal("hello"),
    33  			cty.StringVal("world"),
    34  			false,
    35  		},
    36  		{
    37  			cty.StringVal("hello"),
    38  			cty.StringVal(""),
    39  			false,
    40  		},
    41  		{
    42  			cty.NullVal(cty.String),
    43  			cty.StringVal(""),
    44  			true,
    45  		},
    46  
    47  		// Numbers
    48  		{
    49  			cty.NumberIntVal(1),
    50  			cty.NumberIntVal(1),
    51  			true,
    52  		},
    53  		{
    54  			cty.NumberIntVal(1),
    55  			cty.NumberIntVal(2),
    56  			false,
    57  		},
    58  		{
    59  			cty.NumberIntVal(1),
    60  			cty.Zero,
    61  			false,
    62  		},
    63  		{
    64  			cty.NullVal(cty.Number),
    65  			cty.Zero,
    66  			true,
    67  		},
    68  		{
    69  			cty.NumberVal(piBig),
    70  			cty.Zero,
    71  			false,
    72  		},
    73  		{
    74  			cty.NumberFloatVal(pi64),
    75  			cty.Zero,
    76  			false,
    77  		},
    78  		{
    79  			cty.NumberFloatVal(pi64),
    80  			cty.NumberVal(piBig),
    81  			true,
    82  		},
    83  
    84  		// Bools
    85  		{
    86  			cty.True,
    87  			cty.True,
    88  			true,
    89  		},
    90  		{
    91  			cty.True,
    92  			cty.False,
    93  			false,
    94  		},
    95  		{
    96  			cty.NullVal(cty.Bool),
    97  			cty.False,
    98  			true,
    99  		},
   100  
   101  		// Mixed primitives
   102  		{
   103  			cty.StringVal("hello"),
   104  			cty.False,
   105  			false,
   106  		},
   107  		{
   108  			cty.StringVal(""),
   109  			cty.False,
   110  			true,
   111  		},
   112  		{
   113  			cty.NumberIntVal(0),
   114  			cty.False,
   115  			true,
   116  		},
   117  		{
   118  			cty.StringVal(""),
   119  			cty.NumberIntVal(0),
   120  			true,
   121  		},
   122  		{
   123  			cty.NullVal(cty.Bool),
   124  			cty.NullVal(cty.Number),
   125  			true,
   126  		},
   127  		{
   128  			cty.StringVal(""),
   129  			cty.NullVal(cty.Number),
   130  			true,
   131  		},
   132  
   133  		// Lists
   134  		{
   135  			cty.ListValEmpty(cty.String),
   136  			cty.ListValEmpty(cty.String),
   137  			true,
   138  		},
   139  		{
   140  			cty.ListValEmpty(cty.String),
   141  			cty.NullVal(cty.List(cty.String)),
   142  			true,
   143  		},
   144  		{
   145  			cty.ListVal([]cty.Value{cty.StringVal("hello")}),
   146  			cty.ListVal([]cty.Value{cty.StringVal("hello"), cty.StringVal("hello")}),
   147  			false,
   148  		},
   149  		{
   150  			cty.ListVal([]cty.Value{cty.StringVal("hello")}),
   151  			cty.ListValEmpty(cty.String),
   152  			false,
   153  		},
   154  		{
   155  			cty.ListVal([]cty.Value{cty.StringVal("hello")}),
   156  			cty.ListVal([]cty.Value{cty.StringVal("hello")}),
   157  			true,
   158  		},
   159  		{
   160  			cty.ListVal([]cty.Value{cty.StringVal("hello")}),
   161  			cty.ListVal([]cty.Value{cty.StringVal("world")}),
   162  			false,
   163  		},
   164  		{
   165  			cty.ListVal([]cty.Value{cty.NullVal(cty.String)}),
   166  			cty.ListVal([]cty.Value{cty.StringVal("")}),
   167  			true,
   168  		},
   169  
   170  		// Tuples
   171  		{
   172  			cty.EmptyTupleVal,
   173  			cty.EmptyTupleVal,
   174  			true,
   175  		},
   176  		{
   177  			cty.EmptyTupleVal,
   178  			cty.NullVal(cty.EmptyTuple),
   179  			true,
   180  		},
   181  		{
   182  			cty.TupleVal([]cty.Value{cty.StringVal("hello")}),
   183  			cty.TupleVal([]cty.Value{cty.StringVal("hello"), cty.StringVal("hello")}),
   184  			false,
   185  		},
   186  		{
   187  			cty.TupleVal([]cty.Value{cty.StringVal("hello")}),
   188  			cty.EmptyTupleVal,
   189  			false,
   190  		},
   191  		{
   192  			cty.TupleVal([]cty.Value{cty.StringVal("hello")}),
   193  			cty.TupleVal([]cty.Value{cty.StringVal("hello")}),
   194  			true,
   195  		},
   196  		{
   197  			cty.TupleVal([]cty.Value{cty.StringVal("hello")}),
   198  			cty.TupleVal([]cty.Value{cty.StringVal("world")}),
   199  			false,
   200  		},
   201  		{
   202  			cty.TupleVal([]cty.Value{cty.NullVal(cty.String)}),
   203  			cty.TupleVal([]cty.Value{cty.StringVal("")}),
   204  			true,
   205  		},
   206  
   207  		// Sets
   208  		{
   209  			cty.SetValEmpty(cty.String),
   210  			cty.SetValEmpty(cty.String),
   211  			true,
   212  		},
   213  		{
   214  			cty.SetValEmpty(cty.String),
   215  			cty.NullVal(cty.Set(cty.String)),
   216  			true,
   217  		},
   218  		{
   219  			cty.SetVal([]cty.Value{cty.StringVal("hello")}),
   220  			cty.SetValEmpty(cty.String),
   221  			false,
   222  		},
   223  		{
   224  			cty.SetVal([]cty.Value{cty.StringVal("hello")}),
   225  			cty.SetVal([]cty.Value{cty.StringVal("hello")}),
   226  			true,
   227  		},
   228  		{
   229  			cty.SetVal([]cty.Value{cty.StringVal("hello")}),
   230  			cty.SetVal([]cty.Value{cty.StringVal("world")}),
   231  			false,
   232  		},
   233  		{
   234  			cty.SetVal([]cty.Value{cty.NullVal(cty.String)}),
   235  			cty.SetVal([]cty.Value{cty.StringVal("")}),
   236  			true,
   237  		},
   238  		{
   239  			cty.SetVal([]cty.Value{
   240  				cty.NullVal(cty.String),
   241  				cty.StringVal(""),
   242  			}),
   243  			cty.SetVal([]cty.Value{
   244  				cty.NullVal(cty.String),
   245  			}),
   246  			false, // because the element count is different
   247  		},
   248  		{
   249  			cty.SetVal([]cty.Value{
   250  				cty.ObjectVal(map[string]cty.Value{
   251  					"a": cty.StringVal(""),
   252  					"b": cty.StringVal(""),
   253  				}),
   254  				cty.ObjectVal(map[string]cty.Value{
   255  					"a": cty.NullVal(cty.String),
   256  					"b": cty.StringVal(""),
   257  				}),
   258  			}),
   259  			cty.SetVal([]cty.Value{
   260  				cty.ObjectVal(map[string]cty.Value{
   261  					"a": cty.StringVal(""),
   262  					"b": cty.StringVal(""),
   263  				}),
   264  				cty.ObjectVal(map[string]cty.Value{
   265  					"a": cty.StringVal(""),
   266  					"b": cty.NullVal(cty.String),
   267  				}),
   268  			}),
   269  			true,
   270  		},
   271  		{
   272  			cty.SetVal([]cty.Value{
   273  				cty.ObjectVal(map[string]cty.Value{
   274  					"a": cty.StringVal("boop"),
   275  					"b": cty.StringVal(""),
   276  				}),
   277  				cty.ObjectVal(map[string]cty.Value{
   278  					"a": cty.NullVal(cty.String),
   279  					"b": cty.StringVal(""),
   280  				}),
   281  			}),
   282  			cty.SetVal([]cty.Value{
   283  				cty.ObjectVal(map[string]cty.Value{
   284  					"a": cty.StringVal("beep"),
   285  					"b": cty.StringVal(""),
   286  				}),
   287  				cty.ObjectVal(map[string]cty.Value{
   288  					"a": cty.StringVal(""),
   289  					"b": cty.NullVal(cty.String),
   290  				}),
   291  			}),
   292  			false,
   293  		},
   294  		{
   295  			cty.SetVal([]cty.Value{cty.ObjectVal(map[string]cty.Value{
   296  				"list": cty.ListValEmpty(cty.String),
   297  				"list_block": cty.ListVal([]cty.Value{
   298  					cty.ObjectVal(map[string]cty.Value{
   299  						"unused": cty.StringVal(""),
   300  					}),
   301  				}),
   302  			})}),
   303  			cty.SetVal([]cty.Value{cty.ObjectVal(map[string]cty.Value{
   304  				"list": cty.ListValEmpty(cty.String),
   305  				"list_block": cty.ListVal([]cty.Value{
   306  					cty.ObjectVal(map[string]cty.Value{
   307  						"unused": cty.NullVal(cty.String),
   308  					}),
   309  				}),
   310  			})}),
   311  			true,
   312  		},
   313  
   314  		// Maps
   315  		{
   316  			cty.MapValEmpty(cty.String),
   317  			cty.MapValEmpty(cty.String),
   318  			true,
   319  		},
   320  		{
   321  			cty.MapValEmpty(cty.String),
   322  			cty.NullVal(cty.Map(cty.String)),
   323  			true,
   324  		},
   325  		{
   326  			cty.MapVal(map[string]cty.Value{"hi": cty.StringVal("hello")}),
   327  			cty.MapVal(map[string]cty.Value{"hi": cty.StringVal("hello"), "hey": cty.StringVal("hello")}),
   328  			false,
   329  		},
   330  		{
   331  			cty.MapVal(map[string]cty.Value{"hi": cty.StringVal("hello")}),
   332  			cty.MapValEmpty(cty.String),
   333  			false,
   334  		},
   335  		{
   336  			cty.MapVal(map[string]cty.Value{"hi": cty.StringVal("hello")}),
   337  			cty.MapVal(map[string]cty.Value{"hi": cty.StringVal("hello")}),
   338  			true,
   339  		},
   340  		{
   341  			cty.MapVal(map[string]cty.Value{"hi": cty.StringVal("hello")}),
   342  			cty.MapVal(map[string]cty.Value{"hi": cty.StringVal("world")}),
   343  			false,
   344  		},
   345  		{
   346  			cty.MapVal(map[string]cty.Value{"hi": cty.NullVal(cty.String)}),
   347  			cty.MapVal(map[string]cty.Value{"hi": cty.StringVal("")}),
   348  			true,
   349  		},
   350  
   351  		// Objects
   352  		{
   353  			cty.EmptyObjectVal,
   354  			cty.EmptyObjectVal,
   355  			true,
   356  		},
   357  		{
   358  			cty.EmptyObjectVal,
   359  			cty.NullVal(cty.EmptyObject),
   360  			true,
   361  		},
   362  		{
   363  			cty.ObjectVal(map[string]cty.Value{"hi": cty.StringVal("hello")}),
   364  			cty.ObjectVal(map[string]cty.Value{"hi": cty.StringVal("hello"), "hey": cty.StringVal("hello")}),
   365  			false,
   366  		},
   367  		{
   368  			cty.ObjectVal(map[string]cty.Value{"hi": cty.StringVal("hello")}),
   369  			cty.EmptyObjectVal,
   370  			false,
   371  		},
   372  		{
   373  			cty.ObjectVal(map[string]cty.Value{"hi": cty.StringVal("hello")}),
   374  			cty.ObjectVal(map[string]cty.Value{"hi": cty.StringVal("hello")}),
   375  			true,
   376  		},
   377  		{
   378  			cty.ObjectVal(map[string]cty.Value{"hi": cty.StringVal("hello")}),
   379  			cty.ObjectVal(map[string]cty.Value{"hi": cty.StringVal("world")}),
   380  			false,
   381  		},
   382  		{
   383  			cty.ObjectVal(map[string]cty.Value{"hi": cty.NullVal(cty.String)}),
   384  			cty.ObjectVal(map[string]cty.Value{"hi": cty.StringVal("")}),
   385  			true,
   386  		},
   387  
   388  		// Unknown values
   389  		{
   390  			cty.UnknownVal(cty.String),
   391  			cty.UnknownVal(cty.String),
   392  			true,
   393  		},
   394  		{
   395  			cty.StringVal("hello"),
   396  			cty.UnknownVal(cty.String),
   397  			false,
   398  		},
   399  		{
   400  			cty.StringVal(""),
   401  			cty.UnknownVal(cty.String),
   402  			false,
   403  		},
   404  		{
   405  			cty.NullVal(cty.String),
   406  			cty.UnknownVal(cty.String),
   407  			false,
   408  		},
   409  	}
   410  
   411  	run := func(t *testing.T, a, b cty.Value, want bool) {
   412  		got := ValuesSDKEquivalent(a, b)
   413  
   414  		if got != want {
   415  			t.Errorf("wrong result\nfor: %#v ≈ %#v\ngot %#v, but want %#v", a, b, got, want)
   416  		}
   417  	}
   418  
   419  	for _, test := range tests {
   420  		t.Run(fmt.Sprintf("%#v ≈ %#v", test.A, test.B), func(t *testing.T) {
   421  			run(t, test.A, test.B, test.Want)
   422  		})
   423  		// This function is symmetrical, so we'll also test in reverse so
   424  		// we don't need to manually copy all of the test cases. (But this does
   425  		// mean that one failure normally becomes two, of course!)
   426  		if !test.A.RawEquals(test.B) {
   427  			t.Run(fmt.Sprintf("%#v ≈ %#v", test.B, test.A), func(t *testing.T) {
   428  				run(t, test.B, test.A, test.Want)
   429  			})
   430  		}
   431  	}
   432  }