mox/message/writer_test.go
Mechiel Lukkien ecf60568b4
fix: don't insert spurious \r when fixing up crlf line endings when writing a message
message.Writer.Write() adds missing \r's, but the buffer of "last bytes
written" was only being updated while writing the message headers, not while
writing the body. so for Write()'s in the body section (depending on
buffering), we were compensating based on the "last bytes written" as set
during the last write in the header section. that could cause a spurious \r to
be added when a Write starts with \n while the previous Write did properly
end with \r.

for issue #117, thanks haraldrudell for reporting and investigating
2024-02-08 12:33:19 +01:00

81 lines
2.1 KiB
Go

package message
import (
"strings"
"testing"
)
func TestMsgWriter(t *testing.T) {
check := func(data string, want bool) {
t.Helper()
b := &strings.Builder{}
mw := NewWriter(b)
if _, err := mw.Write([]byte(data)); err != nil {
t.Fatalf("write for message %q: %s", data, err)
}
if mw.HaveBody != want {
t.Fatalf("got %v, expected %v, for message %q", mw.HaveBody, want, data)
}
b = &strings.Builder{}
mw = NewWriter(b)
for i := range data {
if _, err := mw.Write([]byte(data[i : i+1])); err != nil {
t.Fatalf("write for message %q: %s", data, err)
}
}
if mw.HaveBody != want {
t.Fatalf("got %v, expected %v, for message %q", mw.HaveBody, want, data)
}
}
check("no header", false)
check("no header\r\n", false)
check("key: value\r\n\r\n", true)
check("key: value\r\n\r\nbody", true)
check("key: value\n\nbody", true)
check("key: value\n\r\nbody", true)
check("key: value\r\rbody", false)
check("\r\n\r\n", true)
check("\r\n\r\nbody", true)
check("\r\nbody", true)
// Check \n is replaced with \r\n.
var b strings.Builder
mw := NewWriter(&b)
msg := "key: value\n\nline1\r\nline2\nx\n.\n"
_, err := mw.Write([]byte(msg))
tcheck(t, err, "write")
got := b.String()
exp := "key: value\r\n\r\nline1\r\nline2\r\nx\r\n.\r\n"
if got != exp {
t.Fatalf("got %q, expected %q", got, exp)
}
}
func TestMsgWriterIssue117(t *testing.T) {
var b strings.Builder
mw := NewWriter(&b)
// Write header and header/body separator, but with CR missing.
_, err := mw.Write([]byte("a: b\n\n"))
tcheck(t, err, "write")
// Write start of a line. The newline follows in a second write. Just because of buffering.
_, err = mw.Write([]byte("body\r"))
tcheck(t, err, "write")
// Finish the line. The bug is that w.tail was only updated while writing headers,
// not while writing message data for the body. That makes the code think this \n
// wasn't preceded by a \r, causing it to add a \r. And we end up with \r\r\n in
// the file.
_, err = mw.Write([]byte("\n"))
tcheck(t, err, "write")
got := b.String()
exp := "a: b\r\n\r\nbody\r\n"
if got != exp {
t.Fatalf("got %q, expected %q", got, exp)
}
}