mirror of
https://github.com/wneessen/go-mail.git
synced 2024-11-25 15:10:48 +01:00
We now return a Reader instead of the io.Reader interface
This commit is contained in:
parent
4a309dc73a
commit
5faa6dfbd6
3 changed files with 111 additions and 18 deletions
29
msg.go
29
msg.go
|
@ -807,24 +807,31 @@ func (m *Msg) WriteToSendmailWithContext(ctx context.Context, sp string, a ...st
|
|||
return nil
|
||||
}
|
||||
|
||||
// NewReader returns a Msg reader that satisfies the io.Reader interface.
|
||||
// **Please note:** when creating a new reader, the current state of the Msg is taken, as
|
||||
// basis for the reader. If you perform changes on Msg after creating the reader, you need
|
||||
// to perform a call to Msg.UpdateReader first
|
||||
func (m *Msg) NewReader() io.Reader {
|
||||
// NewReader returns a Reader type that satisfies the io.Reader interface.
|
||||
//
|
||||
// IMPORTANT: when creating a new Reader, the current state of the Msg is taken, as
|
||||
// basis for the Reader. If you perform changes on Msg after creating the Reader, these
|
||||
// changes will not be reflected in the Reader. You will have to use Msg.UpdateReader
|
||||
// first to update the Reader's buffer with the current Msg content
|
||||
func (m *Msg) NewReader() *Reader {
|
||||
r := &Reader{}
|
||||
wbuf := bytes.Buffer{}
|
||||
_, _ = m.Write(&wbuf)
|
||||
r := &reader{buf: wbuf.Bytes()}
|
||||
_, err := m.Write(&wbuf)
|
||||
if err != nil {
|
||||
r.err = fmt.Errorf("failed to write Msg to Reader buffer: %w", err)
|
||||
}
|
||||
r.buf = wbuf.Bytes()
|
||||
return r
|
||||
}
|
||||
|
||||
// UpdateReader will update a reader with the content of the current Msg and reset the reader position
|
||||
// to the start
|
||||
func (m *Msg) UpdateReader(r *reader) {
|
||||
// UpdateReader will update a Reader with the content of the given Msg and reset the
|
||||
// Reader position to the start
|
||||
func (m *Msg) UpdateReader(r *Reader) {
|
||||
wbuf := bytes.Buffer{}
|
||||
_, _ = m.Write(&wbuf)
|
||||
_, err := m.Write(&wbuf)
|
||||
r.Reset()
|
||||
r.buf = wbuf.Bytes()
|
||||
r.err = err
|
||||
}
|
||||
|
||||
// Read outputs the length of p into p to satisfy the io.Reader interface
|
||||
|
|
80
msg_test.go
80
msg_test.go
|
@ -1784,6 +1784,86 @@ func TestMsg_Read_ioCopy(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// TestMsg_NewReader tests the Msg.NewReader method
|
||||
func TestMsg_NewReader(t *testing.T) {
|
||||
m := NewMsg()
|
||||
m.SetBodyString(TypeTextPlain, "TEST123")
|
||||
mr := m.NewReader()
|
||||
if mr == nil {
|
||||
t.Errorf("NewReader failed: Reader is nil")
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsg_NewReader_broken tests the Msg.NewReader method error handling
|
||||
func TestMsg_NewReader_broken(t *testing.T) {
|
||||
m := &Msg{}
|
||||
mr := m.NewReader()
|
||||
if mr == nil {
|
||||
t.Errorf("NewReader failed: Reader is nil")
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsg_NewReader_ioCopy tests the Msg.NewReader method using io.Copy
|
||||
func TestMsg_NewReader_ioCopy(t *testing.T) {
|
||||
wbuf1 := bytes.Buffer{}
|
||||
wbuf2 := bytes.Buffer{}
|
||||
m := NewMsg()
|
||||
m.SetBodyString(TypeTextPlain, "TEST123")
|
||||
mr := m.NewReader()
|
||||
if mr == nil {
|
||||
t.Errorf("NewReader failed: Reader is nil")
|
||||
}
|
||||
|
||||
// First we use WriteTo to have something to compare to
|
||||
_, err := m.WriteTo(&wbuf1)
|
||||
if err != nil {
|
||||
t.Errorf("failed to write body to buffer: %s", err)
|
||||
}
|
||||
|
||||
// Then we write to wbuf2 via io.Copy
|
||||
n, err := io.Copy(&wbuf2, mr)
|
||||
if err != nil {
|
||||
t.Errorf("failed to use io.Copy on Reader: %s", err)
|
||||
}
|
||||
if n != int64(wbuf1.Len()) {
|
||||
t.Errorf("message length of WriteTo and io.Copy differ. Expected: %d, got: %d", wbuf1.Len(), n)
|
||||
}
|
||||
if wbuf1.String() != wbuf2.String() {
|
||||
t.Errorf("message content of WriteTo and io.Copy differ")
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsg_UpdateReader tests the Msg.UpdateReader method
|
||||
func TestMsg_UpdateReader(t *testing.T) {
|
||||
m := NewMsg()
|
||||
m.Subject("Subject-Run 1")
|
||||
mr := m.NewReader()
|
||||
if mr == nil {
|
||||
t.Errorf("NewReader failed: Reader is nil")
|
||||
}
|
||||
wbuf1 := bytes.Buffer{}
|
||||
_, err := io.Copy(&wbuf1, mr)
|
||||
if err != nil {
|
||||
t.Errorf("io.Copy on Reader failed: %s", err)
|
||||
}
|
||||
if !strings.Contains(wbuf1.String(), "Subject: Subject-Run 1") {
|
||||
t.Errorf("io.Copy on Reader failed. Expected to find %q but string in Subject was not found",
|
||||
"Subject-Run 1")
|
||||
}
|
||||
|
||||
m.Subject("Subject-Run 2")
|
||||
m.UpdateReader(mr)
|
||||
wbuf2 := bytes.Buffer{}
|
||||
_, err = io.Copy(&wbuf2, mr)
|
||||
if err != nil {
|
||||
t.Errorf("2nd io.Copy on Reader failed: %s", err)
|
||||
}
|
||||
if !strings.Contains(wbuf2.String(), "Subject: Subject-Run 2") {
|
||||
t.Errorf("io.Copy on Reader failed. Expected to find %q but string in Subject was not found",
|
||||
"Subject-Run 2")
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsg_SetBodyTextTemplate tests the Msg.SetBodyTextTemplate method
|
||||
func TestMsg_SetBodyTextTemplate(t *testing.T) {
|
||||
tests := []struct {
|
||||
|
|
20
reader.go
20
reader.go
|
@ -4,16 +4,22 @@
|
|||
|
||||
package mail
|
||||
|
||||
import "io"
|
||||
import (
|
||||
"io"
|
||||
)
|
||||
|
||||
// reader is a type that implements the io.Reader interface for a Msg
|
||||
type reader struct {
|
||||
// Reader is a type that implements the io.Reader interface for a Msg
|
||||
type Reader struct {
|
||||
buf []byte // contents are the bytes buf[off : len(buf)]
|
||||
off int // read at &buf[off], write at &buf[len(buf)]
|
||||
err error // initalization error
|
||||
}
|
||||
|
||||
// Read reads the length of p of the Msg buffer to satisfy the io.Reader interface
|
||||
func (r *reader) Read(p []byte) (n int, err error) {
|
||||
func (r *Reader) Read(p []byte) (n int, err error) {
|
||||
if r.err != nil {
|
||||
return 0, r.err
|
||||
}
|
||||
if r.empty() {
|
||||
r.Reset()
|
||||
if len(p) == 0 {
|
||||
|
@ -23,15 +29,15 @@ func (r *reader) Read(p []byte) (n int, err error) {
|
|||
}
|
||||
n = copy(p, r.buf[r.off:])
|
||||
r.off += n
|
||||
return n, nil
|
||||
return n, err
|
||||
}
|
||||
|
||||
// Reset resets the Reader buffer to be empty, but it retains the underlying storage
|
||||
// for use by future writes.
|
||||
func (r *reader) Reset() {
|
||||
func (r *Reader) Reset() {
|
||||
r.buf = r.buf[:0]
|
||||
r.off = 0
|
||||
}
|
||||
|
||||
// empty reports whether the unread portion of the Reader buffer is empty.
|
||||
func (r *reader) empty() bool { return len(r.buf) <= r.off }
|
||||
func (r *Reader) empty() bool { return len(r.buf) <= r.off }
|
||||
|
|
Loading…
Reference in a new issue