Add WithStack and WithMessage tests
Adds testFormatCompleteCompare as additional testing func.

The new function takes a string slice as "want", wherein
stacktraces and non-stacktrace messages are discerned by
strings.ContainsAny(want[i], "\n").

For example usage, see TestFormatWithStack & TestFormatWithMessage.
diff --git a/errors_test.go b/errors_test.go
index 11d4555..c4ca617 100644
--- a/errors_test.go
+++ b/errors_test.go
@@ -84,6 +84,18 @@
 	}, {
 		err:  x, // return from errors.New
 		want: x,
+	}, {
+		WithMessage(nil, "whoops"),
+		nil,
+	}, {
+		WithMessage(io.EOF, "whoops"),
+		io.EOF,
+	}, {
+		WithStack(nil),
+		nil,
+	}, {
+		WithStack(io.EOF),
+		io.EOF,
 	}}
 
 	for i, tt := range tests {
@@ -137,23 +149,78 @@
 	}
 }
 
+func TestWithStackNil(t *testing.T) {
+	got := WithStack(nil)
+	if got != nil {
+		t.Errorf("WithStack(nil): got %#v, expected nil", got)
+	}
+}
+
+func TestWithStack(t *testing.T) {
+	tests := []struct {
+		err  error
+		want string
+	}{
+		{io.EOF, "EOF"},
+		{WithStack(io.EOF), "EOF"},
+	}
+
+	for _, tt := range tests {
+		got := WithStack(tt.err).Error()
+		if got != tt.want {
+			t.Errorf("WithStack(%v): got: %v, want %v", tt.err, got, tt.want)
+		}
+	}
+}
+
+func TestWithMessageNil(t *testing.T) {
+	got := WithMessage(nil, "no error")
+	if got != nil {
+		t.Errorf("WithMessage(nil, \"no error\"): got %#v, expected nil", got)
+	}
+}
+
+func TestWithMessage(t *testing.T) {
+	tests := []struct {
+		err     error
+		message string
+		want    string
+	}{
+		{io.EOF, "read error", "read error: EOF"},
+		{WithMessage(io.EOF, "read error"), "client error", "client error: read error: EOF"},
+	}
+
+	for _, tt := range tests {
+		got := WithMessage(tt.err, tt.message).Error()
+		if got != tt.want {
+			t.Errorf("WithMessage(%v, %q): got: %q, want %q", tt.err, tt.message, got, tt.want)
+		}
+	}
+
+}
+
 // errors.New, etc values are not expected to be compared by value
 // but the change in errors#27 made them incomparable. Assert that
 // various kinds of errors have a functional equality operator, even
 // if the result of that equality is always false.
 func TestErrorEquality(t *testing.T) {
-	tests := []struct {
-		err1, err2 error
-	}{
-		{io.EOF, io.EOF},
-		{io.EOF, nil},
-		{io.EOF, errors.New("EOF")},
-		{io.EOF, New("EOF")},
-		{New("EOF"), New("EOF")},
-		{New("EOF"), Errorf("EOF")},
-		{New("EOF"), Wrap(io.EOF, "EOF")},
+	vals := []error{
+		nil,
+		io.EOF,
+		errors.New("EOF"),
+		New("EOF"),
+		Errorf("EOF"),
+		Wrap(io.EOF, "EOF"),
+		Wrapf(io.EOF, "EOF%d", 2),
+		WithMessage(nil, "whoops"),
+		WithMessage(io.EOF, "whoops"),
+		WithStack(io.EOF),
+		WithStack(nil),
 	}
-	for _, tt := range tests {
-		_ = tt.err1 == tt.err2 // mustn't panic
+
+	for i := 0; i < len(vals); i++ {
+		for j := 0; j < len(vals); j++ {
+			_ = vals[i] == vals[j] // mustn't panic
+		}
 	}
 }
diff --git a/example_test.go b/example_test.go
index 5bec3ad..c1fc13e 100644
--- a/example_test.go
+++ b/example_test.go
@@ -35,6 +35,59 @@
 	//         /home/dfc/go/src/runtime/asm_amd64.s:2059
 }
 
+func ExampleWithMessage() {
+	cause := errors.New("whoops")
+	err := errors.WithMessage(cause, "oh noes")
+	fmt.Println(err)
+
+	// Output: oh noes: whoops
+}
+
+func ExampleWithStack() {
+	cause := errors.New("whoops")
+	err := errors.WithStack(cause)
+	fmt.Println(err)
+
+	// Output: whoops
+}
+
+func ExampleWithStack_printf() {
+	cause := errors.New("whoops")
+	err := errors.WithStack(cause)
+	fmt.Printf("%+v", err)
+
+	// Example Output:
+	// whoops
+	// github.com/pkg/errors_test.ExampleWithStack_printf
+	//         /home/fabstu/go/src/github.com/pkg/errors/example_test.go:55
+	// testing.runExample
+	//         /usr/lib/go/src/testing/example.go:114
+	// testing.RunExamples
+	//         /usr/lib/go/src/testing/example.go:38
+	// testing.(*M).Run
+	//         /usr/lib/go/src/testing/testing.go:744
+	// main.main
+	//         github.com/pkg/errors/_test/_testmain.go:106
+	// runtime.main
+	//         /usr/lib/go/src/runtime/proc.go:183
+	// runtime.goexit
+	//         /usr/lib/go/src/runtime/asm_amd64.s:2086
+	// github.com/pkg/errors_test.ExampleWithStack_printf
+	//         /home/fabstu/go/src/github.com/pkg/errors/example_test.go:56
+	// testing.runExample
+	//         /usr/lib/go/src/testing/example.go:114
+	// testing.RunExamples
+	//         /usr/lib/go/src/testing/example.go:38
+	// testing.(*M).Run
+	//         /usr/lib/go/src/testing/testing.go:744
+	// main.main
+	//         github.com/pkg/errors/_test/_testmain.go:106
+	// runtime.main
+	//         /usr/lib/go/src/runtime/proc.go:183
+	// runtime.goexit
+	//         /usr/lib/go/src/runtime/asm_amd64.s:2086
+}
+
 func ExampleWrap() {
 	cause := errors.New("whoops")
 	err := errors.Wrap(cause, "oh noes")
diff --git a/format_test.go b/format_test.go
index fd17581..ae1be51 100644
--- a/format_test.go
+++ b/format_test.go
@@ -1,6 +1,7 @@
 package errors
 
 import (
+	"errors"
 	"fmt"
 	"io"
 	"regexp"
@@ -31,6 +32,7 @@
 		New("error"),
 		"%q",
 		`"error"`,
+		"\t.+/github.com/pkg/errors/format_test.go:26",
 	}}
 
 	for i, tt := range tests {
@@ -157,16 +159,270 @@
 	}
 }
 
+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:171"},
+	}, {
+		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:185",
+			"github.com/pkg/errors.TestFormatWithStack\n" +
+				"\t.+/github.com/pkg/errors/format_test.go:185"},
+	}, {
+		WithStack(WithStack(io.EOF)),
+		"%+v",
+		[]string{"EOF",
+			"github.com/pkg/errors.TestFormatWithStack\n" +
+				"\t.+/github.com/pkg/errors/format_test.go:193",
+			"github.com/pkg/errors.TestFormatWithStack\n" +
+				"\t.+/github.com/pkg/errors/format_test.go:193"},
+	}, {
+		WithStack(WithStack(Wrapf(io.EOF, "message"))),
+		"%+v",
+		[]string{"EOF",
+			"message",
+			"github.com/pkg/errors.TestFormatWithStack\n" +
+				"\t.+/github.com/pkg/errors/format_test.go:201",
+			"github.com/pkg/errors.TestFormatWithStack\n" +
+				"\t.+/github.com/pkg/errors/format_test.go:201",
+			"github.com/pkg/errors.TestFormatWithStack\n" +
+				"\t.+/github.com/pkg/errors/format_test.go:201"},
+	}, {
+		WithStack(Errorf("error%d", 1)),
+		"%+v",
+		[]string{"error1",
+			"github.com/pkg/errors.TestFormatWithStack\n" +
+				"\t.+/github.com/pkg/errors/format_test.go:212",
+			"github.com/pkg/errors.TestFormatWithStack\n" +
+				"\t.+/github.com/pkg/errors/format_test.go:212"},
+	}}
+
+	for i, tt := range tests {
+		testFormatCompleteCompare(t, i, tt.error, tt.format, tt.want)
+	}
+}
+
+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:240",
+			"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:268"},
+	}, {
+		WithMessage(Errorf("error%d", 1), "error2"),
+		"%+v",
+		[]string{"error1",
+			"github.com/pkg/errors.TestFormatWithMessage\n" +
+				"\t.+/github.com/pkg/errors/format_test.go:274",
+			"error2"},
+	}, {
+		WithMessage(WithStack(io.EOF), "error"),
+		"%+v",
+		[]string{
+			"EOF",
+			"github.com/pkg/errors.TestFormatWithMessage\n" +
+				"\t.+/github.com/pkg/errors/format_test.go:281",
+			"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:289",
+			"inside-error",
+			"github.com/pkg/errors.TestFormatWithMessage\n" +
+				"\t.+/github.com/pkg/errors/format_test.go:289",
+			"outside-error"},
+	}}
+
+	for i, tt := range tests {
+		testFormatCompleteCompare(t, i, tt.error, tt.format, tt.want)
+	}
+}
+
 func testFormatRegexp(t *testing.T, n int, 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])
+	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): got: %q, want: %q", n+1, i+1, format, got, want)
+			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.
+//
+// Example use:
+//
+// for _, e := range blocks {
+//   if strings.ContainsAny(e, "\n") {
+//     // Match as stack
+//   } else {
+//     // Match as line
+//   }
+// }
+func parseBlocks(input string) ([]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 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) {
+	gotStr := fmt.Sprintf(format, arg)
+
+	got, err := parseBlocks(gotStr)
+	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)
+	}
+
+	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.Errorf("test %d: block %d: fmt.Sprintf(%q, err):\n got: %q\nwant: %q", n+1, i+1, format, got[i], want[i])
+			}
+		} 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])
+			}
 		}
 	}
 }