From e3edae703a8a69978d08f90bd82052ea118e8a52 Mon Sep 17 00:00:00 2001 From: moznion Date: Mon, 21 Jan 2019 22:42:14 +0900 Subject: [PATCH 01/14] Support `caused at` on anonymous func generator --- generator/anonymous_func.go | 11 +++++++++-- generator/anonymous_func_test.go | 6 +++++- generator/frame_fetcher.go | 30 ++++++++++++++++++++++++++++++ internal/errmsg/errmsg.go | 2 +- internal/errmsg/errs_errmsg_gen.go | 6 +++--- 5 files changed, 48 insertions(+), 7 deletions(-) create mode 100644 generator/frame_fetcher.go diff --git a/generator/anonymous_func.go b/generator/anonymous_func.go index 0ddcb3d..fa5598c 100644 --- a/generator/anonymous_func.go +++ b/generator/anonymous_func.go @@ -1,6 +1,8 @@ package generator -import "github.com/moznion/gowrtr/internal/errmsg" +import ( + "github.com/moznion/gowrtr/internal/errmsg" +) // AnonymousFunc represents a code generator for anonymous func. type AnonymousFunc struct { @@ -8,6 +10,7 @@ type AnonymousFunc struct { anonymousFuncSignature *AnonymousFuncSignature statements []Statement funcInvocation *FuncInvocation + caller string } // NewAnonymousFunc returns a new `AnonymousFunc`. @@ -17,6 +20,7 @@ func NewAnonymousFunc(goFunc bool, signature *AnonymousFuncSignature, statements goFunc: goFunc, anonymousFuncSignature: signature, statements: statements, + caller: fetchClientCallerLine(), } } @@ -28,6 +32,7 @@ func (ifg *AnonymousFunc) AddStatements(statements ...Statement) *AnonymousFunc anonymousFuncSignature: ifg.anonymousFuncSignature, statements: append(ifg.statements, statements...), funcInvocation: ifg.funcInvocation, + caller: ifg.caller, } } @@ -39,6 +44,7 @@ func (ifg *AnonymousFunc) Statements(statements ...Statement) *AnonymousFunc { anonymousFuncSignature: ifg.anonymousFuncSignature, statements: statements, funcInvocation: ifg.funcInvocation, + caller: ifg.caller, } } @@ -50,6 +56,7 @@ func (ifg *AnonymousFunc) Invocation(funcInvocation *FuncInvocation) *AnonymousF anonymousFuncSignature: ifg.anonymousFuncSignature, statements: ifg.statements, funcInvocation: funcInvocation, + caller: ifg.caller, } } @@ -64,7 +71,7 @@ func (ifg *AnonymousFunc) Generate(indentLevel int) (string, error) { stmt += "func" if ifg.anonymousFuncSignature == nil { - return "", errmsg.AnonymousFuncSignatureIsNilError() + return "", errmsg.AnonymousFuncSignatureIsNilError(ifg.caller) } sig, err := ifg.anonymousFuncSignature.Generate(0) diff --git a/generator/anonymous_func_test.go b/generator/anonymous_func_test.go index 3887596..54ec946 100644 --- a/generator/anonymous_func_test.go +++ b/generator/anonymous_func_test.go @@ -1,6 +1,8 @@ package generator import ( + "regexp" + "strings" "testing" "github.com/moznion/gowrtr/internal/errmsg" @@ -117,7 +119,9 @@ func TestShouldGenerateAnonymousFuncRaisesErrorWhenAnonymousFuncSignatureIsNil(t nil, ) _, err := generator.Generate(0) - assert.EqualError(t, err, errmsg.AnonymousFuncSignatureIsNilError().Error()) + assert.Regexp(t, regexp.MustCompile( + `^\`+strings.Split(errmsg.AnonymousFuncSignatureIsNilError("").Error(), " ")[0], + ), err.Error()) } func TestShouldGenerateAnonymousFuncRaisesErrorWhenAnonymousFuncSignatureRaisesError(t *testing.T) { diff --git a/generator/frame_fetcher.go b/generator/frame_fetcher.go new file mode 100644 index 0000000..9369186 --- /dev/null +++ b/generator/frame_fetcher.go @@ -0,0 +1,30 @@ +package generator + +import ( + "fmt" + "runtime" + "strings" +) + +func fetchClientCallerLine(skip ...int) string { + s := 2 + if len(skip) > 0 { + s = skip[0] + } + for { + pc, file, line, ok := runtime.Caller(s) + f := runtime.FuncForPC(pc) + if strings.Contains(f.Name(), "github.com/moznion/gowrtr") { + s++ + continue + } + + if !ok { + break + } + + return fmt.Sprintf("%s:%d", file, line) + } + + return "" +} diff --git a/internal/errmsg/errmsg.go b/internal/errmsg/errmsg.go index 696d314..3b14de9 100644 --- a/internal/errmsg/errmsg.go +++ b/internal/errmsg/errmsg.go @@ -12,7 +12,7 @@ type errs struct { FuncReceiverNameIsEmptyError error `errmsg:"name of func receiver must not be empty, but it gets empty"` FuncReceiverTypeIsEmptyError error `errmsg:"type of func receiver must not be empty, but it gets empty"` FuncSignatureIsNilError error `errmsg:"func signature must not be nil, bit it gets nil"` - AnonymousFuncSignatureIsNilError error `errmsg:"anonymous func signature must not be nil, bit it gets nil"` + AnonymousFuncSignatureIsNilError error `errmsg:"anonymous func signature must not be nil, bit it gets nil (caused at %s)" vars:"caller string"` FuncInvocationParameterIsEmptyError error `errmsg:"a parameter of function invocation must not be nil, but it gets nil"` CodeFormatterError error `errmsg:"code formatter raises error: command=\"%s\", err=\"%s\", msg=\"%s\"" vars:"cmd string, msg string, err error"` CaseConditionIsEmptyError error `errmsg:"condition of case must not be empty, but it gets empty"` diff --git a/internal/errmsg/errs_errmsg_gen.go b/internal/errmsg/errs_errmsg_gen.go index e7f4f1d..e9fba84 100644 --- a/internal/errmsg/errs_errmsg_gen.go +++ b/internal/errmsg/errs_errmsg_gen.go @@ -59,8 +59,8 @@ func FuncSignatureIsNilError() error { } // AnonymousFuncSignatureIsNilError returns the error. -func AnonymousFuncSignatureIsNilError() error { - return errors.New(`[GOWRTR-11] anonymous func signature must not be nil, bit it gets nil`) +func AnonymousFuncSignatureIsNilError(caller string) error { + return fmt.Errorf(`[GOWRTR-11] anonymous func signature must not be nil, bit it gets nil (caused at %s)`, caller) } // FuncInvocationParameterIsEmptyError returns the error. @@ -95,5 +95,5 @@ func ValueOfCompositeLiteralIsEmptyError() error { // ErrsList returns the list of errors. func ErrsList() []string { - return []string{"[GOWRTR-1] struct name must not be empty, but it gets empty", "[GOWRTR-2] field name must not be empty, but it gets empty", "[GOWRTR-3] field type must not be empty, but it gets empty", "[GOWRTR-4] func parameter name must not be empty, but it gets empty", "[GOWRTR-5] the last func parameter type must not be empty, but it gets empty", "[GOWRTR-6] name of func must not be empty, but it gets empty", "[GOWRTR-7] name of interface must not be empty, but it gets empty", "[GOWRTR-8] name of func receiver must not be empty, but it gets empty", "[GOWRTR-9] type of func receiver must not be empty, but it gets empty", "[GOWRTR-10] func signature must not be nil, bit it gets nil", "[GOWRTR-11] anonymous func signature must not be nil, bit it gets nil", "[GOWRTR-12] a parameter of function invocation must not be nil, but it gets nil", "[GOWRTR-13] code formatter raises error: command=\"%s\", err=\"%s\", msg=\"%s\"", "[GOWRTR-14] condition of case must not be empty, but it gets empty", "[GOWRTR-15] condition of if must not be empty, but it gets empty", "[GOWRTR-16] unnamed return type appears after named return type", "[GOWRTR-17] a value of composite literal must not be empty, but it gets empty"} + return []string{"[GOWRTR-1] struct name must not be empty, but it gets empty", "[GOWRTR-2] field name must not be empty, but it gets empty", "[GOWRTR-3] field type must not be empty, but it gets empty", "[GOWRTR-4] func parameter name must not be empty, but it gets empty", "[GOWRTR-5] the last func parameter type must not be empty, but it gets empty", "[GOWRTR-6] name of func must not be empty, but it gets empty", "[GOWRTR-7] name of interface must not be empty, but it gets empty", "[GOWRTR-8] name of func receiver must not be empty, but it gets empty", "[GOWRTR-9] type of func receiver must not be empty, but it gets empty", "[GOWRTR-10] func signature must not be nil, bit it gets nil", "[GOWRTR-11] anonymous func signature must not be nil, bit it gets nil (caused at %s)", "[GOWRTR-12] a parameter of function invocation must not be nil, but it gets nil", "[GOWRTR-13] code formatter raises error: command=\"%s\", err=\"%s\", msg=\"%s\"", "[GOWRTR-14] condition of case must not be empty, but it gets empty", "[GOWRTR-15] condition of if must not be empty, but it gets empty", "[GOWRTR-16] unnamed return type appears after named return type", "[GOWRTR-17] a value of composite literal must not be empty, but it gets empty"} } From 879df90b79e3b64268d04caec9e4f633b6e8f0dd Mon Sep 17 00:00:00 2001 From: moznion Date: Mon, 21 Jan 2019 23:14:59 +0900 Subject: [PATCH 02/14] Support `caused at` on func signature --- generator/anonymous_func_signature.go | 13 +++++++++++-- generator/anonymous_func_signature_test.go | 10 ++++++++-- generator/anonymous_func_test.go | 4 +++- generator/frame_fetcher.go | 14 ++++++++++++++ generator/func_signature.go | 13 +++++++++++-- generator/func_signature_test.go | 10 ++++++++-- internal/errmsg/errmsg.go | 4 ++-- internal/errmsg/errs_errmsg_gen.go | 10 +++++----- 8 files changed, 62 insertions(+), 16 deletions(-) diff --git a/generator/anonymous_func_signature.go b/generator/anonymous_func_signature.go index 3e8410d..331d0aa 100644 --- a/generator/anonymous_func_signature.go +++ b/generator/anonymous_func_signature.go @@ -10,6 +10,7 @@ import ( type AnonymousFuncSignature struct { funcParameters []*FuncParameter returnTypes []string + callers []string } // NewAnonymousFuncSignature returns a new `AnonymousFuncSignature`. @@ -23,6 +24,7 @@ func (f *AnonymousFuncSignature) AddParameters(funcParameters ...*FuncParameter) return &AnonymousFuncSignature{ funcParameters: append(f.funcParameters, funcParameters...), returnTypes: f.returnTypes, + callers: append(f.callers, fetchClientCallerLineAsSlice(len(funcParameters))...), } } @@ -32,6 +34,7 @@ func (f *AnonymousFuncSignature) Parameters(funcParameters ...*FuncParameter) *A return &AnonymousFuncSignature{ funcParameters: funcParameters, returnTypes: f.returnTypes, + callers: fetchClientCallerLineAsSlice(len(funcParameters)), } } @@ -41,6 +44,7 @@ func (f *AnonymousFuncSignature) AddReturnTypes(returnTypes ...string) *Anonymou return &AnonymousFuncSignature{ funcParameters: f.funcParameters, returnTypes: append(f.returnTypes, returnTypes...), + callers: f.callers, } } @@ -50,6 +54,7 @@ func (f *AnonymousFuncSignature) ReturnTypes(returnTypes ...string) *AnonymousFu return &AnonymousFuncSignature{ funcParameters: f.funcParameters, returnTypes: returnTypes, + callers: f.callers, } } @@ -58,10 +63,11 @@ func (f *AnonymousFuncSignature) Generate(indentLevel int) (string, error) { stmt := "(" typeExisted := true + typeMissingCaller := "" params := make([]string, len(f.funcParameters)) for i, param := range f.funcParameters { if param.name == "" { - return "", errmsg.FuncParameterNameIsEmptyErr() + return "", errmsg.FuncParameterNameIsEmptyErr(f.callers[i]) } paramSet := param.name @@ -69,11 +75,14 @@ func (f *AnonymousFuncSignature) Generate(indentLevel int) (string, error) { if typeExisted { paramSet += " " + param.typ } + if !typeExisted { + typeMissingCaller = f.callers[i] + } params[i] = paramSet } if !typeExisted { - return "", errmsg.LastFuncParameterTypeIsEmptyErr() + return "", errmsg.LastFuncParameterTypeIsEmptyErr(typeMissingCaller) } stmt += strings.Join(params, ", ") + ")" diff --git a/generator/anonymous_func_signature_test.go b/generator/anonymous_func_signature_test.go index 986e5b3..432f79d 100644 --- a/generator/anonymous_func_signature_test.go +++ b/generator/anonymous_func_signature_test.go @@ -1,6 +1,8 @@ package generator import ( + "regexp" + "strings" "testing" "github.com/moznion/gowrtr/internal/errmsg" @@ -41,7 +43,9 @@ func TestShouldGenerateAnonymousFuncSignatureRaisesErrorWhenParamNameIsEmpty(t * NewFuncParameter("", "string"), ) _, err := generator.Generate(0) - assert.EqualError(t, err, errmsg.FuncParameterNameIsEmptyErr().Error()) + assert.Regexp(t, regexp.MustCompile( + `^\`+strings.Split(errmsg.FuncParameterNameIsEmptyErr("").Error(), " ")[0], + ), err.Error()) } func TestShouldGenerateAnonymousFuncSignatureRaisesErrorWhenParamTypeIsEmpty(t *testing.T) { @@ -49,5 +53,7 @@ func TestShouldGenerateAnonymousFuncSignatureRaisesErrorWhenParamTypeIsEmpty(t * NewFuncParameter("foo", ""), ) _, err := generator.Generate(0) - assert.EqualError(t, err, errmsg.LastFuncParameterTypeIsEmptyErr().Error()) + assert.Regexp(t, regexp.MustCompile( + `^\`+strings.Split(errmsg.LastFuncParameterTypeIsEmptyErr("").Error(), " ")[0], + ), err.Error()) } diff --git a/generator/anonymous_func_test.go b/generator/anonymous_func_test.go index 54ec946..a1637cb 100644 --- a/generator/anonymous_func_test.go +++ b/generator/anonymous_func_test.go @@ -132,7 +132,9 @@ func TestShouldGenerateAnonymousFuncRaisesErrorWhenAnonymousFuncSignatureRaisesE ), ) _, err := generator.Generate(0) - assert.EqualError(t, err, errmsg.FuncParameterNameIsEmptyErr().Error()) + assert.Regexp(t, regexp.MustCompile( + `^\`+strings.Split(errmsg.FuncParameterNameIsEmptyErr("").Error(), " ")[0], + ), err.Error()) } func TestShouldGenerateAnonymousFuncRaisesErrorWhenStatementRaisesError(t *testing.T) { diff --git a/generator/frame_fetcher.go b/generator/frame_fetcher.go index 9369186..d7c48a8 100644 --- a/generator/frame_fetcher.go +++ b/generator/frame_fetcher.go @@ -28,3 +28,17 @@ func fetchClientCallerLine(skip ...int) string { return "" } + +func fetchClientCallerLineAsSlice(size int, skip ...int) []string { + s := 3 + if len(skip) > 0 { + s = skip[0] + } + + caller := fetchClientCallerLine(s) + callers := make([]string, size) + for i := 0; i < size; i++ { + callers[i] = caller + } + return callers +} diff --git a/generator/func_signature.go b/generator/func_signature.go index 642192f..c603479 100644 --- a/generator/func_signature.go +++ b/generator/func_signature.go @@ -37,6 +37,7 @@ type FuncSignature struct { funcName string funcParameters []*FuncParameter returnTypes []*FuncReturnType + callers []string } // NewFuncParameter returns a new `FuncSignature`. @@ -74,6 +75,7 @@ func (f *FuncSignature) AddParameters(funcParameters ...*FuncParameter) *FuncSig funcName: f.funcName, funcParameters: append(f.funcParameters, funcParameters...), returnTypes: f.returnTypes, + callers: append(f.callers, fetchClientCallerLineAsSlice(len(funcParameters))...), } } @@ -84,6 +86,7 @@ func (f *FuncSignature) Parameters(funcParameters ...*FuncParameter) *FuncSignat funcName: f.funcName, funcParameters: funcParameters, returnTypes: f.returnTypes, + callers: fetchClientCallerLineAsSlice(len(funcParameters)), } } @@ -108,6 +111,7 @@ func (f *FuncSignature) AddReturnTypeStructs(returnTypes ...*FuncReturnType) *Fu funcName: f.funcName, funcParameters: f.funcParameters, returnTypes: append(f.returnTypes, returnTypes...), + callers: f.callers, } } @@ -132,6 +136,7 @@ func (f *FuncSignature) ReturnTypeStructs(returnTypes ...*FuncReturnType) *FuncS funcName: f.funcName, funcParameters: f.funcParameters, returnTypes: returnTypes, + callers: f.callers, } } @@ -144,10 +149,11 @@ func (f *FuncSignature) Generate(indentLevel int) (string, error) { stmt := f.funcName + "(" typeExisted := true + typeMissingCaller := "" params := make([]string, len(f.funcParameters)) for i, param := range f.funcParameters { if param.name == "" { - return "", errmsg.FuncParameterNameIsEmptyErr() + return "", errmsg.FuncParameterNameIsEmptyErr(f.callers[i]) } paramSet := param.name @@ -155,11 +161,14 @@ func (f *FuncSignature) Generate(indentLevel int) (string, error) { if typeExisted { paramSet += " " + param.typ } + if !typeExisted { + typeMissingCaller = f.callers[i] + } params[i] = paramSet } if !typeExisted { - return "", errmsg.LastFuncParameterTypeIsEmptyErr() + return "", errmsg.LastFuncParameterTypeIsEmptyErr(typeMissingCaller) } stmt += strings.Join(params, ", ") + ")" diff --git a/generator/func_signature_test.go b/generator/func_signature_test.go index bfc1aa5..a97edcd 100644 --- a/generator/func_signature_test.go +++ b/generator/func_signature_test.go @@ -1,6 +1,8 @@ package generator import ( + "regexp" + "strings" "testing" "github.com/moznion/gowrtr/internal/errmsg" @@ -78,7 +80,9 @@ func TestShouldRaiseErrorWhenFuncParameterNameIsEmpty(t *testing.T) { ) _, err := sig.Generate(0) - assert.EqualError(t, err, errmsg.FuncParameterNameIsEmptyErr().Error()) + assert.Regexp(t, regexp.MustCompile( + `^\`+strings.Split(errmsg.FuncParameterNameIsEmptyErr("").Error(), " ")[0], + ), err.Error()) } func TestShouldRaiseErrorWhenLastFuncParameterTypeIsEmpty(t *testing.T) { @@ -89,7 +93,9 @@ func TestShouldRaiseErrorWhenLastFuncParameterTypeIsEmpty(t *testing.T) { ) _, err := sig.Generate(0) - assert.EqualError(t, err, errmsg.LastFuncParameterTypeIsEmptyErr().Error()) + assert.Regexp(t, regexp.MustCompile( + `^\`+strings.Split(errmsg.LastFuncParameterTypeIsEmptyErr("").Error(), " ")[0], + ), err.Error()) } func TestShouldGeneratingFuncSignatureWithNamedReturnValue(t *testing.T) { diff --git a/internal/errmsg/errmsg.go b/internal/errmsg/errmsg.go index 3b14de9..aa0c332 100644 --- a/internal/errmsg/errmsg.go +++ b/internal/errmsg/errmsg.go @@ -5,8 +5,8 @@ type errs struct { StructNameIsNilErr error `errmsg:"struct name must not be empty, but it gets empty"` StructFieldNameIsEmptyErr error `errmsg:"field name must not be empty, but it gets empty"` StructFieldTypeIsEmptyErr error `errmsg:"field type must not be empty, but it gets empty"` - FuncParameterNameIsEmptyErr error `errmsg:"func parameter name must not be empty, but it gets empty"` - LastFuncParameterTypeIsEmptyErr error `errmsg:"the last func parameter type must not be empty, but it gets empty"` + FuncParameterNameIsEmptyErr error `errmsg:"func parameter name must not be empty, but it gets empty (caused at %s)" vars:"caller string"` + LastFuncParameterTypeIsEmptyErr error `errmsg:"the last func parameter type must not be empty, but it gets empty (caused at %s)" vars:"caller string"` FuncNameIsEmptyError error `errmsg:"name of func must not be empty, but it gets empty"` InterfaceNameIsEmptyError error `errmsg:"name of interface must not be empty, but it gets empty"` FuncReceiverNameIsEmptyError error `errmsg:"name of func receiver must not be empty, but it gets empty"` diff --git a/internal/errmsg/errs_errmsg_gen.go b/internal/errmsg/errs_errmsg_gen.go index e9fba84..78f8f58 100644 --- a/internal/errmsg/errs_errmsg_gen.go +++ b/internal/errmsg/errs_errmsg_gen.go @@ -24,13 +24,13 @@ func StructFieldTypeIsEmptyErr() error { } // FuncParameterNameIsEmptyErr returns the error. -func FuncParameterNameIsEmptyErr() error { - return errors.New(`[GOWRTR-4] func parameter name must not be empty, but it gets empty`) +func FuncParameterNameIsEmptyErr(caller string) error { + return fmt.Errorf(`[GOWRTR-4] func parameter name must not be empty, but it gets empty (caused at %s)`, caller) } // LastFuncParameterTypeIsEmptyErr returns the error. -func LastFuncParameterTypeIsEmptyErr() error { - return errors.New(`[GOWRTR-5] the last func parameter type must not be empty, but it gets empty`) +func LastFuncParameterTypeIsEmptyErr(caller string) error { + return fmt.Errorf(`[GOWRTR-5] the last func parameter type must not be empty, but it gets empty (caused at %s)`, caller) } // FuncNameIsEmptyError returns the error. @@ -95,5 +95,5 @@ func ValueOfCompositeLiteralIsEmptyError() error { // ErrsList returns the list of errors. func ErrsList() []string { - return []string{"[GOWRTR-1] struct name must not be empty, but it gets empty", "[GOWRTR-2] field name must not be empty, but it gets empty", "[GOWRTR-3] field type must not be empty, but it gets empty", "[GOWRTR-4] func parameter name must not be empty, but it gets empty", "[GOWRTR-5] the last func parameter type must not be empty, but it gets empty", "[GOWRTR-6] name of func must not be empty, but it gets empty", "[GOWRTR-7] name of interface must not be empty, but it gets empty", "[GOWRTR-8] name of func receiver must not be empty, but it gets empty", "[GOWRTR-9] type of func receiver must not be empty, but it gets empty", "[GOWRTR-10] func signature must not be nil, bit it gets nil", "[GOWRTR-11] anonymous func signature must not be nil, bit it gets nil (caused at %s)", "[GOWRTR-12] a parameter of function invocation must not be nil, but it gets nil", "[GOWRTR-13] code formatter raises error: command=\"%s\", err=\"%s\", msg=\"%s\"", "[GOWRTR-14] condition of case must not be empty, but it gets empty", "[GOWRTR-15] condition of if must not be empty, but it gets empty", "[GOWRTR-16] unnamed return type appears after named return type", "[GOWRTR-17] a value of composite literal must not be empty, but it gets empty"} + return []string{"[GOWRTR-1] struct name must not be empty, but it gets empty", "[GOWRTR-2] field name must not be empty, but it gets empty", "[GOWRTR-3] field type must not be empty, but it gets empty", "[GOWRTR-4] func parameter name must not be empty, but it gets empty (caused at %s)", "[GOWRTR-5] the last func parameter type must not be empty, but it gets empty (caused at %s)", "[GOWRTR-6] name of func must not be empty, but it gets empty", "[GOWRTR-7] name of interface must not be empty, but it gets empty", "[GOWRTR-8] name of func receiver must not be empty, but it gets empty", "[GOWRTR-9] type of func receiver must not be empty, but it gets empty", "[GOWRTR-10] func signature must not be nil, bit it gets nil", "[GOWRTR-11] anonymous func signature must not be nil, bit it gets nil (caused at %s)", "[GOWRTR-12] a parameter of function invocation must not be nil, but it gets nil", "[GOWRTR-13] code formatter raises error: command=\"%s\", err=\"%s\", msg=\"%s\"", "[GOWRTR-14] condition of case must not be empty, but it gets empty", "[GOWRTR-15] condition of if must not be empty, but it gets empty", "[GOWRTR-16] unnamed return type appears after named return type", "[GOWRTR-17] a value of composite literal must not be empty, but it gets empty"} } From cd8afeb00e396e8e9eec436b4518310c1b73da24 Mon Sep 17 00:00:00 2001 From: moznion Date: Mon, 21 Jan 2019 23:20:31 +0900 Subject: [PATCH 03/14] Support `caused at` on case generator --- generator/case.go | 4 +++- generator/case_test.go | 6 +++++- generator/switch_test.go | 6 +++++- internal/errmsg/errmsg.go | 2 +- internal/errmsg/errs_errmsg_gen.go | 6 +++--- 5 files changed, 17 insertions(+), 7 deletions(-) diff --git a/generator/case.go b/generator/case.go index 863ac79..0ec43b3 100644 --- a/generator/case.go +++ b/generator/case.go @@ -11,6 +11,7 @@ import ( type Case struct { condition string statements []Statement + caller string } // NewCase creates a new `Case`. @@ -18,6 +19,7 @@ func NewCase(condition string, statements ...Statement) *Case { return &Case{ condition: condition, statements: statements, + caller: fetchClientCallerLine(), } } @@ -43,7 +45,7 @@ func (c *Case) Statements(statements ...Statement) *Case { func (c *Case) Generate(indentLevel int) (string, error) { condition := c.condition if condition == "" { - return "", errmsg.CaseConditionIsEmptyError() + return "", errmsg.CaseConditionIsEmptyError(c.caller) } indent := buildIndent(indentLevel) diff --git a/generator/case_test.go b/generator/case_test.go index abc036d..ee1170f 100644 --- a/generator/case_test.go +++ b/generator/case_test.go @@ -1,6 +1,8 @@ package generator import ( + "regexp" + "strings" "testing" "github.com/moznion/gowrtr/internal/errmsg" @@ -51,7 +53,9 @@ func TestShouldGenerateCase(t *testing.T) { func TestShouldGenerateCaseRaisesErrorWhenConditionIsEmpty(t *testing.T) { generator := NewCase("") _, err := generator.Generate(0) - assert.EqualError(t, err, errmsg.CaseConditionIsEmptyError().Error()) + assert.Regexp(t, regexp.MustCompile( + `^\`+strings.Split(errmsg.CaseConditionIsEmptyError("").Error(), " ")[0], + ), err.Error()) } func TestShouldGenerateCaseRaisesErrorWhenStatementsRaisesError(t *testing.T) { diff --git a/generator/switch_test.go b/generator/switch_test.go index 997a4fb..50ddb3f 100644 --- a/generator/switch_test.go +++ b/generator/switch_test.go @@ -1,6 +1,8 @@ package generator import ( + "regexp" + "strings" "testing" "github.com/moznion/gowrtr/internal/errmsg" @@ -77,7 +79,9 @@ func TestShouldGenerateSwitchRaisesErrorWhenCaseRaisesError(t *testing.T) { NewCase(""), ) _, err := generator.Generate(0) - assert.EqualError(t, err, errmsg.CaseConditionIsEmptyError().Error()) + assert.Regexp(t, regexp.MustCompile( + `^\`+strings.Split(errmsg.CaseConditionIsEmptyError("").Error(), " ")[0], + ), err.Error()) } func TestShouldGenerateSwitchRaisesErrorWhenDefaultRaisesError(t *testing.T) { diff --git a/internal/errmsg/errmsg.go b/internal/errmsg/errmsg.go index aa0c332..1aa3a1b 100644 --- a/internal/errmsg/errmsg.go +++ b/internal/errmsg/errmsg.go @@ -15,7 +15,7 @@ type errs struct { AnonymousFuncSignatureIsNilError error `errmsg:"anonymous func signature must not be nil, bit it gets nil (caused at %s)" vars:"caller string"` FuncInvocationParameterIsEmptyError error `errmsg:"a parameter of function invocation must not be nil, but it gets nil"` CodeFormatterError error `errmsg:"code formatter raises error: command=\"%s\", err=\"%s\", msg=\"%s\"" vars:"cmd string, msg string, err error"` - CaseConditionIsEmptyError error `errmsg:"condition of case must not be empty, but it gets empty"` + CaseConditionIsEmptyError error `errmsg:"condition of case must not be empty, but it gets empty (caused at %s)" vars:"caller string"` IfConditionIsEmptyError error `errmsg:"condition of if must not be empty, but it gets empty"` UnnamedReturnTypeAppearsAfterNamedReturnTypeError error `errmsg:"unnamed return type appears after named return type"` ValueOfCompositeLiteralIsEmptyError error `errmsg:"a value of composite literal must not be empty, but it gets empty"` diff --git a/internal/errmsg/errs_errmsg_gen.go b/internal/errmsg/errs_errmsg_gen.go index 78f8f58..8464f79 100644 --- a/internal/errmsg/errs_errmsg_gen.go +++ b/internal/errmsg/errs_errmsg_gen.go @@ -74,8 +74,8 @@ func CodeFormatterError(cmd string, msg string, err error) error { } // CaseConditionIsEmptyError returns the error. -func CaseConditionIsEmptyError() error { - return errors.New(`[GOWRTR-14] condition of case must not be empty, but it gets empty`) +func CaseConditionIsEmptyError(caller string) error { + return fmt.Errorf(`[GOWRTR-14] condition of case must not be empty, but it gets empty (caused at %s)`, caller) } // IfConditionIsEmptyError returns the error. @@ -95,5 +95,5 @@ func ValueOfCompositeLiteralIsEmptyError() error { // ErrsList returns the list of errors. func ErrsList() []string { - return []string{"[GOWRTR-1] struct name must not be empty, but it gets empty", "[GOWRTR-2] field name must not be empty, but it gets empty", "[GOWRTR-3] field type must not be empty, but it gets empty", "[GOWRTR-4] func parameter name must not be empty, but it gets empty (caused at %s)", "[GOWRTR-5] the last func parameter type must not be empty, but it gets empty (caused at %s)", "[GOWRTR-6] name of func must not be empty, but it gets empty", "[GOWRTR-7] name of interface must not be empty, but it gets empty", "[GOWRTR-8] name of func receiver must not be empty, but it gets empty", "[GOWRTR-9] type of func receiver must not be empty, but it gets empty", "[GOWRTR-10] func signature must not be nil, bit it gets nil", "[GOWRTR-11] anonymous func signature must not be nil, bit it gets nil (caused at %s)", "[GOWRTR-12] a parameter of function invocation must not be nil, but it gets nil", "[GOWRTR-13] code formatter raises error: command=\"%s\", err=\"%s\", msg=\"%s\"", "[GOWRTR-14] condition of case must not be empty, but it gets empty", "[GOWRTR-15] condition of if must not be empty, but it gets empty", "[GOWRTR-16] unnamed return type appears after named return type", "[GOWRTR-17] a value of composite literal must not be empty, but it gets empty"} + return []string{"[GOWRTR-1] struct name must not be empty, but it gets empty", "[GOWRTR-2] field name must not be empty, but it gets empty", "[GOWRTR-3] field type must not be empty, but it gets empty", "[GOWRTR-4] func parameter name must not be empty, but it gets empty (caused at %s)", "[GOWRTR-5] the last func parameter type must not be empty, but it gets empty (caused at %s)", "[GOWRTR-6] name of func must not be empty, but it gets empty", "[GOWRTR-7] name of interface must not be empty, but it gets empty", "[GOWRTR-8] name of func receiver must not be empty, but it gets empty", "[GOWRTR-9] type of func receiver must not be empty, but it gets empty", "[GOWRTR-10] func signature must not be nil, bit it gets nil", "[GOWRTR-11] anonymous func signature must not be nil, bit it gets nil (caused at %s)", "[GOWRTR-12] a parameter of function invocation must not be nil, but it gets nil", "[GOWRTR-13] code formatter raises error: command=\"%s\", err=\"%s\", msg=\"%s\"", "[GOWRTR-14] condition of case must not be empty, but it gets empty (caused at %s)", "[GOWRTR-15] condition of if must not be empty, but it gets empty", "[GOWRTR-16] unnamed return type appears after named return type", "[GOWRTR-17] a value of composite literal must not be empty, but it gets empty"} } From c7a9a41bb317d1628e9448cb249fac121aa5977f Mon Sep 17 00:00:00 2001 From: moznion Date: Mon, 21 Jan 2019 23:24:41 +0900 Subject: [PATCH 04/14] Support `created at` on func generator --- generator/func.go | 4 +++- generator/func_test.go | 6 +++++- generator/root_test.go | 5 ++++- internal/errmsg/errmsg.go | 2 +- internal/errmsg/errs_errmsg_gen.go | 6 +++--- 5 files changed, 16 insertions(+), 7 deletions(-) diff --git a/generator/func.go b/generator/func.go index 0d64d7c..86df076 100644 --- a/generator/func.go +++ b/generator/func.go @@ -9,6 +9,7 @@ type Func struct { funcReceiver *FuncReceiver funcSignature *FuncSignature statements []Statement + caller string } // NewFunc returns a new `Func`. @@ -17,6 +18,7 @@ func NewFunc(receiver *FuncReceiver, signature *FuncSignature, statements ...Sta funcReceiver: receiver, funcSignature: signature, statements: statements, + caller: fetchClientCallerLine(), } } @@ -59,7 +61,7 @@ func (fg *Func) Generate(indentLevel int) (string, error) { } if fg.funcSignature == nil { - return "", errmsg.FuncSignatureIsNilError() + return "", errmsg.FuncSignatureIsNilError(fg.caller) } sig, err := fg.funcSignature.Generate(0) if err != nil { diff --git a/generator/func_test.go b/generator/func_test.go index 61d1e82..647391c 100644 --- a/generator/func_test.go +++ b/generator/func_test.go @@ -1,6 +1,8 @@ package generator import ( + "regexp" + "strings" "testing" "github.com/moznion/gowrtr/internal/errmsg" @@ -80,7 +82,9 @@ func TestShouldGenerateFuncCodeGiveUpWhenFuncSignatureIsNil(t *testing.T) { ) _, err := generator.Generate(0) - assert.EqualError(t, err, errmsg.FuncSignatureIsNilError().Error()) + assert.Regexp(t, regexp.MustCompile( + `^\`+strings.Split(errmsg.FuncSignatureIsNilError("").Error(), " ")[0], + ), err.Error()) } func TestShouldGenerateFuncCodeGiveUpWhenFuncReceiverRaisesError(t *testing.T) { diff --git a/generator/root_test.go b/generator/root_test.go index 21f78c2..c550185 100644 --- a/generator/root_test.go +++ b/generator/root_test.go @@ -2,6 +2,7 @@ package generator import ( "regexp" + "strings" "testing" "github.com/moznion/gowrtr/internal/errmsg" @@ -478,7 +479,9 @@ func TestShouldGenerateCodeRaisesError(t *testing.T) { ) _, err := generator.Generate(0) - assert.EqualError(t, err, errmsg.FuncSignatureIsNilError().Error()) + assert.Regexp(t, regexp.MustCompile( + `^\`+strings.Split(errmsg.FuncSignatureIsNilError("").Error(), " ")[0], + ), err.Error()) } func TestShouldGenerateCodeRaiseErrorWhenCodeFormatterIsExited(t *testing.T) { diff --git a/internal/errmsg/errmsg.go b/internal/errmsg/errmsg.go index 1aa3a1b..5704957 100644 --- a/internal/errmsg/errmsg.go +++ b/internal/errmsg/errmsg.go @@ -11,7 +11,7 @@ type errs struct { InterfaceNameIsEmptyError error `errmsg:"name of interface must not be empty, but it gets empty"` FuncReceiverNameIsEmptyError error `errmsg:"name of func receiver must not be empty, but it gets empty"` FuncReceiverTypeIsEmptyError error `errmsg:"type of func receiver must not be empty, but it gets empty"` - FuncSignatureIsNilError error `errmsg:"func signature must not be nil, bit it gets nil"` + FuncSignatureIsNilError error `errmsg:"func signature must not be nil, bit it gets nil (caused at %s)" vars:"caller string"` AnonymousFuncSignatureIsNilError error `errmsg:"anonymous func signature must not be nil, bit it gets nil (caused at %s)" vars:"caller string"` FuncInvocationParameterIsEmptyError error `errmsg:"a parameter of function invocation must not be nil, but it gets nil"` CodeFormatterError error `errmsg:"code formatter raises error: command=\"%s\", err=\"%s\", msg=\"%s\"" vars:"cmd string, msg string, err error"` diff --git a/internal/errmsg/errs_errmsg_gen.go b/internal/errmsg/errs_errmsg_gen.go index 8464f79..6ac681a 100644 --- a/internal/errmsg/errs_errmsg_gen.go +++ b/internal/errmsg/errs_errmsg_gen.go @@ -54,8 +54,8 @@ func FuncReceiverTypeIsEmptyError() error { } // FuncSignatureIsNilError returns the error. -func FuncSignatureIsNilError() error { - return errors.New(`[GOWRTR-10] func signature must not be nil, bit it gets nil`) +func FuncSignatureIsNilError(caller string) error { + return fmt.Errorf(`[GOWRTR-10] func signature must not be nil, bit it gets nil (caused at %s)`, caller) } // AnonymousFuncSignatureIsNilError returns the error. @@ -95,5 +95,5 @@ func ValueOfCompositeLiteralIsEmptyError() error { // ErrsList returns the list of errors. func ErrsList() []string { - return []string{"[GOWRTR-1] struct name must not be empty, but it gets empty", "[GOWRTR-2] field name must not be empty, but it gets empty", "[GOWRTR-3] field type must not be empty, but it gets empty", "[GOWRTR-4] func parameter name must not be empty, but it gets empty (caused at %s)", "[GOWRTR-5] the last func parameter type must not be empty, but it gets empty (caused at %s)", "[GOWRTR-6] name of func must not be empty, but it gets empty", "[GOWRTR-7] name of interface must not be empty, but it gets empty", "[GOWRTR-8] name of func receiver must not be empty, but it gets empty", "[GOWRTR-9] type of func receiver must not be empty, but it gets empty", "[GOWRTR-10] func signature must not be nil, bit it gets nil", "[GOWRTR-11] anonymous func signature must not be nil, bit it gets nil (caused at %s)", "[GOWRTR-12] a parameter of function invocation must not be nil, but it gets nil", "[GOWRTR-13] code formatter raises error: command=\"%s\", err=\"%s\", msg=\"%s\"", "[GOWRTR-14] condition of case must not be empty, but it gets empty (caused at %s)", "[GOWRTR-15] condition of if must not be empty, but it gets empty", "[GOWRTR-16] unnamed return type appears after named return type", "[GOWRTR-17] a value of composite literal must not be empty, but it gets empty"} + return []string{"[GOWRTR-1] struct name must not be empty, but it gets empty", "[GOWRTR-2] field name must not be empty, but it gets empty", "[GOWRTR-3] field type must not be empty, but it gets empty", "[GOWRTR-4] func parameter name must not be empty, but it gets empty (caused at %s)", "[GOWRTR-5] the last func parameter type must not be empty, but it gets empty (caused at %s)", "[GOWRTR-6] name of func must not be empty, but it gets empty", "[GOWRTR-7] name of interface must not be empty, but it gets empty", "[GOWRTR-8] name of func receiver must not be empty, but it gets empty", "[GOWRTR-9] type of func receiver must not be empty, but it gets empty", "[GOWRTR-10] func signature must not be nil, bit it gets nil (caused at %s)", "[GOWRTR-11] anonymous func signature must not be nil, bit it gets nil (caused at %s)", "[GOWRTR-12] a parameter of function invocation must not be nil, but it gets nil", "[GOWRTR-13] code formatter raises error: command=\"%s\", err=\"%s\", msg=\"%s\"", "[GOWRTR-14] condition of case must not be empty, but it gets empty (caused at %s)", "[GOWRTR-15] condition of if must not be empty, but it gets empty", "[GOWRTR-16] unnamed return type appears after named return type", "[GOWRTR-17] a value of composite literal must not be empty, but it gets empty"} } From 3c27e114e122f9664855cac26aaff197ff088488 Mon Sep 17 00:00:00 2001 From: moznion Date: Mon, 21 Jan 2019 23:29:48 +0900 Subject: [PATCH 05/14] Support `created at` on func invocation generator --- generator/anonymous_func_test.go | 4 +++- generator/func_invocation.go | 16 ++++++++++++---- generator/func_invocation_test.go | 6 +++++- internal/errmsg/errmsg.go | 2 +- internal/errmsg/errs_errmsg_gen.go | 6 +++--- 5 files changed, 24 insertions(+), 10 deletions(-) diff --git a/generator/anonymous_func_test.go b/generator/anonymous_func_test.go index a1637cb..54d604e 100644 --- a/generator/anonymous_func_test.go +++ b/generator/anonymous_func_test.go @@ -154,5 +154,7 @@ func TestShouldGenerateAnonymousFuncRaisesErrorWhenFuncInvocationRaisesError(t * NewAnonymousFuncSignature(), ).Invocation(NewFuncInvocation("")) _, err := generator.Generate(0) - assert.EqualError(t, err, errmsg.FuncInvocationParameterIsEmptyError().Error()) + assert.Regexp(t, regexp.MustCompile( + `^\`+strings.Split(errmsg.FuncInvocationParameterIsEmptyError("").Error(), " ")[0], + ), err.Error()) } diff --git a/generator/func_invocation.go b/generator/func_invocation.go index 07064f7..5805652 100644 --- a/generator/func_invocation.go +++ b/generator/func_invocation.go @@ -9,32 +9,40 @@ import ( // FuncInvocation represents a code generator for func invocation. type FuncInvocation struct { parameters []string + callers []string } // NewFuncInvocation returns a new `FuncInvocation`. func NewFuncInvocation(parameters ...string) *FuncInvocation { return &FuncInvocation{ parameters: parameters, + callers: fetchClientCallerLineAsSlice(len(parameters)), } } // AddParameters adds parameters of func invocation to `FuncInvocation`. This does *not* set, just add. // This method returns a *new* `FuncInvocation`; it means this method acts as immutable. func (fig *FuncInvocation) AddParameters(parameters ...string) *FuncInvocation { - return NewFuncInvocation(append(fig.parameters, parameters...)...) + return &FuncInvocation{ + parameters: append(fig.parameters, parameters...), + callers: append(fig.callers, fetchClientCallerLineAsSlice(len(parameters))...), + } } // Parameters sets parameters of func invocation to `FuncInvocation`. This does *not* add, just set. // This method returns a *new* `FuncInvocation`; it means this method acts as immutable. func (fig *FuncInvocation) Parameters(parameters ...string) *FuncInvocation { - return NewFuncInvocation(parameters...) + return &FuncInvocation{ + parameters: parameters, + callers: fetchClientCallerLineAsSlice(len(parameters)), + } } // Generate generates the func invocation as golang code. func (fig *FuncInvocation) Generate(indentLevel int) (string, error) { - for _, param := range fig.parameters { + for i, param := range fig.parameters { if param == "" { - return "", errmsg.FuncInvocationParameterIsEmptyError() + return "", errmsg.FuncInvocationParameterIsEmptyError(fig.callers[i]) } } diff --git a/generator/func_invocation_test.go b/generator/func_invocation_test.go index 58d8988..f45f1af 100644 --- a/generator/func_invocation_test.go +++ b/generator/func_invocation_test.go @@ -1,6 +1,8 @@ package generator import ( + "regexp" + "strings" "testing" "github.com/moznion/gowrtr/internal/errmsg" @@ -34,5 +36,7 @@ func TestShouldGenerateFuncInvocationCode(t *testing.T) { func TestShouldGenerateFuncInvocationRaisesErrorWhenParameterIsEmpty(t *testing.T) { generator := NewFuncInvocation("foo", "", "bar") _, err := generator.Generate(0) - assert.EqualError(t, err, errmsg.FuncInvocationParameterIsEmptyError().Error()) + assert.Regexp(t, regexp.MustCompile( + `^\`+strings.Split(errmsg.FuncInvocationParameterIsEmptyError("").Error(), " ")[0], + ), err.Error()) } diff --git a/internal/errmsg/errmsg.go b/internal/errmsg/errmsg.go index 5704957..c181ddf 100644 --- a/internal/errmsg/errmsg.go +++ b/internal/errmsg/errmsg.go @@ -13,7 +13,7 @@ type errs struct { FuncReceiverTypeIsEmptyError error `errmsg:"type of func receiver must not be empty, but it gets empty"` FuncSignatureIsNilError error `errmsg:"func signature must not be nil, bit it gets nil (caused at %s)" vars:"caller string"` AnonymousFuncSignatureIsNilError error `errmsg:"anonymous func signature must not be nil, bit it gets nil (caused at %s)" vars:"caller string"` - FuncInvocationParameterIsEmptyError error `errmsg:"a parameter of function invocation must not be nil, but it gets nil"` + FuncInvocationParameterIsEmptyError error `errmsg:"a parameter of function invocation must not be nil, but it gets nil (caused at %s)" vars:"caller string"` CodeFormatterError error `errmsg:"code formatter raises error: command=\"%s\", err=\"%s\", msg=\"%s\"" vars:"cmd string, msg string, err error"` CaseConditionIsEmptyError error `errmsg:"condition of case must not be empty, but it gets empty (caused at %s)" vars:"caller string"` IfConditionIsEmptyError error `errmsg:"condition of if must not be empty, but it gets empty"` diff --git a/internal/errmsg/errs_errmsg_gen.go b/internal/errmsg/errs_errmsg_gen.go index 6ac681a..de10546 100644 --- a/internal/errmsg/errs_errmsg_gen.go +++ b/internal/errmsg/errs_errmsg_gen.go @@ -64,8 +64,8 @@ func AnonymousFuncSignatureIsNilError(caller string) error { } // FuncInvocationParameterIsEmptyError returns the error. -func FuncInvocationParameterIsEmptyError() error { - return errors.New(`[GOWRTR-12] a parameter of function invocation must not be nil, but it gets nil`) +func FuncInvocationParameterIsEmptyError(caller string) error { + return fmt.Errorf(`[GOWRTR-12] a parameter of function invocation must not be nil, but it gets nil (caused at %s)`, caller) } // CodeFormatterError returns the error. @@ -95,5 +95,5 @@ func ValueOfCompositeLiteralIsEmptyError() error { // ErrsList returns the list of errors. func ErrsList() []string { - return []string{"[GOWRTR-1] struct name must not be empty, but it gets empty", "[GOWRTR-2] field name must not be empty, but it gets empty", "[GOWRTR-3] field type must not be empty, but it gets empty", "[GOWRTR-4] func parameter name must not be empty, but it gets empty (caused at %s)", "[GOWRTR-5] the last func parameter type must not be empty, but it gets empty (caused at %s)", "[GOWRTR-6] name of func must not be empty, but it gets empty", "[GOWRTR-7] name of interface must not be empty, but it gets empty", "[GOWRTR-8] name of func receiver must not be empty, but it gets empty", "[GOWRTR-9] type of func receiver must not be empty, but it gets empty", "[GOWRTR-10] func signature must not be nil, bit it gets nil (caused at %s)", "[GOWRTR-11] anonymous func signature must not be nil, bit it gets nil (caused at %s)", "[GOWRTR-12] a parameter of function invocation must not be nil, but it gets nil", "[GOWRTR-13] code formatter raises error: command=\"%s\", err=\"%s\", msg=\"%s\"", "[GOWRTR-14] condition of case must not be empty, but it gets empty (caused at %s)", "[GOWRTR-15] condition of if must not be empty, but it gets empty", "[GOWRTR-16] unnamed return type appears after named return type", "[GOWRTR-17] a value of composite literal must not be empty, but it gets empty"} + return []string{"[GOWRTR-1] struct name must not be empty, but it gets empty", "[GOWRTR-2] field name must not be empty, but it gets empty", "[GOWRTR-3] field type must not be empty, but it gets empty", "[GOWRTR-4] func parameter name must not be empty, but it gets empty (caused at %s)", "[GOWRTR-5] the last func parameter type must not be empty, but it gets empty (caused at %s)", "[GOWRTR-6] name of func must not be empty, but it gets empty", "[GOWRTR-7] name of interface must not be empty, but it gets empty", "[GOWRTR-8] name of func receiver must not be empty, but it gets empty", "[GOWRTR-9] type of func receiver must not be empty, but it gets empty", "[GOWRTR-10] func signature must not be nil, bit it gets nil (caused at %s)", "[GOWRTR-11] anonymous func signature must not be nil, bit it gets nil (caused at %s)", "[GOWRTR-12] a parameter of function invocation must not be nil, but it gets nil (caused at %s)", "[GOWRTR-13] code formatter raises error: command=\"%s\", err=\"%s\", msg=\"%s\"", "[GOWRTR-14] condition of case must not be empty, but it gets empty (caused at %s)", "[GOWRTR-15] condition of if must not be empty, but it gets empty", "[GOWRTR-16] unnamed return type appears after named return type", "[GOWRTR-17] a value of composite literal must not be empty, but it gets empty"} } From f171432191bd12ccd12d37114e6667b0e3c3fabe Mon Sep 17 00:00:00 2001 From: moznion Date: Mon, 21 Jan 2019 23:33:33 +0900 Subject: [PATCH 06/14] Support `caused at` on func receiver generator --- generator/func_receiver.go | 18 ++++++++++-------- generator/func_receiver_test.go | 10 ++++++++-- generator/func_test.go | 4 +++- internal/errmsg/errmsg.go | 4 ++-- internal/errmsg/errs_errmsg_gen.go | 10 +++++----- 5 files changed, 28 insertions(+), 18 deletions(-) diff --git a/generator/func_receiver.go b/generator/func_receiver.go index 54e1921..e5327bb 100644 --- a/generator/func_receiver.go +++ b/generator/func_receiver.go @@ -8,33 +8,35 @@ import ( // FuncReceiver represents a code generator for the receiver of the func. type FuncReceiver struct { - Name string - Type string + name string + typ string + caller string } // NewFuncReceiver returns a new `FuncReceiver`. func NewFuncReceiver(name string, typ string) *FuncReceiver { return &FuncReceiver{ - Name: name, - Type: typ, + name: name, + typ: typ, + caller: fetchClientCallerLine(), } } // Generate generates a receiver of the func as golang code. func (f *FuncReceiver) Generate(indentLevel int) (string, error) { - name := f.Name - typ := f.Type + name := f.name + typ := f.typ if typ == "" && name == "" { return "", nil } if name == "" { - return "", errmsg.FuncReceiverNameIsEmptyError() + return "", errmsg.FuncReceiverNameIsEmptyError(f.caller) } if typ == "" { - return "", errmsg.FuncReceiverTypeIsEmptyError() + return "", errmsg.FuncReceiverTypeIsEmptyError(f.caller) } return fmt.Sprintf("(%s %s)", name, typ), nil diff --git a/generator/func_receiver_test.go b/generator/func_receiver_test.go index 9d5ab73..98d3834 100644 --- a/generator/func_receiver_test.go +++ b/generator/func_receiver_test.go @@ -1,6 +1,8 @@ package generator import ( + "regexp" + "strings" "testing" "github.com/moznion/gowrtr/internal/errmsg" @@ -25,11 +27,15 @@ func TestShouldGeneratingFuncReceiverCodeBeSuccessfulWithEmpty(t *testing.T) { func TestShouldGeneratingFuncReceiverRaisesErrorWhenFuncReceiverNameIsEmpty(t *testing.T) { funcReceiver := NewFuncReceiver("", "*Foo") _, err := funcReceiver.Generate(0) - assert.EqualError(t, err, errmsg.FuncReceiverNameIsEmptyError().Error()) + assert.Regexp(t, regexp.MustCompile( + `^\`+strings.Split(errmsg.FuncReceiverNameIsEmptyError("").Error(), " ")[0], + ), err.Error()) } func TestShouldGeneratingFuncReceiverRaisesErrorWhenFuncReceiverTypeIsEmpty(t *testing.T) { funcReceiver := NewFuncReceiver("f", "") _, err := funcReceiver.Generate(0) - assert.EqualError(t, err, errmsg.FuncReceiverTypeIsEmptyError().Error()) + assert.Regexp(t, regexp.MustCompile( + `^\`+strings.Split(errmsg.FuncReceiverTypeIsEmptyError("").Error(), " ")[0], + ), err.Error()) } diff --git a/generator/func_test.go b/generator/func_test.go index 647391c..faad70d 100644 --- a/generator/func_test.go +++ b/generator/func_test.go @@ -98,7 +98,9 @@ func TestShouldGenerateFuncCodeGiveUpWhenFuncReceiverRaisesError(t *testing.T) { ) _, err := generator.Generate(0) - assert.EqualError(t, err, errmsg.FuncReceiverNameIsEmptyError().Error()) + assert.Regexp(t, regexp.MustCompile( + `^\`+strings.Split(errmsg.FuncReceiverNameIsEmptyError("").Error(), " ")[0], + ), err.Error()) } func TestShouldGenerateFuncCodeGiveUpWhenStatementRaisesError(t *testing.T) { diff --git a/internal/errmsg/errmsg.go b/internal/errmsg/errmsg.go index c181ddf..0944c24 100644 --- a/internal/errmsg/errmsg.go +++ b/internal/errmsg/errmsg.go @@ -9,8 +9,8 @@ type errs struct { LastFuncParameterTypeIsEmptyErr error `errmsg:"the last func parameter type must not be empty, but it gets empty (caused at %s)" vars:"caller string"` FuncNameIsEmptyError error `errmsg:"name of func must not be empty, but it gets empty"` InterfaceNameIsEmptyError error `errmsg:"name of interface must not be empty, but it gets empty"` - FuncReceiverNameIsEmptyError error `errmsg:"name of func receiver must not be empty, but it gets empty"` - FuncReceiverTypeIsEmptyError error `errmsg:"type of func receiver must not be empty, but it gets empty"` + FuncReceiverNameIsEmptyError error `errmsg:"name of func receiver must not be empty, but it gets empty (caused at %s)" vars:"caller string"` + FuncReceiverTypeIsEmptyError error `errmsg:"type of func receiver must not be empty, but it gets empty (caused at %s)" vars:"caller string"` FuncSignatureIsNilError error `errmsg:"func signature must not be nil, bit it gets nil (caused at %s)" vars:"caller string"` AnonymousFuncSignatureIsNilError error `errmsg:"anonymous func signature must not be nil, bit it gets nil (caused at %s)" vars:"caller string"` FuncInvocationParameterIsEmptyError error `errmsg:"a parameter of function invocation must not be nil, but it gets nil (caused at %s)" vars:"caller string"` diff --git a/internal/errmsg/errs_errmsg_gen.go b/internal/errmsg/errs_errmsg_gen.go index de10546..6e5cc3f 100644 --- a/internal/errmsg/errs_errmsg_gen.go +++ b/internal/errmsg/errs_errmsg_gen.go @@ -44,13 +44,13 @@ func InterfaceNameIsEmptyError() error { } // FuncReceiverNameIsEmptyError returns the error. -func FuncReceiverNameIsEmptyError() error { - return errors.New(`[GOWRTR-8] name of func receiver must not be empty, but it gets empty`) +func FuncReceiverNameIsEmptyError(caller string) error { + return fmt.Errorf(`[GOWRTR-8] name of func receiver must not be empty, but it gets empty (caused at %s)`, caller) } // FuncReceiverTypeIsEmptyError returns the error. -func FuncReceiverTypeIsEmptyError() error { - return errors.New(`[GOWRTR-9] type of func receiver must not be empty, but it gets empty`) +func FuncReceiverTypeIsEmptyError(caller string) error { + return fmt.Errorf(`[GOWRTR-9] type of func receiver must not be empty, but it gets empty (caused at %s)`, caller) } // FuncSignatureIsNilError returns the error. @@ -95,5 +95,5 @@ func ValueOfCompositeLiteralIsEmptyError() error { // ErrsList returns the list of errors. func ErrsList() []string { - return []string{"[GOWRTR-1] struct name must not be empty, but it gets empty", "[GOWRTR-2] field name must not be empty, but it gets empty", "[GOWRTR-3] field type must not be empty, but it gets empty", "[GOWRTR-4] func parameter name must not be empty, but it gets empty (caused at %s)", "[GOWRTR-5] the last func parameter type must not be empty, but it gets empty (caused at %s)", "[GOWRTR-6] name of func must not be empty, but it gets empty", "[GOWRTR-7] name of interface must not be empty, but it gets empty", "[GOWRTR-8] name of func receiver must not be empty, but it gets empty", "[GOWRTR-9] type of func receiver must not be empty, but it gets empty", "[GOWRTR-10] func signature must not be nil, bit it gets nil (caused at %s)", "[GOWRTR-11] anonymous func signature must not be nil, bit it gets nil (caused at %s)", "[GOWRTR-12] a parameter of function invocation must not be nil, but it gets nil (caused at %s)", "[GOWRTR-13] code formatter raises error: command=\"%s\", err=\"%s\", msg=\"%s\"", "[GOWRTR-14] condition of case must not be empty, but it gets empty (caused at %s)", "[GOWRTR-15] condition of if must not be empty, but it gets empty", "[GOWRTR-16] unnamed return type appears after named return type", "[GOWRTR-17] a value of composite literal must not be empty, but it gets empty"} + return []string{"[GOWRTR-1] struct name must not be empty, but it gets empty", "[GOWRTR-2] field name must not be empty, but it gets empty", "[GOWRTR-3] field type must not be empty, but it gets empty", "[GOWRTR-4] func parameter name must not be empty, but it gets empty (caused at %s)", "[GOWRTR-5] the last func parameter type must not be empty, but it gets empty (caused at %s)", "[GOWRTR-6] name of func must not be empty, but it gets empty", "[GOWRTR-7] name of interface must not be empty, but it gets empty", "[GOWRTR-8] name of func receiver must not be empty, but it gets empty (caused at %s)", "[GOWRTR-9] type of func receiver must not be empty, but it gets empty (caused at %s)", "[GOWRTR-10] func signature must not be nil, bit it gets nil (caused at %s)", "[GOWRTR-11] anonymous func signature must not be nil, bit it gets nil (caused at %s)", "[GOWRTR-12] a parameter of function invocation must not be nil, but it gets nil (caused at %s)", "[GOWRTR-13] code formatter raises error: command=\"%s\", err=\"%s\", msg=\"%s\"", "[GOWRTR-14] condition of case must not be empty, but it gets empty (caused at %s)", "[GOWRTR-15] condition of if must not be empty, but it gets empty", "[GOWRTR-16] unnamed return type appears after named return type", "[GOWRTR-17] a value of composite literal must not be empty, but it gets empty"} } From b8bbc1a761e6f40726a724388a38f1fe50db1f9b Mon Sep 17 00:00:00 2001 From: moznion Date: Mon, 21 Jan 2019 23:55:34 +0900 Subject: [PATCH 07/14] Support `caused at` on func signature generator --- generator/anonymous_func_test.go | 4 +- generator/case_test.go | 4 +- generator/code_block_test.go | 6 ++- generator/default_case_test.go | 6 ++- generator/else_if_test.go | 6 ++- generator/else_test.go | 6 ++- generator/for_test.go | 6 ++- generator/func_signature.go | 61 ++++++++++++++++++------------ generator/func_signature_test.go | 8 +++- generator/func_test.go | 8 +++- generator/if_test.go | 14 +++++-- generator/interface_test.go | 6 ++- generator/switch_test.go | 4 +- internal/errmsg/errmsg.go | 4 +- internal/errmsg/errs_errmsg_gen.go | 10 ++--- 15 files changed, 105 insertions(+), 48 deletions(-) diff --git a/generator/anonymous_func_test.go b/generator/anonymous_func_test.go index 54d604e..6575ab4 100644 --- a/generator/anonymous_func_test.go +++ b/generator/anonymous_func_test.go @@ -145,7 +145,9 @@ func TestShouldGenerateAnonymousFuncRaisesErrorWhenStatementRaisesError(t *testi ) _, err := generator.Generate(0) - assert.EqualError(t, err, errmsg.FuncNameIsEmptyError().Error()) + assert.Regexp(t, regexp.MustCompile( + `^\`+strings.Split(errmsg.FuncNameIsEmptyError("").Error(), " ")[0], + ), err.Error()) } func TestShouldGenerateAnonymousFuncRaisesErrorWhenFuncInvocationRaisesError(t *testing.T) { diff --git a/generator/case_test.go b/generator/case_test.go index ee1170f..710876d 100644 --- a/generator/case_test.go +++ b/generator/case_test.go @@ -64,5 +64,7 @@ func TestShouldGenerateCaseRaisesErrorWhenStatementsRaisesError(t *testing.T) { NewFunc(nil, NewFuncSignature("")), ) _, err := generator.Generate(0) - assert.EqualError(t, err, errmsg.FuncNameIsEmptyError().Error()) + assert.Regexp(t, regexp.MustCompile( + `^\`+strings.Split(errmsg.FuncNameIsEmptyError("").Error(), " ")[0], + ), err.Error()) } diff --git a/generator/code_block_test.go b/generator/code_block_test.go index ea29da1..e990e56 100644 --- a/generator/code_block_test.go +++ b/generator/code_block_test.go @@ -1,6 +1,8 @@ package generator import ( + "regexp" + "strings" "testing" "github.com/moznion/gowrtr/internal/errmsg" @@ -94,5 +96,7 @@ func TestShouldGenerateCodeBlockGiveUpWhenStatementRaisesError(t *testing.T) { NewFunc(nil, NewFuncSignature("")), ) _, err := generator.Generate(0) - assert.EqualError(t, err, errmsg.FuncNameIsEmptyError().Error()) + assert.Regexp(t, regexp.MustCompile( + `^\`+strings.Split(errmsg.FuncNameIsEmptyError("").Error(), " ")[0], + ), err.Error()) } diff --git a/generator/default_case_test.go b/generator/default_case_test.go index 225dcba..0f18d36 100644 --- a/generator/default_case_test.go +++ b/generator/default_case_test.go @@ -1,6 +1,8 @@ package generator import ( + "regexp" + "strings" "testing" "github.com/moznion/gowrtr/internal/errmsg" @@ -52,5 +54,7 @@ func TestShouldGenerateDefaultCaseRaisesErrorWhenStatementsRaisesError(t *testin NewFunc(nil, NewFuncSignature("")), ) _, err := generator.Generate(0) - assert.EqualError(t, err, errmsg.FuncNameIsEmptyError().Error()) + assert.Regexp(t, regexp.MustCompile( + `^\`+strings.Split(errmsg.FuncNameIsEmptyError("").Error(), " ")[0], + ), err.Error()) } diff --git a/generator/else_if_test.go b/generator/else_if_test.go index 5be3867..2d72316 100644 --- a/generator/else_if_test.go +++ b/generator/else_if_test.go @@ -1,6 +1,8 @@ package generator import ( + "regexp" + "strings" "testing" "github.com/moznion/gowrtr/internal/errmsg" @@ -70,5 +72,7 @@ func TestShouldGenerateElseIfRaisesError(t *testing.T) { ) _, err := generator.Generate(0) - assert.EqualError(t, err, errmsg.FuncNameIsEmptyError().Error()) + assert.Regexp(t, regexp.MustCompile( + `^\`+strings.Split(errmsg.FuncNameIsEmptyError("").Error(), " ")[0], + ), err.Error()) } diff --git a/generator/else_test.go b/generator/else_test.go index ea4033c..907eabb 100644 --- a/generator/else_test.go +++ b/generator/else_test.go @@ -1,6 +1,8 @@ package generator import ( + "regexp" + "strings" "testing" "github.com/moznion/gowrtr/internal/errmsg" @@ -54,5 +56,7 @@ func TestShouldGenerateElseCodeRaisesError(t *testing.T) { NewFunc(nil, NewFuncSignature("")), ) _, err := generator.Generate(0) - assert.EqualError(t, err, errmsg.FuncNameIsEmptyError().Error()) + assert.Regexp(t, regexp.MustCompile( + `^\`+strings.Split(errmsg.FuncNameIsEmptyError("").Error(), " ")[0], + ), err.Error()) } diff --git a/generator/for_test.go b/generator/for_test.go index 805c2d0..1bf0ca5 100644 --- a/generator/for_test.go +++ b/generator/for_test.go @@ -1,6 +1,8 @@ package generator import ( + "regexp" + "strings" "testing" "github.com/moznion/gowrtr/internal/errmsg" @@ -73,5 +75,7 @@ func TestShouldGenerateForCodeGiveUpWhenStatementRaisesError(t *testing.T) { NewFunc(nil, NewFuncSignature("")), ) _, err := generator.Generate(0) - assert.EqualError(t, err, errmsg.FuncNameIsEmptyError().Error()) + assert.Regexp(t, regexp.MustCompile( + `^\`+strings.Split(errmsg.FuncNameIsEmptyError("").Error(), " ")[0], + ), err.Error()) } diff --git a/generator/func_signature.go b/generator/func_signature.go index c603479..bb3f733 100644 --- a/generator/func_signature.go +++ b/generator/func_signature.go @@ -34,10 +34,12 @@ func (frt *FuncReturnType) Generate(indentLevel int) (string, error) { // FuncSignature represents a code generator for the signature of the func. type FuncSignature struct { - funcName string - funcParameters []*FuncParameter - returnTypes []*FuncReturnType - callers []string + funcName string + funcParameters []*FuncParameter + returnTypes []*FuncReturnType + paramCallers []string + funcNameCaller string + returnTypesCallers []string } // NewFuncParameter returns a new `FuncSignature`. @@ -64,7 +66,8 @@ func NewFuncReturnType(typ string, name ...string) *FuncReturnType { // NewFuncSignature returns a new `FuncSignature`. func NewFuncSignature(funcName string) *FuncSignature { return &FuncSignature{ - funcName: funcName, + funcName: funcName, + funcNameCaller: fetchClientCallerLine(), } } @@ -72,10 +75,12 @@ func NewFuncSignature(funcName string) *FuncSignature { // This method returns a *new* `FuncSignature`; it means this method acts as immutable. func (f *FuncSignature) AddParameters(funcParameters ...*FuncParameter) *FuncSignature { return &FuncSignature{ - funcName: f.funcName, - funcParameters: append(f.funcParameters, funcParameters...), - returnTypes: f.returnTypes, - callers: append(f.callers, fetchClientCallerLineAsSlice(len(funcParameters))...), + funcName: f.funcName, + funcParameters: append(f.funcParameters, funcParameters...), + returnTypes: f.returnTypes, + paramCallers: append(f.paramCallers, fetchClientCallerLineAsSlice(len(funcParameters))...), + funcNameCaller: f.funcNameCaller, + returnTypesCallers: f.returnTypesCallers, } } @@ -83,10 +88,12 @@ func (f *FuncSignature) AddParameters(funcParameters ...*FuncParameter) *FuncSig // This method returns a *new* `FuncSignature`; it means this method acts as immutable. func (f *FuncSignature) Parameters(funcParameters ...*FuncParameter) *FuncSignature { return &FuncSignature{ - funcName: f.funcName, - funcParameters: funcParameters, - returnTypes: f.returnTypes, - callers: fetchClientCallerLineAsSlice(len(funcParameters)), + funcName: f.funcName, + funcParameters: funcParameters, + returnTypes: f.returnTypes, + paramCallers: fetchClientCallerLineAsSlice(len(funcParameters)), + funcNameCaller: f.funcNameCaller, + returnTypesCallers: f.returnTypesCallers, } } @@ -108,10 +115,12 @@ func (f *FuncSignature) AddReturnTypes(returnTypes ...string) *FuncSignature { // This method returns a *new* `FuncSignature`; it means this method acts as immutable. func (f *FuncSignature) AddReturnTypeStructs(returnTypes ...*FuncReturnType) *FuncSignature { return &FuncSignature{ - funcName: f.funcName, - funcParameters: f.funcParameters, - returnTypes: append(f.returnTypes, returnTypes...), - callers: f.callers, + funcName: f.funcName, + funcParameters: f.funcParameters, + returnTypes: append(f.returnTypes, returnTypes...), + paramCallers: f.paramCallers, + funcNameCaller: f.funcNameCaller, + returnTypesCallers: append(f.returnTypesCallers, fetchClientCallerLineAsSlice(len(returnTypes))...), } } @@ -133,17 +142,19 @@ func (f *FuncSignature) ReturnTypes(returnTypes ...string) *FuncSignature { // This method returns a *new* `FuncSignature`; it means this method acts as immutable. func (f *FuncSignature) ReturnTypeStructs(returnTypes ...*FuncReturnType) *FuncSignature { return &FuncSignature{ - funcName: f.funcName, - funcParameters: f.funcParameters, - returnTypes: returnTypes, - callers: f.callers, + funcName: f.funcName, + funcParameters: f.funcParameters, + returnTypes: returnTypes, + paramCallers: f.paramCallers, + funcNameCaller: f.funcNameCaller, + returnTypesCallers: fetchClientCallerLineAsSlice(len(returnTypes)), } } // Generate generates a signature of the func as golang code. func (f *FuncSignature) Generate(indentLevel int) (string, error) { if f.funcName == "" { - return "", errmsg.FuncNameIsEmptyError() + return "", errmsg.FuncNameIsEmptyError(f.funcNameCaller) } stmt := f.funcName + "(" @@ -153,7 +164,7 @@ func (f *FuncSignature) Generate(indentLevel int) (string, error) { params := make([]string, len(f.funcParameters)) for i, param := range f.funcParameters { if param.name == "" { - return "", errmsg.FuncParameterNameIsEmptyErr(f.callers[i]) + return "", errmsg.FuncParameterNameIsEmptyErr(f.paramCallers[i]) } paramSet := param.name @@ -162,7 +173,7 @@ func (f *FuncSignature) Generate(indentLevel int) (string, error) { paramSet += " " + param.typ } if !typeExisted { - typeMissingCaller = f.callers[i] + typeMissingCaller = f.paramCallers[i] } params[i] = paramSet } @@ -198,7 +209,7 @@ func (f *FuncSignature) Generate(indentLevel int) (string, error) { namedRetTypeAppeared = isNamedRetType } if namedRetTypeAppeared && !isNamedRetType { - return "", errmsg.UnnamedReturnTypeAppearsAfterNamedReturnTypeError() + return "", errmsg.UnnamedReturnTypeAppearsAfterNamedReturnTypeError(f.returnTypesCallers[i]) } } stmt += " (" + strings.Join(retTypes, ", ") + ")" diff --git a/generator/func_signature_test.go b/generator/func_signature_test.go index a97edcd..4c1b8b7 100644 --- a/generator/func_signature_test.go +++ b/generator/func_signature_test.go @@ -69,7 +69,9 @@ func TestShouldRaiseErrorWhenFuncNameIsEmpty(t *testing.T) { sig := NewFuncSignature("") _, err := sig.Generate(0) - assert.EqualError(t, err, errmsg.FuncNameIsEmptyError().Error()) + assert.Regexp(t, regexp.MustCompile( + `^\`+strings.Split(errmsg.FuncNameIsEmptyError("").Error(), " ")[0], + ), err.Error()) } func TestShouldRaiseErrorWhenFuncParameterNameIsEmpty(t *testing.T) { @@ -176,5 +178,7 @@ func TestShouldGeneratingFuncSignatureRaisesUnnamedRetTypeIsAfterNamedRetType(t AddReturnTypeStructs(NewFuncReturnType("string", "foo")). AddReturnTypeStructs(NewFuncReturnType("error", "")) _, err := generator.Generate(0) - assert.EqualError(t, err, errmsg.UnnamedReturnTypeAppearsAfterNamedReturnTypeError().Error()) + assert.Regexp(t, regexp.MustCompile( + `^\`+strings.Split(errmsg.UnnamedReturnTypeAppearsAfterNamedReturnTypeError("").Error(), " ")[0], + ), err.Error()) } diff --git a/generator/func_test.go b/generator/func_test.go index faad70d..6b42ea5 100644 --- a/generator/func_test.go +++ b/generator/func_test.go @@ -72,7 +72,9 @@ func TestShouldGenerateFuncCodeGiveUpWhenFuncNameIsEmpty(t *testing.T) { ) _, err := generator.Generate(0) - assert.EqualError(t, err, errmsg.FuncNameIsEmptyError().Error()) + assert.Regexp(t, regexp.MustCompile( + `^\`+strings.Split(errmsg.FuncNameIsEmptyError("").Error(), " ")[0], + ), err.Error()) } func TestShouldGenerateFuncCodeGiveUpWhenFuncSignatureIsNil(t *testing.T) { @@ -116,5 +118,7 @@ func TestShouldGenerateFuncCodeGiveUpWhenStatementRaisesError(t *testing.T) { ) _, err := generator.Generate(0) - assert.EqualError(t, err, errmsg.FuncNameIsEmptyError().Error()) + assert.Regexp(t, regexp.MustCompile( + `^\`+strings.Split(errmsg.FuncNameIsEmptyError("").Error(), " ")[0], + ), err.Error()) } diff --git a/generator/if_test.go b/generator/if_test.go index 6e0e38c..dd37d11 100644 --- a/generator/if_test.go +++ b/generator/if_test.go @@ -1,6 +1,8 @@ package generator import ( + "regexp" + "strings" "testing" "github.com/moznion/gowrtr/internal/errmsg" @@ -74,7 +76,9 @@ func TestShouldGenerateIfCodeGiveUpWhenStatementRaisesError(t *testing.T) { ) _, err := generator.Generate(0) - assert.EqualError(t, err, errmsg.FuncNameIsEmptyError().Error()) + assert.Regexp(t, regexp.MustCompile( + `^\`+strings.Split(errmsg.FuncNameIsEmptyError("").Error(), " ")[0], + ), err.Error()) } func TestShouldGenerateIfAndElseIfAndElseCode(t *testing.T) { @@ -153,7 +157,9 @@ func TestShouldGenerateIfElseIfRaisesError(t *testing.T) { ) _, err := generator.Generate(0) - assert.EqualError(t, err, errmsg.FuncNameIsEmptyError().Error()) + assert.Regexp(t, regexp.MustCompile( + `^\`+strings.Split(errmsg.FuncNameIsEmptyError("").Error(), " ")[0], + ), err.Error()) } func TestShouldGenerateIfElseRaisesError(t *testing.T) { @@ -164,5 +170,7 @@ func TestShouldGenerateIfElseRaisesError(t *testing.T) { ) _, err := generator.Generate(0) - assert.EqualError(t, err, errmsg.FuncNameIsEmptyError().Error()) + assert.Regexp(t, regexp.MustCompile( + `^\`+strings.Split(errmsg.FuncNameIsEmptyError("").Error(), " ")[0], + ), err.Error()) } diff --git a/generator/interface_test.go b/generator/interface_test.go index 97431c0..50c6092 100644 --- a/generator/interface_test.go +++ b/generator/interface_test.go @@ -1,6 +1,8 @@ package generator import ( + "regexp" + "strings" "testing" "github.com/moznion/gowrtr/internal/errmsg" @@ -117,5 +119,7 @@ func TestShouldRaiseErrorWhenFuncSignatureRaisesError(t *testing.T) { NewFuncSignature(""), ) _, err := in.Generate(0) - assert.EqualError(t, err, errmsg.FuncNameIsEmptyError().Error()) + assert.Regexp(t, regexp.MustCompile( + `^\`+strings.Split(errmsg.FuncNameIsEmptyError("").Error(), " ")[0], + ), err.Error()) } diff --git a/generator/switch_test.go b/generator/switch_test.go index 50ddb3f..9ad8e3c 100644 --- a/generator/switch_test.go +++ b/generator/switch_test.go @@ -91,5 +91,7 @@ func TestShouldGenerateSwitchRaisesErrorWhenDefaultRaisesError(t *testing.T) { ), ) _, err := generator.Generate(0) - assert.EqualError(t, err, errmsg.FuncNameIsEmptyError().Error()) + assert.Regexp(t, regexp.MustCompile( + `^\`+strings.Split(errmsg.FuncNameIsEmptyError("").Error(), " ")[0], + ), err.Error()) } diff --git a/internal/errmsg/errmsg.go b/internal/errmsg/errmsg.go index 0944c24..65eef6d 100644 --- a/internal/errmsg/errmsg.go +++ b/internal/errmsg/errmsg.go @@ -7,7 +7,7 @@ type errs struct { StructFieldTypeIsEmptyErr error `errmsg:"field type must not be empty, but it gets empty"` FuncParameterNameIsEmptyErr error `errmsg:"func parameter name must not be empty, but it gets empty (caused at %s)" vars:"caller string"` LastFuncParameterTypeIsEmptyErr error `errmsg:"the last func parameter type must not be empty, but it gets empty (caused at %s)" vars:"caller string"` - FuncNameIsEmptyError error `errmsg:"name of func must not be empty, but it gets empty"` + FuncNameIsEmptyError error `errmsg:"name of func must not be empty, but it gets empty (caused at %s)" vars:"caller string"` InterfaceNameIsEmptyError error `errmsg:"name of interface must not be empty, but it gets empty"` FuncReceiverNameIsEmptyError error `errmsg:"name of func receiver must not be empty, but it gets empty (caused at %s)" vars:"caller string"` FuncReceiverTypeIsEmptyError error `errmsg:"type of func receiver must not be empty, but it gets empty (caused at %s)" vars:"caller string"` @@ -17,6 +17,6 @@ type errs struct { CodeFormatterError error `errmsg:"code formatter raises error: command=\"%s\", err=\"%s\", msg=\"%s\"" vars:"cmd string, msg string, err error"` CaseConditionIsEmptyError error `errmsg:"condition of case must not be empty, but it gets empty (caused at %s)" vars:"caller string"` IfConditionIsEmptyError error `errmsg:"condition of if must not be empty, but it gets empty"` - UnnamedReturnTypeAppearsAfterNamedReturnTypeError error `errmsg:"unnamed return type appears after named return type"` + UnnamedReturnTypeAppearsAfterNamedReturnTypeError error `errmsg:"unnamed return type appears after named return type (caused at %s)" vars:"caller string"` ValueOfCompositeLiteralIsEmptyError error `errmsg:"a value of composite literal must not be empty, but it gets empty"` } diff --git a/internal/errmsg/errs_errmsg_gen.go b/internal/errmsg/errs_errmsg_gen.go index 6e5cc3f..8460671 100644 --- a/internal/errmsg/errs_errmsg_gen.go +++ b/internal/errmsg/errs_errmsg_gen.go @@ -34,8 +34,8 @@ func LastFuncParameterTypeIsEmptyErr(caller string) error { } // FuncNameIsEmptyError returns the error. -func FuncNameIsEmptyError() error { - return errors.New(`[GOWRTR-6] name of func must not be empty, but it gets empty`) +func FuncNameIsEmptyError(caller string) error { + return fmt.Errorf(`[GOWRTR-6] name of func must not be empty, but it gets empty (caused at %s)`, caller) } // InterfaceNameIsEmptyError returns the error. @@ -84,8 +84,8 @@ func IfConditionIsEmptyError() error { } // UnnamedReturnTypeAppearsAfterNamedReturnTypeError returns the error. -func UnnamedReturnTypeAppearsAfterNamedReturnTypeError() error { - return errors.New(`[GOWRTR-16] unnamed return type appears after named return type`) +func UnnamedReturnTypeAppearsAfterNamedReturnTypeError(caller string) error { + return fmt.Errorf(`[GOWRTR-16] unnamed return type appears after named return type (caused at %s)`, caller) } // ValueOfCompositeLiteralIsEmptyError returns the error. @@ -95,5 +95,5 @@ func ValueOfCompositeLiteralIsEmptyError() error { // ErrsList returns the list of errors. func ErrsList() []string { - return []string{"[GOWRTR-1] struct name must not be empty, but it gets empty", "[GOWRTR-2] field name must not be empty, but it gets empty", "[GOWRTR-3] field type must not be empty, but it gets empty", "[GOWRTR-4] func parameter name must not be empty, but it gets empty (caused at %s)", "[GOWRTR-5] the last func parameter type must not be empty, but it gets empty (caused at %s)", "[GOWRTR-6] name of func must not be empty, but it gets empty", "[GOWRTR-7] name of interface must not be empty, but it gets empty", "[GOWRTR-8] name of func receiver must not be empty, but it gets empty (caused at %s)", "[GOWRTR-9] type of func receiver must not be empty, but it gets empty (caused at %s)", "[GOWRTR-10] func signature must not be nil, bit it gets nil (caused at %s)", "[GOWRTR-11] anonymous func signature must not be nil, bit it gets nil (caused at %s)", "[GOWRTR-12] a parameter of function invocation must not be nil, but it gets nil (caused at %s)", "[GOWRTR-13] code formatter raises error: command=\"%s\", err=\"%s\", msg=\"%s\"", "[GOWRTR-14] condition of case must not be empty, but it gets empty (caused at %s)", "[GOWRTR-15] condition of if must not be empty, but it gets empty", "[GOWRTR-16] unnamed return type appears after named return type", "[GOWRTR-17] a value of composite literal must not be empty, but it gets empty"} + return []string{"[GOWRTR-1] struct name must not be empty, but it gets empty", "[GOWRTR-2] field name must not be empty, but it gets empty", "[GOWRTR-3] field type must not be empty, but it gets empty", "[GOWRTR-4] func parameter name must not be empty, but it gets empty (caused at %s)", "[GOWRTR-5] the last func parameter type must not be empty, but it gets empty (caused at %s)", "[GOWRTR-6] name of func must not be empty, but it gets empty (caused at %s)", "[GOWRTR-7] name of interface must not be empty, but it gets empty", "[GOWRTR-8] name of func receiver must not be empty, but it gets empty (caused at %s)", "[GOWRTR-9] type of func receiver must not be empty, but it gets empty (caused at %s)", "[GOWRTR-10] func signature must not be nil, bit it gets nil (caused at %s)", "[GOWRTR-11] anonymous func signature must not be nil, bit it gets nil (caused at %s)", "[GOWRTR-12] a parameter of function invocation must not be nil, but it gets nil (caused at %s)", "[GOWRTR-13] code formatter raises error: command=\"%s\", err=\"%s\", msg=\"%s\"", "[GOWRTR-14] condition of case must not be empty, but it gets empty (caused at %s)", "[GOWRTR-15] condition of if must not be empty, but it gets empty", "[GOWRTR-16] unnamed return type appears after named return type (caused at %s)", "[GOWRTR-17] a value of composite literal must not be empty, but it gets empty"} } From e68c0650eee923bf9b005115e62e534f106dcdf1 Mon Sep 17 00:00:00 2001 From: moznion Date: Tue, 22 Jan 2019 00:00:29 +0900 Subject: [PATCH 08/14] Support `created at` on if generator --- generator/composite_literal_test.go | 6 +++++- generator/if.go | 9 ++++++++- generator/if_test.go | 4 +++- internal/errmsg/errmsg.go | 2 +- internal/errmsg/errs_errmsg_gen.go | 6 +++--- 5 files changed, 20 insertions(+), 7 deletions(-) diff --git a/generator/composite_literal_test.go b/generator/composite_literal_test.go index 032b0a0..f5955ec 100644 --- a/generator/composite_literal_test.go +++ b/generator/composite_literal_test.go @@ -1,6 +1,8 @@ package generator import ( + "regexp" + "strings" "testing" "github.com/moznion/gowrtr/internal/errmsg" @@ -73,7 +75,9 @@ func TestShouldGenerateCompositeLiteralWithEmptyKey(t *testing.T) { func TestShouldGenerateCompositeLiteralRaiseError(t *testing.T) { _, err := NewCompositeLiteral("").AddField("foo", NewIf("")).Generate(0) - assert.EqualError(t, err, errmsg.IfConditionIsEmptyError().Error()) + assert.Regexp(t, regexp.MustCompile( + `^\`+strings.Split(errmsg.IfConditionIsEmptyError("").Error(), " ")[0], + ), err.Error()) } func TestShouldGenerateCompositeLiteralRaiseErrorWhenValueIsEmpty(t *testing.T) { diff --git a/generator/if.go b/generator/if.go index f94d532..e62793b 100644 --- a/generator/if.go +++ b/generator/if.go @@ -12,6 +12,7 @@ type If struct { statements []Statement elseIfBlocks []*ElseIf elseBlock *Else + caller string } // NewIf returns a new `If`. @@ -19,6 +20,7 @@ func NewIf(condition string, statements ...Statement) *If { return &If{ condition: condition, statements: statements, + caller: fetchClientCallerLine(), } } @@ -30,6 +32,7 @@ func (ig *If) AddStatements(statements ...Statement) *If { statements: append(ig.statements, statements...), elseIfBlocks: ig.elseIfBlocks, elseBlock: ig.elseBlock, + caller: ig.caller, } } @@ -41,6 +44,7 @@ func (ig *If) Statements(statements ...Statement) *If { statements: statements, elseIfBlocks: ig.elseIfBlocks, elseBlock: ig.elseBlock, + caller: ig.caller, } } @@ -52,6 +56,7 @@ func (ig *If) AddElseIf(blocks ...*ElseIf) *If { statements: ig.statements, elseIfBlocks: append(ig.elseIfBlocks, blocks...), elseBlock: ig.elseBlock, + caller: ig.caller, } } @@ -63,6 +68,7 @@ func (ig *If) ElseIf(blocks ...*ElseIf) *If { statements: ig.statements, elseIfBlocks: blocks, elseBlock: ig.elseBlock, + caller: ig.caller, } } @@ -74,6 +80,7 @@ func (ig *If) Else(block *Else) *If { statements: ig.statements, elseIfBlocks: ig.elseIfBlocks, elseBlock: block, + caller: ig.caller, } } @@ -82,7 +89,7 @@ func (ig *If) Generate(indentLevel int) (string, error) { indent := buildIndent(indentLevel) if ig.condition == "" { - return "", errmsg.IfConditionIsEmptyError() + return "", errmsg.IfConditionIsEmptyError(ig.caller) } stmt := fmt.Sprintf("%sif %s {\n", indent, ig.condition) diff --git a/generator/if_test.go b/generator/if_test.go index dd37d11..6759c37 100644 --- a/generator/if_test.go +++ b/generator/if_test.go @@ -146,7 +146,9 @@ func TestShouldGenerateIfAndElseIfAndElseCode(t *testing.T) { func TestShouldGenerateIfRaisesError(t *testing.T) { _, err := NewIf("").Generate(0) - assert.EqualError(t, err, errmsg.IfConditionIsEmptyError().Error()) + assert.Regexp(t, regexp.MustCompile( + `^\`+strings.Split(errmsg.IfConditionIsEmptyError("").Error(), " ")[0], + ), err.Error()) } func TestShouldGenerateIfElseIfRaisesError(t *testing.T) { diff --git a/internal/errmsg/errmsg.go b/internal/errmsg/errmsg.go index 65eef6d..7749971 100644 --- a/internal/errmsg/errmsg.go +++ b/internal/errmsg/errmsg.go @@ -16,7 +16,7 @@ type errs struct { FuncInvocationParameterIsEmptyError error `errmsg:"a parameter of function invocation must not be nil, but it gets nil (caused at %s)" vars:"caller string"` CodeFormatterError error `errmsg:"code formatter raises error: command=\"%s\", err=\"%s\", msg=\"%s\"" vars:"cmd string, msg string, err error"` CaseConditionIsEmptyError error `errmsg:"condition of case must not be empty, but it gets empty (caused at %s)" vars:"caller string"` - IfConditionIsEmptyError error `errmsg:"condition of if must not be empty, but it gets empty"` + IfConditionIsEmptyError error `errmsg:"condition of if must not be empty, but it gets empty (caused at %s)" vars:"caller string"` UnnamedReturnTypeAppearsAfterNamedReturnTypeError error `errmsg:"unnamed return type appears after named return type (caused at %s)" vars:"caller string"` ValueOfCompositeLiteralIsEmptyError error `errmsg:"a value of composite literal must not be empty, but it gets empty"` } diff --git a/internal/errmsg/errs_errmsg_gen.go b/internal/errmsg/errs_errmsg_gen.go index 8460671..8850047 100644 --- a/internal/errmsg/errs_errmsg_gen.go +++ b/internal/errmsg/errs_errmsg_gen.go @@ -79,8 +79,8 @@ func CaseConditionIsEmptyError(caller string) error { } // IfConditionIsEmptyError returns the error. -func IfConditionIsEmptyError() error { - return errors.New(`[GOWRTR-15] condition of if must not be empty, but it gets empty`) +func IfConditionIsEmptyError(caller string) error { + return fmt.Errorf(`[GOWRTR-15] condition of if must not be empty, but it gets empty (caused at %s)`, caller) } // UnnamedReturnTypeAppearsAfterNamedReturnTypeError returns the error. @@ -95,5 +95,5 @@ func ValueOfCompositeLiteralIsEmptyError() error { // ErrsList returns the list of errors. func ErrsList() []string { - return []string{"[GOWRTR-1] struct name must not be empty, but it gets empty", "[GOWRTR-2] field name must not be empty, but it gets empty", "[GOWRTR-3] field type must not be empty, but it gets empty", "[GOWRTR-4] func parameter name must not be empty, but it gets empty (caused at %s)", "[GOWRTR-5] the last func parameter type must not be empty, but it gets empty (caused at %s)", "[GOWRTR-6] name of func must not be empty, but it gets empty (caused at %s)", "[GOWRTR-7] name of interface must not be empty, but it gets empty", "[GOWRTR-8] name of func receiver must not be empty, but it gets empty (caused at %s)", "[GOWRTR-9] type of func receiver must not be empty, but it gets empty (caused at %s)", "[GOWRTR-10] func signature must not be nil, bit it gets nil (caused at %s)", "[GOWRTR-11] anonymous func signature must not be nil, bit it gets nil (caused at %s)", "[GOWRTR-12] a parameter of function invocation must not be nil, but it gets nil (caused at %s)", "[GOWRTR-13] code formatter raises error: command=\"%s\", err=\"%s\", msg=\"%s\"", "[GOWRTR-14] condition of case must not be empty, but it gets empty (caused at %s)", "[GOWRTR-15] condition of if must not be empty, but it gets empty", "[GOWRTR-16] unnamed return type appears after named return type (caused at %s)", "[GOWRTR-17] a value of composite literal must not be empty, but it gets empty"} + return []string{"[GOWRTR-1] struct name must not be empty, but it gets empty", "[GOWRTR-2] field name must not be empty, but it gets empty", "[GOWRTR-3] field type must not be empty, but it gets empty", "[GOWRTR-4] func parameter name must not be empty, but it gets empty (caused at %s)", "[GOWRTR-5] the last func parameter type must not be empty, but it gets empty (caused at %s)", "[GOWRTR-6] name of func must not be empty, but it gets empty (caused at %s)", "[GOWRTR-7] name of interface must not be empty, but it gets empty", "[GOWRTR-8] name of func receiver must not be empty, but it gets empty (caused at %s)", "[GOWRTR-9] type of func receiver must not be empty, but it gets empty (caused at %s)", "[GOWRTR-10] func signature must not be nil, bit it gets nil (caused at %s)", "[GOWRTR-11] anonymous func signature must not be nil, bit it gets nil (caused at %s)", "[GOWRTR-12] a parameter of function invocation must not be nil, but it gets nil (caused at %s)", "[GOWRTR-13] code formatter raises error: command=\"%s\", err=\"%s\", msg=\"%s\"", "[GOWRTR-14] condition of case must not be empty, but it gets empty (caused at %s)", "[GOWRTR-15] condition of if must not be empty, but it gets empty (caused at %s)", "[GOWRTR-16] unnamed return type appears after named return type (caused at %s)", "[GOWRTR-17] a value of composite literal must not be empty, but it gets empty"} } From 28a86ef358f0dc627c925920cf6e9c7c3043a84c Mon Sep 17 00:00:00 2001 From: moznion Date: Tue, 22 Jan 2019 00:02:45 +0900 Subject: [PATCH 09/14] Support `caused at` on interface generator --- generator/interface.go | 6 +++++- generator/interface_test.go | 4 +++- internal/errmsg/errmsg.go | 2 +- internal/errmsg/errs_errmsg_gen.go | 6 +++--- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/generator/interface.go b/generator/interface.go index 539fbd9..596dee0 100644 --- a/generator/interface.go +++ b/generator/interface.go @@ -10,6 +10,7 @@ import ( type Interface struct { name string funcSignatures []*FuncSignature + caller string } // NewInterface returns a new `Interface`. @@ -17,6 +18,7 @@ func NewInterface(name string, funcSignatures ...*FuncSignature) *Interface { return &Interface{ name: name, funcSignatures: funcSignatures, + caller: fetchClientCallerLine(), } } @@ -26,6 +28,7 @@ func (ig *Interface) AddSignatures(sig ...*FuncSignature) *Interface { return &Interface{ name: ig.name, funcSignatures: append(ig.funcSignatures, sig...), + caller: ig.caller, } } @@ -35,13 +38,14 @@ func (ig *Interface) Signatures(sig ...*FuncSignature) *Interface { return &Interface{ name: ig.name, funcSignatures: sig, + caller: ig.caller, } } // Generate generates `interface` block as golang code. func (ig *Interface) Generate(indentLevel int) (string, error) { if ig.name == "" { - return "", errmsg.InterfaceNameIsEmptyError() + return "", errmsg.InterfaceNameIsEmptyError(ig.caller) } indent := buildIndent(indentLevel) diff --git a/generator/interface_test.go b/generator/interface_test.go index 50c6092..0010fe8 100644 --- a/generator/interface_test.go +++ b/generator/interface_test.go @@ -110,7 +110,9 @@ func TestShouldGeneratingInterfaceCodeWithIndentBeSuccessful(t *testing.T) { func TestShouldRaiseErrorWhenInterfaceNameIsEmpty(t *testing.T) { in := NewInterface("") _, err := in.Generate(0) - assert.EqualError(t, err, errmsg.InterfaceNameIsEmptyError().Error()) + assert.Regexp(t, regexp.MustCompile( + `^\`+strings.Split(errmsg.InterfaceNameIsEmptyError("").Error(), " ")[0], + ), err.Error()) } func TestShouldRaiseErrorWhenFuncSignatureRaisesError(t *testing.T) { diff --git a/internal/errmsg/errmsg.go b/internal/errmsg/errmsg.go index 7749971..ae0e42c 100644 --- a/internal/errmsg/errmsg.go +++ b/internal/errmsg/errmsg.go @@ -8,7 +8,7 @@ type errs struct { FuncParameterNameIsEmptyErr error `errmsg:"func parameter name must not be empty, but it gets empty (caused at %s)" vars:"caller string"` LastFuncParameterTypeIsEmptyErr error `errmsg:"the last func parameter type must not be empty, but it gets empty (caused at %s)" vars:"caller string"` FuncNameIsEmptyError error `errmsg:"name of func must not be empty, but it gets empty (caused at %s)" vars:"caller string"` - InterfaceNameIsEmptyError error `errmsg:"name of interface must not be empty, but it gets empty"` + InterfaceNameIsEmptyError error `errmsg:"name of interface must not be empty, but it gets empty (caused at %s)" vars:"caller string"` FuncReceiverNameIsEmptyError error `errmsg:"name of func receiver must not be empty, but it gets empty (caused at %s)" vars:"caller string"` FuncReceiverTypeIsEmptyError error `errmsg:"type of func receiver must not be empty, but it gets empty (caused at %s)" vars:"caller string"` FuncSignatureIsNilError error `errmsg:"func signature must not be nil, bit it gets nil (caused at %s)" vars:"caller string"` diff --git a/internal/errmsg/errs_errmsg_gen.go b/internal/errmsg/errs_errmsg_gen.go index 8850047..4dd9235 100644 --- a/internal/errmsg/errs_errmsg_gen.go +++ b/internal/errmsg/errs_errmsg_gen.go @@ -39,8 +39,8 @@ func FuncNameIsEmptyError(caller string) error { } // InterfaceNameIsEmptyError returns the error. -func InterfaceNameIsEmptyError() error { - return errors.New(`[GOWRTR-7] name of interface must not be empty, but it gets empty`) +func InterfaceNameIsEmptyError(caller string) error { + return fmt.Errorf(`[GOWRTR-7] name of interface must not be empty, but it gets empty (caused at %s)`, caller) } // FuncReceiverNameIsEmptyError returns the error. @@ -95,5 +95,5 @@ func ValueOfCompositeLiteralIsEmptyError() error { // ErrsList returns the list of errors. func ErrsList() []string { - return []string{"[GOWRTR-1] struct name must not be empty, but it gets empty", "[GOWRTR-2] field name must not be empty, but it gets empty", "[GOWRTR-3] field type must not be empty, but it gets empty", "[GOWRTR-4] func parameter name must not be empty, but it gets empty (caused at %s)", "[GOWRTR-5] the last func parameter type must not be empty, but it gets empty (caused at %s)", "[GOWRTR-6] name of func must not be empty, but it gets empty (caused at %s)", "[GOWRTR-7] name of interface must not be empty, but it gets empty", "[GOWRTR-8] name of func receiver must not be empty, but it gets empty (caused at %s)", "[GOWRTR-9] type of func receiver must not be empty, but it gets empty (caused at %s)", "[GOWRTR-10] func signature must not be nil, bit it gets nil (caused at %s)", "[GOWRTR-11] anonymous func signature must not be nil, bit it gets nil (caused at %s)", "[GOWRTR-12] a parameter of function invocation must not be nil, but it gets nil (caused at %s)", "[GOWRTR-13] code formatter raises error: command=\"%s\", err=\"%s\", msg=\"%s\"", "[GOWRTR-14] condition of case must not be empty, but it gets empty (caused at %s)", "[GOWRTR-15] condition of if must not be empty, but it gets empty (caused at %s)", "[GOWRTR-16] unnamed return type appears after named return type (caused at %s)", "[GOWRTR-17] a value of composite literal must not be empty, but it gets empty"} + return []string{"[GOWRTR-1] struct name must not be empty, but it gets empty", "[GOWRTR-2] field name must not be empty, but it gets empty", "[GOWRTR-3] field type must not be empty, but it gets empty", "[GOWRTR-4] func parameter name must not be empty, but it gets empty (caused at %s)", "[GOWRTR-5] the last func parameter type must not be empty, but it gets empty (caused at %s)", "[GOWRTR-6] name of func must not be empty, but it gets empty (caused at %s)", "[GOWRTR-7] name of interface must not be empty, but it gets empty (caused at %s)", "[GOWRTR-8] name of func receiver must not be empty, but it gets empty (caused at %s)", "[GOWRTR-9] type of func receiver must not be empty, but it gets empty (caused at %s)", "[GOWRTR-10] func signature must not be nil, bit it gets nil (caused at %s)", "[GOWRTR-11] anonymous func signature must not be nil, bit it gets nil (caused at %s)", "[GOWRTR-12] a parameter of function invocation must not be nil, but it gets nil (caused at %s)", "[GOWRTR-13] code formatter raises error: command=\"%s\", err=\"%s\", msg=\"%s\"", "[GOWRTR-14] condition of case must not be empty, but it gets empty (caused at %s)", "[GOWRTR-15] condition of if must not be empty, but it gets empty (caused at %s)", "[GOWRTR-16] unnamed return type appears after named return type (caused at %s)", "[GOWRTR-17] a value of composite literal must not be empty, but it gets empty"} } From c2a947c00a7ed56d540c54cf87e8b8e05be08094 Mon Sep 17 00:00:00 2001 From: moznion Date: Tue, 22 Jan 2019 01:01:30 +0900 Subject: [PATCH 10/14] Support `caused at` on struct generator --- generator/struct.go | 19 ++++++++++++------- generator/struct_test.go | 14 +++++++++++--- internal/errmsg/errmsg.go | 6 +++--- internal/errmsg/errs_errmsg_gen.go | 14 +++++++------- 4 files changed, 33 insertions(+), 20 deletions(-) diff --git a/generator/struct.go b/generator/struct.go index 0631dc3..5a4cd40 100644 --- a/generator/struct.go +++ b/generator/struct.go @@ -15,14 +15,17 @@ type StructField struct { // Struct represents a code generator for `struct` notation. type Struct struct { - name string - fields []*StructField + name string + fields []*StructField + nameCaller string + fieldsCallers []string } // NewStruct returns a new `Struct`. func NewStruct(name string) *Struct { return &Struct{ - name: name, + name: name, + nameCaller: fetchClientCallerLine(), } } @@ -42,24 +45,26 @@ func (sg *Struct) AddField(name string, typ string, tag ...string) *Struct { typ: typ, tag: t, }), + nameCaller: sg.nameCaller, + fieldsCallers: append(sg.fieldsCallers, fetchClientCallerLine()), } } // Generate generates `struct` block as golang code. func (sg *Struct) Generate(indentLevel int) (string, error) { if sg.name == "" { - return "", errmsg.StructNameIsNilErr() + return "", errmsg.StructNameIsNilErr(sg.nameCaller) } indent := buildIndent(indentLevel) stmt := fmt.Sprintf("%stype %s struct {\n", indent, sg.name) - for _, field := range sg.fields { + for i, field := range sg.fields { if field.name == "" { - return "", errmsg.StructFieldNameIsEmptyErr() + return "", errmsg.StructFieldNameIsEmptyErr(sg.fieldsCallers[i]) } if field.typ == "" { - return "", errmsg.StructFieldTypeIsEmptyErr() + return "", errmsg.StructFieldTypeIsEmptyErr(sg.fieldsCallers[i]) } stmt += fmt.Sprintf("%s\t%s %s", indent, field.name, field.typ) diff --git a/generator/struct_test.go b/generator/struct_test.go index 19234a7..2ac4f98 100644 --- a/generator/struct_test.go +++ b/generator/struct_test.go @@ -1,6 +1,8 @@ package generator import ( + "regexp" + "strings" "testing" "github.com/moznion/gowrtr/internal/errmsg" @@ -43,17 +45,23 @@ func TestShouldRaiseErrorWhenStructNameIsEmpty(t *testing.T) { structGenerator := NewStruct("") _, err := structGenerator.Generate(0) - assert.EqualError(t, err, errmsg.StructNameIsNilErr().Error()) + assert.Regexp(t, regexp.MustCompile( + `^\`+strings.Split(errmsg.StructNameIsNilErr("").Error(), " ")[0], + ), err.Error()) } func TestShouldRaiseErrorWhenFieldNameIsEmpty(t *testing.T) { structGenerator := NewStruct("TestStruct").AddField("", "string") _, err := structGenerator.Generate(0) - assert.EqualError(t, err, errmsg.StructFieldNameIsEmptyErr().Error()) + assert.Regexp(t, regexp.MustCompile( + `^\`+strings.Split(errmsg.StructFieldNameIsEmptyErr("").Error(), " ")[0], + ), err.Error()) } func TestShouldRaiseErrorWhenFieldTypeIsEmpty(t *testing.T) { structGenerator := NewStruct("TestStruct").AddField("Foo", "") _, err := structGenerator.Generate(0) - assert.EqualError(t, err, errmsg.StructFieldTypeIsEmptyErr().Error()) + assert.Regexp(t, regexp.MustCompile( + `^\`+strings.Split(errmsg.StructFieldTypeIsEmptyErr("").Error(), " ")[0], + ), err.Error()) } diff --git a/internal/errmsg/errmsg.go b/internal/errmsg/errmsg.go index ae0e42c..9aa6625 100644 --- a/internal/errmsg/errmsg.go +++ b/internal/errmsg/errmsg.go @@ -2,9 +2,9 @@ package errmsg //go:generate errgen -type=errs -prefix=GOWRTR- type errs struct { - StructNameIsNilErr error `errmsg:"struct name must not be empty, but it gets empty"` - StructFieldNameIsEmptyErr error `errmsg:"field name must not be empty, but it gets empty"` - StructFieldTypeIsEmptyErr error `errmsg:"field type must not be empty, but it gets empty"` + StructNameIsNilErr error `errmsg:"struct name must not be empty, but it gets empty (caused at %s)" vars:"caller string"` + StructFieldNameIsEmptyErr error `errmsg:"field name must not be empty, but it gets empty (caused at %s)" vars:"caller string"` + StructFieldTypeIsEmptyErr error `errmsg:"field type must not be empty, but it gets empty (caused at %s)" vars:"caller string"` FuncParameterNameIsEmptyErr error `errmsg:"func parameter name must not be empty, but it gets empty (caused at %s)" vars:"caller string"` LastFuncParameterTypeIsEmptyErr error `errmsg:"the last func parameter type must not be empty, but it gets empty (caused at %s)" vars:"caller string"` FuncNameIsEmptyError error `errmsg:"name of func must not be empty, but it gets empty (caused at %s)" vars:"caller string"` diff --git a/internal/errmsg/errs_errmsg_gen.go b/internal/errmsg/errs_errmsg_gen.go index 4dd9235..1d9ab84 100644 --- a/internal/errmsg/errs_errmsg_gen.go +++ b/internal/errmsg/errs_errmsg_gen.go @@ -9,18 +9,18 @@ import ( ) // StructNameIsNilErr returns the error. -func StructNameIsNilErr() error { - return errors.New(`[GOWRTR-1] struct name must not be empty, but it gets empty`) +func StructNameIsNilErr(caller string) error { + return fmt.Errorf(`[GOWRTR-1] struct name must not be empty, but it gets empty (caused at %s)`, caller) } // StructFieldNameIsEmptyErr returns the error. -func StructFieldNameIsEmptyErr() error { - return errors.New(`[GOWRTR-2] field name must not be empty, but it gets empty`) +func StructFieldNameIsEmptyErr(caller string) error { + return fmt.Errorf(`[GOWRTR-2] field name must not be empty, but it gets empty (caused at %s)`, caller) } // StructFieldTypeIsEmptyErr returns the error. -func StructFieldTypeIsEmptyErr() error { - return errors.New(`[GOWRTR-3] field type must not be empty, but it gets empty`) +func StructFieldTypeIsEmptyErr(caller string) error { + return fmt.Errorf(`[GOWRTR-3] field type must not be empty, but it gets empty (caused at %s)`, caller) } // FuncParameterNameIsEmptyErr returns the error. @@ -95,5 +95,5 @@ func ValueOfCompositeLiteralIsEmptyError() error { // ErrsList returns the list of errors. func ErrsList() []string { - return []string{"[GOWRTR-1] struct name must not be empty, but it gets empty", "[GOWRTR-2] field name must not be empty, but it gets empty", "[GOWRTR-3] field type must not be empty, but it gets empty", "[GOWRTR-4] func parameter name must not be empty, but it gets empty (caused at %s)", "[GOWRTR-5] the last func parameter type must not be empty, but it gets empty (caused at %s)", "[GOWRTR-6] name of func must not be empty, but it gets empty (caused at %s)", "[GOWRTR-7] name of interface must not be empty, but it gets empty (caused at %s)", "[GOWRTR-8] name of func receiver must not be empty, but it gets empty (caused at %s)", "[GOWRTR-9] type of func receiver must not be empty, but it gets empty (caused at %s)", "[GOWRTR-10] func signature must not be nil, bit it gets nil (caused at %s)", "[GOWRTR-11] anonymous func signature must not be nil, bit it gets nil (caused at %s)", "[GOWRTR-12] a parameter of function invocation must not be nil, but it gets nil (caused at %s)", "[GOWRTR-13] code formatter raises error: command=\"%s\", err=\"%s\", msg=\"%s\"", "[GOWRTR-14] condition of case must not be empty, but it gets empty (caused at %s)", "[GOWRTR-15] condition of if must not be empty, but it gets empty (caused at %s)", "[GOWRTR-16] unnamed return type appears after named return type (caused at %s)", "[GOWRTR-17] a value of composite literal must not be empty, but it gets empty"} + return []string{"[GOWRTR-1] struct name must not be empty, but it gets empty (caused at %s)", "[GOWRTR-2] field name must not be empty, but it gets empty (caused at %s)", "[GOWRTR-3] field type must not be empty, but it gets empty (caused at %s)", "[GOWRTR-4] func parameter name must not be empty, but it gets empty (caused at %s)", "[GOWRTR-5] the last func parameter type must not be empty, but it gets empty (caused at %s)", "[GOWRTR-6] name of func must not be empty, but it gets empty (caused at %s)", "[GOWRTR-7] name of interface must not be empty, but it gets empty (caused at %s)", "[GOWRTR-8] name of func receiver must not be empty, but it gets empty (caused at %s)", "[GOWRTR-9] type of func receiver must not be empty, but it gets empty (caused at %s)", "[GOWRTR-10] func signature must not be nil, bit it gets nil (caused at %s)", "[GOWRTR-11] anonymous func signature must not be nil, bit it gets nil (caused at %s)", "[GOWRTR-12] a parameter of function invocation must not be nil, but it gets nil (caused at %s)", "[GOWRTR-13] code formatter raises error: command=\"%s\", err=\"%s\", msg=\"%s\"", "[GOWRTR-14] condition of case must not be empty, but it gets empty (caused at %s)", "[GOWRTR-15] condition of if must not be empty, but it gets empty (caused at %s)", "[GOWRTR-16] unnamed return type appears after named return type (caused at %s)", "[GOWRTR-17] a value of composite literal must not be empty, but it gets empty"} } From 634e9bb0d5c05b870219835ee3f85a78806d580e Mon Sep 17 00:00:00 2001 From: moznion Date: Tue, 22 Jan 2019 01:15:16 +0900 Subject: [PATCH 11/14] Fix errgen tool-chain --- Makefile | 2 +- author/bin/.gitkeep | 0 author/errgen.sh | 7 ------- go.mod | 7 ++++--- internal/vendor.go | 8 ++++++++ 5 files changed, 13 insertions(+), 11 deletions(-) delete mode 100644 author/bin/.gitkeep delete mode 100755 author/errgen.sh create mode 100644 internal/vendor.go diff --git a/Makefile b/Makefile index 55b42e8..2db6a3f 100644 --- a/Makefile +++ b/Makefile @@ -43,5 +43,5 @@ bootstrap: installdeps github.com/moznion/go-errgen/cmd/errgen errgen: - ./author/errgen.sh + go generate ./... diff --git a/author/bin/.gitkeep b/author/bin/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/author/errgen.sh b/author/errgen.sh deleted file mode 100755 index ff6b69b..0000000 --- a/author/errgen.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -CURRENT_PATH="$(cd "$(dirname "$0")" || exit; pwd)" -PATH="$CURRENT_PATH/bin:$PATH" - -(cd "$CURRENT_PATH/.." && go generate ./...) - diff --git a/go.mod b/go.mod index d993290..9e8fc6a 100644 --- a/go.mod +++ b/go.mod @@ -1,8 +1,9 @@ module github.com/moznion/gowrtr require ( - github.com/moznion/go-errgen v1.3.1 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/moznion/go-errgen v1.3.2 github.com/stretchr/testify v1.3.0 - golang.org/x/lint v0.0.0-20181217174547-8f45f776aaf1 // indirect - golang.org/x/tools v0.0.0-20190111214448-fc1d57b08d7b // indirect + golang.org/x/lint v0.0.0-20181217174547-8f45f776aaf1 + golang.org/x/tools v0.0.0-20190121143147-24cd39ecf745 // indirect ) diff --git a/internal/vendor.go b/internal/vendor.go new file mode 100644 index 0000000..d1e82fe --- /dev/null +++ b/internal/vendor.go @@ -0,0 +1,8 @@ +package internal + +import ( + // For vendoring + _ "github.com/moznion/go-errgen" + // For vendoring + _ "golang.org/x/lint" +) From af72e33a37b8c64a3a08067364160ccac5ae32a4 Mon Sep 17 00:00:00 2001 From: moznion Date: Tue, 22 Jan 2019 01:38:29 +0900 Subject: [PATCH 12/14] :pencil: doc --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index 8606be4..20ab0c3 100644 --- a/README.md +++ b/README.md @@ -74,6 +74,16 @@ Please refer to the godoc: [![GoDoc](https://godoc.org/github.com/moznion/gowrtr Methods of this library act as immutable. It means it doesn't change any internal state implicitly, so you can take a snapshot of the code generator. That is useful to reuse and derive the code generator instance. +### Debug friendly + +This library shows "where is a cause of the error" when code generator raises an error. This means each error message contains a pointer for the error source (i.e. file name and the line number). This should be helpful for debugging. + +Error messages example: + +``` +[GOWRTR-14] condition of case must not be empty, but it gets empty (caused at /tmp/main.go:22) +``` + ### Supported syntax - [x] `package` From f02a8fe86636514a3b48432506df7dd96beb751f Mon Sep 17 00:00:00 2001 From: moznion Date: Tue, 22 Jan 2019 01:49:44 +0900 Subject: [PATCH 13/14] Add test cases for frame_fetcher --- generator/frame_fetcher.go | 7 +++++-- generator/frame_fetcher_test.go | 18 ++++++++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 generator/frame_fetcher_test.go diff --git a/generator/frame_fetcher.go b/generator/frame_fetcher.go index d7c48a8..f9c2cd2 100644 --- a/generator/frame_fetcher.go +++ b/generator/frame_fetcher.go @@ -11,6 +11,8 @@ func fetchClientCallerLine(skip ...int) string { if len(skip) > 0 { s = skip[0] } + + caller := "" for { pc, file, line, ok := runtime.Caller(s) f := runtime.FuncForPC(pc) @@ -23,10 +25,11 @@ func fetchClientCallerLine(skip ...int) string { break } - return fmt.Sprintf("%s:%d", file, line) + caller = fmt.Sprintf("%s:%d", file, line) + break } - return "" + return caller } func fetchClientCallerLineAsSlice(size int, skip ...int) []string { diff --git a/generator/frame_fetcher_test.go b/generator/frame_fetcher_test.go new file mode 100644 index 0000000..e0fe247 --- /dev/null +++ b/generator/frame_fetcher_test.go @@ -0,0 +1,18 @@ +package generator + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestFetchClientCallerLineShouldBeNG(t *testing.T) { + caller := fetchClientCallerLine(10000) + assert.Empty(t, caller) +} + +func TestFetchCallerLineAsSliceShouldBeNG(t *testing.T) { + callers := fetchClientCallerLineAsSlice(1, 10000) + assert.Len(t, callers, 1) + assert.Empty(t, callers[0]) +} From bbb6ce9bc8f54e276695dec5aa73dadfbaab3a9a Mon Sep 17 00:00:00 2001 From: moznion Date: Tue, 22 Jan 2019 02:13:59 +0900 Subject: [PATCH 14/14] Support `caused at` on composite literal generator --- generator/composite_literal.go | 12 ++++++++---- generator/composite_literal_test.go | 4 +++- internal/errmsg/errmsg.go | 2 +- internal/errmsg/errs_errmsg_gen.go | 11 ++++------- 4 files changed, 16 insertions(+), 13 deletions(-) diff --git a/generator/composite_literal.go b/generator/composite_literal.go index a78501a..02ddc6a 100644 --- a/generator/composite_literal.go +++ b/generator/composite_literal.go @@ -15,8 +15,9 @@ type compositeLiteralField struct { // CompositeLiteral represents a code generator for composite literal. // Please see also: https://golang.org/doc/effective_go.html#composite_literals type CompositeLiteral struct { - typ string - fields []*compositeLiteralField + typ string + fields []*compositeLiteralField + callers []string } // NewCompositeLiteral returns a new `CompositeLiteral`. @@ -35,6 +36,7 @@ func (c *CompositeLiteral) AddField(key string, value Statement) *CompositeLiter key: key, value: value, }), + callers: append(c.callers, fetchClientCallerLine()), } } @@ -47,6 +49,7 @@ func (c *CompositeLiteral) AddFieldStr(key string, value string) *CompositeLiter key: key, value: NewRawStatement(fmt.Sprintf(`"%s"`, value)), }), + callers: append(c.callers, fetchClientCallerLine()), } } @@ -59,6 +62,7 @@ func (c *CompositeLiteral) AddFieldRaw(key string, value interface{}) *Composite key: key, value: NewRawStatement(fmt.Sprintf("%v", value)), }), + callers: append(c.callers, fetchClientCallerLine()), } } @@ -68,7 +72,7 @@ func (c *CompositeLiteral) Generate(indentLevel int) (string, error) { nextLevelIndent := buildIndent(indentLevel + 1) stmt := fmt.Sprintf("%s%s{\n", indent, c.typ) - for _, field := range c.fields { + for i, field := range c.fields { genValue, err := field.value.Generate(indentLevel + 1) if err != nil { return "", err @@ -82,7 +86,7 @@ func (c *CompositeLiteral) Generate(indentLevel int) (string, error) { stmt += key + ": " } if genValue == "" { - return "", errmsg.ValueOfCompositeLiteralIsEmptyError() + return "", errmsg.ValueOfCompositeLiteralIsEmptyError(c.callers[i]) } stmt += fmt.Sprintf("%s,\n", genValue) } diff --git a/generator/composite_literal_test.go b/generator/composite_literal_test.go index f5955ec..bdbb184 100644 --- a/generator/composite_literal_test.go +++ b/generator/composite_literal_test.go @@ -82,5 +82,7 @@ func TestShouldGenerateCompositeLiteralRaiseError(t *testing.T) { func TestShouldGenerateCompositeLiteralRaiseErrorWhenValueIsEmpty(t *testing.T) { _, err := NewCompositeLiteral("[]string").AddField("foo", NewRawStatement("")).Generate(0) - assert.EqualError(t, err, errmsg.ValueOfCompositeLiteralIsEmptyError().Error()) + assert.Regexp(t, regexp.MustCompile( + `^\`+strings.Split(errmsg.ValueOfCompositeLiteralIsEmptyError("").Error(), " ")[0], + ), err.Error()) } diff --git a/internal/errmsg/errmsg.go b/internal/errmsg/errmsg.go index 9aa6625..bd5bc8b 100644 --- a/internal/errmsg/errmsg.go +++ b/internal/errmsg/errmsg.go @@ -18,5 +18,5 @@ type errs struct { CaseConditionIsEmptyError error `errmsg:"condition of case must not be empty, but it gets empty (caused at %s)" vars:"caller string"` IfConditionIsEmptyError error `errmsg:"condition of if must not be empty, but it gets empty (caused at %s)" vars:"caller string"` UnnamedReturnTypeAppearsAfterNamedReturnTypeError error `errmsg:"unnamed return type appears after named return type (caused at %s)" vars:"caller string"` - ValueOfCompositeLiteralIsEmptyError error `errmsg:"a value of composite literal must not be empty, but it gets empty"` + ValueOfCompositeLiteralIsEmptyError error `errmsg:"a value of composite literal must not be empty, but it gets empty (caused at %s)" vars:"caller string"` } diff --git a/internal/errmsg/errs_errmsg_gen.go b/internal/errmsg/errs_errmsg_gen.go index 1d9ab84..1df7589 100644 --- a/internal/errmsg/errs_errmsg_gen.go +++ b/internal/errmsg/errs_errmsg_gen.go @@ -3,10 +3,7 @@ package errmsg -import ( - "errors" - "fmt" -) +import "fmt" // StructNameIsNilErr returns the error. func StructNameIsNilErr(caller string) error { @@ -89,11 +86,11 @@ func UnnamedReturnTypeAppearsAfterNamedReturnTypeError(caller string) error { } // ValueOfCompositeLiteralIsEmptyError returns the error. -func ValueOfCompositeLiteralIsEmptyError() error { - return errors.New(`[GOWRTR-17] a value of composite literal must not be empty, but it gets empty`) +func ValueOfCompositeLiteralIsEmptyError(caller string) error { + return fmt.Errorf(`[GOWRTR-17] a value of composite literal must not be empty, but it gets empty (caused at %s)`, caller) } // ErrsList returns the list of errors. func ErrsList() []string { - return []string{"[GOWRTR-1] struct name must not be empty, but it gets empty (caused at %s)", "[GOWRTR-2] field name must not be empty, but it gets empty (caused at %s)", "[GOWRTR-3] field type must not be empty, but it gets empty (caused at %s)", "[GOWRTR-4] func parameter name must not be empty, but it gets empty (caused at %s)", "[GOWRTR-5] the last func parameter type must not be empty, but it gets empty (caused at %s)", "[GOWRTR-6] name of func must not be empty, but it gets empty (caused at %s)", "[GOWRTR-7] name of interface must not be empty, but it gets empty (caused at %s)", "[GOWRTR-8] name of func receiver must not be empty, but it gets empty (caused at %s)", "[GOWRTR-9] type of func receiver must not be empty, but it gets empty (caused at %s)", "[GOWRTR-10] func signature must not be nil, bit it gets nil (caused at %s)", "[GOWRTR-11] anonymous func signature must not be nil, bit it gets nil (caused at %s)", "[GOWRTR-12] a parameter of function invocation must not be nil, but it gets nil (caused at %s)", "[GOWRTR-13] code formatter raises error: command=\"%s\", err=\"%s\", msg=\"%s\"", "[GOWRTR-14] condition of case must not be empty, but it gets empty (caused at %s)", "[GOWRTR-15] condition of if must not be empty, but it gets empty (caused at %s)", "[GOWRTR-16] unnamed return type appears after named return type (caused at %s)", "[GOWRTR-17] a value of composite literal must not be empty, but it gets empty"} + return []string{"[GOWRTR-1] struct name must not be empty, but it gets empty (caused at %s)", "[GOWRTR-2] field name must not be empty, but it gets empty (caused at %s)", "[GOWRTR-3] field type must not be empty, but it gets empty (caused at %s)", "[GOWRTR-4] func parameter name must not be empty, but it gets empty (caused at %s)", "[GOWRTR-5] the last func parameter type must not be empty, but it gets empty (caused at %s)", "[GOWRTR-6] name of func must not be empty, but it gets empty (caused at %s)", "[GOWRTR-7] name of interface must not be empty, but it gets empty (caused at %s)", "[GOWRTR-8] name of func receiver must not be empty, but it gets empty (caused at %s)", "[GOWRTR-9] type of func receiver must not be empty, but it gets empty (caused at %s)", "[GOWRTR-10] func signature must not be nil, bit it gets nil (caused at %s)", "[GOWRTR-11] anonymous func signature must not be nil, bit it gets nil (caused at %s)", "[GOWRTR-12] a parameter of function invocation must not be nil, but it gets nil (caused at %s)", "[GOWRTR-13] code formatter raises error: command=\"%s\", err=\"%s\", msg=\"%s\"", "[GOWRTR-14] condition of case must not be empty, but it gets empty (caused at %s)", "[GOWRTR-15] condition of if must not be empty, but it gets empty (caused at %s)", "[GOWRTR-16] unnamed return type appears after named return type (caused at %s)", "[GOWRTR-17] a value of composite literal must not be empty, but it gets empty (caused at %s)"} }