replace zxq.co/ripple/hanayo

This commit is contained in:
Alicia
2019-02-23 13:29:15 +00:00
commit c3d206c173
5871 changed files with 1353715 additions and 0 deletions

50
vendor/github.com/ansel1/merry/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,50 @@
# Created by .ignore support plugin (hsz.mobi)
### JetBrains template
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion
*.iml
## Directory-based project format:
.idea/
# if you remove the above rule, at least ignore the following:
# User-specific stuff:
# .idea/workspace.xml
# .idea/tasks.xml
# .idea/dictionaries
# Sensitive or high-churn files:
# .idea/dataSources.ids
# .idea/dataSources.xml
# .idea/sqlDataSources.xml
# .idea/dynamic.xml
# .idea/uiDesigner.xml
# Gradle:
# .idea/gradle.xml
# .idea/libraries
# Mongo Explorer plugin:
# .idea/mongoSettings.xml
## File-based project format:
*.ipr
*.iws
## Plugin-specific files:
# IntelliJ
/out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
vendor/

9
vendor/github.com/ansel1/merry/.travis.yml generated vendored Normal file
View File

@@ -0,0 +1,9 @@
language: go
go:
- 1.5
- 1.6
- 1.7
- 1.8
- 1.9
- tip

27
vendor/github.com/ansel1/merry/Gopkg.lock generated vendored Normal file
View File

@@ -0,0 +1,27 @@
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
[[projects]]
name = "github.com/davecgh/go-spew"
packages = ["spew"]
revision = "346938d642f2ec3594ed81d874461961cd0faa76"
version = "v1.1.0"
[[projects]]
name = "github.com/pmezard/go-difflib"
packages = ["difflib"]
revision = "792786c7400a136282c1664665ae0a8db921c6c2"
version = "v1.0.0"
[[projects]]
name = "github.com/stretchr/testify"
packages = ["assert"]
revision = "69483b4bd14f5845b5a1e55bca19e954e827f1d0"
version = "v1.1.4"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "b750880cdc8ce044e6f9bf3b331d8a392471c328107b8c3d42e3e11022d76858"
solver-name = "gps-cdcl"
solver-version = 1

26
vendor/github.com/ansel1/merry/Gopkg.toml generated vendored Normal file
View File

@@ -0,0 +1,26 @@
# Gopkg.toml example
#
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
# for detailed Gopkg.toml documentation.
#
# required = ["github.com/user/thing/cmd/thing"]
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
#
# [[constraint]]
# name = "github.com/user/project"
# version = "1.0.0"
#
# [[constraint]]
# name = "github.com/user/project2"
# branch = "dev"
# source = "github.com/myfork/project2"
#
# [[override]]
# name = "github.com/x/y"
# version = "2.4.0"
[[constraint]]
name = "github.com/stretchr/testify"
version = "1.1.4"

21
vendor/github.com/ansel1/merry/LICENSE.MIT generated vendored Normal file
View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2015 Russ Egan
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

193
vendor/github.com/ansel1/merry/README.md generated vendored Normal file
View File

@@ -0,0 +1,193 @@
merry [![Build Status](https://travis-ci.org/ansel1/merry.svg?branch=master)](https://travis-ci.org/ansel1/merry) [![GoDoc](https://godoc.org/github.com/ansel1/merry?status.png)](https://godoc.org/github.com/ansel1/merry) [![Go Report Card](https://goreportcard.com/badge/github.com/ansel1/merry)](https://goreportcard.com/report/github.com/ansel1/merry)
=====
Make your golang errors merry, with stacktraces, inheritance, and arbitrary additional context.
The package is largely based on http://github.com/go-errors/errors, with additional
inspiration from https://github.com/go-errgo/errgo and https://github.com/amattn/deeperror.
Installation
------------
go get github.com/ansel1/merry
Features
--------
Merry errors work a lot like google's golang.org/x/net/context package.
Merry errors wrap normal errors with a context of key/value pairs.
Like contexts, merry errors are immutable: adding a key/value to an error
always creates a new error which wraps the original.
`merry` comes with built-in support for adding information to errors:
* stacktraces
* overriding the error message
* HTTP status codes
* End user error messages
You can also add your own additional information.
The stack capturing feature can be turned off for better performance, though it's pretty fast. Benchmarks
on an early 2011 MacBook Pro, with go 1.7rc1:
BenchmarkNew_withStackCapture-8 1000000 1413 ns/op
BenchmarkNew_withoutStackCapture-8 10000000 218 ns/op
Details
-------
* New errors have a stacktrace captured where they are created
* Add a stacktrace to existing errors (captured where they are wrapped)
```go
err := lib.Read()
return merry.Wrap(err) // no-op if err is already merry
```
* Allow golang idiom of comparing an err value to an exported value, using `Is()`
```go
var ParseError = merry.New("Parse error")
func Parse() error {
err := ParseError.Here() // captures a stacktrace here
merry.Is(err, ParseError) // instead of err == ParseError
}
```
* Change the message on an error, while still using `Is()` to compare to the original error
```go
err := merry.WithMessage(ParseError, "Bad input")
merry.Is(err, ParseError) // yes it is
```
* `Is()` supports hierarchies of errors
```go
var ParseError = merry.New("Parse error")
var InvalidCharSet = merry.WithMessage(ParseError, "Invalid char set")
var InvalidSyntax = merry.WithMessage(ParseError, "Invalid syntax")
func Parse(s string) error {
// use chainable methods to add context
return InvalidCharSet.Here().WithMessagef("Invalid char set: %s", "UTF-8")
// or functions
// return merry.WithMessagef(merry.Here(InvalidCharSet), "Invalid char set: %s", "UTF-8")
}
func Check() {
err := Parse("fields")
merry.Is(err, ParseError) // yup
merry.Is(err, InvalidCharSet) // yup
merry.Is(err, InvalidSyntax) // nope
}
```
* Add an HTTP status code
```go
merry.HTTPCode(errors.New("regular error")) // 500
merry.HTTPCode(merry.New("merry error").WithHTTPCode(404)) // 404
```
* Set an alternate error message for end users
```go
e := merry.New("crash").WithUserMessage("nothing to see here")
merry.UserMessage(e) // returns "nothing to see here"
```
* Functions for printing error details
```go
err := merry.New("boom")
m := merry.Stacktrace(err) // just the stacktrace
m = merry.Details(err) // error message and stacktrace
fmt.Sprintf("%+v", err) == merry.Details(err) // errors implement fmt.Formatter
```
* Add your own context info
```go
err := merry.New("boom").WithValue("explosive", "black powder")
```
Basic Usage
-----------
The package contains functions for creating new errors with stacks, or adding a stack to `error`
instances. Functions with add context (e.g. `WithValue()`) work on any `error`, and will
automatically convert them to merry errors (with a stack) if necessary.
Capturing the stack can be globally disabled with `SetStackCaptureEnabled(false)`
Functions which get context values from errors also accept `error`, and will return default
values if the error is not merry, or doesn't have that key attached.
All the functions which create or attach context return concrete instances of `*Error`. `*Error`
implements methods to add context to the error (they mirror the functions and do
the same thing). They allow for a chainable syntax for adding context.
Example:
```go
package main
import (
"github.com/ansel1/merry"
"errors"
)
var InvalidInputs = errors.New("Input is invalid")
func main() {
// create a new error, with a stacktrace attached
err := merry.New("bad stuff happened")
// create a new error with format string, like fmt.Errorf
err = merry.Errorf("bad input: %v", os.Args)
// capture a fresh stacktrace from this callsite
err = merry.Here(InvalidInputs)
// Make err merry if it wasn't already. The stacktrace will be captured here if the
// error didn't already have one. Also useful to cast to *Error
err = merry.Wrap(err, 0)
// override the original error's message
err.WithMessagef("Input is invalid: %v", os.Args)
// Use Is to compare errors against values, which is a common golang idiom
merry.Is(err, InvalidInputs) // will be true
// associated an http code
err.WithHTTPCode(400)
perr := parser.Parse("blah")
err = Wrap(perr, 0)
// Get the original error back
merry.Unwrap(err) == perr // will be true
// Print the error to a string, with the stacktrace, if it has one
s := merry.Details(err)
// Just print the stacktrace (empty string if err is not a RichError)
s := merry.Stacktrace(err)
// Get the location of the error (the first line in the stacktrace)
file, line := merry.Location(err)
// Get an HTTP status code for an error. Defaults to 500 for non-nil errors, and 200 if err is nil.
code := merry.HTTPCode(err)
}
```
See inline docs for more details.
License
-------
This package is licensed under the MIT license, see LICENSE.MIT for details.

556
vendor/github.com/ansel1/merry/errors.go generated vendored Normal file
View File

@@ -0,0 +1,556 @@
package merry
// The merry package augments standard golang errors with stacktraces
// and other context information.
//
// You can add any context information to an error with `e = merry.WithValue(e, "code", 12345)`
// You can retrieve that value with `v, _ := merry.Value(e, "code").(int)`
//
// Any error augmented like this will automatically get a stacktrace attached, if it doesn't have one
// already. If you just want to add the stacktrace, use `Wrap(e)`
//
// It also providers a way to override an error's message:
//
// var InvalidInputs = errors.New("Bad inputs")
//
// `Here()` captures a new stacktrace, and WithMessagef() sets a new error message:
//
// return merry.Here(InvalidInputs).WithMessagef("Bad inputs: %v", inputs)
//
// Errors are immutable. All functions and methods which add context return new errors.
// But errors can still be compared to the originals with `Is()`
//
// if merry.Is(err, InvalidInputs) {
//
// Functions which add context to errors have equivalent methods on *Error, to allow
// convenient chaining:
//
// return merry.New("Invalid body").WithHTTPCode(400)
//
// merry.Errors also implement fmt.Formatter, similar to github.com/pkg/errors.
//
// fmt.Sprintf("%+v", e) == merry.Details(e)
//
// pkg/errors Cause() interface is not implemented (yet).
import (
"errors"
"fmt"
"io"
"runtime"
)
// MaxStackDepth is the maximum number of stackframes on any error.
var MaxStackDepth = 50
var captureStacks = true
var verbose = false
// StackCaptureEnabled returns whether stack capturing is enabled
func StackCaptureEnabled() bool {
return captureStacks
}
// SetStackCaptureEnabled sets stack capturing globally. Disabling stack capture can increase performance
func SetStackCaptureEnabled(enabled bool) {
captureStacks = enabled
}
// VerboseDefault returns the global default for verbose mode.
// When true, e.Error() == Details(e)
// When false, e.Error() == Message(e)
func VerboseDefault() bool {
return verbose
}
// SetVerboseDefault sets the global default for verbose mode.
// When true, e.Error() == Details(e)
// When false, e.Error() == Message(e)
func SetVerboseDefault(b bool) {
verbose = b
}
// Error extends the standard golang `error` interface with functions
// for attachment additional data to the error
type Error interface {
error
Appendf(format string, args ...interface{}) Error
Append(msg string) Error
Prepend(msg string) Error
Prependf(format string, args ...interface{}) Error
WithMessage(msg string) Error
WithMessagef(format string, args ...interface{}) Error
WithUserMessage(msg string) Error
WithUserMessagef(format string, args ...interface{}) Error
WithValue(key, value interface{}) Error
Here() Error
WithStackSkipping(skip int) Error
WithHTTPCode(code int) Error
fmt.Formatter
}
// New creates a new error, with a stack attached. The equivalent of golang's errors.New()
func New(msg string) Error {
return WrapSkipping(errors.New(msg), 1)
}
// Errorf creates a new error with a formatted message and a stack. The equivalent of golang's fmt.Errorf()
func Errorf(format string, a ...interface{}) Error {
return WrapSkipping(fmt.Errorf(format, a...), 1)
}
// UserError creates a new error with a message intended for display to an
// end user.
func UserError(msg string) Error {
return WrapSkipping(errors.New(""), 1).WithUserMessage(msg)
}
// UserErrorf is like UserError, but uses fmt.Sprintf()
func UserErrorf(format string, a ...interface{}) Error {
return WrapSkipping(errors.New(""), 1).WithUserMessagef(format, a...)
}
// Wrap turns the argument into a merry.Error. If the argument already is a
// merry.Error, this is a no-op.
// If e == nil, return nil
func Wrap(e error) Error {
return WrapSkipping(e, 1)
}
// WrapSkipping turns the error arg into a merry.Error if the arg is not
// already a merry.Error.
// If e is nil, return nil.
// If a merry.Error is created by this call, the stack captured will skip
// `skip` frames (0 is the call site of `WrapSkipping()`)
func WrapSkipping(e error, skip int) Error {
switch e1 := e.(type) {
case nil:
return nil
case *merryErr:
return e1
default:
return &merryErr{
err: e,
key: stack,
value: captureStack(skip + 1),
}
}
}
// WithValue adds a context an error. If the key was already set on e,
// the new value will take precedence.
// If e is nil, returns nil.
func WithValue(e error, key, value interface{}) Error {
if e == nil {
return nil
}
return WrapSkipping(e, 1).WithValue(key, value)
}
// Value returns the value for key, or nil if not set.
// If e is nil, returns nil.
func Value(e error, key interface{}) interface{} {
for {
switch m := e.(type) {
case nil:
return nil
case *merryErr:
if m.key == key {
return m.value
}
e = m.err
default:
return nil
}
}
}
// Values returns a map of all values attached to the error
// If a key has been attached multiple times, the map will
// contain the last value mapped
// If e is nil, returns nil.
func Values(e error) map[interface{}]interface{} {
if e == nil {
return nil
}
var values map[interface{}]interface{}
for {
w, ok := e.(*merryErr)
if !ok {
return values
}
if values == nil {
values = make(map[interface{}]interface{}, 1)
}
if _, ok := values[w.key]; !ok {
values[w.key] = w.value
}
e = w.err
}
}
// Here returns an error with a new stacktrace, at the call site of Here().
// Useful when returning copies of exported package errors.
// If e is nil, returns nil.
func Here(e error) Error {
switch m := e.(type) {
case nil:
return nil
case *merryErr:
// optimization: only capture the stack once, since its expensive
return m.WithStackSkipping(1)
default:
return WrapSkipping(e, 1)
}
}
// Stack returns the stack attached to an error, or nil if one is not attached
// If e is nil, returns nil.
func Stack(e error) []uintptr {
stack, _ := Value(e, stack).([]uintptr)
return stack
}
// WithHTTPCode returns an error with an http code attached.
// If e is nil, returns nil.
func WithHTTPCode(e error, code int) Error {
if e == nil {
return nil
}
return WrapSkipping(e, 1).WithHTTPCode(code)
}
// HTTPCode converts an error to an http status code. All errors
// map to 500, unless the error has an http code attached.
// If e is nil, returns 200.
func HTTPCode(e error) int {
if e == nil {
return 200
}
code, _ := Value(e, httpCode).(int)
if code == 0 {
return 500
}
return code
}
// UserMessage returns the end-user safe message. Returns empty if not set.
// If e is nil, returns "".
func UserMessage(e error) string {
if e == nil {
return ""
}
msg, _ := Value(e, userMessage).(string)
return msg
}
// Message returns just the error message. It is equivalent to
// Error() when Verbose is false.
// The behavior of Error() is (pseudo-code):
//
// if verbose
// Details(e)
// else
// Message(e) || UserMessage(e)
//
// If e is nil, returns "".
func Message(e error) string {
if e == nil {
return ""
}
m, _ := Value(e, message).(string)
if m == "" {
return Unwrap(e).Error()
}
return m
}
// WithMessage returns an error with a new message.
// The resulting error's Error() method will return
// the new message.
// If e is nil, returns nil.
func WithMessage(e error, msg string) Error {
if e == nil {
return nil
}
return WrapSkipping(e, 1).WithValue(message, msg)
}
// WithMessagef is the same as WithMessage(), using fmt.Sprintf().
func WithMessagef(e error, format string, a ...interface{}) Error {
if e == nil {
return nil
}
return WrapSkipping(e, 1).WithMessagef(format, a...)
}
// WithUserMessage adds a message which is suitable for end users to see.
// If e is nil, returns nil.
func WithUserMessage(e error, msg string) Error {
if e == nil {
return nil
}
return WrapSkipping(e, 1).WithUserMessage(msg)
}
// WithUserMessagef is the same as WithMessage(), using fmt.Sprintf()
func WithUserMessagef(e error, format string, args ...interface{}) Error {
if e == nil {
return nil
}
return WrapSkipping(e, 1).WithUserMessagef(format, args...)
}
// Append a message after the current error message, in the format "original: new".
// If e == nil, return nil.
func Append(e error, msg string) Error {
if e == nil {
return nil
}
return WrapSkipping(e, 1).Append(msg)
}
// Appendf is the same as Append, but uses fmt.Sprintf().
func Appendf(e error, format string, args ...interface{}) Error {
if e == nil {
return nil
}
return WrapSkipping(e, 1).Appendf(format, args...)
}
// Prepend a message before the current error message, in the format "new: original".
// If e == nil, return nil.
func Prepend(e error, msg string) Error {
if e == nil {
return nil
}
return WrapSkipping(e, 1).Prepend(msg)
}
// Prependf is the same as Prepend, but uses fmt.Sprintf()
func Prependf(e error, format string, args ...interface{}) Error {
if e == nil {
return nil
}
return WrapSkipping(e, 1).Prependf(format, args...)
}
// Is checks whether e is equal to or wraps the original, at any depth.
// If e == nil, return false.
// This is useful if your package uses the common golang pattern of
// exported error constants. If your package exports an ErrEOF constant,
// which is initialized like this:
//
// var ErrEOF = errors.New("End of file error")
//
// ...and your user wants to compare an error returned by your package
// with ErrEOF:
//
// err := urpack.Read()
// if err == urpack.ErrEOF {
//
// ...the comparison will fail if the error has been wrapped by merry
// at some point. Replace the comparison with:
//
// if merry.Is(err, urpack.ErrEOF) {
//
func Is(e error, originals ...error) bool {
is := func(e, original error) bool {
for {
if e == original {
return true
}
if e == nil || original == nil {
return false
}
w, ok := e.(*merryErr)
if !ok {
return false
}
e = w.err
}
}
for _, o := range originals {
if is(e, o) {
return true
}
}
return false
}
// Unwrap returns the innermost underlying error.
// Only useful in advanced cases, like if you need to
// cast the underlying error to some type to get
// additional information from it.
// If e == nil, return nil.
func Unwrap(e error) error {
if e == nil {
return nil
}
for {
w, ok := e.(*merryErr)
if !ok {
return e
}
e = w.err
}
}
func captureStack(skip int) []uintptr {
if !captureStacks {
return nil
}
stack := make([]uintptr, MaxStackDepth)
length := runtime.Callers(2+skip, stack[:])
return stack[:length]
}
type errorProperty string
const (
stack errorProperty = "stack"
message = "message"
httpCode = "http status code"
userMessage = "user message"
)
type merryErr struct {
err error
key, value interface{}
}
// Format implements fmt.Formatter
func (e *merryErr) Format(s fmt.State, verb rune) {
switch verb {
case 'v':
if s.Flag('+') {
io.WriteString(s, Details(e))
return
}
fallthrough
case 's':
io.WriteString(s, e.Error())
case 'q':
fmt.Fprintf(s, "%q", e.Error())
}
}
// make sure merryErr implements Error
var _ Error = (*merryErr)(nil)
// Error implements golang's error interface
// returns the message value if set, otherwise
// delegates to inner error
func (e *merryErr) Error() string {
if verbose {
return Details(e)
}
m := Message(e)
if m == "" {
return UserMessage(e)
}
return m
}
// return a new error with additional context
func (e *merryErr) WithValue(key, value interface{}) Error {
if e == nil {
return nil
}
return &merryErr{
err: e,
key: key,
value: value,
}
}
// Shorthand for capturing a new stack trace
func (e *merryErr) Here() Error {
if e == nil {
return nil
}
return e.WithStackSkipping(1)
}
// return a new error with a new stack capture
func (e *merryErr) WithStackSkipping(skip int) Error {
if e == nil {
return nil
}
return &merryErr{
err: e,
key: stack,
value: captureStack(skip + 1),
}
}
// return a new error with an http status code attached
func (e *merryErr) WithHTTPCode(code int) Error {
if e == nil {
return nil
}
return e.WithValue(httpCode, code)
}
// return a new error with a new message
func (e *merryErr) WithMessage(msg string) Error {
if e == nil {
return nil
}
return e.WithValue(message, msg)
}
// return a new error with a new formatted message
func (e *merryErr) WithMessagef(format string, a ...interface{}) Error {
if e == nil {
return nil
}
return e.WithMessage(fmt.Sprintf(format, a...))
}
// Add a message which is suitable for end users to see
func (e *merryErr) WithUserMessage(msg string) Error {
if e == nil {
return nil
}
return e.WithValue(userMessage, msg)
}
// Add a message which is suitable for end users to see
func (e *merryErr) WithUserMessagef(format string, args ...interface{}) Error {
if e == nil {
return nil
}
return e.WithUserMessage(fmt.Sprintf(format, args...))
}
// Append a message after the current error message, in the format "original: new"
func (e *merryErr) Append(msg string) Error {
if e == nil {
return nil
}
return e.WithMessagef("%s: %s", e.Error(), msg)
}
// Append a message after the current error message, in the format "original: new"
func (e *merryErr) Appendf(format string, args ...interface{}) Error {
if e == nil {
return nil
}
return e.Append(fmt.Sprintf(format, args...))
}
// Prepend a message before the current error message, in the format "new: original"
func (e *merryErr) Prepend(msg string) Error {
if e == nil {
return nil
}
return e.WithMessagef("%s: %s", msg, e.Error())
}
// Prepend a message before the current error message, in the format "new: original"
func (e *merryErr) Prependf(format string, args ...interface{}) Error {
if e == nil {
return nil
}
return e.Prepend(fmt.Sprintf(format, args...))
}

556
vendor/github.com/ansel1/merry/errors_test.go generated vendored Normal file
View File

@@ -0,0 +1,556 @@
package merry
import (
"errors"
"fmt"
"reflect"
"runtime"
"strconv"
"strings"
"testing"
"github.com/stretchr/testify/assert"
)
func TestNew(t *testing.T) {
_, _, rl, _ := runtime.Caller(0)
err := New("bang")
if HTTPCode(err) != 500 {
t.Errorf("http code should have been 500, was %v", HTTPCode(err))
}
if err.Error() != "bang" {
t.Errorf("error message should have been bang, was %v", err.Error())
}
f, l := Location(err)
if !strings.Contains(f, "errors_test.go") {
t.Errorf("error message should have contained errors_test.go, was %s", f)
}
if l != rl+1 {
t.Errorf("error line should have been %d, was %d", rl+1, 8)
}
}
func TestErrorf(t *testing.T) {
_, _, rl, _ := runtime.Caller(0)
err := Errorf("chitty chitty %v %v", "bang", "bang")
if HTTPCode(err) != 500 {
t.Errorf("http code should have been 500, was %v", HTTPCode(err))
}
if err.Error() != "chitty chitty bang bang" {
t.Errorf("error message should have been chitty chitty bang bang, was %v", err.Error())
}
f, l := Location(err)
if !strings.Contains(f, "errors_test.go") {
t.Errorf("error message should have contained errors_test.go, was %s", f)
}
if l != rl+1 {
t.Errorf("error line should have been %d, was %d", rl+1, 8)
}
}
func TestUserError(t *testing.T) {
_, _, rl, _ := runtime.Caller(0)
err := UserError("bang")
assert.Equal(t, "bang", UserMessage(err))
assert.Empty(t, Message(err))
_, l := Location(err)
assert.Equal(t, rl+1, l)
}
func TestUserErrorf(t *testing.T) {
_, _, rl, _ := runtime.Caller(0)
err := UserErrorf("bang %v", "bang")
assert.Equal(t, "bang bang", UserMessage(err))
assert.Empty(t, Message(err))
_, l := Location(err)
assert.Equal(t, rl+1, l)
}
func TestDetails(t *testing.T) {
var err error = New("bang")
deets := Details(err)
t.Log(deets)
lines := strings.Split(deets, "\n")
if lines[0] != "bang" {
t.Errorf("first line should have been bang: %v", lines[0])
}
if !strings.Contains(deets, Stacktrace(err)) {
t.Error("should have contained the error stacktrace")
}
err = WithUserMessage(err, "stay calm")
deets = Details(err)
t.Log(deets)
assert.Contains(t, deets, "User Message: stay calm")
// Allow nil error
assert.Empty(t, Details(nil))
}
func TestStacktrace(t *testing.T) {
_, _, rl, _ := runtime.Caller(0)
var err error = New("bang")
assert.NotEmpty(t, Stack(err))
s := Stacktrace(err)
t.Log(s)
lines := strings.Split(s, "\n")
assert.NotEmpty(t, lines)
assert.Equal(t, "github.com/ansel1/merry.TestStacktrace", lines[0])
assert.Contains(t, lines[1], fmt.Sprintf("errors_test.go:%d", rl+1))
// Allow nil error
assert.Empty(t, Stacktrace(nil))
}
func TestWrap(t *testing.T) {
err := errors.New("simple")
_, _, rl, _ := runtime.Caller(0)
wrapped := WrapSkipping(err, 0)
f, l := Location(wrapped)
if !strings.Contains(f, "errors_test.go") {
t.Errorf("error message should have contained errors_test.go, was %s", f)
}
if l != rl+1 {
t.Errorf("error line should have been %d, was %d", rl+1, l)
}
rich2 := WrapSkipping(wrapped, 0)
if wrapped != rich2 {
t.Error("rich and rich2 are not the same. Wrap should have been no-op if rich was already a RichError")
}
if !reflect.DeepEqual(Stack(wrapped), Stack(rich2)) {
t.Log(Details(rich2))
t.Error("wrap should have left the stacktrace alone if the original error already had a stack")
}
// wrapping nil -> nil
assert.Nil(t, Wrap(nil))
assert.Nil(t, WrapSkipping(nil, 1))
}
func TestHere(t *testing.T) {
ParseError := New("Parse error")
InvalidCharSet := WithMessage(ParseError, "Invalid charset").WithHTTPCode(400)
InvalidSyntax := ParseError.WithMessage("Syntax error")
if !Is(InvalidCharSet, ParseError) {
t.Error("InvalidCharSet should be a ParseError")
}
_, _, rl, _ := runtime.Caller(0)
pe := Here(ParseError)
_, l := Location(pe)
if l != rl+1 {
t.Errorf("Extend should capture a new stack. Expected %d, got %d", rl+1, l)
}
if !Is(pe, ParseError) {
t.Error("pe should be a ParseError")
}
if Is(pe, InvalidCharSet) {
t.Error("pe should not be an InvalidCharSet")
}
if pe.Error() != "Parse error" {
t.Errorf("child error's message is wrong, expected: Parse error, got %v", pe.Error())
}
icse := Here(InvalidCharSet)
if !Is(icse, ParseError) {
t.Error("icse should be a ParseError")
}
if !Is(icse, InvalidCharSet) {
t.Error("icse should be an InvalidCharSet")
}
if Is(icse, InvalidSyntax) {
t.Error("icse should not be an InvalidSyntax")
}
if icse.Error() != "Invalid charset" {
t.Errorf("child's message is wrong. Expected: Invalid charset, got: %v", icse.Error())
}
if HTTPCode(icse) != 400 {
t.Errorf("child's http code is wrong. Expected 400, got %v", HTTPCode(icse))
}
// nil -> nil
assert.Nil(t, Here(nil))
}
func TestUnwrap(t *testing.T) {
inner := errors.New("bing")
wrapper := WrapSkipping(inner, 0)
if Unwrap(wrapper) != inner {
t.Errorf("unwrapped error should have been the inner err, was %#v", inner)
}
doubleWrap := wrapper.WithMessage("blag")
if Unwrap(doubleWrap) != inner {
t.Errorf("unwrapped should recurse to inner, but got %#v", inner)
}
// nil -> nil
assert.Nil(t, Unwrap(nil))
}
func TestNilValues(t *testing.T) {
// Quirk of go
// http://devs.cloudimmunity.com/gotchas-and-common-mistakes-in-go-golang/index.html#nil_in_nil_in_vals
// an interface value isn't nil unless both the type *and* the value are nil
// make sure we aren't accidentally returning nil values but non-nil types
type e struct{}
var anE *e
type f interface{}
var anF f
if anF != nil {
t.Error("anF should have been nil here, because it doesn't have a concete type yet")
}
anF = anE
if anF == nil {
t.Error("anF should have been not nil here, because it now has a concrete type")
}
if WithMessage(WithHTTPCode(Wrap(nil), 400), "hey") != nil {
t.Error("by using interfaces in all the returns, this should have remained a true nil value")
}
}
func TestIs(t *testing.T) {
ParseError := errors.New("blag")
cp := Here(ParseError)
if !Is(cp, ParseError) {
t.Error("Is(child, parent) should be true")
}
if Is(ParseError, cp) {
t.Error("Is(parent, child) should not be true")
}
if !Is(ParseError, ParseError) {
t.Error("errors are always themselves")
}
if !Is(cp, cp) {
t.Error("should work when comparing rich error to itself")
}
if Is(Here(ParseError), cp) {
t.Error("Is(sibling, sibling) should not be true")
}
err2 := errors.New("blag")
if Is(ParseError, err2) {
t.Error("These should not have been equal")
}
if Is(Here(err2), cp) {
t.Error("these were not copies of the same error")
}
if Is(Here(err2), ParseError) {
t.Error("underlying errors were not equal")
}
nilTests := []struct {
arg1, arg2 error
expect bool
msg string
}{
{nil, New("t"), false, "nil is not any concrete error"},
{New("t"), nil, false, "no concrete error is nil"},
{nil, nil, true, "nil is nil"},
}
for _, tst := range nilTests {
assert.Equal(t, tst.expect, Is(tst.arg1, tst.arg2), tst.msg)
}
}
func TestHTTPCode(t *testing.T) {
basicErr := errors.New("blag")
if c := HTTPCode(basicErr); c != 500 {
t.Errorf("default code should be 500, was %d", c)
}
err := New("blug")
if c := HTTPCode(err); c != 500 {
t.Errorf("default code for rich errors should be 500, was %d", c)
}
errWCode := err.WithHTTPCode(404)
if c := HTTPCode(errWCode); c != 404 {
t.Errorf("the code should be set to 404, was %d", c)
}
if HTTPCode(err) != 500 {
t.Error("original error should not have been modified")
}
// nil -> nil
assert.Nil(t, WithHTTPCode(nil, 404))
assert.Equal(t, 200, HTTPCode(nil), "The code for nil is 200 (ok)")
}
func TestImplicitWrapping(t *testing.T) {
// WithXXX functions will implicitly wrap non-merry errors
// but if they do so, they should skip a frame, so the merry error's stack
// appears to start wherever the WithXXX function was called
_, _, rl, _ := runtime.Caller(0)
tests := []struct {
f func() error
fname string
}{
{fname: "WithHTTPCode", f: func() error { return WithHTTPCode(errors.New("bug"), 404) }},
{fname: "WithUserMessage", f: func() error { return WithUserMessage(errors.New("bug"), "asdf") }},
{fname: "WithUserMessages", f: func() error { return WithUserMessagef(errors.New("bug"), "asdf") }},
{fname: "WithMessage", f: func() error { return WithMessage(errors.New("bug"), "asdf") }},
{fname: "WithMessagef", f: func() error { return WithMessagef(errors.New("bug"), "asdf") }},
{fname: "WithValue", f: func() error { return WithValue(errors.New("bug"), "asdf", "asdf") }},
{fname: "Append", f: func() error { return Append(errors.New("bug"), "asdf") }},
{fname: "Appendf", f: func() error { return Appendf(errors.New("bug"), "asdf") }},
{fname: "Prepend", f: func() error { return Prepend(errors.New("bug"), "asdf") }},
{fname: "Prependf", f: func() error { return Prependf(errors.New("bug"), "asdf") }},
}
for i, test := range tests {
t.Log("Testing ", test.fname)
err := test.f()
f, l := Location(err)
assert.Contains(t, f, "errors_test.go", "error message should have contained errors_test.go")
assert.Equal(t, rl+5+i, l, "error line number was incorrect")
}
}
func TestWithMessage(t *testing.T) {
err1 := New("blug")
err2 := err1.WithMessage("blee")
err3 := err2.WithMessage("red")
assert.EqualError(t, err1, "blug")
assert.EqualError(t, err2, "blee", "should have overridden the underlying message")
assert.EqualError(t, err3, "red")
assert.Equal(t, Stack(err1), Stack(err2), "stack should not have been altered")
// nil -> nil
assert.Nil(t, WithMessage(nil, ""))
}
func TestWithMessagef(t *testing.T) {
err1 := New("blug")
err2 := err1.WithMessagef("super %v", "stew")
err3 := err1.WithMessagef("blue %v", "red")
assert.EqualError(t, err1, "blug")
assert.EqualError(t, err2, "super stew")
assert.EqualError(t, err3, "blue red")
assert.Equal(t, Stack(err1), Stack(err2), "stack should not have been altered")
// nil -> nil
assert.Nil(t, WithMessagef(nil, "", ""))
}
func TestMessage(t *testing.T) {
tests := []error{
errors.New("one"),
WithMessage(errors.New("blue"), "one"),
New("one"),
}
for _, test := range tests {
assert.Equal(t, "one", test.Error())
assert.Equal(t, "one", Message(test))
}
// when verbose is on, Error() changes, but Message() doesn't
defer SetVerboseDefault(false)
SetVerboseDefault(true)
e := New("two")
assert.Equal(t, "two", Message(e))
assert.NotEqual(t, "two", e.Error())
// when error is nil, return ""
assert.Empty(t, Message(nil))
}
func TestWithUserMessage(t *testing.T) {
fault := New("seg fault")
e := WithUserMessage(fault, "a glitch")
assert.Equal(t, "seg fault", e.Error())
assert.Equal(t, "a glitch", UserMessage(e))
e = WithUserMessagef(e, "not a %s deal", "huge")
assert.Equal(t, "not a huge deal", UserMessage(e))
// If user message is set and regular message isn't, set regular message to user message
e = New("").WithUserMessage("a blag")
assert.Equal(t, "a blag", UserMessage(e))
assert.Equal(t, "a blag", e.Error())
}
func TestAppend(t *testing.T) {
blug := New("blug")
err := blug.Append("blog")
assert.Equal(t, err.Error(), "blug: blog")
err = Append(err, "blig")
assert.Equal(t, err.Error(), "blug: blog: blig")
err = blug.Appendf("%s", "blog")
assert.Equal(t, err.Error(), "blug: blog")
err = Appendf(err, "%s", "blig")
assert.Equal(t, err.Error(), "blug: blog: blig")
// nil -> nil
assert.Nil(t, Append(nil, ""))
assert.Nil(t, Appendf(nil, "", ""))
}
func TestPrepend(t *testing.T) {
blug := New("blug")
err := blug.Prepend("blog")
assert.Equal(t, err.Error(), "blog: blug")
err = Prepend(err, "blig")
assert.Equal(t, err.Error(), "blig: blog: blug")
err = blug.Prependf("%s", "blog")
assert.Equal(t, err.Error(), "blog: blug")
err = Prependf(err, "%s", "blig")
assert.Equal(t, err.Error(), "blig: blog: blug")
// nil -> nil
assert.Nil(t, Prepend(nil, ""))
assert.Nil(t, Prependf(nil, "", ""))
}
func TestLocation(t *testing.T) {
// nil -> nil
f, l := Location(nil)
assert.Equal(t, "", f)
assert.Equal(t, 0, l)
}
func TestSourceLine(t *testing.T) {
source := SourceLine(nil)
assert.Equal(t, source, "")
err := New("foo")
source = SourceLine(err)
t.Log(source)
assert.NotEqual(t, source, "")
parts := strings.Split(source, ":")
assert.Equal(t, len(parts), 2)
if !strings.HasSuffix(parts[0], "errors_test.go") {
t.Error("source line should contain file name")
}
if i, e := strconv.Atoi(parts[1]); e != nil {
t.Errorf("not a number: %s", parts[1])
} else if i <= 0 {
t.Errorf("source line must be > 1: %s", parts[1])
}
}
func TestValue(t *testing.T) {
// nil -> nil
assert.Nil(t, WithValue(nil, "", ""))
assert.Nil(t, Value(nil, ""))
}
func TestValues(t *testing.T) {
// nil -> nil
values := Values(nil)
assert.Nil(t, values)
var e error
e = New("bad stuff")
e = WithValue(e, "key1", "val1")
e = WithValue(e, "key2", "val2")
values = Values(e)
assert.NotNil(t, values)
assert.Equal(t, values["key1"], "val1")
assert.Equal(t, values["key2"], "val2")
assert.NotNil(t, values[stack])
// make sure the last value attached is returned
e = WithValue(e, "key3", "val3")
e = WithValue(e, "key3", "val4")
values = Values(e)
assert.Equal(t, values["key3"], "val4")
}
func TestStackCaptureEnabled(t *testing.T) {
// on by default
assert.True(t, StackCaptureEnabled())
SetStackCaptureEnabled(false)
assert.False(t, StackCaptureEnabled())
e := New("yikes")
assert.Empty(t, Stack(e))
// let's just make sure none of the print functions bomb when there's no stack
assert.Empty(t, SourceLine(e))
f, l := Location(e)
assert.Empty(t, f)
assert.Equal(t, 0, l)
assert.Empty(t, Stacktrace(e))
assert.NotPanics(t, func() { Details(e) })
// turn it back on
SetStackCaptureEnabled(true)
assert.True(t, StackCaptureEnabled())
e = New("mommy")
assert.NotEmpty(t, Stack(e))
}
func TestVerboseDefault(t *testing.T) {
defer SetVerboseDefault(false)
// off by default
assert.False(t, VerboseDefault())
SetVerboseDefault(true)
assert.True(t, VerboseDefault())
e := New("yikes")
// test verbose on
assert.Equal(t, Details(e), e.Error())
// test verbose off
SetVerboseDefault(false)
s := e.Error()
assert.Equal(t, Message(e), s)
assert.Equal(t, "yikes", s)
}
func TestMerryErr_Error(t *testing.T) {
origVerbose := verbose
defer func() {
verbose = origVerbose
}()
// test with verbose on
verbose = false
tests := []struct {
desc string
verbose bool
message, userMessage string
expected string
}{
{
desc: "with message",
message: "blue",
expected: "blue",
},
{
desc: "with user message",
userMessage: "red",
expected: "red",
},
}
for _, test := range tests {
t.Log("error message tests: " + test.desc)
verbose = test.verbose
err := New(test.message).WithUserMessage(test.userMessage)
t.Log(err.Error())
assert.Equal(t, test.expected, err.Error())
}
}
func TestMerryErr_Format(t *testing.T) {
e := New("Hi")
assert.Equal(t, fmt.Sprintf("%v", e), e.Error())
assert.Equal(t, fmt.Sprintf("%s", e), e.Error())
assert.Equal(t, fmt.Sprintf("%q", e), fmt.Sprintf("%q", e.Error()))
assert.Equal(t, fmt.Sprintf("%+v", e), Details(e))
}
func BenchmarkNew_withStackCapture(b *testing.B) {
for i := 0; i < b.N; i++ {
New("boom")
}
}
func BenchmarkNew_withoutStackCapture(b *testing.B) {
SetStackCaptureEnabled(false)
for i := 0; i < b.N; i++ {
New("boom")
}
}

68
vendor/github.com/ansel1/merry/print.go generated vendored Normal file
View File

@@ -0,0 +1,68 @@
package merry
import (
"bytes"
"fmt"
"runtime"
)
// Location returns zero values if e has no stacktrace
func Location(e error) (file string, line int) {
s := Stack(e)
if len(s) > 0 {
fnc := runtime.FuncForPC(s[0])
if fnc != nil {
return fnc.FileLine(s[0])
}
}
return "", 0
}
// SourceLine returns the string representation of
// Location's result or an empty string if there's
// no stracktrace.
func SourceLine(e error) string {
file, line := Location(e)
if line != 0 {
return fmt.Sprintf("%s:%d", file, line)
}
return ""
}
// Stacktrace returns the error's stacktrace as a string formatted
// the same way as golangs runtime package.
// If e has no stacktrace, returns an empty string.
func Stacktrace(e error) string {
s := Stack(e)
if len(s) > 0 {
buf := bytes.Buffer{}
for _, fp := range s {
fnc := runtime.FuncForPC(fp)
if fnc != nil {
f, l := fnc.FileLine(fp)
buf.WriteString(fnc.Name())
buf.WriteString(fmt.Sprintf("\n\t%s:%d\n", f, l))
}
}
return buf.String()
}
return ""
}
// Details returns e.Error() and e's stacktrace and user message, if set.
func Details(e error) string {
if e == nil {
return ""
}
msg := Message(e)
userMsg := UserMessage(e)
if userMsg != "" {
msg = fmt.Sprintf("%s\n\nUser Message: %s", msg, userMsg)
}
s := Stacktrace(e)
if s != "" {
msg += "\n\n" + s
}
return msg
}