From f50470ebfaeb91dc1874c865bdd7b6550c8cdf56 Mon Sep 17 00:00:00 2001 From: Jeevanandam M Date: Fri, 1 Nov 2024 22:10:48 -0700 Subject: [PATCH] test: corner case coverage --- middleware.go | 6 ++++-- middleware_test.go | 47 ++++++++++++++++++++++++++++++++++++++++++++++ multipart.go | 7 +++---- multipart_test.go | 26 +++++++++++++++++++++++++ request.go | 2 +- request_test.go | 15 ++++++++++++--- util.go | 18 ++++++++++++++---- util_test.go | 16 ++++++++++++++++ 8 files changed, 123 insertions(+), 14 deletions(-) diff --git a/middleware.go b/middleware.go index 5ec6b0af..5d155f11 100644 --- a/middleware.go +++ b/middleware.go @@ -11,7 +11,6 @@ import ( "mime/multipart" "net/http" "net/url" - "os" "path/filepath" "reflect" "strconv" @@ -585,6 +584,7 @@ func handleRequestBody(c *Client, r *Request) error { } else if xmlKey == encKey { if inferKind(r.Body) != reflect.Struct { releaseBuffer(r.bodyBuf) + r.bodyBuf = nil return ErrUnsupportedRequestBodyKind } } @@ -593,10 +593,12 @@ func handleRequestBody(c *Client, r *Request) error { encFunc, found := c.inferContentTypeEncoder(contentType, encKey) if !found { releaseBuffer(r.bodyBuf) + r.bodyBuf = nil return fmt.Errorf("resty: content-type encoder not found for %s", contentType) } if err := encFunc(r.bodyBuf, r.Body); err != nil { releaseBuffer(r.bodyBuf) + r.bodyBuf = nil return err } } @@ -617,7 +619,7 @@ func saveResponseIntoFile(c *Client, res *Response) error { return err } - outFile, err := os.Create(file) + outFile, err := createFile(file) if err != nil { return err } diff --git a/middleware_test.go b/middleware_test.go index 4994fca6..79c23ebc 100644 --- a/middleware_test.go +++ b/middleware_test.go @@ -1,13 +1,21 @@ +// Copyright (c) 2015-present Jeevanandam M (jeeva@myjeeva.com), All rights reserved. +// resty source code and usage is governed by a MIT style +// license that can be found in the LICENSE file. +// SPDX-License-Identifier: MIT + package resty import ( "bytes" "encoding/json" + "errors" "io" "mime" "mime/multipart" "net/http" "net/url" + "os" + "path/filepath" "reflect" "strings" "testing" @@ -1037,3 +1045,42 @@ func Benchmark_parseRequestBody_MultiPart(b *testing.B) { } } } + +func TestSaveResponseToFile(t *testing.T) { + c := dcnl() + tempDir := t.TempDir() + + errDirMsg := "test dir error" + mkdirAll = func(_ string, _ os.FileMode) error { + return errors.New(errDirMsg) + } + errFileMsg := "test file error" + createFile = func(_ string) (*os.File, error) { + return nil, errors.New(errFileMsg) + } + t.Cleanup(func() { + mkdirAll = os.MkdirAll + createFile = os.Create + }) + + // dir create error + req1 := c.R() + req1.SetOutputFile(filepath.Join(tempDir, "new-res-dir", "sample.txt")) + err1 := saveResponseIntoFile(c, &Response{Request: req1}) + assertEqual(t, errDirMsg, err1.Error()) + + // file create error + req2 := c.R() + req2.SetOutputFile(filepath.Join(tempDir, "sample.txt")) + err2 := saveResponseIntoFile(c, &Response{Request: req2}) + assertEqual(t, errFileMsg, err2.Error()) +} + +func TestMiddlewareCoverage(t *testing.T) { + c := dcnl() + + req1 := c.R() + req1.URL = "//invalid-url .local" + err1 := createHTTPRequest(c, req1) + assertEqual(t, true, strings.Contains(err1.Error(), "invalid character")) +} diff --git a/multipart.go b/multipart.go index 35117b17..12d6ea21 100644 --- a/multipart.go +++ b/multipart.go @@ -1,6 +1,7 @@ // Copyright (c) 2015-present Jeevanandam M (jeeva@myjeeva.com), All rights reserved. // resty source code and usage is governed by a MIT style // license that can be found in the LICENSE file. +// SPDX-License-Identifier: MIT package resty @@ -98,10 +99,8 @@ func (mf *MultipartField) openFileIfRequired() error { return err } - fileStat, err := file.Stat() - if err != nil { - return err - } + // if file open is success, stat will succeed + fileStat, _ := file.Stat() mf.Reader = file mf.FileSize = fileStat.Size() diff --git a/multipart_test.go b/multipart_test.go index 23a7393e..aa612855 100644 --- a/multipart_test.go +++ b/multipart_test.go @@ -1,6 +1,7 @@ // Copyright (c) 2015-present Jeevanandam M (jeeva@myjeeva.com), All rights reserved. // resty source code and usage is governed by a MIT style // license that can be found in the LICENSE file. +// SPDX-License-Identifier: MIT package resty @@ -9,6 +10,7 @@ import ( "context" "errors" "io/fs" + "mime/multipart" "net/http" "net/url" "os" @@ -475,6 +477,30 @@ func TestMultipartReaderErrors(t *testing.T) { }) } +type mpWriterError struct{} + +func (mwe *mpWriterError) Write(p []byte) (int, error) { + return 0, errors.New("multipart write error") +} + +func TestRequest_writeFormData(t *testing.T) { + mw := multipart.NewWriter(&mpWriterError{}) + + c := dcnl() + req1 := c.R().SetFormData(map[string]string{ + "name1": "value1", + "name2": "value2", + }) + + err1 := req1.writeFormData(mw) + assertNotNil(t, err1) + assertEqual(t, "multipart write error", err1.Error()) + + err2 := createMultipart(mw, req1) + assertNotNil(t, err2) + assertEqual(t, "multipart write error", err2.Error()) +} + type returnValueTestWriter struct { } diff --git a/request.go b/request.go index 5bfd3aa9..30281c53 100644 --- a/request.go +++ b/request.go @@ -1320,7 +1320,7 @@ func (r *Request) Execute(method, url string) (res *Response, err error) { } r.sendLoadBalancerFeedback(res, err) - releaseBuffer(r.bodyBuf) + backToBufPool(r.bodyBuf) return } diff --git a/request_test.go b/request_test.go index 02e45bbe..5d2a93c4 100644 --- a/request_test.go +++ b/request_test.go @@ -2167,9 +2167,6 @@ func TestRequestPanicContext(t *testing.T) { //lint:ignore SA1012 test case nil check _ = c.R().WithContext(nil) - - //lint:ignore SA1012 test case nil check - _ = c.R().Clone(nil) } // This test methods exist for test coverage purpose @@ -2213,6 +2210,18 @@ func TestRequestSettingsCoverage(t *testing.T) { invalidJsonBytes := []byte(`{\" \": "value here"}`) result := jsonIndent(invalidJsonBytes) assertEqual(t, string(invalidJsonBytes), string(result)) + + defer func() { + if rec := recover(); rec != nil { + if err, ok := rec.(error); ok { + assertEqual(t, true, strings.Contains(err.Error(), "resty: Request.Clone nil context")) + } + } + }() + r6 := c.R() + //lint:ignore SA1012 test case nil check + r62 := r6.Clone(nil) + assertEqual(t, nil, r62.ctx) } func TestRequestDataRace(t *testing.T) { diff --git a/util.go b/util.go index 738cca7b..e2551efa 100644 --- a/util.go +++ b/util.go @@ -137,10 +137,15 @@ func firstNonEmpty(v ...string) string { return "" } +var ( + mkdirAll = os.MkdirAll + createFile = os.Create +) + func createDirectory(dir string) (err error) { if _, err = os.Stat(dir); err != nil { if os.IsNotExist(err) { - if err = os.MkdirAll(dir, 0755); err != nil { + if err = mkdirAll(dir, 0755); err != nil { return } } @@ -184,14 +189,19 @@ func acquireBuffer() *bytes.Buffer { buf.Reset() return buf } + bufPool.Put(buf) return new(bytes.Buffer) } func releaseBuffer(buf *bytes.Buffer) { if buf != nil { - if buf.Len() == 0 { - buf.Reset() - } + buf.Reset() + bufPool.Put(buf) + } +} + +func backToBufPool(buf *bytes.Buffer) { + if buf != nil { bufPool.Put(buf) } } diff --git a/util_test.go b/util_test.go index cfb47dae..21bb3476 100644 --- a/util_test.go +++ b/util_test.go @@ -9,6 +9,8 @@ import ( "bytes" "errors" "net/url" + "os" + "path/filepath" "strings" "testing" ) @@ -108,6 +110,20 @@ func TestRestyErrorFuncs(t *testing.T) { assertEqual(t, "inner error 1", e.Error()) } +func Test_createDirectory(t *testing.T) { + errMsg := "test dir error" + mkdirAll = func(path string, perm os.FileMode) error { + return errors.New(errMsg) + } + t.Cleanup(func() { + mkdirAll = os.MkdirAll + }) + + tempDir := filepath.Join(t.TempDir(), "test-dir") + err := createDirectory(tempDir) + assertEqual(t, errMsg, err.Error()) +} + // This test methods exist for test coverage purpose // to validate the getter and setter func TestUtilMiscTestCoverage(t *testing.T) {