From 806a74bdff6cf2f014bb93d01d84611c9ef26e04 Mon Sep 17 00:00:00 2001
From: Paul Duncan <pabs@pablotron.org>
Date: Tue, 1 Feb 2022 13:49:24 -0500
Subject: internal/feed: add severity, severity tests

---
 internal/feed/feed.go            | 32 +---------------
 internal/feed/severity.go        | 47 +++++++++++++++++++++++
 internal/feed/severity_string.go | 27 +++++++++++++
 internal/feed/severity_test.go   | 83 ++++++++++++++++++++++++++++++++++++++++
 4 files changed, 158 insertions(+), 31 deletions(-)
 create mode 100644 internal/feed/severity.go
 create mode 100644 internal/feed/severity_string.go
 create mode 100644 internal/feed/severity_test.go

(limited to 'internal/feed')

diff --git a/internal/feed/feed.go b/internal/feed/feed.go
index b8a3849..40e385d 100644
--- a/internal/feed/feed.go
+++ b/internal/feed/feed.go
@@ -21,36 +21,6 @@ const (
 
 // TODO: parse cpe
 
-// CVSS severity
-type Severity int
-
-// Unmarshal CVSS severity from JSON.
-func (me *Severity) UnmarshalJSON(b []byte) error {
-  // decode string, check for error
-  var s string
-  if err := json.Unmarshal(b, &s); err != nil {
-    return err
-  }
-
-  // check value
-  switch s {
-  case "LOW":
-    *me = Low
-  case "MEDIUM":
-    *me = Medium
-  case "HIGH":
-    *me = High
-  case "CRITICAL":
-    *me = Critical
-  default:
-    // return error
-    return fmt.Errorf("unknown severity: %s", s)
-  }
-
-  // return success
-  return nil
-}
-
 type V2AccessVector byte
 
 const (
@@ -372,7 +342,7 @@ type CvssV2 struct {
 // CVSS V2 base metrics
 type BaseMetricV2 struct {
   CvssV2                  CvssV2    `json:"cvssV2"`
-  severity                Severity  `json:"severity"`
+  Severity                Severity  `json:"severity"`
   ExploitabilityScore     Score     `json:"impactScore"`
   ImpactScore             Score     `json:"impactScore"`
   InsufficientInfo        bool      `json:"acInsufInfo"`
diff --git a/internal/feed/severity.go b/internal/feed/severity.go
new file mode 100644
index 0000000..50969ed
--- /dev/null
+++ b/internal/feed/severity.go
@@ -0,0 +1,47 @@
+package feed
+
+//go:generate stringer -linecomment -type=Severity
+
+import (
+  "encoding/json"
+  "fmt"
+)
+
+type Severity byte
+
+const (
+  SeverityNone Severity = iota // NONE
+  SeverityLow // LOW
+  SeverityMedium // MEDIUM
+  SeverityHigh // HIGH
+  SeverityCritical // CRITICAL
+)
+
+// Unmarshal CVSS severity from JSON.
+func (me *Severity) UnmarshalJSON(b []byte) error {
+  // decode string, check for error
+  var s string
+  if err := json.Unmarshal(b, &s); err != nil {
+    return err
+  }
+
+  // check value
+  switch s {
+  case "NONE":
+    *me = SeverityNone
+  case "LOW":
+    *me = SeverityLow
+  case "MEDIUM":
+    *me = SeverityMedium
+  case "HIGH":
+    *me = SeverityHigh
+  case "CRITICAL":
+    *me = SeverityCritical
+  default:
+    // return error
+    return fmt.Errorf("unknown severity: %s", s)
+  }
+
+  // return success
+  return nil
+}
diff --git a/internal/feed/severity_string.go b/internal/feed/severity_string.go
new file mode 100644
index 0000000..28e1e91
--- /dev/null
+++ b/internal/feed/severity_string.go
@@ -0,0 +1,27 @@
+// Code generated by "stringer -linecomment -type=Severity"; DO NOT EDIT.
+
+package feed
+
+import "strconv"
+
+func _() {
+	// An "invalid array index" compiler error signifies that the constant values have changed.
+	// Re-run the stringer command to generate them again.
+	var x [1]struct{}
+	_ = x[SeverityNone-0]
+	_ = x[SeverityLow-1]
+	_ = x[SeverityMedium-2]
+	_ = x[SeverityHigh-3]
+	_ = x[SeverityCritical-4]
+}
+
+const _Severity_name = "NONELOWMEDIUMHIGHCRITICAL"
+
+var _Severity_index = [...]uint8{0, 4, 7, 13, 17, 25}
+
+func (i Severity) String() string {
+	if i >= Severity(len(_Severity_index)-1) {
+		return "Severity(" + strconv.FormatInt(int64(i), 10) + ")"
+	}
+	return _Severity_name[_Severity_index[i]:_Severity_index[i+1]]
+}
diff --git a/internal/feed/severity_test.go b/internal/feed/severity_test.go
new file mode 100644
index 0000000..75aec72
--- /dev/null
+++ b/internal/feed/severity_test.go
@@ -0,0 +1,83 @@
+package feed
+
+import (
+  "encoding/json"
+  "testing"
+)
+
+func TestSeverityUnmarshalInvalidData(t *testing.T) {
+  test := []byte(`{}`)
+  var val Severity
+
+  if err := json.Unmarshal(test, &val); err == nil {
+    t.Errorf("got \"%s\", exp error", val)
+  }
+}
+
+func TestSeverityUnmarshalUnknown(t *testing.T) {
+  test := []byte(`"foo"`)
+  exp := "unknown severity: foo"
+  var val Severity
+
+  err := json.Unmarshal(test, &val)
+  if err == nil {
+    t.Errorf("got \"%s\", exp error", val)
+    return
+  }
+
+  if err.Error() != exp {
+    t.Errorf("got \"%s\", exp \"%s\"", err.Error(), exp)
+  }
+}
+
+func TestSeverityUnmarshalValid(t *testing.T) {
+  tests := []struct {
+    val string
+    exp Severity
+  } {
+    { "\"NONE\"", SeverityNone },
+    { "\"LOW\"", SeverityLow },
+    { "\"MEDIUM\"", SeverityMedium },
+    { "\"HIGH\"", SeverityHigh },
+    { "\"CRITICAL\"", SeverityCritical },
+  }
+
+  for _, test := range(tests) {
+    t.Run(test.val, func(t *testing.T) {
+      var got Severity
+      if err := json.Unmarshal([]byte(test.val), &got); err != nil {
+        t.Error(err)
+        return
+      }
+
+      if got != test.exp {
+        t.Errorf("got \"%s\", exp \"%s\"", got, test.exp)
+      }
+    })
+  }
+}
+
+func TestSeverityString(t *testing.T) {
+  tests := []struct {
+    val Severity
+    exp string
+  } {
+    { SeverityNone, "NONE" },
+    { SeverityLow, "LOW" },
+    { SeverityMedium, "MEDIUM" },
+    { SeverityHigh, "HIGH" },
+    { SeverityCritical, "CRITICAL" },
+
+    { Severity(255), "Severity(255)" },
+  }
+
+  for _, test := range(tests) {
+    t.Run(test.exp, func(t *testing.T) {
+      got := test.val.String()
+
+      if got != test.exp {
+        t.Errorf("got \"%s\", exp \"%s\"", got, test.exp)
+      }
+    })
+  }
+}
-- 
cgit v1.2.3