github.com/yoheimuta/protolint@v0.49.8-0.20240515023657-4ecaebb7575d/internal/addon/rules/fileNamesLowerSnakeCaseRule_test.go (about) 1 package rules_test 2 3 import ( 4 "os" 5 "reflect" 6 "strings" 7 "testing" 8 9 "github.com/yoheimuta/protolint/internal/linter/file" 10 "github.com/yoheimuta/protolint/internal/setting_test" 11 "github.com/yoheimuta/protolint/internal/util_test" 12 "github.com/yoheimuta/protolint/linter/rule" 13 "github.com/yoheimuta/protolint/linter/strs" 14 15 "github.com/yoheimuta/go-protoparser/v4/parser/meta" 16 17 "github.com/yoheimuta/go-protoparser/v4/parser" 18 19 "github.com/yoheimuta/protolint/internal/addon/rules" 20 "github.com/yoheimuta/protolint/linter/report" 21 ) 22 23 func TestFileNamesLowerSnakeCaseRule_Apply(t *testing.T) { 24 tests := []struct { 25 name string 26 inputProto *parser.Proto 27 inputExcluded []string 28 wantFailures []report.Failure 29 }{ 30 { 31 name: "no failures for proto with a valid file name", 32 inputProto: &parser.Proto{ 33 Meta: &parser.ProtoMeta{ 34 Filename: "../proto/simple.proto", 35 }, 36 }, 37 }, 38 { 39 name: "no failures for proto with a valid lower snake case file name", 40 inputProto: &parser.Proto{ 41 Meta: &parser.ProtoMeta{ 42 Filename: "../proto/lower_snake_case.proto", 43 }, 44 }, 45 }, 46 { 47 name: "no failures for excluded proto", 48 inputProto: &parser.Proto{ 49 Meta: &parser.ProtoMeta{ 50 Filename: "proto/lowerSnakeCase.proto", 51 }, 52 }, 53 inputExcluded: []string{ 54 "proto/lowerSnakeCase.proto", 55 }, 56 }, 57 { 58 name: "a failure for proto with a camel case file name", 59 inputProto: &parser.Proto{ 60 Meta: &parser.ProtoMeta{ 61 Filename: "proto/lowerSnakeCase.proto", 62 }, 63 }, 64 wantFailures: []report.Failure{ 65 report.Failuref( 66 meta.Position{ 67 Filename: "proto/lowerSnakeCase.proto", 68 Offset: 0, 69 Line: 1, 70 Column: 1, 71 }, 72 "FILE_NAMES_LOWER_SNAKE_CASE", 73 `File name "lowerSnakeCase.proto" should be lower_snake_case.proto like "lower_snake_case.proto".`, 74 ), 75 }, 76 }, 77 { 78 name: "a failure for proto with an invalid file extension", 79 inputProto: &parser.Proto{ 80 Meta: &parser.ProtoMeta{ 81 Filename: "proto/lowerSnakeCase.txt", 82 }, 83 }, 84 wantFailures: []report.Failure{ 85 report.Failuref( 86 meta.Position{ 87 Filename: "proto/lowerSnakeCase.txt", 88 Offset: 0, 89 Line: 1, 90 Column: 1, 91 }, 92 "FILE_NAMES_LOWER_SNAKE_CASE", 93 `File name "lowerSnakeCase.txt" should be lower_snake_case.proto like "lower_snake_case.proto".`, 94 ), 95 }, 96 }, 97 { 98 name: "a failure for proto with an invalid separater", 99 inputProto: &parser.Proto{ 100 Meta: &parser.ProtoMeta{ 101 Filename: "proto/dot.separated.proto", 102 }, 103 }, 104 wantFailures: []report.Failure{ 105 report.Failuref( 106 meta.Position{ 107 Filename: "proto/dot.separated.proto", 108 Offset: 0, 109 Line: 1, 110 Column: 1, 111 }, 112 "FILE_NAMES_LOWER_SNAKE_CASE", 113 `File name "dot.separated.proto" should be lower_snake_case.proto like "dot_separated.proto".`, 114 ), 115 }, 116 }, 117 { 118 name: "a failure for proto with a kebab case file name", 119 inputProto: &parser.Proto{ 120 Meta: &parser.ProtoMeta{ 121 Filename: "proto/user-role.proto", 122 }, 123 }, 124 wantFailures: []report.Failure{ 125 report.Failuref( 126 meta.Position{ 127 Filename: "proto/user-role.proto", 128 Offset: 0, 129 Line: 1, 130 Column: 1, 131 }, 132 "FILE_NAMES_LOWER_SNAKE_CASE", 133 `File name "user-role.proto" should be lower_snake_case.proto like "user_role.proto".`, 134 ), 135 }, 136 }, 137 } 138 139 for _, test := range tests { 140 test := test 141 t.Run(test.name, func(t *testing.T) { 142 rule := rules.NewFileNamesLowerSnakeCaseRule(rule.SeverityError, test.inputExcluded, false) 143 144 got, err := rule.Apply(test.inputProto) 145 if err != nil { 146 t.Errorf("got err %v, but want nil", err) 147 return 148 } 149 if !reflect.DeepEqual(got, test.wantFailures) { 150 t.Errorf("got %v, but want %v", got, test.wantFailures) 151 } 152 }) 153 } 154 } 155 156 func TestFileNamesLowerSnakeCaseRule_Apply_fix(t *testing.T) { 157 tests := []struct { 158 name string 159 inputExcluded []string 160 inputFilename string 161 wantFilename string 162 wantAbort bool 163 }{ 164 { 165 name: "no fix for a correct proto", 166 inputFilename: "lower_snake_case.proto", 167 wantFilename: "lower_snake_case.proto", 168 }, 169 { 170 name: "abort to fix the proto because of alreadyExists", 171 inputFilename: "lowerSnakeCase.proto", 172 wantAbort: true, 173 }, 174 { 175 name: "fix for an incorrect proto", 176 inputFilename: "UpperCamelCase.proto", 177 wantFilename: "upper_camel_case.proto", 178 }, 179 { 180 name: "fix for a kebab case proto", 181 inputFilename: "kebab-case.proto", 182 wantFilename: "kebab_case.proto", 183 }, 184 } 185 186 for _, test := range tests { 187 test := test 188 t.Run(test.name, func(t *testing.T) { 189 r := rules.NewFileNamesLowerSnakeCaseRule(rule.SeverityError, test.inputExcluded, true) 190 191 dataDir := strs.ToLowerCamelCase(r.ID()) 192 input, err := util_test.NewTestData(setting_test.TestDataPath("rules", dataDir, test.inputFilename)) 193 if err != nil { 194 t.Errorf("got err %v", err) 195 return 196 } 197 proto, err := file.NewProtoFile(input.FilePath, input.FilePath).Parse(false) 198 if err != nil { 199 t.Errorf(err.Error()) 200 return 201 } 202 fs, err := r.Apply(proto) 203 if err != nil { 204 t.Errorf("got err %v, but want nil", err) 205 return 206 } 207 if test.wantAbort { 208 if _, err := os.Stat(input.FilePath); os.IsNotExist(err) { 209 t.Errorf("not found %q, but want to locate it", input.FilePath) 210 return 211 } 212 for _, f := range fs { 213 if strings.Contains(f.Message(), "Failed to rename") { 214 return 215 } 216 } 217 t.Error("not found failure message, but want to include it") 218 return 219 } 220 221 wantPath := setting_test.TestDataPath("rules", dataDir, test.wantFilename) 222 if _, err := os.Stat(wantPath); os.IsNotExist(err) { 223 t.Errorf("not found %q, but want to locate it", wantPath) 224 return 225 } 226 227 err = os.Rename(wantPath, input.FilePath) 228 if err != nil { 229 t.Errorf("got err %v", err) 230 } 231 }) 232 } 233 }