13 "github.com/mjl-/mox/mlog"
16func TestPreviewText(t *testing.T) {
17 check := func(body, expLine string) {
20 line, err := previewText(strings.NewReader(body))
23 t.Fatalf("got %q, expected %q, for body %q", line, expLine, body)
28 check("single line", "single line\n")
29 check("single line\n", "single line\n")
30 check("> quoted\n", "[...]\n")
31 check("> quoted\nresponse\n", "[...]\nresponse\n")
32 check("> quoted\n[...]\nresponse after author snip\n", "[...]\nresponse after author snip\n")
33 check("[...]\nresponse after author snip\n", "[...]\nresponse after author snip\n")
34 check("[…]\nresponse after author snip\n", "[…]\nresponse after author snip\n")
35 check(">> quoted0\n> quoted1\n>quoted2\n[...]\nresponse after author snip\n", "[...]\nresponse after author snip\n")
36 check(">quoted\n\n>quoted\ncoalesce line-separated quotes\n", "[...]\ncoalesce line-separated quotes\n")
37 check("On <date> <user> wrote:\n> hi\nresponse", "[...]\nresponse\n")
38 check("On <longdate>\n<user> wrote:\n> hi\nresponse", "[...]\nresponse\n")
39 check("> quote\nresponse\n--\nsignature\n", "[...]\nresponse\n")
40 check("> quote\nline1\nline2\nline3\n", "[...]\nline1\nline2\nline3\n")
43func tcompose(t *testing.T, typeContents ...string) *bytes.Reader {
46 xc := NewComposer(&b, 100*1024, true)
47 xc.Header("MIME-Version", "1.0")
49 var cur, alt *multipart.Writer
51 xcreateMultipart := func(subtype string) *multipart.Writer {
52 mp := multipart.NewWriter(xc)
54 xc.Header("Content-Type", fmt.Sprintf(`multipart/%s; boundary="%s"`, subtype, mp.Boundary()))
57 _, err := cur.CreatePart(textproto.MIMEHeader{"Content-Type": []string{fmt.Sprintf(`multipart/%s; boundary="%s"`, subtype, mp.Boundary())}})
58 tcheck(t, err, "adding multipart")
63 xcreatePart := func(header textproto.MIMEHeader) io.Writer {
65 for k, vl := range header {
66 for _, v := range vl {
73 p, err := cur.CreatePart(header)
74 tcheck(t, err, "adding part")
78 if len(typeContents)/2 > 1 {
79 alt = xcreateMultipart("alternative")
81 for i := 0; i < len(typeContents); i += 2 {
82 body, ct, cte := xc.TextPart(typeContents[i], typeContents[i+1])
83 tp := xcreatePart(textproto.MIMEHeader{"Content-Type": []string{ct}, "Content-Transfer-Encoding": []string{cte}})
84 _, err := tp.Write([]byte(body))
85 tcheck(t, err, "write part")
89 tcheck(t, err, "close multipart")
94 return bytes.NewReader(buf)
97func TestPreviewHTML(t *testing.T) {
98 check := func(r *bytes.Reader, exp string) {
101 p, err := Parse(slog.Default(), false, r)
102 tcheck(t, err, "parse")
103 err = p.Walk(slog.Default(), nil)
104 tcheck(t, err, "walk")
105 log := mlog.New("message", nil)
106 s, err := p.Preview(log)
107 tcheck(t, err, "preview")
111 // We use the first part for the preview.
112 m := tcompose(t, "plain", "the text", "html", "<html><body>the html</body></html>")
113 check(m, "the text\n")
116 m = tcompose(t, "html", "<body>the html</body>", "plain", "the text")
117 check(m, "the html\n")
120 m = tcompose(t, "plain", "the text")
121 check(m, "the text\n")
124 m = tcompose(t, "html", "<body>the html</body>")
125 check(m, "the html\n")
128 m = tcompose(t, "other", "other text")
131 // HTML with quoted text.
132 m = tcompose(t, "html", "<html><div>On ... someone wrote:</div><blockquote>something worth replying</blockquote><div>agreed</div></body>")
133 check(m, "[...]\nagreed\n")
135 // HTML with ignored elements, inline elements and tables.
136 const moreHTML = `<!doctype html>
140 <style>head style</style>
141 <script>head script</script>
144<script>body script</script>
145<style>body style</style>
148<div><a href="about:blank">link1 </a> text <span>word</span><span>word2</span>.</div>
149<table><tr><td>col1</td><th>col2</th></tr><tr><td>row2</td></tr></table>
152 m = tcompose(t, "html", moreHTML)