github.com/terramate-io/tf@v0.0.0-20230830114523-fce866b4dfcd/backend/unparsed_value_test.go (about)

     1  // Copyright (c) HashiCorp, Inc.
     2  // SPDX-License-Identifier: MPL-2.0
     3  
     4  package backend
     5  
     6  import (
     7  	"strings"
     8  	"testing"
     9  
    10  	"github.com/google/go-cmp/cmp"
    11  	"github.com/hashicorp/hcl/v2"
    12  	"github.com/zclconf/go-cty/cty"
    13  
    14  	"github.com/terramate-io/tf/configs"
    15  	"github.com/terramate-io/tf/terraform"
    16  	"github.com/terramate-io/tf/tfdiags"
    17  )
    18  
    19  func TestUnparsedValue(t *testing.T) {
    20  	vv := map[string]UnparsedVariableValue{
    21  		"undeclared0": testUnparsedVariableValue("0"),
    22  		"undeclared1": testUnparsedVariableValue("1"),
    23  		"undeclared2": testUnparsedVariableValue("2"),
    24  		"undeclared3": testUnparsedVariableValue("3"),
    25  		"undeclared4": testUnparsedVariableValue("4"),
    26  		"declared1":   testUnparsedVariableValue("5"),
    27  	}
    28  	decls := map[string]*configs.Variable{
    29  		"declared1": {
    30  			Name:           "declared1",
    31  			Type:           cty.String,
    32  			ConstraintType: cty.String,
    33  			ParsingMode:    configs.VariableParseLiteral,
    34  			DeclRange: hcl.Range{
    35  				Filename: "fake.tf",
    36  				Start:    hcl.Pos{Line: 2, Column: 1, Byte: 0},
    37  				End:      hcl.Pos{Line: 2, Column: 1, Byte: 0},
    38  			},
    39  		},
    40  		"missing1": {
    41  			Name:           "missing1",
    42  			Type:           cty.String,
    43  			ConstraintType: cty.String,
    44  			ParsingMode:    configs.VariableParseLiteral,
    45  			DeclRange: hcl.Range{
    46  				Filename: "fake.tf",
    47  				Start:    hcl.Pos{Line: 3, Column: 1, Byte: 0},
    48  				End:      hcl.Pos{Line: 3, Column: 1, Byte: 0},
    49  			},
    50  		},
    51  		"missing2": {
    52  			Name:           "missing1",
    53  			Type:           cty.String,
    54  			ConstraintType: cty.String,
    55  			ParsingMode:    configs.VariableParseLiteral,
    56  			Default:        cty.StringVal("default for missing2"),
    57  			DeclRange: hcl.Range{
    58  				Filename: "fake.tf",
    59  				Start:    hcl.Pos{Line: 4, Column: 1, Byte: 0},
    60  				End:      hcl.Pos{Line: 4, Column: 1, Byte: 0},
    61  			},
    62  		},
    63  	}
    64  
    65  	const undeclSingular = `Value for undeclared variable`
    66  	const undeclPlural = `Values for undeclared variables`
    67  
    68  	t.Run("ParseDeclaredVariableValues", func(t *testing.T) {
    69  		gotVals, diags := ParseDeclaredVariableValues(vv, decls)
    70  
    71  		if got, want := len(diags), 0; got != want {
    72  			t.Fatalf("wrong number of diagnostics %d; want %d", got, want)
    73  		}
    74  
    75  		wantVals := terraform.InputValues{
    76  			"declared1": {
    77  				Value:      cty.StringVal("5"),
    78  				SourceType: terraform.ValueFromNamedFile,
    79  				SourceRange: tfdiags.SourceRange{
    80  					Filename: "fake.tfvars",
    81  					Start:    tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
    82  					End:      tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
    83  				},
    84  			},
    85  		}
    86  
    87  		if diff := cmp.Diff(wantVals, gotVals, cmp.Comparer(cty.Value.RawEquals)); diff != "" {
    88  			t.Errorf("wrong result\n%s", diff)
    89  		}
    90  	})
    91  
    92  	t.Run("ParseUndeclaredVariableValues", func(t *testing.T) {
    93  		gotVals, diags := ParseUndeclaredVariableValues(vv, decls)
    94  
    95  		if got, want := len(diags), 3; got != want {
    96  			t.Fatalf("wrong number of diagnostics %d; want %d", got, want)
    97  		}
    98  
    99  		if got, want := diags[0].Description().Summary, undeclSingular; got != want {
   100  			t.Errorf("wrong summary for diagnostic 0\ngot:  %s\nwant: %s", got, want)
   101  		}
   102  
   103  		if got, want := diags[1].Description().Summary, undeclSingular; got != want {
   104  			t.Errorf("wrong summary for diagnostic 1\ngot:  %s\nwant: %s", got, want)
   105  		}
   106  
   107  		if got, want := diags[2].Description().Summary, undeclPlural; got != want {
   108  			t.Errorf("wrong summary for diagnostic 2\ngot:  %s\nwant: %s", got, want)
   109  		}
   110  
   111  		wantVals := terraform.InputValues{
   112  			"undeclared0": {
   113  				Value:      cty.StringVal("0"),
   114  				SourceType: terraform.ValueFromNamedFile,
   115  				SourceRange: tfdiags.SourceRange{
   116  					Filename: "fake.tfvars",
   117  					Start:    tfdiags.SourcePos{Line: 1, Column: 1},
   118  					End:      tfdiags.SourcePos{Line: 1, Column: 1},
   119  				},
   120  			},
   121  			"undeclared1": {
   122  				Value:      cty.StringVal("1"),
   123  				SourceType: terraform.ValueFromNamedFile,
   124  				SourceRange: tfdiags.SourceRange{
   125  					Filename: "fake.tfvars",
   126  					Start:    tfdiags.SourcePos{Line: 1, Column: 1},
   127  					End:      tfdiags.SourcePos{Line: 1, Column: 1},
   128  				},
   129  			},
   130  			"undeclared2": {
   131  				Value:      cty.StringVal("2"),
   132  				SourceType: terraform.ValueFromNamedFile,
   133  				SourceRange: tfdiags.SourceRange{
   134  					Filename: "fake.tfvars",
   135  					Start:    tfdiags.SourcePos{Line: 1, Column: 1},
   136  					End:      tfdiags.SourcePos{Line: 1, Column: 1},
   137  				},
   138  			},
   139  			"undeclared3": {
   140  				Value:      cty.StringVal("3"),
   141  				SourceType: terraform.ValueFromNamedFile,
   142  				SourceRange: tfdiags.SourceRange{
   143  					Filename: "fake.tfvars",
   144  					Start:    tfdiags.SourcePos{Line: 1, Column: 1},
   145  					End:      tfdiags.SourcePos{Line: 1, Column: 1},
   146  				},
   147  			},
   148  			"undeclared4": {
   149  				Value:      cty.StringVal("4"),
   150  				SourceType: terraform.ValueFromNamedFile,
   151  				SourceRange: tfdiags.SourceRange{
   152  					Filename: "fake.tfvars",
   153  					Start:    tfdiags.SourcePos{Line: 1, Column: 1},
   154  					End:      tfdiags.SourcePos{Line: 1, Column: 1},
   155  				},
   156  			},
   157  		}
   158  		if diff := cmp.Diff(wantVals, gotVals, cmp.Comparer(cty.Value.RawEquals)); diff != "" {
   159  			t.Errorf("wrong result\n%s", diff)
   160  		}
   161  	})
   162  
   163  	t.Run("ParseVariableValues", func(t *testing.T) {
   164  		gotVals, diags := ParseVariableValues(vv, decls)
   165  		for _, diag := range diags {
   166  			t.Logf("%s: %s", diag.Description().Summary, diag.Description().Detail)
   167  		}
   168  		if got, want := len(diags), 4; got != want {
   169  			t.Fatalf("wrong number of diagnostics %d; want %d", got, want)
   170  		}
   171  
   172  		const missingRequired = `No value for required variable`
   173  
   174  		if got, want := diags[0].Description().Summary, undeclSingular; got != want {
   175  			t.Errorf("wrong summary for diagnostic 0\ngot:  %s\nwant: %s", got, want)
   176  		}
   177  		if got, want := diags[1].Description().Summary, undeclSingular; got != want {
   178  			t.Errorf("wrong summary for diagnostic 1\ngot:  %s\nwant: %s", got, want)
   179  		}
   180  		if got, want := diags[2].Description().Summary, undeclPlural; got != want {
   181  			t.Errorf("wrong summary for diagnostic 2\ngot:  %s\nwant: %s", got, want)
   182  		}
   183  		if got, want := diags[2].Description().Detail, "3 other variable(s)"; !strings.Contains(got, want) {
   184  			t.Errorf("wrong detail for diagnostic 2\ngot:  %s\nmust contain: %s", got, want)
   185  		}
   186  		if got, want := diags[3].Description().Summary, missingRequired; got != want {
   187  			t.Errorf("wrong summary for diagnostic 3\ngot:  %s\nwant: %s", got, want)
   188  		}
   189  
   190  		wantVals := terraform.InputValues{
   191  			"declared1": {
   192  				Value:      cty.StringVal("5"),
   193  				SourceType: terraform.ValueFromNamedFile,
   194  				SourceRange: tfdiags.SourceRange{
   195  					Filename: "fake.tfvars",
   196  					Start:    tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
   197  					End:      tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
   198  				},
   199  			},
   200  			"missing1": {
   201  				Value:      cty.DynamicVal,
   202  				SourceType: terraform.ValueFromConfig,
   203  				SourceRange: tfdiags.SourceRange{
   204  					Filename: "fake.tf",
   205  					Start:    tfdiags.SourcePos{Line: 3, Column: 1, Byte: 0},
   206  					End:      tfdiags.SourcePos{Line: 3, Column: 1, Byte: 0},
   207  				},
   208  			},
   209  			"missing2": {
   210  				Value:      cty.NilVal, // Terraform Core handles substituting the default
   211  				SourceType: terraform.ValueFromConfig,
   212  				SourceRange: tfdiags.SourceRange{
   213  					Filename: "fake.tf",
   214  					Start:    tfdiags.SourcePos{Line: 4, Column: 1, Byte: 0},
   215  					End:      tfdiags.SourcePos{Line: 4, Column: 1, Byte: 0},
   216  				},
   217  			},
   218  		}
   219  		if diff := cmp.Diff(wantVals, gotVals, cmp.Comparer(cty.Value.RawEquals)); diff != "" {
   220  			t.Errorf("wrong result\n%s", diff)
   221  		}
   222  	})
   223  }
   224  
   225  type testUnparsedVariableValue string
   226  
   227  func (v testUnparsedVariableValue) ParseVariableValue(mode configs.VariableParsingMode) (*terraform.InputValue, tfdiags.Diagnostics) {
   228  	return &terraform.InputValue{
   229  		Value:      cty.StringVal(string(v)),
   230  		SourceType: terraform.ValueFromNamedFile,
   231  		SourceRange: tfdiags.SourceRange{
   232  			Filename: "fake.tfvars",
   233  			Start:    tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
   234  			End:      tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
   235  		},
   236  	}, nil
   237  }