-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Support Go1.13 error unwrapping.
- Loading branch information
Showing
26 changed files
with
525 additions
and
193 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
// Copyright 2019 The ebml-go authors. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
package ebml | ||
|
||
import ( | ||
"fmt" | ||
"reflect" | ||
) | ||
|
||
// Error records a failed parsing. | ||
type Error struct { | ||
Err error | ||
Failure string | ||
} | ||
|
||
func (e *Error) Error() string { | ||
// TODO: migrate to fmt.Sprintf %w once Go1.12 reaches EOL. | ||
return e.Failure + ": " + e.Err.Error() | ||
} | ||
|
||
// Unwrap returns the reason of the failure. | ||
// This is for Go1.13 error unwrapping. | ||
func (e *Error) Unwrap() error { | ||
return e.Err | ||
} | ||
|
||
// Is reports whether chained error contains target. | ||
// This is for Go1.13 error unwrapping. | ||
func (e *Error) Is(target error) bool { | ||
err := e.Err | ||
|
||
switch target { | ||
case e: | ||
return true | ||
case nil: | ||
return err == nil | ||
} | ||
for { | ||
switch err { | ||
case nil: | ||
return false | ||
case target: | ||
return true | ||
} | ||
x, ok := err.(interface{ Unwrap() error }) | ||
if !ok { | ||
// Some stdlibs haven't have error unwrapper yet. | ||
// Check err.Err field if exposed. | ||
if reflect.TypeOf(err).Kind() == reflect.Ptr { | ||
e := reflect.ValueOf(err).Elem().FieldByName("Err") | ||
if e.IsValid() { | ||
e2, ok := e.Interface().(error) | ||
if !ok { | ||
return false | ||
} | ||
err = e2 | ||
continue | ||
} | ||
} | ||
return false | ||
} | ||
err = x.Unwrap() | ||
} | ||
} | ||
|
||
func wrapError(err error, failure string) error { | ||
return &Error{ | ||
Failure: failure, | ||
Err: err, | ||
} | ||
} | ||
|
||
func wrapErrorf(err error, failureFmt string, v ...interface{}) error { | ||
return wrapError(err, fmt.Sprintf(failureFmt, v...)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
// Copyright 2019 The ebml-go authors. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
package ebml | ||
|
||
import ( | ||
"errors" | ||
"testing" | ||
|
||
"github.com/at-wat/ebml-go/internal/errs" | ||
) | ||
|
||
type dummyError struct { | ||
Err error | ||
} | ||
|
||
func (e *dummyError) Error() string { | ||
return e.Err.Error() | ||
} | ||
|
||
func TestError(t *testing.T) { | ||
errBase := errors.New("an error") | ||
errOther := errors.New("an another error") | ||
errChained := wrapErrorf(errBase, "info") | ||
errChainedNil := wrapErrorf(nil, "info") | ||
errChainedOther := wrapErrorf(errOther, "info") | ||
err112Chained := wrapErrorf(&dummyError{errBase}, "info") | ||
err112Nil := wrapErrorf(&dummyError{nil}, "info") | ||
errStr := "info: an error" | ||
|
||
t.Run("ErrorsIs", func(t *testing.T) { | ||
if !errs.Is(errChained, errBase) { | ||
t.Errorf("Wrapped error '%v' doesn't chain '%v'", errChained, errBase) | ||
} | ||
}) | ||
|
||
t.Run("Is", func(t *testing.T) { | ||
if !errChained.(*Error).Is(errChained) { | ||
t.Errorf("Wrapped error '%v' doesn't match its-self", errChained) | ||
} | ||
if !errChained.(*Error).Is(errBase) { | ||
t.Errorf("Wrapped error '%v' doesn't match '%v'", errChained, errBase) | ||
} | ||
if !err112Chained.(*Error).Is(errBase) { | ||
t.Errorf("Wrapped error '%v' doesn't match '%v'", | ||
err112Chained, errBase) | ||
} | ||
if !errChainedNil.(*Error).Is(nil) { | ||
t.Errorf("Nil chained error '%v' doesn't match 'nil'", errChainedNil) | ||
} | ||
|
||
if errChainedNil.(*Error).Is(errBase) { | ||
t.Errorf("Wrapped error '%v' unexpectedly matched '%v'", | ||
errChainedNil, errBase) | ||
} | ||
if errChainedOther.(*Error).Is(errBase) { | ||
t.Errorf("Wrapped error '%v' unexpectedly matched '%v'", | ||
errChainedOther, errBase) | ||
} | ||
if err112Nil.(*Error).Is(errBase) { | ||
t.Errorf("Wrapped error '%v' unexpectedly matched '%v'", | ||
errChainedOther, errBase) | ||
} | ||
}) | ||
|
||
if errChained.Error() != errStr { | ||
t.Errorf("Error string expected: %s, got: %s", errStr, errChained.Error()) | ||
} | ||
if errChained.(*Error).Unwrap() != errBase { | ||
t.Errorf("Unwrapped error expected: %s, got: %s", errBase, errChained.(*Error).Unwrap()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
// +build !go1.13 | ||
|
||
// Copyright 2019 The ebml-go authors. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
package errs | ||
|
||
// Is compares error type. Works like Go1.13 errors.Is(). | ||
func Is(err, target error) bool { | ||
if target == nil { | ||
return err == nil | ||
} | ||
for { | ||
if err == target { | ||
return true | ||
} | ||
if err == nil { | ||
return false | ||
} | ||
if x, ok := err.(interface{ Is(error) bool }); ok { | ||
return x.Is(target) | ||
} | ||
x, ok := err.(interface{ Unwrap() error }) | ||
if !ok { | ||
return false | ||
} | ||
err = x.Unwrap() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
// +build go1.13 | ||
|
||
// Copyright 2019 The ebml-go authors. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
// Package errs is for compatibility with Go1.13 error wrapping. | ||
package errs | ||
|
||
import ( | ||
"errors" | ||
) | ||
|
||
// Is compares error type. Wrapping Go1.13 errors.Is(). | ||
func Is(err, target error) bool { | ||
return errors.Is(err, target) | ||
} |
Oops, something went wrong.