blob: cecc2eec14a6221a2da58151c05abe80a8dbf0e1 [file] [log] [blame]
// Copyright 2016 The Upspin Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build debug
package errors_test
import (
"fmt"
"regexp"
"strings"
"testing"
"upspin.io/errors"
"upspin.io/upspin"
"upspin.io/valid"
)
var errorLines = strings.Split(strings.TrimSpace(`
.*/upspin.io/errors/debug_test.go:\d+: upspin.io/errors_test.func1:
.*/upspin.io/errors/debug_test.go:\d+: ...T.func2:
.*/upspin.io/errors/debug_test.go:\d+: ...func3:
.*/upspin.io/errors/debug_test.go:\d+: ...func4:
.*/upspin.io/valid/valid.go:\d+: ...valid.UserName:
.*/upspin.io/user/user.go:\d+: ...user.Parse: op: user@home/path: invalid operation:
valid.UserName:
user.Parse: user bad-username: user name must contain one @ symbol
`), "\n")
var errorLineREs = make([]*regexp.Regexp, len(errorLines))
func init() {
for i, s := range errorLines {
errorLineREs[i] = regexp.MustCompile(fmt.Sprintf("^%s$", s))
}
}
// Test that the error stack includes all the function calls between where it
// was generated and where it was printed. It should not include the name
// of the function in which the Error method is called. It should coalesce
// the call stacks of nested errors into one single stack, and present that
// stack before the other error values.
func TestDebug(t *testing.T) {
got := printErr(t, func1())
lines := strings.Split(got, "\n")
for i, re := range errorLineREs {
if i >= len(lines) {
// Handled by line number check.
break
}
if !re.MatchString(lines[i]) {
t.Errorf("error does not match at line %v, got:\n\t%q\nwant:\n\t%q", i, lines[i], re)
}
}
// Check number of lines after checking the lines themselves,
// as the content check will likely be more illuminating.
if got, want := len(lines), len(errorLines); got != want {
t.Errorf("got %v lines of errors, want %v", got, want)
}
}
func printErr(t *testing.T, err error) string {
return err.Error()
}
func func1() error {
var t T
return t.func2()
}
type T struct{}
func (T) func2() error {
return errors.E(errors.Op("op"), upspin.PathName("user@home/path"), func3())
}
func func3() error {
return func4()
}
func func4() error {
return valid.UserName("bad-username")
}