1package errors
2
3import (
4	"errors"
5	"fmt"
6	"io"
7	"reflect"
8	"testing"
9)
10
11func TestNew(t *testing.T) {
12	tests := []struct {
13		err  string
14		want error
15	}{
16		{"", fmt.Errorf("")},
17		{"foo", fmt.Errorf("foo")},
18		{"foo", New("foo")},
19		{"string with format specifiers: %v", errors.New("string with format specifiers: %v")},
20	}
21
22	for _, tt := range tests {
23		got := New(tt.err)
24		if got.Error() != tt.want.Error() {
25			t.Errorf("New.Error(): got: %q, want %q", got, tt.want)
26		}
27	}
28}
29
30func TestWrapNil(t *testing.T) {
31	got := Wrap(nil, "no error")
32	if got != nil {
33		t.Errorf("Wrap(nil, \"no error\"): got %#v, expected nil", got)
34	}
35}
36
37func TestWrap(t *testing.T) {
38	tests := []struct {
39		err     error
40		message string
41		want    string
42	}{
43		{io.EOF, "read error", "read error: EOF"},
44		{Wrap(io.EOF, "read error"), "client error", "client error: read error: EOF"},
45	}
46
47	for _, tt := range tests {
48		got := Wrap(tt.err, tt.message).Error()
49		if got != tt.want {
50			t.Errorf("Wrap(%v, %q): got: %v, want %v", tt.err, tt.message, got, tt.want)
51		}
52	}
53}
54
55type nilError struct{}
56
57func (nilError) Error() string { return "nil error" }
58
59func TestCause(t *testing.T) {
60	x := New("error")
61	tests := []struct {
62		err  error
63		want error
64	}{{
65		// nil error is nil
66		err:  nil,
67		want: nil,
68	}, {
69		// explicit nil error is nil
70		err:  (error)(nil),
71		want: nil,
72	}, {
73		// typed nil is nil
74		err:  (*nilError)(nil),
75		want: (*nilError)(nil),
76	}, {
77		// uncaused error is unaffected
78		err:  io.EOF,
79		want: io.EOF,
80	}, {
81		// caused error returns cause
82		err:  Wrap(io.EOF, "ignored"),
83		want: io.EOF,
84	}, {
85		err:  x, // return from errors.New
86		want: x,
87	}, {
88		WithMessage(nil, "whoops"),
89		nil,
90	}, {
91		WithMessage(io.EOF, "whoops"),
92		io.EOF,
93	}, {
94		WithStack(nil),
95		nil,
96	}, {
97		WithStack(io.EOF),
98		io.EOF,
99	}}
100
101	for i, tt := range tests {
102		got := Cause(tt.err)
103		if !reflect.DeepEqual(got, tt.want) {
104			t.Errorf("test %d: got %#v, want %#v", i+1, got, tt.want)
105		}
106	}
107}
108
109func TestWrapfNil(t *testing.T) {
110	got := Wrapf(nil, "no error")
111	if got != nil {
112		t.Errorf("Wrapf(nil, \"no error\"): got %#v, expected nil", got)
113	}
114}
115
116func TestWrapf(t *testing.T) {
117	tests := []struct {
118		err     error
119		message string
120		want    string
121	}{
122		{io.EOF, "read error", "read error: EOF"},
123		{Wrapf(io.EOF, "read error without format specifiers"), "client error", "client error: read error without format specifiers: EOF"},
124		{Wrapf(io.EOF, "read error with %d format specifier", 1), "client error", "client error: read error with 1 format specifier: EOF"},
125	}
126
127	for _, tt := range tests {
128		got := Wrapf(tt.err, tt.message).Error()
129		if got != tt.want {
130			t.Errorf("Wrapf(%v, %q): got: %v, want %v", tt.err, tt.message, got, tt.want)
131		}
132	}
133}
134
135func TestErrorf(t *testing.T) {
136	tests := []struct {
137		err  error
138		want string
139	}{
140		{Errorf("read error without format specifiers"), "read error without format specifiers"},
141		{Errorf("read error with %d format specifier", 1), "read error with 1 format specifier"},
142	}
143
144	for _, tt := range tests {
145		got := tt.err.Error()
146		if got != tt.want {
147			t.Errorf("Errorf(%v): got: %q, want %q", tt.err, got, tt.want)
148		}
149	}
150}
151
152func TestWithStackNil(t *testing.T) {
153	got := WithStack(nil)
154	if got != nil {
155		t.Errorf("WithStack(nil): got %#v, expected nil", got)
156	}
157}
158
159func TestWithStack(t *testing.T) {
160	tests := []struct {
161		err  error
162		want string
163	}{
164		{io.EOF, "EOF"},
165		{WithStack(io.EOF), "EOF"},
166	}
167
168	for _, tt := range tests {
169		got := WithStack(tt.err).Error()
170		if got != tt.want {
171			t.Errorf("WithStack(%v): got: %v, want %v", tt.err, got, tt.want)
172		}
173	}
174}
175
176func TestWithMessageNil(t *testing.T) {
177	got := WithMessage(nil, "no error")
178	if got != nil {
179		t.Errorf("WithMessage(nil, \"no error\"): got %#v, expected nil", got)
180	}
181}
182
183func TestWithMessage(t *testing.T) {
184	tests := []struct {
185		err     error
186		message string
187		want    string
188	}{
189		{io.EOF, "read error", "read error: EOF"},
190		{WithMessage(io.EOF, "read error"), "client error", "client error: read error: EOF"},
191	}
192
193	for _, tt := range tests {
194		got := WithMessage(tt.err, tt.message).Error()
195		if got != tt.want {
196			t.Errorf("WithMessage(%v, %q): got: %q, want %q", tt.err, tt.message, got, tt.want)
197		}
198	}
199}
200
201func TestWithMessagefNil(t *testing.T) {
202	got := WithMessagef(nil, "no error")
203	if got != nil {
204		t.Errorf("WithMessage(nil, \"no error\"): got %#v, expected nil", got)
205	}
206}
207
208func TestWithMessagef(t *testing.T) {
209	tests := []struct {
210		err     error
211		message string
212		want    string
213	}{
214		{io.EOF, "read error", "read error: EOF"},
215		{WithMessagef(io.EOF, "read error without format specifier"), "client error", "client error: read error without format specifier: EOF"},
216		{WithMessagef(io.EOF, "read error with %d format specifier", 1), "client error", "client error: read error with 1 format specifier: EOF"},
217	}
218
219	for _, tt := range tests {
220		got := WithMessagef(tt.err, tt.message).Error()
221		if got != tt.want {
222			t.Errorf("WithMessage(%v, %q): got: %q, want %q", tt.err, tt.message, got, tt.want)
223		}
224	}
225}
226
227// errors.New, etc values are not expected to be compared by value
228// but the change in errors#27 made them incomparable. Assert that
229// various kinds of errors have a functional equality operator, even
230// if the result of that equality is always false.
231func TestErrorEquality(t *testing.T) {
232	vals := []error{
233		nil,
234		io.EOF,
235		errors.New("EOF"),
236		New("EOF"),
237		Errorf("EOF"),
238		Wrap(io.EOF, "EOF"),
239		Wrapf(io.EOF, "EOF%d", 2),
240		WithMessage(nil, "whoops"),
241		WithMessage(io.EOF, "whoops"),
242		WithStack(io.EOF),
243		WithStack(nil),
244	}
245
246	for i := range vals {
247		for j := range vals {
248			_ = vals[i] == vals[j] // mustn't panic
249		}
250	}
251}
252