Re: [PATCH 2/2] test: use emacsclient(1) for Emacs tests
authorDmitry Kurochkin <dmitry.kurochkin@gmail.com>
Tue, 28 Jun 2011 01:03:11 +0000 (05:03 +0400)
committerW. Trevor King <wking@tremily.us>
Fri, 7 Nov 2014 17:38:44 +0000 (09:38 -0800)
92/08c4f695702d9be359ca6b2c01f30799eea6ad [new file with mode: 0644]

diff --git a/92/08c4f695702d9be359ca6b2c01f30799eea6ad b/92/08c4f695702d9be359ca6b2c01f30799eea6ad
new file mode 100644 (file)
index 0000000..30931e0
--- /dev/null
@@ -0,0 +1,644 @@
+Return-Path: <dmitry.kurochkin@gmail.com>\r
+X-Original-To: notmuch@notmuchmail.org\r
+Delivered-To: notmuch@notmuchmail.org\r
+Received: from localhost (localhost [127.0.0.1])\r
+       by olra.theworths.org (Postfix) with ESMTP id A4FF0429E25\r
+       for <notmuch@notmuchmail.org>; Mon, 27 Jun 2011 18:03:21 -0700 (PDT)\r
+X-Virus-Scanned: Debian amavisd-new at olra.theworths.org\r
+X-Spam-Flag: NO\r
+X-Spam-Score: -0.799\r
+X-Spam-Level: \r
+X-Spam-Status: No, score=-0.799 tagged_above=-999 required=5\r
+       tests=[DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1,\r
+       FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_LOW=-0.7] autolearn=disabled\r
+Received: from olra.theworths.org ([127.0.0.1])\r
+       by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024)\r
+       with ESMTP id cT2OPdsY99Ju for <notmuch@notmuchmail.org>;\r
+       Mon, 27 Jun 2011 18:03:19 -0700 (PDT)\r
+Received: from mail-bw0-f53.google.com (mail-bw0-f53.google.com\r
+       [209.85.214.53]) (using TLSv1 with cipher RC4-SHA (128/128 bits))\r
+       (No client certificate requested)\r
+       by olra.theworths.org (Postfix) with ESMTPS id 1D3F6431FD0\r
+       for <notmuch@notmuchmail.org>; Mon, 27 Jun 2011 18:03:18 -0700 (PDT)\r
+Received: by bwg12 with SMTP id 12so4785130bwg.26\r
+       for <notmuch@notmuchmail.org>; Mon, 27 Jun 2011 18:03:17 -0700 (PDT)\r
+DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma;\r
+       h=domainkey-signature:from:to:cc:subject:in-reply-to:references\r
+       :user-agent:date:message-id:mime-version:content-type\r
+       :content-transfer-encoding;\r
+       bh=Ssmt3zhFE8vqcl5sHdeet7qu+7denH4HMjuHb4voBP0=;\r
+       b=gWqwXcupkspRWRwEii6JD1kKQsSklrhKxBsPDTWSLDuz5IX+cPlKZlR0B0Q4xC15fY\r
+       Mex565Bv7cEBUUFTzXhey+lpmyBxySQZ3JM9+JUxWNtckkYTOiU9Bh5/c5cYPsQwURXN\r
+       UzD55XYj9A9uPZiIaJxMA/haKfutdl3imKDMQ=\r
+DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma;\r
+       h=from:to:cc:subject:in-reply-to:references:user-agent:date\r
+       :message-id:mime-version:content-type:content-transfer-encoding;\r
+       b=J6xE4GLzUhLNbNkdmQmJvtFUlkV/I9MYQQmGMEVn1hvgTR2zV9JKgbHzOw8nu1Qv1V\r
+       g+amqc294tl0+5cynA/fsVxKvA3llW2wZ3D61fKx80w+mnU3z2nx2zPh9ydb7LwYrTiG\r
+       JP4iEpJY8WLmdapt28vC9POrVyvWhE/+8rdlg=\r
+Received: by 10.204.57.82 with SMTP id b18mr1585748bkh.95.1309222997435;\r
+       Mon, 27 Jun 2011 18:03:17 -0700 (PDT)\r
+Received: from localhost ([91.144.186.21])\r
+       by mx.google.com with ESMTPS id l24sm4630993bkw.3.2011.06.27.18.03.15\r
+       (version=TLSv1/SSLv3 cipher=OTHER);\r
+       Mon, 27 Jun 2011 18:03:16 -0700 (PDT)\r
+From: Dmitry Kurochkin <dmitry.kurochkin@gmail.com>\r
+To: Austin Clements <amdragon@mit.edu>\r
+Subject: Re: [PATCH 2/2] test: use emacsclient(1) for Emacs tests\r
+In-Reply-To: <87hb7byqge.fsf@gmail.com>\r
+References: <1309132379-24089-1-git-send-email-dmitry.kurochkin@gmail.com>\r
+       <1309146846-30991-1-git-send-email-dmitry.kurochkin@gmail.com>\r
+       <1309146846-30991-2-git-send-email-dmitry.kurochkin@gmail.com>\r
+       <BANLkTi=nwHRndz367K5oh4=tPaU-KNeZ8Q@mail.gmail.com>\r
+       <87hb7byqge.fsf@gmail.com>\r
+User-Agent: Notmuch/0.5-275-g75c95e5 (http://notmuchmail.org) Emacs/23.3.1\r
+       (x86_64-pc-linux-gnu)\r
+Date: Tue, 28 Jun 2011 05:03:11 +0400\r
+Message-ID: <87d3hyzs1c.fsf@gmail.com>\r
+MIME-Version: 1.0\r
+Content-Type: text/plain; charset=utf-8\r
+Content-Transfer-Encoding: quoted-printable\r
+Cc: notmuch@notmuchmail.org\r
+X-BeenThere: notmuch@notmuchmail.org\r
+X-Mailman-Version: 2.1.13\r
+Precedence: list\r
+List-Id: "Use and development of the notmuch mail system."\r
+       <notmuch.notmuchmail.org>\r
+List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,\r
+       <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>\r
+List-Archive: <http://notmuchmail.org/pipermail/notmuch>\r
+List-Post: <mailto:notmuch@notmuchmail.org>\r
+List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>\r
+List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,\r
+       <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
+X-List-Received-Date: Tue, 28 Jun 2011 01:03:21 -0000\r
+\r
+Austin,\r
+\r
+On Tue, 28 Jun 2011 00:22:41 +0400, Dmitry Kurochkin <dmitry.kurochkin@gmai=\r
+l.com> wrote:\r
+> On Mon, 27 Jun 2011 16:02:12 -0400, Austin Clements <amdragon@mit.edu> wr=\r
+ote:\r
+> > This looks like a great idea!  The test suite has been getting irritati=\r
+ng slow.\r
+> >=20\r
+> > A few minor comments: This patch would be clearer if it the\r
+> > setq-to-let translation were a separate patch.  It would also be worth\r
+> > adding a big comment at the top of the test explaining why all of the\r
+> > tests let-bind everything instead of setq'ing, primarily for the\r
+> > benefit of people writing new tests.\r
+> >=20\r
+>=20\r
+> Agreed, will separate and add the warning.\r
+>=20\r
+> > I might just be having trouble reading the patch, but the difference\r
+> > between emacs_start and emacs_server_start seems unclear.  Perhaps the\r
+> > comments should explain how somebody would use these scripts?\r
+> >=20\r
+>=20\r
+> emacs_start start a normal Emacs in non-daemon mode.  Something you\r
+> might prefer when debugging.\r
+>=20\r
+> >=20\r
+> > My bigger concern with this change is that it may leave behind stale\r
+> > emacs daemons if the script gets interrupted.\r
+>=20\r
+> That is an issue indeed.  I would probably do smth like a periodic check\r
+> inside Emacs that the shell is alive, but your approach below looks more\r
+> reliable.\r
+>=20\r
+> >  The only way I know to\r
+> > reliably kill a child process is to open a pipe to it and have it exit\r
+> > on its own when it reads EOF.  Unfortunately, I couldn't find a way to\r
+> > do this with an emacs daemon (it appears daemon mode aggressively\r
+> > cleans up things like pipes), but here's a different approach:\r
+> >=20\r
+> >     coproc emacs --batch --eval "(while t (eval (read)))"\r
+> >     EMACSFD=3D${COPROC[1]}\r
+> >     trap "echo '(kill-emacs)' >&$EMACSFD" EXIT\r
+> >=20\r
+> >     echo '(message "Hi")' >&$EMACSFD\r
+> >     # ...\r
+> >=20\r
+> > This is, basically, a poor man's emacs server, but the coprocess pipe\r
+> > binds it tightly to the shell.  If the shell exits for *any* reason,\r
+> > the pipe will be closed by the kernel, emacs will read an EOF, and\r
+> > exit.\r
+>=20\r
+> I like this idea.\r
+>=20\r
+> >  The trap is there just to cleanly shut down in case of a normal\r
+> > exit [1].\r
+>=20\r
+> For normal exit we should just put this into test_done.  Otherwise it is\r
+> not a normal exit and we do not care about Emacs error message.  No?\r
+>=20\r
+> >  This also has the advantage that read-from-minibuffer still\r
+> > works:\r
+> >=20\r
+> >     echo '(message (read-from-minibuffer ""))' >&$EMACSFD\r
+> >     echo 'Test' >&$EMACSFD\r
+> >=20\r
+> > Thoughts?\r
+> >=20\r
+>=20\r
+> I like it and I will implement it.  Thanks for the idea.\r
+>=20\r
+\r
+While implementing the idea, I stumbled upon a problem: we need to know\r
+when Emacs finished what we echoed or failed with an error.  At the\r
+moment tests fail because they check for OUTPUT before Emacs creates it.\r
+\r
+We can tell Emacs to print some special marker and wait for it.  But\r
+there may be exceptions and errors which may make it difficult.  I did\r
+not found a good solution yet.  Would love to hear your thoughts :)\r
+\r
+Regards,\r
+  Dmitry\r
+\r
+> Regards,\r
+>   Dmitry\r
+>=20\r
+> > [1] If you don't do this, emacs complains that it can't read from\r
+> > stdin before it exits.  It would be nice to catch this condition in\r
+> > the elisp code and not bother with the trap, but the error thrown is\r
+> > just an 'error, so I don't think we can catch and ignore it without\r
+> > catching and ignoring *all* errors.\r
+> >=20\r
+> > On Sun, Jun 26, 2011 at 11:54 PM, Dmitry Kurochkin\r
+> > <dmitry.kurochkin@gmail.com> wrote:\r
+> > > Before the change, every Emacs tests ran in a separate Emacs\r
+> > > instance. =C2=A0Starting Emacs many times wastes considerable time and\r
+> > > it gets worse as the test suite grows. =C2=A0The patch solves this by\r
+> > > using a single Emacs server and emacsclient(1) to run multiple\r
+> > > tests. =C2=A0Emacs server is started on the first test_emacs call and\r
+> > > stopped when test_done is called or the test is killed by a\r
+> > > signal. =C2=A0Several auxiliary scripts useful for debugging and test\r
+> > > development are generated instead of the run_emacs script:\r
+> > >\r
+> > > =C2=A0* emacs_server_start - start Emacs server\r
+> > > =C2=A0* emacs_server_stop =C2=A0- stop Emacs server\r
+> > > =C2=A0* emacs_start =C2=A0 =C2=A0 =C2=A0 =C2=A0- start Emacs\r
+> > > =C2=A0* emacs_run =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0- execute ELisp e=\r
+xpressions in running Emacs server\r
+> > >\r
+> > > Since multiple tests are run in a single Emacs instance, they\r
+> > > must not change Emacs environment because it may affect other\r
+> > > tests. =C2=A0For now, the only Emacs environment modifications done by\r
+> > > the tests are variable settings. =C2=A0Before the change, variables\r
+> > > were set with `setq' which affected other tests. =C2=A0The patch\r
+> > > changes all variables to use `let', so the scope of the change is\r
+> > > limited to a single test.\r
+> > > ---\r
+> > > =C2=A0test/emacs =C2=A0 =C2=A0 =C2=A0 | =C2=A0 74 +++++++++++++------=\r
+-------\r
+> > > =C2=A0test/test-lib.el | =C2=A0 =C2=A06 ++\r
+> > > =C2=A0test/test-lib.sh | =C2=A0149 ++++++++++++++++++++++++++++++++++=\r
+++++++++-----------\r
+> > > =C2=A03 files changed, 161 insertions(+), 68 deletions(-)\r
+> > >\r
+> > > diff --git a/test/emacs b/test/emacs\r
+> > > index 4f16b41..f1939dc 100755\r
+> > > --- a/test/emacs\r
+> > > +++ b/test/emacs\r
+> > > @@ -12,20 +12,20 @@ test_emacs '(notmuch-hello)\r
+> > > =C2=A0test_expect_equal_file OUTPUT $EXPECTED/notmuch-hello\r
+> > >\r
+> > > =C2=A0test_begin_subtest "Saved search with 0 results"\r
+> > > -test_emacs '(setq notmuch-show-empty-saved-searches t)\r
+> > > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (setq notmuch-saved-searches\r
+> > > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 '\''(("inbo=\r
+x" . "tag:inbox")\r
+> > > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=\r
+=A0 =C2=A0("unread" . "tag:unread")\r
+> > > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=\r
+=A0 =C2=A0("empty" . "tag:doesnotexist")))\r
+> > > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (notmuch-hello)\r
+> > > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (test-output)'\r
+> > > +test_emacs '(let ((notmuch-show-empty-saved-searches t)\r
+> > > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (notmuch-sa=\r
+ved-searches\r
+> > > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0'\''(=\r
+("inbox" . "tag:inbox")\r
+> > > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=\r
+=A0 =C2=A0 ("unread" . "tag:unread")\r
+> > > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=\r
+=A0 =C2=A0 ("empty" . "tag:doesnotexist"))))\r
+> > > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (notmuch-hello)\r
+> > > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (test-output))'\r
+> > > =C2=A0test_expect_equal_file OUTPUT $EXPECTED/notmuch-hello-with-empty\r
+> > >\r
+> > > =C2=A0test_begin_subtest "No saved searches displayed (all with 0 res=\r
+ults)"\r
+> > > -test_emacs '(setq notmuch-saved-searches\r
+> > > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 '\''(("empt=\r
+y" . "tag:doesnotexist")))\r
+> > > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (notmuch-hello)\r
+> > > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (test-output)'\r
+> > > +test_emacs '(let ((notmuch-saved-searches\r
+> > > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0'\''(=\r
+("empty" . "tag:doesnotexist"))))\r
+> > > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (notmuch-hello)\r
+> > > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (test-output))'\r
+> > > =C2=A0test_expect_equal_file OUTPUT $EXPECTED/notmuch-hello-no-saved-=\r
+searches\r
+> > >\r
+> > > =C2=A0test_begin_subtest "Basic notmuch-search view in emacs"\r
+> > > @@ -147,9 +147,9 @@ output=3D$(notmuch search 'subject:"testing messa=\r
+ge sent via SMTP"' | notmuch_sear\r
+> > > =C2=A0test_expect_equal "$output" "thread:XXX =C2=A0 2000-01-01 [1/1]=\r
+ Notmuch Test Suite; Testing message sent via SMTP (inbox)"\r
+> > >\r
+> > > =C2=A0test_begin_subtest "notmuch-fcc-dirs set to nil"\r
+> > > -test_emacs "(setq notmuch-fcc-dirs nil)\r
+> > > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (notmuch-mua-mail)\r
+> > > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (test-output)"\r
+> > > +test_emacs "(let ((notmuch-fcc-dirs nil))\r
+> > > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (notmuch-mua-mail)\r
+> > > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (test-output))"\r
+> > > =C2=A0cat <<EOF >EXPECTED\r
+> > > =C2=A0From: Notmuch Test Suite <test_suite@notmuchmail.org>\r
+> > > =C2=A0To:\r
+> > > @@ -164,9 +164,9 @@ mkdir -p mail/sent-string/new\r
+> > > =C2=A0mkdir -p mail/sent-string/tmp\r
+> > >\r
+> > > =C2=A0test_begin_subtest "notmuch-fcc-dirs set to a string"\r
+> > > -test_emacs "(setq notmuch-fcc-dirs \"sent-string\")\r
+> > > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (notmuch-mua-mail)\r
+> > > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (test-output)"\r
+> > > +test_emacs "(let ((notmuch-fcc-dirs \"sent-string\"))\r
+> > > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (notmuch-mua-mail)\r
+> > > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (test-output))"\r
+> > > =C2=A0cat <<EOF >EXPECTED\r
+> > > =C2=A0From: Notmuch Test Suite <test_suite@notmuchmail.org>\r
+> > > =C2=A0To:\r
+> > > @@ -185,11 +185,11 @@ mkdir -p mail/failure/new\r
+> > > =C2=A0mkdir -p mail/failure/tmp\r
+> > >\r
+> > > =C2=A0test_begin_subtest "notmuch-fcc-dirs set to a list (with match)"\r
+> > > -test_emacs "(setq notmuch-fcc-dirs\r
+> > > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 '((\"notmuc=\r
+hmail.org\" . \"sent-list-match\")\r
+> > > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (\".=\r
+*\" . \"failure\")))\r
+> > > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (notmuch-mua-mail)\r
+> > > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (test-output)"\r
+> > > +test_emacs "(let ((notmuch-fcc-dirs\r
+> > > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0'((\"=\r
+notmuchmail.org\" . \"sent-list-match\")\r
+> > > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=\r
+=A0(\".*\" . \"failure\"))))\r
+> > > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (notmuch-mua-mail)\r
+> > > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (test-output))"\r
+> > > =C2=A0cat <<EOF >EXPECTED\r
+> > > =C2=A0From: Notmuch Test Suite <test_suite@notmuchmail.org>\r
+> > > =C2=A0To:\r
+> > > @@ -205,11 +205,11 @@ mkdir -p mail/sent-list-catch-all/new\r
+> > > =C2=A0mkdir -p mail/sent-list-catch-all/tmp\r
+> > >\r
+> > > =C2=A0test_begin_subtest "notmuch-fcc-dirs set to a list (catch-all)"\r
+> > > -test_emacs "(setq notmuch-fcc-dirs\r
+> > > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 '((\"exampl=\r
+e.com\" . \"failure\")\r
+> > > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (\".=\r
+*\" . \"sent-list-catch-all\")))\r
+> > > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (notmuch-mua-mail)\r
+> > > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (test-output)"\r
+> > > +test_emacs "(let ((notmuch-fcc-dirs\r
+> > > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0'((\"=\r
+example.com\" . \"failure\")\r
+> > > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=\r
+=A0(\".*\" . \"sent-list-catch-all\"))))\r
+> > > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (notmuch-mua-mail)\r
+> > > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (test-output))"\r
+> > > =C2=A0cat <<EOF >EXPECTED\r
+> > > =C2=A0From: Notmuch Test Suite <test_suite@notmuchmail.org>\r
+> > > =C2=A0To:\r
+> > > @@ -220,11 +220,11 @@ EOF\r
+> > > =C2=A0test_expect_equal_file OUTPUT EXPECTED\r
+> > >\r
+> > > =C2=A0test_begin_subtest "notmuch-fcc-dirs set to a list (no match)"\r
+> > > -test_emacs "(setq notmuch-fcc-dirs\r
+> > > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 '((\"exampl=\r
+e.com\" . \"failure\")\r
+> > > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (\"n=\r
+omatchhere.net\" . \"failure\")))\r
+> > > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (notmuch-mua-mail)\r
+> > > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (test-output)"\r
+> > > +test_emacs "(let ((notmuch-fcc-dirs\r
+> > > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0'((\"=\r
+example.com\" . \"failure\")\r
+> > > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=\r
+=A0(\"nomatchhere.net\" . \"failure\"))))\r
+> > > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (notmuch-mua-mail)\r
+> > > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (test-output))"\r
+> > > =C2=A0cat <<EOF >EXPECTED\r
+> > > =C2=A0From: Notmuch Test Suite <test_suite@notmuchmail.org>\r
+> > > =C2=A0To:\r
+> > > @@ -253,15 +253,15 @@ test_expect_equal_file OUTPUT EXPECTED\r
+> > >\r
+> > > =C2=A0test_begin_subtest "Save attachment from within emacs using not=\r
+much-show-save-attachments"\r
+> > > =C2=A0# save as archive to test that Emacs does not re-compress .gz\r
+> > > -echo ./attachment1.gz |\r
+> > > -test_emacs '(notmuch-show "id:cf0c4d610911171136h1713aa59w9cf9aa31f0=\r
+52ad0a@mail.gmail.com")\r
+> > > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (notmuch-show-save-attachments)'=\r
+ > /dev/null 2>&1\r
+> > > +test_emacs '(let ((standard-input "\"attachment1.gz\""))\r
+> > > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (notmuch-show "id:cf0c4d6=\r
+10911171136h1713aa59w9cf9aa31f052ad0a@mail.gmail.com")\r
+> > > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (notmuch-show-save-attach=\r
+ments))'\r
+> > > =C2=A0test_expect_equal_file "$EXPECTED/attachment" attachment1.gz\r
+> > >\r
+> > > =C2=A0test_begin_subtest "Save attachment from within emacs using not=\r
+much-show-save-part"\r
+> > > =C2=A0# save as archive to test that Emacs does not re-compress .gz\r
+> > > -echo ./attachment2.gz |\r
+> > > -test_emacs '(notmuch-show-save-part "id:cf0c4d610911171136h1713aa59w=\r
+9cf9aa31f052ad0a@mail.gmail.com" 5)' > /dev/null 2>&1\r
+> > > +test_emacs '(let ((standard-input "\"attachment2.gz\""))\r
+> > > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (notmuch-show-save-part "=\r
+id:cf0c4d610911171136h1713aa59w9cf9aa31f052ad0a@mail.gmail.com" 5))' > /dev=\r
+/null 2>&1\r
+> > > =C2=A0test_expect_equal_file "$EXPECTED/attachment" attachment2.gz\r
+> > >\r
+> > > =C2=A0test_begin_subtest "View raw message within emacs"\r
+> > > diff --git a/test/test-lib.el b/test/test-lib.el\r
+> > > index 4e7f5cf..a5a3125 100644\r
+> > > --- a/test/test-lib.el\r
+> > > +++ b/test/test-lib.el\r
+> > > @@ -23,6 +23,12 @@\r
+> > > =C2=A0;; avoid crazy 10-column default of --batch\r
+> > > =C2=A0(set-frame-width (window-frame (get-buffer-window)) 80)\r
+> > >\r
+> > > +;; `read-file-name' by default uses `completing-read' function to re=\r
+ad\r
+> > > +;; user input. =C2=A0It does not respect `standard-input' variable w=\r
+hich we\r
+> > > +;; use in tests to provide user input. =C2=A0So replace it with a pl=\r
+ain\r
+> > > +;; `read' call.\r
+> > > +(setq read-file-name-function (lambda (&rest _) (read)))\r
+> > > +\r
+> > > =C2=A0(defun notmuch-test-wait ()\r
+> > > =C2=A0 "Wait for process completion."\r
+> > > =C2=A0 (while (get-buffer-process (current-buffer))\r
+> > > diff --git a/test/test-lib.sh b/test/test-lib.sh\r
+> > > index ad1506c..1c1581b 100755\r
+> > > --- a/test/test-lib.sh\r
+> > > +++ b/test/test-lib.sh\r
+> > > @@ -57,6 +57,9 @@ unset CDPATH\r
+> > >\r
+> > > =C2=A0unset GREP_OPTIONS\r
+> > >\r
+> > > +# PID of running Emacs server\r
+> > > +emacs_server_pid=3D\r
+> > > +\r
+> > > =C2=A0# Convenience\r
+> > > =C2=A0#\r
+> > > =C2=A0# A regexp to match 5 and 40 hexdigits\r
+> > > @@ -174,6 +177,7 @@ test_success=3D0\r
+> > >\r
+> > > =C2=A0die () {\r
+> > > =C2=A0 =C2=A0 =C2=A0 =C2=A0code=3D$?\r
+> > > + =C2=A0 =C2=A0 =C2=A0 emacs_server_stop\r
+> > > =C2=A0 =C2=A0 =C2=A0 =C2=A0if test -n "$GIT_EXIT_OK"\r
+> > > =C2=A0 =C2=A0 =C2=A0 =C2=A0then\r
+> > > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0exit $code\r
+> > > @@ -394,19 +398,20 @@ emacs_deliver_message ()\r
+> > > =C2=A0 =C2=A0 mkdir -p "$MAIL_DIR"/sent/{cur,new,tmp}\r
+> > > =C2=A0 =C2=A0 ../smtp-dummy sent_message &\r
+> > > =C2=A0 =C2=A0 smtp_dummy_pid=3D$!\r
+> > > - =C2=A0 =C2=A0test_emacs "(setq message-send-mail-function 'message-=\r
+smtpmail-send-it)\r
+> > > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (setq smtpmail-smt=\r
+p-server \"localhost\")\r
+> > > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (setq smtpmail-smt=\r
+p-service \"25025\")\r
+> > > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (notmuch-hello)\r
+> > > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (notmuch-mua-mail)\r
+> > > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (message-goto-to)\r
+> > > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (insert \"test_sui=\r
+te@notmuchmail.org\nDate: 01 Jan 2000 12:00:00 -0000\")\r
+> > > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (message-goto-subj=\r
+ect)\r
+> > > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (insert \"${subjec=\r
+t}\")\r
+> > > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (message-goto-body)\r
+> > > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (insert \"${body}\=\r
+")\r
+> > > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 $@\r
+> > > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (message-send-and-=\r
+exit)" >/dev/null 2>&1\r
+> > > + =C2=A0 =C2=A0test_emacs \\r
+> > > + =C2=A0 =C2=A0 =C2=A0 "(let ((message-send-mail-function 'message-sm=\r
+tpmail-send-it)\r
+> > > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(smtpmail-smtp-serv=\r
+er \"localhost\")\r
+> > > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(smtpmail-smtp-serv=\r
+ice \"25025\"))\r
+> > > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(notmuch-hello)\r
+> > > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(notmuch-mua-mail)\r
+> > > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(message-goto-to)\r
+> > > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(insert \"test_suite@notmuchmail.=\r
+org\nDate: 01 Jan 2000 12:00:00 -0000\")\r
+> > > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(message-goto-subject)\r
+> > > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(insert \"${subject}\")\r
+> > > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(message-goto-body)\r
+> > > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(insert \"${body}\")\r
+> > > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0$@\r
+> > > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(message-send-and-exit))" >/dev/n=\r
+ull 2>&1\r
+> > > =C2=A0 =C2=A0 wait ${smtp_dummy_pid}\r
+> > > =C2=A0 =C2=A0 notmuch new >/dev/null\r
+> > > =C2=A0}\r
+> > > @@ -828,6 +833,8 @@ test_done () {\r
+> > >\r
+> > > =C2=A0 =C2=A0 =C2=A0 =C2=A0echo\r
+> > >\r
+> > > + =C2=A0 =C2=A0 =C2=A0 emacs_server_stop\r
+> > > +\r
+> > > =C2=A0 =C2=A0 =C2=A0 =C2=A0if [ "$test_failure" =3D "0" ]; then\r
+> > > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if [ "$test_broken" =3D "0" =\r
+]; then\r
+> > > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0rm -rf "$remov=\r
+e_tmp"\r
+> > > @@ -838,24 +845,26 @@ test_done () {\r
+> > > =C2=A0 =C2=A0 =C2=A0 =C2=A0fi\r
+> > > =C2=A0}\r
+> > >\r
+> > > -test_emacs () {\r
+> > > - =C2=A0 =C2=A0 =C2=A0 # Construct a little test script here for the =\r
+benefit of the user,\r
+> > > - =C2=A0 =C2=A0 =C2=A0 # (who can easily run "run_emacs" to get the s=\r
+ame emacs environment\r
+> > > - =C2=A0 =C2=A0 =C2=A0 # for investigating any failures).\r
+> > > - =C2=A0 =C2=A0 =C2=A0 cat <<EOF > run_emacs\r
+> > > +# Generate some scripts for running Emacs tests. =C2=A0These scripts=\r
+ are\r
+> > > +# used by Emacs tests and help investigating failures. =C2=A0The fol=\r
+lowing\r
+> > > +# scripts are generated:\r
+> > > +#\r
+> > > +# * emacs_server_start - start Emacs server\r
+> > > +# * emacs_server_stop =C2=A0- stop Emacs server\r
+> > > +# * emacs_start =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=\r
+=A0- start Emacs\r
+> > > +# * emacs_run =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0- execute ELisp expr=\r
+essions in running Emacs server\r
+> > > +emacs_generate_scripts ()\r
+> > > +{\r
+> > > + =C2=A0 =C2=A0 =C2=A0 server_name=3D"notmuch-test-suite-$$"\r
+> > > +\r
+> > > + =C2=A0 =C2=A0 =C2=A0 cat <<EOF > "$TMP_DIRECTORY/emacs_server_start"\r
+> > > =C2=A0#!/bin/sh\r
+> > > =C2=A0export PATH=3D$PATH\r
+> > > =C2=A0export NOTMUCH_CONFIG=3D$NOTMUCH_CONFIG\r
+> > >\r
+> > > -# We assume that the user will give a command-line argument only if\r
+> > > -# wanting to run in batch mode.\r
+> > > -if [ \$# -gt 0 ]; then\r
+> > > - =C2=A0 =C2=A0 =C2=A0 BATCH=3D--batch\r
+> > > -fi\r
+> > > -\r
+> > > =C2=A0# Here's what we are using here:\r
+> > > =C2=A0#\r
+> > > -# --batch: =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 Quit after give=\r
+n commands and print all (messages)\r
+> > > +# --daemon =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 Start Emacs as =\r
+a daemon\r
+> > > =C2=A0#\r
+> > > =C2=A0# --no-init-file =C2=A0 =C2=A0 =C2=A0 Don't load users ~/.emacs\r
+> > > =C2=A0#\r
+> > > @@ -865,13 +874,90 @@ fi\r
+> > > =C2=A0#\r
+> > > =C2=A0# --load =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 Force=\r
+ loading of notmuch.el and test-lib.el\r
+> > >\r
+> > > -emacs \$BATCH --no-init-file --no-site-file \\r
+> > > - =C2=A0 =C2=A0 =C2=A0 --directory ../../emacs --load notmuch.el \\r
+> > > - =C2=A0 =C2=A0 =C2=A0 --directory .. --load test-lib.el \\r
+> > > - =C2=A0 =C2=A0 =C2=A0 --eval "(progn \$@)"\r
+> > > +emacs --daemon --no-init-file --no-site-file \\r
+> > > + =C2=A0 =C2=A0 =C2=A0 --directory "$TEST_DIRECTORY/../emacs" --load =\r
+notmuch.el \\r
+> > > + =C2=A0 =C2=A0 =C2=A0 --directory "$TEST_DIRECTORY" --load test-lib.=\r
+el \\r
+> > > + =C2=A0 =C2=A0 =C2=A0 --eval '(setq server-name "$server_name")'\r
+> > > +EOF\r
+> > > + =C2=A0 =C2=A0 =C2=A0 chmod a+x "$TMP_DIRECTORY/emacs_server_start"\r
+> > > +\r
+> > > + =C2=A0 =C2=A0 =C2=A0 cat <<EOF > "$TMP_DIRECTORY/emacs_server_stop"\r
+> > > +#!/bin/sh\r
+> > > +\r
+> > > +dir=3D\$(dirname "\$0")\r
+> > > +"\$dir"/emacs_run '(kill-emacs)'\r
+> > > =C2=A0EOF\r
+> > > - =C2=A0 =C2=A0 =C2=A0 chmod a+x ./run_emacs\r
+> > > - =C2=A0 =C2=A0 =C2=A0 ./run_emacs "$@"\r
+> > > + =C2=A0 =C2=A0 =C2=A0 chmod a+x "$TMP_DIRECTORY/emacs_server_stop"\r
+> > > +\r
+> > > + =C2=A0 =C2=A0 =C2=A0 cat <<EOF > "$TMP_DIRECTORY/emacs_start"\r
+> > > +#!/bin/sh\r
+> > > +export PATH=3D$PATH\r
+> > > +export NOTMUCH_CONFIG=3D$NOTMUCH_CONFIG\r
+> > > +\r
+> > > +# Here's what we are using here:\r
+> > > +#\r
+> > > +# --no-init-file =C2=A0 =C2=A0 =C2=A0 Don't load users ~/.emacs\r
+> > > +#\r
+> > > +# --no-site-file =C2=A0 =C2=A0 =C2=A0 Don't load the site-wide start=\r
+up stuff\r
+> > > +#\r
+> > > +# --directory =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0Ensure that the loca=\r
+l elisp sources are found\r
+> > > +#\r
+> > > +# --load =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 Force load=\r
+ing of notmuch.el and test-lib.el\r
+> > > +\r
+> > > +emacs --no-init-file --no-site-file \\r
+> > > + =C2=A0 =C2=A0 =C2=A0 --directory "$TEST_DIRECTORY/../emacs" --load =\r
+notmuch.el \\r
+> > > + =C2=A0 =C2=A0 =C2=A0 --directory "$TEST_DIRECTORY" --load test-lib.=\r
+el\r
+> > > +EOF\r
+> > > + =C2=A0 =C2=A0 =C2=A0 chmod a+x "$TMP_DIRECTORY/emacs_start"\r
+> > > +\r
+> > > + =C2=A0 =C2=A0 =C2=A0 cat <<EOF > "$TMP_DIRECTORY/emacs_run"\r
+> > > +#!/bin/sh\r
+> > > +\r
+> > > +# Here's what we are using here:\r
+> > > +#\r
+> > > +# --socket-name =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=\r
+=A0Emacs server name\r
+> > > +#\r
+> > > +# --eval =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 Evaluate E=\r
+Lisp expressions\r
+> > > +\r
+> > > +emacsclient --socket-name "$server_name" --eval "(progn \$@)"\r
+> > > +EOF\r
+> > > + =C2=A0 =C2=A0 =C2=A0 chmod a+x "$TMP_DIRECTORY/emacs_run"\r
+> > > +}\r
+> > > +\r
+> > > +# Start Emacs server if it is not running.\r
+> > > +emacs_server_start ()\r
+> > > +{\r
+> > > + =C2=A0 =C2=A0 =C2=A0 [ -n "$emacs_server_pid" ] && return\r
+> > > +\r
+> > > + =C2=A0 =C2=A0 =C2=A0 output=3D$("$TMP_DIRECTORY/emacs_server_start"=\r
+ 2>&1)\r
+> > > + =C2=A0 =C2=A0 =C2=A0 if [ "$?" -ne 0 ]; then\r
+> > > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 echo "$output"\r
+> > > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return 1\r
+> > > + =C2=A0 =C2=A0 =C2=A0 fi\r
+> > > +\r
+> > > + =C2=A0 =C2=A0 =C2=A0 emacs_server_pid=3D$("$TMP_DIRECTORY/emacs_run=\r
+" '(emacs-pid)')\r
+> > > + =C2=A0 =C2=A0 =C2=A0 [ "$?" -eq 0 -a -n "$emacs_server_pid" ]\r
+> > > +}\r
+> > > +\r
+> > > +# Stop Emacs server if it is running.\r
+> > > +emacs_server_stop ()\r
+> > > +{\r
+> > > + =C2=A0 =C2=A0 =C2=A0 [ -z "$emacs_server_pid" ] && return\r
+> > > +\r
+> > > + =C2=A0 =C2=A0 =C2=A0 emacs_server_pid=3D\r
+> > > + =C2=A0 =C2=A0 =C2=A0 output=3D$("$TMP_DIRECTORY/emacs_server_stop" =\r
+2>&1)\r
+> > > + =C2=A0 =C2=A0 =C2=A0 if [ "$?" -ne 0 ]; then\r
+> > > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 echo "$output"\r
+> > > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return 1\r
+> > > + =C2=A0 =C2=A0 =C2=A0 fi\r
+> > > +}\r
+> > > +\r
+> > > +# Evaluate ELisp expressions in Emacs server. =C2=A0Server is starte=\r
+d if it\r
+> > > +# is not running.\r
+> > > +test_emacs () {\r
+> > > + =C2=A0 =C2=A0 =C2=A0 emacs_server_start || return\r
+> > > +\r
+> > > + =C2=A0 =C2=A0 =C2=A0 "$TMP_DIRECTORY/emacs_run" "$@"\r
+> > > =C2=A0}\r
+> > >\r
+> > >\r
+> > > @@ -999,6 +1085,7 @@ primary_email=3Dtest_suite@notmuchmail.org\r
+> > > =C2=A0other_email=3Dtest_suite_other@notmuchmail.org;test_suite@other=\r
+domain.org\r
+> > > =C2=A0EOF\r
+> > >\r
+> > > +emacs_generate_scripts\r
+> > >\r
+> > > =C2=A0# Use -P to resolve symlinks in our working directory so that t=\r
+he cwd\r
+> > > =C2=A0# in subprocesses like git equals our $PWD (for pathname compar=\r
+isons).\r
+> > > --\r
+> > > 1.7.5.4\r
+> > >\r
+> > > _______________________________________________\r
+> > > notmuch mailing list\r
+> > > notmuch@notmuchmail.org\r
+> > > http://notmuchmail.org/mailman/listinfo/notmuch\r
+> > >\r