diff options
-rw-r--r-- | internal/feed/feed.go | 39 | ||||
-rw-r--r-- | internal/feed/time.go | 44 | ||||
-rw-r--r-- | internal/feed/time_test.go | 66 |
3 files changed, 113 insertions, 36 deletions
diff --git a/internal/feed/feed.go b/internal/feed/feed.go index c013877..cf0fd2d 100644 --- a/internal/feed/feed.go +++ b/internal/feed/feed.go @@ -4,8 +4,6 @@ import ( "encoding/json" "fmt" // "strconv" - "regexp" - "time" ) const ( @@ -40,37 +38,6 @@ const ( // TODO: parse cpe -// partial timestamp -type PartialTime time.Time - -var partialTimeRe = regexp.MustCompile("\\A\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}Z\\z") - -// Unmarshal partial timestamp from JSON. -func (me *PartialTime) UnmarshalJSON(b []byte) error { - // decode string, check for error - var s string - if err := json.Unmarshal(b, &s); err != nil { - return err - } - - // match partial string regex - if !partialTimeRe.MatchString(s) { - return fmt.Errorf("invalid partial time string: %s", s) - } - - // correct string suffix - s = s[0:16] + ":00Z" - - // unmarshal time - var t time.Time - if err := t.UnmarshalText([]byte(s)); err != nil { - return err - } - - // return success - return nil -} - // Configuration node boolean operator. type NodeOp int @@ -666,10 +633,10 @@ type Item struct { Impact Impact `json:"impact"` // item published date - PublishedDate PartialTime `json:"publishedDate"` + PublishedDate Time `json:"publishedDate"` // last modification date - LastModifiedDate PartialTime `json:"lastModifiedDate"` + LastModifiedDate Time `json:"lastModifiedDate"` } // NVD feed @@ -687,7 +654,7 @@ type Feed struct { NumCVEs uint64 `json:"CVE_data_numberOfCVEs,string"` // data timestamp - Timestamp PartialTime `json:"CVE_data_timestamp"` + Timestamp Time `json:"CVE_data_timestamp"` // CVE items Items []Item `json:"CVE_Items"` diff --git a/internal/feed/time.go b/internal/feed/time.go new file mode 100644 index 0000000..6eb5d37 --- /dev/null +++ b/internal/feed/time.go @@ -0,0 +1,44 @@ +package feed + +import ( + "encoding/json" + "fmt" + // "strconv" + "regexp" + "time" +) + +// partial timestamp +type Time time.Time + +var timeRe = regexp.MustCompile("\\A\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}Z\\z") + +// Unmarshal timestamp from JSON. +func (me *Time) UnmarshalJSON(b []byte) error { + // decode string, check for error + var s string + if err := json.Unmarshal(b, &s); err != nil { + return err + } + + // match partial string regex + if !timeRe.MatchString(s) { + return fmt.Errorf("invalid time: \"%s\"", s) + } + + // correct string suffix + s = s[0:16] + ":00Z" + + // unmarshal time + var t time.Time + if err := t.UnmarshalText([]byte(s)); err != nil { + return err + } + + // save time + *me = Time(t) + + // return success + return nil +} + diff --git a/internal/feed/time_test.go b/internal/feed/time_test.go new file mode 100644 index 0000000..cc490c5 --- /dev/null +++ b/internal/feed/time_test.go @@ -0,0 +1,66 @@ +package feed + +import ( + "encoding/json" + "testing" + "time" +) + +func TestTimeUnmarshallInvalidData(t *testing.T) { + test := []byte(`{}`) + var val Time + + if err := json.Unmarshal(test, &val); err == nil { + t.Errorf("got \"%v\", exp error", val) + } +} + +func TestTimeUnmarshallInvalidString(t *testing.T) { + test := []byte(`"2020-"`) + exp := "invalid time: \"2020-\"" + var val Time + + if err := json.Unmarshal(test, &val); err == nil { + t.Errorf("got \"%v\", exp error", val) + } else if err.Error() != exp { + t.Errorf("got \"%s\", exp \"%s\"", err.Error(), exp) + } +} + +func TestTimeUnmarshallInvalidTime(t *testing.T) { + test := []byte(`"2020-99-99T99:99Z"`) + var val Time + + if err := json.Unmarshal(test, &val); err == nil { + t.Errorf("got \"%v\", exp error", val) + } +} + +func TestTimeString(t *testing.T) { + tests := []struct { + val string + exp string + } { + { "\"2021-06-09T20:15Z\"", "2021-06-09T20:15:00Z" }, + } + + for _, test := range(tests) { + t.Run(test.val, func(t *testing.T) { + var gotTime Time + if err := json.Unmarshal([]byte(test.val), &gotTime); err != nil { + t.Error(err) + return + } + + got, err := time.Time(gotTime).MarshalText() + if err != nil { + t.Error(err) + return + } + + if string(got) != test.exp { + t.Errorf("got \"%s\", exp \"%s\"", string(got), test.exp) + } + }) + } +} |