Skip to content

Commit

Permalink
add histogram values functions
Browse files Browse the repository at this point in the history
cvilsmeier committed Jan 6, 2024
1 parent b10cce1 commit 2524e4b
Showing 2 changed files with 44 additions and 29 deletions.
15 changes: 12 additions & 3 deletions histogram/values.go
Original file line number Diff line number Diff line change
@@ -7,7 +7,12 @@ import (
"strings"
)

// StringifyValues turns
// StringifyValues formats histogram values into a string.
// The result is a comma-separated list of "value:count" pairs.
// Each value is a non-negative int64 value, each count is a
// greater or equal to 1 int.
// If count is 1, the ":count" part is left out, so "42:1" and
// "42" are sematically equal.
func StringifyValues(values []int64) string {
n := len(values)
if n == 0 {
@@ -48,14 +53,18 @@ func StringifyValues(values []int64) string {
return strings.Join(toks, ",")
}

// ParseValues parses a "value:count" comma-separated
// list of histogram values into a slice of int64 values.
// The resulting slice contains each value ":count" times.
// The resulting slice is sorted in ascending order.
func ParseValues(s string) ([]int64, error) {
if s == "" {
return nil, nil
}
var values []int64
toks := strings.Split(s, ",")
for itok, tok := range toks {
v, c, err := parseValue(tok)
v, c, err := parseValueAndCount(tok)
if err != nil {
return nil, fmt.Errorf("cannot parse token #%d %q: %w", itok+1, tok, err)
}
@@ -70,7 +79,7 @@ func ParseValues(s string) ([]int64, error) {
return values, nil
}

func parseValue(s string) (int64, int, error) {
func parseValueAndCount(s string) (int64, int, error) {
parts := strings.Split(s, ":")
np := len(parts)
if np < 1 || 2 < np {
58 changes: 32 additions & 26 deletions histogram/values_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package histogram

import (
"strconv"
"strings"
"testing"

"github.com/cvilsmeier/monibot-go/internal/assert"
@@ -17,33 +19,37 @@ func TestStringifyValues(t *testing.T) {
}

func TestParseValues(t *testing.T) {
strErr := func(err error) string {
if err == nil {
return "nil"
str := func(values []int64, err error) string {
if err != nil {
return err.Error()
}
return err.Error()
var ss []string
for _, v := range values {
ss = append(ss, strconv.FormatInt(v, 10))
}
return strings.Join(ss, ",")
}
ass := assert.New(t)
mustParse := func(s string) []int64 {
v, err := ParseValues(s)
ass.Nil(err)
return v
}
ass.Eq("", StringifyValues(mustParse("")))
ass.Eq("1", StringifyValues(mustParse("1")))
ass.Eq("1", StringifyValues(mustParse("1:1")))
ass.Eq("1:2", StringifyValues(mustParse("1:2")))
ass.Eq("1,2,3:2", StringifyValues(mustParse("3:2,2:1,1")))
_, err := ParseValues("-3:2")
ass.Eq("cannot parse token #1 \"-3:2\": invalid value -3", strErr(err))
_, err = ParseValues("-3:2")
ass.Eq("cannot parse token #1 \"-3:2\": invalid value -3", strErr(err))
_, err = ParseValues("3:0")
ass.Eq("cannot parse token #1 \"3:0\": invalid count 0", strErr(err))
_, err = ParseValues("foo")
ass.Eq("cannot parse token #1 \"foo\": cannot parse value \"foo\": strconv.ParseInt: parsing \"foo\": invalid syntax", strErr(err))
_, err = ParseValues("foo:1")
ass.Eq("cannot parse token #1 \"foo:1\": cannot parse value \"foo\": strconv.ParseInt: parsing \"foo\": invalid syntax", strErr(err))
_, err = ParseValues("1:foo")
ass.Eq("cannot parse token #1 \"1:foo\": cannot parse count \"foo\": strconv.Atoi: parsing \"foo\": invalid syntax", strErr(err))
v, err := ParseValues("")
ass.Eq("", str(v, err))
v, err = ParseValues("1")
ass.Eq("1", str(v, err))
v, err = ParseValues("1:1")
ass.Eq("1", str(v, err))
v, err = ParseValues("1:2")
ass.Eq("1,1", str(v, err))
v, err = ParseValues("3:2,2:1,1")
ass.Eq("1,2,3,3", str(v, err))
v, err = ParseValues("-3:2")
ass.Eq("cannot parse token #1 \"-3:2\": invalid value -3", str(v, err))
v, err = ParseValues("-3:2")
ass.Eq("cannot parse token #1 \"-3:2\": invalid value -3", str(v, err))
v, err = ParseValues("3:0")
ass.Eq("cannot parse token #1 \"3:0\": invalid count 0", str(v, err))
v, err = ParseValues("foo")
ass.Eq("cannot parse token #1 \"foo\": cannot parse value \"foo\": strconv.ParseInt: parsing \"foo\": invalid syntax", str(v, err))
v, err = ParseValues("foo:1")
ass.Eq("cannot parse token #1 \"foo:1\": cannot parse value \"foo\": strconv.ParseInt: parsing \"foo\": invalid syntax", str(v, err))
v, err = ParseValues("1:foo")
ass.Eq("cannot parse token #1 \"1:foo\": cannot parse count \"foo\": strconv.Atoi: parsing \"foo\": invalid syntax", str(v, err))
}

0 comments on commit 2524e4b

Please sign in to comment.