github.com/kanishk98/terraform@v1.3.0-dev.0.20220917174235-661ca8088a6a/internal/command/jsonplan/plan_test.go (about)

     1  package jsonplan
     2  
     3  import (
     4  	"encoding/json"
     5  	"reflect"
     6  	"testing"
     7  
     8  	"github.com/google/go-cmp/cmp"
     9  	"github.com/zclconf/go-cty/cty"
    10  )
    11  
    12  func TestOmitUnknowns(t *testing.T) {
    13  	tests := []struct {
    14  		Input cty.Value
    15  		Want  cty.Value
    16  	}{
    17  		{
    18  			cty.StringVal("hello"),
    19  			cty.StringVal("hello"),
    20  		},
    21  		{
    22  			cty.NullVal(cty.String),
    23  			cty.NullVal(cty.String),
    24  		},
    25  		{
    26  			cty.UnknownVal(cty.String),
    27  			cty.NilVal,
    28  		},
    29  		{
    30  			cty.ListValEmpty(cty.String),
    31  			cty.EmptyTupleVal,
    32  		},
    33  		{
    34  			cty.ListVal([]cty.Value{cty.StringVal("hello")}),
    35  			cty.TupleVal([]cty.Value{cty.StringVal("hello")}),
    36  		},
    37  		{
    38  			cty.ListVal([]cty.Value{cty.NullVal(cty.String)}),
    39  			cty.TupleVal([]cty.Value{cty.NullVal(cty.String)}),
    40  		},
    41  		{
    42  			cty.ListVal([]cty.Value{cty.UnknownVal(cty.String)}),
    43  			cty.TupleVal([]cty.Value{cty.NullVal(cty.String)}),
    44  		},
    45  		{
    46  			cty.ListVal([]cty.Value{cty.StringVal("hello")}),
    47  			cty.TupleVal([]cty.Value{cty.StringVal("hello")}),
    48  		},
    49  		//
    50  		{
    51  			cty.ListVal([]cty.Value{
    52  				cty.StringVal("hello"),
    53  				cty.UnknownVal(cty.String)}),
    54  			cty.TupleVal([]cty.Value{
    55  				cty.StringVal("hello"),
    56  				cty.NullVal(cty.String),
    57  			}),
    58  		},
    59  		{
    60  			cty.MapVal(map[string]cty.Value{
    61  				"hello": cty.True,
    62  				"world": cty.UnknownVal(cty.Bool),
    63  			}),
    64  			cty.ObjectVal(map[string]cty.Value{
    65  				"hello": cty.True,
    66  			}),
    67  		},
    68  		{
    69  			cty.TupleVal([]cty.Value{
    70  				cty.StringVal("alpha"),
    71  				cty.UnknownVal(cty.String),
    72  				cty.StringVal("charlie"),
    73  			}),
    74  			cty.TupleVal([]cty.Value{
    75  				cty.StringVal("alpha"),
    76  				cty.NullVal(cty.String),
    77  				cty.StringVal("charlie"),
    78  			}),
    79  		},
    80  		{
    81  			cty.SetVal([]cty.Value{
    82  				cty.StringVal("dev"),
    83  				cty.StringVal("foo"),
    84  				cty.StringVal("stg"),
    85  				cty.UnknownVal(cty.String),
    86  			}),
    87  			cty.TupleVal([]cty.Value{
    88  				cty.StringVal("dev"),
    89  				cty.StringVal("foo"),
    90  				cty.StringVal("stg"),
    91  				cty.NullVal(cty.String),
    92  			}),
    93  		},
    94  		{
    95  			cty.SetVal([]cty.Value{
    96  				cty.ObjectVal(map[string]cty.Value{
    97  					"a": cty.UnknownVal(cty.String),
    98  				}),
    99  				cty.ObjectVal(map[string]cty.Value{
   100  					"a": cty.StringVal("known"),
   101  				}),
   102  			}),
   103  			cty.TupleVal([]cty.Value{
   104  				cty.ObjectVal(map[string]cty.Value{
   105  					"a": cty.StringVal("known"),
   106  				}),
   107  				cty.EmptyObjectVal,
   108  			}),
   109  		},
   110  	}
   111  
   112  	for _, test := range tests {
   113  		got := omitUnknowns(test.Input)
   114  		if !reflect.DeepEqual(got, test.Want) {
   115  			t.Errorf(
   116  				"wrong result\ninput: %#v\ngot:   %#v\nwant:  %#v",
   117  				test.Input, got, test.Want,
   118  			)
   119  		}
   120  	}
   121  }
   122  
   123  func TestUnknownAsBool(t *testing.T) {
   124  	tests := []struct {
   125  		Input cty.Value
   126  		Want  cty.Value
   127  	}{
   128  		{
   129  			cty.StringVal("hello"),
   130  			cty.False,
   131  		},
   132  		{
   133  			cty.NullVal(cty.String),
   134  			cty.False,
   135  		},
   136  		{
   137  			cty.UnknownVal(cty.String),
   138  			cty.True,
   139  		},
   140  
   141  		{
   142  			cty.NullVal(cty.DynamicPseudoType),
   143  			cty.False,
   144  		},
   145  		{
   146  			cty.NullVal(cty.Object(map[string]cty.Type{"test": cty.String})),
   147  			cty.False,
   148  		},
   149  		{
   150  			cty.DynamicVal,
   151  			cty.True,
   152  		},
   153  
   154  		{
   155  			cty.ListValEmpty(cty.String),
   156  			cty.EmptyTupleVal,
   157  		},
   158  		{
   159  			cty.ListVal([]cty.Value{cty.StringVal("hello")}),
   160  			cty.TupleVal([]cty.Value{cty.False}),
   161  		},
   162  		{
   163  			cty.ListVal([]cty.Value{cty.NullVal(cty.String)}),
   164  			cty.TupleVal([]cty.Value{cty.False}),
   165  		},
   166  		{
   167  			cty.ListVal([]cty.Value{cty.UnknownVal(cty.String)}),
   168  			cty.TupleVal([]cty.Value{cty.True}),
   169  		},
   170  		{
   171  			cty.SetValEmpty(cty.String),
   172  			cty.EmptyTupleVal,
   173  		},
   174  		{
   175  			cty.SetVal([]cty.Value{cty.StringVal("hello")}),
   176  			cty.TupleVal([]cty.Value{cty.False}),
   177  		},
   178  		{
   179  			cty.SetVal([]cty.Value{cty.NullVal(cty.String)}),
   180  			cty.TupleVal([]cty.Value{cty.False}),
   181  		},
   182  		{
   183  			cty.SetVal([]cty.Value{cty.UnknownVal(cty.String)}),
   184  			cty.TupleVal([]cty.Value{cty.True}),
   185  		},
   186  		{
   187  			cty.EmptyTupleVal,
   188  			cty.EmptyTupleVal,
   189  		},
   190  		{
   191  			cty.TupleVal([]cty.Value{cty.StringVal("hello")}),
   192  			cty.TupleVal([]cty.Value{cty.False}),
   193  		},
   194  		{
   195  			cty.TupleVal([]cty.Value{cty.NullVal(cty.String)}),
   196  			cty.TupleVal([]cty.Value{cty.False}),
   197  		},
   198  		{
   199  			cty.TupleVal([]cty.Value{cty.UnknownVal(cty.String)}),
   200  			cty.TupleVal([]cty.Value{cty.True}),
   201  		},
   202  		{
   203  			cty.MapValEmpty(cty.String),
   204  			cty.EmptyObjectVal,
   205  		},
   206  		{
   207  			cty.MapVal(map[string]cty.Value{"greeting": cty.StringVal("hello")}),
   208  			cty.EmptyObjectVal,
   209  		},
   210  		{
   211  			cty.MapVal(map[string]cty.Value{"greeting": cty.NullVal(cty.String)}),
   212  			cty.EmptyObjectVal,
   213  		},
   214  		{
   215  			cty.MapVal(map[string]cty.Value{"greeting": cty.UnknownVal(cty.String)}),
   216  			cty.ObjectVal(map[string]cty.Value{"greeting": cty.True}),
   217  		},
   218  		{
   219  			cty.EmptyObjectVal,
   220  			cty.EmptyObjectVal,
   221  		},
   222  		{
   223  			cty.ObjectVal(map[string]cty.Value{"greeting": cty.StringVal("hello")}),
   224  			cty.EmptyObjectVal,
   225  		},
   226  		{
   227  			cty.ObjectVal(map[string]cty.Value{"greeting": cty.NullVal(cty.String)}),
   228  			cty.EmptyObjectVal,
   229  		},
   230  		{
   231  			cty.ObjectVal(map[string]cty.Value{"greeting": cty.UnknownVal(cty.String)}),
   232  			cty.ObjectVal(map[string]cty.Value{"greeting": cty.True}),
   233  		},
   234  		{
   235  			cty.SetVal([]cty.Value{
   236  				cty.ObjectVal(map[string]cty.Value{
   237  					"a": cty.UnknownVal(cty.String),
   238  				}),
   239  				cty.ObjectVal(map[string]cty.Value{
   240  					"a": cty.StringVal("known"),
   241  				}),
   242  			}),
   243  			cty.TupleVal([]cty.Value{
   244  				cty.EmptyObjectVal,
   245  				cty.ObjectVal(map[string]cty.Value{
   246  					"a": cty.True,
   247  				}),
   248  			}),
   249  		},
   250  		{
   251  			cty.SetVal([]cty.Value{
   252  				cty.MapValEmpty(cty.String),
   253  				cty.MapVal(map[string]cty.Value{
   254  					"a": cty.StringVal("known"),
   255  				}),
   256  				cty.MapVal(map[string]cty.Value{
   257  					"a": cty.UnknownVal(cty.String),
   258  				}),
   259  			}),
   260  			cty.TupleVal([]cty.Value{
   261  				cty.EmptyObjectVal,
   262  				cty.ObjectVal(map[string]cty.Value{
   263  					"a": cty.True,
   264  				}),
   265  				cty.EmptyObjectVal,
   266  			}),
   267  		},
   268  	}
   269  
   270  	for _, test := range tests {
   271  		got := unknownAsBool(test.Input)
   272  		if !reflect.DeepEqual(got, test.Want) {
   273  			t.Errorf(
   274  				"wrong result\ninput: %#v\ngot:   %#v\nwant:  %#v",
   275  				test.Input, got, test.Want,
   276  			)
   277  		}
   278  	}
   279  }
   280  
   281  func TestEncodePaths(t *testing.T) {
   282  	tests := map[string]struct {
   283  		Input cty.PathSet
   284  		Want  json.RawMessage
   285  	}{
   286  		"empty set": {
   287  			cty.NewPathSet(),
   288  			json.RawMessage(nil),
   289  		},
   290  		"index path with string and int steps": {
   291  			cty.NewPathSet(cty.IndexStringPath("boop").IndexInt(0)),
   292  			json.RawMessage(`[["boop",0]]`),
   293  		},
   294  		"get attr path with one step": {
   295  			cty.NewPathSet(cty.GetAttrPath("triggers")),
   296  			json.RawMessage(`[["triggers"]]`),
   297  		},
   298  		"multiple paths of different types": {
   299  			cty.NewPathSet(
   300  				cty.GetAttrPath("alpha").GetAttr("beta").GetAttr("gamma"),
   301  				cty.GetAttrPath("triggers").IndexString("name"),
   302  				cty.IndexIntPath(0).IndexInt(1).IndexInt(2).IndexInt(3),
   303  			),
   304  			json.RawMessage(`[["alpha","beta","gamma"],["triggers","name"],[0,1,2,3]]`),
   305  		},
   306  	}
   307  
   308  	for name, test := range tests {
   309  		t.Run(name, func(t *testing.T) {
   310  			got, err := encodePaths(test.Input)
   311  			if err != nil {
   312  				t.Fatalf("unexpected error: %s", err)
   313  			}
   314  			if !cmp.Equal(got, test.Want) {
   315  				t.Errorf("wrong result:\n %v\n", cmp.Diff(got, test.Want))
   316  			}
   317  		})
   318  	}
   319  }
   320  
   321  func deepObjectValue(depth int) cty.Value {
   322  	v := cty.ObjectVal(map[string]cty.Value{
   323  		"a": cty.StringVal("a"),
   324  		"b": cty.NumberIntVal(2),
   325  		"c": cty.True,
   326  		"d": cty.UnknownVal(cty.String),
   327  	})
   328  
   329  	result := v
   330  
   331  	for i := 0; i < depth; i++ {
   332  		result = cty.ObjectVal(map[string]cty.Value{
   333  			"a": result,
   334  			"b": result,
   335  			"c": result,
   336  		})
   337  	}
   338  
   339  	return result
   340  }
   341  
   342  func BenchmarkUnknownAsBool_2(b *testing.B) {
   343  	value := deepObjectValue(2)
   344  	for n := 0; n < b.N; n++ {
   345  		unknownAsBool(value)
   346  	}
   347  }
   348  
   349  func BenchmarkUnknownAsBool_3(b *testing.B) {
   350  	value := deepObjectValue(3)
   351  	for n := 0; n < b.N; n++ {
   352  		unknownAsBool(value)
   353  	}
   354  }
   355  
   356  func BenchmarkUnknownAsBool_5(b *testing.B) {
   357  	value := deepObjectValue(5)
   358  	for n := 0; n < b.N; n++ {
   359  		unknownAsBool(value)
   360  	}
   361  }
   362  
   363  func BenchmarkUnknownAsBool_7(b *testing.B) {
   364  	value := deepObjectValue(7)
   365  	for n := 0; n < b.N; n++ {
   366  		unknownAsBool(value)
   367  	}
   368  }
   369  
   370  func BenchmarkUnknownAsBool_9(b *testing.B) {
   371  	value := deepObjectValue(9)
   372  	for n := 0; n < b.N; n++ {
   373  		unknownAsBool(value)
   374  	}
   375  }