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