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