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)