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 }