1#!/bin/sh
2
3test_description='git send-email'
4. ./test-lib.sh
5
6if ! test_have_prereq PERL; then
7 say 'skipping git send-email tests, perl not available'
8 test_done
9fi
10
11PROG='git send-email'
12test_expect_success \
13 'prepare reference tree' \
14 'echo "1A quick brown fox jumps over the" >file &&
15 echo "lazy dog" >>file &&
16 git add file &&
17 GIT_AUTHOR_NAME="A" git commit -a -m "Initial."'
18
19test_expect_success \
20 'Setup helper tool' \
21 '(echo "#!$SHELL_PATH"
22 echo shift
23 echo output=1
24 echo "while test -f commandline\$output; do output=\$((\$output+1)); done"
25 echo for a
26 echo do
27 echo " echo \"!\$a!\""
28 echo "done >commandline\$output"
29 echo "cat > msgtxt\$output"
30 ) >fake.sendmail &&
31 chmod +x ./fake.sendmail &&
32 git add fake.sendmail &&
33 GIT_AUTHOR_NAME="A" git commit -a -m "Second."'
34
35clean_fake_sendmail() {
36 rm -f commandline* msgtxt*
37}
38
39test_expect_success 'Extract patches' '
40 patches=`git format-patch -s --cc="One <one@example.com>" --cc=two@example.com -n HEAD^1`
41'
42
43# Test no confirm early to ensure remaining tests will not hang
44test_no_confirm () {
45 rm -f no_confirm_okay
46 echo n | \
47 GIT_SEND_EMAIL_NOTTY=1 \
48 git send-email \
49 --from="Example <from@example.com>" \
50 --to=nobody@example.com \
51 --smtp-server="$(pwd)/fake.sendmail" \
52 $@ \
53 $patches > stdout &&
54 test_must_fail grep "Send this email" stdout &&
55 > no_confirm_okay
56}
57
58# Exit immediately to prevent hang if a no-confirm test fails
59check_no_confirm () {
60 test -f no_confirm_okay || {
61 say 'No confirm test failed; skipping remaining tests to prevent hanging'
62 test_done
63 }
64}
65
66test_expect_success 'No confirm with --suppress-cc' '
67 test_no_confirm --suppress-cc=sob
68'
69check_no_confirm
70
71test_expect_success 'No confirm with --confirm=never' '
72 test_no_confirm --confirm=never
73'
74check_no_confirm
75
76# leave sendemail.confirm set to never after this so that none of the
77# remaining tests prompt unintentionally.
78test_expect_success 'No confirm with sendemail.confirm=never' '
79 git config sendemail.confirm never &&
80 test_no_confirm --compose --subject=foo
81'
82check_no_confirm
83
84test_expect_success 'Send patches' '
85 git send-email --suppress-cc=sob --from="Example <nobody@example.com>" --to=nobody@example.com --smtp-server="$(pwd)/fake.sendmail" $patches 2>errors
86'
87
88cat >expected <<\EOF
89!nobody@example.com!
90!author@example.com!
91!one@example.com!
92!two@example.com!
93EOF
94test_expect_success \
95 'Verify commandline' \
96 'test_cmp expected commandline1'
97
98cat >expected-show-all-headers <<\EOF
990001-Second.patch
100(mbox) Adding cc: A <author@example.com> from line 'From: A <author@example.com>'
101(mbox) Adding cc: One <one@example.com> from line 'Cc: One <one@example.com>, two@example.com'
102(mbox) Adding cc: two@example.com from line 'Cc: One <one@example.com>, two@example.com'
103Dry-OK. Log says:
104Server: relay.example.com
105MAIL FROM:<from@example.com>
106RCPT TO:<to@example.com>,<cc@example.com>,<author@example.com>,<one@example.com>,<two@example.com>,<bcc@example.com>
107From: Example <from@example.com>
108To: to@example.com
109Cc: cc@example.com, A <author@example.com>, One <one@example.com>, two@example.com
110Subject: [PATCH 1/1] Second.
111Date: DATE-STRING
112Message-Id: MESSAGE-ID-STRING
113X-Mailer: X-MAILER-STRING
114In-Reply-To: <unique-message-id@example.com>
115References: <unique-message-id@example.com>
116
117Result: OK
118EOF
119
120test_expect_success 'Show all headers' '
121 git send-email \
122 --dry-run \
123 --suppress-cc=sob \
124 --from="Example <from@example.com>" \
125 --to=to@example.com \
126 --cc=cc@example.com \
127 --bcc=bcc@example.com \
128 --in-reply-to="<unique-message-id@example.com>" \
129 --smtp-server relay.example.com \
130 $patches |
131 sed -e "s/^\(Date:\).*/\1 DATE-STRING/" \
132 -e "s/^\(Message-Id:\).*/\1 MESSAGE-ID-STRING/" \
133 -e "s/^\(X-Mailer:\).*/\1 X-MAILER-STRING/" \
134 >actual-show-all-headers &&
135 test_cmp expected-show-all-headers actual-show-all-headers
136'
137
138test_expect_success 'Prompting works' '
139 clean_fake_sendmail &&
140 (echo "Example <from@example.com>"
141 echo "to@example.com"
142 echo ""
143 ) | GIT_SEND_EMAIL_NOTTY=1 git send-email \
144 --smtp-server="$(pwd)/fake.sendmail" \
145 $patches \
146 2>errors &&
147 grep "^From: Example <from@example.com>$" msgtxt1 &&
148 grep "^To: to@example.com$" msgtxt1
149'
150
151z8=zzzzzzzz
152z64=$z8$z8$z8$z8$z8$z8$z8$z8
153z512=$z64$z64$z64$z64$z64$z64$z64$z64
154test_expect_success 'reject long lines' '
155 clean_fake_sendmail &&
156 cp $patches longline.patch &&
157 echo $z512$z512 >>longline.patch &&
158 test_must_fail git send-email \
159 --from="Example <nobody@example.com>" \
160 --to=nobody@example.com \
161 --smtp-server="$(pwd)/fake.sendmail" \
162 $patches longline.patch \
163 2>errors &&
164 grep longline.patch errors
165'
166
167test_expect_success 'no patch was sent' '
168 ! test -e commandline1
169'
170
171test_expect_success 'Author From: in message body' '
172 clean_fake_sendmail &&
173 git send-email \
174 --from="Example <nobody@example.com>" \
175 --to=nobody@example.com \
176 --smtp-server="$(pwd)/fake.sendmail" \
177 $patches &&
178 sed "1,/^$/d" < msgtxt1 > msgbody1
179 grep "From: A <author@example.com>" msgbody1
180'
181
182test_expect_success 'Author From: not in message body' '
183 clean_fake_sendmail &&
184 git send-email \
185 --from="A <author@example.com>" \
186 --to=nobody@example.com \
187 --smtp-server="$(pwd)/fake.sendmail" \
188 $patches &&
189 sed "1,/^$/d" < msgtxt1 > msgbody1
190 ! grep "From: A <author@example.com>" msgbody1
191'
192
193test_expect_success 'allow long lines with --no-validate' '
194 git send-email \
195 --from="Example <nobody@example.com>" \
196 --to=nobody@example.com \
197 --smtp-server="$(pwd)/fake.sendmail" \
198 --novalidate \
199 $patches longline.patch \
200 2>errors
201'
202
203test_expect_success 'Invalid In-Reply-To' '
204 clean_fake_sendmail &&
205 git send-email \
206 --from="Example <nobody@example.com>" \
207 --to=nobody@example.com \
208 --in-reply-to=" " \
209 --smtp-server="$(pwd)/fake.sendmail" \
210 $patches
211 2>errors
212 ! grep "^In-Reply-To: < *>" msgtxt1
213'
214
215test_expect_success 'Valid In-Reply-To when prompting' '
216 clean_fake_sendmail &&
217 (echo "From Example <from@example.com>"
218 echo "To Example <to@example.com>"
219 echo ""
220 ) | env GIT_SEND_EMAIL_NOTTY=1 git send-email \
221 --smtp-server="$(pwd)/fake.sendmail" \
222 $patches 2>errors &&
223 ! grep "^In-Reply-To: < *>" msgtxt1
224'
225
226test_expect_success 'setup fake editor' '
227 (echo "#!$SHELL_PATH" &&
228 echo "echo fake edit >>\"\$1\""
229 ) >fake-editor &&
230 chmod +x fake-editor
231'
232
233test_set_editor "$(pwd)/fake-editor"
234
235test_expect_success '--compose works' '
236 clean_fake_sendmail &&
237 git send-email \
238 --compose --subject foo \
239 --from="Example <nobody@example.com>" \
240 --to=nobody@example.com \
241 --smtp-server="$(pwd)/fake.sendmail" \
242 $patches \
243 2>errors
244'
245
246test_expect_success 'first message is compose text' '
247 grep "^fake edit" msgtxt1
248'
249
250test_expect_success 'second message is patch' '
251 grep "Subject:.*Second" msgtxt2
252'
253
254cat >expected-suppress-sob <<\EOF
2550001-Second.patch
256(mbox) Adding cc: A <author@example.com> from line 'From: A <author@example.com>'
257(mbox) Adding cc: One <one@example.com> from line 'Cc: One <one@example.com>, two@example.com'
258(mbox) Adding cc: two@example.com from line 'Cc: One <one@example.com>, two@example.com'
259Dry-OK. Log says:
260Server: relay.example.com
261MAIL FROM:<from@example.com>
262RCPT TO:<to@example.com>,<cc@example.com>,<author@example.com>,<one@example.com>,<two@example.com>
263From: Example <from@example.com>
264To: to@example.com
265Cc: cc@example.com, A <author@example.com>, One <one@example.com>, two@example.com
266Subject: [PATCH 1/1] Second.
267Date: DATE-STRING
268Message-Id: MESSAGE-ID-STRING
269X-Mailer: X-MAILER-STRING
270
271Result: OK
272EOF
273
274test_suppression () {
275 git send-email \
276 --dry-run \
277 --suppress-cc=$1 \
278 --from="Example <from@example.com>" \
279 --to=to@example.com \
280 --smtp-server relay.example.com \
281 $patches |
282 sed -e "s/^\(Date:\).*/\1 DATE-STRING/" \
283 -e "s/^\(Message-Id:\).*/\1 MESSAGE-ID-STRING/" \
284 -e "s/^\(X-Mailer:\).*/\1 X-MAILER-STRING/" \
285 >actual-suppress-$1 &&
286 test_cmp expected-suppress-$1 actual-suppress-$1
287}
288
289test_expect_success 'sendemail.cc set' '
290 git config sendemail.cc cc@example.com &&
291 test_suppression sob
292'
293
294cat >expected-suppress-sob <<\EOF
2950001-Second.patch
296(mbox) Adding cc: A <author@example.com> from line 'From: A <author@example.com>'
297(mbox) Adding cc: One <one@example.com> from line 'Cc: One <one@example.com>, two@example.com'
298(mbox) Adding cc: two@example.com from line 'Cc: One <one@example.com>, two@example.com'
299Dry-OK. Log says:
300Server: relay.example.com
301MAIL FROM:<from@example.com>
302RCPT TO:<to@example.com>,<author@example.com>,<one@example.com>,<two@example.com>
303From: Example <from@example.com>
304To: to@example.com
305Cc: A <author@example.com>, One <one@example.com>, two@example.com
306Subject: [PATCH 1/1] Second.
307Date: DATE-STRING
308Message-Id: MESSAGE-ID-STRING
309X-Mailer: X-MAILER-STRING
310
311Result: OK
312EOF
313
314test_expect_success 'sendemail.cc unset' '
315 git config --unset sendemail.cc &&
316 test_suppression sob
317'
318
319cat >expected-suppress-all <<\EOF
3200001-Second.patch
321Dry-OK. Log says:
322Server: relay.example.com
323MAIL FROM:<from@example.com>
324RCPT TO:<to@example.com>
325From: Example <from@example.com>
326To: to@example.com
327Subject: [PATCH 1/1] Second.
328Date: DATE-STRING
329Message-Id: MESSAGE-ID-STRING
330X-Mailer: X-MAILER-STRING
331
332Result: OK
333EOF
334
335test_expect_success '--suppress-cc=all' '
336 test_suppression all
337'
338
339cat >expected-suppress-body <<\EOF
3400001-Second.patch
341(mbox) Adding cc: A <author@example.com> from line 'From: A <author@example.com>'
342(mbox) Adding cc: One <one@example.com> from line 'Cc: One <one@example.com>, two@example.com'
343(mbox) Adding cc: two@example.com from line 'Cc: One <one@example.com>, two@example.com'
344Dry-OK. Log says:
345Server: relay.example.com
346MAIL FROM:<from@example.com>
347RCPT TO:<to@example.com>,<author@example.com>,<one@example.com>,<two@example.com>
348From: Example <from@example.com>
349To: to@example.com
350Cc: A <author@example.com>, One <one@example.com>, two@example.com
351Subject: [PATCH 1/1] Second.
352Date: DATE-STRING
353Message-Id: MESSAGE-ID-STRING
354X-Mailer: X-MAILER-STRING
355
356Result: OK
357EOF
358
359test_expect_success '--suppress-cc=body' '
360 test_suppression body
361'
362
363cat >expected-suppress-sob <<\EOF
3640001-Second.patch
365(mbox) Adding cc: A <author@example.com> from line 'From: A <author@example.com>'
366(mbox) Adding cc: One <one@example.com> from line 'Cc: One <one@example.com>, two@example.com'
367(mbox) Adding cc: two@example.com from line 'Cc: One <one@example.com>, two@example.com'
368Dry-OK. Log says:
369Server: relay.example.com
370MAIL FROM:<from@example.com>
371RCPT TO:<to@example.com>,<author@example.com>,<one@example.com>,<two@example.com>
372From: Example <from@example.com>
373To: to@example.com
374Cc: A <author@example.com>, One <one@example.com>, two@example.com
375Subject: [PATCH 1/1] Second.
376Date: DATE-STRING
377Message-Id: MESSAGE-ID-STRING
378X-Mailer: X-MAILER-STRING
379
380Result: OK
381EOF
382
383test_expect_success '--suppress-cc=sob' '
384 test_suppression sob
385'
386
387cat >expected-suppress-bodycc <<\EOF
3880001-Second.patch
389(mbox) Adding cc: A <author@example.com> from line 'From: A <author@example.com>'
390(mbox) Adding cc: One <one@example.com> from line 'Cc: One <one@example.com>, two@example.com'
391(mbox) Adding cc: two@example.com from line 'Cc: One <one@example.com>, two@example.com'
392(body) Adding cc: C O Mitter <committer@example.com> from line 'Signed-off-by: C O Mitter <committer@example.com>'
393Dry-OK. Log says:
394Server: relay.example.com
395MAIL FROM:<from@example.com>
396RCPT TO:<to@example.com>,<author@example.com>,<one@example.com>,<two@example.com>,<committer@example.com>
397From: Example <from@example.com>
398To: to@example.com
399Cc: A <author@example.com>, One <one@example.com>, two@example.com, C O Mitter <committer@example.com>
400Subject: [PATCH 1/1] Second.
401Date: DATE-STRING
402Message-Id: MESSAGE-ID-STRING
403X-Mailer: X-MAILER-STRING
404
405Result: OK
406EOF
407
408test_expect_success '--suppress-cc=bodycc' '
409 test_suppression bodycc
410'
411
412cat >expected-suppress-cc <<\EOF
4130001-Second.patch
414(mbox) Adding cc: A <author@example.com> from line 'From: A <author@example.com>'
415(body) Adding cc: C O Mitter <committer@example.com> from line 'Signed-off-by: C O Mitter <committer@example.com>'
416Dry-OK. Log says:
417Server: relay.example.com
418MAIL FROM:<from@example.com>
419RCPT TO:<to@example.com>,<author@example.com>,<committer@example.com>
420From: Example <from@example.com>
421To: to@example.com
422Cc: A <author@example.com>, C O Mitter <committer@example.com>
423Subject: [PATCH 1/1] Second.
424Date: DATE-STRING
425Message-Id: MESSAGE-ID-STRING
426X-Mailer: X-MAILER-STRING
427
428Result: OK
429EOF
430
431test_expect_success '--suppress-cc=cc' '
432 test_suppression cc
433'
434
435test_confirm () {
436 echo y | \
437 GIT_SEND_EMAIL_NOTTY=1 \
438 git send-email \
439 --from="Example <nobody@example.com>" \
440 --to=nobody@example.com \
441 --smtp-server="$(pwd)/fake.sendmail" \
442 $@ $patches > stdout &&
443 grep "Send this email" stdout
444}
445
446test_expect_success '--confirm=always' '
447 test_confirm --confirm=always --suppress-cc=all
448'
449
450test_expect_success '--confirm=auto' '
451 test_confirm --confirm=auto
452'
453
454test_expect_success '--confirm=cc' '
455 test_confirm --confirm=cc
456'
457
458test_expect_success '--confirm=compose' '
459 test_confirm --confirm=compose --compose
460'
461
462test_expect_success 'confirm by default (due to cc)' '
463 CONFIRM=$(git config --get sendemail.confirm) &&
464 git config --unset sendemail.confirm &&
465 test_confirm
466 ret="$?"
467 git config sendemail.confirm ${CONFIRM:-never}
468 test $ret = "0"
469'
470
471test_expect_success 'confirm by default (due to --compose)' '
472 CONFIRM=$(git config --get sendemail.confirm) &&
473 git config --unset sendemail.confirm &&
474 test_confirm --suppress-cc=all --compose
475 ret="$?"
476 git config sendemail.confirm ${CONFIRM:-never}
477 test $ret = "0"
478'
479
480test_expect_success 'confirm detects EOF (inform assumes y)' '
481 CONFIRM=$(git config --get sendemail.confirm) &&
482 git config --unset sendemail.confirm &&
483 rm -fr outdir &&
484 git format-patch -2 -o outdir &&
485 GIT_SEND_EMAIL_NOTTY=1 \
486 git send-email \
487 --from="Example <nobody@example.com>" \
488 --to=nobody@example.com \
489 --smtp-server="$(pwd)/fake.sendmail" \
490 outdir/*.patch < /dev/null
491 ret="$?"
492 git config sendemail.confirm ${CONFIRM:-never}
493 test $ret = "0"
494'
495
496test_expect_success 'confirm detects EOF (auto causes failure)' '
497 CONFIRM=$(git config --get sendemail.confirm) &&
498 git config sendemail.confirm auto &&
499 GIT_SEND_EMAIL_NOTTY=1 &&
500 export GIT_SEND_EMAIL_NOTTY &&
501 test_must_fail git send-email \
502 --from="Example <nobody@example.com>" \
503 --to=nobody@example.com \
504 --smtp-server="$(pwd)/fake.sendmail" \
505 $patches < /dev/null
506 ret="$?"
507 git config sendemail.confirm ${CONFIRM:-never}
508 test $ret = "0"
509'
510
511test_expect_success 'confirm doesnt loop forever' '
512 CONFIRM=$(git config --get sendemail.confirm) &&
513 git config sendemail.confirm auto &&
514 GIT_SEND_EMAIL_NOTTY=1 &&
515 export GIT_SEND_EMAIL_NOTTY &&
516 yes "bogus" | test_must_fail git send-email \
517 --from="Example <nobody@example.com>" \
518 --to=nobody@example.com \
519 --smtp-server="$(pwd)/fake.sendmail" \
520 $patches
521 ret="$?"
522 git config sendemail.confirm ${CONFIRM:-never}
523 test $ret = "0"
524'
525
526test_expect_success 'utf8 Cc is rfc2047 encoded' '
527 clean_fake_sendmail &&
528 rm -fr outdir &&
529 git format-patch -1 -o outdir --cc="àéìöú <utf8@example.com>" &&
530 git send-email \
531 --from="Example <nobody@example.com>" \
532 --to=nobody@example.com \
533 --smtp-server="$(pwd)/fake.sendmail" \
534 outdir/*.patch &&
535 grep "^Cc:" msgtxt1 |
536 grep "=?utf-8?q?=C3=A0=C3=A9=C3=AC=C3=B6=C3=BA?= <utf8@example.com>"
537'
538
539test_expect_success '--compose adds MIME for utf8 body' '
540 clean_fake_sendmail &&
541 (echo "#!$SHELL_PATH" &&
542 echo "echo utf8 body: àéìöú >>\"\$1\""
543 ) >fake-editor-utf8 &&
544 chmod +x fake-editor-utf8 &&
545 GIT_EDITOR="\"$(pwd)/fake-editor-utf8\"" \
546 git send-email \
547 --compose --subject foo \
548 --from="Example <nobody@example.com>" \
549 --to=nobody@example.com \
550 --smtp-server="$(pwd)/fake.sendmail" \
551 $patches &&
552 grep "^utf8 body" msgtxt1 &&
553 grep "^Content-Type: text/plain; charset=utf-8" msgtxt1
554'
555
556test_expect_success '--compose respects user mime type' '
557 clean_fake_sendmail &&
558 (echo "#!$SHELL_PATH" &&
559 echo "(echo MIME-Version: 1.0"
560 echo " echo Content-Type: text/plain\\; charset=iso-8859-1"
561 echo " echo Content-Transfer-Encoding: 8bit"
562 echo " echo Subject: foo"
563 echo " echo "
564 echo " echo utf8 body: àéìöú) >\"\$1\""
565 ) >fake-editor-utf8-mime &&
566 chmod +x fake-editor-utf8-mime &&
567 GIT_EDITOR="\"$(pwd)/fake-editor-utf8-mime\"" \
568 git send-email \
569 --compose --subject foo \
570 --from="Example <nobody@example.com>" \
571 --to=nobody@example.com \
572 --smtp-server="$(pwd)/fake.sendmail" \
573 $patches &&
574 grep "^utf8 body" msgtxt1 &&
575 grep "^Content-Type: text/plain; charset=iso-8859-1" msgtxt1 &&
576 ! grep "^Content-Type: text/plain; charset=utf-8" msgtxt1
577'
578
579test_expect_success '--compose adds MIME for utf8 subject' '
580 clean_fake_sendmail &&
581 GIT_EDITOR="\"$(pwd)/fake-editor\"" \
582 git send-email \
583 --compose --subject utf8-sübjëct \
584 --from="Example <nobody@example.com>" \
585 --to=nobody@example.com \
586 --smtp-server="$(pwd)/fake.sendmail" \
587 $patches &&
588 grep "^fake edit" msgtxt1 &&
589 grep "^Subject: =?utf-8?q?utf8-s=C3=BCbj=C3=ABct?=" msgtxt1
590'
591
592test_expect_success 'detects ambiguous reference/file conflict' '
593 echo master > master &&
594 git add master &&
595 git commit -m"add master" &&
596 test_must_fail git send-email --dry-run master 2>errors &&
597 grep disambiguate errors
598'
599
600test_expect_success 'feed two files' '
601 rm -fr outdir &&
602 git format-patch -2 -o outdir &&
603 git send-email \
604 --dry-run \
605 --from="Example <nobody@example.com>" \
606 --to=nobody@example.com \
607 outdir/000?-*.patch 2>errors >out &&
608 grep "^Subject: " out >subjects &&
609 test "z$(sed -n -e 1p subjects)" = "zSubject: [PATCH 1/2] Second." &&
610 test "z$(sed -n -e 2p subjects)" = "zSubject: [PATCH 2/2] add master"
611'
612
613test_expect_success 'in-reply-to but no threading' '
614 git send-email \
615 --dry-run \
616 --from="Example <nobody@example.com>" \
617 --to=nobody@example.com \
618 --in-reply-to="<in-reply-id@example.com>" \
619 --nothread \
620 $patches |
621 grep "In-Reply-To: <in-reply-id@example.com>"
622'
623
624test_done