Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

issue 28: fix wrong location of some errors #30

Merged
merged 1 commit into from
Jun 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1 @@
.idea
.idea/
11 changes: 11 additions & 0 deletions fault.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,17 @@ func Wrap(err error, w ...Wrapper) error {
return nil
}

// the passed err might already have a location if it's a fault.New error, or it might not if it's another type of
// error like one from the standard library. Wrapping it in a container with an empty location ensures that the
// location will be reset when we flatten the error chain. If the error is a fault.New error, it will itself be
// wrapped in a container which will have a location
if _, ok := err.(*container); !ok {
err = &container{
cause: err,
location: "",
}
}

for _, fn := range w {
err = fn(err)
}
Expand Down
10 changes: 8 additions & 2 deletions flatten.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,14 @@ func Flatten(err error) Chain {
// exist to contain other errors that actually contain information,
// store the container's recorded location for usage with the next item.
case *container:
if _, ok := next.(*container); ok && unwrapped.location != "" {
// Having 2 containers back to back can happen if we're using .Wrap without using any wrappers. In that
// case, we add a Step to avoid losing the location whe the wrapping occurred
f = append([]Step{{
Location: unwrapped.location,
Message: "",
}}, f...)
}
lastLocation = unwrapped.location

case *fundamental:
Expand Down Expand Up @@ -79,8 +87,6 @@ func Flatten(err error) Chain {
Location: lastLocation,
Message: message,
}}, f...)

lastLocation = ""
}
}

Expand Down
92 changes: 70 additions & 22 deletions tests/flatten_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,23 @@ func TestFlattenStdlibSentinelError(t *testing.T) {
full := err.Error()

a.Equal("failed to call function: stdlib sentinel error", full)
a.Len(chain, 2)
a.Len(chain, 4)

e0 := chain[0]
a.Equal("stdlib sentinel error", e0.Message)
a.Contains(e0.Location, "test_callers.go:29")
a.Empty(e0.Location)

e1 := chain[1]
a.Equal("failed to call function", e1.Message)
a.Contains(e1.Location, "test_callers.go:20")
a.Empty(e1.Message)
a.Contains(e1.Location, "test_callers.go:29")

e2 := chain[2]
a.Equal("failed to call function", e2.Message)
a.Contains(e2.Location, "test_callers.go:20")

e3 := chain[3]
a.Empty(e3.Message)
a.Contains(e3.Location, "test_callers.go:11")
}

func TestFlattenFaultSentinelError(t *testing.T) {
Expand All @@ -35,15 +43,23 @@ func TestFlattenFaultSentinelError(t *testing.T) {
full := err.Error()

a.Equal("failed to call function: fault sentinel error", full)
a.Len(chain, 2)
a.Len(chain, 4)

e0 := chain[0]
a.Equal("fault sentinel error", e0.Message)
a.Contains(e0.Location, "root.go:15")

e1 := chain[1]
a.Equal("failed to call function", e1.Message)
a.Contains(e1.Location, "test_callers.go:20")
a.Empty(e1.Message)
a.Contains(e1.Location, "test_callers.go:29")

e2 := chain[2]
a.Equal("failed to call function", e2.Message)
a.Contains(e2.Location, "test_callers.go:20")

e3 := chain[3]
a.Empty(e3.Message)
a.Contains(e3.Location, "test_callers.go:11")
}

func TestFlattenStdlibInlineError(t *testing.T) {
Expand All @@ -54,15 +70,23 @@ func TestFlattenStdlibInlineError(t *testing.T) {
full := err.Error()

a.Equal("failed to call function: stdlib root cause error", full)
a.Len(chain, 2)
a.Len(chain, 4)

e0 := chain[0]
a.Equal("stdlib root cause error", e0.Message)
a.Contains(e0.Location, "test_callers.go:29")
a.Empty(e0.Location)

e1 := chain[1]
a.Equal("failed to call function", e1.Message)
a.Contains(e1.Location, "test_callers.go:20")
a.Empty(e1.Message)
a.Contains(e1.Location, "test_callers.go:29")

e2 := chain[2]
a.Equal("failed to call function", e2.Message)
a.Contains(e2.Location, "test_callers.go:20")

e3 := chain[3]
a.Empty(e3.Message)
a.Contains(e3.Location, "test_callers.go:11")
}

func TestFlattenFaultInlineError(t *testing.T) {
Expand All @@ -73,15 +97,23 @@ func TestFlattenFaultInlineError(t *testing.T) {
full := err.Error()

a.Equal("failed to call function: fault root cause error", full)
a.Len(chain, 2)
a.Len(chain, 4)

e0 := chain[0]
a.Equal("fault root cause error", e0.Message)
a.Contains(e0.Location, "root.go:28")

e1 := chain[1]
a.Equal("failed to call function", e1.Message)
a.Contains(e1.Location, "test_callers.go:20")
a.Empty(e1.Message)
a.Contains(e1.Location, "test_callers.go:29")

e2 := chain[2]
a.Equal("failed to call function", e2.Message)
a.Contains(e2.Location, "test_callers.go:20")

e3 := chain[3]
a.Empty(e3.Message)
a.Contains(e3.Location, "test_callers.go:11")
}

func TestFlattenStdlibErrorfWrappedError(t *testing.T) {
Expand All @@ -92,19 +124,27 @@ func TestFlattenStdlibErrorfWrappedError(t *testing.T) {
full := err.Error()

a.Equal("failed to call function: errorf wrapped: stdlib sentinel error", full)
a.Len(chain, 3)
a.Len(chain, 5)

e0 := chain[0]
a.Equal("stdlib sentinel error", e0.Message)
a.Empty(e0.Location)

e1 := chain[1]
a.Equal("errorf wrapped", e1.Message)
a.Contains(e1.Location, "test_callers.go:29")
a.Empty(e1.Location)

e2 := chain[2]
a.Equal("failed to call function", e2.Message)
a.Contains(e2.Location, "test_callers.go:20")
a.Empty(e2.Message)
a.Contains(e2.Location, "test_callers.go:29")

e3 := chain[3]
a.Equal("failed to call function", e3.Message)
a.Contains(e3.Location, "test_callers.go:20")

e4 := chain[4]
a.Empty(e4.Message)
a.Contains(e4.Location, "test_callers.go:11")
}

func TestFlattenStdlibErrorfWrappedExternalError(t *testing.T) {
Expand All @@ -115,7 +155,7 @@ func TestFlattenStdlibErrorfWrappedExternalError(t *testing.T) {
full := err.Error()

a.Equal("failed to call function: errorf wrapped external: external error wrapped with errorf: stdlib external error", full)
a.Len(chain, 4)
a.Len(chain, 6)

e0 := chain[0]
a.Equal("stdlib external error", e0.Message)
Expand All @@ -127,11 +167,19 @@ func TestFlattenStdlibErrorfWrappedExternalError(t *testing.T) {

e2 := chain[2]
a.Equal("errorf wrapped external", e2.Message)
a.Contains(e2.Location, "test_callers.go:29")
a.Empty(e2.Location)

e3 := chain[3]
a.Equal("failed to call function", e3.Message)
a.Contains(e3.Location, "test_callers.go:20")
a.Empty(e3.Message)
a.Contains(e3.Location, "test_callers.go:29")

e4 := chain[4]
a.Equal("failed to call function", e4.Message)
a.Contains(e4.Location, "test_callers.go:20")

e5 := chain[5]
a.Empty(e5.Message)
a.Contains(e5.Location, "test_callers.go:11")
}

func TestFlattenStdlibErrorfWrappedExternallyWrappedError(t *testing.T) {
Expand Down
4 changes: 4 additions & 0 deletions tests/format_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,10 @@ func TestFormatFaultSentinelError(t *testing.T) {
a.Equal("failed to call function: fault sentinel error", fmt.Sprintf("%v", err))
a.Regexp(`fault sentinel error
\s+.+fault/tests/root.go:15
\s+.+fault/tests/test_callers.go:29
failed to call function
\s+.+fault/tests/test_callers.go:20
\s+.+fault/tests/test_callers.go:11
`, fmt.Sprintf("%+v", err))
}

Expand Down Expand Up @@ -66,8 +68,10 @@ func TestFormatFaultInlineError(t *testing.T) {
a.Equal("failed to call function: fault root cause error", fmt.Sprintf("%v", err))
a.Regexp(`fault root cause error
\s+.+fault/tests/root.go:28
\s+.+fault/tests/test_callers.go:29
failed to call function
\s+.+fault/tests/test_callers.go:20
\s+.+fault/tests/test_callers.go:11
`, fmt.Sprintf("%+v", err))
}

Expand Down