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

~gofmt

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