github.com/yoheimuta/protolint@v0.49.8-0.20240515023657-4ecaebb7575d/internal/addon/rules/fieldNamesLowerSnakeCaseRule_test.go (about)

     1  package rules_test
     2  
     3  import (
     4  	"reflect"
     5  	"testing"
     6  
     7  	"github.com/yoheimuta/go-protoparser/v4/parser"
     8  	"github.com/yoheimuta/go-protoparser/v4/parser/meta"
     9  
    10  	"github.com/yoheimuta/protolint/internal/addon/rules"
    11  	"github.com/yoheimuta/protolint/linter/autodisable"
    12  	"github.com/yoheimuta/protolint/linter/report"
    13  	"github.com/yoheimuta/protolint/linter/rule"
    14  )
    15  
    16  func TestFieldNamesLowerSnakeCaseRule_Apply(t *testing.T) {
    17  	tests := []struct {
    18  		name         string
    19  		inputProto   *parser.Proto
    20  		wantFailures []report.Failure
    21  	}{
    22  		{
    23  			name: "no failures for proto without fields",
    24  			inputProto: &parser.Proto{
    25  				ProtoBody: []parser.Visitee{
    26  					&parser.Enum{},
    27  				},
    28  			},
    29  		},
    30  		{
    31  			name: "no failures for proto with valid field names",
    32  			inputProto: &parser.Proto{
    33  				ProtoBody: []parser.Visitee{
    34  					&parser.Service{},
    35  					&parser.Message{
    36  						MessageBody: []parser.Visitee{
    37  							&parser.Field{
    38  								FieldName: "song_name",
    39  							},
    40  							&parser.Field{
    41  								FieldName: "singer",
    42  							},
    43  							&parser.MapField{
    44  								MapName: "song_name2",
    45  							},
    46  							&parser.Oneof{
    47  								OneofFields: []*parser.OneofField{
    48  									{
    49  										FieldName: "song_name3",
    50  									},
    51  								},
    52  							},
    53  						},
    54  					},
    55  				},
    56  			},
    57  		},
    58  		{
    59  			name: "failures for proto with invalid field names",
    60  			inputProto: &parser.Proto{
    61  				ProtoBody: []parser.Visitee{
    62  					&parser.Message{
    63  						MessageBody: []parser.Visitee{
    64  							&parser.Field{
    65  								FieldName: "song_Name",
    66  								Meta: meta.Meta{
    67  									Pos: meta.Position{
    68  										Filename: "example.proto",
    69  										Offset:   100,
    70  										Line:     5,
    71  										Column:   10,
    72  									},
    73  								},
    74  							},
    75  							&parser.MapField{
    76  								MapName: "MapFieldName",
    77  								Meta: meta.Meta{
    78  									Pos: meta.Position{
    79  										Filename: "example.proto",
    80  										Offset:   210,
    81  										Line:     14,
    82  										Column:   30,
    83  									},
    84  								},
    85  							},
    86  							&parser.Oneof{
    87  								OneofFields: []*parser.OneofField{
    88  									{
    89  										FieldName: "OneofFieldName",
    90  										Meta: meta.Meta{
    91  											Pos: meta.Position{
    92  												Filename: "example.proto",
    93  												Offset:   300,
    94  												Line:     21,
    95  												Column:   45,
    96  											},
    97  										},
    98  									},
    99  								},
   100  							},
   101  						},
   102  					},
   103  				},
   104  			},
   105  			wantFailures: []report.Failure{
   106  				report.Failuref(
   107  					meta.Position{
   108  						Filename: "example.proto",
   109  						Offset:   100,
   110  						Line:     5,
   111  						Column:   10,
   112  					},
   113  					"FIELD_NAMES_LOWER_SNAKE_CASE",
   114  					`Field name "song_Name" must be underscore_separated_names like "song_name"`,
   115  				),
   116  				report.Failuref(
   117  					meta.Position{
   118  						Filename: "example.proto",
   119  						Offset:   210,
   120  						Line:     14,
   121  						Column:   30,
   122  					},
   123  					"FIELD_NAMES_LOWER_SNAKE_CASE",
   124  					`Field name "MapFieldName" must be underscore_separated_names like "map_field_name"`,
   125  				),
   126  				report.Failuref(
   127  					meta.Position{
   128  						Filename: "example.proto",
   129  						Offset:   300,
   130  						Line:     21,
   131  						Column:   45,
   132  					},
   133  					"FIELD_NAMES_LOWER_SNAKE_CASE",
   134  					`Field name "OneofFieldName" must be underscore_separated_names like "oneof_field_name"`,
   135  				),
   136  			},
   137  		},
   138  	}
   139  
   140  	for _, test := range tests {
   141  		test := test
   142  		t.Run(test.name, func(t *testing.T) {
   143  			rule := rules.NewFieldNamesLowerSnakeCaseRule(rule.SeverityError, false, autodisable.Noop)
   144  
   145  			got, err := rule.Apply(test.inputProto)
   146  			if err != nil {
   147  				t.Errorf("got err %v, but want nil", err)
   148  				return
   149  			}
   150  			if !reflect.DeepEqual(got, test.wantFailures) {
   151  				t.Errorf("got %v, but want %v", got, test.wantFailures)
   152  			}
   153  		})
   154  	}
   155  }
   156  
   157  func TestFieldNamesLowerSnakeCaseRule_Apply_fix(t *testing.T) {
   158  	tests := []struct {
   159  		name          string
   160  		inputFilename string
   161  		wantFilename  string
   162  	}{
   163  		{
   164  			name:          "no fix for a correct proto",
   165  			inputFilename: "lower_snake_case.proto",
   166  			wantFilename:  "lower_snake_case.proto",
   167  		},
   168  		{
   169  			name:          "fix for an incorrect proto",
   170  			inputFilename: "invalid.proto",
   171  			wantFilename:  "lower_snake_case.proto",
   172  		},
   173  	}
   174  
   175  	for _, test := range tests {
   176  		test := test
   177  		t.Run(test.name, func(t *testing.T) {
   178  			r := rules.NewFieldNamesLowerSnakeCaseRule(rule.SeverityError, true, autodisable.Noop)
   179  			testApplyFix(t, r, test.inputFilename, test.wantFilename)
   180  		})
   181  	}
   182  }
   183  
   184  func TestFieldNamesLowerSnakeCaseRule_Apply_disable(t *testing.T) {
   185  	tests := []struct {
   186  		name               string
   187  		inputFilename      string
   188  		inputPlacementType autodisable.PlacementType
   189  		wantFilename       string
   190  	}{
   191  		{
   192  			name:          "do nothing in case of no violations",
   193  			inputFilename: "lower_snake_case.proto",
   194  			wantFilename:  "lower_snake_case.proto",
   195  		},
   196  		{
   197  			name:               "insert disable:next comments",
   198  			inputFilename:      "invalid.proto",
   199  			inputPlacementType: autodisable.Next,
   200  			wantFilename:       "disable_next.proto",
   201  		},
   202  		{
   203  			name:               "insert disable:this comments",
   204  			inputFilename:      "invalid.proto",
   205  			inputPlacementType: autodisable.ThisThenNext,
   206  			wantFilename:       "disable_this.proto",
   207  		},
   208  	}
   209  
   210  	for _, test := range tests {
   211  		test := test
   212  		t.Run(test.name, func(t *testing.T) {
   213  			r := rules.NewFieldNamesLowerSnakeCaseRule(rule.SeverityError, true, test.inputPlacementType)
   214  			testApplyFix(t, r, test.inputFilename, test.wantFilename)
   215  		})
   216  	}
   217  }