closes #54 will print stack trace if case of panic
Этот коммит содержится в:
родитель
dbda8afb77
коммит
bfb741f6c7
6 изменённых файлов: 139 добавлений и 6 удалений
|
@ -8,6 +8,7 @@ import (
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
txdb "github.com/DATA-DOG/go-txdb"
|
||||||
"github.com/DATA-DOG/godog"
|
"github.com/DATA-DOG/godog"
|
||||||
"github.com/DATA-DOG/godog/gherkin"
|
"github.com/DATA-DOG/godog/gherkin"
|
||||||
)
|
)
|
||||||
|
|
|
@ -308,7 +308,7 @@ func (f *pretty) printStepKind(res *stepResult) {
|
||||||
|
|
||||||
f.printStep(res.step, res.def, res.typ.clr())
|
f.printStep(res.step, res.def, res.typ.clr())
|
||||||
if res.err != nil {
|
if res.err != nil {
|
||||||
fmt.Fprintln(f.out, s(f.indent*2)+redb(res.err))
|
fmt.Fprintln(f.out, s(f.indent*2)+redb(fmt.Sprintf("%+v", res.err)))
|
||||||
}
|
}
|
||||||
if res.typ == pending {
|
if res.typ == pending {
|
||||||
fmt.Fprintln(f.out, s(f.indent*3)+yellow("TODO: write pending definition"))
|
fmt.Fprintln(f.out, s(f.indent*3)+yellow("TODO: write pending definition"))
|
||||||
|
|
|
@ -59,7 +59,7 @@ func (f *progress) Summary() {
|
||||||
fmt.Fprintln(f.out, "\n--- "+red("Failed steps:")+"\n")
|
fmt.Fprintln(f.out, "\n--- "+red("Failed steps:")+"\n")
|
||||||
for _, fail := range f.failed {
|
for _, fail := range f.failed {
|
||||||
fmt.Fprintln(f.out, s(4)+red(fail.step.Keyword+" "+fail.step.Text)+black(" # "+fail.line()))
|
fmt.Fprintln(f.out, s(4)+red(fail.step.Keyword+" "+fail.step.Text)+black(" # "+fail.line()))
|
||||||
fmt.Fprintln(f.out, s(6)+red("Error: ")+redb(fail.err)+"\n")
|
fmt.Fprintln(f.out, s(6)+red("Error: ")+redb(fmt.Sprintf("%+v", fail.err))+"\n")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
f.basefmt.Summary()
|
f.basefmt.Summary()
|
||||||
|
|
132
stacktrace.go
Обычный файл
132
stacktrace.go
Обычный файл
|
@ -0,0 +1,132 @@
|
||||||
|
package godog
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"path"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Frame represents a program counter inside a stack frame.
|
||||||
|
type stackFrame uintptr
|
||||||
|
|
||||||
|
// pc returns the program counter for this frame;
|
||||||
|
// multiple frames may have the same PC value.
|
||||||
|
func (f stackFrame) pc() uintptr { return uintptr(f) - 1 }
|
||||||
|
|
||||||
|
// file returns the full path to the file that contains the
|
||||||
|
// function for this Frame's pc.
|
||||||
|
func (f stackFrame) file() string {
|
||||||
|
fn := runtime.FuncForPC(f.pc())
|
||||||
|
if fn == nil {
|
||||||
|
return "unknown"
|
||||||
|
}
|
||||||
|
file, _ := fn.FileLine(f.pc())
|
||||||
|
return file
|
||||||
|
}
|
||||||
|
|
||||||
|
// line returns the line number of source code of the
|
||||||
|
// function for this Frame's pc.
|
||||||
|
func (f stackFrame) line() int {
|
||||||
|
fn := runtime.FuncForPC(f.pc())
|
||||||
|
if fn == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
_, line := fn.FileLine(f.pc())
|
||||||
|
return line
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format formats the frame according to the fmt.Formatter interface.
|
||||||
|
//
|
||||||
|
// %s source file
|
||||||
|
// %d source line
|
||||||
|
// %n function name
|
||||||
|
// %v equivalent to %s:%d
|
||||||
|
//
|
||||||
|
// Format accepts flags that alter the printing of some verbs, as follows:
|
||||||
|
//
|
||||||
|
// %+s path of source file relative to the compile time GOPATH
|
||||||
|
// %+v equivalent to %+s:%d
|
||||||
|
func (f stackFrame) Format(s fmt.State, verb rune) {
|
||||||
|
funcname := func(name string) string {
|
||||||
|
i := strings.LastIndex(name, "/")
|
||||||
|
name = name[i+1:]
|
||||||
|
i = strings.Index(name, ".")
|
||||||
|
return name[i+1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
switch verb {
|
||||||
|
case 's':
|
||||||
|
switch {
|
||||||
|
case s.Flag('+'):
|
||||||
|
pc := f.pc()
|
||||||
|
fn := runtime.FuncForPC(pc)
|
||||||
|
if fn == nil {
|
||||||
|
io.WriteString(s, "unknown")
|
||||||
|
} else {
|
||||||
|
file, _ := fn.FileLine(pc)
|
||||||
|
fmt.Fprintf(s, "%s\n\t%s", fn.Name(), file)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
io.WriteString(s, path.Base(f.file()))
|
||||||
|
}
|
||||||
|
case 'd':
|
||||||
|
fmt.Fprintf(s, "%d", f.line())
|
||||||
|
case 'n':
|
||||||
|
name := runtime.FuncForPC(f.pc()).Name()
|
||||||
|
io.WriteString(s, funcname(name))
|
||||||
|
case 'v':
|
||||||
|
f.Format(s, 's')
|
||||||
|
io.WriteString(s, ":")
|
||||||
|
f.Format(s, 'd')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// stack represents a stack of program counters.
|
||||||
|
type stack []uintptr
|
||||||
|
|
||||||
|
func (s *stack) Format(st fmt.State, verb rune) {
|
||||||
|
switch verb {
|
||||||
|
case 'v':
|
||||||
|
switch {
|
||||||
|
case st.Flag('+'):
|
||||||
|
for _, pc := range *s {
|
||||||
|
f := stackFrame(pc)
|
||||||
|
fmt.Fprintf(st, "\n%+v", f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func callStack() *stack {
|
||||||
|
const depth = 32
|
||||||
|
var pcs [depth]uintptr
|
||||||
|
n := runtime.Callers(3, pcs[:])
|
||||||
|
var st stack = pcs[0:n]
|
||||||
|
return &st
|
||||||
|
}
|
||||||
|
|
||||||
|
// fundamental is an error that has a message and a stack, but no caller.
|
||||||
|
type traceError struct {
|
||||||
|
msg string
|
||||||
|
*stack
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *traceError) Error() string { return f.msg }
|
||||||
|
|
||||||
|
func (f *traceError) Format(s fmt.State, verb rune) {
|
||||||
|
switch verb {
|
||||||
|
case 'v':
|
||||||
|
if s.Flag('+') {
|
||||||
|
io.WriteString(s, f.msg)
|
||||||
|
f.stack.Format(s, verb)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fallthrough
|
||||||
|
case 's':
|
||||||
|
io.WriteString(s, f.msg)
|
||||||
|
case 'q':
|
||||||
|
fmt.Fprintf(s, "%q", f.msg)
|
||||||
|
}
|
||||||
|
}
|
7
suite.go
7
suite.go
|
@ -220,10 +220,9 @@ func (s *Suite) runStep(step *gherkin.Step, prevStepErr error) (err error) {
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
if e := recover(); e != nil {
|
if e := recover(); e != nil {
|
||||||
var ok bool
|
err = &traceError{
|
||||||
err, ok = e.(error)
|
msg: fmt.Sprintf("%v", e),
|
||||||
if !ok {
|
stack: callStack(),
|
||||||
err = fmt.Errorf("%v", e)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
switch err {
|
switch err {
|
||||||
|
|
|
@ -287,6 +287,7 @@ func (s *suiteContext) iRunFeatureSuite() error {
|
||||||
s.testedSuite.fmt = testFormatterFunc("godog", &s.out)
|
s.testedSuite.fmt = testFormatterFunc("godog", &s.out)
|
||||||
s.testedSuite.run()
|
s.testedSuite.run()
|
||||||
s.testedSuite.fmt.Summary()
|
s.testedSuite.fmt.Summary()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче