]> git.notmuchmail.org Git - notmuch/blob - test/T081-sexpr-search.sh
test/sexp: tests for path, folder, including trailing '/' (sexp)
[notmuch] / test / T081-sexpr-search.sh
1 #!/usr/bin/env bash
2 test_description='"notmuch search" in several variations'
3 . $(dirname "$0")/test-lib.sh || exit 1
4
5 if [ $NOTMUCH_HAVE_SFSEXP -ne 1 ]; then
6     printf "Skipping due to missing sfsexp library\n"
7     test_done
8 fi
9
10 add_email_corpus
11
12 for query in '()' '(not)' '(and)' '(or ())' '(or (not))' '(or (and))' \
13             '(or (and) (or) (not (and)))'; do
14     test_begin_subtest "all messages: $query"
15     notmuch search '*' > EXPECTED
16     notmuch search --query=sexp "$query" > OUTPUT
17     test_expect_equal_file EXPECTED OUTPUT
18 done
19
20 for query in '(or)' '(not ())' '(not (not))' '(not (and))' \
21                    '(not (or (and) (or) (not (and))))'; do
22     test_begin_subtest "no messages: $query"
23     notmuch search --query=sexp "$query" > OUTPUT
24     test_expect_equal_file /dev/null OUTPUT
25 done
26
27 test_begin_subtest "and of exact terms"
28 notmuch search --query=sexp '(and "wonderful" "wizard")' | notmuch_search_sanitize > OUTPUT
29 cat <<EOF > EXPECTED
30 thread:XXX   2009-11-18 [1/3] Carl Worth| Jan Janak; [notmuch] What a great idea! (inbox unread)
31 EOF
32 test_expect_equal_file EXPECTED OUTPUT
33
34 test_begin_subtest "or of exact terms"
35 notmuch search --query=sexp '(or "php" "wizard")' | notmuch_search_sanitize > OUTPUT
36 cat <<EOF > EXPECTED
37 thread:XXX   2010-12-29 [1/1] François Boulogne; [aur-general] Guidelines: cp, mkdir vs install (inbox unread)
38 thread:XXX   2009-11-18 [1/3] Carl Worth| Jan Janak; [notmuch] What a great idea! (inbox unread)
39 EOF
40 test_expect_equal_file EXPECTED OUTPUT
41
42 test_begin_subtest "single term in body"
43 notmuch search --query=sexp 'wizard' | notmuch_search_sanitize>OUTPUT
44 cat <<EOF > EXPECTED
45 thread:XXX   2009-11-18 [1/3] Carl Worth| Jan Janak; [notmuch] What a great idea! (inbox unread)
46 EOF
47 test_expect_equal_file EXPECTED OUTPUT
48
49 test_begin_subtest "single term in body (case insensitive)"
50 notmuch search --query=sexp 'Wizard' | notmuch_search_sanitize>OUTPUT
51 cat <<EOF > EXPECTED
52 thread:XXX   2009-11-18 [1/3] Carl Worth| Jan Janak; [notmuch] What a great idea! (inbox unread)
53 EOF
54 test_expect_equal_file EXPECTED OUTPUT
55
56 test_begin_subtest "single term in body, stemmed version"
57 notmuch search arriv > EXPECTED
58 notmuch search --query=sexp arriv > OUTPUT
59 test_expect_equal_file EXPECTED OUTPUT
60
61 test_begin_subtest "single term in body, unstemmed version"
62 notmuch search --query=sexp '"arriv"' > OUTPUT
63 test_expect_equal_file /dev/null OUTPUT
64
65 test_begin_subtest "Search by 'subject'"
66 add_message [subject]=subjectsearchtest '[date]="Sat, 01 Jan 2000 12:00:00 -0000"'
67 output=$(notmuch search --query=sexp '(subject subjectsearchtest)' | notmuch_search_sanitize)
68 test_expect_equal "$output" "thread:XXX   2000-01-01 [1/1] Notmuch Test Suite; subjectsearchtest (inbox unread)"
69
70 test_begin_subtest "Search by 'subject' (case insensitive)"
71 notmuch search tag:inbox and subject:maildir | notmuch_search_sanitize > EXPECTED
72 notmuch search --query=sexp '(subject "Maildir")' | notmuch_search_sanitize > OUTPUT
73 test_expect_equal_file EXPECTED OUTPUT
74
75 test_begin_subtest "Search by 'subject' (utf-8):"
76 add_message [subject]=utf8-sübjéct '[date]="Sat, 01 Jan 2000 12:00:00 -0000"'
77 output=$(notmuch search --query=sexp '(subject utf8 sübjéct)' | notmuch_search_sanitize)
78 test_expect_equal "$output" "thread:XXX   2000-01-01 [1/1] Notmuch Test Suite; utf8-sübjéct (inbox unread)"
79
80 test_begin_subtest "Search by 'subject' (utf-8, and):"
81 output=$(notmuch search --query=sexp '(subject (and utf8 sübjéct))' | notmuch_search_sanitize)
82 test_expect_equal "$output" "thread:XXX   2000-01-01 [1/1] Notmuch Test Suite; utf8-sübjéct (inbox unread)"
83
84 test_begin_subtest "Search by 'subject' (utf-8, and outside):"
85 output=$(notmuch search --query=sexp '(and (subject utf8) (subject sübjéct))' | notmuch_search_sanitize)
86 test_expect_equal "$output" "thread:XXX   2000-01-01 [1/1] Notmuch Test Suite; utf8-sübjéct (inbox unread)"
87
88 test_begin_subtest "Search by 'subject' (utf-8, or):"
89 notmuch search --query=sexp '(subject (or utf8 subjectsearchtest))' | notmuch_search_sanitize > OUTPUT
90 cat <<EOF > EXPECTED
91 thread:XXX   2000-01-01 [1/1] Notmuch Test Suite; subjectsearchtest (inbox unread)
92 thread:XXX   2000-01-01 [1/1] Notmuch Test Suite; utf8-sübjéct (inbox unread)
93 EOF
94 test_expect_equal_file EXPECTED OUTPUT
95
96 test_begin_subtest "Search by 'subject' (utf-8, or outside):"
97 notmuch search --query=sexp '(or (subject utf8) (subject subjectsearchtest))' | notmuch_search_sanitize > OUTPUT
98 cat <<EOF > EXPECTED
99 thread:XXX   2000-01-01 [1/1] Notmuch Test Suite; subjectsearchtest (inbox unread)
100 thread:XXX   2000-01-01 [1/1] Notmuch Test Suite; utf8-sübjéct (inbox unread)
101 EOF
102 test_expect_equal_file EXPECTED OUTPUT
103
104 test_begin_subtest "Search by 'attachment'"
105 notmuch search attachment:notmuch-help.patch > EXPECTED
106 notmuch search --query=sexp '(attachment notmuch-help.patch)' > OUTPUT
107 test_expect_equal_file EXPECTED OUTPUT
108
109 test_begin_subtest "Search by 'body'"
110 add_message '[subject]="body search"' '[date]="Sat, 01 Jan 2000 12:00:00 -0000"' [body]=bodysearchtest
111 output=$(notmuch search --query=sexp '(body bodysearchtest)' | notmuch_search_sanitize)
112 test_expect_equal "$output" "thread:XXX   2000-01-01 [1/1] Notmuch Test Suite; body search (inbox unread)"
113
114 test_begin_subtest "Search by 'body' (phrase)"
115 add_message '[subject]="body search (phrase)"' '[date]="Sat, 01 Jan 2000 12:00:00 -0000"' '[body]="body search (phrase)"'
116 add_message '[subject]="negative result"' '[date]="Sat, 01 Jan 2000 12:00:00 -0000"' '[body]="This phrase should not match the body search"'
117 output=$(notmuch search --query=sexp '(body "body search phrase")' | notmuch_search_sanitize)
118 test_expect_equal "$output" "thread:XXX   2000-01-01 [1/1] Notmuch Test Suite; body search (phrase) (inbox unread)"
119
120 test_begin_subtest "Search by 'body' (utf-8):"
121 add_message '[subject]="utf8-message-body-subject"' '[date]="Sat, 01 Jan 2000 12:00:00 -0000"' '[body]="message body utf8: bödý"'
122 output=$(notmuch search --query=sexp '(body bödý)' | notmuch_search_sanitize)
123 test_expect_equal "$output" "thread:XXX   2000-01-01 [1/1] Notmuch Test Suite; utf8-message-body-subject (inbox unread)"
124
125 add_message "[body]=thebody-1" "[subject]=kryptonite-1"
126 add_message "[body]=nothing-to-see-here-1" "[subject]=thebody-1"
127
128 test_begin_subtest 'search without body: prefix'
129 notmuch search thebody > EXPECTED
130 notmuch search --query=sexp '(and thebody)' > OUTPUT
131 test_expect_equal_file EXPECTED OUTPUT
132
133 test_begin_subtest 'negated body: prefix'
134 notmuch search thebody and not body:thebody > EXPECTED
135 notmuch search --query=sexp '(and (not (body thebody)) thebody)' > OUTPUT
136 test_expect_equal_file EXPECTED OUTPUT
137
138 test_begin_subtest 'search unprefixed for prefixed term'
139 notmuch search kryptonite > EXPECTED
140 notmuch search --query=sexp '(and kryptonite)' > OUTPUT
141 test_expect_equal_file EXPECTED OUTPUT
142
143 test_begin_subtest 'search with body: prefix for term only in subject'
144 notmuch search body:kryptonite > EXPECTED
145 notmuch search --query=sexp '(body kryptonite)' > OUTPUT
146 test_expect_equal_file EXPECTED OUTPUT
147
148 test_begin_subtest "Search by 'from'"
149 add_message '[subject]="search by from"' '[date]="Sat, 01 Jan 2000 12:00:00 -0000"' [from]=searchbyfrom
150 output=$(notmuch search --query=sexp '(from searchbyfrom)' | notmuch_search_sanitize)
151 test_expect_equal "$output" "thread:XXX   2000-01-01 [1/1] searchbyfrom; search by from (inbox unread)"
152
153 test_begin_subtest "Search by 'from' (address)"
154 add_message '[subject]="search by from (address)"' '[date]="Sat, 01 Jan 2000 12:00:00 -0000"' [from]=searchbyfrom@example.com
155 output=$(notmuch search --query=sexp '(from searchbyfrom@example.com)' | notmuch_search_sanitize)
156 test_expect_equal "$output" "thread:XXX   2000-01-01 [1/1] searchbyfrom@example.com; search by from (address) (inbox unread)"
157
158 test_begin_subtest "Search by 'from' (name)"
159 add_message '[subject]="search by from (name)"' '[date]="Sat, 01 Jan 2000 12:00:00 -0000"' '[from]="Search By From Name <test@example.com>"'
160 output=$(notmuch search --query=sexp '(from "Search By From Name")' | notmuch_search_sanitize)
161 test_expect_equal "$output" "thread:XXX   2000-01-01 [1/1] Search By From Name; search by from (name) (inbox unread)"
162
163 test_begin_subtest "Search by 'from' (name and address)"
164 output=$(notmuch search --query=sexp '(from "Search By From Name <test@example.com>")' | notmuch_search_sanitize)
165 test_expect_equal "$output" "thread:XXX   2000-01-01 [1/1] Search By From Name; search by from (name) (inbox unread)"
166
167 add_message '[dir]=bad' '[subject]="To the bone"'
168 add_message '[dir]=.' '[subject]="Top level"'
169 add_message '[dir]=bad/news' '[subject]="Bears"'
170 mkdir -p "${MAIL_DIR}/duplicate/bad/news"
171 cp "$gen_msg_filename" "${MAIL_DIR}/duplicate/bad/news"
172
173 add_message '[dir]=things' '[subject]="These are a few"'
174 add_message '[dir]=things/favorite' '[subject]="Raindrops, whiskers, kettles"'
175 add_message '[dir]=things/bad' '[subject]="Bites, stings, sad feelings"'
176
177 test_begin_subtest "Search by 'folder' (multiple)"
178 output=$(notmuch search --query=sexp '(folder bad bad/news things/bad)' | notmuch_search_sanitize)
179 test_expect_equal "$output" "thread:XXX   2001-01-05 [1/1] Notmuch Test Suite; To the bone (inbox unread)
180 thread:XXX   2001-01-05 [1/1(2)] Notmuch Test Suite; Bears (inbox unread)
181 thread:XXX   2001-01-05 [1/1] Notmuch Test Suite; Bites, stings, sad feelings (inbox unread)"
182
183 test_begin_subtest "Search by 'folder': top level."
184 notmuch search folder:'""' > EXPECTED
185 notmuch search --query=sexp '(folder "")'  > OUTPUT
186 test_expect_equal_file EXPECTED OUTPUT
187
188 test_begin_subtest "Search by 'folder' with --output=files"
189 output=$(notmuch search --output=files --query=sexp '(folder bad/news)' | notmuch_search_files_sanitize)
190 test_expect_equal "$output" "MAIL_DIR/bad/news/msg-XXX
191 MAIL_DIR/duplicate/bad/news/msg-XXX"
192
193 test_begin_subtest "Search by 'folder' with --output=files (trailing /)"
194 test_subtest_known_broken
195 output=$(notmuch search --output=files --query=sexp '(folder bad/news/)' | notmuch_search_files_sanitize)
196 test_expect_equal "$output" "MAIL_DIR/bad/news/msg-XXX
197 MAIL_DIR/duplicate/bad/news/msg-XXX"
198
199 test_begin_subtest "Search by 'path' with --output=files"
200 output=$(notmuch search --output=files --query=sexp '(path bad/news)' | notmuch_search_files_sanitize)
201 test_expect_equal "$output" "MAIL_DIR/bad/news/msg-XXX
202 MAIL_DIR/duplicate/bad/news/msg-XXX"
203
204 test_begin_subtest "Search by 'path' with --output=files (trailing /)"
205 test_subtest_known_broken
206 output=$(notmuch search --output=files --query=sexp '(path bad/news/)' | notmuch_search_files_sanitize)
207 test_expect_equal "$output" "MAIL_DIR/bad/news/msg-XXX
208 MAIL_DIR/duplicate/bad/news/msg-XXX"
209
210 test_begin_subtest "Search by 'id'"
211 add_message '[subject]="search by id"' '[date]="Sat, 01 Jan 2000 12:00:00 -0000"'
212 output=$(notmuch search --query=sexp "(id ${gen_msg_id})" | notmuch_search_sanitize)
213 test_expect_equal "$output" "thread:XXX   2000-01-01 [1/1] Notmuch Test Suite; search by id (inbox unread)"
214
215 test_begin_subtest "Search by 'id' (or)"
216 add_message '[subject]="search by id"' '[date]="Sat, 01 Jan 2000 12:00:00 -0000"'
217 output=$(notmuch search --query=sexp "(id non-existent-mid ${gen_msg_id})" | notmuch_search_sanitize)
218 test_expect_equal "$output" "thread:XXX   2000-01-01 [1/1] Notmuch Test Suite; search by id (inbox unread)"
219
220 test_begin_subtest "Search by 'is' (multiple)"
221 notmuch tag -inbox tag:searchbytag
222 notmuch search is:inbox AND is:unread | notmuch_search_sanitize > EXPECTED
223 notmuch search --query=sexp '(is inbox unread)' | notmuch_search_sanitize > OUTPUT
224 notmuch tag +inbox tag:searchbytag
225 test_expect_equal_file EXPECTED OUTPUT
226
227 test_begin_subtest "Search by 'mid'"
228 add_message '[subject]="search by mid"' '[date]="Sat, 01 Jan 2000 12:00:00 -0000"'
229 output=$(notmuch search --query=sexp "(mid ${gen_msg_id})" | notmuch_search_sanitize)
230 test_expect_equal "$output" "thread:XXX   2000-01-01 [1/1] Notmuch Test Suite; search by mid (inbox unread)"
231
232 test_begin_subtest "Search by 'mid' (or)"
233 add_message '[subject]="search by mid"' '[date]="Sat, 01 Jan 2000 12:00:00 -0000"'
234 output=$(notmuch search --query=sexp "(mid non-existent-mid ${gen_msg_id})" | notmuch_search_sanitize)
235 test_expect_equal "$output" "thread:XXX   2000-01-01 [1/1] Notmuch Test Suite; search by mid (inbox unread)"
236
237 test_begin_subtest "Search by 'mimetype'"
238 notmuch search mimetype:text/html > EXPECTED
239 notmuch search --query=sexp '(mimetype text html)'  > OUTPUT
240 test_expect_equal_file EXPECTED OUTPUT
241
242 QUERYSTR="date:2009-11-18..2009-11-18 and tag:unread"
243 QUERYSTR2="query:test and subject:Maildir"
244 notmuch config set --database query.test "$QUERYSTR"
245 notmuch config set query.test2 "$QUERYSTR2"
246
247 test_begin_subtest "ill-formed named query search"
248 notmuch search --query=sexp '(query)' > OUTPUT 2>&1
249 cat <<EOF > EXPECTED
250 notmuch search: Syntax error in query
251 'query' expects single atom as argument
252 EOF
253 test_expect_equal_file EXPECTED OUTPUT
254
255 test_begin_subtest "ill-formed named query search 2"
256 notmuch search --query=sexp '(to (query))' > OUTPUT 2>&1
257 cat <<EOF > EXPECTED
258 notmuch search: Syntax error in query
259 'query' not supported inside 'to'
260 EOF
261 test_expect_equal_file EXPECTED OUTPUT
262
263 test_begin_subtest "search named query"
264 notmuch search --query=sexp '(query test)' > OUTPUT
265 notmuch search $QUERYSTR > EXPECTED
266 test_expect_equal_file EXPECTED OUTPUT
267
268 test_begin_subtest "Search by 'subject' (utf-8, phrase-token):"
269 output=$(notmuch search --query=sexp '(subject utf8-sübjéct)' | notmuch_search_sanitize)
270 test_expect_equal "$output" "thread:XXX   2000-01-01 [1/1] Notmuch Test Suite; utf8-sübjéct (inbox unread)"
271
272 test_begin_subtest "search named query with other terms"
273 notmuch search --query=sexp '(and (query test) (subject Maildir))' > OUTPUT
274 notmuch search $QUERYSTR and subject:Maildir > EXPECTED
275 test_expect_equal_file EXPECTED OUTPUT
276
277 test_begin_subtest "search nested named query"
278 notmuch search --query=sexp '(query test2)' > OUTPUT
279 notmuch search $QUERYSTR2 > EXPECTED
280 test_expect_equal_file EXPECTED OUTPUT
281
282 test_begin_subtest "Search by 'subject' (utf-8, quoted string):"
283 output=$(notmuch search --query=sexp '(subject "utf8 sübjéct")' | notmuch_search_sanitize)
284 test_expect_equal "$output" "thread:XXX   2000-01-01 [1/1] Notmuch Test Suite; utf8-sübjéct (inbox unread)"
285
286 test_begin_subtest "Search by 'subject' (combine phrase, term):"
287 output=$(notmuch search --query=sexp '(subject Mac "compatibility issues")' | notmuch_search_sanitize)
288 test_expect_equal "$output" "thread:XXX   2009-11-18 [4/4] Jjgod Jiang, Alexander Botero-Lowry; [notmuch] Mac OS X/Darwin compatibility issues (inbox unread)"
289
290 test_begin_subtest "Search by 'subject' (combine phrase, term 2):"
291 notmuch search --query=sexp '(subject (or utf8 "compatibility issues"))' | notmuch_search_sanitize > OUTPUT
292 cat <<EOF > EXPECTED
293 thread:XXX   2009-11-18 [4/4] Jjgod Jiang, Alexander Botero-Lowry; [notmuch] Mac OS X/Darwin compatibility issues (inbox unread)
294 thread:XXX   2000-01-01 [1/1] Notmuch Test Suite; utf8-sübjéct (inbox unread)
295 thread:XXX   2000-01-01 [1/1] Notmuch Test Suite; utf8-message-body-subject (inbox unread)
296 EOF
297 test_expect_equal_file EXPECTED OUTPUT
298
299 test_begin_subtest "Search by 'subject' (combine phrase, term 3):"
300 notmuch search --query=sexp '(subject issues X/Darwin)' | notmuch_search_sanitize > OUTPUT
301 cat <<EOF > EXPECTED
302 thread:XXX   2009-11-18 [4/4] Jjgod Jiang, Alexander Botero-Lowry; [notmuch] Mac OS X/Darwin compatibility issues (inbox unread)
303 EOF
304 test_expect_equal_file EXPECTED OUTPUT
305
306 test_begin_subtest "Search by 'tag'"
307 add_message '[subject]="search by tag"' '[date]="Sat, 01 Jan 2000 12:00:00 -0000"'
308 notmuch tag +searchbytag id:${gen_msg_id}
309 output=$(notmuch search --query=sexp '(tag searchbytag)' | notmuch_search_sanitize)
310 test_expect_equal "$output" "thread:XXX   2000-01-01 [1/1] Notmuch Test Suite; search by tag (inbox searchbytag unread)"
311
312 test_begin_subtest "Search by 'tag' (multiple)"
313 notmuch tag -inbox tag:searchbytag
314 notmuch search tag:inbox AND tag:unread | notmuch_search_sanitize > EXPECTED
315 notmuch search --query=sexp '(tag inbox unread)' | notmuch_search_sanitize > OUTPUT
316 notmuch tag +inbox tag:searchbytag
317 test_expect_equal_file EXPECTED OUTPUT
318
319 test_begin_subtest "Search by 'tag' and 'subject'"
320 notmuch search tag:inbox and subject:maildir | notmuch_search_sanitize > EXPECTED
321 notmuch search --query=sexp '(and (tag inbox) (subject maildir))' | notmuch_search_sanitize > OUTPUT
322 test_expect_equal_file EXPECTED OUTPUT
323
324 test_begin_subtest "Search by 'thread'"
325 add_message '[subject]="search by thread"' '[date]="Sat, 01 Jan 2000 12:00:00 -0000"'
326 thread_id=$(notmuch search id:${gen_msg_id} | sed -e "s/thread:\([a-f0-9]*\).*/\1/")
327 output=$(notmuch search --query=sexp "(thread ${thread_id})" | notmuch_search_sanitize)
328 test_expect_equal "$output" "thread:XXX   2000-01-01 [1/1] Notmuch Test Suite; search by thread (inbox unread)"
329
330 test_begin_subtest "Search by 'to'"
331 add_message '[subject]="search by to"' '[date]="Sat, 01 Jan 2000 12:00:00 -0000"' [to]=searchbyto
332 output=$(notmuch search --query=sexp '(to searchbyto)' | notmuch_search_sanitize)
333 test_expect_equal "$output" "thread:XXX   2000-01-01 [1/1] Notmuch Test Suite; search by to (inbox unread)"
334
335 test_begin_subtest "Search by 'to' (address)"
336 add_message '[subject]="search by to (address)"' '[date]="Sat, 01 Jan 2000 12:00:00 -0000"' [to]=searchbyto@example.com
337 output=$(notmuch search --query=sexp '(to searchbyto@example.com)' | notmuch_search_sanitize)
338 test_expect_equal "$output" "thread:XXX   2000-01-01 [1/1] Notmuch Test Suite; search by to (address) (inbox unread)"
339
340 test_begin_subtest "Search by 'to' (name)"
341 add_message '[subject]="search by to (name)"' '[date]="Sat, 01 Jan 2000 12:00:00 -0000"' '[to]="Search By To Name <test@example.com>"'
342 output=$(notmuch search --query=sexp '(to "Search By To Name")' | notmuch_search_sanitize)
343 test_expect_equal "$output" "thread:XXX   2000-01-01 [1/1] Notmuch Test Suite; search by to (name) (inbox unread)"
344
345 test_begin_subtest "Search by 'to' (name and address)"
346 output=$(notmuch search --query=sexp '(to "Search By To Name <test@example.com>")' | notmuch_search_sanitize)
347 test_expect_equal "$output" "thread:XXX   2000-01-01 [1/1] Notmuch Test Suite; search by to (name) (inbox unread)"
348
349 test_begin_subtest "starts-with, no prefix"
350 output=$(notmuch search --query=sexp '(starts-with prelim)' | notmuch_search_sanitize)
351 test_expect_equal "$output" "thread:XXX   2009-11-17 [2/2] Alex Botero-Lowry, Carl Worth; [notmuch] preliminary FreeBSD support (attachment inbox unread)"
352
353 test_begin_subtest "starts-with, case-insensitive"
354 notmuch search --query=sexp '(starts-with FreeB)' | notmuch_search_sanitize > OUTPUT
355 cat <<EOF > EXPECTED
356 thread:XXX   2009-11-18 [3/4] Alexander Botero-Lowry, Jjgod Jiang; [notmuch] Mac OS X/Darwin compatibility issues (inbox unread)
357 thread:XXX   2009-11-17 [2/2] Alex Botero-Lowry, Carl Worth; [notmuch] preliminary FreeBSD support (attachment inbox unread)
358 EOF
359 test_expect_equal_file EXPECTED OUTPUT
360
361 test_begin_subtest "starts-with, no prefix, all messages"
362 notmuch search --query=sexp '(starts-with "")' | notmuch_search_sanitize > OUTPUT
363 notmuch search '*' | notmuch_search_sanitize > EXPECTED
364 test_expect_equal_file EXPECTED OUTPUT
365
366 test_begin_subtest "starts-with, attachment"
367 output=$(notmuch search --query=sexp '(attachment (starts-with not))' | notmuch_search_sanitize)
368 test_expect_equal "$output" 'thread:XXX   2009-11-18 [2/2] Lars Kellogg-Stedman; [notmuch] "notmuch help" outputs to stderr? (attachment inbox signed unread)'
369
370 test_begin_subtest "starts-with, folder"
371 notmuch search --output=files --query=sexp '(folder (starts-with bad))' | notmuch_search_files_sanitize > OUTPUT
372 cat <<EOF > EXPECTED
373 MAIL_DIR/bad/msg-XXX
374 MAIL_DIR/bad/news/msg-XXX
375 MAIL_DIR/duplicate/bad/news/msg-XXX
376 EOF
377 test_expect_equal_file EXPECTED OUTPUT
378
379 test_begin_subtest "starts-with, from"
380 notmuch search --query=sexp '(from (starts-with Mik))' | notmuch_search_sanitize > OUTPUT
381 cat <<EOF > EXPECTED
382 thread:XXX   2009-11-17 [1/1] Mikhail Gusarov; [notmuch] [PATCH] Handle rename of message file (inbox unread)
383 thread:XXX   2009-11-17 [2/7] Mikhail Gusarov| Lars Kellogg-Stedman, Keith Packard, Carl Worth; [notmuch] Working with Maildir storage? (inbox signed unread)
384 thread:XXX   2009-11-17 [2/5] Mikhail Gusarov| Carl Worth, Keith Packard; [notmuch] [PATCH 2/2] Include <stdint.h> to get uint32_t in C++ file with gcc 4.4 (inbox unread)
385 EOF
386 test_expect_equal_file EXPECTED OUTPUT
387
388 test_begin_subtest "starts-with, id"
389 notmuch search --query=sexp --output=messages '(id (starts-with 877))' > OUTPUT
390 cat <<EOF > EXPECTED
391 id:877h1wv7mg.fsf@inf-8657.int-evry.fr
392 id:877htoqdbo.fsf@yoom.home.cworth.org
393 EOF
394 test_expect_equal_file EXPECTED OUTPUT
395
396 test_begin_subtest "starts-with, is"
397 output=$(notmuch search --query=sexp '(is (starts-with searchby))' | notmuch_search_sanitize)
398 test_expect_equal "$output" 'thread:XXX   2000-01-01 [1/1] Notmuch Test Suite; search by tag (inbox searchbytag unread)'
399
400 test_begin_subtest "starts-with, mid"
401 notmuch search --query=sexp --output=messages '(mid (starts-with 877))' > OUTPUT
402 cat <<EOF > EXPECTED
403 id:877h1wv7mg.fsf@inf-8657.int-evry.fr
404 id:877htoqdbo.fsf@yoom.home.cworth.org
405 EOF
406 test_expect_equal_file EXPECTED OUTPUT
407
408 test_begin_subtest "starts-with, mimetype"
409 notmuch search --query=sexp '(mimetype (starts-with sig))' | notmuch_search_sanitize > OUTPUT
410 cat <<EOF > EXPECTED
411 thread:XXX   2009-11-18 [2/2] Lars Kellogg-Stedman; [notmuch] "notmuch help" outputs to stderr? (attachment inbox signed unread)
412 thread:XXX   2009-11-18 [4/7] Lars Kellogg-Stedman, Mikhail Gusarov| Keith Packard, Carl Worth; [notmuch] Working with Maildir storage? (inbox signed unread)
413 thread:XXX   2009-11-17 [1/3] Adrian Perez de Castro| Keith Packard, Carl Worth; [notmuch] Introducing myself (inbox signed unread)
414 EOF
415 test_expect_equal_file EXPECTED OUTPUT
416
417 add_message '[subject]="message with properties"'
418 notmuch restore <<EOF
419 #= ${gen_msg_id} foo=bar
420 EOF
421
422 test_begin_subtest "starts-with, property"
423 notmuch search --query=sexp '(property (starts-with foo=))' | notmuch_search_sanitize > OUTPUT
424 cat <<EOF > EXPECTED
425 thread:XXX   2001-01-05 [1/1] Notmuch Test Suite; message with properties (inbox unread)
426 EOF
427 test_expect_equal_file EXPECTED OUTPUT
428
429 test_begin_subtest "starts-with, subject"
430 notmuch search --query=sexp '(subject (starts-with FreeB))' | notmuch_search_sanitize > OUTPUT
431 cat <<EOF > EXPECTED
432 thread:XXX   2009-11-17 [2/2] Alex Botero-Lowry, Carl Worth; [notmuch] preliminary FreeBSD support (attachment inbox unread)
433 EOF
434 test_expect_equal_file EXPECTED OUTPUT
435
436 test_begin_subtest "starts-with, tag"
437 output=$(notmuch search --query=sexp '(tag (starts-with searchby))' | notmuch_search_sanitize)
438 test_expect_equal "$output" 'thread:XXX   2000-01-01 [1/1] Notmuch Test Suite; search by tag (inbox searchbytag unread)'
439
440 add_message '[subject]="no tags"'
441 notag_mid=${gen_msg_id}
442 notmuch tag -unread -inbox id:${notag_mid}
443
444 test_begin_subtest "negated starts-with, tag"
445 output=$(notmuch search --query=sexp '(tag (not (starts-with in)))' | notmuch_search_sanitize)
446 test_expect_equal "$output" 'thread:XXX   2001-01-05 [1/1] Notmuch Test Suite; no tags ()'
447
448 test_begin_subtest "negated starts-with, tag 2"
449 output=$(notmuch search --query=sexp '(not (tag (starts-with in)))' | notmuch_search_sanitize)
450 test_expect_equal "$output" 'thread:XXX   2001-01-05 [1/1] Notmuch Test Suite; no tags ()'
451
452 test_begin_subtest "negated starts-with, tag 3"
453 output=$(notmuch search --query=sexp '(not (tag (starts-with "")))' | notmuch_search_sanitize)
454 test_expect_equal "$output" 'thread:XXX   2001-01-05 [1/1] Notmuch Test Suite; no tags ()'
455
456 test_begin_subtest "starts-with, thread"
457 notmuch search --query=sexp '(thread (starts-with "00"))' > OUTPUT
458 notmuch search '*' > EXPECTED
459 test_expect_equal_file EXPECTED OUTPUT
460
461 test_begin_subtest "starts-with, to"
462 notmuch search --query=sexp '(to (starts-with "search"))' | notmuch_search_sanitize > OUTPUT
463 cat <<EOF > EXPECTED
464 thread:XXX   2000-01-01 [1/1] Notmuch Test Suite; search by to (inbox unread)
465 thread:XXX   2000-01-01 [1/1] Notmuch Test Suite; search by to (address) (inbox unread)
466 thread:XXX   2000-01-01 [1/1] Notmuch Test Suite; search by to (name) (inbox unread)
467 EOF
468 test_expect_equal_file EXPECTED OUTPUT
469
470 test_begin_subtest "wildcard search for 'is'"
471 notmuch search not id:${notag_mid} > EXPECTED
472 notmuch search --query=sexp '(is *)' > OUTPUT
473 test_expect_equal_file EXPECTED OUTPUT
474
475 test_begin_subtest "negated wildcard search for 'is'"
476 notmuch search id:${notag_mid} > EXPECTED
477 notmuch search --query=sexp '(not (is *))' > OUTPUT
478 test_expect_equal_file EXPECTED OUTPUT
479
480 test_begin_subtest "wildcard search for 'property'"
481 notmuch search property:foo=bar > EXPECTED
482 notmuch search --query=sexp '(property *)' > OUTPUT
483 test_expect_equal_file EXPECTED OUTPUT
484
485 test_begin_subtest "wildcard search for 'tag'"
486 notmuch search not id:${notag_mid} > EXPECTED
487 notmuch search --query=sexp '(tag *)' > OUTPUT
488 test_expect_equal_file EXPECTED OUTPUT
489
490 test_begin_subtest "negated wildcard search for 'tag'"
491 notmuch search id:${notag_mid} > EXPECTED
492 notmuch search --query=sexp '(not (tag *))' > OUTPUT
493 test_expect_equal_file EXPECTED OUTPUT
494
495 add_message '[subject]="message with tag \"*\""'
496 notmuch tag '+*' id:${gen_msg_id}
497
498 test_begin_subtest "search for 'tag' \"*\""
499 output=$(notmuch search --query=sexp --output=messages '(tag "*")')
500 test_expect_equal "$output" "id:$gen_msg_id"
501
502 test_begin_subtest "search for missing / empty to"
503 add_message [to]="undisclosed-recipients:"
504 notmuch search --query=sexp '(not (to *))' | notmuch_search_sanitize > OUTPUT
505 cat <<EOF > EXPECTED
506 thread:XXX   2001-01-05 [1/1] Notmuch Test Suite; search for missing / empty to (inbox unread)
507 EOF
508 test_expect_equal_file EXPECTED OUTPUT
509
510 test_begin_subtest "Unbalanced parens"
511 # A code 1 indicates the error was handled (a crash will return e.g. 139).
512 test_expect_code 1 "notmuch search --query=sexp '('"
513
514 test_begin_subtest "Unbalanced parens, error message"
515 notmuch search --query=sexp '(' >OUTPUT 2>&1
516 cat <<EOF > EXPECTED
517 notmuch search: Syntax error in query
518 invalid s-expression: '('
519 EOF
520 test_expect_equal_file EXPECTED OUTPUT
521
522 test_begin_subtest "unknown prefix"
523 notmuch search --query=sexp '(foo)' >OUTPUT 2>&1
524 cat <<EOF > EXPECTED
525 notmuch search: Syntax error in query
526 unknown prefix 'foo'
527 EOF
528 test_expect_equal_file EXPECTED OUTPUT
529
530 test_begin_subtest "list as prefix"
531 notmuch search --query=sexp '((foo))' >OUTPUT 2>&1
532 cat <<EOF > EXPECTED
533 notmuch search: Syntax error in query
534 unexpected list in field/operation position
535 EOF
536 test_expect_equal_file EXPECTED OUTPUT
537
538 test_begin_subtest "illegal nesting"
539 notmuch search --query=sexp '(subject (subject foo))' >OUTPUT 2>&1
540 cat <<EOF > EXPECTED
541 notmuch search: Syntax error in query
542 nested field: 'subject' inside 'subject'
543 EOF
544 test_expect_equal_file EXPECTED OUTPUT
545
546 test_begin_subtest "starts-with, no argument"
547 notmuch search --query=sexp '(starts-with)' >OUTPUT 2>&1
548 cat <<EOF > EXPECTED
549 notmuch search: Syntax error in query
550 'starts-with' expects single atom as argument
551 EOF
552 test_expect_equal_file EXPECTED OUTPUT
553
554 test_begin_subtest "starts-with, list argument"
555 notmuch search --query=sexp '(starts-with (stuff))' >OUTPUT 2>&1
556 cat <<EOF > EXPECTED
557 notmuch search: Syntax error in query
558 'starts-with' expects single atom as argument
559 EOF
560 test_expect_equal_file EXPECTED OUTPUT
561
562 test_begin_subtest "starts-with, too many arguments"
563 notmuch search --query=sexp '(starts-with a b c)' >OUTPUT 2>&1
564 cat <<EOF > EXPECTED
565 notmuch search: Syntax error in query
566 'starts-with' expects single atom as argument
567 EOF
568 test_expect_equal_file EXPECTED OUTPUT
569
570 test_begin_subtest "starts-with, illegal field"
571 notmuch search --query=sexp '(body (starts-with foo))' >OUTPUT 2>&1
572 cat <<EOF > EXPECTED
573 notmuch search: Syntax error in query
574 'body' does not support wildcard queries
575 EOF
576 test_expect_equal_file EXPECTED OUTPUT
577
578 test_begin_subtest "wildcard, illegal field"
579 notmuch search --query=sexp '(body *)' >OUTPUT 2>&1
580 cat <<EOF > EXPECTED
581 notmuch search: Syntax error in query
582 'body' does not support wildcard queries
583 EOF
584 test_expect_equal_file EXPECTED OUTPUT
585
586 test_begin_subtest "Search, exclude \"deleted\" messages from search"
587 notmuch config set search.exclude_tags deleted
588 generate_message '[subject]="Not deleted"'
589 not_deleted_id=$gen_msg_id
590 generate_message '[subject]="Deleted"'
591 notmuch new > /dev/null
592 notmuch tag +deleted id:$gen_msg_id
593 deleted_id=$gen_msg_id
594 output=$(notmuch search --query=sexp '(subject deleted)' | notmuch_search_sanitize)
595 test_expect_equal "$output" "thread:XXX   2001-01-05 [1/1] Notmuch Test Suite; Not deleted (inbox unread)"
596
597 test_begin_subtest "Search, exclude \"deleted\" messages from message search --exclude=false"
598 output=$(notmuch search --query=sexp --exclude=false --output=messages '(subject deleted)' | notmuch_search_sanitize)
599 test_expect_equal "$output" "id:$not_deleted_id
600 id:$deleted_id"
601
602 test_begin_subtest "Search, exclude \"deleted\" messages from search, overridden"
603 notmuch search --query=sexp '(and (subject deleted) (tag deleted))' | notmuch_search_sanitize > OUTPUT
604 cat <<EOF > EXPECTED
605 thread:XXX   2001-01-05 [1/1] Notmuch Test Suite; Deleted (deleted inbox unread)
606 EOF
607 test_expect_equal_file EXPECTED OUTPUT
608
609 test_begin_subtest "Search, exclude \"deleted\" messages from threads"
610 add_message '[subject]="Not deleted reply"' '[in-reply-to]="<$gen_msg_id>"'
611 output=$(notmuch search --query=sexp '(subject deleted)' | notmuch_search_sanitize)
612 test_expect_equal "$output" "thread:XXX   2001-01-05 [1/1] Notmuch Test Suite; Not deleted (inbox unread)
613 thread:XXX   2001-01-05 [1/2] Notmuch Test Suite; Not deleted reply (deleted inbox unread)"
614
615 test_begin_subtest "Search, don't exclude \"deleted\" messages when --exclude=flag specified"
616 output=$(notmuch search --query=sexp --exclude=flag '(subject deleted)' | notmuch_search_sanitize)
617 test_expect_equal "$output" "thread:XXX   2001-01-05 [1/1] Notmuch Test Suite; Not deleted (inbox unread)
618 thread:XXX   2001-01-05 [1/2] Notmuch Test Suite; Deleted (deleted inbox unread)"
619
620 test_begin_subtest "Search, don't exclude \"deleted\" messages from search if not configured"
621 notmuch config set search.exclude_tags
622 output=$(notmuch search --query=sexp '(subject deleted)' | notmuch_search_sanitize)
623 test_expect_equal "$output" "thread:XXX   2001-01-05 [1/1] Notmuch Test Suite; Not deleted (inbox unread)
624 thread:XXX   2001-01-05 [2/2] Notmuch Test Suite; Deleted (deleted inbox unread)"
625
626 test_begin_subtest "regex at top level"
627 notmuch search --query=sexp '(rx foo)' >& OUTPUT
628 cat <<EOF > EXPECTED
629 notmuch search: Syntax error in query
630 illegal 'rx' outside field
631 EOF
632 test_expect_equal_file EXPECTED OUTPUT
633
634 test_begin_subtest "regex in illegal field"
635 notmuch search --query=sexp '(body (regex foo))' >& OUTPUT
636 cat <<EOF > EXPECTED
637 notmuch search: Syntax error in query
638 'regex' not supported in field 'body'
639 EOF
640 test_expect_equal_file EXPECTED OUTPUT
641
642 notmuch search --output=messages from:cworth > cworth.msg-ids
643
644 test_begin_subtest "regexp 'from' search"
645 notmuch search --output=messages --query=sexp '(from (rx cworth))' > OUTPUT
646 test_expect_equal_file cworth.msg-ids OUTPUT
647
648 test_begin_subtest "regexp search for 'from' 2"
649 notmuch search from:/cworth@cworth.org/ and subject:patch | notmuch_search_sanitize > EXPECTED
650 notmuch search --query=sexp '(and (from (rx cworth@cworth.org)) (subject patch))' \
651     | notmuch_search_sanitize > OUTPUT
652 test_expect_equal_file EXPECTED OUTPUT
653
654 test_begin_subtest "regexp 'folder' search"
655 notmuch search 'folder:/^bar$/' | notmuch_search_sanitize > EXPECTED
656 notmuch search --query=sexp '(folder (rx ^bar$))' | notmuch_search_sanitize > OUTPUT
657 test_expect_equal_file EXPECTED OUTPUT
658
659 test_begin_subtest "regexp 'id' search"
660 notmuch search --output=messages --query=sexp '(id (rx yoom))' > OUTPUT
661 test_expect_equal_file cworth.msg-ids OUTPUT
662
663 test_begin_subtest "unanchored 'is' search"
664 notmuch search tag:signed or tag:inbox > EXPECTED
665 notmuch search --query=sexp '(is (rx i))' > OUTPUT
666 test_expect_equal_file EXPECTED OUTPUT
667
668 test_begin_subtest "anchored 'is' search"
669 notmuch search tag:signed > EXPECTED
670 notmuch search --query=sexp '(is (rx ^si))' > OUTPUT
671 test_expect_equal_file EXPECTED OUTPUT
672
673 test_begin_subtest "combine regexp mid and subject"
674 notmuch search subject:/-C/ and mid:/y..m/ | notmuch_search_sanitize > EXPECTED
675 notmuch search --query=sexp '(and (subject (rx -C)) (mid (rx y..m)))' | notmuch_search_sanitize > OUTPUT
676 test_expect_equal_file EXPECTED OUTPUT
677
678 test_begin_subtest "regexp 'path' search"
679 notmuch search 'path:/^bar$/' | notmuch_search_sanitize > EXPECTED
680 notmuch search --query=sexp '(path (rx ^bar$))' | notmuch_search_sanitize > OUTPUT
681 test_expect_equal_file EXPECTED OUTPUT
682
683 test_begin_subtest "regexp 'property' search"
684 notmuch search property:foo=bar > EXPECTED
685 notmuch search --query=sexp '(property (rx foo=.*))' > OUTPUT
686 test_expect_equal_file EXPECTED OUTPUT
687
688 test_begin_subtest "anchored 'tag' search"
689 notmuch search tag:signed > EXPECTED
690 notmuch search --query=sexp '(tag (rx ^si))' > OUTPUT
691 test_expect_equal_file EXPECTED OUTPUT
692
693 test_begin_subtest "regexp 'thread' search"
694 notmuch search --output=threads '*' | grep '7$' > EXPECTED
695 notmuch search --output=threads --query=sexp '(thread (rx 7$))' > OUTPUT
696 test_expect_equal_file EXPECTED OUTPUT
697
698 test_begin_subtest "Basic query that matches no messages"
699 count=$(notmuch count from:keithp and to:keithp)
700 test_expect_equal 0 "$count"
701
702 test_begin_subtest "Same query against threads"
703 notmuch search --query=sexp '(and (thread (of (from keithp))) (thread (matching (to keithp))))' \
704     | notmuch_search_sanitize > OUTPUT
705 cat<<EOF > EXPECTED
706 thread:XXX   2009-11-18 [7/7] Lars Kellogg-Stedman, Mikhail Gusarov, Keith Packard, Carl Worth; [notmuch] Working with Maildir storage? (inbox signed unread)
707 EOF
708 test_expect_equal_file EXPECTED OUTPUT
709
710 test_begin_subtest "Mix thread and non-threads query"
711 notmuch search --query=sexp '(and (thread (matching keithp)) (to keithp))' | notmuch_search_sanitize > OUTPUT
712 cat<<EOF > EXPECTED
713 thread:XXX   2009-11-18 [1/7] Lars Kellogg-Stedman| Mikhail Gusarov, Keith Packard, Carl Worth; [notmuch] Working with Maildir storage? (inbox signed unread)
714 EOF
715 test_expect_equal_file EXPECTED OUTPUT
716
717 test_begin_subtest "Compound subquery"
718 notmuch search --query=sexp '(thread (of (from keithp) (subject Maildir)))' | notmuch_search_sanitize > OUTPUT
719 cat<<EOF > EXPECTED
720 thread:XXX   2009-11-18 [7/7] Lars Kellogg-Stedman, Mikhail Gusarov, Keith Packard, Carl Worth; [notmuch] Working with Maildir storage? (inbox signed unread)
721 EOF
722 test_expect_equal_file EXPECTED OUTPUT
723
724 test_begin_subtest "empty subquery"
725 notmuch search --query=sexp '(thread (of))' 1>OUTPUT 2>&1
726 notmuch search '*' > EXPECTED
727 test_expect_equal_file EXPECTED OUTPUT
728
729 test_begin_subtest "illegal expansion"
730 notmuch search --query=sexp '(id (of ego))' 1>OUTPUT 2>&1
731 cat<<EOF > EXPECTED
732 notmuch search: Syntax error in query
733 'of' unsupported inside 'id'
734 EOF
735 test_expect_equal_file EXPECTED OUTPUT
736
737 test_begin_subtest "(folder (of subquery))"
738 notmuch search --query=sexp --output=messages '(folder (of (id yun3a4cegoa.fsf@aiko.keithp.com)))' > OUTPUT
739 cat <<EOF > EXPECTED
740 id:yun1vjwegii.fsf@aiko.keithp.com
741 id:yun3a4cegoa.fsf@aiko.keithp.com
742 id:1258509400-32511-1-git-send-email-stewart@flamingspork.com
743 id:1258506353-20352-1-git-send-email-stewart@flamingspork.com
744 id:20091118010116.GC25380@dottiness.seas.harvard.edu
745 id:20091118005829.GB25380@dottiness.seas.harvard.edu
746 id:cf0c4d610911171136h1713aa59w9cf9aa31f052ad0a@mail.gmail.com
747 EOF
748 test_expect_equal_file EXPECTED OUTPUT
749
750 test_begin_subtest "infix query"
751 notmuch search to:searchbyto | notmuch_search_sanitize > EXPECTED
752 notmuch search --query=sexp '(infix "to:searchbyto")' |  notmuch_search_sanitize > OUTPUT
753 test_expect_equal_file EXPECTED OUTPUT
754
755 test_begin_subtest "bad infix query 1"
756 notmuch search --query=sexp '(infix "from:/unbalanced")' 2>&1|  notmuch_search_sanitize > OUTPUT
757 cat <<EOF > EXPECTED
758 notmuch search: Syntax error in query
759 Syntax error in infix query: from:/unbalanced
760 EOF
761 test_expect_equal_file EXPECTED OUTPUT
762
763 test_begin_subtest "bad infix query 2"
764 notmuch search --query=sexp '(infix "thread:{unbalanced")' 2>&1|  notmuch_search_sanitize > OUTPUT
765 cat <<EOF > EXPECTED
766 notmuch search: Syntax error in query
767 Syntax error in infix query: thread:{unbalanced
768 EOF
769 test_expect_equal_file EXPECTED OUTPUT
770
771 test_begin_subtest "bad infix query 3: bad nesting"
772 notmuch search --query=sexp '(subject (infix "tag:inbox"))' 2>&1|  notmuch_search_sanitize > OUTPUT
773 cat <<EOF > EXPECTED
774 notmuch search: Syntax error in query
775 'infix' not supported inside 'subject'
776 EOF
777 test_expect_equal_file EXPECTED OUTPUT
778
779 test_begin_subtest "infix query that matches no messages"
780 notmuch search --query=sexp '(and (infix "from:keithp") (infix "to:keithp"))' > OUTPUT
781 test_expect_equal_file /dev/null OUTPUT
782
783 test_begin_subtest "compound infix query"
784 notmuch search date:2009-11-18..2009-11-18 and tag:unread > EXPECTED
785 notmuch search --query=sexp  '(infix "date:2009-11-18..2009-11-18 and tag:unread")' > OUTPUT
786 test_expect_equal_file EXPECTED OUTPUT
787
788 test_begin_subtest "compound infix query 2"
789 notmuch search date:2009-11-18..2009-11-18 and tag:unread > EXPECTED
790 notmuch search --query=sexp  '(and (infix "date:2009-11-18..2009-11-18") (infix "tag:unread"))' > OUTPUT
791 test_expect_equal_file EXPECTED OUTPUT
792
793 test_begin_subtest "date query, empty"
794 notmuch search from:keithp | notmuch_search_sanitize > EXPECTED
795 notmuch search --query=sexp  '(and (date) (from keithp))'| notmuch_search_sanitize > OUTPUT
796 test_expect_equal_file EXPECTED OUTPUT
797
798 test_begin_subtest "date query, one argument"
799 notmuch search date:2009-11-18 and from:keithp | notmuch_search_sanitize > EXPECTED
800 notmuch search --query=sexp  '(and (date 2009-11-18) (from keithp))' | notmuch_search_sanitize > OUTPUT
801 test_expect_equal_file EXPECTED OUTPUT
802
803 test_begin_subtest "date query, two arguments"
804 notmuch search date:2009-11-17..2009-11-18 and from:keithp | notmuch_search_sanitize > EXPECTED
805 notmuch search --query=sexp  '(and (date 2009-11-17 2009-11-18) (from keithp))' | notmuch_search_sanitize > OUTPUT
806 test_expect_equal_file EXPECTED OUTPUT
807
808 test_begin_subtest "date query, illegal nesting 1"
809 notmuch search --query=sexp '(to (date))' > OUTPUT 2>&1
810 cat <<EOF > EXPECTED
811 notmuch search: Syntax error in query
812 nested field: 'date' inside 'to'
813 EOF
814 test_expect_equal_file EXPECTED OUTPUT
815
816 test_begin_subtest "date query, illegal nesting 2"
817 notmuch search --query=sexp '(to (date 2021-11-18))' > OUTPUT 2>&1
818 cat <<EOF > EXPECTED
819 notmuch search: Syntax error in query
820 nested field: 'date' inside 'to'
821 EOF
822 test_expect_equal_file EXPECTED OUTPUT
823
824 test_begin_subtest "date query, illegal nesting 3"
825 notmuch search --query=sexp '(date (to))' > OUTPUT 2>&1
826 cat <<EOF > EXPECTED
827 notmuch search: Syntax error in query
828 expected atom as first argument of 'date'
829 EOF
830 test_expect_equal_file EXPECTED OUTPUT
831
832 test_begin_subtest "date query, illegal nesting 4"
833 notmuch search --query=sexp '(date today (to))' > OUTPUT 2>&1
834 cat <<EOF > EXPECTED
835 notmuch search: Syntax error in query
836 expected atom as second argument of 'date'
837 EOF
838 test_expect_equal_file EXPECTED OUTPUT
839
840 test_begin_subtest "date query, too many arguments"
841 notmuch search --query=sexp '(date yesterday and tommorow)' > OUTPUT 2>&1
842 cat <<EOF > EXPECTED
843 notmuch search: Syntax error in query
844 'date' expects maximum of two arguments
845 EOF
846 test_expect_equal_file EXPECTED OUTPUT
847
848 test_begin_subtest "date query, bad date"
849 notmuch search --query=sexp '(date "hawaiian-pizza-day")' > OUTPUT 2>&1
850 cat <<EOF > EXPECTED
851 notmuch search: Syntax error in query
852 Didn't understand date specification 'hawaiian-pizza-day'
853 EOF
854 test_expect_equal_file EXPECTED OUTPUT
855
856 test_begin_subtest "lastmod query, empty"
857 notmuch search from:keithp | notmuch_search_sanitize > EXPECTED
858 notmuch search --query=sexp  '(and (lastmod) (from keithp))'| notmuch_search_sanitize > OUTPUT
859 test_expect_equal_file EXPECTED OUTPUT
860
861 test_begin_subtest "lastmod query, one argument"
862 notmuch tag +4EFC743A.3060609@april.org id:4EFC743A.3060609@april.org
863 revision=$(notmuch count --lastmod '*' | cut -f3)
864 notmuch search lastmod:$revision..$revision | notmuch_search_sanitize > EXPECTED
865 notmuch search --query=sexp  "(and (lastmod $revision))" | notmuch_search_sanitize > OUTPUT
866 test_expect_equal_file EXPECTED OUTPUT
867
868 test_begin_subtest "lastmod query, two arguments"
869 notmuch tag +keithp from:keithp
870 revision2=$(notmuch count --lastmod '*' | cut -f3)
871 notmuch search lastmod:$revision..$revision2 | notmuch_search_sanitize > EXPECTED
872 notmuch search --query=sexp  "(and (lastmod $revision $revision2))" | notmuch_search_sanitize > OUTPUT
873 test_expect_equal_file EXPECTED OUTPUT
874
875 test_begin_subtest "lastmod query, illegal nesting 1"
876 notmuch search --query=sexp '(to (lastmod))' > OUTPUT 2>&1
877 cat <<EOF > EXPECTED
878 notmuch search: Syntax error in query
879 nested field: 'lastmod' inside 'to'
880 EOF
881 test_expect_equal_file EXPECTED OUTPUT
882
883 test_begin_subtest "lastmod query, bad from revision"
884 notmuch search --query=sexp '(lastmod apples)' > OUTPUT 2>&1
885 cat <<EOF > EXPECTED
886 notmuch search: Syntax error in query
887 bad 'from' revision: 'apples'
888 EOF
889 test_expect_equal_file EXPECTED OUTPUT
890
891 test_begin_subtest "lastmod query, bad to revision"
892 notmuch search --query=sexp '(lastmod 0 apples)' > OUTPUT 2>&1
893 cat <<EOF > EXPECTED
894 notmuch search: Syntax error in query
895 bad 'to' revision: 'apples'
896 EOF
897 test_expect_equal_file EXPECTED OUTPUT
898
899 test_begin_subtest "lastmod query, illegal nesting 2"
900 notmuch search --query=sexp '(to (lastmod 2021-11-18))' > OUTPUT 2>&1
901 cat <<EOF > EXPECTED
902 notmuch search: Syntax error in query
903 nested field: 'lastmod' inside 'to'
904 EOF
905 test_expect_equal_file EXPECTED OUTPUT
906
907 test_begin_subtest "lastmod query, illegal nesting 3"
908 notmuch search --query=sexp '(lastmod (to))' > OUTPUT 2>&1
909 cat <<EOF > EXPECTED
910 notmuch search: Syntax error in query
911 expected atom as first argument of 'lastmod'
912 EOF
913 test_expect_equal_file EXPECTED OUTPUT
914
915 test_begin_subtest "lastmod query, illegal nesting 4"
916 notmuch search --query=sexp '(lastmod today (to))' > OUTPUT 2>&1
917 cat <<EOF > EXPECTED
918 notmuch search: Syntax error in query
919 expected atom as second argument of 'lastmod'
920 EOF
921 test_expect_equal_file EXPECTED OUTPUT
922
923 test_begin_subtest "lastmod query, too many arguments"
924 notmuch search --query=sexp '(lastmod yesterday and tommorow)' > OUTPUT 2>&1
925 cat <<EOF > EXPECTED
926 notmuch search: Syntax error in query
927 'lastmod' expects maximum of two arguments
928 EOF
929 test_expect_equal_file EXPECTED OUTPUT
930
931 test_begin_subtest "user header (unknown header)"
932 notmuch search --query=sexp '(FooBar)' >& OUTPUT
933 cat <<EOF > EXPECTED
934 notmuch search: Syntax error in query
935 unknown prefix 'FooBar'
936 EOF
937 test_expect_equal_file EXPECTED OUTPUT
938
939 test_begin_subtest "adding user header"
940 test_expect_code 0 "notmuch config set index.header.List \"List-Id\""
941
942 test_begin_subtest "reindexing"
943 test_expect_code 0 'notmuch reindex "*"'
944
945 test_begin_subtest "wildcard search for user header"
946 grep -Ril List-Id ${MAIL_DIR} | sort | notmuch_dir_sanitize > EXPECTED
947 notmuch search --output=files --query=sexp '(List *)' | sort | notmuch_dir_sanitize > OUTPUT
948 test_expect_equal_file EXPECTED OUTPUT
949
950 test_begin_subtest "wildcard search for user header 2"
951 grep -Ril List-Id ${MAIL_DIR} | sort | notmuch_dir_sanitize > EXPECTED
952 notmuch search --output=files --query=sexp '(List (starts-with not))' | sort | notmuch_dir_sanitize > OUTPUT
953 test_expect_equal_file EXPECTED OUTPUT
954
955 test_begin_subtest "search for user header"
956 notmuch search List:notmuch | notmuch_search_sanitize > EXPECTED
957 notmuch search --query=sexp '(List notmuch)' | notmuch_search_sanitize > OUTPUT
958 test_expect_equal_file EXPECTED OUTPUT
959
960 test_begin_subtest "search for user header (list token)"
961 notmuch search List:notmuch | notmuch_search_sanitize > EXPECTED
962 notmuch search --query=sexp '(List notmuch.notmuchmail.org)' | notmuch_search_sanitize > OUTPUT
963 test_expect_equal_file EXPECTED OUTPUT
964
965 test_begin_subtest "search for user header (quoted string)"
966 notmuch search 'List:"notmuch notmuchmail org"' | notmuch_search_sanitize > EXPECTED
967 notmuch search --query=sexp '(List "notmuch notmuchmail org")' | notmuch_search_sanitize > OUTPUT
968 test_expect_equal_file EXPECTED OUTPUT
969
970 test_begin_subtest "search for user header (atoms)"
971 notmuch search 'List:"notmuch notmuchmail org"' | notmuch_search_sanitize > EXPECTED
972 notmuch search --query=sexp '(List notmuch notmuchmail org)' | notmuch_search_sanitize > OUTPUT
973 test_expect_equal_file EXPECTED OUTPUT
974
975 test_begin_subtest "check saved query name"
976 test_expect_code 1 "notmuch config set squery.test '(subject utf8-sübjéct)'"
977
978 test_begin_subtest "roundtrip saved query (database)"
979 notmuch config set --database squery.Test '(subject utf8-sübjéct)'
980 output=$(notmuch config get squery.Test)
981 test_expect_equal "$output" '(subject utf8-sübjéct)'
982
983 test_begin_subtest "roundtrip saved query"
984 notmuch config set squery.Test '(subject override subject)'
985 output=$(notmuch config get squery.Test)
986 test_expect_equal "$output" '(subject override subject)'
987
988 test_begin_subtest "unknown saved query"
989 notmuch search --query=sexp '(Unknown foo bar)' >OUTPUT 2>&1
990 cat <<EOF > EXPECTED
991 notmuch search: Syntax error in query
992 unknown prefix 'Unknown'
993 EOF
994 test_expect_equal_file EXPECTED OUTPUT
995
996 test_begin_subtest "syntax error in saved query"
997 notmuch config set squery.Bad '(Bad'
998 notmuch search --query=sexp '(Bad foo bar)' >OUTPUT 2>&1
999 cat <<EOF > EXPECTED
1000 notmuch search: Syntax error in query
1001 invalid saved s-expression query: '(Bad'
1002 EOF
1003 test_expect_equal_file EXPECTED OUTPUT
1004
1005 test_begin_subtest "Saved Search by 'tag' and 'subject'"
1006 notmuch search tag:inbox and subject:maildir | notmuch_search_sanitize > EXPECTED
1007 notmuch config set squery.TagSubject  '(and (tag inbox) (subject maildir))'
1008 notmuch search --query=sexp '(TagSubject)' | notmuch_search_sanitize > OUTPUT
1009 test_expect_equal_file EXPECTED OUTPUT
1010
1011 test_begin_subtest "Saved Search: illegal nesting"
1012 notmuch config set squery.TagSubject  '(and (tag inbox) (subject maildir))'
1013 notmuch search --query=sexp '(subject (TagSubject))' >OUTPUT 2>&1
1014 cat <<EOF > EXPECTED
1015 notmuch search: Syntax error in query
1016 nested field: 'tag' inside 'subject'
1017 EOF
1018 test_expect_equal_file EXPECTED OUTPUT
1019
1020 test_begin_subtest "Saved Search: list as prefix"
1021 notmuch config set squery.Bad2  '((and) (tag inbox) (subject maildir))'
1022 notmuch search --query=sexp '(Bad2)' >OUTPUT 2>&1
1023 cat <<EOF > EXPECTED
1024 notmuch search: Syntax error in query
1025 unexpected list in field/operation position
1026 EOF
1027 test_expect_equal_file EXPECTED OUTPUT
1028
1029 test_begin_subtest "Saved Search: bad parameter syntax"
1030 notmuch config set squery.Bad3  '(macro a b)'
1031 notmuch search --query=sexp '(Bad3)' >OUTPUT 2>&1
1032 cat <<EOF > EXPECTED
1033 notmuch search: Syntax error in query
1034 missing (possibly empty) list of arguments to macro
1035 EOF
1036 test_expect_equal_file EXPECTED OUTPUT
1037
1038 test_begin_subtest "Saved Search: bad parameter syntax 2"
1039 notmuch config set squery.Bad4  '(macro ((a b)) a)'
1040 notmuch search --query=sexp '(Bad4 1)' >OUTPUT 2>&1
1041 cat <<EOF > EXPECTED
1042 notmuch search: Syntax error in query
1043 macro parameters must be unquoted atoms
1044 EOF
1045 test_expect_equal_file EXPECTED OUTPUT
1046
1047 test_begin_subtest "Saved Search: bad parameter syntax 3"
1048 notmuch config set squery.Bad5  '(macro (a b) a)'
1049 notmuch search --query=sexp '(Bad5 1)' >OUTPUT 2>&1
1050 cat <<EOF > EXPECTED
1051 notmuch search: Syntax error in query
1052 too few arguments to macro
1053 EOF
1054 test_expect_equal_file EXPECTED OUTPUT
1055
1056 test_begin_subtest "Saved Search: bad parameter syntax 4"
1057 notmuch search --query=sexp '(Bad5 1 2 3)' >OUTPUT 2>&1
1058 cat <<EOF > EXPECTED
1059 notmuch search: Syntax error in query
1060 too many arguments to macro
1061 EOF
1062 test_expect_equal_file EXPECTED OUTPUT
1063
1064 test_begin_subtest "Saved Search: macro without body"
1065 notmuch config set squery.Bad3  '(macro (a b))'
1066 notmuch search --query=sexp '(Bad3)' >OUTPUT 2>&1
1067 cat <<EOF > EXPECTED
1068 notmuch search: Syntax error in query
1069 missing body of macro
1070 EOF
1071 test_expect_equal_file EXPECTED OUTPUT
1072
1073 test_begin_subtest "macro in query"
1074 notmuch search --query=sexp '(macro (a) (and ,b (subject maildir)))' >OUTPUT 2>&1
1075 cat <<EOF > EXPECTED
1076 notmuch search: Syntax error in query
1077 macro definition not permitted here
1078 EOF
1079 test_expect_equal_file EXPECTED OUTPUT
1080
1081 test_begin_subtest "zero argument macro"
1082 notmuch search tag:inbox and subject:maildir | notmuch_search_sanitize > EXPECTED
1083 notmuch config set squery.TagSubject0  '(macro () (and (tag inbox) (subject maildir)))'
1084 notmuch search --query=sexp '(TagSubject0)' | notmuch_search_sanitize > OUTPUT
1085 test_expect_equal_file EXPECTED OUTPUT
1086
1087 test_begin_subtest "undefined argument"
1088 notmuch search tag:inbox and subject:maildir | notmuch_search_sanitize > EXPECTED
1089 notmuch config set squery.Bad6  '(macro (a) (and ,b (subject maildir)))'
1090 notmuch search --query=sexp '(Bad6 foo)' >OUTPUT 2>&1
1091 cat <<EOF > EXPECTED
1092 notmuch search: Syntax error in query
1093 undefined parameter b
1094 EOF
1095 test_expect_equal_file EXPECTED OUTPUT
1096
1097 test_begin_subtest "Single argument macro"
1098 notmuch search tag:inbox and subject:maildir | notmuch_search_sanitize > EXPECTED
1099 notmuch config set squery.TagSubject1  '(macro (tagname) (and (tag ,tagname) (subject maildir)))'
1100 notmuch search --query=sexp '(TagSubject1 inbox)' | notmuch_search_sanitize > OUTPUT
1101 test_expect_equal_file EXPECTED OUTPUT
1102
1103 test_begin_subtest "Single argument macro, list argument"
1104 notmuch search tag:inbox and subject:maildir | notmuch_search_sanitize > EXPECTED
1105 notmuch config set squery.ThingSubject  '(macro (thing) (and ,thing (subject maildir)))'
1106 notmuch search --query=sexp '(ThingSubject (tag inbox))' | notmuch_search_sanitize > OUTPUT
1107 test_expect_equal_file EXPECTED OUTPUT
1108
1109 test_begin_subtest "two argument macro"
1110 notmuch search tag:inbox and subject:maildir | notmuch_search_sanitize > EXPECTED
1111 notmuch config set squery.TagSubject2  '(macro (tagname subj) (and (tag ,tagname) (subject ,subj)))'
1112 notmuch search --query=sexp '(TagSubject2 inbox maildir)' | notmuch_search_sanitize > OUTPUT
1113 test_expect_equal_file EXPECTED OUTPUT
1114
1115 test_begin_subtest "nested macros (shadowing)"
1116 notmuch search tag:inbox and subject:maildir | notmuch_search_sanitize > EXPECTED
1117 notmuch config set squery.Inner '(macro (x) (subject ,x))'
1118 notmuch config set squery.Outer  '(macro (x y) (and (tag ,x) (Inner ,y)))'
1119 notmuch search --query=sexp '(Outer inbox maildir)' | notmuch_search_sanitize > OUTPUT
1120 test_expect_equal_file EXPECTED OUTPUT
1121
1122 test_begin_subtest "nested macros (no dynamic scope)"
1123 notmuch config set squery.Inner2 '(macro (x) (subject ,y))'
1124 notmuch config set squery.Outer2  '(macro (x y) (and (tag ,x) (Inner2 ,y)))'
1125 notmuch search --query=sexp '(Outer2 inbox maildir)' > OUTPUT 2>&1
1126 cat <<EOF > EXPECTED
1127 notmuch search: Syntax error in query
1128 undefined parameter y
1129 EOF
1130 test_expect_equal_file EXPECTED OUTPUT
1131
1132 test_begin_subtest "combine macro and user defined header"
1133 notmuch config set squery.About '(macro (name) (or (subject ,name) (List ,name)))'
1134 notmuch search subject:notmuch or List:notmuch | notmuch_search_sanitize > EXPECTED
1135 notmuch search --query=sexp '(About notmuch)' | notmuch_search_sanitize > OUTPUT
1136 test_expect_equal_file EXPECTED OUTPUT
1137
1138
1139 test_begin_subtest "combine macro and user defined header"
1140 notmuch config set squery.About '(macro (name) (or (subject ,name) (List ,name)))'
1141 notmuch search subject:notmuch or List:notmuch | notmuch_search_sanitize > EXPECTED
1142 notmuch search --query=sexp '(About notmuch)' | notmuch_search_sanitize > OUTPUT
1143 test_expect_equal_file EXPECTED OUTPUT
1144
1145
1146 test_done