Commit 66a27966 authored by Kirill Smelkov's avatar Kirill Smelkov

~gofmt

parent ad78da1b
......@@ -14,56 +14,56 @@
package exc
import (
"fmt"
"strings"
"fmt"
"strings"
"lab.nexedi.com/kirr/go123/myname"
"lab.nexedi.com/kirr/go123/xruntime"
"lab.nexedi.com/kirr/go123/myname"
"lab.nexedi.com/kirr/go123/xruntime"
)
// error type which is raised by Raise(arg)
type Error struct {
arg interface{}
link *Error // chain of linked Error(s) - see e.g. Context()
arg interface{}
link *Error // chain of linked Error(s) - see e.g. Context()
}
func (e *Error) Error() string {
msgv := []string{}
msg := ""
for e != nil {
// TODO(go1.7) -> runtime.Frame (see xruntime.Traceback())
if f, ok := e.arg.(xruntime.Frame); ok {
//msg = f.Function
//msg = fmt.Sprintf("%s (%s:%d)", f.Function, f.File, f.Line)
msg = strings.TrimPrefix(f.Name(), _errorpkgdot) // XXX -> better prettyfunc
} else {
msg = fmt.Sprint(e.arg)
}
msgv = append(msgv, msg)
e = e.link
}
return strings.Join(msgv, ": ")
msgv := []string{}
msg := ""
for e != nil {
// TODO(go1.7) -> runtime.Frame (see xruntime.Traceback())
if f, ok := e.arg.(xruntime.Frame); ok {
//msg = f.Function
//msg = fmt.Sprintf("%s (%s:%d)", f.Function, f.File, f.Line)
msg = strings.TrimPrefix(f.Name(), _errorpkgdot) // XXX -> better prettyfunc
} else {
msg = fmt.Sprint(e.arg)
}
msgv = append(msgv, msg)
e = e.link
}
return strings.Join(msgv, ": ")
}
// turn any value into Error
// if v is already Error - it stays the same
// otherwise new Error is created
func Aserror(v interface{}) *Error {
if e, ok := v.(*Error); ok {
return e
}
return &Error{v, nil}
if e, ok := v.(*Error); ok {
return e
}
return &Error{v, nil}
}
// raise error to upper level
func Raise(arg interface{}) {
panic(Aserror(arg))
panic(Aserror(arg))
}
// raise formatted string
func Raisef(format string, a ...interface{}) {
panic(Aserror(fmt.Sprintf(format, a...)))
panic(Aserror(fmt.Sprintf(format, a...)))
}
// raise if err != nil
......@@ -72,32 +72,32 @@ func Raisef(format string, a ...interface{}) {
// err = obj
// err != nil is true
func Raiseif(err error) {
//if err != nil && !reflect.ValueOf(err).IsNil() {
if err != nil {
panic(Aserror(err))
}
//if err != nil && !reflect.ValueOf(err).IsNil() {
if err != nil {
panic(Aserror(err))
}
}
// checks recovered value to be of *Error
// if there is non-Error error - repanic it
// otherwise return Error either nil (no panic), or actual value
func _errcatch(r interface{}) *Error {
e, _ := r.(*Error)
if e == nil && r != nil {
panic(r)
}
return e
e, _ := r.(*Error)
if e == nil && r != nil {
panic(r)
}
return e
}
// catch error and call f(e) if it was caught.
// must be called under defer
func Catch(f func(e *Error)) {
e := _errcatch(recover())
if e == nil {
return
}
e := _errcatch(recover())
if e == nil {
return
}
f(e)
f(e)
}
// be notified when error unwinding is being happening.
......@@ -105,15 +105,15 @@ func Catch(f func(e *Error)) {
// see also: Context()
// must be called under defer
func Onunwind(f func(e *Error) *Error) {
// cannot do Catch(...)
// as recover() works only in first-level called functions
e := _errcatch(recover())
if e == nil {
return
}
e = f(e)
panic(e)
// cannot do Catch(...)
// as recover() works only in first-level called functions
e := _errcatch(recover())
if e == nil {
return
}
e = f(e)
panic(e)
}
// provide error context to automatically add on unwinding.
......@@ -121,59 +121,59 @@ func Onunwind(f func(e *Error) *Error) {
// call result is added to raised error as "prefix" context
// must be called under defer
func Context(f func() interface{}) {
e := _errcatch(recover())
if e == nil {
return
}
e := _errcatch(recover())
if e == nil {
return
}
arg := f()
panic(Addcontext(e, arg))
arg := f()
panic(Addcontext(e, arg))
}
// add "prefix" context to error
func Addcontext(e *Error, arg interface{}) *Error {
return &Error{arg, e}
return &Error{arg, e}
}
var (
_errorpkgname string // package name under which error.go lives
_errorpkgdot string // errorpkg.
_errorraise string // errorpkg.Raise
_errorpkgname string // package name under which error.go lives
_errorpkgdot string // errorpkg.
_errorraise string // errorpkg.Raise
)
func init() {
_errorpkgname = myname.Pkg()
_errorpkgdot = _errorpkgname + "."
_errorraise = _errorpkgname + ".Raise"
_errorpkgname = myname.Pkg()
_errorpkgdot = _errorpkgname + "."
_errorraise = _errorpkgname + ".Raise"
}
// add calling context to error.
// Add calling function names as error context up-to topfunc not including.
// see also: Addcontext()
func Addcallingcontext(topfunc string, e *Error) *Error {
seenraise := false
for _, f := range xruntime.Traceback(2) {
// do not show anything after raise*()
if !seenraise && strings.HasPrefix(f.Name(), _errorraise) {
seenraise = true
continue
}
if !seenraise {
continue
}
// do not go beyond topfunc
if topfunc != "" && f.Name() == topfunc {
break
}
// skip intermediates
if strings.HasSuffix(f.Name(), "_") { // XXX -> better skipfunc
continue
}
e = &Error{f, e}
}
return e
seenraise := false
for _, f := range xruntime.Traceback(2) {
// do not show anything after raise*()
if !seenraise && strings.HasPrefix(f.Name(), _errorraise) {
seenraise = true
continue
}
if !seenraise {
continue
}
// do not go beyond topfunc
if topfunc != "" && f.Name() == topfunc {
break
}
// skip intermediates
if strings.HasSuffix(f.Name(), "_") { // XXX -> better skipfunc
continue
}
e = &Error{f, e}
}
return e
}
......@@ -13,129 +13,128 @@
package exc
import (
"errors"
"testing"
"errors"
"testing"
"lab.nexedi.com/kirr/go123/myname"
"lab.nexedi.com/kirr/go123/myname"
)
func do_raise1() {
Raise(1)
Raise(1)
}
func TestErrRaiseCatch(t *testing.T) {
defer Catch(func(e *Error) {
if !(e.arg == 1 && e.link == nil) {
t.Fatalf("error caught but unexpected: %#v ; want {1, nil}", e)
}
})
do_raise1()
t.Fatal("error not caught")
defer Catch(func(e *Error) {
if !(e.arg == 1 && e.link == nil) {
t.Fatalf("error caught but unexpected: %#v ; want {1, nil}", e)
}
})
do_raise1()
t.Fatal("error not caught")
}
// verify err chain has .arg(s) as expected
func verifyErrChain(t *testing.T, e *Error, argv ...interface{}) {
i := 0
for ; e != nil; i, e = i+1, e.link {
if i >= len(argv) {
t.Fatal("too long error chain")
}
if e.arg != argv[i] {
t.Fatalf("error caught but unexpected %vth arg: %v ; want %v", i, e.arg, argv[i])
}
}
if i < len(argv) {
t.Fatal("too small error chain")
}
i := 0
for ; e != nil; i, e = i+1, e.link {
if i >= len(argv) {
t.Fatal("too long error chain")
}
if e.arg != argv[i] {
t.Fatalf("error caught but unexpected %vth arg: %v ; want %v", i, e.arg, argv[i])
}
}
if i < len(argv) {
t.Fatal("too small error chain")
}
}
func do_onunwind1(t *testing.T) {
defer Onunwind(func(e *Error) *Error {
t.Fatal("on unwind called without raise")
return nil
})
defer Onunwind(func(e *Error) *Error {
t.Fatal("on unwind called without raise")
return nil
})
}
func do_onunwind2() {
defer Onunwind(func(e *Error) *Error {
return &Error{2, e}
})
do_raise1()
defer Onunwind(func(e *Error) *Error {
return &Error{2, e}
})
do_raise1()
}
func TestErrOnUnwind(t *testing.T) {
defer Catch(func(e *Error) {
verifyErrChain(t, e, 2, 1)
})
do_onunwind1(t)
do_onunwind2()
t.Fatal("error not caught")
defer Catch(func(e *Error) {
verifyErrChain(t, e, 2, 1)
})
do_onunwind1(t)
do_onunwind2()
t.Fatal("error not caught")
}
func do_context1(t *testing.T) {
defer Context(func() interface{} {
t.Fatal("on context called without raise")
return nil
})
defer Context(func() interface{} {
t.Fatal("on context called without raise")
return nil
})
}
func do_context2() {
defer Context(func() interface{} {
return 3
})
do_raise1()
defer Context(func() interface{} {
return 3
})
do_raise1()
}
func TestErrContext(t *testing.T) {
defer Catch(func(e *Error) {
verifyErrChain(t, e, 3, 1)
})
do_context1(t)
do_context2()
t.Fatal("error not caught")
defer Catch(func(e *Error) {
verifyErrChain(t, e, 3, 1)
})
do_context1(t)
do_context2()
t.Fatal("error not caught")
}
func do_raise11() {
do_raise1()
do_raise1()
}
func do_raise3if() {
Raiseif(errors.New("3"))
Raiseif(errors.New("3"))
}
func do_raise3if1() {
do_raise3if()
do_raise3if()
}
func do_raise4f() {
Raisef("%d", 4)
Raisef("%d", 4)
}
func do_raise4f1() {
do_raise4f()
do_raise4f()
}
func TestErrAddCallingContext(t *testing.T) {
var tests = []struct{ f func(); wanterrcontext string } {
{do_raise11, "do_raise11: do_raise1: 1"},
{do_raise3if1, "do_raise3if1: do_raise3if: 3"},
{do_raise4f1, "do_raise4f1: do_raise4f: 4"},
}
for _, tt := range tests {
func() {
myfunc := myname.Func()
defer Catch(func(e *Error) {
e = Addcallingcontext(myfunc, e)
msg := e.Error()
if msg != tt.wanterrcontext {
t.Fatalf("err + calling context: %q ; want %q", msg, tt.wanterrcontext)
}
})
tt.f()
t.Fatal("error not caught")
}()
}
var tests = []struct { f func(); wanterrcontext string } {
{do_raise11, "do_raise11: do_raise1: 1"},
{do_raise3if1, "do_raise3if1: do_raise3if: 3"},
{do_raise4f1, "do_raise4f1: do_raise4f: 4"},
}
for _, tt := range tests {
func() {
myfunc := myname.Func()
defer Catch(func(e *Error) {
e = Addcallingcontext(myfunc, e)
msg := e.Error()
if msg != tt.wanterrcontext {
t.Fatalf("err + calling context: %q ; want %q", msg, tt.wanterrcontext)
}
})
tt.f()
t.Fatal("error not caught")
}()
}
}
......@@ -14,25 +14,25 @@
package mem
import (
"reflect"
"unsafe"
"reflect"
"unsafe"
)
// string -> []byte without copying
func Bytes(s string) []byte {
var b []byte
bp := (*reflect.SliceHeader)(unsafe.Pointer(&b))
bp.Data = (*reflect.StringHeader)(unsafe.Pointer(&s)).Data
bp.Cap = len(s)
bp.Len = len(s)
return b
var b []byte
bp := (*reflect.SliceHeader)(unsafe.Pointer(&b))
bp.Data = (*reflect.StringHeader)(unsafe.Pointer(&s)).Data
bp.Cap = len(s)
bp.Len = len(s)
return b
}
// []byte -> string without copying
func String(b []byte) string {
var s string
sp := (*reflect.StringHeader)(unsafe.Pointer(&s))
sp.Data = (*reflect.SliceHeader)(unsafe.Pointer(&b)).Data
sp.Len = len(b)
return s
var s string
sp := (*reflect.StringHeader)(unsafe.Pointer(&s))
sp.Data = (*reflect.SliceHeader)(unsafe.Pointer(&b)).Data
sp.Len = len(b)
return s
}
......@@ -13,21 +13,21 @@
package mem
import (
"reflect"
"testing"
"reflect"
"testing"
)
// check that String() and Bytes() create correct objects which alias original object memory
func TestStringBytes(t *testing.T) {
s := "Hello"
b := []byte(s)
s := "Hello"
b := []byte(s)
s1 := String(b)
b1 := Bytes(s1)
if s1 != s { t.Error("string -> []byte -> String != Identity") }
if !reflect.DeepEqual(b1, b) { t.Error("[]byte -> String -> Bytes != Identity") }
b[0] = 'I'
if s != "Hello" { t.Error("string -> []byte not copied") }
if s1 != "Iello" { t.Error("[]byte -> String not aliased") }
if !reflect.DeepEqual(b1, b) { t.Error("string -> Bytes not aliased") }
s1 := String(b)
b1 := Bytes(s1)
if s1 != s { t.Error("string -> []byte -> String != Identity") }
if !reflect.DeepEqual(b1, b) { t.Error("[]byte -> String -> Bytes != Identity") }
b[0] = 'I'
if s != "Hello" { t.Error("string -> []byte not copied") }
if s1 != "Iello" { t.Error("[]byte -> String not aliased") }
if !reflect.DeepEqual(b1, b) { t.Error("string -> Bytes not aliased") }
}
......@@ -14,44 +14,44 @@
package myname
import (
"fmt"
"runtime"
"strings"
"fmt"
"runtime"
"strings"
)
func _myfuncname(nskip int) string {
pcv := [1]uintptr{}
runtime.Callers(nskip, pcv[:])
f := runtime.FuncForPC(pcv[0])
if f == nil {
return ""
}
return f.Name()
pcv := [1]uintptr{}
runtime.Callers(nskip, pcv[:])
f := runtime.FuncForPC(pcv[0])
if f == nil {
return ""
}
return f.Name()
}
// get name of currently running function (caller of Func())
// name is fully qualified package/name.function(.x)
func Func() string {
return _myfuncname(3)
return _myfuncname(3)
}
// get name of currently running function's package
// package is fully qualified package/name
func Pkg() string {
myfunc := _myfuncname(3)
if myfunc == "" {
return ""
}
// NOTE dots in package name are after last slash are escaped by go as %2e
// this way the first '.' after last '/' is delimiter between package and function
//
// lab.nexedi.com/kirr/git-backup/package%2ename.Function
// lab.nexedi.com/kirr/git-backup/pkg2.qqq/name%2ezzz.Function
islash := strings.LastIndexByte(myfunc, '/')
iafterslash := islash + 1 // NOTE if '/' not found iafterslash = 0
idot := strings.IndexByte(myfunc[iafterslash:], '.')
if idot == -1 {
panic(fmt.Errorf("funcname %q is not fully qualified", myfunc))
}
return myfunc[:iafterslash+idot]
myfunc := _myfuncname(3)
if myfunc == "" {
return ""
}
// NOTE dots in package name are after last slash are escaped by go as %2e
// this way the first '.' after last '/' is delimiter between package and function
//
// lab.nexedi.com/kirr/git-backup/package%2ename.Function
// lab.nexedi.com/kirr/git-backup/pkg2.qqq/name%2ezzz.Function
islash := strings.LastIndexByte(myfunc, '/')
iafterslash := islash + 1 // NOTE if '/' not found iafterslash = 0
idot := strings.IndexByte(myfunc[iafterslash:], '.')
if idot == -1 {
panic(fmt.Errorf("funcname %q is not fully qualified", myfunc))
}
return myfunc[:iafterslash+idot]
}
......@@ -13,16 +13,16 @@
package myname
import (
"strings"
"testing"
"strings"
"testing"
)
func TestMyFuncName(t *testing.T) {
myfunc := Func()
// go test changes full package name (putting filesystem of the tree into ti)
// thus we check only for suffix
wantsuffix := ".TestMyFuncName"
if !strings.HasSuffix(myfunc, wantsuffix) {
t.Errorf("myname.Func() -> %v ; want *%v", myfunc, wantsuffix)
}
myfunc := Func()
// go test changes full package name (putting filesystem of the tree into ti)
// thus we check only for suffix
wantsuffix := ".TestMyFuncName"
if !strings.HasSuffix(myfunc, wantsuffix) {
t.Errorf("myname.Func() -> %v ; want *%v", myfunc, wantsuffix)
}
}
......@@ -14,20 +14,20 @@
package xerr
import (
"fmt"
"fmt"
)
// error merging multiple errors (e.g. after collecting them from several parallel workers)
type Errorv []error
func (ev Errorv) Error() string {
if len(ev) == 1 {
return ev[0].Error()
}
if len(ev) == 1 {
return ev[0].Error()
}
msg := fmt.Sprintf("%d errors:\n", len(ev))
for _, e := range ev {
msg += fmt.Sprintf("\t- %s\n", e)
}
return msg
msg := fmt.Sprintf("%d errors:\n", len(ev))
for _, e := range ev {
msg += fmt.Sprintf("\t- %s\n", e)
}
return msg
}
......@@ -14,44 +14,44 @@
package xruntime
import (
"runtime"
"runtime"
)
// TODO(go1.7) goes away in favour of runtime.Frame
type Frame struct {
*runtime.Func
Pc uintptr
*runtime.Func
Pc uintptr
}
// get current calling traceback as []Frame
// nskip meaning: the same as in runtime.Callers()
// TODO(go1.7) []Frame -> []runtime.Frame
func Traceback(nskip int) []Frame {
// all callers
var pcv = []uintptr{0}
for {
pcv = make([]uintptr, 2*len(pcv))
n := runtime.Callers(nskip+1, pcv)
if n < len(pcv) {
pcv = pcv[:n]
break
}
}
// all callers
var pcv = []uintptr{0}
for {
pcv = make([]uintptr, 2*len(pcv))
n := runtime.Callers(nskip+1, pcv)
if n < len(pcv) {
pcv = pcv[:n]
break
}
}
// pcv -> frames
// pcv -> frames
/*
framev := make([]runtime.Frame, 0, len(pcv))
frames := runtime.CallersFrames(pcv)
for more := true; more; {
var frame runtime.Frame
frame, more = frames.Next()
framev = append(framev, frame)
}
framev := make([]runtime.Frame, 0, len(pcv))
frames := runtime.CallersFrames(pcv)
for more := true; more; {
var frame runtime.Frame
frame, more = frames.Next()
framev = append(framev, frame)
}
*/
framev := make([]Frame, 0, len(pcv))
for _, pc := range pcv {
framev = append(framev, Frame{runtime.FuncForPC(pc), pc})
}
framev := make([]Frame, 0, len(pcv))
for _, pc := range pcv {
framev = append(framev, Frame{runtime.FuncForPC(pc), pc})
}
return framev
return framev
}
......@@ -14,35 +14,35 @@
package xstrings
import (
"fmt"
"strings"
"fmt"
"strings"
)
// split string into lines. The last line, if it is empty, is omitted from the result
// (rationale is: string.Split("hello\nworld\n", "\n") -> ["hello", "world", ""])
func SplitLines(s, sep string) []string {
sv := strings.Split(s, sep)
l := len(sv)
if l > 0 && sv[l-1] == "" {
sv = sv[:l-1]
}
return sv
sv := strings.Split(s, sep)
l := len(sv)
if l > 0 && sv[l-1] == "" {
sv = sv[:l-1]
}
return sv
}
// split string by sep and expect exactly 2 parts
func Split2(s, sep string) (s1, s2 string, err error) {
parts := strings.Split(s, sep)
if len(parts) != 2 {
return "", "", fmt.Errorf("split2: %q has %v parts (expected 2, sep: %q)", s, len(parts), sep)
}
return parts[0], parts[1], nil
parts := strings.Split(s, sep)
if len(parts) != 2 {
return "", "", fmt.Errorf("split2: %q has %v parts (expected 2, sep: %q)", s, len(parts), sep)
}
return parts[0], parts[1], nil
}
// (head+sep+tail) -> head, tail
func HeadTail(s, sep string) (head, tail string, err error) {
parts := strings.SplitN(s, sep, 2)
if len(parts) != 2 {
return "", "", fmt.Errorf("headtail: %q has no %q", s, sep)
}
return parts[0], parts[1], nil
parts := strings.SplitN(s, sep, 2)
if len(parts) != 2 {
return "", "", fmt.Errorf("headtail: %q has no %q", s, sep)
}
return parts[0], parts[1], nil
}
......@@ -13,62 +13,62 @@
package xstrings
import (
"reflect"
"testing"
"reflect"
"testing"
)
func TestSplitLines(t *testing.T) {
var tests = []struct { input, sep string; output []string } {
{"", "\n", []string{}},
{"hello", "\n", []string{"hello"}},
{"hello\n", "\n", []string{"hello"}},
{"hello\nworld", "\n", []string{"hello", "world"}},
{"hello\nworld\n", "\n", []string{"hello", "world"}},
{"hello\x00world\x00", "\n", []string{"hello\x00world\x00"}},
{"hello\x00world\x00", "\x00", []string{"hello", "world"}},
}
var tests = []struct { input, sep string; output []string } {
{"", "\n", []string{}},
{"hello", "\n", []string{"hello"}},
{"hello\n", "\n", []string{"hello"}},
{"hello\nworld", "\n", []string{"hello", "world"}},
{"hello\nworld\n", "\n", []string{"hello", "world"}},
{"hello\x00world\x00", "\n", []string{"hello\x00world\x00"}},
{"hello\x00world\x00", "\x00", []string{"hello", "world"}},
}
for _, tt := range tests {
sv := SplitLines(tt.input, tt.sep)
if !reflect.DeepEqual(sv, tt.output) {
t.Errorf("splitlines(%q, %q) -> %q ; want %q", tt.input, tt.sep, sv, tt.output)
}
}
for _, tt := range tests {
sv := SplitLines(tt.input, tt.sep)
if !reflect.DeepEqual(sv, tt.output) {
t.Errorf("splitlines(%q, %q) -> %q ; want %q", tt.input, tt.sep, sv, tt.output)
}
}
}
func TestSplit2(t *testing.T) {
var tests = []struct { input, s1, s2 string; ok bool } {
{"", "", "", false},
{" ", "", "", true},
{"hello", "", "", false},
{"hello world", "hello", "world", true},
{"hello world 1", "", "", false},
}
var tests = []struct { input, s1, s2 string; ok bool } {
{"", "", "", false},
{" ", "", "", true},
{"hello", "", "", false},
{"hello world", "hello", "world", true},
{"hello world 1", "", "", false},
}
for _, tt := range tests {
s1, s2, err := Split2(tt.input, " ")
ok := err == nil
if s1 != tt.s1 || s2 != tt.s2 || ok != tt.ok {
t.Errorf("split2(%q) -> %q %q %v ; want %q %q %v", tt.input, s1, s2, ok, tt.s1, tt.s2, tt.ok)
}
}
for _, tt := range tests {
s1, s2, err := Split2(tt.input, " ")
ok := err == nil
if s1 != tt.s1 || s2 != tt.s2 || ok != tt.ok {
t.Errorf("split2(%q) -> %q %q %v ; want %q %q %v", tt.input, s1, s2, ok, tt.s1, tt.s2, tt.ok)
}
}
}
func TestHeadtail(t *testing.T) {
var tests = []struct { input, head, tail string; ok bool } {
{"", "", "", false},
{" ", "", "", true},
{" ", "", " ", true},
{"hello world", "hello", "world", true},
{"hello world 1", "hello", "world 1", true},
{"hello world 2", "hello", " world 2", true},
}
var tests = []struct { input, head, tail string; ok bool } {
{"", "", "", false},
{" ", "", "", true},
{" ", "", " ", true},
{"hello world", "hello", "world", true},
{"hello world 1", "hello", "world 1", true},
{"hello world 2", "hello", " world 2", true},
}
for _, tt := range tests {
head, tail, err := HeadTail(tt.input, " ")
ok := err == nil
if head != tt.head || tail != tt.tail || ok != tt.ok {
t.Errorf("headtail(%q) -> %q %q %v ; want %q %q %v", tt.input, head, tail, ok, tt.head, tt.tail, tt.ok)
}
}
for _, tt := range tests {
head, tail, err := HeadTail(tt.input, " ")
ok := err == nil
if head != tt.head || tail != tt.tail || ok != tt.ok {
t.Errorf("headtail(%q) -> %q %q %v ; want %q %q %v", tt.input, head, tail, ok, tt.head, tt.tail, tt.ok)
}
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment