Extended stacktrace output (#49)

* Extended stacktrace output

* Make format tests less sensitive to sourcecode prefix

* use testFormatRegexp for all Sprintf tests

* replace output test with sample output

* work around the different fn.Name format in go 1.4

* fix windows tests when there is a drive letter in the source path
diff --git a/errors.go b/errors.go
index 0e4f94a..8143650 100644
--- a/errors.go
+++ b/errors.go
@@ -87,7 +87,9 @@
 	switch verb {
 	case 'v':
 		if s.Flag('+') {
-			fmt.Fprintf(s, "%+v: ", e.Stacktrace()[0])
+			io.WriteString(s, e.msg)
+			fmt.Fprintf(s, "%+v", e.Stacktrace())
+			return
 		}
 		fallthrough
 	case 's':
diff --git a/example_test.go b/example_test.go
index ebec7e7..0f0c80a 100644
--- a/example_test.go
+++ b/example_test.go
@@ -17,7 +17,22 @@
 	err := errors.New("whoops")
 	fmt.Printf("%+v", err)
 
-	// Output: github.com/pkg/errors/example_test.go:17: whoops
+	// Example output:
+	// whoops
+	// github.com/pkg/errors_test.ExampleNew_printf
+	//         /home/dfc/src/github.com/pkg/errors/example_test.go:17
+	// testing.runExample
+	//         /home/dfc/go/src/testing/example.go:114
+	// testing.RunExamples
+	//         /home/dfc/go/src/testing/example.go:38
+	// testing.(*M).Run
+	//         /home/dfc/go/src/testing/testing.go:744
+	// main.main
+	//         /github.com/pkg/errors/_test/_testmain.go:106
+	// runtime.main
+	//         /home/dfc/go/src/runtime/proc.go:183
+	// runtime.goexit
+	//         /home/dfc/go/src/runtime/asm_amd64.s:2059
 }
 
 func ExampleWrap() {
@@ -44,14 +59,34 @@
 	// error
 }
 
-func ExampleCause_printf() {
+func ExampleWrap_extended() {
 	err := fn()
 	fmt.Printf("%+v\n", err)
 
-	// Output: github.com/pkg/errors/example_test.go:32: error
-	// github.com/pkg/errors/example_test.go:33: inner
-	// github.com/pkg/errors/example_test.go:34: middle
-	// github.com/pkg/errors/example_test.go:35: outer
+	// Example output:
+	// error
+	// github.com/pkg/errors_test.fn
+	//         /home/dfc/src/github.com/pkg/errors/example_test.go:47
+	// github.com/pkg/errors_test.ExampleCause_printf
+	//         /home/dfc/src/github.com/pkg/errors/example_test.go:63
+	// testing.runExample
+	//         /home/dfc/go/src/testing/example.go:114
+	// testing.RunExamples
+	//         /home/dfc/go/src/testing/example.go:38
+	// testing.(*M).Run
+	//         /home/dfc/go/src/testing/testing.go:744
+	// main.main
+	//         /github.com/pkg/errors/_test/_testmain.go:104
+	// runtime.main
+	//         /home/dfc/go/src/runtime/proc.go:183
+	// runtime.goexit
+	//         /home/dfc/go/src/runtime/asm_amd64.s:2059
+	// github.com/pkg/errors_test.fn
+	// 	  /home/dfc/src/github.com/pkg/errors/example_test.go:48: inner
+	// github.com/pkg/errors_test.fn
+	//        /home/dfc/src/github.com/pkg/errors/example_test.go:49: middle
+	// github.com/pkg/errors_test.fn
+	//      /home/dfc/src/github.com/pkg/errors/example_test.go:50: outer
 }
 
 func ExampleWrapf() {
@@ -62,11 +97,26 @@
 	// Output: oh noes #2: whoops
 }
 
-func ExampleErrorf() {
+func ExampleErrorf_extended() {
 	err := errors.Errorf("whoops: %s", "foo")
 	fmt.Printf("%+v", err)
 
-	// Output: github.com/pkg/errors/example_test.go:66: whoops: foo
+	// Example output:
+	// whoops: foo
+	// github.com/pkg/errors_test.ExampleErrorf
+	//         /home/dfc/src/github.com/pkg/errors/example_test.go:101
+	// testing.runExample
+	//         /home/dfc/go/src/testing/example.go:114
+	// testing.RunExamples
+	//         /home/dfc/go/src/testing/example.go:38
+	// testing.(*M).Run
+	//         /home/dfc/go/src/testing/testing.go:744
+	// main.main
+	//         /github.com/pkg/errors/_test/_testmain.go:102
+	// runtime.main
+	//         /home/dfc/go/src/runtime/proc.go:183
+	// runtime.goexit
+	//         /home/dfc/go/src/runtime/asm_amd64.s:2059
 }
 
 func Example_stacktrace() {
@@ -82,5 +132,21 @@
 	st := err.Stacktrace()
 	fmt.Printf("%+v", st[0:2]) // top two frames
 
-	// Output: [github.com/pkg/errors/example_test.go:32 github.com/pkg/errors/example_test.go:77]
+	// Example output:
+	// github.com/pkg/errors_test.fn
+	//	/home/dfc/src/github.com/pkg/errors/example_test.go:47
+	// github.com/pkg/errors_test.Example_stacktrace
+	//	/home/dfc/src/github.com/pkg/errors/example_test.go:127
+}
+
+func ExampleCause_printf() {
+	err := errors.Wrap(func() error {
+		return func() error {
+			return errors.Errorf("hello %s", fmt.Sprintf("world"))
+		}()
+	}(), "failed")
+
+	fmt.Printf("%v", err)
+
+	// Output: failed: hello world
 }
diff --git a/format_test.go b/format_test.go
index c7d49f4..60806ae 100644
--- a/format_test.go
+++ b/format_test.go
@@ -3,28 +3,43 @@
 import (
 	"fmt"
 	"io"
+	"regexp"
+	"strings"
 	"testing"
 )
 
-func TestFormat(t *testing.T) {
+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:25",
+	}}
 
-		New("error"),
-		"%s",
-		"error",
-	}, {
-		New("error"),
-		"%v",
-		"error",
-	}, {
-		New("error"),
-		"%+v",
-		"github.com/pkg/errors/format_test.go:24: error",
-	}, {
+	for _, tt := range tests {
+		testFormatRegexp(t, tt.error, tt.format, tt.want)
+	}
+}
+
+func TestFormatErrorf(t *testing.T) {
+	tests := []struct {
+		error
+		format string
+		want   string
+	}{{
 		Errorf("%s", "error"),
 		"%s",
 		"error",
@@ -35,8 +50,22 @@
 	}, {
 		Errorf("%s", "error"),
 		"%+v",
-		"github.com/pkg/errors/format_test.go:36: error",
-	}, {
+		"error\n" +
+			"github.com/pkg/errors.TestFormatErrorf\n" +
+			"\t.+/github.com/pkg/errors/format_test.go:51",
+	}}
+
+	for _, tt := range tests {
+		testFormatRegexp(t, 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",
@@ -47,13 +76,26 @@
 	}, {
 		Wrap(New("error"), "error2"),
 		"%+v",
-		"github.com/pkg/errors/format_test.go:48: error\n" +
-			"github.com/pkg/errors/format_test.go:48: error2",
+		"error\n" +
+			"github.com/pkg/errors.TestFormatWrap\n" +
+			"\t.+/github.com/pkg/errors/format_test.go:77",
 	}, {
 		Wrap(io.EOF, "error"),
 		"%s",
 		"error: EOF",
-	}, {
+	}}
+
+	for _, tt := range tests {
+		testFormatRegexp(t, tt.error, tt.format, tt.want)
+	}
+}
+
+func TestFormatWrapf(t *testing.T) {
+	tests := []struct {
+		error
+		format string
+		want   string
+	}{{
 		Wrapf(New("error"), "error%d", 2),
 		"%s",
 		"error2: error",
@@ -65,7 +107,8 @@
 		Wrap(io.EOF, "error"),
 		"%+v",
 		"EOF\n" +
-			"github.com/pkg/errors/format_test.go:65: error",
+			"github.com/pkg/errors.TestFormatWrapf\n" +
+			"\t.+/github.com/pkg/errors/format_test.go:107: error",
 	}, {
 		Wrapf(New("error"), "error%d", 2),
 		"%v",
@@ -73,14 +116,26 @@
 	}, {
 		Wrapf(New("error"), "error%d", 2),
 		"%+v",
-		"github.com/pkg/errors/format_test.go:74: error\n" +
-			"github.com/pkg/errors/format_test.go:74: error2",
+		"error\n" +
+			"github.com/pkg/errors.TestFormatWrapf\n" +
+			"\t.+/github.com/pkg/errors/format_test.go:117",
 	}}
 
 	for _, tt := range tests {
-		got := fmt.Sprintf(tt.format, tt.error)
-		if got != tt.want {
-			t.Errorf("fmt.Sprintf(%q, err): got: %q, want: %q", tt.format, got, tt.want)
+		testFormatRegexp(t, tt.error, tt.format, tt.want)
+	}
+}
+
+func testFormatRegexp(t *testing.T, arg interface{}, format, want string) {
+	got := fmt.Sprintf(format, arg)
+	lines := strings.SplitN(got, "\n", -1)
+	for i, w := range strings.SplitN(want, "\n", -1) {
+		match, err := regexp.MatchString(w, lines[i])
+		if err != nil {
+			t.Fatal(err)
+		}
+		if !match {
+			t.Errorf("fmt.Sprintf(%q, err): got: %q, want: %q", format, got, want)
 		}
 	}
 }
diff --git a/stack.go b/stack.go
index 6f6940d..72a7a6c 100644
--- a/stack.go
+++ b/stack.go
@@ -59,7 +59,7 @@
 				io.WriteString(s, "unknown")
 			} else {
 				file, _ := fn.FileLine(pc)
-				io.WriteString(s, trimGOPATH(fn.Name(), file))
+				fmt.Fprintf(s, "%s\n\t%s", fn.Name(), file)
 			}
 		default:
 			io.WriteString(s, path.Base(f.file()))
@@ -84,7 +84,9 @@
 	case 'v':
 		switch {
 		case s.Flag('+'):
-			fmt.Fprintf(s, "%+v", []Frame(st))
+			for _, f := range st {
+				fmt.Fprintf(s, "\n%+v", f)
+			}
 		case s.Flag('#'):
 			fmt.Fprintf(s, "%#v", []Frame(st))
 		default:
diff --git a/stack_test.go b/stack_test.go
index 00221e4..dcc5436 100644
--- a/stack_test.go
+++ b/stack_test.go
@@ -65,7 +65,8 @@
 	}, {
 		Frame(initpc),
 		"%+s",
-		"github.com/pkg/errors/stack_test.go",
+		"github.com/pkg/errors.init\n" +
+			"\t.+/github.com/pkg/errors/stack_test.go",
 	}, {
 		Frame(0),
 		"%s",
@@ -92,7 +93,7 @@
 			return x.ptr()
 		}(),
 		"%n",
-		"(*X).ptr",
+		`\(\*X\).ptr`,
 	}, {
 		func() Frame {
 			var x X
@@ -111,7 +112,8 @@
 	}, {
 		Frame(initpc),
 		"%+v",
-		"github.com/pkg/errors/stack_test.go:9",
+		"github.com/pkg/errors.init\n" +
+			"\t.+/github.com/pkg/errors/stack_test.go:9",
 	}, {
 		Frame(0),
 		"%v",
@@ -119,11 +121,7 @@
 	}}
 
 	for _, tt := range tests {
-		got := fmt.Sprintf(tt.format, tt.Frame)
-		want := tt.want
-		if want != got {
-			t.Errorf("%v %q: want: %q, got: %q", tt.Frame, tt.format, want, got)
-		}
+		testFormatRegexp(t, tt.Frame, tt.format, tt.want)
 	}
 }
 
@@ -175,20 +173,25 @@
 		want []string
 	}{{
 		New("ooh"), []string{
-			"github.com/pkg/errors/stack_test.go:177",
+			"github.com/pkg/errors.TestStacktrace\n" +
+				"\t.+/github.com/pkg/errors/stack_test.go:175",
 		},
 	}, {
 		Wrap(New("ooh"), "ahh"), []string{
-			"github.com/pkg/errors/stack_test.go:181", // this is the stack of Wrap, not New
+			"github.com/pkg/errors.TestStacktrace\n" +
+				"\t.+/github.com/pkg/errors/stack_test.go:180", // this is the stack of Wrap, not New
 		},
 	}, {
 		Cause(Wrap(New("ooh"), "ahh")), []string{
-			"github.com/pkg/errors/stack_test.go:185", // this is the stack of New
+			"github.com/pkg/errors.TestStacktrace\n" +
+				"\t.+/github.com/pkg/errors/stack_test.go:185", // this is the stack of New
 		},
 	}, {
 		func() error { return New("ooh") }(), []string{
-			"github.com/pkg/errors/stack_test.go:189", // this is the stack of New
-			"github.com/pkg/errors/stack_test.go:189", // this is the stack of New's caller
+			`github.com/pkg/errors.(func·005|TestStacktrace.func1)` +
+				"\n\t.+/github.com/pkg/errors/stack_test.go:190", // this is the stack of New
+			"github.com/pkg/errors.TestStacktrace\n" +
+				"\t.+/github.com/pkg/errors/stack_test.go:190", // this is the stack of New's caller
 		},
 	}, {
 		Cause(func() error {
@@ -196,12 +199,15 @@
 				return Errorf("hello %s", fmt.Sprintf("world"))
 			}()
 		}()), []string{
-			"github.com/pkg/errors/stack_test.go:196", // this is the stack of Errorf
-			"github.com/pkg/errors/stack_test.go:197", // this is the stack of Errorf's caller
-			"github.com/pkg/errors/stack_test.go:198", // this is the stack of Errorf's caller's caller
+			`github.com/pkg/errors.(func·006|TestStacktrace.func2.1)` +
+				"\n\t.+/github.com/pkg/errors/stack_test.go:199", // this is the stack of Errorf
+			`github.com/pkg/errors.(func·007|TestStacktrace.func2)` +
+				"\n\t.+/github.com/pkg/errors/stack_test.go:200", // this is the stack of Errorf's caller
+			"github.com/pkg/errors.TestStacktrace\n" +
+				"\t.+/github.com/pkg/errors/stack_test.go:201", // this is the stack of Errorf's caller's caller
 		},
 	}}
-	for i, tt := range tests {
+	for _, tt := range tests {
 		x, ok := tt.err.(interface {
 			Stacktrace() Stacktrace
 		})
@@ -211,11 +217,7 @@
 		}
 		st := x.Stacktrace()
 		for j, want := range tt.want {
-			frame := st[j]
-			got := fmt.Sprintf("%+v", frame)
-			if got != want {
-				t.Errorf("test %d: frame %d: got %q, want %q", i, j, got, want)
-			}
+			testFormatRegexp(t, st[j], "%+v", want)
 		}
 	}
 }
@@ -236,57 +238,58 @@
 	}{{
 		nil,
 		"%s",
-		"[]",
+		`\[\]`,
 	}, {
 		nil,
 		"%v",
-		"[]",
+		`\[\]`,
 	}, {
 		nil,
 		"%+v",
-		"[]",
+		"",
 	}, {
 		nil,
 		"%#v",
-		"[]errors.Frame(nil)",
+		`\[\]errors.Frame\(nil\)`,
 	}, {
 		make(Stacktrace, 0),
 		"%s",
-		"[]",
+		`\[\]`,
 	}, {
 		make(Stacktrace, 0),
 		"%v",
-		"[]",
+		`\[\]`,
 	}, {
 		make(Stacktrace, 0),
 		"%+v",
-		"[]",
+		"",
 	}, {
 		make(Stacktrace, 0),
 		"%#v",
-		"[]errors.Frame{}",
+		`\[\]errors.Frame{}`,
 	}, {
 		stacktrace()[:2],
 		"%s",
-		"[stack_test.go stack_test.go]",
+		`\[stack_test.go stack_test.go\]`,
 	}, {
 		stacktrace()[:2],
 		"%v",
-		"[stack_test.go:226 stack_test.go:273]",
+		`\[stack_test.go:228 stack_test.go:275\]`,
 	}, {
 		stacktrace()[:2],
 		"%+v",
-		"[github.com/pkg/errors/stack_test.go:226 github.com/pkg/errors/stack_test.go:277]",
+		"\n" +
+			"github.com/pkg/errors.stacktrace\n" +
+			"\t.+/github.com/pkg/errors/stack_test.go:228\n" +
+			"github.com/pkg/errors.TestStacktraceFormat\n" +
+			"\t.+/github.com/pkg/errors/stack_test.go:279",
 	}, {
 		stacktrace()[:2],
 		"%#v",
-		"[]errors.Frame{stack_test.go:226, stack_test.go:281}",
+		`\[\]errors.Frame{stack_test.go:228, stack_test.go:287}`,
 	}}
 
-	for i, tt := range tests {
-		got := fmt.Sprintf(tt.format, tt.Stacktrace)
-		if got != tt.want {
-			t.Errorf("test %d: got: %q, want: %q", i+1, got, tt.want)
-		}
+	for _, tt := range tests {
+		testFormatRegexp(t, tt.Stacktrace, tt.format, tt.want)
 	}
 }