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
133test_expect_success 'Prompting works' '
134 clean_fake_sendmail &&
135 (echo "Example <from@example.com>"
136 echo "to@example.com"
137 echo ""
138 ) | GIT_SEND_EMAIL_NOTTY=1 git send-email \
139 --smtp-server="$(pwd)/fake.sendmail" \
140 $patches \
141 2>errors &&
142 grep "^From: Example <from@example.com>$" msgtxt1 &&
143 grep "^To: to@example.com$" msgtxt1
144'
145
146z8=zzzzzzzz
147z64=$z8$z8$z8$z8$z8$z8$z8$z8
148z512=$z64$z64$z64$z64$z64$z64$z64$z64
149test_expect_success 'reject long lines' '
150 clean_fake_sendmail &&
151 cp $patches longline.patch &&
152 echo $z512$z512 >>longline.patch &&
153 test_must_fail git send-email \
154 --from="Example <nobody@example.com>" \
155 --to=nobody@example.com \
156 --smtp-server="$(pwd)/fake.sendmail" \
157 $patches longline.patch \
158 2>errors &&
159 grep longline.patch errors
160'
161
162test_expect_success 'no patch was sent' '
163 ! test -e commandline1
164'
165
166test_expect_success 'Author From: in message body' '
167 clean_fake_sendmail &&
168 git send-email \
169 --from="Example <nobody@example.com>" \
170 --to=nobody@example.com \
171 --smtp-server="$(pwd)/fake.sendmail" \
172 $patches &&
173 sed "1,/^$/d" < msgtxt1 > msgbody1
174 grep "From: A <author@example.com>" msgbody1
175'
176
177test_expect_success 'Author From: not in message body' '
178 clean_fake_sendmail &&
179 git send-email \
180 --from="A <author@example.com>" \
181 --to=nobody@example.com \
182 --smtp-server="$(pwd)/fake.sendmail" \
183 $patches &&
184 sed "1,/^$/d" < msgtxt1 > msgbody1
185 ! grep "From: A <author@example.com>" msgbody1
186'
187
188test_expect_success 'allow long lines with --no-validate' '
189 git send-email \
190 --from="Example <nobody@example.com>" \
191 --to=nobody@example.com \
192 --smtp-server="$(pwd)/fake.sendmail" \
193 --novalidate \
194 $patches longline.patch \
195 2>errors
196'
197
198test_expect_success 'Invalid In-Reply-To' '
199 clean_fake_sendmail &&
200 git send-email \
201 --from="Example <nobody@example.com>" \
202 --to=nobody@example.com \
203 --in-reply-to=" " \
204 --smtp-server="$(pwd)/fake.sendmail" \
205 $patches
206 2>errors
207 ! grep "^In-Reply-To: < *>" msgtxt1
208'
209
210test_expect_success 'Valid In-Reply-To when prompting' '
211 clean_fake_sendmail &&
212 (echo "From Example <from@example.com>"
213 echo "To Example <to@example.com>"
214 echo ""
215 ) | env GIT_SEND_EMAIL_NOTTY=1 git send-email \
216 --smtp-server="$(pwd)/fake.sendmail" \
217 $patches 2>errors &&
218 ! grep "^In-Reply-To: < *>" msgtxt1
219'
220
221test_expect_success 'setup fake editor' '
222 (echo "#!$SHELL_PATH" &&
223 echo "echo fake edit >>\"\$1\""
224 ) >fake-editor &&
225 chmod +x fake-editor
226'
227
228test_set_editor "$(pwd)/fake-editor"
229
230test_expect_success '--compose works' '
231 clean_fake_sendmail &&
232 git send-email \
233 --compose --subject foo \
234 --from="Example <nobody@example.com>" \
235 --to=nobody@example.com \
236 --smtp-server="$(pwd)/fake.sendmail" \
237 $patches \
238 2>errors
239'
240
241test_expect_success 'first message is compose text' '
242 grep "^fake edit" msgtxt1
243'
244
245test_expect_success 'second message is patch' '
246 grep "Subject:.*Second" msgtxt2
247'
248
249cat >expected-suppress-sob <<\EOF
2500001-Second.patch
251(mbox) Adding cc: A <author@example.com> from line 'From: A <author@example.com>'
252(mbox) Adding cc: One <one@example.com> from line 'Cc: One <one@example.com>, two@example.com'
253(mbox) Adding cc: two@example.com from line 'Cc: One <one@example.com>, two@example.com'
254Dry-OK. Log says:
255Server: relay.example.com
256MAIL FROM:<from@example.com>
257RCPT TO:<to@example.com>,<cc@example.com>,<author@example.com>,<one@example.com>,<two@example.com>
258From: Example <from@example.com>
259To: to@example.com
260Cc: cc@example.com, A <author@example.com>, One <one@example.com>, two@example.com
261Subject: [PATCH 1/1] Second.
262Date: DATE-STRING
263Message-Id: MESSAGE-ID-STRING
264X-Mailer: X-MAILER-STRING
265
266Result: OK
267EOF
268
269test_suppression () {
270 git send-email \
271 --dry-run \
272 --suppress-cc=$1 \
273 --from="Example <from@example.com>" \
274 --to=to@example.com \
275 --smtp-server relay.example.com \
276 $patches |
277 sed -e "s/^\(Date:\).*/\1 DATE-STRING/" \
278 -e "s/^\(Message-Id:\).*/\1 MESSAGE-ID-STRING/" \
279 -e "s/^\(X-Mailer:\).*/\1 X-MAILER-STRING/" \
280 >actual-suppress-$1 &&
281 test_cmp expected-suppress-$1 actual-suppress-$1
282}
283
284test_expect_success 'sendemail.cc set' '
285 git config sendemail.cc cc@example.com &&
286 test_suppression sob
287'
288
289cat >expected-suppress-sob <<\EOF
2900001-Second.patch
291(mbox) Adding cc: A <author@example.com> from line 'From: A <author@example.com>'
292(mbox) Adding cc: One <one@example.com> from line 'Cc: One <one@example.com>, two@example.com'
293(mbox) Adding cc: two@example.com from line 'Cc: One <one@example.com>, two@example.com'
294Dry-OK. Log says:
295Server: relay.example.com
296MAIL FROM:<from@example.com>
297RCPT TO:<to@example.com>,<author@example.com>,<one@example.com>,<two@example.com>
298From: Example <from@example.com>
299To: to@example.com
300Cc: A <author@example.com>, One <one@example.com>, two@example.com
301Subject: [PATCH 1/1] Second.
302Date: DATE-STRING
303Message-Id: MESSAGE-ID-STRING
304X-Mailer: X-MAILER-STRING
305
306Result: OK
307EOF
308
309test_expect_success 'sendemail.cc unset' '
310 git config --unset sendemail.cc &&
311 test_suppression sob
312'
313
314cat >expected-suppress-all <<\EOF
3150001-Second.patch
316Dry-OK. Log says:
317Server: relay.example.com
318MAIL FROM:<from@example.com>
319RCPT TO:<to@example.com>
320From: Example <from@example.com>
321To: to@example.com
322Subject: [PATCH 1/1] Second.
323Date: DATE-STRING
324Message-Id: MESSAGE-ID-STRING
325X-Mailer: X-MAILER-STRING
326
327Result: OK
328EOF
329
330test_expect_success '--suppress-cc=all' '
331 test_suppression all
332'
333
334cat >expected-suppress-body <<\EOF
3350001-Second.patch
336(mbox) Adding cc: A <author@example.com> from line 'From: A <author@example.com>'
337(mbox) Adding cc: One <one@example.com> from line 'Cc: One <one@example.com>, two@example.com'
338(mbox) Adding cc: two@example.com from line 'Cc: One <one@example.com>, two@example.com'
339Dry-OK. Log says:
340Server: relay.example.com
341MAIL FROM:<from@example.com>
342RCPT TO:<to@example.com>,<author@example.com>,<one@example.com>,<two@example.com>
343From: Example <from@example.com>
344To: to@example.com
345Cc: A <author@example.com>, One <one@example.com>, two@example.com
346Subject: [PATCH 1/1] Second.
347Date: DATE-STRING
348Message-Id: MESSAGE-ID-STRING
349X-Mailer: X-MAILER-STRING
350
351Result: OK
352EOF
353
354test_expect_success '--suppress-cc=body' '
355 test_suppression body
356'
357
358cat >expected-suppress-sob <<\EOF
3590001-Second.patch
360(mbox) Adding cc: A <author@example.com> from line 'From: A <author@example.com>'
361(mbox) Adding cc: One <one@example.com> from line 'Cc: One <one@example.com>, two@example.com'
362(mbox) Adding cc: two@example.com from line 'Cc: One <one@example.com>, two@example.com'
363Dry-OK. Log says:
364Server: relay.example.com
365MAIL FROM:<from@example.com>
366RCPT TO:<to@example.com>,<author@example.com>,<one@example.com>,<two@example.com>
367From: Example <from@example.com>
368To: to@example.com
369Cc: A <author@example.com>, One <one@example.com>, two@example.com
370Subject: [PATCH 1/1] Second.
371Date: DATE-STRING
372Message-Id: MESSAGE-ID-STRING
373X-Mailer: X-MAILER-STRING
374
375Result: OK
376EOF
377
378test_expect_success '--suppress-cc=sob' '
379 test_suppression sob
380'
381
382cat >expected-suppress-bodycc <<\EOF
3830001-Second.patch
384(mbox) Adding cc: A <author@example.com> from line 'From: A <author@example.com>'
385(mbox) Adding cc: One <one@example.com> from line 'Cc: One <one@example.com>, two@example.com'
386(mbox) Adding cc: two@example.com from line 'Cc: One <one@example.com>, two@example.com'
387(body) Adding cc: C O Mitter <committer@example.com> from line 'Signed-off-by: C O Mitter <committer@example.com>'
388Dry-OK. Log says:
389Server: relay.example.com
390MAIL FROM:<from@example.com>
391RCPT TO:<to@example.com>,<author@example.com>,<one@example.com>,<two@example.com>,<committer@example.com>
392From: Example <from@example.com>
393To: to@example.com
394Cc: A <author@example.com>, One <one@example.com>, two@example.com, C O Mitter <committer@example.com>
395Subject: [PATCH 1/1] Second.
396Date: DATE-STRING
397Message-Id: MESSAGE-ID-STRING
398X-Mailer: X-MAILER-STRING
399
400Result: OK
401EOF
402
403test_expect_success '--suppress-cc=bodycc' '
404 test_suppression bodycc
405'
406
407cat >expected-suppress-cc <<\EOF
4080001-Second.patch
409(mbox) Adding cc: A <author@example.com> from line 'From: A <author@example.com>'
410(body) Adding cc: C O Mitter <committer@example.com> from line 'Signed-off-by: C O Mitter <committer@example.com>'
411Dry-OK. Log says:
412Server: relay.example.com
413MAIL FROM:<from@example.com>
414RCPT TO:<to@example.com>,<author@example.com>,<committer@example.com>
415From: Example <from@example.com>
416To: to@example.com
417Cc: A <author@example.com>, C O Mitter <committer@example.com>
418Subject: [PATCH 1/1] Second.
419Date: DATE-STRING
420Message-Id: MESSAGE-ID-STRING
421X-Mailer: X-MAILER-STRING
422
423Result: OK
424EOF
425
426test_expect_success '--suppress-cc=cc' '
427 test_suppression cc
428'
429
430test_confirm () {
431 echo y | \
432 GIT_SEND_EMAIL_NOTTY=1 \
433 git send-email \
434 --from="Example <nobody@example.com>" \
435 --to=nobody@example.com \
436 --smtp-server="$(pwd)/fake.sendmail" \
437 $@ $patches > stdout &&
438 grep "Send this email" stdout
439}
440
441test_expect_success '--confirm=always' '
442 test_confirm --confirm=always --suppress-cc=all
443'
444
445test_expect_success '--confirm=auto' '
446 test_confirm --confirm=auto
447'
448
449test_expect_success '--confirm=cc' '
450 test_confirm --confirm=cc
451'
452
453test_expect_success '--confirm=compose' '
454 test_confirm --confirm=compose --compose
455'
456
457test_expect_success 'confirm by default (due to cc)' '
458 CONFIRM=$(git config --get sendemail.confirm) &&
459 git config --unset sendemail.confirm &&
460 test_confirm
461 ret="$?"
462 git config sendemail.confirm ${CONFIRM:-never}
463 test $ret = "0"
464'
465
466test_expect_success 'confirm by default (due to --compose)' '
467 CONFIRM=$(git config --get sendemail.confirm) &&
468 git config --unset sendemail.confirm &&
469 test_confirm --suppress-cc=all --compose
470 ret="$?"
471 git config sendemail.confirm ${CONFIRM:-never}
472 test $ret = "0"
473'
474
475test_expect_success 'confirm detects EOF (inform assumes y)' '
476 CONFIRM=$(git config --get sendemail.confirm) &&
477 git config --unset sendemail.confirm &&
478 rm -fr outdir &&
479 git format-patch -2 -o outdir &&
480 GIT_SEND_EMAIL_NOTTY=1 \
481 git send-email \
482 --from="Example <nobody@example.com>" \
483 --to=nobody@example.com \
484 --smtp-server="$(pwd)/fake.sendmail" \
485 outdir/*.patch < /dev/null
486 ret="$?"
487 git config sendemail.confirm ${CONFIRM:-never}
488 test $ret = "0"
489'
490
491test_expect_success 'confirm detects EOF (auto causes failure)' '
492 CONFIRM=$(git config --get sendemail.confirm) &&
493 git config sendemail.confirm auto &&
494 GIT_SEND_EMAIL_NOTTY=1 &&
495 export GIT_SEND_EMAIL_NOTTY &&
496 test_must_fail git send-email \
497 --from="Example <nobody@example.com>" \
498 --to=nobody@example.com \
499 --smtp-server="$(pwd)/fake.sendmail" \
500 $patches < /dev/null
501 ret="$?"
502 git config sendemail.confirm ${CONFIRM:-never}
503 test $ret = "0"
504'
505
506test_expect_success 'confirm doesnt loop forever' '
507 CONFIRM=$(git config --get sendemail.confirm) &&
508 git config sendemail.confirm auto &&
509 GIT_SEND_EMAIL_NOTTY=1 &&
510 export GIT_SEND_EMAIL_NOTTY &&
511 yes "bogus" | test_must_fail git send-email \
512 --from="Example <nobody@example.com>" \
513 --to=nobody@example.com \
514 --smtp-server="$(pwd)/fake.sendmail" \
515 $patches
516 ret="$?"
517 git config sendemail.confirm ${CONFIRM:-never}
518 test $ret = "0"
519'
520
521test_expect_success 'utf8 Cc is rfc2047 encoded' '
522 clean_fake_sendmail &&
523 rm -fr outdir &&
524 git format-patch -1 -o outdir --cc="àéìöú <utf8@example.com>" &&
525 git send-email \
526 --from="Example <nobody@example.com>" \
527 --to=nobody@example.com \
528 --smtp-server="$(pwd)/fake.sendmail" \
529 outdir/*.patch &&
530 grep "^Cc:" msgtxt1 |
531 grep "=?utf-8?q?=C3=A0=C3=A9=C3=AC=C3=B6=C3=BA?= <utf8@example.com>"
532'
533
534test_expect_success '--compose adds MIME for utf8 body' '
535 clean_fake_sendmail &&
536 (echo "#!$SHELL_PATH" &&
537 echo "echo utf8 body: àéìöú >>\"\$1\""
538 ) >fake-editor-utf8 &&
539 chmod +x fake-editor-utf8 &&
540 GIT_EDITOR="\"$(pwd)/fake-editor-utf8\"" \
541 git send-email \
542 --compose --subject foo \
543 --from="Example <nobody@example.com>" \
544 --to=nobody@example.com \
545 --smtp-server="$(pwd)/fake.sendmail" \
546 $patches &&
547 grep "^utf8 body" msgtxt1 &&
548 grep "^Content-Type: text/plain; charset=utf-8" msgtxt1
549'
550
551test_expect_success '--compose respects user mime type' '
552 clean_fake_sendmail &&
553 (echo "#!$SHELL_PATH" &&
554 echo "(echo MIME-Version: 1.0"
555 echo " echo Content-Type: text/plain\\; charset=iso-8859-1"
556 echo " echo Content-Transfer-Encoding: 8bit"
557 echo " echo Subject: foo"
558 echo " echo "
559 echo " echo utf8 body: àéìöú) >\"\$1\""
560 ) >fake-editor-utf8-mime &&
561 chmod +x fake-editor-utf8-mime &&
562 GIT_EDITOR="\"$(pwd)/fake-editor-utf8-mime\"" \
563 git send-email \
564 --compose --subject foo \
565 --from="Example <nobody@example.com>" \
566 --to=nobody@example.com \
567 --smtp-server="$(pwd)/fake.sendmail" \
568 $patches &&
569 grep "^utf8 body" msgtxt1 &&
570 grep "^Content-Type: text/plain; charset=iso-8859-1" msgtxt1 &&
571 ! grep "^Content-Type: text/plain; charset=utf-8" msgtxt1
572'
573
574test_expect_success '--compose adds MIME for utf8 subject' '
575 clean_fake_sendmail &&
576 GIT_EDITOR="\"$(pwd)/fake-editor\"" \
577 git send-email \
578 --compose --subject utf8-sübjëct \
579 --from="Example <nobody@example.com>" \
580 --to=nobody@example.com \
581 --smtp-server="$(pwd)/fake.sendmail" \
582 $patches &&
583 grep "^fake edit" msgtxt1 &&
584 grep "^Subject: =?utf-8?q?utf8-s=C3=BCbj=C3=ABct?=" msgtxt1
585'
586
587test_expect_success 'detects ambiguous reference/file conflict' '
588 echo master > master &&
589 git add master &&
590 git commit -m"add master" &&
591 test_must_fail git send-email --dry-run master 2>errors &&
592 grep disambiguate errors
593'
594
595test_expect_success 'feed two files' '
596 rm -fr outdir &&
597 git format-patch -2 -o outdir &&
598 git send-email \
599 --dry-run \
600 --from="Example <nobody@example.com>" \
601 --to=nobody@example.com \
602 outdir/000?-*.patch 2>errors >out &&
603 grep "^Subject: " out >subjects &&
604 test "z$(sed -n -e 1p subjects)" = "zSubject: [PATCH 1/2] Second." &&
605 test "z$(sed -n -e 2p subjects)" = "zSubject: [PATCH 2/2] add master"
606'
607
608test_expect_success 'in-reply-to but no threading' '
609 git send-email \
610 --dry-run \
611 --from="Example <nobody@example.com>" \
612 --to=nobody@example.com \
613 --in-reply-to="<in-reply-id@example.com>" \
614 --no-thread \
615 $patches |
616 grep "In-Reply-To: <in-reply-id@example.com>"
617'
618
619test_done