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

     1  package terraform
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/hashicorp/terraform/internal/configs"
     7  	"github.com/zclconf/go-cty/cty"
     8  )
     9  
    10  func TestCheckInputVariables(t *testing.T) {
    11  	c := testModule(t, "input-variables")
    12  
    13  	t.Run("No variables set", func(t *testing.T) {
    14  		// No variables set
    15  		diags := checkInputVariables(c.Module.Variables, nil)
    16  		if !diags.HasErrors() {
    17  			t.Fatal("check succeeded, but want errors")
    18  		}
    19  
    20  		// Required variables set, optional variables unset
    21  		// This is still an error at this layer, since it's the caller's
    22  		// responsibility to have already merged in any default values.
    23  		diags = checkInputVariables(c.Module.Variables, InputValues{
    24  			"foo": &InputValue{
    25  				Value:      cty.StringVal("bar"),
    26  				SourceType: ValueFromCLIArg,
    27  			},
    28  		})
    29  		if !diags.HasErrors() {
    30  			t.Fatal("check succeeded, but want errors")
    31  		}
    32  	})
    33  
    34  	t.Run("All variables set", func(t *testing.T) {
    35  		diags := checkInputVariables(c.Module.Variables, InputValues{
    36  			"foo": &InputValue{
    37  				Value:      cty.StringVal("bar"),
    38  				SourceType: ValueFromCLIArg,
    39  			},
    40  			"bar": &InputValue{
    41  				Value:      cty.StringVal("baz"),
    42  				SourceType: ValueFromCLIArg,
    43  			},
    44  			"map": &InputValue{
    45  				Value:      cty.StringVal("baz"), // okay because config has no type constraint
    46  				SourceType: ValueFromCLIArg,
    47  			},
    48  			"object_map": &InputValue{
    49  				Value: cty.MapVal(map[string]cty.Value{
    50  					"uno": cty.ObjectVal(map[string]cty.Value{
    51  						"foo": cty.StringVal("baz"),
    52  						"bar": cty.NumberIntVal(2), // type = any
    53  					}),
    54  					"dos": cty.ObjectVal(map[string]cty.Value{
    55  						"foo": cty.StringVal("bat"),
    56  						"bar": cty.NumberIntVal(99), // type = any
    57  					}),
    58  				}),
    59  				SourceType: ValueFromCLIArg,
    60  			},
    61  			"object_list": &InputValue{
    62  				Value: cty.ListVal([]cty.Value{
    63  					cty.ObjectVal(map[string]cty.Value{
    64  						"foo": cty.StringVal("baz"),
    65  						"bar": cty.NumberIntVal(2), // type = any
    66  					}),
    67  					cty.ObjectVal(map[string]cty.Value{
    68  						"foo": cty.StringVal("bang"),
    69  						"bar": cty.NumberIntVal(42), // type = any
    70  					}),
    71  				}),
    72  				SourceType: ValueFromCLIArg,
    73  			},
    74  		})
    75  		if diags.HasErrors() {
    76  			t.Fatalf("unexpected errors: %s", diags.Err())
    77  		}
    78  	})
    79  
    80  	t.Run("Invalid Complex Types", func(t *testing.T) {
    81  		diags := checkInputVariables(c.Module.Variables, InputValues{
    82  			"foo": &InputValue{
    83  				Value:      cty.StringVal("bar"),
    84  				SourceType: ValueFromCLIArg,
    85  			},
    86  			"bar": &InputValue{
    87  				Value:      cty.StringVal("baz"),
    88  				SourceType: ValueFromCLIArg,
    89  			},
    90  			"map": &InputValue{
    91  				Value:      cty.StringVal("baz"), // okay because config has no type constraint
    92  				SourceType: ValueFromCLIArg,
    93  			},
    94  			"object_map": &InputValue{
    95  				Value: cty.MapVal(map[string]cty.Value{
    96  					"uno": cty.ObjectVal(map[string]cty.Value{
    97  						"foo": cty.StringVal("baz"),
    98  						"bar": cty.NumberIntVal(2), // type = any
    99  					}),
   100  					"dos": cty.ObjectVal(map[string]cty.Value{
   101  						"foo": cty.StringVal("bat"),
   102  						"bar": cty.NumberIntVal(99), // type = any
   103  					}),
   104  				}),
   105  				SourceType: ValueFromCLIArg,
   106  			},
   107  			"object_list": &InputValue{
   108  				Value: cty.TupleVal([]cty.Value{
   109  					cty.ObjectVal(map[string]cty.Value{
   110  						"foo": cty.StringVal("baz"),
   111  						"bar": cty.NumberIntVal(2), // type = any
   112  					}),
   113  					cty.ObjectVal(map[string]cty.Value{
   114  						"foo": cty.StringVal("bang"),
   115  						"bar": cty.StringVal("42"), // type = any, but mismatch with the first list item
   116  					}),
   117  				}),
   118  				SourceType: ValueFromCLIArg,
   119  			},
   120  		})
   121  
   122  		if diags.HasErrors() {
   123  			t.Fatalf("unexpected errors: %s", diags.Err())
   124  		}
   125  	})
   126  }
   127  
   128  // testInputValuesUnset is a helper for constructing InputValues values for
   129  // situations where all of the root module variables are optional and a
   130  // test case intends to just use those default values and not override them
   131  // at all.
   132  //
   133  // In other words, this constructs an InputValues with one entry per given
   134  // input variable declaration where all of them are declared as unset.
   135  func testInputValuesUnset(decls map[string]*configs.Variable) InputValues {
   136  	if len(decls) == 0 {
   137  		return nil
   138  	}
   139  
   140  	ret := make(InputValues, len(decls))
   141  	for name := range decls {
   142  		ret[name] = &InputValue{
   143  			Value:      cty.NilVal,
   144  			SourceType: ValueFromUnknown,
   145  		}
   146  	}
   147  	return ret
   148  }