github.com/yoheimuta/protolint@v0.49.8-0.20240515023657-4ecaebb7575d/internal/addon/rules/orderRule_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/report"
    12  	"github.com/yoheimuta/protolint/linter/rule"
    13  )
    14  
    15  func TestOrderRule_Apply(t *testing.T) {
    16  	tests := []struct {
    17  		name         string
    18  		inputProto   *parser.Proto
    19  		wantFailures []report.Failure
    20  	}{
    21  		{
    22  			name: "no failures for proto including all elements in order",
    23  			inputProto: &parser.Proto{
    24  				ProtoBody: []parser.Visitee{
    25  					&parser.Syntax{},
    26  					&parser.Package{},
    27  					&parser.Import{},
    28  					&parser.Import{},
    29  					&parser.Option{},
    30  					&parser.Option{},
    31  					&parser.Message{},
    32  					&parser.Enum{},
    33  					&parser.Service{},
    34  					&parser.Extend{},
    35  				},
    36  			},
    37  		},
    38  		{
    39  			name: "no failures for proto omitting the syntax",
    40  			inputProto: &parser.Proto{
    41  				ProtoBody: []parser.Visitee{
    42  					&parser.Package{},
    43  					&parser.Import{},
    44  					&parser.Import{},
    45  					&parser.Option{},
    46  					&parser.Option{},
    47  					&parser.Message{},
    48  					&parser.Enum{},
    49  					&parser.Service{},
    50  					&parser.Extend{},
    51  				},
    52  			},
    53  		},
    54  		{
    55  			name: "no failures for proto omitting the package",
    56  			inputProto: &parser.Proto{
    57  				ProtoBody: []parser.Visitee{
    58  					&parser.Syntax{},
    59  					&parser.Import{},
    60  					&parser.Import{},
    61  					&parser.Option{},
    62  					&parser.Option{},
    63  					&parser.Message{},
    64  					&parser.Enum{},
    65  					&parser.Service{},
    66  					&parser.Extend{},
    67  				},
    68  			},
    69  		},
    70  		{
    71  			name: "no failures for proto omitting the imports",
    72  			inputProto: &parser.Proto{
    73  				ProtoBody: []parser.Visitee{
    74  					&parser.Syntax{},
    75  					&parser.Package{},
    76  					&parser.Option{},
    77  					&parser.Option{},
    78  					&parser.Message{},
    79  					&parser.Enum{},
    80  					&parser.Service{},
    81  					&parser.Extend{},
    82  				},
    83  			},
    84  		},
    85  		{
    86  			name: "no failures for proto omitting the options",
    87  			inputProto: &parser.Proto{
    88  				ProtoBody: []parser.Visitee{
    89  					&parser.Syntax{},
    90  					&parser.Package{},
    91  					&parser.Import{},
    92  					&parser.Import{},
    93  					&parser.Message{},
    94  					&parser.Enum{},
    95  					&parser.Service{},
    96  					&parser.Extend{},
    97  				},
    98  			},
    99  		},
   100  		{
   101  			name: "no failures for proto omitting the everything else",
   102  			inputProto: &parser.Proto{
   103  				ProtoBody: []parser.Visitee{
   104  					&parser.Syntax{},
   105  					&parser.Package{},
   106  					&parser.Import{},
   107  					&parser.Import{},
   108  					&parser.Option{},
   109  					&parser.Option{},
   110  				},
   111  			},
   112  		},
   113  		{
   114  			name: "no failures for proto including only the everything else",
   115  			inputProto: &parser.Proto{
   116  				ProtoBody: []parser.Visitee{
   117  					&parser.Message{},
   118  					&parser.Enum{},
   119  					&parser.Service{},
   120  					&parser.Extend{},
   121  				},
   122  			},
   123  		},
   124  		{
   125  			name: "no failures for proto omitting the syntax and the package",
   126  			inputProto: &parser.Proto{
   127  				ProtoBody: []parser.Visitee{
   128  					&parser.Import{},
   129  					&parser.Import{},
   130  					&parser.Option{},
   131  					&parser.Option{},
   132  					&parser.Message{},
   133  					&parser.Enum{},
   134  					&parser.Service{},
   135  					&parser.Extend{},
   136  				},
   137  			},
   138  		},
   139  		{
   140  			name: "no failures for proto omitting the syntax, the package and the imports",
   141  			inputProto: &parser.Proto{
   142  				ProtoBody: []parser.Visitee{
   143  					&parser.Option{},
   144  					&parser.Option{},
   145  					&parser.Message{},
   146  					&parser.Enum{},
   147  					&parser.Service{},
   148  					&parser.Extend{},
   149  				},
   150  			},
   151  		},
   152  		{
   153  			name: "no failures for proto omitting the syntax, the package and the options",
   154  			inputProto: &parser.Proto{
   155  				ProtoBody: []parser.Visitee{
   156  					&parser.Import{},
   157  					&parser.Import{},
   158  					&parser.Message{},
   159  					&parser.Enum{},
   160  					&parser.Service{},
   161  					&parser.Extend{},
   162  				},
   163  			},
   164  		},
   165  		{
   166  			name: "failures for proto in which the order of the syntax is invalid",
   167  			inputProto: &parser.Proto{
   168  				ProtoBody: []parser.Visitee{
   169  					&parser.Package{},
   170  					&parser.Syntax{
   171  						Meta: meta.Meta{
   172  							Pos: meta.Position{
   173  								Filename: "example.proto",
   174  								Offset:   100,
   175  								Line:     5,
   176  								Column:   10,
   177  							},
   178  						},
   179  					},
   180  				},
   181  			},
   182  			wantFailures: []report.Failure{
   183  				report.Failuref(
   184  					meta.Position{
   185  						Filename: "example.proto",
   186  						Offset:   100,
   187  						Line:     5,
   188  						Column:   10,
   189  					},
   190  					"ORDER",
   191  					`Syntax should be located at the top. Check if the file is ordered in the correct manner.`,
   192  				),
   193  			},
   194  		},
   195  		{
   196  			name: "failures for proto in which the order of the package is invalid",
   197  			inputProto: &parser.Proto{
   198  				ProtoBody: []parser.Visitee{
   199  					&parser.Syntax{},
   200  					&parser.Import{},
   201  					&parser.Package{
   202  						Meta: meta.Meta{
   203  							Pos: meta.Position{
   204  								Filename: "example.proto",
   205  								Offset:   100,
   206  								Line:     5,
   207  								Column:   10,
   208  							},
   209  						},
   210  					},
   211  				},
   212  			},
   213  			wantFailures: []report.Failure{
   214  				report.Failuref(
   215  					meta.Position{
   216  						Filename: "example.proto",
   217  						Offset:   100,
   218  						Line:     5,
   219  						Column:   10,
   220  					},
   221  					"ORDER",
   222  					`The order of Package is invalid. Check if the file is ordered in the correct manner.`,
   223  				),
   224  			},
   225  		},
   226  		{
   227  			name: "failures for proto in which the order of the imports is invalid",
   228  			inputProto: &parser.Proto{
   229  				ProtoBody: []parser.Visitee{
   230  					&parser.Syntax{},
   231  					&parser.Package{},
   232  					&parser.Message{},
   233  					&parser.Import{
   234  						Meta: meta.Meta{
   235  							Pos: meta.Position{
   236  								Filename: "example.proto",
   237  								Offset:   100,
   238  								Line:     5,
   239  								Column:   10,
   240  							},
   241  						},
   242  					},
   243  					&parser.Import{},
   244  					&parser.Option{},
   245  					&parser.Import{
   246  						Meta: meta.Meta{
   247  							Pos: meta.Position{
   248  								Filename: "example.proto",
   249  								Offset:   200,
   250  								Line:     10,
   251  								Column:   20,
   252  							},
   253  						},
   254  					},
   255  				},
   256  			},
   257  			wantFailures: []report.Failure{
   258  				report.Failuref(
   259  					meta.Position{
   260  						Filename: "example.proto",
   261  						Offset:   100,
   262  						Line:     5,
   263  						Column:   10,
   264  					},
   265  					"ORDER",
   266  					`The order of Import is invalid. Check if the file is ordered in the correct manner.`,
   267  				),
   268  				report.Failuref(
   269  					meta.Position{
   270  						Filename: "example.proto",
   271  						Offset:   200,
   272  						Line:     10,
   273  						Column:   20,
   274  					},
   275  					"ORDER",
   276  					`The order of Import is invalid. Check if the file is ordered in the correct manner.`,
   277  				),
   278  			},
   279  		},
   280  		{
   281  			name: "failures for proto in which the order of the options is invalid",
   282  			inputProto: &parser.Proto{
   283  				ProtoBody: []parser.Visitee{
   284  					&parser.Option{},
   285  					&parser.Extend{},
   286  					&parser.Option{
   287  						Meta: meta.Meta{
   288  							Pos: meta.Position{
   289  								Filename: "example.proto",
   290  								Offset:   100,
   291  								Line:     5,
   292  								Column:   10,
   293  							},
   294  						},
   295  					},
   296  					&parser.Option{},
   297  					&parser.Service{},
   298  					&parser.Option{
   299  						Meta: meta.Meta{
   300  							Pos: meta.Position{
   301  								Filename: "example.proto",
   302  								Offset:   200,
   303  								Line:     10,
   304  								Column:   20,
   305  							},
   306  						},
   307  					},
   308  				},
   309  			},
   310  			wantFailures: []report.Failure{
   311  				report.Failuref(
   312  					meta.Position{
   313  						Filename: "example.proto",
   314  						Offset:   100,
   315  						Line:     5,
   316  						Column:   10,
   317  					},
   318  					"ORDER",
   319  					`The order of Option is invalid. Check if the file is ordered in the correct manner.`,
   320  				),
   321  				report.Failuref(
   322  					meta.Position{
   323  						Filename: "example.proto",
   324  						Offset:   200,
   325  						Line:     10,
   326  						Column:   20,
   327  					},
   328  					"ORDER",
   329  					`The order of Option is invalid. Check if the file is ordered in the correct manner.`,
   330  				),
   331  			},
   332  		},
   333  	}
   334  
   335  	for _, test := range tests {
   336  		test := test
   337  		t.Run(test.name, func(t *testing.T) {
   338  			rule := rules.NewOrderRule(rule.SeverityError, false)
   339  
   340  			got, err := rule.Apply(test.inputProto)
   341  			if err != nil {
   342  				t.Errorf("got err %v, but want nil", err)
   343  				return
   344  			}
   345  			if !reflect.DeepEqual(got, test.wantFailures) {
   346  				t.Errorf("got %v, but want %v", got, test.wantFailures)
   347  			}
   348  		})
   349  	}
   350  }
   351  
   352  func TestOrderRule_Apply_fix(t *testing.T) {
   353  	tests := []struct {
   354  		name          string
   355  		inputFilename string
   356  		wantFilename  string
   357  	}{
   358  		{
   359  			name:          "no fix for a correct proto",
   360  			inputFilename: "order.proto",
   361  			wantFilename:  "order.proto",
   362  		},
   363  		{
   364  			name:          "fix for an incorrect proto",
   365  			inputFilename: "invalid.proto",
   366  			wantFilename:  "order.proto",
   367  		},
   368  		{
   369  			name:          "fix for an incorrect proto while keeping contiguous misc elements",
   370  			inputFilename: "invalidContiguousMisc.proto",
   371  			wantFilename:  "orderContiguousMisc.proto",
   372  		},
   373  		{
   374  			name:          "fix for an incorrect proto filled with many elements",
   375  			inputFilename: "invalidMany.proto",
   376  			wantFilename:  "orderMany.proto",
   377  		},
   378  		{
   379  			name:          "fix for an incorrect proto filled with many comments",
   380  			inputFilename: "invalidWithComments.proto",
   381  			wantFilename:  "orderWithComments.proto",
   382  		},
   383  	}
   384  
   385  	for _, test := range tests {
   386  		test := test
   387  		t.Run(test.name, func(t *testing.T) {
   388  			r := rules.NewOrderRule(rule.SeverityError, true)
   389  			testApplyFix(t, r, test.inputFilename, test.wantFilename)
   390  		})
   391  	}
   392  }