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