diff --git a/.golangci.yml b/.golangci.yml index 5752e2f2..80a62880 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -12,6 +12,12 @@ issues: # Default: 3 max-same-issues: 0 new-from-rev: "" + exclude-rules: + - path: '(.+)_test\.go' + linters: + - funlen + - goconst + - gocyclo skip-files: - cron/data/request.pb.go # autogenerated linters: diff --git a/checker/check_request_test.go b/checker/check_request_test.go new file mode 100644 index 00000000..0db006cc --- /dev/null +++ b/checker/check_request_test.go @@ -0,0 +1,122 @@ +// Copyright 2023 OpenSSF Scorecard Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package checker + +import ( + "testing" + + "github.com/google/go-cmp/cmp" +) + +func TestListUnsupported(t *testing.T) { + t.Parallel() + type args struct { + required []RequestType + supported []RequestType + } + tests := []struct { + name string + args args + want []RequestType + }{ + { + name: "empty", + args: args{ + required: []RequestType{}, + supported: []RequestType{}, + }, + want: []RequestType{FileBased}, + }, + { + name: "empty required", + args: args{ + required: []RequestType{}, + supported: []RequestType{FileBased}, + }, + want: []RequestType{}, + }, + { + name: "supported", + args: args{ + required: []RequestType{FileBased}, + supported: []RequestType{FileBased}, + }, + want: []RequestType{FileBased}, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + if got := ListUnsupported(tt.args.required, tt.args.supported); cmp.Equal(got, tt.want) { + t.Errorf("ListUnsupported() = %v, want %v", got, cmp.Diff(got, tt.want)) + } + }) + } +} + +func Test_contains(t *testing.T) { + t.Parallel() + type args struct { + in []RequestType + exists RequestType + } + tests := []struct { + name string + args args + want bool + }{ + { + name: "empty", + args: args{ + in: []RequestType{}, + exists: FileBased, + }, + want: false, + }, + { + name: "empty exists", + args: args{ + in: []RequestType{FileBased}, + exists: FileBased, + }, + want: true, + }, + { + name: "empty exists", + args: args{ + in: []RequestType{FileBased}, + exists: CommitBased, + }, + want: false, + }, + { + name: "empty exists", + args: args{ + in: []RequestType{FileBased, CommitBased}, + exists: CommitBased, + }, + want: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + if got := contains(tt.args.in, tt.args.exists); got != tt.want { + t.Errorf("contains() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/checker/check_result.go b/checker/check_result.go index d49ac02a..8491bdd3 100644 --- a/checker/check_result.go +++ b/checker/check_result.go @@ -44,7 +44,7 @@ const ( const ( // DetailInfo is info-level log. DetailInfo DetailType = iota - // DetailWarn is warn log. + // DetailWarn is warned log. DetailWarn // DetailDebug is debug log. DetailDebug @@ -75,7 +75,7 @@ type CheckDetail struct { // //nolint:govet type LogMessage struct { - // Structured resuts. + // Structured results. Finding *finding.Finding // Non-structured results. @@ -127,13 +127,11 @@ func NormalizeReason(reason string, score int) string { } // CreateResultWithScore is used when -// the check runs without runtime errors and we want to assign a +// the check runs without runtime errors, and we want to assign a // specific score. func CreateResultWithScore(name, reason string, score int) CheckResult { return CheckResult{ - Name: name, - // Old structure. - // New structure. + Name: name, Version: 2, Error: nil, Score: score, @@ -144,8 +142,8 @@ func CreateResultWithScore(name, reason string, score int) CheckResult { // CreateProportionalScoreResult is used when // the check runs without runtime errors and we assign a // proportional score. This may be used if a check contains -// multiple tests and we want to assign a score proportional -// the the number of tests that succeeded. +// multiple tests, and we want to assign a score proportional +// the number of tests that succeeded. func CreateProportionalScoreResult(name, reason string, b, t int) CheckResult { score := CreateProportionalScore(b, t) return CheckResult{ @@ -178,9 +176,7 @@ func CreateMinScoreResult(name, reason string) CheckResult { // have enough evidence to set a score. func CreateInconclusiveResult(name, reason string) CheckResult { return CheckResult{ - Name: name, - // Old structure. - // New structure. + Name: name, Version: 2, Score: InconclusiveResultScore, Reason: reason, @@ -190,9 +186,7 @@ func CreateInconclusiveResult(name, reason string) CheckResult { // CreateRuntimeErrorResult is used when the check fails to run because of a runtime error. func CreateRuntimeErrorResult(name string, e error) CheckResult { return CheckResult{ - Name: name, - // Old structure. - // New structure. + Name: name, Version: 2, Error: e, Score: InconclusiveResultScore, diff --git a/checker/check_result_test.go b/checker/check_result_test.go new file mode 100644 index 00000000..291f0696 --- /dev/null +++ b/checker/check_result_test.go @@ -0,0 +1,470 @@ +// Copyright 2023 OpenSSF Scorecard Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package checker + +import ( + "errors" + "reflect" + "testing" + + "github.com/google/go-cmp/cmp" +) + +func TestAggregateScores(t *testing.T) { + t.Parallel() + type args struct { + scores []int + } + tests := []struct { + name string + args args + want int + }{ + { + name: "single", + args: args{ + scores: []int{1}, + }, + want: 1, + }, + { + name: "multiple", + args: args{ + scores: []int{1, 2, 3}, + }, + want: 2, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + if got := AggregateScores(tt.args.scores...); got != tt.want { //nolint:govet + t.Errorf("AggregateScores() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestAggregateScoresWithWeight(t *testing.T) { + t.Parallel() + type args struct { + scores map[int]int + } + tests := []struct { //nolint:govet + name string + args args + want int + }{ + { + name: "single", + args: args{ + scores: map[int]int{1: 1}, + }, + want: 1, + }, + { + name: "multiple", + args: args{ + scores: map[int]int{1: 1, 2: 2, 3: 3}, + }, + want: 2, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + if got := AggregateScoresWithWeight(tt.args.scores); got != tt.want { //nolint:govet + t.Errorf("AggregateScoresWithWeight() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestCreateProportionalScore(t *testing.T) { + t.Parallel() + type args struct { + success int + total int + } + tests := []struct { + name string + args args + want int + }{ + { + name: "empty", + args: args{ + success: 0, + }, + want: 0, + }, + { + name: "single", + args: args{ + success: 1, + total: 1, + }, + want: 10, + }, + { + name: "multiple", + args: args{ + success: 1, + total: 2, + }, + want: 5, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + if got := CreateProportionalScore(tt.args.success, tt.args.total); got != tt.want { //nolint:govet + t.Errorf("CreateProportionalScore() = %v, want %v", got, tt.want) //nolint:govet + } + }) + } +} + +func TestNormalizeReason(t *testing.T) { + t.Parallel() + type args struct { + reason string + score int + } + tests := []struct { //nolint:govet + name string + args args + want string + }{ + { + name: "empty", + args: args{ + reason: "", + }, + want: " -- score normalized to 0", + }, + { + name: "a reason", + args: args{ + reason: "reason", + score: 1, + }, + want: "reason -- score normalized to 1", + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + if got := NormalizeReason(tt.args.reason, tt.args.score); got != tt.want { //nolint:govet + t.Errorf("NormalizeReason() = %v, want %v", got, tt.want) //nolint:govet + } + }) + } +} + +func TestCreateResultWithScore(t *testing.T) { + t.Parallel() + type args struct { + name string + reason string + score int + } + tests := []struct { + name string + args args + want CheckResult + }{ + { + name: "empty", + args: args{ + name: "", + reason: "", + score: 0, + }, + want: CheckResult{ + Name: "", + Reason: "", + Score: 0, + Version: 2, + }, + }, + { + name: "a reason", + args: args{ + name: "name", + reason: "reason", + score: 1, + }, + want: CheckResult{ + Name: "name", + Reason: "reason", + Version: 2, + Score: 1, + }, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + if got := CreateResultWithScore(tt.args.name, tt.args.reason, tt.args.score); !cmp.Equal(got, tt.want) { //nolint:lll,govet + t.Errorf("CreateResultWithScore() = %v, want %v", got, cmp.Diff(got, tt.want)) //nolint:govet + } + }) + } +} + +func TestCreateProportionalScoreResult(t *testing.T) { + t.Parallel() + type args struct { + name string + reason string + b int + t int + } + tests := []struct { //nolint:govet + name string + args args + want CheckResult + }{ + { + name: "empty", + args: args{ + name: "", + reason: "", + b: 0, + t: 0, + }, + want: CheckResult{ + Name: "", + Reason: " -- score normalized to 0", + Score: 0, + Version: 2, + }, + }, + { + name: "a reason", + args: args{ + name: "name", + reason: "reason", + b: 1, + t: 1, + }, + want: CheckResult{ + Name: "name", + Reason: "reason -- score normalized to 10", + Score: 10, + Version: 2, + }, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + if got := CreateProportionalScoreResult(tt.args.name, tt.args.reason, tt.args.b, tt.args.t); !cmp.Equal(got, tt.want) { //nolint:govet,lll + t.Errorf("CreateProportionalScoreResult() = %v, want %v", got, cmp.Diff(got, tt.want)) //nolint:govet + } + }) + } +} + +func TestCreateMaxScoreResult(t *testing.T) { + t.Parallel() + type args struct { + name string + reason string + } + tests := []struct { + name string + args args + want CheckResult + }{ + { + name: "empty", + args: args{ + name: "", + reason: "", + }, + want: CheckResult{ + Name: "", + Reason: "", + Score: 10, + Version: 2, + }, + }, + { + name: "a reason", + args: args{ + name: "name", + reason: "reason", + }, + want: CheckResult{ + Name: "name", + Reason: "reason", + Score: 10, + Version: 2, + }, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + if got := CreateMaxScoreResult(tt.args.name, tt.args.reason); !cmp.Equal(got, tt.want) { //nolint:govet + t.Errorf("CreateMaxScoreResult() = %v, want %v", got, cmp.Diff(got, tt.want)) + } + }) + } +} + +func TestCreateMinScoreResult(t *testing.T) { + t.Parallel() + type args struct { + name string + reason string + } + tests := []struct { + name string + args args + want CheckResult + }{ + { + name: "empty", + args: args{ + name: "", + reason: "", + }, + want: CheckResult{ + Name: "", + Reason: "", + Score: 0, + Version: 2, + }, + }, + { + name: "a reason", + args: args{ + name: "name", + reason: "reason", + }, + want: CheckResult{ + Name: "name", + Reason: "reason", + Score: 0, + Version: 2, + }, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + if got := CreateMinScoreResult(tt.args.name, tt.args.reason); !cmp.Equal(got, tt.want) { //nolint:govet + t.Errorf("CreateMinScoreResult() = %v, want %v", got, cmp.Diff(got, tt.want)) + } + }) + } +} + +func TestCreateInconclusiveResult(t *testing.T) { + t.Parallel() + type args struct { + name string + reason string + } + tests := []struct { + name string + args args + want CheckResult + }{ + { + name: "empty", + args: args{ + name: "", + reason: "", + }, + want: CheckResult{ + Name: "", + Reason: "", + Score: -1, + Version: 2, + }, + }, + { + name: "a reason", + args: args{ + name: "name", + reason: "reason", + }, + want: CheckResult{ + Name: "name", + Reason: "reason", + Score: -1, + Version: 2, + }, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + if got := CreateInconclusiveResult(tt.args.name, tt.args.reason); !cmp.Equal(got, tt.want) { + t.Errorf("CreateInconclusiveResult() = %v, want %v", got, cmp.Diff(got, tt.want)) + } + }) + } +} + +func TestCreateRuntimeErrorResult(t *testing.T) { + t.Parallel() + type args struct { //nolint:govet + name string + e error + } + tests := []struct { + name string + args args + want CheckResult + }{ + { + name: "empty", + args: args{ + name: "", + e: errors.New("runtime error"), //nolint:goerr113 + }, + want: CheckResult{ + Name: "", + Reason: "runtime error", + Score: -1, + Version: 2, + Error: errors.New("runtime error"), //nolint:goerr113 + }, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + if got := CreateRuntimeErrorResult(tt.args.name, tt.args.e); !reflect.DeepEqual(got, tt.want) { + t.Errorf("CreateRuntimeErrorResult() = %v, want %v", got, cmp.Diff(got, tt.want)) + } + }) + } +}