3 test_description='git send-email'
6 if ! test_have_prereq PERL; then
7 say 'skipping git send-email tests, perl not available'
13 'prepare reference tree' \
14 'echo "1A quick brown fox jumps over the" >file &&
15 echo "lazy dog" >>file &&
17 GIT_AUTHOR_NAME="A" git commit -a -m "Initial."'
21 '(echo "#!$SHELL_PATH"
24 echo "while test -f commandline\$output; do output=\$((\$output+1)); done"
27 echo " echo \"!\$a!\""
28 echo "done >commandline\$output"
29 echo "cat > msgtxt\$output"
31 chmod +x ./fake.sendmail &&
32 git add fake.sendmail &&
33 GIT_AUTHOR_NAME="A" git commit -a -m "Second."'
35 clean_fake_sendmail() {
36 rm -f commandline* msgtxt*
39 test_expect_success 'Extract patches' '
40 patches=`git format-patch -s --cc="One <one@example.com>" --cc=two@example.com -n HEAD^1`
43 # Test no confirm early to ensure remaining tests will not hang
47 GIT_SEND_EMAIL_NOTTY=1 \
49 --from="Example <from@example.com>" \
50 --to=nobody@example.com \
51 --smtp-server="$(pwd)/fake.sendmail" \
54 test_must_fail grep "Send this email" stdout &&
58 # Exit immediately to prevent hang if a no-confirm test fails
60 test -f no_confirm_okay || {
61 say 'No confirm test failed; skipping remaining tests to prevent hanging'
66 test_expect_success 'No confirm with --suppress-cc' '
67 test_no_confirm --suppress-cc=sob
71 test_expect_success 'No confirm with --confirm=never' '
72 test_no_confirm --confirm=never
76 # leave sendemail.confirm set to never after this so that none of the
77 # remaining tests prompt unintentionally.
78 test_expect_success 'No confirm with sendemail.confirm=never' '
79 git config sendemail.confirm never &&
80 test_no_confirm --compose --subject=foo
84 test_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
95 'Verify commandline' \
96 'test_cmp expected commandline1'
98 cat >expected-show-all-headers <<\EOF
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'
104 Server: relay.example.com
105 MAIL FROM:<from@example.com>
106 RCPT TO:<to@example.com>,<cc@example.com>,<author@example.com>,<one@example.com>,<two@example.com>,<bcc@example.com>
107 From: Example <from@example.com>
109 Cc: cc@example.com, A <author@example.com>, One <one@example.com>, two@example.com
110 Subject: [PATCH 1/1] Second.
112 Message-Id: MESSAGE-ID-STRING
113 X-Mailer: X-MAILER-STRING
114 In-Reply-To: <unique-message-id@example.com>
115 References: <unique-message-id@example.com>
120 test_expect_success 'Show all headers' '
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 \
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
138 test_expect_success 'Prompting works' '
139 clean_fake_sendmail &&
140 (echo "Example <from@example.com>"
141 echo "to@example.com"
143 ) | GIT_SEND_EMAIL_NOTTY=1 git send-email \
144 --smtp-server="$(pwd)/fake.sendmail" \
147 grep "^From: Example <from@example.com>$" msgtxt1 &&
148 grep "^To: to@example.com$" msgtxt1
152 z64=$z8$z8$z8$z8$z8$z8$z8$z8
153 z512=$z64$z64$z64$z64$z64$z64$z64$z64
154 test_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 \
164 grep longline.patch errors
167 test_expect_success 'no patch was sent' '
168 ! test -e commandline1
171 test_expect_success 'Author From: in message body' '
172 clean_fake_sendmail &&
174 --from="Example <nobody@example.com>" \
175 --to=nobody@example.com \
176 --smtp-server="$(pwd)/fake.sendmail" \
178 sed "1,/^$/d" < msgtxt1 > msgbody1
179 grep "From: A <author@example.com>" msgbody1
182 test_expect_success 'Author From: not in message body' '
183 clean_fake_sendmail &&
185 --from="A <author@example.com>" \
186 --to=nobody@example.com \
187 --smtp-server="$(pwd)/fake.sendmail" \
189 sed "1,/^$/d" < msgtxt1 > msgbody1
190 ! grep "From: A <author@example.com>" msgbody1
193 test_expect_success 'allow long lines with --no-validate' '
195 --from="Example <nobody@example.com>" \
196 --to=nobody@example.com \
197 --smtp-server="$(pwd)/fake.sendmail" \
199 $patches longline.patch \
203 test_expect_success 'Invalid In-Reply-To' '
204 clean_fake_sendmail &&
206 --from="Example <nobody@example.com>" \
207 --to=nobody@example.com \
209 --smtp-server="$(pwd)/fake.sendmail" \
212 ! grep "^In-Reply-To: < *>" msgtxt1
215 test_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>"
220 ) | env GIT_SEND_EMAIL_NOTTY=1 git send-email \
221 --smtp-server="$(pwd)/fake.sendmail" \
223 ! grep "^In-Reply-To: < *>" msgtxt1
226 test_expect_success 'setup fake editor' '
227 (echo "#!$SHELL_PATH" &&
228 echo "echo fake edit >>\"\$1\""
233 test_set_editor "$(pwd)/fake-editor"
235 test_expect_success '--compose works' '
236 clean_fake_sendmail &&
238 --compose --subject foo \
239 --from="Example <nobody@example.com>" \
240 --to=nobody@example.com \
241 --smtp-server="$(pwd)/fake.sendmail" \
246 test_expect_success 'first message is compose text' '
247 grep "^fake edit" msgtxt1
250 test_expect_success 'second message is patch' '
251 grep "Subject:.*Second" msgtxt2
254 cat >expected-suppress-sob <<\EOF
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'
260 Server: relay.example.com
261 MAIL FROM:<from@example.com>
262 RCPT TO:<to@example.com>,<cc@example.com>,<author@example.com>,<one@example.com>,<two@example.com>
263 From: Example <from@example.com>
265 Cc: cc@example.com, A <author@example.com>, One <one@example.com>, two@example.com
266 Subject: [PATCH 1/1] Second.
268 Message-Id: MESSAGE-ID-STRING
269 X-Mailer: X-MAILER-STRING
274 test_suppression () {
278 --from="Example <from@example.com>" \
279 --to=to@example.com \
280 --smtp-server relay.example.com \
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
289 test_expect_success 'sendemail.cc set' '
290 git config sendemail.cc cc@example.com &&
294 cat >expected-suppress-sob <<\EOF
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'
300 Server: relay.example.com
301 MAIL FROM:<from@example.com>
302 RCPT TO:<to@example.com>,<author@example.com>,<one@example.com>,<two@example.com>
303 From: Example <from@example.com>
305 Cc: A <author@example.com>, One <one@example.com>, two@example.com
306 Subject: [PATCH 1/1] Second.
308 Message-Id: MESSAGE-ID-STRING
309 X-Mailer: X-MAILER-STRING
314 test_expect_success 'sendemail.cc unset' '
315 git config --unset sendemail.cc &&
319 cat >expected-suppress-all <<\EOF
322 Server: relay.example.com
323 MAIL FROM:<from@example.com>
324 RCPT TO:<to@example.com>
325 From: Example <from@example.com>
327 Subject: [PATCH 1/1] Second.
329 Message-Id: MESSAGE-ID-STRING
330 X-Mailer: X-MAILER-STRING
335 test_expect_success '--suppress-cc=all' '
339 cat >expected-suppress-body <<\EOF
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'
345 Server: relay.example.com
346 MAIL FROM:<from@example.com>
347 RCPT TO:<to@example.com>,<author@example.com>,<one@example.com>,<two@example.com>
348 From: Example <from@example.com>
350 Cc: A <author@example.com>, One <one@example.com>, two@example.com
351 Subject: [PATCH 1/1] Second.
353 Message-Id: MESSAGE-ID-STRING
354 X-Mailer: X-MAILER-STRING
359 test_expect_success '--suppress-cc=body' '
360 test_suppression body
363 cat >expected-suppress-sob <<\EOF
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'
369 Server: relay.example.com
370 MAIL FROM:<from@example.com>
371 RCPT TO:<to@example.com>,<author@example.com>,<one@example.com>,<two@example.com>
372 From: Example <from@example.com>
374 Cc: A <author@example.com>, One <one@example.com>, two@example.com
375 Subject: [PATCH 1/1] Second.
377 Message-Id: MESSAGE-ID-STRING
378 X-Mailer: X-MAILER-STRING
383 test_expect_success '--suppress-cc=sob' '
387 cat >expected-suppress-bodycc <<\EOF
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>'
394 Server: relay.example.com
395 MAIL FROM:<from@example.com>
396 RCPT TO:<to@example.com>,<author@example.com>,<one@example.com>,<two@example.com>,<committer@example.com>
397 From: Example <from@example.com>
399 Cc: A <author@example.com>, One <one@example.com>, two@example.com, C O Mitter <committer@example.com>
400 Subject: [PATCH 1/1] Second.
402 Message-Id: MESSAGE-ID-STRING
403 X-Mailer: X-MAILER-STRING
408 test_expect_success '--suppress-cc=bodycc' '
409 test_suppression bodycc
412 cat >expected-suppress-cc <<\EOF
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>'
417 Server: relay.example.com
418 MAIL FROM:<from@example.com>
419 RCPT TO:<to@example.com>,<author@example.com>,<committer@example.com>
420 From: Example <from@example.com>
422 Cc: A <author@example.com>, C O Mitter <committer@example.com>
423 Subject: [PATCH 1/1] Second.
425 Message-Id: MESSAGE-ID-STRING
426 X-Mailer: X-MAILER-STRING
431 test_expect_success '--suppress-cc=cc' '
437 GIT_SEND_EMAIL_NOTTY=1 \
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
446 test_expect_success '--confirm=always' '
447 test_confirm --confirm=always --suppress-cc=all
450 test_expect_success '--confirm=auto' '
451 test_confirm --confirm=auto
454 test_expect_success '--confirm=cc' '
455 test_confirm --confirm=cc
458 test_expect_success '--confirm=compose' '
459 test_confirm --confirm=compose --compose
462 test_expect_success 'confirm by default (due to cc)' '
463 CONFIRM=$(git config --get sendemail.confirm) &&
464 git config --unset sendemail.confirm &&
467 git config sendemail.confirm ${CONFIRM:-never}
471 test_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
476 git config sendemail.confirm ${CONFIRM:-never}
480 test_expect_success 'confirm detects EOF (inform assumes y)' '
481 CONFIRM=$(git config --get sendemail.confirm) &&
482 git config --unset sendemail.confirm &&
484 git format-patch -2 -o outdir &&
485 GIT_SEND_EMAIL_NOTTY=1 \
487 --from="Example <nobody@example.com>" \
488 --to=nobody@example.com \
489 --smtp-server="$(pwd)/fake.sendmail" \
490 outdir/*.patch < /dev/null
492 git config sendemail.confirm ${CONFIRM:-never}
496 test_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" \
507 git config sendemail.confirm ${CONFIRM:-never}
511 test_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" \
522 git config sendemail.confirm ${CONFIRM:-never}
526 test_expect_success 'utf8 Cc is rfc2047 encoded' '
527 clean_fake_sendmail &&
529 git format-patch -1 -o outdir --cc="àéìöú <utf8@example.com>" &&
531 --from="Example <nobody@example.com>" \
532 --to=nobody@example.com \
533 --smtp-server="$(pwd)/fake.sendmail" \
535 grep "^Cc:" msgtxt1 |
536 grep "=?UTF-8?q?=C3=A0=C3=A9=C3=AC=C3=B6=C3=BA?= <utf8@example.com>"
539 test_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\"" \
547 --compose --subject foo \
548 --from="Example <nobody@example.com>" \
549 --to=nobody@example.com \
550 --smtp-server="$(pwd)/fake.sendmail" \
552 grep "^utf8 body" msgtxt1 &&
553 grep "^Content-Type: text/plain; charset=UTF-8" msgtxt1
556 test_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"
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\"" \
569 --compose --subject foo \
570 --from="Example <nobody@example.com>" \
571 --to=nobody@example.com \
572 --smtp-server="$(pwd)/fake.sendmail" \
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
579 test_expect_success '--compose adds MIME for utf8 subject' '
580 clean_fake_sendmail &&
581 GIT_EDITOR="\"$(pwd)/fake-editor\"" \
583 --compose --subject utf8-sübjëct \
584 --from="Example <nobody@example.com>" \
585 --to=nobody@example.com \
586 --smtp-server="$(pwd)/fake.sendmail" \
588 grep "^fake edit" msgtxt1 &&
589 grep "^Subject: =?UTF-8?q?utf8-s=C3=BCbj=C3=ABct?=" msgtxt1
592 test_expect_success 'detects ambiguous reference/file conflict' '
593 echo master > master &&
595 git commit -m"add master" &&
596 test_must_fail git send-email --dry-run master 2>errors &&
597 grep disambiguate errors
600 test_expect_success 'feed two files' '
602 git format-patch -2 -o outdir &&
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"
613 test_expect_success 'in-reply-to but no threading' '
616 --from="Example <nobody@example.com>" \
617 --to=nobody@example.com \
618 --in-reply-to="<in-reply-id@example.com>" \
621 grep "In-Reply-To: <in-reply-id@example.com>"
624 test_expect_success 'no in-reply-to and no threading' '
627 --from="Example <nobody@example.com>" \
628 --to=nobody@example.com \
630 $patches $patches >stdout &&
631 ! grep "In-Reply-To: " stdout
634 test_expect_success 'threading but no chain-reply-to' '
637 --from="Example <nobody@example.com>" \
638 --to=nobody@example.com \
641 $patches $patches >stdout &&
642 grep "In-Reply-To: " stdout