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" + // "game/errors.TestFormatNew\n" + // "\t.+game/errors/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" + // "game/errors.TestFormatErrorf\n" + // "\t.+game/errors/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" + // "game/errors.TestFormatWrap\n" + // "\t.+game/errors/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" + // "game/errors.TestFormatWrap\n" + // "\t.+game/errors/errors/format_test.go:96", // }, { // Wrap(Wrap(io.EOF, "error1"), "error2"), // "%+v", // "EOF\n" + // "error1\n" + // "game/errors.TestFormatWrap\n" + // "\t.+game/errors/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" + // "game/errors.TestFormatWrapf\n" + // "\t.+game/errors/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" + // "game/errors.TestFormatWrapf\n" + // "\t.+game/errors/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", // "game/errors.TestFormatWithStack\n" + // "\t.+game/errors/errors/format_test.go:175"}, // }, { // WithStack(New("error")), // "%s", // []string{"error"}, // }, { // WithStack(New("error")), // "%v", // []string{"error"}, // }, { // WithStack(New("error")), // "%+v", // []string{"error", // "game/errors.TestFormatWithStack\n" + // "\t.+game/errors/errors/format_test.go:189", // "game/errors.TestFormatWithStack\n" + // "\t.+game/errors/errors/format_test.go:189"}, // }, { // WithStack(WithStack(io.EOF)), // "%+v", // []string{"EOF", // "game/errors.TestFormatWithStack\n" + // "\t.+game/errors/errors/format_test.go:197", // "game/errors.TestFormatWithStack\n" + // "\t.+game/errors/errors/format_test.go:197"}, // }, { // WithStack(WithStack(Wrapf(io.EOF, "message"))), // "%+v", // []string{"EOF", // "message", // "game/errors.TestFormatWithStack\n" + // "\t.+game/errors/errors/format_test.go:205", // "game/errors.TestFormatWithStack\n" + // "\t.+game/errors/errors/format_test.go:205", // "game/errors.TestFormatWithStack\n" + // "\t.+game/errors/errors/format_test.go:205"}, // }, { // WithStack(Errorf("error%d", 1)), // "%+v", // []string{"error1", // "game/errors.TestFormatWithStack\n" + // "\t.+game/errors/errors/format_test.go:216", // "game/errors.TestFormatWithStack\n" + // "\t.+game/errors/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", // "game/errors.TestFormatWithMessage\n" + // "\t.+game/errors/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", // "game/errors.TestFormatWithMessage\n" + // "\t.+game/errors/errors/format_test.go:272"}, // }, { // WithMessage(Errorf("error%d", 1), "error2"), // "%+v", // []string{"error1", // "game/errors.TestFormatWithMessage\n" + // "\t.+game/errors/errors/format_test.go:278", // "error2"}, // }, { // WithMessage(WithStack(io.EOF), "error"), // "%+v", // []string{ // "EOF", // "game/errors.TestFormatWithMessage\n" + // "\t.+game/errors/errors/format_test.go:285", // "error"}, // }, { // WithMessage(Wrap(WithStack(io.EOF), "inside-error"), "outside-error"), // "%+v", // []string{ // "EOF", // "game/errors.TestFormatWithMessage\n" + // "\t.+game/errors/errors/format_test.go:293", // "inside-error", // "game/errors.TestFormatWithMessage\n" + // "\t.+game/errors/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", // "game/errors.TestFormatGeneric\n" + // "\t.+game/errors/errors/format_test.go:315"}, // }, {Errorf("errorf-error"), []string{ // "errorf-error", // "game/errors.TestFormatGeneric\n" + // "\t.+game/errors/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{ // "game/errors.(func·002|TestFormatGeneric.func2)\n\t" + // ".+game/errors/errors/format_test.go:333", // }, // }, { // func(err error) error { return Wrap(err, "wrap-error") }, // []string{ // "wrap-error", // "game/errors.(func·003|TestFormatGeneric.func3)\n\t" + // ".+game/errors/errors/format_test.go:339", // }, // }, { // func(err error) error { return Wrapf(err, "wrapf-error%d", 1) }, // []string{ // "wrapf-error1", // "game/errors.(func·004|TestFormatGeneric.func4)\n\t" + // ".+game/errors/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 wrappedNew(message string) error { // This function will be mid-stack inlined in go 1.12+ // return New(message) //} // //func TestFormatWrappedNew(t *testing.T) { // tests := []struct { // error // format string // want string // }{{ // wrappedNew("error"), // "%+v", // "error\n" + // "game/errors.wrappedNew\n" + // "\t.+game/errors/errors/format_test.go:364\n" + // "game/errors.TestFormatWrappedNew\n" + // "\t.+game/errors/errors/format_test.go:373", // }} // // for i, tt := range tests { // testFormatRegexp(t, i, tt.error, tt.format, tt.want) // } //} // //func testFormatRegexp(t *testing.T, n int, arg interface{}, format, want string) { // t.Helper() // 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) // } // } //}