OSDN Git Service

Hulk did something
[bytom/vapor.git] / vendor / github.com / pkg / errors / format_test.go
diff --git a/vendor/github.com/pkg/errors/format_test.go b/vendor/github.com/pkg/errors/format_test.go
new file mode 100644 (file)
index 0000000..c2eef5f
--- /dev/null
@@ -0,0 +1,535 @@
+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) 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)
+               }
+       }
+}