1package message
2
3import (
4 "strings"
5 "testing"
6)
7
8func TestMsgWriter(t *testing.T) {
9 check := func(data string, want bool) {
10 t.Helper()
11
12 b := &strings.Builder{}
13 mw := NewWriter(b)
14 if _, err := mw.Write([]byte(data)); err != nil {
15 t.Fatalf("write for message %q: %s", data, err)
16 }
17 if mw.HaveBody != want {
18 t.Fatalf("got %v, expected %v, for message %q", mw.HaveBody, want, data)
19 }
20
21 b = &strings.Builder{}
22 mw = NewWriter(b)
23 for i := range data {
24 if _, err := mw.Write([]byte(data[i : i+1])); err != nil {
25 t.Fatalf("write for message %q: %s", data, err)
26 }
27 }
28 if mw.HaveBody != want {
29 t.Fatalf("got %v, expected %v, for message %q", mw.HaveBody, want, data)
30 }
31 }
32
33 check("no header", false)
34 check("no header\r\n", false)
35 check("key: value\r\n\r\n", true)
36 check("key: value\r\n\r\nbody", true)
37 check("key: value\n\nbody", true)
38 check("key: value\n\r\nbody", true)
39 check("key: value\r\rbody", false)
40 check("\r\n\r\n", true)
41 check("\r\n\r\nbody", true)
42 check("\r\nbody", true)
43
44 // Check \n is replaced with \r\n.
45 var b strings.Builder
46 mw := NewWriter(&b)
47 msg := "key: value\n\nline1\r\nline2\nx\n.\n"
48 _, err := mw.Write([]byte(msg))
49 tcheck(t, err, "write")
50 got := b.String()
51 exp := "key: value\r\n\r\nline1\r\nline2\r\nx\r\n.\r\n"
52 if got != exp {
53 t.Fatalf("got %q, expected %q", got, exp)
54 }
55}
56
57func TestMsgWriterIssue117(t *testing.T) {
58 var b strings.Builder
59 mw := NewWriter(&b)
60
61 // Write header and header/body separator, but with CR missing.
62 _, err := mw.Write([]byte("a: b\n\n"))
63 tcheck(t, err, "write")
64
65 // Write start of a line. The newline follows in a second write. Just because of buffering.
66 _, err = mw.Write([]byte("body\r"))
67 tcheck(t, err, "write")
68
69 // Finish the line. The bug is that w.tail was only updated while writing headers,
70 // not while writing message data for the body. That makes the code think this \n
71 // wasn't preceded by a \r, causing it to add a \r. And we end up with \r\r\n in
72 // the file.
73 _, err = mw.Write([]byte("\n"))
74 tcheck(t, err, "write")
75
76 got := b.String()
77 exp := "a: b\r\n\r\nbody\r\n"
78 if got != exp {
79 t.Fatalf("got %q, expected %q", got, exp)
80 }
81}
82