Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion request_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ import (
)

type AuthSuccess struct {
ID, Message string
ID string `xml:"Id"`
Message string `xml:"Message"`
}

type AuthError struct {
Expand Down
69 changes: 68 additions & 1 deletion util.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import (
"crypto/sha256"
"encoding/binary"
"encoding/hex"
"encoding/json"
"encoding/xml"
"errors"
"fmt"
"io"
Expand Down Expand Up @@ -69,9 +71,74 @@ func (l *logger) output(format string, v ...any) {
l.l.Printf(format, v...)
}

//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
// In Memory JSON & XML Marshal and Unmarshal using Go package
//_____________________________________________________________

var (
// InMemoryJSONMarshal function performs the JSON marshalling completely in memory.
//
// c := resty.New()
// defer c.Close()
//
// c.AddContentTypeEncoder("application/json", resty.InMemoryJSONMarshal)
InMemoryJSONMarshal = func(w io.Writer, v any) error {
jsonData, err := json.Marshal(v)
if err != nil {
return err
}
_, err = w.Write(jsonData)
return err
}

// InMemoryJSONUnmarshal function performs the JSON unmarshalling completely in memory.
//
// c := resty.New()
// defer c.Close()
//
// c.AddContentTypeDecoder("application/json", resty.InMemoryJSONUnmarshal)
InMemoryJSONUnmarshal = func(r io.Reader, v any) error {
byteData, err := io.ReadAll(r)
if err != nil {
return err
}
return json.Unmarshal(byteData, v)
}

// InMemoryXMLMarshal function performs the XML marshalling completely in memory.
//
// c := resty.New()
// defer c.Close()
//
// c.AddContentTypeEncoder("application/xml", resty.InMemoryXMLMarshal)
InMemoryXMLMarshal = func(w io.Writer, v any) error {
xmlData, err := xml.Marshal(v)
if err != nil {
return err
}
_, err = w.Write(xmlData)
return err
}

// InMemoryJSONUnmarshal function performs the XML unmarshalling completely in memory.
//
// c := resty.New()
// defer c.Close()
//
// c.AddContentTypeDecoder("application/xml", resty.InMemoryXMLUnmarshal)
InMemoryXMLUnmarshal = func(r io.Reader, v any) error {
byteData, err := io.ReadAll(r)
if err != nil {
return err
}
return xml.Unmarshal(byteData, v)
}
)

// credentials type is to hold an username and password information
type credentials struct {
Username, Password string
Username string `json:"username"`
Password string `json:"password"`
}

// Clone method returns clone of c.
Expand Down
141 changes: 141 additions & 0 deletions util_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ package resty
import (
"bytes"
"errors"
"fmt"
"io"
"net/http"
"net/url"
"os"
"path/filepath"
Expand Down Expand Up @@ -180,6 +182,145 @@ func TestUtil_readMachineID(t *testing.T) {
})
}

func TestInMemoryJSONMarshalUnmarshal(t *testing.T) {
t.Run("json encoder", func(t *testing.T) {
user := &credentials{Username: "testuser", Password: "testpass"}
buf := acquireBuffer()
defer releaseBuffer(buf)
err := InMemoryJSONMarshal(buf, user)
assertNil(t, err)
assertEqual(t, `{"username":"testuser","password":"testpass"}`, buf.String())
})

t.Run("json encoder error", func(t *testing.T) {
obj := &brokenMarshalJSON{}
buf := acquireBuffer()
defer releaseBuffer(buf)
err := InMemoryJSONMarshal(buf, obj)
assertNotNil(t, err)
assertEqual(t, true, strings.Contains(err.Error(), "b0rk3d"))
})

t.Run("json decoder", func(t *testing.T) {
byteData := []byte(`{"username":"testuser","password":"testpass"}`)
cred := &credentials{}
err := InMemoryJSONUnmarshal(bytes.NewReader(byteData), cred)
assertNil(t, err)
assertEqual(t, "testuser", cred.Username)
assertEqual(t, "testpass", cred.Password)
})

t.Run("json decoder read error", func(t *testing.T) {
cred := &credentials{}
err := InMemoryJSONUnmarshal(&brokenReadCloser{}, cred)
assertNotNil(t, err)
assertEqual(t, err.Error(), "read error")
})

t.Run("json decoder error", func(t *testing.T) {
byteData := []byte(`"username":"testuser","password":"testpass"}`)
cred := &credentials{}
err := InMemoryJSONUnmarshal(bytes.NewReader(byteData), cred)
assertNotNil(t, err)
assertEqual(t, true, strings.Contains(err.Error(), "invalid character ':' after top-level value"))
})
}

func TestInMemoryXMLMarshalUnmarshal(t *testing.T) {
t.Run("xml encoder", func(t *testing.T) {
user := &credentials{Username: "testuser", Password: "testpass"}
buf := acquireBuffer()
defer releaseBuffer(buf)
err := InMemoryXMLMarshal(buf, user)
assertNil(t, err)
assertEqual(t, `<credentials><Username>testuser</Username><Password>testpass</Password></credentials>`, buf.String())
})

t.Run("xml encoder error", func(t *testing.T) {
obj := &brokenMarshalXML{}
buf := acquireBuffer()
defer releaseBuffer(buf)
err := InMemoryXMLMarshal(buf, obj)
assertNotNil(t, err)
assertEqual(t, err.Error(), "b0rk3d")
})

t.Run("xml decoder", func(t *testing.T) {
byteData := []byte(`<?xml version="1.0" encoding="UTF-8"?><credentials><Username>testuser</Username><Password>testpass</Password></credentials>`)
cred := &credentials{}
err := InMemoryXMLUnmarshal(bytes.NewReader(byteData), cred)
assertNil(t, err)
assertEqual(t, "testuser", cred.Username)
assertEqual(t, "testpass", cred.Password)
})

t.Run("xml decoder read error", func(t *testing.T) {
cred := &credentials{}
err := InMemoryXMLUnmarshal(&brokenReadCloser{}, cred)
assertNotNil(t, err)
assertEqual(t, err.Error(), "read error")
})

t.Run("xml decoder error", func(t *testing.T) {
byteData := []byte(`<?xml version="1.0" encoding="UTF-8"?><Username>testuser</Username><Password>testpass</Password></credentials>`)
cred := &credentials{}
err := InMemoryJSONUnmarshal(bytes.NewReader(byteData), cred)
fmt.Println(err)
assertNotNil(t, err)
assertEqual(t, err.Error(), "invalid character '<' looking for beginning of value")
})
}

func TestInMemoryJSONPost(t *testing.T) {
ts := createPostServer(t)
defer ts.Close()

user := &credentials{Username: "testuser", Password: "testpass"}
assertEqual(t, "Username: **********, Password: **********", user.String())

c := dcnl().
AddContentTypeEncoder(jsonContentType, InMemoryJSONMarshal).
AddContentTypeDecoder(jsonContentType, InMemoryJSONUnmarshal)

r := c.R().
SetHeader(hdrContentTypeKey, jsonContentType).
SetBody(user).
SetResult(&AuthSuccess{})

resp, err := r.Post(ts.URL + "/login")
authResp := resp.Result().(*AuthSuccess)

assertError(t, err)
assertEqual(t, http.StatusOK, resp.StatusCode())
assertEqual(t, int64(50), resp.Size())
assertEqual(t, authResp.ID, "success")
assertEqual(t, authResp.Message, "login successful")
}

func TestInMemoryXMLPost(t *testing.T) {
ts := createPostServer(t)
defer ts.Close()

xmlContentType := "application/xml"
c := dcnl().
AddContentTypeEncoder(xmlContentType, InMemoryXMLMarshal).
AddContentTypeDecoder(xmlContentType, InMemoryXMLUnmarshal)

resp, err := c.R().
SetHeader(hdrContentTypeKey, xmlContentType).
SetBody(credentials{Username: "testuser", Password: "testpass"}).
SetResult(&AuthSuccess{}).
Post(ts.URL + "/login")

authResp := resp.Result().(*AuthSuccess)

assertError(t, err)
assertEqual(t, http.StatusOK, resp.StatusCode())
assertEqual(t, int64(116), resp.Size())
assertEqual(t, authResp.ID, "success")
assertEqual(t, authResp.Message, "login successful")
}

// This test methods exist for test coverage purpose
// to validate the getter and setter
func TestUtilMiscTestCoverage(t *testing.T) {
Expand Down