Skip to content

Commit f616278

Browse files
Generalize CheckIfFileExists fn (#1668)
Co-authored-by: Azeem Shaikh <azeems@google.com>
1 parent c03085a commit f616278

File tree

8 files changed

+176
-175
lines changed

8 files changed

+176
-175
lines changed

checks/errors.go

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,12 @@ import (
1818
"errors"
1919
)
2020

21-
//nolint
2221
var (
2322
errInternalInvalidDockerFile = errors.New("invalid Dockerfile")
24-
errInternalInvalidYamlFile = errors.New("invalid yaml file")
25-
errInternalFilenameMatch = errors.New("filename match error")
26-
errInternalEmptyFile = errors.New("empty file")
2723
errInvalidGitHubWorkflow = errors.New("invalid GitHub workflow")
28-
errInternalNoReviews = errors.New("no reviews found")
29-
errInternalNoCommits = errors.New("no commits found")
30-
errInternalInvalidPermissions = errors.New("invalid permissions")
3124
errInternalNameCannotBeEmpty = errors.New("name cannot be empty")
3225
errInternalCheckFuncCannotBeNil = errors.New("checkFunc cannot be nil")
26+
// TODO(#1245): these should be moved under `raw` package after migration.
27+
errInvalidArgType = errors.New("invalid arg type")
28+
errInvalidArgLength = errors.New("invalid arg length")
3329
)

checks/fileparser/listing.go

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -168,22 +168,19 @@ func CheckFilesContentV6(shellPathFnPattern string,
168168
return nil
169169
}
170170

171-
// FileCbV6 is the callback.
172-
// The bool returned indicates whether the FileCbData
173-
// should continue iterating over files or not.
174-
type FileCbV6 func(path string, data FileCbData) (bool, error)
171+
// DoWhileTrueOnFilename takes a filename and optional variadic args and returns
172+
// true if the next filename should continue to be processed.
173+
type DoWhileTrueOnFilename func(path string, args ...interface{}) (bool, error)
175174

176-
// CheckIfFileExistsV6 downloads the tar of the repository and calls the onFile() to check
177-
// for the occurrence.
178-
func CheckIfFileExistsV6(repoClient clients.RepoClient,
179-
onFile FileCbV6, data FileCbData) error {
175+
// OnAllFilesDo iterates through all files returned by `repoClient` and
176+
// calls `onFile` fn on them until `onFile` returns error or a false value.
177+
func OnAllFilesDo(repoClient clients.RepoClient, onFile DoWhileTrueOnFilename, args ...interface{}) error {
180178
matchedFiles, err := repoClient.ListFiles(func(string) (bool, error) { return true, nil })
181179
if err != nil {
182-
// nolint: wrapcheck
183-
return err
180+
return fmt.Errorf("error during ListFiles: %w", err)
184181
}
185182
for _, filename := range matchedFiles {
186-
continueIter, err := onFile(filename, data)
183+
continueIter, err := onFile(filename, args...)
187184
if err != nil {
188185
return err
189186
}
@@ -192,7 +189,6 @@ func CheckIfFileExistsV6(repoClient clients.RepoClient,
192189
break
193190
}
194191
}
195-
196192
return nil
197193
}
198194

checks/fileparser/listing_test.go

Lines changed: 88 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,12 @@ import (
2424
mockrepo "github.com/ossf/scorecard/v4/clients/mockclients"
2525
)
2626

27+
var (
28+
errInvalidArgType = errors.New("invalid arg type")
29+
errInvalidArgLength = errors.New("invalid arg length")
30+
errTest = errors.New("test")
31+
)
32+
2733
func TestIsTemplateFile(t *testing.T) {
2834
t.Parallel()
2935

@@ -572,81 +578,108 @@ func TestCheckFilesContent(t *testing.T) {
572578
}
573579
}
574580

575-
// TestCheckFilesContentV6 tests the CheckFilesContentV6 function.
576-
func TestCheckIfFileExistsV6(t *testing.T) {
581+
// TestOnAllFilesDo tests the OnAllFilesDo function.
582+
// nolint:gocognit
583+
func TestOnAllFilesDo(t *testing.T) {
577584
t.Parallel()
578-
//nolint
579-
type args struct {
580-
cbReturn bool
581-
cbwantErr bool
582-
listFilesReturnError error
585+
586+
type testArgsFn func(args ...interface{}) bool
587+
validateCountIs := func(count int) testArgsFn {
588+
return func(args ...interface{}) bool {
589+
if len(args) == 0 {
590+
return false
591+
}
592+
val, ok := args[0].(*int)
593+
if !ok {
594+
return false
595+
}
596+
return val != nil && *val == count
597+
}
583598
}
584-
//nolint
599+
600+
incrementCount := func(path string, args ...interface{}) (bool, error) {
601+
if len(args) < 1 {
602+
return false, errInvalidArgLength
603+
}
604+
val, ok := args[0].(*int)
605+
if !ok || val == nil {
606+
return false, errInvalidArgType
607+
}
608+
(*val)++
609+
if len(args) > 1 {
610+
maxVal, ok := args[1].(int)
611+
if !ok {
612+
return false, errInvalidArgType
613+
}
614+
if *val >= maxVal {
615+
return false, nil
616+
}
617+
}
618+
return true, nil
619+
}
620+
alwaysFail := func(path string, args ...interface{}) (bool, error) {
621+
return false, errTest
622+
}
623+
// nolint
585624
tests := []struct {
586-
name string
587-
args args
588-
wantErr bool
625+
name string
626+
onFile DoWhileTrueOnFilename
627+
onFileArgs []interface{}
628+
listFiles []string
629+
errListFiles error
630+
err error
631+
testArgs testArgsFn
589632
}{
590633
{
591-
name: "cb true and no error",
592-
args: args{
593-
cbReturn: true,
594-
cbwantErr: false,
595-
listFilesReturnError: nil,
596-
},
597-
wantErr: false,
634+
name: "error during ListFiles",
635+
errListFiles: errTest,
636+
err: errTest,
637+
onFile: alwaysFail,
598638
},
599639
{
600-
name: "cb false and no error",
601-
args: args{
602-
cbReturn: false,
603-
cbwantErr: false,
604-
listFilesReturnError: nil,
605-
},
606-
wantErr: false,
640+
name: "empty ListFiles",
641+
listFiles: []string{},
642+
onFile: incrementCount,
643+
onFileArgs: []interface{}{new(int)},
644+
testArgs: validateCountIs(0),
607645
},
608646
{
609-
name: "cb wantErr and error",
610-
args: args{
611-
cbReturn: true,
612-
cbwantErr: true,
613-
listFilesReturnError: nil,
614-
},
615-
wantErr: true,
647+
name: "onFile true and no error",
648+
listFiles: []string{"foo", "bar"},
649+
onFile: incrementCount,
650+
onFileArgs: []interface{}{new(int)},
651+
testArgs: validateCountIs(2),
616652
},
617653
{
618-
name: "listFilesReturnError and error",
619-
args: args{
620-
cbReturn: true,
621-
cbwantErr: true,
622-
//nolint
623-
listFilesReturnError: errors.New("test error"),
624-
},
625-
wantErr: true,
654+
name: "onFile false and no error",
655+
listFiles: []string{"foo", "bar"},
656+
onFile: incrementCount,
657+
onFileArgs: []interface{}{new(int), 1 /*maxVal*/},
658+
testArgs: validateCountIs(1),
659+
},
660+
{
661+
name: "onFile has error",
662+
listFiles: []string{"foo", "bar"},
663+
onFile: alwaysFail,
664+
err: errTest,
626665
},
627666
}
628667
for _, tt := range tests {
629668
tt := tt // Re-initializing variable so it is not changed while executing the closure below
630669
t.Run(tt.name, func(t *testing.T) {
631670
t.Parallel()
632671

633-
x := func(path string, data FileCbData) (bool, error) {
634-
if tt.args.cbwantErr {
635-
//nolint
636-
return false, errors.New("test error")
637-
}
638-
return tt.args.cbReturn, nil
639-
}
640-
641672
ctrl := gomock.NewController(t)
642-
mockRepo := mockrepo.NewMockRepoClient(ctrl)
643-
mockRepo.EXPECT().ListFiles(gomock.Any()).Return([]string{"foo"}, nil).AnyTimes()
673+
mockRepoClient := mockrepo.NewMockRepoClient(ctrl)
674+
mockRepoClient.EXPECT().ListFiles(gomock.Any()).
675+
Return(tt.listFiles, tt.errListFiles).AnyTimes()
644676

645-
err := CheckIfFileExistsV6(mockRepo, x, x)
646-
647-
if (err != nil) != tt.wantErr {
648-
t.Errorf("CheckIfFileExistsV6() error = %v, wantErr %v for %v", err, tt.wantErr, tt.name)
649-
return
677+
err := OnAllFilesDo(mockRepoClient, tt.onFile, tt.onFileArgs...)
678+
if !errors.Is(err, tt.err) {
679+
t.Errorf("OnAllFilesDo() expected error = %v, got %v", tt.err, err)
680+
}
681+
if tt.testArgs != nil && !tt.testArgs(tt.onFileArgs...) {
682+
t.Error("testArgs validation failed")
650683
}
651684
})
652685
}

checks/license.go

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
package checks
1616

1717
import (
18+
"fmt"
1819
"regexp"
1920
"strings"
2021

@@ -105,17 +106,7 @@ func testLicenseCheck(name string) bool {
105106
func LicenseCheck(c *checker.CheckRequest) checker.CheckResult {
106107
var s string
107108

108-
onFile := func(name string, data fileparser.FileCbData) (bool, error) {
109-
if checkLicense(name) {
110-
if strData, ok := data.(*string); ok && strData != nil {
111-
*strData = name
112-
}
113-
return false, nil
114-
}
115-
return true, nil
116-
}
117-
118-
err := fileparser.CheckIfFileExistsV6(c.RepoClient, onFile, &s)
109+
err := fileparser.OnAllFilesDo(c.RepoClient, isLicenseFile, &s)
119110
if err != nil {
120111
return checker.CreateRuntimeErrorResult(CheckLicense, err)
121112
}
@@ -130,6 +121,23 @@ func LicenseCheck(c *checker.CheckRequest) checker.CheckResult {
130121
return checker.CreateMinScoreResult(CheckLicense, "license file not detected")
131122
}
132123

124+
var isLicenseFile fileparser.DoWhileTrueOnFilename = func(name string, args ...interface{}) (bool, error) {
125+
if len(args) != 1 {
126+
return false, fmt.Errorf("isLicenseFile requires exactly one argument: %w", errInvalidArgLength)
127+
}
128+
s, ok := args[0].(*string)
129+
if !ok {
130+
return false, fmt.Errorf("isLicenseFile requires argument of type: *string: %w", errInvalidArgType)
131+
}
132+
if checkLicense(name) {
133+
if s != nil {
134+
*s = name
135+
}
136+
return false, nil
137+
}
138+
return true, nil
139+
}
140+
133141
// CheckLicense to check whether the name parameter fulfill license file criteria.
134142
func checkLicense(name string) bool {
135143
for _, check := range regexChecks {

checks/raw/dependency_update_tool.go

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import (
2626
// DependencyUpdateTool is the exported name for Depdendency-Update-Tool.
2727
func DependencyUpdateTool(c clients.RepoClient) (checker.DependencyUpdateToolData, error) {
2828
var tools []checker.Tool
29-
err := fileparser.CheckIfFileExistsV6(c, checkDependencyFileExists, &tools)
29+
err := fileparser.OnAllFilesDo(c, checkDependencyFileExists, &tools)
3030
if err != nil {
3131
return checker.DependencyUpdateToolData{}, fmt.Errorf("%w", err)
3232
}
@@ -35,11 +35,14 @@ func DependencyUpdateTool(c clients.RepoClient) (checker.DependencyUpdateToolDat
3535
return checker.DependencyUpdateToolData{Tools: tools}, nil
3636
}
3737

38-
func checkDependencyFileExists(name string, data fileparser.FileCbData) (bool, error) {
39-
ptools, ok := data.(*[]checker.Tool)
38+
var checkDependencyFileExists fileparser.DoWhileTrueOnFilename = func(name string, args ...interface{}) (bool, error) {
39+
if len(args) != 1 {
40+
return false, fmt.Errorf("checkDependencyFileExists requires exactly one argument: %w", errInvalidArgLength)
41+
}
42+
ptools, ok := args[0].(*[]checker.Tool)
4043
if !ok {
41-
// This never happens.
42-
panic("invalid type")
44+
return false, fmt.Errorf(
45+
"checkDependencyFileExists requires an argument of type: *[]checker.Tool: %w", errInvalidArgType)
4346
}
4447

4548
switch strings.ToLower(name) {

checks/raw/errors.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,9 @@ import (
1818
"errors"
1919
)
2020

21-
//nolint
2221
var (
2322
errInternalCommitishNil = errors.New("commitish is nil")
2423
errInternalBranchNotFound = errors.New("branch not found")
24+
errInvalidArgType = errors.New("invalid arg type")
25+
errInvalidArgLength = errors.New("invalid arg length")
2526
)

0 commit comments

Comments
 (0)