diff --git a/assert.go b/assert.go index 9cc0506..bc6db8b 100644 --- a/assert.go +++ b/assert.go @@ -1,58 +1,48 @@ package cute import ( - "fmt" "net/http" - "runtime" ) // This is type of asserts, for create some assert with using custom logic. -// AssertBody ... +// AssertBody is type for create custom assertions for body +// Example asserts: +// - json.LengthGreaterThan +// - json.LengthGreaterOrEqualThan +// - json.LengthLessThan +// - json.LengthLessOrEqualThan +// - json.Present +// - json.NotEmpty +// - json.NotPresent type AssertBody func(body []byte) error -// AssertHeaders ... +// AssertHeaders is type for create custom assertions for headers +// Example asserts: +// - headers.Present +// - headers.NotPresent type AssertHeaders func(headers http.Header) error -// AssertResponse ... +// AssertResponse is type for create custom assertions for response type AssertResponse func(response *http.Response) error // This is type for create custom assertions with using allure and testing.allureProvider -// AssertBodyT ... +// AssertBodyT is type for create custom assertions for body with TB +// Check example in AssertBody +// TB is testing.T and it can be used for require ore assert from testify or another packages type AssertBodyT func(t T, body []byte) error -// AssertHeadersT ... +// AssertHeadersT is type for create custom assertions for headers with TB +// Check example in AssertHeaders +// TB is testing.T and it can be used for require ore assert from testify or another packages type AssertHeadersT func(t T, headers http.Header) error -// AssertResponseT ... +// AssertResponseT is type for create custom assertions for response with TB +// Check example in AssertResponse +// TB is testing.T and it can be used for require ore assert from testify or another packages type AssertResponseT func(t T, response *http.Response) error -func callAssertWrapper(assert AssertBody, withCall string) func(body []byte) error { - return func(body []byte) error { - err := assert(body) - - if err != nil { - return fmt.Errorf("%w\n%s", err, withCall) - } - - return nil - } -} - -func getCaller() string { - pcs := make([]uintptr, 10) - depth := runtime.Callers(3, pcs) - if depth == 0 { - fmt.Println("Couldn't get the stack information") - return "" - } - callers := runtime.CallersFrames(pcs[:depth]) - caller, _ := callers.Next() - - return fmt.Sprintf("Called from: %s:%d\n", caller.File, caller.Line) -} - func (it *Test) assertHeaders(t internalT, headers http.Header) []error { var ( asserts = it.Expect.AssertHeaders diff --git a/assert_broken.go b/assert_broken.go index b40ed5d..d64383e 100644 --- a/assert_broken.go +++ b/assert_broken.go @@ -54,20 +54,6 @@ func brokenAssertResponseT(assert AssertResponseT) AssertResponseT { } } -func wrapWithTrace(err error, trace string) error { - if err == nil { - return nil - } - - if tErr, ok := err.(errors.WithTrace); ok { - tErr.SetTrace(trace) - - return tErr.(error) - } - - return errors.WrapErrorWithTrace(err, trace) -} - func wrapBrokenError(err error) error { if err == nil { return nil diff --git a/assert_trace.go b/assert_trace.go new file mode 100644 index 0000000..ae8faae --- /dev/null +++ b/assert_trace.go @@ -0,0 +1,91 @@ +package cute + +import ( + "fmt" + "net/http" + "runtime" + + "github.com/ozontech/cute/errors" +) + +// assertHeadersWithTrace is a function to add trace inside assert headers error +func assertHeadersWithTrace(assert AssertHeaders, trace string) AssertHeaders { + return func(headers http.Header) error { + err := assert(headers) + + return wrapWithTrace(err, trace) + } +} + +// assertBodyWithTrace is a function to add trace inside assert body error +func assertBodyWithTrace(assert AssertBody, trace string) AssertBody { + return func(body []byte) error { + err := assert(body) + + return wrapWithTrace(err, trace) + } +} + +// assertResponseWithTrace is a function to add trace inside assert response error +func assertResponseWithTrace(assert AssertResponse, trace string) AssertResponse { + return func(resp *http.Response) error { + err := assert(resp) + + return wrapWithTrace(err, trace) + } +} + +// assertHeadersTWithTrace is a function to add trace inside assert headers error +func assertHeadersTWithTrace(assert AssertHeadersT, trace string) AssertHeadersT { + return func(t T, headers http.Header) error { + err := assert(t, headers) + + return wrapWithTrace(err, trace) + } +} + +// assertBodyTWithTrace is a function to add trace inside assert body error +func assertBodyTWithTrace(assert AssertBodyT, trace string) AssertBodyT { + return func(t T, body []byte) error { + err := assert(t, body) + + return wrapWithTrace(err, trace) + } +} + +// assertResponseTWithTrace is a function to add trace inside assert response error +func assertResponseTWithTrace(assert AssertResponseT, trace string) AssertResponseT { + return func(t T, resp *http.Response) error { + err := assert(t, resp) + + return wrapWithTrace(err, trace) + } +} + +// wrapWithTrace is a function to add trace inside error +func wrapWithTrace(err error, trace string) error { + if err == nil { + return nil + } + + if tErr, ok := err.(errors.WithTrace); ok { + tErr.SetTrace(trace) + + return tErr.(error) + } + + return errors.WrapErrorWithTrace(err, trace) +} + +func getTrace() string { + pcs := make([]uintptr, 10) + depth := runtime.Callers(3, pcs) + if depth == 0 { + fmt.Println("Couldn't get the stack information") + return "" + } + callers := runtime.CallersFrames(pcs[:depth]) + caller, _ := callers.Next() + + return fmt.Sprintf("%s:%d", caller.File, caller.Line) +} diff --git a/builder_asserts.go b/builder_asserts.go index 17842c3..343625e 100644 --- a/builder_asserts.go +++ b/builder_asserts.go @@ -3,288 +3,336 @@ package cute import "time" func (qt *cute) AssertBody(asserts ...AssertBody) ExpectHTTPBuilder { + trace := getTrace() + for _, assert := range asserts { if assert == nil { panic(errorAssertIsNil) } - qt.tests[qt.countTests].Expect.AssertBody = append(qt.tests[qt.countTests].Expect.AssertBody, assert) + qt.tests[qt.countTests].Expect.AssertBody = append(qt.tests[qt.countTests].Expect.AssertBody, assertBodyWithTrace(assert, trace)) } return qt } func (qt *cute) OptionalAssertBody(asserts ...AssertBody) ExpectHTTPBuilder { + trace := getTrace() + for _, assert := range asserts { if assert == nil { panic(errorAssertIsNil) } - qt.tests[qt.countTests].Expect.AssertBody = append(qt.tests[qt.countTests].Expect.AssertBody, optionalAssertBody(assert)) + qt.tests[qt.countTests].Expect.AssertBody = append(qt.tests[qt.countTests].Expect.AssertBody, assertBodyWithTrace(optionalAssertBody(assert), trace)) } return qt } func (qt *cute) BrokenAssertBody(asserts ...AssertBody) ExpectHTTPBuilder { + trace := getTrace() + for _, assert := range asserts { if assert == nil { panic(errorAssertIsNil) } - qt.tests[qt.countTests].Expect.AssertBody = append(qt.tests[qt.countTests].Expect.AssertBody, brokenAssertBody(assert)) + qt.tests[qt.countTests].Expect.AssertBody = append(qt.tests[qt.countTests].Expect.AssertBody, assertBodyWithTrace(brokenAssertBody(assert), trace)) } return qt } func (qt *cute) RequireBody(asserts ...AssertBody) ExpectHTTPBuilder { + trace := getTrace() + for _, assert := range asserts { if assert == nil { panic(errorAssertIsNil) } - qt.tests[qt.countTests].Expect.AssertBody = append(qt.tests[qt.countTests].Expect.AssertBody, requireAssertBody(assert)) + qt.tests[qt.countTests].Expect.AssertBody = append(qt.tests[qt.countTests].Expect.AssertBody, assertBodyWithTrace(requireAssertBody(assert), trace)) } return qt } func (qt *cute) AssertHeaders(asserts ...AssertHeaders) ExpectHTTPBuilder { + trace := getTrace() + for _, assert := range asserts { if assert == nil { panic(errorAssertIsNil) } - qt.tests[qt.countTests].Expect.AssertHeaders = append(qt.tests[qt.countTests].Expect.AssertHeaders, assert) + qt.tests[qt.countTests].Expect.AssertHeaders = append(qt.tests[qt.countTests].Expect.AssertHeaders, assertHeadersWithTrace(assert, trace)) } return qt } func (qt *cute) OptionalAssertHeaders(asserts ...AssertHeaders) ExpectHTTPBuilder { + trace := getTrace() + for _, assert := range asserts { if assert == nil { panic(errorAssertIsNil) } - qt.tests[qt.countTests].Expect.AssertHeaders = append(qt.tests[qt.countTests].Expect.AssertHeaders, optionalAssertHeaders(assert)) + qt.tests[qt.countTests].Expect.AssertHeaders = append(qt.tests[qt.countTests].Expect.AssertHeaders, assertHeadersWithTrace(optionalAssertHeaders(assert), trace)) } return qt } func (qt *cute) RequireHeaders(asserts ...AssertHeaders) ExpectHTTPBuilder { + trace := getTrace() + for _, assert := range asserts { if assert == nil { panic(errorAssertIsNil) } - qt.tests[qt.countTests].Expect.AssertHeaders = append(qt.tests[qt.countTests].Expect.AssertHeaders, requireAssertHeaders(assert)) + qt.tests[qt.countTests].Expect.AssertHeaders = append(qt.tests[qt.countTests].Expect.AssertHeaders, assertHeadersWithTrace(requireAssertHeaders(assert), trace)) } return qt } func (qt *cute) BrokenAssertHeaders(asserts ...AssertHeaders) ExpectHTTPBuilder { + trace := getTrace() + for _, assert := range asserts { if assert == nil { panic(errorAssertIsNil) } - qt.tests[qt.countTests].Expect.AssertHeaders = append(qt.tests[qt.countTests].Expect.AssertHeaders, brokenAssertHeaders(assert)) + qt.tests[qt.countTests].Expect.AssertHeaders = append(qt.tests[qt.countTests].Expect.AssertHeaders, assertHeadersWithTrace(brokenAssertHeaders(assert), trace)) } return qt } func (qt *cute) AssertResponse(asserts ...AssertResponse) ExpectHTTPBuilder { + trace := getTrace() + for _, assert := range asserts { if assert == nil { panic(errorAssertIsNil) } - qt.tests[qt.countTests].Expect.AssertResponse = append(qt.tests[qt.countTests].Expect.AssertResponse, assert) + qt.tests[qt.countTests].Expect.AssertResponse = append(qt.tests[qt.countTests].Expect.AssertResponse, assertResponseWithTrace(assert, trace)) } return qt } func (qt *cute) OptionalAssertResponse(asserts ...AssertResponse) ExpectHTTPBuilder { + trace := getTrace() + for _, assert := range asserts { if assert == nil { panic(errorAssertIsNil) } - qt.tests[qt.countTests].Expect.AssertResponse = append(qt.tests[qt.countTests].Expect.AssertResponse, optionalAssertResponse(assert)) + qt.tests[qt.countTests].Expect.AssertResponse = append(qt.tests[qt.countTests].Expect.AssertResponse, assertResponseWithTrace(optionalAssertResponse(assert), trace)) } return qt } func (qt *cute) RequireResponse(asserts ...AssertResponse) ExpectHTTPBuilder { + trace := getTrace() + for _, assert := range asserts { if assert == nil { panic(errorAssertIsNil) } - qt.tests[qt.countTests].Expect.AssertResponse = append(qt.tests[qt.countTests].Expect.AssertResponse, requireAssertResponse(assert)) + qt.tests[qt.countTests].Expect.AssertResponse = append(qt.tests[qt.countTests].Expect.AssertResponse, assertResponseWithTrace(requireAssertResponse(assert), trace)) } return qt } func (qt *cute) BrokenAssertResponse(asserts ...AssertResponse) ExpectHTTPBuilder { + trace := getTrace() + for _, assert := range asserts { if assert == nil { panic(errorAssertIsNil) } - qt.tests[qt.countTests].Expect.AssertResponse = append(qt.tests[qt.countTests].Expect.AssertResponse, brokenAssertResponse(assert)) + qt.tests[qt.countTests].Expect.AssertResponse = append(qt.tests[qt.countTests].Expect.AssertResponse, assertResponseWithTrace(brokenAssertResponse(assert), trace)) } return qt } func (qt *cute) AssertBodyT(asserts ...AssertBodyT) ExpectHTTPBuilder { + trace := getTrace() + for _, assert := range asserts { if assert == nil { panic(errorAssertIsNil) } - qt.tests[qt.countTests].Expect.AssertBodyT = append(qt.tests[qt.countTests].Expect.AssertBodyT, assert) + qt.tests[qt.countTests].Expect.AssertBodyT = append(qt.tests[qt.countTests].Expect.AssertBodyT, assertBodyTWithTrace(assert, trace)) } return qt } func (qt *cute) OptionalAssertBodyT(asserts ...AssertBodyT) ExpectHTTPBuilder { + trace := getTrace() + for _, assert := range asserts { if assert == nil { panic(errorAssertIsNil) } - qt.tests[qt.countTests].Expect.AssertBodyT = append(qt.tests[qt.countTests].Expect.AssertBodyT, optionalAssertBodyT(assert)) + qt.tests[qt.countTests].Expect.AssertBodyT = append(qt.tests[qt.countTests].Expect.AssertBodyT, assertBodyTWithTrace(optionalAssertBodyT(assert), trace)) } return qt } func (qt *cute) BrokenAssertBodyT(asserts ...AssertBodyT) ExpectHTTPBuilder { + trace := getTrace() + for _, assert := range asserts { if assert == nil { panic(errorAssertIsNil) } - qt.tests[qt.countTests].Expect.AssertBodyT = append(qt.tests[qt.countTests].Expect.AssertBodyT, brokenAssertBodyT(assert)) + qt.tests[qt.countTests].Expect.AssertBodyT = append(qt.tests[qt.countTests].Expect.AssertBodyT, assertBodyTWithTrace(brokenAssertBodyT(assert), trace)) } return qt } func (qt *cute) RequireBodyT(asserts ...AssertBodyT) ExpectHTTPBuilder { + trace := getTrace() + for _, assert := range asserts { if assert == nil { panic(errorAssertIsNil) } - qt.tests[qt.countTests].Expect.AssertBodyT = append(qt.tests[qt.countTests].Expect.AssertBodyT, requireAssertBodyT(assert)) + qt.tests[qt.countTests].Expect.AssertBodyT = append(qt.tests[qt.countTests].Expect.AssertBodyT, assertBodyTWithTrace(requireAssertBodyT(assert), trace)) } return qt } func (qt *cute) AssertHeadersT(asserts ...AssertHeadersT) ExpectHTTPBuilder { + trace := getTrace() + for _, assert := range asserts { if assert == nil { panic(errorAssertIsNil) } - } - qt.tests[qt.countTests].Expect.AssertHeadersT = append(qt.tests[qt.countTests].Expect.AssertHeadersT, asserts...) + qt.tests[qt.countTests].Expect.AssertHeadersT = append(qt.tests[qt.countTests].Expect.AssertHeadersT, assertHeadersTWithTrace(assert, trace)) + } return qt } func (qt *cute) OptionalAssertHeadersT(asserts ...AssertHeadersT) ExpectHTTPBuilder { + trace := getTrace() + for _, assert := range asserts { if assert == nil { panic(errorAssertIsNil) } - qt.tests[qt.countTests].Expect.AssertHeadersT = append(qt.tests[qt.countTests].Expect.AssertHeadersT, optionalAssertHeadersT(assert)) + qt.tests[qt.countTests].Expect.AssertHeadersT = append(qt.tests[qt.countTests].Expect.AssertHeadersT, assertHeadersTWithTrace(optionalAssertHeadersT(assert), trace)) } return qt } func (qt *cute) RequireHeadersT(asserts ...AssertHeadersT) ExpectHTTPBuilder { + trace := getTrace() + for _, assert := range asserts { if assert == nil { panic(errorAssertIsNil) } - qt.tests[qt.countTests].Expect.AssertHeadersT = append(qt.tests[qt.countTests].Expect.AssertHeadersT, requireAssertHeadersT(assert)) + qt.tests[qt.countTests].Expect.AssertHeadersT = append(qt.tests[qt.countTests].Expect.AssertHeadersT, assertHeadersTWithTrace(requireAssertHeadersT(assert), trace)) } return qt } func (qt *cute) BrokenAssertHeadersT(asserts ...AssertHeadersT) ExpectHTTPBuilder { + trace := getTrace() + for _, assert := range asserts { if assert == nil { panic(errorAssertIsNil) } - qt.tests[qt.countTests].Expect.AssertHeadersT = append(qt.tests[qt.countTests].Expect.AssertHeadersT, brokenAssertHeadersT(assert)) + qt.tests[qt.countTests].Expect.AssertHeadersT = append(qt.tests[qt.countTests].Expect.AssertHeadersT, assertHeadersTWithTrace(brokenAssertHeadersT(assert), trace)) } return qt } func (qt *cute) AssertResponseT(asserts ...AssertResponseT) ExpectHTTPBuilder { + trace := getTrace() + for _, assert := range asserts { if assert == nil { panic(errorAssertIsNil) } - } - qt.tests[qt.countTests].Expect.AssertResponseT = append(qt.tests[qt.countTests].Expect.AssertResponseT, asserts...) + qt.tests[qt.countTests].Expect.AssertResponseT = append(qt.tests[qt.countTests].Expect.AssertResponseT, assertResponseTWithTrace(assert, trace)) + } return qt } func (qt *cute) OptionalAssertResponseT(asserts ...AssertResponseT) ExpectHTTPBuilder { + trace := getTrace() + for _, assert := range asserts { if assert == nil { panic(errorAssertIsNil) } - qt.tests[qt.countTests].Expect.AssertResponseT = append(qt.tests[qt.countTests].Expect.AssertResponseT, optionalAssertResponseT(assert)) + qt.tests[qt.countTests].Expect.AssertResponseT = append(qt.tests[qt.countTests].Expect.AssertResponseT, assertResponseTWithTrace(optionalAssertResponseT(assert), trace)) } return qt } func (qt *cute) BrokenAssertResponseT(asserts ...AssertResponseT) ExpectHTTPBuilder { + trace := getTrace() + for _, assert := range asserts { if assert == nil { panic(errorAssertIsNil) } - qt.tests[qt.countTests].Expect.AssertResponseT = append(qt.tests[qt.countTests].Expect.AssertResponseT, brokenAssertResponseT(assert)) + qt.tests[qt.countTests].Expect.AssertResponseT = append(qt.tests[qt.countTests].Expect.AssertResponseT, assertResponseTWithTrace(brokenAssertResponseT(assert), trace)) } return qt } func (qt *cute) RequireResponseT(asserts ...AssertResponseT) ExpectHTTPBuilder { + trace := getTrace() + for _, assert := range asserts { if assert == nil { panic(errorAssertIsNil) } - qt.tests[qt.countTests].Expect.AssertResponseT = append(qt.tests[qt.countTests].Expect.AssertResponseT, requireAssertResponseT(assert)) + qt.tests[qt.countTests].Expect.AssertResponseT = append(qt.tests[qt.countTests].Expect.AssertResponseT, assertResponseTWithTrace(requireAssertResponseT(assert), trace)) } return qt diff --git a/errors/error.go b/errors/error.go index e4e3c98..d7ff7c3 100644 --- a/errors/error.go +++ b/errors/error.go @@ -63,7 +63,7 @@ type CuteError struct { // NewAssertError is the function, which creates error with "Actual" and "Expected" for allure func NewAssertError(name string, message string, actual interface{}, expected interface{}) error { - return CuteError{ + return &CuteError{ Name: name, Message: message, Fields: map[string]interface{}{ @@ -75,7 +75,7 @@ func NewAssertError(name string, message string, actual interface{}, expected in // NewAssertErrorWithMessage ... func NewAssertErrorWithMessage(name string, message string) error { - return CuteError{ + return &CuteError{ Name: name, Message: message, } @@ -83,18 +83,18 @@ func NewAssertErrorWithMessage(name string, message string) error { // NewEmptyAssertError ... func NewEmptyAssertError(name string, message string) AssertError { - return CuteError{ + return &CuteError{ Name: name, Message: message, Fields: map[string]interface{}{}, } } -func (a CuteError) Unwrap() error { +func (a *CuteError) Unwrap() error { return a.Err } -func (a CuteError) Error() string { +func (a *CuteError) Error() string { if a.Trace == "" { return a.Message } @@ -105,63 +105,63 @@ func (a CuteError) Error() string { errText = a.Err.Error() } - return fmt.Sprintf("%s\nCalled from:%S", errText, a.Trace) + return fmt.Sprintf("%s\nCalled from: %s", errText, a.Trace) } -func (a CuteError) GetName() string { +func (a *CuteError) GetName() string { return a.Name } -func (a CuteError) SetName(name string) { +func (a *CuteError) SetName(name string) { a.Name = name } -func (a CuteError) GetFields() map[string]interface{} { +func (a *CuteError) GetFields() map[string]interface{} { return a.Fields } -func (a CuteError) PutFields(fields map[string]interface{}) { +func (a *CuteError) PutFields(fields map[string]interface{}) { for k, v := range fields { a.Fields[k] = v } } -func (a CuteError) GetAttachments() []*Attachment { +func (a *CuteError) GetAttachments() []*Attachment { return a.Attachments } -func (a CuteError) PutAttachment(attachment *Attachment) { +func (a *CuteError) PutAttachment(attachment *Attachment) { a.Attachments = append(a.Attachments, attachment) } -func (a CuteError) IsOptional() bool { +func (a *CuteError) IsOptional() bool { return a.Optional } -func (a CuteError) SetOptional(opt bool) { +func (a *CuteError) SetOptional(opt bool) { a.Optional = opt } -func (a CuteError) IsRequire() bool { +func (a *CuteError) IsRequire() bool { return a.Require } -func (a CuteError) SetRequire(b bool) { +func (a *CuteError) SetRequire(b bool) { a.Require = b } -func (a CuteError) IsBroken() bool { +func (a *CuteError) IsBroken() bool { return a.Broken } -func (a CuteError) SetBroken(b bool) { +func (a *CuteError) SetBroken(b bool) { a.Broken = b } -func (a CuteError) GetTrace() string { +func (a *CuteError) GetTrace() string { return a.Trace } -func (a CuteError) SetTrace(trace string) { +func (a *CuteError) SetTrace(trace string) { a.Trace = trace } diff --git a/examples/suite/main_test.go b/examples/suite/main_test.go index 4bc0d5a..c7631dd 100644 --- a/examples/suite/main_test.go +++ b/examples/suite/main_test.go @@ -14,8 +14,3 @@ func TestExampleSuite(t *testing.T) { os.Setenv("ALLURE_OUTPUT_PATH", "../") // custom, read Readme.md for more info suite.RunSuite(t, new(ExampleSuite)) } - -func TestExampleSuite1(t *testing.T) { - os.Setenv("ALLURE_OUTPUT_PATH", "../") // custom, read Readme.md for more info - suite.RunSuite(t, new(ExampleSuite1)) -}