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  }