github.com/yoheimuta/protolint@v0.49.8-0.20240515023657-4ecaebb7575d/internal/linter/report/reporters/ciReporter_test.go (about)

     1  package reporters_test
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"os"
     7  	"path/filepath"
     8  	"testing"
     9  
    10  	"github.com/yoheimuta/go-protoparser/v4/parser/meta"
    11  	"github.com/yoheimuta/protolint/internal/linter/report/reporters"
    12  	"github.com/yoheimuta/protolint/linter/report"
    13  	"github.com/yoheimuta/protolint/linter/rule"
    14  )
    15  
    16  type testFiles struct {
    17  	files []string
    18  }
    19  
    20  type testStruct struct {
    21  	name          string
    22  	inputFailures []report.Failure
    23  	wantOutput    string
    24  	expectedError error
    25  	files         testFiles
    26  }
    27  
    28  type testCases struct {
    29  	oneWarningOneError testStruct
    30  	onlyErrors         testStruct
    31  	oneOfEach          testStruct
    32  }
    33  
    34  func makeTestData() testCases {
    35  	return testCases{
    36  
    37  		oneWarningOneError: testStruct{
    38  			name:          "oneWarningOneError",
    39  			wantOutput:    "",
    40  			expectedError: nil,
    41  			files:         testFiles{},
    42  			inputFailures: []report.Failure{
    43  				report.FailureWithSeverityf(
    44  					meta.Position{
    45  						Filename: "example.proto",
    46  						Offset:   100,
    47  						Line:     5,
    48  						Column:   10,
    49  					},
    50  					"ENUM_NAMES_UPPER_CAMEL_CASE",
    51  					string(rule.SeverityWarning),
    52  					`EnumField name "fIRST_VALUE" must be CAPITALS_WITH_UNDERSCORES`,
    53  				),
    54  				report.FailureWithSeverityf(
    55  					meta.Position{
    56  						Filename: "example.proto",
    57  						Offset:   200,
    58  						Line:     10,
    59  						Column:   20,
    60  					},
    61  					"ENUM_NAMES_UPPER_CAMEL_CASE",
    62  					string(rule.SeverityError),
    63  					`EnumField name "SECOND.VALUE" must be CAPITALS_WITH_UNDERSCORES`,
    64  				),
    65  			},
    66  		},
    67  
    68  		onlyErrors: testStruct{
    69  			name:          "onlyErrors",
    70  			wantOutput:    "",
    71  			expectedError: nil,
    72  			files:         testFiles{},
    73  			inputFailures: []report.Failure{
    74  				report.FailureWithSeverityf(
    75  					meta.Position{
    76  						Filename: "example.proto",
    77  						Offset:   100,
    78  						Line:     5,
    79  						Column:   10,
    80  					},
    81  					"ENUM_NAMES_UPPER_CAMEL_CASE",
    82  					string(rule.SeverityError),
    83  					`EnumField name "fIRST_VALUE" must be CAPITALS_WITH_UNDERSCORES`,
    84  				),
    85  				report.FailureWithSeverityf(
    86  					meta.Position{
    87  						Filename: "example.proto",
    88  						Offset:   200,
    89  						Line:     10,
    90  						Column:   20,
    91  					},
    92  					"ENUM_NAMES_UPPER_CAMEL_CASE",
    93  					string(rule.SeverityError),
    94  					`EnumField name "SECOND.VALUE" must be CAPITALS_WITH_UNDERSCORES`,
    95  				),
    96  				report.FailureWithSeverityf(
    97  					meta.Position{
    98  						Filename: "example.proto",
    99  						Offset:   300,
   100  						Line:     20,
   101  						Column:   40,
   102  					},
   103  					"ENUM_NAMES_UPPER_CAMEL_CASE",
   104  					string(rule.SeverityError),
   105  					`EnumField name "third.VALUE" must be CAPITALS_WITH_UNDERSCORES`,
   106  				),
   107  			},
   108  		},
   109  
   110  		oneOfEach: testStruct{
   111  			name:          "oneOfEach",
   112  			wantOutput:    "",
   113  			expectedError: nil,
   114  			files:         testFiles{},
   115  			inputFailures: []report.Failure{
   116  				report.FailureWithSeverityf(
   117  					meta.Position{
   118  						Filename: "example.proto",
   119  						Offset:   100,
   120  						Line:     5,
   121  						Column:   10,
   122  					},
   123  					"ENUM_NAMES_UPPER_CAMEL_CASE",
   124  					string(rule.SeverityNote),
   125  					`EnumField name "fIRST_VALUE" must be CAPITALS_WITH_UNDERSCORES`,
   126  				),
   127  				report.FailureWithSeverityf(
   128  					meta.Position{
   129  						Filename: "example.proto",
   130  						Offset:   200,
   131  						Line:     10,
   132  						Column:   20,
   133  					},
   134  					"ENUM_NAMES_UPPER_CAMEL_CASE",
   135  					string(rule.SeverityWarning),
   136  					`EnumField name "SECOND.VALUE" must be CAPITALS_WITH_UNDERSCORES`,
   137  				),
   138  				report.FailureWithSeverityf(
   139  					meta.Position{
   140  						Filename: "example.proto",
   141  						Offset:   300,
   142  						Line:     20,
   143  						Column:   40,
   144  					},
   145  					"ENUM_NAMES_UPPER_CAMEL_CASE",
   146  					string(rule.SeverityError),
   147  					`EnumField name "third.VALUE" must be CAPITALS_WITH_UNDERSCORES`,
   148  				),
   149  			},
   150  		},
   151  	}
   152  }
   153  
   154  func TestProblemMatcherReporter_Report(t *testing.T) {
   155  	initTestCases := makeTestData()
   156  	initTestCases.oneOfEach.want(`Protolint ENUM_NAMES_UPPER_CAMEL_CASE (info): example.proto[5,10]: EnumField name \"fIRST_VALUE\" must be CAPITALS_WITH_UNDERSCORES
   157  Protolint ENUM_NAMES_UPPER_CAMEL_CASE (warning): example.proto[10,20]: EnumField name \"SECOND.VALUE\" must be CAPITALS_WITH_UNDERSCORES
   158  Protolint ENUM_NAMES_UPPER_CAMEL_CASE (error): example.proto[20,40]: EnumField name \"third.VALUE\" must be CAPITALS_WITH_UNDERSCORES
   159  `)
   160  	initTestCases.oneWarningOneError.want(`Protolint ENUM_NAMES_UPPER_CAMEL_CASE (warning): example.proto[5,10]: EnumField name \"fIRST_VALUE\" must be CAPITALS_WITH_UNDERSCORES
   161  Protolint ENUM_NAMES_UPPER_CAMEL_CASE (error): example.proto[10,20]: EnumField name \"SECOND.VALUE\" must be CAPITALS_WITH_UNDERSCORES
   162  `)
   163  	initTestCases.onlyErrors.want(`Protolint ENUM_NAMES_UPPER_CAMEL_CASE (error): example.proto[5,10]: EnumField name \"fIRST_VALUE\" must be CAPITALS_WITH_UNDERSCORES
   164  Protolint ENUM_NAMES_UPPER_CAMEL_CASE (error): example.proto[10,20]: EnumField name \"SECOND.VALUE\" must be CAPITALS_WITH_UNDERSCORES
   165  Protolint ENUM_NAMES_UPPER_CAMEL_CASE (error): example.proto[20,40]: EnumField name \"third.VALUE\" must be CAPITALS_WITH_UNDERSCORES
   166  `)
   167  
   168  	tests := initTestCases.tests()
   169  
   170  	reporter := reporters.NewCiReporterWithGenericFormat()
   171  	run_tests(t, tests, reporter)
   172  }
   173  
   174  func TestAzureDevOpsMatcherReporter_Report(t *testing.T) {
   175  	initTestCases := makeTestData()
   176  	initTestCases.oneOfEach.want(`##vso[task.logissue type=warning;sourcepath=example.proto;linenumber=10;columnnumber=20;code=ENUM_NAMES_UPPER_CAMEL_CASE;]EnumField name \"SECOND.VALUE\" must be CAPITALS_WITH_UNDERSCORES
   177  ##vso[task.logissue type=error;sourcepath=example.proto;linenumber=20;columnnumber=40;code=ENUM_NAMES_UPPER_CAMEL_CASE;]EnumField name \"third.VALUE\" must be CAPITALS_WITH_UNDERSCORES
   178  `)
   179  	initTestCases.oneWarningOneError.want(`##vso[task.logissue type=warning;sourcepath=example.proto;linenumber=5;columnnumber=10;code=ENUM_NAMES_UPPER_CAMEL_CASE;]EnumField name \"fIRST_VALUE\" must be CAPITALS_WITH_UNDERSCORES
   180  ##vso[task.logissue type=error;sourcepath=example.proto;linenumber=10;columnnumber=20;code=ENUM_NAMES_UPPER_CAMEL_CASE;]EnumField name \"SECOND.VALUE\" must be CAPITALS_WITH_UNDERSCORES
   181  `)
   182  	initTestCases.onlyErrors.want(`##vso[task.logissue type=error;sourcepath=example.proto;linenumber=5;columnnumber=10;code=ENUM_NAMES_UPPER_CAMEL_CASE;]EnumField name \"fIRST_VALUE\" must be CAPITALS_WITH_UNDERSCORES
   183  ##vso[task.logissue type=error;sourcepath=example.proto;linenumber=10;columnnumber=20;code=ENUM_NAMES_UPPER_CAMEL_CASE;]EnumField name \"SECOND.VALUE\" must be CAPITALS_WITH_UNDERSCORES
   184  ##vso[task.logissue type=error;sourcepath=example.proto;linenumber=20;columnnumber=40;code=ENUM_NAMES_UPPER_CAMEL_CASE;]EnumField name \"third.VALUE\" must be CAPITALS_WITH_UNDERSCORES
   185  `)
   186  
   187  	tests := initTestCases.tests()
   188  
   189  	reporter := reporters.NewCiReporterForAzureDevOps()
   190  	run_tests(t, tests, reporter)
   191  }
   192  func TestGithubActionMatcherReporter_Report(t *testing.T) {
   193  	initTestCases := makeTestData()
   194  	initTestCases.oneOfEach.want(`::notice file=example.proto,line=5,col=10,title=ENUM_NAMES_UPPER_CAMEL_CASE::EnumField name \"fIRST_VALUE\" must be CAPITALS_WITH_UNDERSCORES
   195  ::warning file=example.proto,line=10,col=20,title=ENUM_NAMES_UPPER_CAMEL_CASE::EnumField name \"SECOND.VALUE\" must be CAPITALS_WITH_UNDERSCORES
   196  ::error file=example.proto,line=20,col=40,title=ENUM_NAMES_UPPER_CAMEL_CASE::EnumField name \"third.VALUE\" must be CAPITALS_WITH_UNDERSCORES
   197  `)
   198  	initTestCases.oneWarningOneError.want(`::warning file=example.proto,line=5,col=10,title=ENUM_NAMES_UPPER_CAMEL_CASE::EnumField name \"fIRST_VALUE\" must be CAPITALS_WITH_UNDERSCORES
   199  ::error file=example.proto,line=10,col=20,title=ENUM_NAMES_UPPER_CAMEL_CASE::EnumField name \"SECOND.VALUE\" must be CAPITALS_WITH_UNDERSCORES
   200  `)
   201  	initTestCases.onlyErrors.want(`::error file=example.proto,line=5,col=10,title=ENUM_NAMES_UPPER_CAMEL_CASE::EnumField name \"fIRST_VALUE\" must be CAPITALS_WITH_UNDERSCORES
   202  ::error file=example.proto,line=10,col=20,title=ENUM_NAMES_UPPER_CAMEL_CASE::EnumField name \"SECOND.VALUE\" must be CAPITALS_WITH_UNDERSCORES
   203  ::error file=example.proto,line=20,col=40,title=ENUM_NAMES_UPPER_CAMEL_CASE::EnumField name \"third.VALUE\" must be CAPITALS_WITH_UNDERSCORES
   204  `)
   205  
   206  	tests := initTestCases.tests()
   207  
   208  	reporter := reporters.NewCiReporterForGithubActions()
   209  	run_tests(t, tests, reporter)
   210  }
   211  func TestGitlabCiCdMatcherReporter_Report(t *testing.T) {
   212  	initTestCases := makeTestData()
   213  	initTestCases.oneOfEach.want(`INFO: ENUM_NAMES_UPPER_CAMEL_CASE  example.proto(5,10) : EnumField name \"fIRST_VALUE\" must be CAPITALS_WITH_UNDERSCORES
   214  WARNING: ENUM_NAMES_UPPER_CAMEL_CASE  example.proto(10,20) : EnumField name \"SECOND.VALUE\" must be CAPITALS_WITH_UNDERSCORES
   215  ERROR: ENUM_NAMES_UPPER_CAMEL_CASE  example.proto(20,40) : EnumField name \"third.VALUE\" must be CAPITALS_WITH_UNDERSCORES
   216  `)
   217  	initTestCases.oneWarningOneError.want(`WARNING: ENUM_NAMES_UPPER_CAMEL_CASE  example.proto(5,10) : EnumField name \"fIRST_VALUE\" must be CAPITALS_WITH_UNDERSCORES
   218  ERROR: ENUM_NAMES_UPPER_CAMEL_CASE  example.proto(10,20) : EnumField name \"SECOND.VALUE\" must be CAPITALS_WITH_UNDERSCORES
   219  `)
   220  	initTestCases.onlyErrors.want(`ERROR: ENUM_NAMES_UPPER_CAMEL_CASE  example.proto(5,10) : EnumField name \"fIRST_VALUE\" must be CAPITALS_WITH_UNDERSCORES
   221  ERROR: ENUM_NAMES_UPPER_CAMEL_CASE  example.proto(10,20) : EnumField name \"SECOND.VALUE\" must be CAPITALS_WITH_UNDERSCORES
   222  ERROR: ENUM_NAMES_UPPER_CAMEL_CASE  example.proto(20,40) : EnumField name \"third.VALUE\" must be CAPITALS_WITH_UNDERSCORES
   223  `)
   224  
   225  	tests := initTestCases.tests()
   226  	reporter := reporters.NewCiReporterForGitlab()
   227  	run_tests(t, tests, reporter)
   228  }
   229  
   230  func TestEnvMatcherReporterFromTemplateString_Report(t *testing.T) {
   231  	t.Setenv("PROTOLINT_CIREPORTER_TEMPLATE_STRING", "{{ .Severity }}@{{ .File }}[{{ .Line }},{{ .Column }}] triggered rule {{ .Rule }} with message {{ .Message }}")
   232  	initTestCases := makeTestData()
   233  	initTestCases.oneOfEach.want(`info@example.proto[5,10] triggered rule ENUM_NAMES_UPPER_CAMEL_CASE with message EnumField name \"fIRST_VALUE\" must be CAPITALS_WITH_UNDERSCORES
   234  warning@example.proto[10,20] triggered rule ENUM_NAMES_UPPER_CAMEL_CASE with message EnumField name \"SECOND.VALUE\" must be CAPITALS_WITH_UNDERSCORES
   235  error@example.proto[20,40] triggered rule ENUM_NAMES_UPPER_CAMEL_CASE with message EnumField name \"third.VALUE\" must be CAPITALS_WITH_UNDERSCORES
   236  `)
   237  	initTestCases.oneWarningOneError.want(`warning@example.proto[5,10] triggered rule ENUM_NAMES_UPPER_CAMEL_CASE with message EnumField name \"fIRST_VALUE\" must be CAPITALS_WITH_UNDERSCORES
   238  error@example.proto[10,20] triggered rule ENUM_NAMES_UPPER_CAMEL_CASE with message EnumField name \"SECOND.VALUE\" must be CAPITALS_WITH_UNDERSCORES
   239  `)
   240  	initTestCases.onlyErrors.want(`error@example.proto[5,10] triggered rule ENUM_NAMES_UPPER_CAMEL_CASE with message EnumField name \"fIRST_VALUE\" must be CAPITALS_WITH_UNDERSCORES
   241  error@example.proto[10,20] triggered rule ENUM_NAMES_UPPER_CAMEL_CASE with message EnumField name \"SECOND.VALUE\" must be CAPITALS_WITH_UNDERSCORES
   242  error@example.proto[20,40] triggered rule ENUM_NAMES_UPPER_CAMEL_CASE with message EnumField name \"third.VALUE\" must be CAPITALS_WITH_UNDERSCORES
   243  `)
   244  
   245  	tests := initTestCases.tests()
   246  	reporter := reporters.NewCiReporterFromEnv()
   247  	run_tests(t, tests, reporter)
   248  }
   249  
   250  func TestEnvMatcherReporterFromTemplateFile_Report(t *testing.T) {
   251  	initTestCases := makeTestData()
   252  	initTestCases.oneOfEach.files.appendFile(t, "0oneOfEach.template", "[fromfile:0oneOfEach.template] {{ .Severity }}@{{ .File }}[{{ .Line }},{{ .Column }}] triggered rule {{ .Rule }} with message {{ .Message }}")
   253  	initTestCases.oneOfEach.want(`[fromfile:0oneOfEach.template] info@example.proto[5,10] triggered rule ENUM_NAMES_UPPER_CAMEL_CASE with message EnumField name \"fIRST_VALUE\" must be CAPITALS_WITH_UNDERSCORES
   254  [fromfile:0oneOfEach.template] warning@example.proto[10,20] triggered rule ENUM_NAMES_UPPER_CAMEL_CASE with message EnumField name \"SECOND.VALUE\" must be CAPITALS_WITH_UNDERSCORES
   255  [fromfile:0oneOfEach.template] error@example.proto[20,40] triggered rule ENUM_NAMES_UPPER_CAMEL_CASE with message EnumField name \"third.VALUE\" must be CAPITALS_WITH_UNDERSCORES
   256  `)
   257  	initTestCases.oneWarningOneError.files.appendFile(t, "0oneWarningOneError.template", "[fromfile:0oneWarningOneError.template] {{ .Severity }}@{{ .File }}[{{ .Line }},{{ .Column }}] triggered rule {{ .Rule }} with message {{ .Message }}")
   258  	initTestCases.oneWarningOneError.want(`[fromfile:0oneWarningOneError.template] warning@example.proto[5,10] triggered rule ENUM_NAMES_UPPER_CAMEL_CASE with message EnumField name \"fIRST_VALUE\" must be CAPITALS_WITH_UNDERSCORES
   259  [fromfile:0oneWarningOneError.template] error@example.proto[10,20] triggered rule ENUM_NAMES_UPPER_CAMEL_CASE with message EnumField name \"SECOND.VALUE\" must be CAPITALS_WITH_UNDERSCORES
   260  `)
   261  	initTestCases.onlyErrors.files.appendFile(t, "0onlyErrors.template", "[fromfile:0onlyErrors.template] {{ .Severity }}@{{ .File }}[{{ .Line }},{{ .Column }}] triggered rule {{ .Rule }} with message {{ .Message }}")
   262  	initTestCases.onlyErrors.want(`[fromfile:0onlyErrors.template] error@example.proto[5,10] triggered rule ENUM_NAMES_UPPER_CAMEL_CASE with message EnumField name \"fIRST_VALUE\" must be CAPITALS_WITH_UNDERSCORES
   263  [fromfile:0onlyErrors.template] error@example.proto[10,20] triggered rule ENUM_NAMES_UPPER_CAMEL_CASE with message EnumField name \"SECOND.VALUE\" must be CAPITALS_WITH_UNDERSCORES
   264  [fromfile:0onlyErrors.template] error@example.proto[20,40] triggered rule ENUM_NAMES_UPPER_CAMEL_CASE with message EnumField name \"third.VALUE\" must be CAPITALS_WITH_UNDERSCORES
   265  `)
   266  
   267  	tests := initTestCases.tests()
   268  	reporter := reporters.NewCiReporterFromEnv()
   269  	run_tests(t, tests, reporter)
   270  }
   271  
   272  func TestEnvMatcherReporterFromNonExistingTemplateFile_Report(t *testing.T) {
   273  	t.Setenv("PROTOLINT_CIREPORTER_TEMPLATE_FILE", filepath.Join(t.TempDir(), "does.not.exist"))
   274  	initTestCases := makeTestData()
   275  	initTestCases.oneOfEach.want(`Protolint ENUM_NAMES_UPPER_CAMEL_CASE (info): example.proto[5,10]: EnumField name \"fIRST_VALUE\" must be CAPITALS_WITH_UNDERSCORES
   276  Protolint ENUM_NAMES_UPPER_CAMEL_CASE (warning): example.proto[10,20]: EnumField name \"SECOND.VALUE\" must be CAPITALS_WITH_UNDERSCORES
   277  Protolint ENUM_NAMES_UPPER_CAMEL_CASE (error): example.proto[20,40]: EnumField name \"third.VALUE\" must be CAPITALS_WITH_UNDERSCORES
   278  `)
   279  	initTestCases.oneWarningOneError.want(`Protolint ENUM_NAMES_UPPER_CAMEL_CASE (warning): example.proto[5,10]: EnumField name \"fIRST_VALUE\" must be CAPITALS_WITH_UNDERSCORES
   280  Protolint ENUM_NAMES_UPPER_CAMEL_CASE (error): example.proto[10,20]: EnumField name \"SECOND.VALUE\" must be CAPITALS_WITH_UNDERSCORES
   281  `)
   282  	initTestCases.onlyErrors.want(`Protolint ENUM_NAMES_UPPER_CAMEL_CASE (error): example.proto[5,10]: EnumField name \"fIRST_VALUE\" must be CAPITALS_WITH_UNDERSCORES
   283  Protolint ENUM_NAMES_UPPER_CAMEL_CASE (error): example.proto[10,20]: EnumField name \"SECOND.VALUE\" must be CAPITALS_WITH_UNDERSCORES
   284  Protolint ENUM_NAMES_UPPER_CAMEL_CASE (error): example.proto[20,40]: EnumField name \"third.VALUE\" must be CAPITALS_WITH_UNDERSCORES
   285  `)
   286  
   287  	tests := initTestCases.tests()
   288  	reporter := reporters.NewCiReporterFromEnv()
   289  	run_tests(t, tests, reporter)
   290  }
   291  
   292  func TestEnvMatcherReporterFromUnallowedTemplateFile_Report(t *testing.T) {
   293  	tplFile := filepath.Join(t.TempDir(), "does.exist")
   294  	t.Setenv("PROTOLINT_CIREPORTER_TEMPLATE_FILE", tplFile)
   295  	t.Cleanup(func() {
   296  		if _, err := os.Stat(tplFile); os.IsNotExist(err) {
   297  			t.Logf("File %s already deleted", tplFile)
   298  		}
   299  
   300  		err := os.Remove(tplFile)
   301  		if err != nil {
   302  			t.Errorf("ERROR while cleaning up file %s: %v", tplFile, err)
   303  		}
   304  	})
   305  	file, err := os.Create(tplFile)
   306  	if err != nil {
   307  		t.Errorf("Failed to create temp file: %v", err)
   308  	}
   309  	_, err = file.Write([]byte("[fromfile:does.exist] {{ .Severity }}@{{ .File }}[{{ .Line }},{{ .Column }}] triggered rule {{ .Rule }} with message {{ .Message }}"))
   310  	if err != nil {
   311  		t.Errorf("Failed to write temp file: %v", err)
   312  	}
   313  	err = file.Close()
   314  	if err != nil {
   315  		t.Errorf("Failed to create temp file (error while closing): %v", err)
   316  	}
   317  	err = os.Chmod(tplFile, 0200)
   318  	if err != nil {
   319  		t.Errorf("Failed to remove read permissions: %v", err)
   320  	}
   321  
   322  	initTestCases := makeTestData()
   323  	initTestCases.oneOfEach.want(`Protolint ENUM_NAMES_UPPER_CAMEL_CASE (info): example.proto[5,10]: EnumField name \"fIRST_VALUE\" must be CAPITALS_WITH_UNDERSCORES
   324  Protolint ENUM_NAMES_UPPER_CAMEL_CASE (warning): example.proto[10,20]: EnumField name \"SECOND.VALUE\" must be CAPITALS_WITH_UNDERSCORES
   325  Protolint ENUM_NAMES_UPPER_CAMEL_CASE (error): example.proto[20,40]: EnumField name \"third.VALUE\" must be CAPITALS_WITH_UNDERSCORES
   326  `)
   327  	initTestCases.oneWarningOneError.want(`Protolint ENUM_NAMES_UPPER_CAMEL_CASE (warning): example.proto[5,10]: EnumField name \"fIRST_VALUE\" must be CAPITALS_WITH_UNDERSCORES
   328  Protolint ENUM_NAMES_UPPER_CAMEL_CASE (error): example.proto[10,20]: EnumField name \"SECOND.VALUE\" must be CAPITALS_WITH_UNDERSCORES
   329  `)
   330  	initTestCases.onlyErrors.want(`Protolint ENUM_NAMES_UPPER_CAMEL_CASE (error): example.proto[5,10]: EnumField name \"fIRST_VALUE\" must be CAPITALS_WITH_UNDERSCORES
   331  Protolint ENUM_NAMES_UPPER_CAMEL_CASE (error): example.proto[10,20]: EnumField name \"SECOND.VALUE\" must be CAPITALS_WITH_UNDERSCORES
   332  Protolint ENUM_NAMES_UPPER_CAMEL_CASE (error): example.proto[20,40]: EnumField name \"third.VALUE\" must be CAPITALS_WITH_UNDERSCORES
   333  `)
   334  
   335  	tests := initTestCases.tests()
   336  	reporter := reporters.NewCiReporterFromEnv()
   337  	run_tests(t, tests, reporter)
   338  }
   339  
   340  func TestEnvMatcherReporterFromErroneousTemplateFile_ReportTestEnvMatcherReporterFromErroneousTemplateString_Report(t *testing.T) {
   341  	initTestCases := makeTestData()
   342  	initTestCases.oneOfEach.files.appendFile(t, "1oneOfEach.template", "[fromfile:1oneOfEach.template] {{ .Severit }}@{{ .Fil }}[{{ .Lne }},{{ .Colum }}] triggered rule {{ .ule }} with message {{ .Msg }}")
   343  	initTestCases.oneOfEach.expectError(`template: Failure:1:34: executing "Failure" at <.Severit>: can't evaluate field Severit in type reporters.ciReportedFailure`)
   344  
   345  	initTestCases.oneWarningOneError.files.appendFile(t, "1oneWarningOneError.template", "[fromfile:1oneWarningOneError.template] {{ .Severit }}@{{ .Fil }}[{{ .Lne }},{{ .Colum }}] triggered rule {{ .ule }} with message {{ .Msg }}")
   346  	initTestCases.oneWarningOneError.expectError(`template: Failure:1:43: executing "Failure" at <.Severit>: can't evaluate field Severit in type reporters.ciReportedFailure`)
   347  
   348  	initTestCases.onlyErrors.files.appendFile(t, "1onlyErrors.template", "[fromfile:1onlyErrors.template] {{ .Severit }}@{{ .Fil }}[{{ .Lne }},{{ .Colum }}] triggered rule {{ .ule }} with message {{ .Msg }}")
   349  	initTestCases.onlyErrors.expectError(`template: Failure:1:35: executing "Failure" at <.Severit>: can't evaluate field Severit in type reporters.ciReportedFailure`)
   350  
   351  	tests := initTestCases.tests()
   352  	reporter := reporters.NewCiReporterFromEnv()
   353  	run_tests(t, tests, reporter)
   354  }
   355  
   356  func TestEnvMatcherReporterFromErroneousTemplateString_Report(t *testing.T) {
   357  	t.Setenv("PROTOLINT_CIREPORTER_TEMPLATE_STRING", "{{ .Severit }}@{{ .Fil }}[{{ .Lne }},{{ .Colum }}] triggered rule {{ .ule }} with message {{ .Msg }}")
   358  	initTestCases := makeTestData()
   359  	initTestCases.oneOfEach.expectError(`template: Failure:1:3: executing "Failure" at <.Severit>: can't evaluate field Severit in type reporters.ciReportedFailure`)
   360  	initTestCases.oneWarningOneError.expectError(`template: Failure:1:3: executing "Failure" at <.Severit>: can't evaluate field Severit in type reporters.ciReportedFailure`)
   361  	initTestCases.onlyErrors.expectError(`template: Failure:1:3: executing "Failure" at <.Severit>: can't evaluate field Severit in type reporters.ciReportedFailure`)
   362  
   363  	tests := initTestCases.tests()
   364  	reporter := reporters.NewCiReporterFromEnv()
   365  	run_tests(t, tests, reporter)
   366  }
   367  
   368  func run_tests(t *testing.T, tests []testStruct, r reporters.CiReporter) {
   369  	if len(tests) == 0 {
   370  		t.SkipNow()
   371  	}
   372  	for _, test := range tests {
   373  		test := test
   374  		t.Cleanup(func() { test.cleanUp(t) })
   375  		t.Run(test.name, func(t *testing.T) {
   376  			if len(test.files.files) > 0 {
   377  				t.Setenv("PROTOLINT_CIREPORTER_TEMPLATE_FILE", test.files.files[0])
   378  			}
   379  
   380  			buf := &bytes.Buffer{}
   381  			err := r.Report(buf, test.inputFailures)
   382  			test.cleanUp(t)
   383  			if err != nil {
   384  				isExpectedError := false
   385  				if test.expectedError != nil {
   386  					isExpectedError = err.Error() == test.expectedError.Error()
   387  				}
   388  
   389  				if !isExpectedError {
   390  					t.Errorf("got err %v, but want %v", err, test.expectedError)
   391  					return
   392  				} else {
   393  					t.Logf("Wanted %v, got %v", test.expectedError, err)
   394  				}
   395  			}
   396  			if buf.String() != test.wantOutput {
   397  				t.Errorf(`  got 
   398  %s
   399  , but want
   400  %s`, buf.String(), test.wantOutput)
   401  			}
   402  		})
   403  	}
   404  }
   405  
   406  func (ts testStruct) cleanUp(t *testing.T) {
   407  	ts.files.cleanUp(t)
   408  }
   409  
   410  func (tf testFiles) cleanUp(t *testing.T) {
   411  	for _, file := range tf.files {
   412  
   413  		if _, err := os.Stat(file); os.IsNotExist(err) {
   414  			t.Logf("File %s already deleted", file)
   415  			continue
   416  		}
   417  
   418  		err := os.Remove(file)
   419  		if err != nil {
   420  			t.Errorf("ERROR while cleaning up file %s: %v", file, err)
   421  		}
   422  	}
   423  }
   424  
   425  func (tf *testFiles) appendFile(t *testing.T, fileName string, fileContent string) {
   426  	filePath := filepath.Join(t.TempDir(), fileName)
   427  	file, err := os.Create(filePath)
   428  	if err != nil {
   429  		t.Errorf("Failed to create file %s: %v", filePath, err)
   430  		return
   431  	}
   432  
   433  	defer func(td *testing.T) {
   434  		err = file.Close()
   435  		if err != nil {
   436  			td.Errorf("Failed to content to file %s: %v", filePath, err)
   437  			return
   438  		}
   439  	}(t)
   440  
   441  	_, err = file.WriteString(fileContent)
   442  	if err != nil {
   443  		t.Errorf("Failed to content to file %s: %v", filePath, err)
   444  		return
   445  	}
   446  
   447  	tf.files = append(tf.files, filePath)
   448  }
   449  
   450  func (ts *testStruct) want(input string) {
   451  	ts.wantOutput = input
   452  }
   453  
   454  func (ts *testStruct) expectError(err string) {
   455  	ts.expectedError = fmt.Errorf(err)
   456  	ts.want("")
   457  }
   458  
   459  func (td testCases) tests() []testStruct {
   460  	var allCases []testStruct
   461  
   462  	allCases = append(allCases, td.oneOfEach)
   463  	allCases = append(allCases, td.oneWarningOneError)
   464  	allCases = append(allCases, td.onlyErrors)
   465  
   466  	return allCases
   467  }