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