Skip to content

Commit

Permalink
Rremove unnecessary exports
Browse files Browse the repository at this point in the history
  • Loading branch information
e-sumin committed Feb 2, 2024
1 parent 0eb7c44 commit 5aefee0
Show file tree
Hide file tree
Showing 2 changed files with 109 additions and 79 deletions.
93 changes: 64 additions & 29 deletions errors_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,55 +32,89 @@ var (
predefinedTestError = newTestError("TEST_ERR: Sample error of custom test type")
)

type Check func(originalErr error, jsonErr errkit.JSONError) error
type Check func(originalErr error, data []byte) error

func unmarshalJsonError(data []byte, target any) error {
unmarshallingErr := json.Unmarshal(data, target)
if unmarshallingErr != nil {
return fmt.Errorf("Unable to unmarshal error %s\n%s", string(data), unmarshallingErr.Error())
}

return nil
}

func getMessageCheck(msg string) Check {
return func(_ error, err errkit.JSONError) error {
if err.Message != msg {
return fmt.Errorf("error message does not match the expectd\nexpected: %s\nactual: %s", msg, err.Message)
return func(err error, data []byte) error {
var unmarshalledError struct {
Message string `json:"message,omitempty"`
}

if e := unmarshalJsonError(data, &unmarshalledError); e != nil {
return e
}

if unmarshalledError.Message != msg {
return fmt.Errorf("error message does not match the expectd\nexpected: %s\nactual: %s", msg, unmarshalledError.Message)
}
return nil
}
}

func getTextCheck(msg string) Check {
return func(origError error, _ errkit.JSONError) error {
return func(origError error, _ []byte) error {
if origError.Error() != msg {
return fmt.Errorf("error text does not match the expected\nexpected: %s\nactual: %s", msg, origError.Error())
}
return nil
}
}

func filenameCheck(_ error, err errkit.JSONError) error {
func filenameCheck(_ error, data []byte) error {
_, filename, _, _ := runtime.Caller(1)
if !strings.HasPrefix(err.File, filename) {
return fmt.Errorf("error occured in an unexpected file: %s", err.File)
var unmarshalledError struct {
File string `json:"file,omitempty"`
}
if e := unmarshalJsonError(data, &unmarshalledError); e != nil {
return e
}

if !strings.HasPrefix(unmarshalledError.File, filename) {
return fmt.Errorf("error occured in an unexpected file. expected: %s\ngot: %s", filename, unmarshalledError.File)
}

return nil
}

func getStackCheck(fnName string, lineNumber int) Check {
return func(err error, jsonErr errkit.JSONError) error {
e := filenameCheck(err, jsonErr)
return func(err error, data []byte) error {
e := filenameCheck(err, data)
if e != nil {
return e
}

if jsonErr.LineNumber != lineNumber {
return fmt.Errorf("Line number does not match\nexpected: %d\ngot: %d", lineNumber, jsonErr.LineNumber)
var unmarshalledError struct {
LineNumber int `json:"linenumber,omitempty"`
Function string `json:"function,omitempty"`
}

if jsonErr.Function != fnName {
return fmt.Errorf("Function name does not match\nexpected: %s\ngot: %s", fnName, jsonErr.Function)
if e := unmarshalJsonError(data, &unmarshalledError); e != nil {
return e
}

if unmarshalledError.LineNumber != lineNumber {
return fmt.Errorf("Line number does not match\nexpected: %d\ngot: %d", lineNumber, unmarshalledError.LineNumber)
}

if unmarshalledError.Function != fnName {
return fmt.Errorf("Function name does not match\nexpected: %s\ngot: %s", fnName, unmarshalledError.Function)
}

return nil
}
}

func getErrkitIsCheck(cause error) Check {
return func(origErr error, jsonErr errkit.JSONError) error {
return func(origErr error, _ []byte) error {
if !errkit.Is(origErr, cause) {
return errors.New("error is not implementing requested type")
}
Expand All @@ -90,7 +124,7 @@ func getErrkitIsCheck(cause error) Check {
}

func getUnwrapCheck(expected error) Check {
return func(origErr error, jsonErr errkit.JSONError) error {
return func(origErr error, _ []byte) error {
err1 := errors.Unwrap(origErr)
if err1 != expected {
return errors.New("Unable to unwrap error")
Expand All @@ -101,13 +135,21 @@ func getUnwrapCheck(expected error) Check {
}

func getDetailsCheck(details errkit.ErrorDetails) Check {
return func(origErr error, jsonErr errkit.JSONError) error {
if len(details) != len(jsonErr.Details) {
return func(_ error, data []byte) error {
var unmarshalledError struct {
Details errkit.ErrorDetails `json:"details,omitempty"`
}

if e := unmarshalJsonError(data, &unmarshalledError); e != nil {
return e
}

if len(details) != len(unmarshalledError.Details) {
return errors.New("details don't match")
}

for k, v := range details {
if jsonErr.Details[k] != v {
if unmarshalledError.Details[k] != v {
return errors.New("details don't match")
}
}
Expand All @@ -125,15 +167,8 @@ func checkErrorResult(t *testing.T, err error, checks ...Check) {
return
}

var unmarshalledError errkit.JSONError
unmarshallingErr := unmarshalledError.UnmarshalJSON([]byte(got))
if unmarshallingErr != nil {
t.Errorf("serialized error is not a JSON: %s\ngot: %s", unmarshallingErr.Error(), err.Error())
return
}

for _, checker := range checks {
e := checker(err, unmarshalledError)
e := checker(err, got)
if e != nil {
t.Errorf("%s", e.Error())
return
Expand Down Expand Up @@ -189,7 +224,7 @@ func TestErrorsWrapping(t *testing.T) {
getMessageCheck("Wrapped TEST error"), // Checking what msg is serialized on top level
filenameCheck, // Checking callstack capture
getErrkitIsCheck(predefinedTestError), // Checking that original error was successfully wrapped
func(origErr error, jsonErr errkit.JSONError) error {
func(origErr error, _ []byte) error {
var asErr *testErrorType
if errors.As(origErr, &asErr) {
if asErr.Error() == predefinedTestError.Error() {
Expand Down Expand Up @@ -263,7 +298,7 @@ func TestErrorsWithDetails(t *testing.T) {
wrappedResult := "{\"message\":\"Wrapped error\",\"details\":{\"Some numeric detail\":123,\"Some text detail\":\"String value\"},\"cause\":{\"message\":\"TEST_ERR: Sample of sentinel error\"}}"

getResultCheck := func(expected string) Check {
return func(orig error, _ errkit.JSONError) error {
return func(orig error, _ []byte) error {
b, _ := json.Marshal(orig)
errStr := string(b)
type simplifiedStruct struct {
Expand Down
95 changes: 45 additions & 50 deletions marshable_error.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ func getLocationFromStack(stack []uintptr, callers int) (function, file string,
return frame.Function, filename, frame.Line
}

type JSONError struct {
type jsonError struct {
Message string `json:"message,omitempty"`
Function string `json:"function,omitempty"`
LineNumber int `json:"linenumber,omitempty"`
Expand All @@ -33,6 +33,48 @@ type JSONError struct {
Cause any `json:"cause,omitempty"`
}

// UnmarshalJSON return error unmarshaled into jsonError.
func (e *jsonError) UnmarshalJSON(source []byte) error {
var parsedError struct {
Message string `json:"message,omitempty"`
Function string `json:"function,omitempty"`
LineNumber int `json:"linenumber,omitempty"`
File string `json:"file,omitempty"`
Details ErrorDetails `json:"details,omitempty"`
Cause json.RawMessage `json:"cause,omitempty"`
}
err := json.Unmarshal(source, &parsedError)
if err != nil {
return err
}

e.Message = parsedError.Message
e.Function = parsedError.Function
e.File = parsedError.File
e.LineNumber = parsedError.LineNumber
e.Details = parsedError.Details

if parsedError.Cause == nil {
return nil
}

// Trying to parse as jsonError
var jsonErrorCause *jsonError
err = json.Unmarshal(parsedError.Cause, &jsonErrorCause)
if err == nil {
e.Cause = jsonErrorCause
return nil
}

// fallback to any
var cause any
err = json.Unmarshal(parsedError.Cause, &cause)
if err == nil {
e.Cause = cause
}
return err
}

// JSONMarshable attempts to produce a JSON representation of the given err.
// If the resulting string is empty, then the JSON encoding of the err.Error()
// string is returned or empty if the Error() string cannot be encoded.
Expand All @@ -46,20 +88,18 @@ func JSONMarshable(err error) any {
return err
default:
// Otherwise wrap the error with {"message":"…"}
return JSONError{Message: err.Error()}
return jsonError{Message: err.Error()}
}
}

type MarshableErrorList []JSONError

func MarshalErrkitErrorToJSON(err *errkitError) ([]byte, error) {
if err == nil {
return nil, nil
}

function, file, line := getLocationFromStack(err.stack, err.callers)

result := JSONError{
result := jsonError{
Message: err.Message(),
Function: function,
LineNumber: line,
Expand All @@ -82,48 +122,3 @@ func MarshalErrkitErrorToJSON(err *errkitError) ([]byte, error) {

return json.Marshal(result)
}

// jsonError is a data structure which helps to deserialize error at once.
type jsonError struct {
Message string `json:"message,omitempty"`
Function string `json:"function,omitempty"`
LineNumber int `json:"linenumber,omitempty"`
File string `json:"file,omitempty"`
Details ErrorDetails `json:"details,omitempty"`
Cause json.RawMessage `json:"cause,omitempty"`
}

// UnmarshalJSON return error unmarshaled into JSONError.
func (e *JSONError) UnmarshalJSON(source []byte) error {
var parsedError *jsonError
err := json.Unmarshal(source, &parsedError)
if err != nil {
return err
}

e.Message = parsedError.Message
e.Function = parsedError.Function
e.File = parsedError.File
e.LineNumber = parsedError.LineNumber
e.Details = parsedError.Details

if parsedError.Cause == nil {
return nil
}

// Trying to parse as JSONError
var jsonErrorCause *JSONError
err = json.Unmarshal(parsedError.Cause, &jsonErrorCause)
if err == nil {
e.Cause = jsonErrorCause
return nil
}

// fallback to any
var cause any
err = json.Unmarshal(parsedError.Cause, &cause)
if err == nil {
e.Cause = cause
}
return err
}

0 comments on commit 5aefee0

Please sign in to comment.