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 }