Skip to content

Commit

Permalink
More unit tests for new metric
Browse files Browse the repository at this point in the history
  • Loading branch information
sparrc committed Dec 1, 2016
1 parent 6fd7361 commit af6e7b9
Show file tree
Hide file tree
Showing 9 changed files with 1,007 additions and 114 deletions.
4 changes: 2 additions & 2 deletions metric.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,12 @@ type Metric interface {
// Tag functions
HasTag(key string) bool
AddTag(key, value string)
RemoveTag(key string) bool
RemoveTag(key string)

// Field functions
HasField(key string) bool
AddField(key string, value interface{})
RemoveField(key string) bool
RemoveField(key string) error

// Name functions
SetName(name string)
Expand Down
49 changes: 49 additions & 0 deletions metric/escape.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package metric

import (
"strings"
)

var (
// escaper is for escaping:
// - tag keys
// - tag values
// - field keys
// see https://docs.influxdata.com/influxdb/v1.0/write_protocols/line_protocol_tutorial/#special-characters-and-keywords
escaper = strings.NewReplacer(`,`, `\,`, `"`, `\"`, ` `, `\ `, `=`, `\=`)
unEscaper = strings.NewReplacer(`\,`, `,`, `\"`, `"`, `\ `, ` `, `\=`, `=`)

// nameEscaper is for escaping measurement names only.
// see https://docs.influxdata.com/influxdb/v1.0/write_protocols/line_protocol_tutorial/#special-characters-and-keywords
nameEscaper = strings.NewReplacer(`,`, `\,`, ` `, `\ `)
nameUnEscaper = strings.NewReplacer(`\,`, `,`, `\ `, ` `)

// stringFieldEscaper is for escaping string field values only.
// see https://docs.influxdata.com/influxdb/v1.0/write_protocols/line_protocol_tutorial/#special-characters-and-keywords
stringFieldEscaper = strings.NewReplacer(`"`, `\"`)
stringFieldUnEscaper = strings.NewReplacer(`\"`, `"`)
)

func escape(s string, t string) string {
switch t {
case "fieldkey", "tagkey", "tagval":
return escaper.Replace(s)
case "name":
return nameEscaper.Replace(s)
case "fieldval":
return stringFieldEscaper.Replace(s)
}
return s
}

func unescape(s string, t string) string {
switch t {
case "fieldkey", "tagkey", "tagval":
return unEscaper.Replace(s)
case "name":
return nameUnEscaper.Replace(s)
case "fieldval":
return stringFieldUnEscaper.Replace(s)
}
return s
}
103 changes: 103 additions & 0 deletions metric/inline_strconv_parse_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package metric

import (
"strconv"
"testing"
"testing/quick"
)

func TestParseIntBytesEquivalenceFuzz(t *testing.T) {
f := func(b []byte, base int, bitSize int) bool {
exp, expErr := strconv.ParseInt(string(b), base, bitSize)
got, gotErr := parseIntBytes(b, base, bitSize)

return exp == got && checkErrs(expErr, gotErr)
}

cfg := &quick.Config{
MaxCount: 10000,
}

if err := quick.Check(f, cfg); err != nil {
t.Fatal(err)
}
}

func TestParseIntBytesValid64bitBase10EquivalenceFuzz(t *testing.T) {
buf := []byte{}
f := func(n int64) bool {
buf = strconv.AppendInt(buf[:0], n, 10)

exp, expErr := strconv.ParseInt(string(buf), 10, 64)
got, gotErr := parseIntBytes(buf, 10, 64)

return exp == got && checkErrs(expErr, gotErr)
}

cfg := &quick.Config{
MaxCount: 10000,
}

if err := quick.Check(f, cfg); err != nil {
t.Fatal(err)
}
}

func TestParseFloatBytesEquivalenceFuzz(t *testing.T) {
f := func(b []byte, bitSize int) bool {
exp, expErr := strconv.ParseFloat(string(b), bitSize)
got, gotErr := parseFloatBytes(b, bitSize)

return exp == got && checkErrs(expErr, gotErr)
}

cfg := &quick.Config{
MaxCount: 10000,
}

if err := quick.Check(f, cfg); err != nil {
t.Fatal(err)
}
}

func TestParseFloatBytesValid64bitEquivalenceFuzz(t *testing.T) {
buf := []byte{}
f := func(n float64) bool {
buf = strconv.AppendFloat(buf[:0], n, 'f', -1, 64)

exp, expErr := strconv.ParseFloat(string(buf), 64)
got, gotErr := parseFloatBytes(buf, 64)

return exp == got && checkErrs(expErr, gotErr)
}

cfg := &quick.Config{
MaxCount: 10000,
}

if err := quick.Check(f, cfg); err != nil {
t.Fatal(err)
}
}

func TestParseBoolBytesEquivalence(t *testing.T) {
var buf []byte
for _, s := range []string{"1", "t", "T", "TRUE", "true", "True", "0", "f", "F", "FALSE", "false", "False", "fail", "TrUe", "FAlSE", "numbers", ""} {
buf = append(buf[:0], s...)

exp, expErr := strconv.ParseBool(s)
got, gotErr := parseBoolBytes(buf)

if got != exp || !checkErrs(expErr, gotErr) {
t.Errorf("Failed to parse boolean value %q correctly: wanted (%t, %v), got (%t, %v)", s, exp, expErr, got, gotErr)
}
}
}

func checkErrs(a, b error) bool {
if (a == nil) != (b == nil) {
return false
}

return a == nil || a.Error() == b.Error()
}
Loading

0 comments on commit af6e7b9

Please sign in to comment.