| package configs |
| |
| import ( |
| "bufio" |
| "bytes" |
| "io/ioutil" |
| "path/filepath" |
| "strings" |
| "testing" |
| |
| "github.com/google/go-cmp/cmp" |
| |
| "github.com/hashicorp/hcl/v2" |
| ) |
| |
| // TestParseLoadConfigFileSuccess is a simple test that just verifies that |
| // a number of test configuration files (in testdata/valid-files) can |
| // be parsed without raising any diagnostics. |
| // |
| // This test does not verify that reading these files produces the correct |
| // file element contents. More detailed assertions may be made on some subset |
| // of these configuration files in other tests. |
| func TestParserLoadConfigFileSuccess(t *testing.T) { |
| files, err := ioutil.ReadDir("testdata/valid-files") |
| if err != nil { |
| t.Fatal(err) |
| } |
| |
| for _, info := range files { |
| name := info.Name() |
| t.Run(name, func(t *testing.T) { |
| src, err := ioutil.ReadFile(filepath.Join("testdata/valid-files", name)) |
| if err != nil { |
| t.Fatal(err) |
| } |
| |
| parser := testParser(map[string]string{ |
| name: string(src), |
| }) |
| |
| _, diags := parser.LoadConfigFile(name) |
| if len(diags) != 0 { |
| t.Errorf("unexpected diagnostics") |
| for _, diag := range diags { |
| t.Logf("- %s", diag) |
| } |
| } |
| }) |
| } |
| } |
| |
| // TestParseLoadConfigFileFailure is a simple test that just verifies that |
| // a number of test configuration files (in testdata/invalid-files) |
| // produce errors as expected. |
| // |
| // This test does not verify specific error messages, so more detailed |
| // assertions should be made on some subset of these configuration files in |
| // other tests. |
| func TestParserLoadConfigFileFailure(t *testing.T) { |
| files, err := ioutil.ReadDir("testdata/invalid-files") |
| if err != nil { |
| t.Fatal(err) |
| } |
| |
| for _, info := range files { |
| name := info.Name() |
| t.Run(name, func(t *testing.T) { |
| src, err := ioutil.ReadFile(filepath.Join("testdata/invalid-files", name)) |
| if err != nil { |
| t.Fatal(err) |
| } |
| |
| parser := testParser(map[string]string{ |
| name: string(src), |
| }) |
| |
| _, diags := parser.LoadConfigFile(name) |
| if !diags.HasErrors() { |
| t.Errorf("LoadConfigFile succeeded; want errors") |
| } |
| for _, diag := range diags { |
| t.Logf("- %s", diag) |
| } |
| }) |
| } |
| } |
| |
| // This test uses a subset of the same fixture files as |
| // TestParserLoadConfigFileFailure, but additionally verifies that each |
| // file produces the expected diagnostic summary. |
| func TestParserLoadConfigFileFailureMessages(t *testing.T) { |
| tests := []struct { |
| Filename string |
| WantSeverity hcl.DiagnosticSeverity |
| WantDiag string |
| }{ |
| { |
| "invalid-files/data-resource-lifecycle.tf", |
| hcl.DiagError, |
| "Invalid data resource lifecycle argument", |
| }, |
| { |
| "invalid-files/variable-type-unknown.tf", |
| hcl.DiagError, |
| "Invalid type specification", |
| }, |
| { |
| "invalid-files/unexpected-attr.tf", |
| hcl.DiagError, |
| "Unsupported argument", |
| }, |
| { |
| "invalid-files/unexpected-block.tf", |
| hcl.DiagError, |
| "Unsupported block type", |
| }, |
| { |
| "invalid-files/resource-count-and-for_each.tf", |
| hcl.DiagError, |
| `Invalid combination of "count" and "for_each"`, |
| }, |
| { |
| "invalid-files/data-count-and-for_each.tf", |
| hcl.DiagError, |
| `Invalid combination of "count" and "for_each"`, |
| }, |
| { |
| "invalid-files/resource-lifecycle-badbool.tf", |
| hcl.DiagError, |
| "Unsuitable value type", |
| }, |
| } |
| |
| for _, test := range tests { |
| t.Run(test.Filename, func(t *testing.T) { |
| src, err := ioutil.ReadFile(filepath.Join("testdata", test.Filename)) |
| if err != nil { |
| t.Fatal(err) |
| } |
| |
| parser := testParser(map[string]string{ |
| test.Filename: string(src), |
| }) |
| |
| _, diags := parser.LoadConfigFile(test.Filename) |
| if len(diags) != 1 { |
| t.Errorf("Wrong number of diagnostics %d; want 1", len(diags)) |
| for _, diag := range diags { |
| t.Logf("- %s", diag) |
| } |
| return |
| } |
| if diags[0].Severity != test.WantSeverity { |
| t.Errorf("Wrong diagnostic severity %#v; want %#v", diags[0].Severity, test.WantSeverity) |
| } |
| if diags[0].Summary != test.WantDiag { |
| t.Errorf("Wrong diagnostic summary\ngot: %s\nwant: %s", diags[0].Summary, test.WantDiag) |
| } |
| }) |
| } |
| } |
| |
| // TestParseLoadConfigFileWarning is a test that verifies files from |
| // testdata/warning-files produce particular warnings. |
| // |
| // This test does not verify that reading these files produces the correct |
| // file element contents in spite of those warnings. More detailed assertions |
| // may be made on some subset of these configuration files in other tests. |
| func TestParserLoadConfigFileWarning(t *testing.T) { |
| files, err := ioutil.ReadDir("testdata/warning-files") |
| if err != nil { |
| t.Fatal(err) |
| } |
| |
| for _, info := range files { |
| name := info.Name() |
| t.Run(name, func(t *testing.T) { |
| src, err := ioutil.ReadFile(filepath.Join("testdata/warning-files", name)) |
| if err != nil { |
| t.Fatal(err) |
| } |
| |
| // First we'll scan the file to see what warnings are expected. |
| // That's declared inside the files themselves by using the |
| // string "WARNING: " somewhere on each line that is expected |
| // to produce a warning, followed by the expected warning summary |
| // text. A single-line comment (with #) is the main way to do that. |
| const marker = "WARNING: " |
| sc := bufio.NewScanner(bytes.NewReader(src)) |
| wantWarnings := make(map[int]string) |
| lineNum := 1 |
| for sc.Scan() { |
| lineText := sc.Text() |
| if idx := strings.Index(lineText, marker); idx != -1 { |
| summaryText := lineText[idx+len(marker):] |
| wantWarnings[lineNum] = summaryText |
| } |
| lineNum++ |
| } |
| |
| parser := testParser(map[string]string{ |
| name: string(src), |
| }) |
| |
| _, diags := parser.LoadConfigFile(name) |
| if diags.HasErrors() { |
| t.Errorf("unexpected error diagnostics") |
| for _, diag := range diags { |
| t.Logf("- %s", diag) |
| } |
| } |
| |
| gotWarnings := make(map[int]string) |
| for _, diag := range diags { |
| if diag.Severity != hcl.DiagWarning || diag.Subject == nil { |
| continue |
| } |
| gotWarnings[diag.Subject.Start.Line] = diag.Summary |
| } |
| |
| if diff := cmp.Diff(wantWarnings, gotWarnings); diff != "" { |
| t.Errorf("wrong warnings\n%s", diff) |
| } |
| }) |
| } |
| } |
| |
| // TestParseLoadConfigFileError is a test that verifies files from |
| // testdata/warning-files produce particular errors. |
| // |
| // This test does not verify that reading these files produces the correct |
| // file element contents in spite of those errors. More detailed assertions |
| // may be made on some subset of these configuration files in other tests. |
| func TestParserLoadConfigFileError(t *testing.T) { |
| files, err := ioutil.ReadDir("testdata/error-files") |
| if err != nil { |
| t.Fatal(err) |
| } |
| |
| for _, info := range files { |
| name := info.Name() |
| t.Run(name, func(t *testing.T) { |
| src, err := ioutil.ReadFile(filepath.Join("testdata/error-files", name)) |
| if err != nil { |
| t.Fatal(err) |
| } |
| |
| // First we'll scan the file to see what warnings are expected. |
| // That's declared inside the files themselves by using the |
| // string "ERROR: " somewhere on each line that is expected |
| // to produce a warning, followed by the expected warning summary |
| // text. A single-line comment (with #) is the main way to do that. |
| const marker = "ERROR: " |
| sc := bufio.NewScanner(bytes.NewReader(src)) |
| wantErrors := make(map[int]string) |
| lineNum := 1 |
| for sc.Scan() { |
| lineText := sc.Text() |
| if idx := strings.Index(lineText, marker); idx != -1 { |
| summaryText := lineText[idx+len(marker):] |
| wantErrors[lineNum] = summaryText |
| } |
| lineNum++ |
| } |
| |
| parser := testParser(map[string]string{ |
| name: string(src), |
| }) |
| |
| _, diags := parser.LoadConfigFile(name) |
| |
| gotErrors := make(map[int]string) |
| for _, diag := range diags { |
| if diag.Severity != hcl.DiagError || diag.Subject == nil { |
| continue |
| } |
| gotErrors[diag.Subject.Start.Line] = diag.Summary |
| } |
| |
| if diff := cmp.Diff(wantErrors, gotErrors); diff != "" { |
| t.Errorf("wrong errors\n%s", diff) |
| } |
| }) |
| } |
| } |