Skip to content

Commit f3d7dca

Browse files
Refactored internal/scorer/scorer (#317)
* Refactored internal/scorer/scorer - Refactored `internal/scorer/scorer.go` to improve readablilty. Signed-off-by: nathannaveen <42319948+nathannaveen@users.noreply.github.com> * Updated based on code review Signed-off-by: nathannaveen <42319948+nathannaveen@users.noreply.github.com> * Included Test for scorer Signed-off-by: nathannaveen <42319948+nathannaveen@users.noreply.github.com> * Updated Tests for scorer Signed-off-by: nathannaveen <42319948+nathannaveen@users.noreply.github.com> * Updated based on code review Signed-off-by: nathannaveen <42319948+nathannaveen@users.noreply.github.com> --------- Signed-off-by: nathannaveen <42319948+nathannaveen@users.noreply.github.com> Co-authored-by: Caleb Brown <calebbrown@google.com>
1 parent aedb63b commit f3d7dca

File tree

2 files changed

+203
-7
lines changed

2 files changed

+203
-7
lines changed

internal/scorer/scorer.go

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,21 +18,26 @@ import (
1818
"fmt"
1919
"io"
2020
"path"
21-
"regexp"
2221
"strconv"
2322
"strings"
23+
"unicode"
2424

2525
"github.com/ossf/criticality_score/internal/collector/signal"
2626
"github.com/ossf/criticality_score/internal/scorer/algorithm"
2727
_ "github.com/ossf/criticality_score/internal/scorer/algorithm/wam"
2828
)
2929

30+
var ErrEmptyName = fmt.Errorf("name must be non-empty")
31+
3032
type Scorer struct {
3133
a algorithm.Algorithm
3234
name string
3335
}
3436

3537
func FromConfig(name string, r io.Reader) (*Scorer, error) {
38+
if name == "" {
39+
return nil, ErrEmptyName
40+
}
3641
cfg, err := LoadConfig(r)
3742
if err != nil {
3843
return nil, fmt.Errorf("load config: %w", err)
@@ -50,8 +55,9 @@ func FromConfig(name string, r io.Reader) (*Scorer, error) {
5055
func (s *Scorer) Score(signals []signal.Set) float64 {
5156
record := make(map[string]float64)
5257
for _, s := range signals {
53-
// Get all of the signal data from the set and floatify it.
58+
// Get all the signal data from the set change it to a float.
5459
for k, v := range signal.SetAsMap(s, true) {
60+
fmt.Println(k, v)
5561
switch r := v.(type) {
5662
case float64:
5763
record[k] = r
@@ -102,11 +108,20 @@ func (s *Scorer) Name() string {
102108
func NameFromFilepath(filepath string) string {
103109
// Get the name of the file used, without the path
104110
f := path.Base(filepath)
111+
112+
modifier := func(r rune) rune {
113+
// Change any non-alphanumeric character into an underscore
114+
if !unicode.IsDigit(r) && !unicode.IsLetter(r) {
115+
return '_'
116+
}
117+
// Convert any characters to lowercase
118+
return unicode.ToLower(r)
119+
}
120+
121+
// Strip the extension
105122
ext := path.Ext(f)
106-
// Strip the extension and convert to lowercase
107-
f = strings.ToLower(strings.TrimSuffix(f, ext))
108-
// Change any non-alphanumeric character into an underscore
109-
f = regexp.MustCompile("[^a-z0-9_]").ReplaceAllString(f, "_")
123+
f = strings.TrimSuffix(f, ext)
124+
110125
// Append "_score" to the end
111-
return f + "_score"
126+
return strings.Map(modifier, f) + "_score"
112127
}

internal/scorer/scorer_test.go

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
// Copyright 2022 Criticality Score Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package scorer
16+
17+
import (
18+
"testing"
19+
20+
"github.com/ossf/criticality_score/internal/collector/signal"
21+
"github.com/ossf/criticality_score/internal/scorer/algorithm"
22+
)
23+
24+
type testAlgo struct {
25+
UpdatedCount signal.Field[int] `signal:"legacy"`
26+
}
27+
28+
func (t testAlgo) Score(record map[string]float64) float64 {
29+
sum := 0.0
30+
for _, v := range record {
31+
sum += v
32+
}
33+
return sum
34+
}
35+
36+
func (t testAlgo) Namespace() signal.Namespace {
37+
return ""
38+
}
39+
40+
func TestScorer_ScoreRaw(t *testing.T) {
41+
tests := []struct { //nolint:govet
42+
name string
43+
s *Scorer
44+
raw map[string]string
45+
want float64
46+
}{
47+
{
48+
name: "average test",
49+
s: &Scorer{
50+
name: "Valid",
51+
a: testAlgo{},
52+
},
53+
raw: map[string]string{
54+
"one": "1",
55+
"two": "2",
56+
},
57+
want: 3,
58+
},
59+
{
60+
name: "invalid",
61+
s: &Scorer{
62+
name: "invalid",
63+
a: testAlgo{},
64+
},
65+
raw: map[string]string{
66+
"invalid number": "abcd",
67+
},
68+
want: 0,
69+
},
70+
{
71+
name: "empty",
72+
73+
s: &Scorer{
74+
name: "Valid",
75+
a: testAlgo{},
76+
},
77+
raw: map[string]string{},
78+
want: 0,
79+
},
80+
}
81+
for _, tt := range tests {
82+
t.Run(tt.name, func(t *testing.T) {
83+
if got := tt.s.ScoreRaw(tt.raw); got != tt.want {
84+
t.Errorf("ScoreRaw() = %v, want %v", got, tt.want)
85+
}
86+
})
87+
}
88+
}
89+
90+
func TestNameFromFilepath(t *testing.T) {
91+
tests := []struct {
92+
name string
93+
filepath string
94+
want string
95+
}{
96+
{
97+
name: "empty",
98+
filepath: "",
99+
want: "_score",
100+
},
101+
{
102+
name: "without extension",
103+
filepath: "test",
104+
want: "test_score",
105+
},
106+
{
107+
name: "with extension",
108+
filepath: "test.json",
109+
want: "test_score",
110+
},
111+
{
112+
name: "with path",
113+
filepath: "path/to/test.json",
114+
want: "test_score",
115+
},
116+
{
117+
name: "invalid characters",
118+
filepath: "configuración-+=_básica.yaml",
119+
want: "configuración____básica_score",
120+
},
121+
}
122+
for _, test := range tests {
123+
t.Run(test.name, func(t *testing.T) {
124+
if got := NameFromFilepath(test.filepath); got != test.want {
125+
t.Errorf("NameFromFilepath() = %v, want %v", got, test.want)
126+
}
127+
})
128+
}
129+
}
130+
131+
func TestScorer_Name(t *testing.T) {
132+
test := struct {
133+
name string
134+
s *Scorer
135+
want string
136+
}{
137+
name: "default",
138+
s: &Scorer{
139+
name: "Valid",
140+
a: testAlgo{},
141+
},
142+
want: "Valid",
143+
}
144+
145+
if got := test.s.Name(); got != test.want {
146+
t.Errorf("Name() = %v, want %v", got, test.want)
147+
}
148+
}
149+
150+
func TestScorer_Score(t *testing.T) {
151+
type fields struct {
152+
a algorithm.Algorithm
153+
name string
154+
}
155+
test := struct {
156+
name string
157+
fields fields
158+
signals []signal.Set
159+
want float64
160+
}{
161+
name: "average test",
162+
fields: fields{
163+
a: testAlgo{},
164+
name: "Valid",
165+
},
166+
signals: []signal.Set{
167+
&testAlgo{
168+
UpdatedCount: signal.Val(1),
169+
},
170+
},
171+
want: 1,
172+
}
173+
174+
s := &Scorer{
175+
a: test.fields.a,
176+
name: test.fields.name,
177+
}
178+
if got := s.Score(test.signals); got != test.want {
179+
t.Errorf("Score() = %v, want %v", got, test.want)
180+
}
181+
}

0 commit comments

Comments
 (0)