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