5849898283
Unit tests functional and coverage back to 100% Add more routes to dictionary, add more credentials, add default port 5554, rename cameradar logs ENV variable, improve unit test readability, remove tmp file
536 lines
12 KiB
Go
536 lines
12 KiB
Go
package errors
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"regexp"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestFormatNew(t *testing.T) {
|
|
tests := []struct {
|
|
error
|
|
format string
|
|
want string
|
|
}{{
|
|
New("error"),
|
|
"%s",
|
|
"error",
|
|
}, {
|
|
New("error"),
|
|
"%v",
|
|
"error",
|
|
}, {
|
|
New("error"),
|
|
"%+v",
|
|
"error\n" +
|
|
"github.com/pkg/errors.TestFormatNew\n" +
|
|
"\t.+/github.com/pkg/errors/format_test.go:26",
|
|
}, {
|
|
New("error"),
|
|
"%q",
|
|
`"error"`,
|
|
}}
|
|
|
|
for i, tt := range tests {
|
|
testFormatRegexp(t, i, tt.error, tt.format, tt.want)
|
|
}
|
|
}
|
|
|
|
func TestFormatErrorf(t *testing.T) {
|
|
tests := []struct {
|
|
error
|
|
format string
|
|
want string
|
|
}{{
|
|
Errorf("%s", "error"),
|
|
"%s",
|
|
"error",
|
|
}, {
|
|
Errorf("%s", "error"),
|
|
"%v",
|
|
"error",
|
|
}, {
|
|
Errorf("%s", "error"),
|
|
"%+v",
|
|
"error\n" +
|
|
"github.com/pkg/errors.TestFormatErrorf\n" +
|
|
"\t.+/github.com/pkg/errors/format_test.go:56",
|
|
}}
|
|
|
|
for i, tt := range tests {
|
|
testFormatRegexp(t, i, tt.error, tt.format, tt.want)
|
|
}
|
|
}
|
|
|
|
func TestFormatWrap(t *testing.T) {
|
|
tests := []struct {
|
|
error
|
|
format string
|
|
want string
|
|
}{{
|
|
Wrap(New("error"), "error2"),
|
|
"%s",
|
|
"error2: error",
|
|
}, {
|
|
Wrap(New("error"), "error2"),
|
|
"%v",
|
|
"error2: error",
|
|
}, {
|
|
Wrap(New("error"), "error2"),
|
|
"%+v",
|
|
"error\n" +
|
|
"github.com/pkg/errors.TestFormatWrap\n" +
|
|
"\t.+/github.com/pkg/errors/format_test.go:82",
|
|
}, {
|
|
Wrap(io.EOF, "error"),
|
|
"%s",
|
|
"error: EOF",
|
|
}, {
|
|
Wrap(io.EOF, "error"),
|
|
"%v",
|
|
"error: EOF",
|
|
}, {
|
|
Wrap(io.EOF, "error"),
|
|
"%+v",
|
|
"EOF\n" +
|
|
"error\n" +
|
|
"github.com/pkg/errors.TestFormatWrap\n" +
|
|
"\t.+/github.com/pkg/errors/format_test.go:96",
|
|
}, {
|
|
Wrap(Wrap(io.EOF, "error1"), "error2"),
|
|
"%+v",
|
|
"EOF\n" +
|
|
"error1\n" +
|
|
"github.com/pkg/errors.TestFormatWrap\n" +
|
|
"\t.+/github.com/pkg/errors/format_test.go:103\n",
|
|
}, {
|
|
Wrap(New("error with space"), "context"),
|
|
"%q",
|
|
`"context: error with space"`,
|
|
}}
|
|
|
|
for i, tt := range tests {
|
|
testFormatRegexp(t, i, tt.error, tt.format, tt.want)
|
|
}
|
|
}
|
|
|
|
func TestFormatWrapf(t *testing.T) {
|
|
tests := []struct {
|
|
error
|
|
format string
|
|
want string
|
|
}{{
|
|
Wrapf(io.EOF, "error%d", 2),
|
|
"%s",
|
|
"error2: EOF",
|
|
}, {
|
|
Wrapf(io.EOF, "error%d", 2),
|
|
"%v",
|
|
"error2: EOF",
|
|
}, {
|
|
Wrapf(io.EOF, "error%d", 2),
|
|
"%+v",
|
|
"EOF\n" +
|
|
"error2\n" +
|
|
"github.com/pkg/errors.TestFormatWrapf\n" +
|
|
"\t.+/github.com/pkg/errors/format_test.go:134",
|
|
}, {
|
|
Wrapf(New("error"), "error%d", 2),
|
|
"%s",
|
|
"error2: error",
|
|
}, {
|
|
Wrapf(New("error"), "error%d", 2),
|
|
"%v",
|
|
"error2: error",
|
|
}, {
|
|
Wrapf(New("error"), "error%d", 2),
|
|
"%+v",
|
|
"error\n" +
|
|
"github.com/pkg/errors.TestFormatWrapf\n" +
|
|
"\t.+/github.com/pkg/errors/format_test.go:149",
|
|
}}
|
|
|
|
for i, tt := range tests {
|
|
testFormatRegexp(t, i, tt.error, tt.format, tt.want)
|
|
}
|
|
}
|
|
|
|
func TestFormatWithStack(t *testing.T) {
|
|
tests := []struct {
|
|
error
|
|
format string
|
|
want []string
|
|
}{{
|
|
WithStack(io.EOF),
|
|
"%s",
|
|
[]string{"EOF"},
|
|
}, {
|
|
WithStack(io.EOF),
|
|
"%v",
|
|
[]string{"EOF"},
|
|
}, {
|
|
WithStack(io.EOF),
|
|
"%+v",
|
|
[]string{"EOF",
|
|
"github.com/pkg/errors.TestFormatWithStack\n" +
|
|
"\t.+/github.com/pkg/errors/format_test.go:175"},
|
|
}, {
|
|
WithStack(New("error")),
|
|
"%s",
|
|
[]string{"error"},
|
|
}, {
|
|
WithStack(New("error")),
|
|
"%v",
|
|
[]string{"error"},
|
|
}, {
|
|
WithStack(New("error")),
|
|
"%+v",
|
|
[]string{"error",
|
|
"github.com/pkg/errors.TestFormatWithStack\n" +
|
|
"\t.+/github.com/pkg/errors/format_test.go:189",
|
|
"github.com/pkg/errors.TestFormatWithStack\n" +
|
|
"\t.+/github.com/pkg/errors/format_test.go:189"},
|
|
}, {
|
|
WithStack(WithStack(io.EOF)),
|
|
"%+v",
|
|
[]string{"EOF",
|
|
"github.com/pkg/errors.TestFormatWithStack\n" +
|
|
"\t.+/github.com/pkg/errors/format_test.go:197",
|
|
"github.com/pkg/errors.TestFormatWithStack\n" +
|
|
"\t.+/github.com/pkg/errors/format_test.go:197"},
|
|
}, {
|
|
WithStack(WithStack(Wrapf(io.EOF, "message"))),
|
|
"%+v",
|
|
[]string{"EOF",
|
|
"message",
|
|
"github.com/pkg/errors.TestFormatWithStack\n" +
|
|
"\t.+/github.com/pkg/errors/format_test.go:205",
|
|
"github.com/pkg/errors.TestFormatWithStack\n" +
|
|
"\t.+/github.com/pkg/errors/format_test.go:205",
|
|
"github.com/pkg/errors.TestFormatWithStack\n" +
|
|
"\t.+/github.com/pkg/errors/format_test.go:205"},
|
|
}, {
|
|
WithStack(Errorf("error%d", 1)),
|
|
"%+v",
|
|
[]string{"error1",
|
|
"github.com/pkg/errors.TestFormatWithStack\n" +
|
|
"\t.+/github.com/pkg/errors/format_test.go:216",
|
|
"github.com/pkg/errors.TestFormatWithStack\n" +
|
|
"\t.+/github.com/pkg/errors/format_test.go:216"},
|
|
}}
|
|
|
|
for i, tt := range tests {
|
|
testFormatCompleteCompare(t, i, tt.error, tt.format, tt.want, true)
|
|
}
|
|
}
|
|
|
|
func TestFormatWithMessage(t *testing.T) {
|
|
tests := []struct {
|
|
error
|
|
format string
|
|
want []string
|
|
}{{
|
|
WithMessage(New("error"), "error2"),
|
|
"%s",
|
|
[]string{"error2: error"},
|
|
}, {
|
|
WithMessage(New("error"), "error2"),
|
|
"%v",
|
|
[]string{"error2: error"},
|
|
}, {
|
|
WithMessage(New("error"), "error2"),
|
|
"%+v",
|
|
[]string{
|
|
"error",
|
|
"github.com/pkg/errors.TestFormatWithMessage\n" +
|
|
"\t.+/github.com/pkg/errors/format_test.go:244",
|
|
"error2"},
|
|
}, {
|
|
WithMessage(io.EOF, "addition1"),
|
|
"%s",
|
|
[]string{"addition1: EOF"},
|
|
}, {
|
|
WithMessage(io.EOF, "addition1"),
|
|
"%v",
|
|
[]string{"addition1: EOF"},
|
|
}, {
|
|
WithMessage(io.EOF, "addition1"),
|
|
"%+v",
|
|
[]string{"EOF", "addition1"},
|
|
}, {
|
|
WithMessage(WithMessage(io.EOF, "addition1"), "addition2"),
|
|
"%v",
|
|
[]string{"addition2: addition1: EOF"},
|
|
}, {
|
|
WithMessage(WithMessage(io.EOF, "addition1"), "addition2"),
|
|
"%+v",
|
|
[]string{"EOF", "addition1", "addition2"},
|
|
}, {
|
|
Wrap(WithMessage(io.EOF, "error1"), "error2"),
|
|
"%+v",
|
|
[]string{"EOF", "error1", "error2",
|
|
"github.com/pkg/errors.TestFormatWithMessage\n" +
|
|
"\t.+/github.com/pkg/errors/format_test.go:272"},
|
|
}, {
|
|
WithMessage(Errorf("error%d", 1), "error2"),
|
|
"%+v",
|
|
[]string{"error1",
|
|
"github.com/pkg/errors.TestFormatWithMessage\n" +
|
|
"\t.+/github.com/pkg/errors/format_test.go:278",
|
|
"error2"},
|
|
}, {
|
|
WithMessage(WithStack(io.EOF), "error"),
|
|
"%+v",
|
|
[]string{
|
|
"EOF",
|
|
"github.com/pkg/errors.TestFormatWithMessage\n" +
|
|
"\t.+/github.com/pkg/errors/format_test.go:285",
|
|
"error"},
|
|
}, {
|
|
WithMessage(Wrap(WithStack(io.EOF), "inside-error"), "outside-error"),
|
|
"%+v",
|
|
[]string{
|
|
"EOF",
|
|
"github.com/pkg/errors.TestFormatWithMessage\n" +
|
|
"\t.+/github.com/pkg/errors/format_test.go:293",
|
|
"inside-error",
|
|
"github.com/pkg/errors.TestFormatWithMessage\n" +
|
|
"\t.+/github.com/pkg/errors/format_test.go:293",
|
|
"outside-error"},
|
|
}}
|
|
|
|
for i, tt := range tests {
|
|
testFormatCompleteCompare(t, i, tt.error, tt.format, tt.want, true)
|
|
}
|
|
}
|
|
|
|
func TestFormatGeneric(t *testing.T) {
|
|
starts := []struct {
|
|
err error
|
|
want []string
|
|
}{
|
|
{New("new-error"), []string{
|
|
"new-error",
|
|
"github.com/pkg/errors.TestFormatGeneric\n" +
|
|
"\t.+/github.com/pkg/errors/format_test.go:315"},
|
|
}, {Errorf("errorf-error"), []string{
|
|
"errorf-error",
|
|
"github.com/pkg/errors.TestFormatGeneric\n" +
|
|
"\t.+/github.com/pkg/errors/format_test.go:319"},
|
|
}, {errors.New("errors-new-error"), []string{
|
|
"errors-new-error"},
|
|
},
|
|
}
|
|
|
|
wrappers := []wrapper{
|
|
{
|
|
func(err error) error { return WithMessage(err, "with-message") },
|
|
[]string{"with-message"},
|
|
}, {
|
|
func(err error) error { return WithStack(err) },
|
|
[]string{
|
|
"github.com/pkg/errors.(func·002|TestFormatGeneric.func2)\n\t" +
|
|
".+/github.com/pkg/errors/format_test.go:333",
|
|
},
|
|
}, {
|
|
func(err error) error { return Wrap(err, "wrap-error") },
|
|
[]string{
|
|
"wrap-error",
|
|
"github.com/pkg/errors.(func·003|TestFormatGeneric.func3)\n\t" +
|
|
".+/github.com/pkg/errors/format_test.go:339",
|
|
},
|
|
}, {
|
|
func(err error) error { return Wrapf(err, "wrapf-error%d", 1) },
|
|
[]string{
|
|
"wrapf-error1",
|
|
"github.com/pkg/errors.(func·004|TestFormatGeneric.func4)\n\t" +
|
|
".+/github.com/pkg/errors/format_test.go:346",
|
|
},
|
|
},
|
|
}
|
|
|
|
for s := range starts {
|
|
err := starts[s].err
|
|
want := starts[s].want
|
|
testFormatCompleteCompare(t, s, err, "%+v", want, false)
|
|
testGenericRecursive(t, err, want, wrappers, 3)
|
|
}
|
|
}
|
|
|
|
func testFormatRegexp(t *testing.T, n int, arg interface{}, format, want string) {
|
|
got := fmt.Sprintf(format, arg)
|
|
gotLines := strings.SplitN(got, "\n", -1)
|
|
wantLines := strings.SplitN(want, "\n", -1)
|
|
|
|
if len(wantLines) > len(gotLines) {
|
|
t.Errorf("test %d: wantLines(%d) > gotLines(%d):\n got: %q\nwant: %q", n+1, len(wantLines), len(gotLines), got, want)
|
|
return
|
|
}
|
|
|
|
for i, w := range wantLines {
|
|
match, err := regexp.MatchString(w, gotLines[i])
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !match {
|
|
t.Errorf("test %d: line %d: fmt.Sprintf(%q, err):\n got: %q\nwant: %q", n+1, i+1, format, got, want)
|
|
}
|
|
}
|
|
}
|
|
|
|
var stackLineR = regexp.MustCompile(`\.`)
|
|
|
|
// parseBlocks parses input into a slice, where:
|
|
// - incase entry contains a newline, its a stacktrace
|
|
// - incase entry contains no newline, its a solo line.
|
|
//
|
|
// Detecting stack boundaries only works incase the WithStack-calls are
|
|
// to be found on the same line, thats why it is optionally here.
|
|
//
|
|
// Example use:
|
|
//
|
|
// for _, e := range blocks {
|
|
// if strings.ContainsAny(e, "\n") {
|
|
// // Match as stack
|
|
// } else {
|
|
// // Match as line
|
|
// }
|
|
// }
|
|
//
|
|
func parseBlocks(input string, detectStackboundaries bool) ([]string, error) {
|
|
var blocks []string
|
|
|
|
stack := ""
|
|
wasStack := false
|
|
lines := map[string]bool{} // already found lines
|
|
|
|
for _, l := range strings.Split(input, "\n") {
|
|
isStackLine := stackLineR.MatchString(l)
|
|
|
|
switch {
|
|
case !isStackLine && wasStack:
|
|
blocks = append(blocks, stack, l)
|
|
stack = ""
|
|
lines = map[string]bool{}
|
|
case isStackLine:
|
|
if wasStack {
|
|
// Detecting two stacks after another, possible cause lines match in
|
|
// our tests due to WithStack(WithStack(io.EOF)) on same line.
|
|
if detectStackboundaries {
|
|
if lines[l] {
|
|
if len(stack) == 0 {
|
|
return nil, errors.New("len of block must not be zero here")
|
|
}
|
|
|
|
blocks = append(blocks, stack)
|
|
stack = l
|
|
lines = map[string]bool{l: true}
|
|
continue
|
|
}
|
|
}
|
|
|
|
stack = stack + "\n" + l
|
|
} else {
|
|
stack = l
|
|
}
|
|
lines[l] = true
|
|
case !isStackLine && !wasStack:
|
|
blocks = append(blocks, l)
|
|
default:
|
|
return nil, errors.New("must not happen")
|
|
}
|
|
|
|
wasStack = isStackLine
|
|
}
|
|
|
|
// Use up stack
|
|
if stack != "" {
|
|
blocks = append(blocks, stack)
|
|
}
|
|
return blocks, nil
|
|
}
|
|
|
|
func testFormatCompleteCompare(t *testing.T, n int, arg interface{}, format string, want []string, detectStackBoundaries bool) {
|
|
gotStr := fmt.Sprintf(format, arg)
|
|
|
|
got, err := parseBlocks(gotStr, detectStackBoundaries)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if len(got) != len(want) {
|
|
t.Fatalf("test %d: fmt.Sprintf(%s, err) -> wrong number of blocks: got(%d) want(%d)\n got: %s\nwant: %s\ngotStr: %q",
|
|
n+1, format, len(got), len(want), prettyBlocks(got), prettyBlocks(want), gotStr)
|
|
}
|
|
|
|
for i := range got {
|
|
if strings.ContainsAny(want[i], "\n") {
|
|
// Match as stack
|
|
match, err := regexp.MatchString(want[i], got[i])
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !match {
|
|
t.Fatalf("test %d: block %d: fmt.Sprintf(%q, err):\ngot:\n%q\nwant:\n%q\nall-got:\n%s\nall-want:\n%s\n",
|
|
n+1, i+1, format, got[i], want[i], prettyBlocks(got), prettyBlocks(want))
|
|
}
|
|
} else {
|
|
// Match as message
|
|
if got[i] != want[i] {
|
|
t.Fatalf("test %d: fmt.Sprintf(%s, err) at block %d got != want:\n got: %q\nwant: %q", n+1, format, i+1, got[i], want[i])
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
type wrapper struct {
|
|
wrap func(err error) error
|
|
want []string
|
|
}
|
|
|
|
func prettyBlocks(blocks []string, prefix ...string) string {
|
|
var out []string
|
|
|
|
for _, b := range blocks {
|
|
out = append(out, fmt.Sprintf("%v", b))
|
|
}
|
|
|
|
return " " + strings.Join(out, "\n ")
|
|
}
|
|
|
|
func testGenericRecursive(t *testing.T, beforeErr error, beforeWant []string, list []wrapper, maxDepth int) {
|
|
if len(beforeWant) == 0 {
|
|
panic("beforeWant must not be empty")
|
|
}
|
|
for _, w := range list {
|
|
if len(w.want) == 0 {
|
|
panic("want must not be empty")
|
|
}
|
|
|
|
err := w.wrap(beforeErr)
|
|
|
|
// Copy required cause append(beforeWant, ..) modified beforeWant subtly.
|
|
beforeCopy := make([]string, len(beforeWant))
|
|
copy(beforeCopy, beforeWant)
|
|
|
|
beforeWant := beforeCopy
|
|
last := len(beforeWant) - 1
|
|
var want []string
|
|
|
|
// Merge two stacks behind each other.
|
|
if strings.ContainsAny(beforeWant[last], "\n") && strings.ContainsAny(w.want[0], "\n") {
|
|
want = append(beforeWant[:last], append([]string{beforeWant[last] + "((?s).*)" + w.want[0]}, w.want[1:]...)...)
|
|
} else {
|
|
want = append(beforeWant, w.want...)
|
|
}
|
|
|
|
testFormatCompleteCompare(t, maxDepth, err, "%+v", want, false)
|
|
if maxDepth > 0 {
|
|
testGenericRecursive(t, err, want, list, maxDepth-1)
|
|
}
|
|
}
|
|
}
|