Skip to content
This repository was archived by the owner on Dec 1, 2021. It is now read-only.

Commit c978824

Browse files
committed
wip
1 parent 105e86f commit c978824

File tree

2 files changed

+121
-13
lines changed

2 files changed

+121
-13
lines changed

errors.go

Lines changed: 76 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,33 @@
11
// Package errors implements functions to manipulate errors.
22
package errors
33

4-
import "fmt"
4+
import (
5+
"fmt"
6+
"runtime"
7+
)
58

69
// New returns an error that formats as the given text.
7-
func New(text string) error {
8-
return Errorf(text)
10+
func New(message string) error {
11+
pc, _, _, _ := runtime.Caller(1) // the caller of New
12+
return struct {
13+
error
14+
pc uintptr
15+
}{
16+
fmt.Errorf(message),
17+
pc,
18+
}
919
}
1020

1121
// Errorf returns a formatted error.
1222
func Errorf(format string, args ...interface{}) error {
13-
return fmt.Errorf(format, args...)
23+
pc, _, _, _ := runtime.Caller(1) // the caller of Errorf
24+
return struct {
25+
error
26+
pc uintptr
27+
}{
28+
fmt.Errorf(format, args...),
29+
pc,
30+
}
1431
}
1532

1633
// Cause returns the underlying cause of the error, if possible.
@@ -35,3 +52,58 @@ func Cause(err error) error {
3552
}
3653
return err
3754
}
55+
56+
func underlying(err error) (error, bool) {
57+
if err == nil {
58+
return nil, false
59+
}
60+
type underlying interface {
61+
underlying() error
62+
}
63+
if err, ok := err.(underlying); ok {
64+
return err.underlying(), true
65+
}
66+
return nil, false
67+
}
68+
69+
type traced struct {
70+
error // underlying error
71+
pc uintptr
72+
}
73+
74+
func (t *traced) underlying() error { return t.error }
75+
76+
// Trace adds caller information to the error.
77+
// If error is nil, nil will be returned.
78+
func Trace(err error) error {
79+
if err == nil {
80+
return nil
81+
}
82+
pc, _, _, _ := runtime.Caller(1) // the caller of Trace
83+
return traced{
84+
error: err,
85+
pc: pc,
86+
}
87+
}
88+
89+
type annotated struct {
90+
error // underlying error
91+
pc uintptr
92+
}
93+
94+
func (a *annotated) Cause() error { return a.error }
95+
96+
// Annotate returns a new error annotating the error provided
97+
// with the message, and the location of the caller of Annotate.
98+
// The underlying error can be recovered by calling Cause.
99+
// If err is nil, nil will be returned.
100+
func Annotate(err error, message string) error {
101+
if err == nil {
102+
return nil
103+
}
104+
pc, _, _, _ := runtime.Caller(1) // the caller of Annotate
105+
return annotated{
106+
error: err,
107+
pc: pc,
108+
}
109+
}

errors_test.go

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,6 @@ import (
77
"testing"
88
)
99

10-
func TestNew(t *testing.T) {
11-
got := New("test error")
12-
want := fmt.Errorf("test error")
13-
14-
if !reflect.DeepEqual(got, want) {
15-
t.Errorf("New: got %#v, want %#v", got, want)
16-
}
17-
}
18-
1910
func TestNewError(t *testing.T) {
2011
tests := []struct {
2112
err string
@@ -34,6 +25,26 @@ func TestNewError(t *testing.T) {
3425
}
3526
}
3627

28+
func TestNewEqualNew(t *testing.T) {
29+
// test that two calls to New return the same error when called from the same location
30+
var errs []error
31+
for i := 0; i < 2; i++ {
32+
errs = append(errs, New("error"))
33+
}
34+
a, b := errs[0], errs[1]
35+
if !reflect.DeepEqual(a, b) {
36+
t.Errorf("Expected two calls to New from the same location to give the same error: %#v, %#v", a, b)
37+
}
38+
}
39+
40+
func TestNewNotEqualNew(t *testing.T) {
41+
// test that two calls to New return different errors when called from different locations
42+
a, b := New("error"), New("error")
43+
if reflect.DeepEqual(a, b) {
44+
t.Errorf("Expected two calls to New from the different locations give the same error: %#v, %#v", a, b)
45+
}
46+
}
47+
3748
type nilError struct{}
3849

3950
func (nilError) Error() string { return "nil error" }
@@ -46,6 +57,7 @@ func (e *causeError) Error() string { return "cause error" }
4657
func (e *causeError) Cause() error { return e.cause }
4758

4859
func TestCause(t *testing.T) {
60+
x := New("error")
4961
tests := []struct {
5062
err error
5163
want error
@@ -69,6 +81,9 @@ func TestCause(t *testing.T) {
6981
// caused error returns cause
7082
err: &causeError{cause: io.EOF},
7183
want: io.EOF,
84+
}, {
85+
err: x, // return from errors.New
86+
want: x,
7287
}}
7388

7489
for i, tt := range tests {
@@ -78,3 +93,24 @@ func TestCause(t *testing.T) {
7893
}
7994
}
8095
}
96+
97+
func TestTraceNotEqual(t *testing.T) {
98+
// test that two calls to trace do not return identical errors
99+
err := New("error")
100+
a := err
101+
var errs []error
102+
for i := 0; i < 2; i++ {
103+
err = Trace(err)
104+
errs = append(errs, err)
105+
}
106+
b, c := errs[0], errs[1]
107+
if reflect.DeepEqual(a, b) {
108+
t.Errorf("a and b equal: %#v, %#v", a, b)
109+
}
110+
if reflect.DeepEqual(b, c) {
111+
t.Errorf("b and c equal: %#v, %#v", b, c)
112+
}
113+
if reflect.DeepEqual(a, c) {
114+
t.Errorf("a and c equal: %#v, %#v", a, c)
115+
}
116+
}

0 commit comments

Comments
 (0)