github.com/hashicorp/hcl/v2@v2.20.0/diagnostic_text_test.go (about) 1 // Copyright (c) HashiCorp, Inc. 2 // SPDX-License-Identifier: MPL-2.0 3 4 package hcl 5 6 import ( 7 "bytes" 8 "fmt" 9 "testing" 10 11 "github.com/zclconf/go-cty/cty" 12 ) 13 14 func TestDiagnosticTextWriter(t *testing.T) { 15 tests := []struct { 16 Input *Diagnostic 17 Want string 18 }{ 19 { 20 &Diagnostic{ 21 Severity: DiagError, 22 Summary: "Splines not reticulated", 23 Detail: "All splines must be pre-reticulated.", 24 Subject: &Range{ 25 Start: Pos{ 26 Byte: 0, 27 Column: 1, 28 Line: 1, 29 }, 30 End: Pos{ 31 Byte: 3, 32 Column: 4, 33 Line: 1, 34 }, 35 }, 36 }, 37 `Error: Splines not reticulated 38 39 on line 1, in hardcoded-context: 40 1: foo = 1 41 42 All splines must be pre-reticulated. 43 44 `, 45 }, 46 { 47 &Diagnostic{ 48 Severity: DiagError, 49 Summary: "Unsupported attribute", 50 Detail: `"baz" is not a supported top-level attribute. Did you mean "bam"?`, 51 Subject: &Range{ 52 Start: Pos{ 53 Byte: 16, 54 Column: 1, 55 Line: 3, 56 }, 57 End: Pos{ 58 Byte: 19, 59 Column: 4, 60 Line: 3, 61 }, 62 }, 63 }, 64 `Error: Unsupported attribute 65 66 on line 3, in hardcoded-context: 67 3: baz = 3 68 69 "baz" is not a supported top-level 70 attribute. Did you mean "bam"? 71 72 `, 73 }, 74 { 75 &Diagnostic{ 76 Severity: DiagError, 77 Summary: "Unsupported attribute", 78 Detail: `"pizza" is not a supported attribute. Did you mean "pizzetta"?`, 79 Subject: &Range{ 80 Start: Pos{ 81 Byte: 42, 82 Column: 3, 83 Line: 5, 84 }, 85 End: Pos{ 86 Byte: 47, 87 Column: 8, 88 Line: 5, 89 }, 90 }, 91 // This is actually not a great example of a context, but is here to test 92 // whether we're able to show a multi-line context when needed. 93 Context: &Range{ 94 Start: Pos{ 95 Byte: 24, 96 Column: 1, 97 Line: 4, 98 }, 99 End: Pos{ 100 Byte: 60, 101 Column: 2, 102 Line: 6, 103 }, 104 }, 105 }, 106 `Error: Unsupported attribute 107 108 on line 5, in hardcoded-context: 109 4: block "party" { 110 5: pizza = "cheese" 111 6: } 112 113 "pizza" is not a supported attribute. 114 Did you mean "pizzetta"? 115 116 `, 117 }, 118 { 119 &Diagnostic{ 120 Severity: DiagError, 121 Summary: "Test of including relevant variable values", 122 Detail: `This diagnostic includes an expression and an evalcontext.`, 123 Subject: &Range{ 124 Start: Pos{ 125 Byte: 42, 126 Column: 3, 127 Line: 5, 128 }, 129 End: Pos{ 130 Byte: 47, 131 Column: 8, 132 Line: 5, 133 }, 134 }, 135 Expression: &diagnosticTestExpr{ 136 vars: []Traversal{ 137 { 138 TraverseRoot{ 139 Name: "foo", 140 }, 141 }, 142 { 143 TraverseRoot{ 144 Name: "bar", 145 }, 146 TraverseAttr{ 147 Name: "baz", 148 }, 149 }, 150 { 151 TraverseRoot{ 152 Name: "missing", 153 }, 154 }, 155 { 156 TraverseRoot{ 157 Name: "boz", 158 }, 159 }, 160 }, 161 }, 162 EvalContext: &EvalContext{ 163 parent: &EvalContext{ 164 Variables: map[string]cty.Value{ 165 "foo": cty.StringVal("foo value"), 166 }, 167 }, 168 Variables: map[string]cty.Value{ 169 "bar": cty.ObjectVal(map[string]cty.Value{ 170 "baz": cty.ListValEmpty(cty.String), 171 }), 172 "boz": cty.NumberIntVal(5), 173 "unused": cty.True, 174 }, 175 }, 176 }, 177 `Error: Test of including relevant variable values 178 179 on line 5, in hardcoded-context: 180 5: pizza = "cheese" 181 182 with bar.baz as empty list of string, 183 boz as 5, 184 foo as "foo value". 185 186 This diagnostic includes an expression 187 and an evalcontext. 188 189 `, 190 }, 191 } 192 193 files := map[string]*File{ 194 "": &File{ 195 Bytes: []byte(testDiagnosticTextWriterSource), 196 Nav: &diagnosticTestNav{}, 197 }, 198 } 199 200 for i, test := range tests { 201 t.Run(fmt.Sprintf("%02d", i), func(t *testing.T) { 202 bwr := &bytes.Buffer{} 203 dwr := NewDiagnosticTextWriter(bwr, files, 40, false) 204 err := dwr.WriteDiagnostic(test.Input) 205 if err != nil { 206 t.Fatalf("unexpected error: %s", err) 207 } 208 got := bwr.String() 209 if got != test.Want { 210 t.Errorf("wrong result\n\ngot:\n%swant:\n%s", got, test.Want) 211 } 212 }) 213 } 214 } 215 216 const testDiagnosticTextWriterSource = `foo = 1 217 bar = 2 218 baz = 3 219 block "party" { 220 pizza = "cheese" 221 } 222 ` 223 224 type diagnosticTestNav struct { 225 } 226 227 func (tn *diagnosticTestNav) ContextString(offset int) string { 228 return "hardcoded-context" 229 } 230 231 type diagnosticTestExpr struct { 232 vars []Traversal 233 staticExpr 234 } 235 236 func (e *diagnosticTestExpr) Variables() []Traversal { 237 return e.vars 238 }