1
0
mirror of https://github.com/kataras/iris.git synced 2026-01-08 20:41:57 +00:00

Add notes for the new lead maintainer of the open-source iris project and align with @get-ion/ion by @hiveminded

Former-commit-id: da4f38eb9034daa49446df3ee529423b98f9b331
This commit is contained in:
kataras
2017-07-10 18:32:42 +03:00
parent 2d4c2779a7
commit 9f85b74fc9
344 changed files with 4842 additions and 5174 deletions

View File

@@ -1,40 +1,62 @@
// Copyright 2017 Gerasimos Maropoulos, ΓΜ. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package errors
import (
"fmt"
"runtime"
"strings"
"github.com/satori/go.uuid"
)
var (
// Prefix the error prefix, applies to each error's message.
Prefix = ""
// NewLine adds a new line to the end of each error's message
// defaults to true
NewLine = true
)
// Error holds the error message, this message never really changes
type Error struct {
message string
appended bool
// ID returns the unique id of the error, it's needed
// when we want to check if a specific error returned
// but the `Error() string` value is not the same because the error may be dynamic
// by a `Format` call.
ID string `json:"id"`
// The message of the error.
Message string `json:"message"`
// Apennded is true whenever it's a child error.
Appended bool `json:"appended"`
// Stack returns the list of the errors that are shown at `Error() string`.
Stack []Error `json:"stack"` // filled on AppendX.
}
// New creates and returns an Error with a pre-defined user output message
// all methods below that doesn't accept a pointer receiver because actually they are not changing the original message
func New(errMsg string) *Error {
if NewLine {
errMsg += "\n"
func New(errMsg string) Error {
return Error{
ID: uuid.NewV4().String(),
Message: Prefix + errMsg,
}
return &Error{message: Prefix + errMsg}
}
// Equal returns true if "e" and "e2" are matched, by their IDs.
// It will always returns true if the "e2" is a children of "e"
// or the error messages are exactly the same, otherwise false.
func (e Error) Equal(e2 Error) bool {
return e.ID == e2.ID || e.Error() == e2.Error()
}
// Empty returns true if the "e" Error has no message on its stack.
func (e Error) Empty() bool {
return e.Message == ""
}
// NotEmpty returns true if the "e" Error has got a non-empty message on its stack.
func (e Error) NotEmpty() bool {
return !e.Empty()
}
// String returns the error message
func (e Error) String() string {
return e.message
return e.Message
}
// Error returns the message of the actual error
@@ -46,34 +68,53 @@ func (e Error) Error() string {
// Format returns a formatted new error based on the arguments
// it does NOT change the original error's message
func (e Error) Format(a ...interface{}) Error {
e.message = fmt.Sprintf(e.message, a...)
e.Message = fmt.Sprintf(e.Message, a...)
return e
}
func omitNewLine(message string) string {
if strings.HasSuffix(message, "\n") {
return message[0 : len(message)-2]
} else if strings.HasSuffix(message, "\\n") {
return message[0 : len(message)-3]
}
return message
}
// AppendInline appends an error to the stack.
// It doesn't try to append a new line if needed.
func (e Error) AppendInline(format string, a ...interface{}) Error {
msg := fmt.Sprintf(format, a...)
e.Message += msg
e.Appended = true
e.Stack = append(e.Stack, New(omitNewLine(msg)))
return e
}
// Append adds a message to the predefined error message and returns a new error
// it does NOT change the original error's message
func (e Error) Append(format string, a ...interface{}) Error {
// eCp := *e
if NewLine {
format += "\n"
// if new line is false then append this error but first
// we need to add a new line to the first, if it was true then it has the newline already.
if e.Message != "" {
e.Message += "\n"
}
e.message += fmt.Sprintf(format, a...)
e.appended = true
return e
return e.AppendInline(format, a...)
}
// AppendErr adds an error's message to the predefined error message and returns a new error
// AppendErr adds an error's message to the predefined error message and returns a new error.
// it does NOT change the original error's message
func (e Error) AppendErr(err error) Error {
return e.Append(err.Error())
}
// IsAppended returns true if the Error instance is created using original's Error.Append/AppendErr func
func (e Error) IsAppended() bool {
return e.appended
// HasStack returns true if the Error instance is created using Append/AppendInline/AppendErr funcs.
func (e Error) HasStack() bool {
return len(e.Stack) > 0
}
// With does the same thing as Format but it receives an error type which if it's nil it returns a nil error
// With does the same thing as Format but it receives an error type which if it's nil it returns a nil error.
func (e Error) With(err error) error {
if err == nil {
return nil
@@ -82,15 +123,15 @@ func (e Error) With(err error) error {
return e.Format(err.Error())
}
// Panic output the message and after panics
// Panic output the message and after panics.
func (e Error) Panic() {
_, fn, line, _ := runtime.Caller(1)
errMsg := e.message
errMsg := e.Message
errMsg += "\nCaller was: " + fmt.Sprintf("%s:%d", fn, line)
panic(errMsg)
}
// Panicf output the formatted message and after panics
// Panicf output the formatted message and after panics.
func (e Error) Panicf(args ...interface{}) {
_, fn, line, _ := runtime.Caller(1)
errMsg := e.Format(args...).Error()

View File

@@ -13,26 +13,16 @@ var errUserAlreadyExists = errors.New(errMessage)
var userMail = "user1@mail.go"
var expectedUserAlreadyExists = "User with mail: user1@mail.go already exists"
func getNewLine() string {
if errors.NewLine {
return "\n"
}
return ""
}
func ExampleError() {
fmt.Print(errUserAlreadyExists.Format(userMail))
// first output first Output line
fmt.Print(errUserAlreadyExists.Format(userMail).Append("Please change your mail addr"))
// second output second and third Output lines
// Output:
// User with mail: user1@mail.go already exists
// User with mail: user1@mail.go already exists
// Please change your mail addr
}
func do(method string, testErr *errors.Error, expectingMsg string, t *testing.T) {
func do(method string, testErr errors.Error, expectingMsg string, t *testing.T) {
formattedErr := func() error {
return testErr.Format(userMail)
}()
@@ -43,56 +33,51 @@ func do(method string, testErr *errors.Error, expectingMsg string, t *testing.T)
}
func TestFormat(t *testing.T) {
expected := errors.Prefix + expectedUserAlreadyExists + getNewLine()
expected := errors.Prefix + expectedUserAlreadyExists
do("Format Test", errUserAlreadyExists, expected, t)
}
func TestAppendErr(t *testing.T) {
errors.NewLine = true
errors.Prefix = "error: "
errChangeMailMsg := "Please change your mail addr"
errChangeMail := fmt.Errorf(errChangeMailMsg) // test go standard error
expectedErrorMessage := errUserAlreadyExists.Format(userMail).Error() + errChangeMailMsg + getNewLine() // first Prefix and last newline lives inside do
errChangeMail := fmt.Errorf(errChangeMailMsg) // test go standard error
errAppended := errUserAlreadyExists.AppendErr(errChangeMail)
do("Append Test Standard error type", &errAppended, expectedErrorMessage, t)
expectedErrorMessage := errUserAlreadyExists.Format(userMail).Error() + "\n" + errChangeMailMsg
do("Append Test Standard error type", errAppended, expectedErrorMessage, t)
}
func TestAppendError(t *testing.T) {
errors.NewLine = true
errors.Prefix = "error: "
errChangeMailMsg := "Please change your mail addr"
errChangeMail := errors.New(errChangeMailMsg) // test Error struct
expectedErrorMessage := errUserAlreadyExists.Format(userMail).Error() + errChangeMail.Error() + getNewLine() // first Prefix and last newline lives inside do
errChangeMail := errors.New(errChangeMailMsg)
errAppended := errUserAlreadyExists.AppendErr(errChangeMail)
do("Append Test Error type", &errAppended, expectedErrorMessage, t)
expectedErrorMessage := errUserAlreadyExists.Format(userMail).Error() + "\n" + errChangeMail.Error()
do("Append Test Error type", errAppended, expectedErrorMessage, t)
}
func TestAppend(t *testing.T) {
errors.NewLine = true
errors.Prefix = "error: "
errChangeMailMsg := "Please change your mail addr"
expectedErrorMessage := errUserAlreadyExists.Format(userMail).Error() + errChangeMailMsg + getNewLine() // first Prefix and last newline lives inside do
expectedErrorMessage := errUserAlreadyExists.Format(userMail).Error() + "\n" + errChangeMailMsg
errAppended := errUserAlreadyExists.Append(errChangeMailMsg)
do("Append Test string Message", &errAppended, expectedErrorMessage, t)
do("Append Test string Message", errAppended, expectedErrorMessage, t)
}
func TestNewLine(t *testing.T) {
errors.NewLine = false
errNoNewLine := errors.New(errMessage)
err := errors.New(errMessage)
expected := errors.Prefix + expectedUserAlreadyExists
do("NewLine Test", errNoNewLine, expected, t)
errors.NewLine = true
do("NewLine Test", err, expected, t)
}
func TestPrefix(t *testing.T) {
errors.Prefix = "MyPrefix: "
errUpdatedPrefix := errors.New(errMessage)
expected := errors.Prefix + expectedUserAlreadyExists + "\n"
expected := errors.Prefix + expectedUserAlreadyExists
do("Prefix Test with "+errors.Prefix, errUpdatedPrefix, expected, t)
}

141
core/errors/reporter.go Normal file
View File

@@ -0,0 +1,141 @@
package errors
import (
"sync"
)
// StackError contains the Stack method.
type StackError interface {
Stack() []Error
Error() string
}
// PrintAndReturnErrors prints the "err" to the given "printer",
// printer will be called multiple times if the "err" is a StackError, where it contains more than one error.
func PrintAndReturnErrors(err error, printer func(string, ...interface{})) error {
if err == nil || err.Error() == "" {
return nil
}
if stackErr, ok := err.(StackError); ok {
if len(stackErr.Stack()) == 0 {
return nil
}
stack := stackErr.Stack()
for _, e := range stack {
if e.HasStack() {
for _, es := range e.Stack {
printer("%v", es)
}
continue
}
printer("%v", e)
}
return stackErr
}
printer("%v", err)
return err
}
// Reporter is a helper structure which can
// stack errors and prints them to a printer of func(string).
type Reporter struct {
mu sync.Mutex
wrapper Error
}
// NewReporter returns a new empty error reporter.
func NewReporter() *Reporter {
return &Reporter{wrapper: New("")}
}
// AddErr adds an error to the error stack.
// if "err" is a StackError then
// each of these errors will be printed as individual.
func (r *Reporter) AddErr(err error) {
if err == nil {
return
}
if stackErr, ok := err.(StackError); ok {
r.addStack(stackErr.Stack())
return
}
r.mu.Lock()
r.wrapper = r.wrapper.AppendErr(err)
r.mu.Unlock()
}
// Add adds a formatted message as an error to the error stack.
func (r *Reporter) Add(format string, a ...interface{}) {
// usually used as: "module: %v", err so
// check if the first argument is error and if that error is empty then don't add it.
if len(a) > 0 {
f := a[0]
if e, ok := f.(interface {
Error() string
}); ok {
if e.Error() == "" {
return
}
}
}
r.mu.Lock()
r.wrapper = r.wrapper.Append(format, a...)
r.mu.Unlock()
}
// Describe same as `Add` but if "err" is nil then it does nothing.
func (r *Reporter) Describe(format string, err error) {
if err == nil {
return
}
if stackErr, ok := err.(StackError); ok {
r.addStack(stackErr.Stack())
return
}
r.Add(format, err)
}
// PrintStack prints all the errors to the given "printer".
// Returns itself in order to be used as printer and return the full error in the same time.
func (r Reporter) PrintStack(printer func(string, ...interface{})) error {
return PrintAndReturnErrors(r, printer)
}
// Stack returns the list of the errors in the stack.
func (r Reporter) Stack() []Error {
return r.wrapper.Stack
}
func (r *Reporter) addStack(stack []Error) {
for _, e := range stack {
if e.Error() == "" {
continue
}
r.mu.Lock()
r.wrapper = r.wrapper.AppendErr(e)
r.mu.Unlock()
}
}
// Error implements the error, returns the full error string.
func (r Reporter) Error() string {
return r.wrapper.Error()
}
// Return returns nil if the error is empty, otherwise returns the full error.
func (r Reporter) Return() error {
if r.Error() == "" {
return nil
}
return r
}

View File

@@ -0,0 +1,26 @@
// black-box testing
package errors_test
import (
"testing"
"github.com/kataras/iris/core/errors"
)
func TestReporterAdd(t *testing.T) {
errors.Prefix = ""
r := errors.NewReporter()
tests := []string{"err1", "err3", "err4\nerr5"}
for _, tt := range tests {
r.Add(tt)
}
for i, e := range r.Stack() {
tt := tests[i]
if expected, got := tt, e.Error(); expected != got {
t.Fatalf("[%d] expected %s but got %s", i, expected, got)
}
}
}