tests: added recursively trying out combinations of calls for %+v.
diff --git a/format_test.go b/format_test.go
index ae1be51..98288c6 100644
--- a/format_test.go
+++ b/format_test.go
@@ -224,7 +224,7 @@
}}
for i, tt := range tests {
- testFormatCompleteCompare(t, i, tt.error, tt.format, tt.want)
+ testFormatCompleteCompare(t, i, tt.error, tt.format, tt.want, true)
}
}
@@ -304,7 +304,60 @@
}}
for i, tt := range tests {
- testFormatCompleteCompare(t, i, tt.error, tt.format, tt.want)
+ 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:311"},
+ }, {Errorf("errorf-error"), []string{
+ "errorf-error",
+ "github.com/pkg/errors.TestFormatGeneric\n" +
+ "\t.+/github.com/pkg/errors/format_test.go:315"},
+ }, {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.TestFormatGeneric.func2\n\t" +
+ ".+/github.com/pkg/errors/format_test.go:329",
+ },
+ }, {
+ func(err error) error { return Wrap(err, "wrap-error") },
+ []string{
+ "wrap-error",
+ "github.com/pkg/errors.TestFormatGeneric.func3\n\t" +
+ ".+/github.com/pkg/errors/format_test.go:335",
+ },
+ }, {
+ func(err error) error { return Wrapf(err, "wrapf-error%d", 1) },
+ []string{
+ "wrapf-error1",
+ "github.com/pkg/errors.TestFormatGeneric.func4\n\t" +
+ ".+/github.com/pkg/errors/format_test.go:342",
+ },
+ },
+ }
+
+ 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)
}
}
@@ -335,6 +388,9 @@
// - 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 {
@@ -344,7 +400,8 @@
// // Match as line
// }
// }
-func parseBlocks(input string) ([]string, error) {
+//
+func parseBlocks(input string, detectStackboundaries bool) ([]string, error) {
var blocks []string
stack := ""
@@ -363,15 +420,17 @@
if wasStack {
// Detecting two stacks after another, possible cause lines match in
// our tests due to WithStack(WithStack(io.EOF)) on same line.
- if lines[l] {
- if len(stack) == 0 {
- return nil, errors.New("len of block must not be zero here")
- }
+ 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
+ blocks = append(blocks, stack)
+ stack = l
+ lines = map[string]bool{l: true}
+ continue
+ }
}
stack = stack + "\n" + l
@@ -395,17 +454,17 @@
return blocks, nil
}
-func testFormatCompleteCompare(t *testing.T, n int, arg interface{}, format string, want []string) {
+func testFormatCompleteCompare(t *testing.T, n int, arg interface{}, format string, want []string, detectStackBoundaries bool) {
gotStr := fmt.Sprintf(format, arg)
- got, err := parseBlocks(gotStr)
+ 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: %q\nwant: %q\ngotStr: %q",
- n+1, format, len(got), len(want), got, want, gotStr)
+ 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 {
@@ -416,13 +475,62 @@
t.Fatal(err)
}
if !match {
- t.Errorf("test %d: block %d: fmt.Sprintf(%q, err):\n got: %q\nwant: %q", n+1, i+1, format, got[i], want[i])
+ 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.Errorf("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])
+ 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)
+ }
+ }
+}