Skip to content

Commit

Permalink
Refactored internal/scorer/scorer (#317)
Browse files Browse the repository at this point in the history
* 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>
  • Loading branch information
nathannaveen and calebbrown committed Feb 27, 2023
1 parent aedb63b commit f3d7dca
Show file tree
Hide file tree
Showing 2 changed files with 203 additions and 7 deletions.
29 changes: 22 additions & 7 deletions internal/scorer/scorer.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,26 @@ import (
"fmt"
"io"
"path"
"regexp"
"strconv"
"strings"
"unicode"

"github.com/ossf/criticality_score/internal/collector/signal"
"github.com/ossf/criticality_score/internal/scorer/algorithm"
_ "github.com/ossf/criticality_score/internal/scorer/algorithm/wam"
)

var ErrEmptyName = fmt.Errorf("name must be non-empty")

type Scorer struct {
a algorithm.Algorithm
name string
}

func FromConfig(name string, r io.Reader) (*Scorer, error) {
if name == "" {
return nil, ErrEmptyName
}
cfg, err := LoadConfig(r)
if err != nil {
return nil, fmt.Errorf("load config: %w", err)
Expand All @@ -50,8 +55,9 @@ func FromConfig(name string, r io.Reader) (*Scorer, error) {
func (s *Scorer) Score(signals []signal.Set) float64 {
record := make(map[string]float64)
for _, s := range signals {
// Get all of the signal data from the set and floatify it.
// Get all the signal data from the set change it to a float.
for k, v := range signal.SetAsMap(s, true) {
fmt.Println(k, v)
switch r := v.(type) {
case float64:
record[k] = r
Expand Down Expand Up @@ -102,11 +108,20 @@ func (s *Scorer) Name() string {
func NameFromFilepath(filepath string) string {
// Get the name of the file used, without the path
f := path.Base(filepath)

modifier := func(r rune) rune {
// Change any non-alphanumeric character into an underscore
if !unicode.IsDigit(r) && !unicode.IsLetter(r) {
return '_'
}
// Convert any characters to lowercase
return unicode.ToLower(r)
}

// Strip the extension
ext := path.Ext(f)
// Strip the extension and convert to lowercase
f = strings.ToLower(strings.TrimSuffix(f, ext))
// Change any non-alphanumeric character into an underscore
f = regexp.MustCompile("[^a-z0-9_]").ReplaceAllString(f, "_")
f = strings.TrimSuffix(f, ext)

// Append "_score" to the end
return f + "_score"
return strings.Map(modifier, f) + "_score"
}
181 changes: 181 additions & 0 deletions internal/scorer/scorer_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
// Copyright 2022 Criticality Score 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
//
// https://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 scorer

import (
"testing"

"github.com/ossf/criticality_score/internal/collector/signal"
"github.com/ossf/criticality_score/internal/scorer/algorithm"
)

type testAlgo struct {
UpdatedCount signal.Field[int] `signal:"legacy"`
}

func (t testAlgo) Score(record map[string]float64) float64 {
sum := 0.0
for _, v := range record {
sum += v
}
return sum
}

func (t testAlgo) Namespace() signal.Namespace {
return ""
}

func TestScorer_ScoreRaw(t *testing.T) {
tests := []struct { //nolint:govet
name string
s *Scorer
raw map[string]string
want float64
}{
{
name: "average test",
s: &Scorer{
name: "Valid",
a: testAlgo{},
},
raw: map[string]string{
"one": "1",
"two": "2",
},
want: 3,
},
{
name: "invalid",
s: &Scorer{
name: "invalid",
a: testAlgo{},
},
raw: map[string]string{
"invalid number": "abcd",
},
want: 0,
},
{
name: "empty",

s: &Scorer{
name: "Valid",
a: testAlgo{},
},
raw: map[string]string{},
want: 0,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := tt.s.ScoreRaw(tt.raw); got != tt.want {
t.Errorf("ScoreRaw() = %v, want %v", got, tt.want)
}
})
}
}

func TestNameFromFilepath(t *testing.T) {
tests := []struct {
name string
filepath string
want string
}{
{
name: "empty",
filepath: "",
want: "_score",
},
{
name: "without extension",
filepath: "test",
want: "test_score",
},
{
name: "with extension",
filepath: "test.json",
want: "test_score",
},
{
name: "with path",
filepath: "path/to/test.json",
want: "test_score",
},
{
name: "invalid characters",
filepath: "configuración-+=_básica.yaml",
want: "configuración____básica_score",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
if got := NameFromFilepath(test.filepath); got != test.want {
t.Errorf("NameFromFilepath() = %v, want %v", got, test.want)
}
})
}
}

func TestScorer_Name(t *testing.T) {
test := struct {
name string
s *Scorer
want string
}{
name: "default",
s: &Scorer{
name: "Valid",
a: testAlgo{},
},
want: "Valid",
}

if got := test.s.Name(); got != test.want {
t.Errorf("Name() = %v, want %v", got, test.want)
}
}

func TestScorer_Score(t *testing.T) {
type fields struct {
a algorithm.Algorithm
name string
}
test := struct {
name string
fields fields
signals []signal.Set
want float64
}{
name: "average test",
fields: fields{
a: testAlgo{},
name: "Valid",
},
signals: []signal.Set{
&testAlgo{
UpdatedCount: signal.Val(1),
},
},
want: 1,
}

s := &Scorer{
a: test.fields.a,
name: test.fields.name,
}
if got := s.Score(test.signals); got != test.want {
t.Errorf("Score() = %v, want %v", got, test.want)
}
}

0 comments on commit f3d7dca

Please sign in to comment.