github.com/yoheimuta/protolint@v0.49.8-0.20240515023657-4ecaebb7575d/internal/addon/rules/repeatedFieldNamesPluralizedRule_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  	"github.com/yoheimuta/protolint/internal/addon/rules"
    10  	"github.com/yoheimuta/protolint/linter/autodisable"
    11  	"github.com/yoheimuta/protolint/linter/report"
    12  	"github.com/yoheimuta/protolint/linter/rule"
    13  )
    14  
    15  func TestRepeatedFieldNamesPluralizedRule_Apply(t *testing.T) {
    16  	tests := []struct {
    17  		name             string
    18  		pluralRules      map[string]string
    19  		singularRules    map[string]string
    20  		uncountableRules []string
    21  		irregularRules   map[string]string
    22  		inputProto       *parser.Proto
    23  		wantFailures     []report.Failure
    24  	}{
    25  		{
    26  			name: "no failures for proto without fields",
    27  			inputProto: &parser.Proto{
    28  				ProtoBody: []parser.Visitee{
    29  					&parser.Enum{},
    30  				},
    31  			},
    32  		},
    33  		{
    34  			name: "no failures for proto with valid field names",
    35  			inputProto: &parser.Proto{
    36  				ProtoBody: []parser.Visitee{
    37  					&parser.Service{},
    38  					&parser.Message{
    39  						MessageBody: []parser.Visitee{
    40  							&parser.Field{
    41  								FieldName: "singer",
    42  							},
    43  							&parser.Field{
    44  								IsRepeated: true,
    45  								FieldName:  "singers",
    46  							},
    47  							&parser.GroupField{
    48  								IsRepeated: true,
    49  								GroupName:  "people",
    50  								MessageBody: []parser.Visitee{
    51  									&parser.Field{
    52  										IsRepeated: true,
    53  										FieldName:  "some_singers",
    54  									},
    55  								},
    56  							},
    57  						},
    58  					},
    59  				},
    60  			},
    61  		},
    62  		{
    63  			name: "no failures for proto with valid field names considering the rule is case insensitive",
    64  			inputProto: &parser.Proto{
    65  				ProtoBody: []parser.Visitee{
    66  					&parser.Service{},
    67  					&parser.Message{
    68  						MessageBody: []parser.Visitee{
    69  							&parser.Field{
    70  								IsRepeated: true,
    71  								FieldName:  "RunningOnDeviceIDS",
    72  							},
    73  							&parser.GroupField{
    74  								IsRepeated: true,
    75  								GroupName:  "RunningOnDeviceIDs",
    76  							},
    77  						},
    78  					},
    79  				},
    80  			},
    81  		},
    82  		{
    83  			name: "no failures for proto with field names including 'uri' by applying some customization internally",
    84  			inputProto: &parser.Proto{
    85  				ProtoBody: []parser.Visitee{
    86  					&parser.Service{},
    87  					&parser.Message{
    88  						MessageBody: []parser.Visitee{
    89  							&parser.Field{
    90  								IsRepeated: true,
    91  								FieldName:  "uris",
    92  							},
    93  							&parser.Field{
    94  								IsRepeated: true,
    95  								FieldName:  "module_uris",
    96  							},
    97  						},
    98  					},
    99  				},
   100  			},
   101  		},
   102  		{
   103  			name: "no failures for proto with field names by applying some customization",
   104  			inputProto: &parser.Proto{
   105  				ProtoBody: []parser.Visitee{
   106  					&parser.Service{},
   107  					&parser.Message{
   108  						MessageBody: []parser.Visitee{
   109  							&parser.Field{
   110  								IsRepeated: true,
   111  								FieldName:  "regexii",
   112  							},
   113  							&parser.Field{
   114  								IsRepeated: true,
   115  								FieldName:  "paper",
   116  							},
   117  							&parser.Field{
   118  								IsRepeated: true,
   119  								FieldName:  "paper",
   120  							},
   121  							&parser.Field{
   122  								IsRepeated: true,
   123  								FieldName:  "regular",
   124  							},
   125  						},
   126  					},
   127  				},
   128  			},
   129  			pluralRules: map[string]string{
   130  				"(?i)gex$": "gexii",
   131  			},
   132  			singularRules: map[string]string{
   133  				"(?i)gexii": "gex",
   134  			},
   135  			uncountableRules: []string{
   136  				"paper",
   137  			},
   138  			irregularRules: map[string]string{
   139  				"irregular": "regular",
   140  			},
   141  		},
   142  		{
   143  			name: "failures for proto with non-pluralized repeated field names",
   144  			inputProto: &parser.Proto{
   145  				ProtoBody: []parser.Visitee{
   146  					&parser.Message{
   147  						MessageBody: []parser.Visitee{
   148  							&parser.Field{
   149  								IsRepeated: true,
   150  								FieldName:  "singer",
   151  								Meta: meta.Meta{
   152  									Pos: meta.Position{
   153  										Filename: "example.proto",
   154  										Offset:   100,
   155  										Line:     5,
   156  										Column:   10,
   157  									},
   158  								},
   159  							},
   160  							&parser.Field{
   161  								IsRepeated: true,
   162  								FieldName:  "persons",
   163  								Meta: meta.Meta{
   164  									Pos: meta.Position{
   165  										Filename: "example.proto",
   166  										Offset:   200,
   167  										Line:     10,
   168  										Column:   20,
   169  									},
   170  								},
   171  							},
   172  							&parser.GroupField{
   173  								IsRepeated: true,
   174  								GroupName:  "some_singer",
   175  								Meta: meta.Meta{
   176  									Pos: meta.Position{
   177  										Filename: "example.proto",
   178  										Offset:   210,
   179  										Line:     14,
   180  										Column:   30,
   181  									},
   182  								},
   183  							},
   184  						},
   185  					},
   186  				},
   187  			},
   188  			wantFailures: []report.Failure{
   189  				report.Failuref(
   190  					meta.Position{
   191  						Filename: "example.proto",
   192  						Offset:   100,
   193  						Line:     5,
   194  						Column:   10,
   195  					},
   196  					"REPEATED_FIELD_NAMES_PLURALIZED",
   197  					`Repeated field name "singer" must be pluralized name "singers"`,
   198  				),
   199  				report.Failuref(
   200  					meta.Position{
   201  						Filename: "example.proto",
   202  						Offset:   200,
   203  						Line:     10,
   204  						Column:   20,
   205  					},
   206  					"REPEATED_FIELD_NAMES_PLURALIZED",
   207  					`Repeated field name "persons" must be pluralized name "people"`,
   208  				),
   209  				report.Failuref(
   210  					meta.Position{
   211  						Filename: "example.proto",
   212  						Offset:   210,
   213  						Line:     14,
   214  						Column:   30,
   215  					},
   216  					"REPEATED_FIELD_NAMES_PLURALIZED",
   217  					`Repeated group name "some_singer" must be pluralized name "some_singers"`,
   218  				),
   219  			},
   220  		},
   221  	}
   222  
   223  	for _, test := range tests {
   224  		test := test
   225  		t.Run(test.name, func(t *testing.T) {
   226  			rule := rules.NewRepeatedFieldNamesPluralizedRule(
   227  				rule.SeverityError,
   228  				test.pluralRules,
   229  				test.singularRules,
   230  				test.uncountableRules,
   231  				test.irregularRules,
   232  				false,
   233  				autodisable.Noop,
   234  			)
   235  
   236  			got, err := rule.Apply(test.inputProto)
   237  			if err != nil {
   238  				t.Errorf("got err %v, but want nil", err)
   239  				return
   240  			}
   241  			if !reflect.DeepEqual(got, test.wantFailures) {
   242  				t.Errorf("got %v, but want %v", got, test.wantFailures)
   243  			}
   244  		})
   245  	}
   246  }
   247  
   248  func TestRepeatedFieldNamesPluralizedRule_Apply_fix(t *testing.T) {
   249  	tests := []struct {
   250  		name             string
   251  		pluralRules      map[string]string
   252  		singularRules    map[string]string
   253  		uncountableRules []string
   254  		irregularRules   map[string]string
   255  		inputFilename    string
   256  		wantFilename     string
   257  	}{
   258  		{
   259  			name:          "no fix for a correct proto",
   260  			inputFilename: "pluralized.proto",
   261  			wantFilename:  "pluralized.proto",
   262  		},
   263  		{
   264  			name:          "fix for an incorrect proto",
   265  			inputFilename: "invalid.proto",
   266  			wantFilename:  "pluralized.proto",
   267  		},
   268  	}
   269  
   270  	for _, test := range tests {
   271  		test := test
   272  		t.Run(test.name, func(t *testing.T) {
   273  			r := rules.NewRepeatedFieldNamesPluralizedRule(
   274  				rule.SeverityError,
   275  				test.pluralRules,
   276  				test.singularRules,
   277  				test.uncountableRules,
   278  				test.irregularRules,
   279  				true,
   280  				autodisable.Noop,
   281  			)
   282  			testApplyFix(t, r, test.inputFilename, test.wantFilename)
   283  		})
   284  	}
   285  }
   286  
   287  func TestRepeatedFieldNamesPluralizedRule_Apply_disable(t *testing.T) {
   288  	tests := []struct {
   289  		name               string
   290  		pluralRules        map[string]string
   291  		singularRules      map[string]string
   292  		uncountableRules   []string
   293  		irregularRules     map[string]string
   294  		inputFilename      string
   295  		inputPlacementType autodisable.PlacementType
   296  		wantFilename       string
   297  	}{
   298  		{
   299  			name:          "do nothing in case of no violations",
   300  			inputFilename: "pluralized.proto",
   301  			wantFilename:  "pluralized.proto",
   302  		},
   303  		{
   304  			name:               "insert disable:next comments",
   305  			inputFilename:      "invalid.proto",
   306  			inputPlacementType: autodisable.Next,
   307  			wantFilename:       "disable_next.proto",
   308  		},
   309  		{
   310  			name:               "insert disable:this comments",
   311  			inputFilename:      "invalid.proto",
   312  			inputPlacementType: autodisable.ThisThenNext,
   313  			wantFilename:       "disable_this.proto",
   314  		},
   315  	}
   316  
   317  	for _, test := range tests {
   318  		test := test
   319  		t.Run(test.name, func(t *testing.T) {
   320  			r := rules.NewRepeatedFieldNamesPluralizedRule(
   321  				rule.SeverityError,
   322  				test.pluralRules,
   323  				test.singularRules,
   324  				test.uncountableRules,
   325  				test.irregularRules,
   326  				true,
   327  				test.inputPlacementType,
   328  			)
   329  			testApplyFix(t, r, test.inputFilename, test.wantFilename)
   330  		})
   331  	}
   332  }