1 Return-Path: <amdragon@mit.edu>
\r
2 X-Original-To: notmuch@notmuchmail.org
\r
3 Delivered-To: notmuch@notmuchmail.org
\r
4 Received: from localhost (localhost [127.0.0.1])
\r
5 by olra.theworths.org (Postfix) with ESMTP id 9D7D8431FB6
\r
6 for <notmuch@notmuchmail.org>; Fri, 13 Jul 2012 19:09:59 -0700 (PDT)
\r
7 X-Virus-Scanned: Debian amavisd-new at olra.theworths.org
\r
11 X-Spam-Status: No, score=-0.7 tagged_above=-999 required=5
\r
12 tests=[RCVD_IN_DNSWL_LOW=-0.7] autolearn=disabled
\r
13 Received: from olra.theworths.org ([127.0.0.1])
\r
14 by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024)
\r
15 with ESMTP id uXg3NFNtSJQX for <notmuch@notmuchmail.org>;
\r
16 Fri, 13 Jul 2012 19:09:57 -0700 (PDT)
\r
17 Received: from dmz-mailsec-scanner-7.mit.edu (DMZ-MAILSEC-SCANNER-7.MIT.EDU
\r
19 by olra.theworths.org (Postfix) with ESMTP id A22E8431FAE
\r
20 for <notmuch@notmuchmail.org>; Fri, 13 Jul 2012 19:09:57 -0700 (PDT)
\r
21 X-AuditID: 12074424-b7f2a6d0000008bf-16-5000d4f548e4
\r
22 Received: from mailhub-auth-1.mit.edu ( [18.9.21.35])
\r
23 by dmz-mailsec-scanner-7.mit.edu (Symantec Messaging Gateway) with SMTP
\r
24 id D6.1C.02239.5F4D0005; Fri, 13 Jul 2012 22:09:57 -0400 (EDT)
\r
25 Received: from outgoing.mit.edu (OUTGOING-AUTH.MIT.EDU [18.7.22.103])
\r
26 by mailhub-auth-1.mit.edu (8.13.8/8.9.2) with ESMTP id q6E29ukA022868;
\r
27 Fri, 13 Jul 2012 22:09:56 -0400
\r
28 Received: from awakening.csail.mit.edu (awakening.csail.mit.edu [18.26.4.91])
\r
29 (authenticated bits=0)
\r
30 (User authenticated as amdragon@ATHENA.MIT.EDU)
\r
31 by outgoing.mit.edu (8.13.6/8.12.4) with ESMTP id q6E29tcc009849
\r
32 (version=TLSv1/SSLv3 cipher=AES256-SHA bits=256 verify=NOT);
\r
33 Fri, 13 Jul 2012 22:09:55 -0400 (EDT)
\r
34 Received: from amthrax by awakening.csail.mit.edu with local (Exim 4.77)
\r
35 (envelope-from <amdragon@mit.edu>)
\r
36 id 1Sprnu-0000f4-Sr; Fri, 13 Jul 2012 22:09:54 -0400
\r
37 Date: Fri, 13 Jul 2012 22:09:54 -0400
\r
38 From: Austin Clements <amdragon@MIT.EDU>
\r
39 To: Peter Feigl <craven@gmx.net>
\r
40 Subject: Re: [PATCH v5 3/3] Use the structured formatters in notmuch-search.c.
\r
41 Message-ID: <20120714020954.GD31670@mit.edu>
\r
42 References: <20120710191331.GE7332@mit.edu>
\r
43 <1342167097-25012-1-git-send-email-craven@gmx.net>
\r
44 <1342167097-25012-4-git-send-email-craven@gmx.net>
\r
46 Content-Type: text/plain; charset=iso-8859-1
\r
47 Content-Disposition: inline
\r
48 Content-Transfer-Encoding: 8bit
\r
49 In-Reply-To: <1342167097-25012-4-git-send-email-craven@gmx.net>
\r
50 User-Agent: Mutt/1.5.21 (2010-09-15)
\r
51 X-Brightmail-Tracker:
\r
52 H4sIAAAAAAAAA+NgFprDKsWRmVeSWpSXmKPExsUixCmqrPv1CkOAwcqtHBZ7G9oZLa7fnMns
\r
53 wOSxeNN+No9nq24xBzBFcdmkpOZklqUW6dslcGX8vXiSuWBKXcXnm2tZGxjnxXcxcnBICJhI
\r
54 rP4j2MXICWSKSVy4t56ti5GLQ0hgH6PEp9bPUM4GRomVDyayQjgnmSRmbbgK5SxhlPjx/Asz
\r
55 SD+LgKrEmpmbWUBsNgENiW37lzOC2CICChLP1jWB2cwC0hLffjczgdjCAn4SFxb1soHYvAI6
\r
56 Ept372GEGDqVUWLeit+MEAlBiZMzn7BANOtI7Nx6hw3kbpBBy/9xQITlJZq3zga7gVPAXuLq
\r
57 6s3sILaogIrElJPb2CYwCs9CMmkWkkmzECbNQjJpASPLKkbZlNwq3dzEzJzi1GTd4uTEvLzU
\r
58 Il1zvdzMEr3UlNJNjKBIYHdR2cHYfEjpEKMAB6MSD2+SP0OAEGtiWXFl7iFGSQ4mJVHeWReB
\r
59 QnxJ+SmVGYnFGfFFpTmpxYcYJTiYlUR4zduAcrwpiZVVqUX5MClpDhYlcd7rKTf9hQTSE0tS
\r
60 s1NTC1KLYLIyHBxKEryFwIgXEixKTU+tSMvMKUFIM3FwggznARreAlLDW1yQmFucmQ6RP8Wo
\r
61 KCXOGwKSEABJZJTmwfXCEtUrRnGgV4R540GqeIBJDq77FdBgJqDBs37+8wcaXJKIkJJqYDT5
\r
62 zDhXLax3wr8rR6Mn7fv3RcXMPXfe9DunHMucw3dNL3T7tKZ9W+LNpfHNp80t98+awbA77zO/
\r
63 v5IOf0BGftLFKx1zF0xe8KfqSK3bH3/vGfy/vJvub5i5ZottlV7GDE3pPmPJG86LlPa4PE2y
\r
64 l5P+dSZa/rZ28PulWf9X7GFqfvS+pzRrSq0SS3FGoqEWc1FxIgDICgKQLwMAAA==
\r
65 Cc: notmuch@notmuchmail.org
\r
66 X-BeenThere: notmuch@notmuchmail.org
\r
67 X-Mailman-Version: 2.1.13
\r
69 List-Id: "Use and development of the notmuch mail system."
\r
70 <notmuch.notmuchmail.org>
\r
71 List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,
\r
72 <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>
\r
73 List-Archive: <http://notmuchmail.org/pipermail/notmuch>
\r
74 List-Post: <mailto:notmuch@notmuchmail.org>
\r
75 List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>
\r
76 List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,
\r
77 <mailto:notmuch-request@notmuchmail.org?subject=subscribe>
\r
78 X-List-Received-Date: Sat, 14 Jul 2012 02:09:59 -0000
\r
80 Just one comment below. Otherwise this patch LGTM (though some of my
\r
81 comments on the previous patch will affect this one). It's nice to
\r
82 see all of that old newline logic disappear.
\r
84 Quoth Peter Feigl on Jul 13 at 10:11 am:
\r
85 > From: <craven@gmx.net>
\r
87 > This patch switches from the current ad-hoc printer to the structured
\r
88 > output formatter in sprinter.h, sprinter-text-search.c and
\r
91 > The JSON tests are changed slightly in order to make them PASS for the
\r
92 > new structured output formatter.
\r
94 > The Text tests pass without adaptation.
\r
96 > notmuch-search.c | 292 +++++++++++--------------------------------------------
\r
97 > test/json | 18 +---
\r
98 > 2 files changed, 58 insertions(+), 252 deletions(-)
\r
100 > diff --git a/notmuch-search.c b/notmuch-search.c
\r
101 > index 3be296d..99fddac 100644
\r
102 > --- a/notmuch-search.c
\r
103 > +++ b/notmuch-search.c
\r
104 > @@ -19,6 +19,7 @@
\r
107 > #include "notmuch-client.h"
\r
108 > +#include "sprinter.h"
\r
112 > @@ -28,175 +29,8 @@ typedef enum {
\r
116 > -typedef struct search_format {
\r
117 > - const char *results_start;
\r
118 > - const char *item_start;
\r
119 > - void (*item_id) (const void *ctx,
\r
120 > - const char *item_type,
\r
121 > - const char *item_id);
\r
122 > - void (*thread_summary) (const void *ctx,
\r
123 > - const char *thread_id,
\r
124 > - const time_t date,
\r
125 > - const int matched,
\r
126 > - const int total,
\r
127 > - const char *authors,
\r
128 > - const char *subject);
\r
129 > - const char *tag_start;
\r
130 > - const char *tag;
\r
131 > - const char *tag_sep;
\r
132 > - const char *tag_end;
\r
133 > - const char *item_sep;
\r
134 > - const char *item_end;
\r
135 > - const char *results_end;
\r
136 > - const char *results_null;
\r
137 > -} search_format_t;
\r
140 > -format_item_id_text (const void *ctx,
\r
141 > - const char *item_type,
\r
142 > - const char *item_id);
\r
145 > -format_thread_text (const void *ctx,
\r
146 > - const char *thread_id,
\r
147 > - const time_t date,
\r
148 > - const int matched,
\r
149 > - const int total,
\r
150 > - const char *authors,
\r
151 > - const char *subject);
\r
152 > -static const search_format_t format_text = {
\r
155 > - format_item_id_text,
\r
156 > - format_thread_text,
\r
166 > -format_item_id_json (const void *ctx,
\r
167 > - const char *item_type,
\r
168 > - const char *item_id);
\r
171 > -format_thread_json (const void *ctx,
\r
172 > - const char *thread_id,
\r
173 > - const time_t date,
\r
174 > - const int matched,
\r
175 > - const int total,
\r
176 > - const char *authors,
\r
177 > - const char *subject);
\r
179 > -/* Any changes to the JSON format should be reflected in the file
\r
180 > - * devel/schemata. */
\r
181 > -static const search_format_t format_json = {
\r
184 > - format_item_id_json,
\r
185 > - format_thread_json,
\r
187 > - "\"%s\"", ", ",
\r
195 > -format_item_id_text (unused (const void *ctx),
\r
196 > - const char *item_type,
\r
197 > - const char *item_id)
\r
199 > - printf ("%s%s", item_type, item_id);
\r
203 > -sanitize_string (const void *ctx, const char *str)
\r
205 > - char *out, *loop;
\r
207 > - if (NULL == str)
\r
210 > - loop = out = talloc_strdup (ctx, str);
\r
212 > - for (; *loop; loop++) {
\r
213 > - if ((unsigned char)(*loop) < 32)
\r
220 > -format_thread_text (const void *ctx,
\r
221 > - const char *thread_id,
\r
222 > - const time_t date,
\r
223 > - const int matched,
\r
224 > - const int total,
\r
225 > - const char *authors,
\r
226 > - const char *subject)
\r
228 > - void *ctx_quote = talloc_new (ctx);
\r
230 > - printf ("thread:%s %12s [%d/%d] %s; %s",
\r
232 > - notmuch_time_relative_date (ctx, date),
\r
235 > - sanitize_string (ctx_quote, authors),
\r
236 > - sanitize_string (ctx_quote, subject));
\r
238 > - talloc_free (ctx_quote);
\r
242 > -format_item_id_json (const void *ctx,
\r
243 > - unused (const char *item_type),
\r
244 > - const char *item_id)
\r
246 > - void *ctx_quote = talloc_new (ctx);
\r
248 > - printf ("%s", json_quote_str (ctx_quote, item_id));
\r
250 > - talloc_free (ctx_quote);
\r
255 > -format_thread_json (const void *ctx,
\r
256 > - const char *thread_id,
\r
257 > - const time_t date,
\r
258 > - const int matched,
\r
259 > - const int total,
\r
260 > - const char *authors,
\r
261 > - const char *subject)
\r
263 > - void *ctx_quote = talloc_new (ctx);
\r
265 > - printf ("\"thread\": %s,\n"
\r
266 > - "\"timestamp\": %ld,\n"
\r
267 > - "\"date_relative\": \"%s\",\n"
\r
268 > - "\"matched\": %d,\n"
\r
269 > - "\"total\": %d,\n"
\r
270 > - "\"authors\": %s,\n"
\r
271 > - "\"subject\": %s,\n",
\r
272 > - json_quote_str (ctx_quote, thread_id),
\r
274 > - notmuch_time_relative_date (ctx, date),
\r
277 > - json_quote_str (ctx_quote, authors),
\r
278 > - json_quote_str (ctx_quote, subject));
\r
280 > - talloc_free (ctx_quote);
\r
284 > -do_search_threads (const search_format_t *format,
\r
285 > +do_search_threads (sprinter_t *format,
\r
286 > notmuch_query_t *query,
\r
287 > notmuch_sort_t sort,
\r
289 > @@ -207,7 +41,6 @@ do_search_threads (const search_format_t *format,
\r
290 > notmuch_threads_t *threads;
\r
291 > notmuch_tags_t *tags;
\r
293 > - int first_thread = 1;
\r
296 > if (offset < 0) {
\r
297 > @@ -220,14 +53,12 @@ do_search_threads (const search_format_t *format,
\r
298 > if (threads == NULL)
\r
301 > - fputs (format->results_start, stdout);
\r
302 > + format->begin_list (format);
\r
305 > notmuch_threads_valid (threads) && (limit < 0 || i < offset + limit);
\r
306 > notmuch_threads_move_to_next (threads), i++)
\r
308 > - int first_tag = 1;
\r
310 > thread = notmuch_threads_get (threads);
\r
312 > if (i < offset) {
\r
313 > @@ -235,60 +66,65 @@ do_search_threads (const search_format_t *format,
\r
317 > - if (! first_thread)
\r
318 > - fputs (format->item_sep, stdout);
\r
320 > if (output == OUTPUT_THREADS) {
\r
321 > - format->item_id (thread, "thread:",
\r
322 > - notmuch_thread_get_thread_id (thread));
\r
323 > + format->set_prefix (format, "thread");
\r
324 > + format->string (format,
\r
325 > + notmuch_thread_get_thread_id (thread));
\r
326 > + format->separator (format);
\r
327 > } else { /* output == OUTPUT_SUMMARY */
\r
328 > - fputs (format->item_start, stdout);
\r
329 > + void *ctx_quote = talloc_new (thread);
\r
331 > + format->begin_map (format);
\r
333 > if (sort == NOTMUCH_SORT_OLDEST_FIRST)
\r
334 > date = notmuch_thread_get_oldest_date (thread);
\r
336 > date = notmuch_thread_get_newest_date (thread);
\r
338 > - format->thread_summary (thread,
\r
339 > - notmuch_thread_get_thread_id (thread),
\r
341 > - notmuch_thread_get_matched_messages (thread),
\r
342 > - notmuch_thread_get_total_messages (thread),
\r
343 > - notmuch_thread_get_authors (thread),
\r
344 > - notmuch_thread_get_subject (thread));
\r
346 > - fputs (format->tag_start, stdout);
\r
347 > + format->map_key (format, "thread");
\r
348 > + format->string (format, notmuch_thread_get_thread_id (thread));
\r
349 > + format->map_key (format, "timestamp");
\r
350 > + format->integer (format, date);
\r
351 > + format->map_key (format, "date_relative");
\r
352 > + format->string (format, notmuch_time_relative_date (ctx_quote, date));
\r
353 > + format->map_key (format, "matched");
\r
354 > + format->integer (format, notmuch_thread_get_matched_messages (thread));
\r
355 > + format->map_key (format, "total");
\r
356 > + format->integer (format, notmuch_thread_get_total_messages (thread));
\r
357 > + format->map_key (format, "authors");
\r
358 > + format->string (format, notmuch_thread_get_authors (thread));
\r
359 > + format->map_key (format, "subject");
\r
360 > + format->string (format, notmuch_thread_get_subject (thread));
\r
362 > + talloc_free (ctx_quote);
\r
364 > + format->map_key (format, "tags");
\r
365 > + format->begin_list (format);
\r
367 > for (tags = notmuch_thread_get_tags (thread);
\r
368 > notmuch_tags_valid (tags);
\r
369 > notmuch_tags_move_to_next (tags))
\r
371 > - if (! first_tag)
\r
372 > - fputs (format->tag_sep, stdout);
\r
373 > - printf (format->tag, notmuch_tags_get (tags));
\r
376 > + const char *tag = notmuch_tags_get (tags);
\r
378 > - fputs (format->tag_end, stdout);
\r
379 > + format->string (format, tag);
\r
382 > - fputs (format->item_end, stdout);
\r
383 > + format->end (format);
\r
384 > + format->end (format);
\r
385 > + format->separator (format);
\r
388 > - first_thread = 0;
\r
390 > notmuch_thread_destroy (thread);
\r
393 > - if (first_thread)
\r
394 > - fputs (format->results_null, stdout);
\r
396 > - fputs (format->results_end, stdout);
\r
397 > + format->end (format);
\r
403 > -do_search_messages (const search_format_t *format,
\r
404 > +do_search_messages (sprinter_t *format,
\r
405 > notmuch_query_t *query,
\r
408 > @@ -297,7 +133,6 @@ do_search_messages (const search_format_t *format,
\r
409 > notmuch_message_t *message;
\r
410 > notmuch_messages_t *messages;
\r
411 > notmuch_filenames_t *filenames;
\r
412 > - int first_message = 1;
\r
415 > if (offset < 0) {
\r
416 > @@ -310,7 +145,7 @@ do_search_messages (const search_format_t *format,
\r
417 > if (messages == NULL)
\r
420 > - fputs (format->results_start, stdout);
\r
421 > + format->begin_list (format);
\r
424 > notmuch_messages_valid (messages) && (limit < 0 || i < offset + limit);
\r
425 > @@ -328,24 +163,17 @@ do_search_messages (const search_format_t *format,
\r
426 > notmuch_filenames_valid (filenames);
\r
427 > notmuch_filenames_move_to_next (filenames))
\r
429 > - if (! first_message)
\r
430 > - fputs (format->item_sep, stdout);
\r
432 > - format->item_id (message, "",
\r
433 > - notmuch_filenames_get (filenames));
\r
435 > - first_message = 0;
\r
436 > + format->string (format, notmuch_filenames_get (filenames));
\r
437 > + format->separator (format);
\r
441 > notmuch_filenames_destroy( filenames );
\r
443 > } else { /* output == OUTPUT_MESSAGES */
\r
444 > - if (! first_message)
\r
445 > - fputs (format->item_sep, stdout);
\r
447 > - format->item_id (message, "id:",
\r
448 > - notmuch_message_get_message_id (message));
\r
449 > - first_message = 0;
\r
450 > + format->set_prefix (format, "id");
\r
451 > + format->string (format,
\r
452 > + notmuch_message_get_message_id (message));
\r
453 > + format->separator (format);
\r
456 > notmuch_message_destroy (message);
\r
457 > @@ -353,23 +181,19 @@ do_search_messages (const search_format_t *format,
\r
459 > notmuch_messages_destroy (messages);
\r
461 > - if (first_message)
\r
462 > - fputs (format->results_null, stdout);
\r
464 > - fputs (format->results_end, stdout);
\r
465 > + format->end (format);
\r
471 > do_search_tags (notmuch_database_t *notmuch,
\r
472 > - const search_format_t *format,
\r
473 > + sprinter_t *format,
\r
474 > notmuch_query_t *query)
\r
476 > notmuch_messages_t *messages = NULL;
\r
477 > notmuch_tags_t *tags;
\r
479 > - int first_tag = 1;
\r
481 > /* should the following only special case if no excluded terms
\r
483 > @@ -387,7 +211,7 @@ do_search_tags (notmuch_database_t *notmuch,
\r
484 > if (tags == NULL)
\r
487 > - fputs (format->results_start, stdout);
\r
488 > + format->begin_list (format);
\r
491 > notmuch_tags_valid (tags);
\r
492 > @@ -395,12 +219,9 @@ do_search_tags (notmuch_database_t *notmuch,
\r
494 > tag = notmuch_tags_get (tags);
\r
496 > - if (! first_tag)
\r
497 > - fputs (format->item_sep, stdout);
\r
498 > + format->string (format, tag);
\r
499 > + format->separator (format);
\r
501 > - format->item_id (tags, "", tag);
\r
506 > notmuch_tags_destroy (tags);
\r
507 > @@ -408,10 +229,7 @@ do_search_tags (notmuch_database_t *notmuch,
\r
509 > notmuch_messages_destroy (messages);
\r
512 > - fputs (format->results_null, stdout);
\r
514 > - fputs (format->results_end, stdout);
\r
515 > + format->end (format);
\r
519 > @@ -430,7 +248,7 @@ notmuch_search_command (void *ctx, int argc, char *argv[])
\r
520 > notmuch_query_t *query;
\r
522 > notmuch_sort_t sort = NOTMUCH_SORT_NEWEST_FIRST;
\r
523 > - const search_format_t *format = &format_text;
\r
524 > + sprinter_t *format = NULL;
\r
525 > int opt_index, ret;
\r
526 > output_t output = OUTPUT_SUMMARY;
\r
528 > @@ -475,10 +293,10 @@ notmuch_search_command (void *ctx, int argc, char *argv[])
\r
530 > switch (format_sel) {
\r
531 > case NOTMUCH_FORMAT_TEXT:
\r
532 > - format = &format_text;
\r
533 > + format = sprinter_text_search_create (ctx, stdout);
\r
535 > case NOTMUCH_FORMAT_JSON:
\r
536 > - format = &format_json;
\r
537 > + format = sprinter_json_create (ctx, stdout);
\r
541 > @@ -546,5 +364,7 @@ notmuch_search_command (void *ctx, int argc, char *argv[])
\r
542 > notmuch_query_destroy (query);
\r
543 > notmuch_database_destroy (notmuch);
\r
545 > + talloc_free (format);
\r
549 > diff --git a/test/json b/test/json
\r
550 > index 6439788..f0ebf08 100755
\r
553 > @@ -10,14 +10,7 @@ test_expect_equal "$output" "[[[{\"id\": \"${gen_msg_id}\", \"match\": true, \"e
\r
554 > test_begin_subtest "Search message: json"
\r
555 > add_message "[subject]=\"json-search-subject\"" "[date]=\"Sat, 01 Jan 2000 12:00:00 -0000\"" "[body]=\"json-search-message\""
\r
556 > output=$(notmuch search --format=json "json-search-message" | notmuch_search_sanitize)
\r
558 If you pipe this through notmuch_json_show_sanitize, it'll make the
\r
559 test output much cleaner and closer to the original output (probably
\r
560 not exactly the same, unfortunately).
\r
562 > -test_expect_equal "$output" "[{\"thread\": \"XXX\",
\r
563 > -\"timestamp\": 946728000,
\r
564 > -\"date_relative\": \"2000-01-01\",
\r
567 > -\"authors\": \"Notmuch Test Suite\",
\r
568 > -\"subject\": \"json-search-subject\",
\r
569 > -\"tags\": [\"inbox\", \"unread\"]}]"
\r
570 > +test_expect_equal "$output" "[{\"thread\": \"XXX\", \"timestamp\": 946728000, \"date_relative\": \"2000-01-01\", \"matched\": 1, \"total\": 1, \"authors\": \"Notmuch Test Suite\", \"subject\": \"json-search-subject\", \"tags\": [\"inbox\", \"unread\"]}]"
\r
572 > test_begin_subtest "Show message: json, utf-8"
\r
573 > add_message "[subject]=\"json-show-utf8-body-sübjéct\"" "[date]=\"Sat, 01 Jan 2000 12:00:00 -0000\"" "[body]=\"jsön-show-méssage\""
\r
574 > @@ -40,13 +33,6 @@ test_expect_equal "$output" "[[[{\"id\": \"$id\", \"match\": true, \"excluded\":
\r
575 > test_begin_subtest "Search message: json, utf-8"
\r
576 > add_message "[subject]=\"json-search-utf8-body-sübjéct\"" "[date]=\"Sat, 01 Jan 2000 12:00:00 -0000\"" "[body]=\"jsön-search-méssage\""
\r
577 > output=$(notmuch search --format=json "jsön-search-méssage" | notmuch_search_sanitize)
\r
581 > -test_expect_equal "$output" "[{\"thread\": \"XXX\",
\r
582 > -\"timestamp\": 946728000,
\r
583 > -\"date_relative\": \"2000-01-01\",
\r
586 > -\"authors\": \"Notmuch Test Suite\",
\r
587 > -\"subject\": \"json-search-utf8-body-sübjéct\",
\r
588 > -\"tags\": [\"inbox\", \"unread\"]}]"
\r
589 > +test_expect_equal "$output" "[{\"thread\": \"XXX\", \"timestamp\": 946728000, \"date_relative\": \"2000-01-01\", \"matched\": 1, \"total\": 1, \"authors\": \"Notmuch Test Suite\", \"subject\": \"json-search-utf8-body-sübjéct\", \"tags\": [\"inbox\", \"unread\"]}]"
\r