omegatest: Use test_scriptindex more
[xapian.git] / xapian-applications / omega / omegatest
blobb6efa60c4660effe093f53a80125ab1d1d8d68a0
1 #!/bin/sh
2 # omegatest: Test omega CGI
4 # Copyright (C) 2015-2022 Olly Betts
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License as
8 # published by the Free Software Foundation; either version 2 of the
9 # License, or (at your option) any later version.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
19 # USA
20 set -e
22 : ${OMEGA=./omega}
23 : ${SCRIPTINDEX=./scriptindex}
24 : ${FAKETIME=faketime}
26 # Suppress HTTP Content-Type header.
27 SERVER_PROTOCOL=INCLUDED
28 export SERVER_PROTOCOL
30 # Don't complain about memory left allocated on exit - the OS will reclaim
31 # all memory at that point.
32 LSAN_OPTIONS=leak_check_at_exit=0
33 export LSAN_OPTIONS
35 # Set up an empty database.
36 TEST_DB=test-db
37 rm -rf "$TEST_DB"
38 echo 'inmemory' > "$TEST_DB"
40 # Simple template which just shows the parsed query.
41 TEST_TEMPLATE=test-template
42 printf '$querydescription' > "$TEST_TEMPLATE"
44 TEST_INDEXSCRIPT=test-indexscript
46 OMEGA_CONFIG_FILE=test-omega.conf
47 export OMEGA_CONFIG_FILE
48 cat > "$OMEGA_CONFIG_FILE" <<__END__
49 database_dir .
50 template_dir .
51 log_dir tmplog
52 default_template $TEST_TEMPLATE
53 default_db $TEST_DB
54 __END__
56 # Glob pattern matching scriptindex summary line.
57 SUMMARY_GLOB='records (added, replaced, deleted, skipped) = (*, *, *, *)'
59 failed=0
61 testcase() {
62 expected=$1
63 shift
64 # If there are no positional parameters, pass one as otherwise omega will
65 # wait for parameters on stdin.
66 [ "$#" != 0 ] || { set x dummy; shift; }
68 if [ -n "$FAKE_NOW" ] ; then
69 if [ -n "${TZ+set}" ] ; then
70 output=`TZ=$TZ $FAKETIME -f "$FAKE_NOW" "$OMEGA" "$@"`
71 else
72 output=`$FAKETIME -f "$FAKE_NOW" "$OMEGA" "$@"`
74 else
75 output=`"$OMEGA" "$@"`
78 if [ "$output" != "$expected" ] ; then
79 echo "$OMEGA $@:"
80 printf '%s\n' " expected: «${expected}»"
81 printf '%s\n' " received: «${output}»"
82 failed=`expr $failed + 1`
86 qtestcase() {
87 expected="Query($1)"
88 shift
89 testcase "$expected" "$@"
92 # Test scriptindex gives expected error.
94 # Parameters:
95 # * what: text to report to describe situation
96 # * expect: expected glob pattern stdout+stderr should match
97 # * (optional) input: input to feed scriptindex; can contain \n, etc escapes
98 # (default: /dev/null)
100 # Uses database $TEST_DB and index script $TEST_INDEXSCRIPT.
101 test_scriptindex_error() {
102 what=$1
103 expect=$2
104 input=$3
105 rm -rf "$TEST_DB"
106 rc=0
107 case $input in
109 out=`$SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" < /dev/null 2>&1` || rc=$?
111 *%*)
112 # Escape any % by doubling.
113 input=`printf '%s' "$input"|sed 's/%/%%/g'`
114 out=`printf "$input"|$SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" 2>&1` || rc=$?
117 out=`printf "$input"|$SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" 2>&1` || rc=$?
119 esac
120 if [ $rc -eq 0 ] ; then
121 printf "scriptindex didn't exit with non-zero return code for %s"'\n' "$what"
122 printf 'Output: %s\n' "$out"
123 failed=`expr $failed + 1`
124 else
125 case $out in
126 $expect) ;; # OK
128 printf "scriptindex didn't give expected error for %s"'\n' "$what"
129 printf 'Expect: %s\n' "$expect"
130 printf 'Output: %s\n' "$out"
131 failed=`expr $failed + 1`
133 esac
137 # Test scriptindex gives expected warning.
139 # Parameters:
140 # * what: text to report to describe situation
141 # * expect: expected glob pattern stdout+stderr should match
142 # * (optional) input: input to feed scriptindex; can contain \n, etc escapes
143 # (default: /dev/null)
145 # Uses database $TEST_DB and index script $TEST_INDEXSCRIPT.
146 test_scriptindex_warning() {
147 what=$1
148 expect="$2
149 $SUMMARY_GLOB"
150 input=$3
151 rm -rf "$TEST_DB"
152 rc=0
153 case $input in
155 out=`$SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" < /dev/null 2>&1` || rc=$?
157 *%*)
158 # Escape any % by doubling.
159 input=`printf '%s' "$input"|sed 's/%/%%/g'`
160 out=`printf "$input"|$SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" 2>&1` || rc=$?
163 out=`printf "$input"|$SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" 2>&1` || rc=$?
165 esac
166 if [ $rc -ne 0 ] ; then
167 printf "scriptindex gave an error rather than the expected warning for %s"'\n' "$what"
168 printf 'Output: %s\n' "$out"
169 failed=`expr $failed + 1`
170 else
171 case $out in
172 $expect) ;; # OK
174 printf "scriptindex didn't give expected warning for %s"'\n' "$what"
175 printf 'Expect: %s\n' "$expect"
176 printf 'Output: %s\n' "$out"
177 failed=`expr $failed + 1`
179 esac
183 # Test scriptindex runs cleanly
185 # Parameters:
186 # * what: text to report to describe situation
187 # * (optional) input: input to feed scriptindex; can contain \n, etc escapes
188 # (default: /dev/null)
190 # Uses database $TEST_DB and index script $TEST_INDEXSCRIPT.
191 test_scriptindex() {
192 what=$1
193 input=$2
194 rm -rf "$TEST_DB"
195 rc=0
196 case $input in
198 out=`$SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" < /dev/null 2>&1` || rc=$?
200 *%*)
201 # Escape any % by doubling.
202 input=`printf '%s' "$input"|sed 's/%/%%/g'`
203 out=`printf "$input"|$SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" 2>&1` || rc=$?
206 out=`printf "$input"|$SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" 2>&1` || rc=$?
208 esac
209 if [ $rc -ne 0 ] ; then
210 printf 'scriptindex gave an error for %s\n' "$what"
211 printf 'Output: %s\n' "$out"
212 failed=`expr $failed + 1`
213 else
214 case $out in
215 $SUMMARY_GLOB) ;; # OK
217 printf 'scriptindex gave unexpected output for %s\n' "$what"
218 printf 'Output: %s\n' "$out"
219 failed=`expr $failed + 1`
221 esac
225 unset FAKE_NOW
227 # Test a few simple things.
228 qtestcase 'Zsimpl@1' P=simple
229 qtestcase '(chocolate@1 FILTER Tconfectionary/fudge)' P=Chocolate B=Tconfectionary/fudge
231 # Test date value ranges.
232 qtestcase 'VALUE_RANGE 0 2 ~' DATEVALUE=0 START=2000
233 qtestcase 'VALUE_RANGE 0 2 ~' DATEVALUE=0 START=200001
234 qtestcase 'VALUE_RANGE 0 2 ~' DATEVALUE=0 START=20000101
235 qtestcase 'VALUE_LE 1 1~' DATEVALUE=1 END=1999
236 qtestcase 'VALUE_LE 1 1~' DATEVALUE=1 END=199912
237 qtestcase 'VALUE_LE 1 1~' DATEVALUE=1 END=19991231
238 qtestcase 'VALUE_RANGE 2 201 ~' DATEVALUE=2 START=2010
239 qtestcase 'VALUE_RANGE 2 201 ~' DATEVALUE=2 START=201001
240 qtestcase 'VALUE_RANGE 2 201 ~' DATEVALUE=2 START=20100101
241 qtestcase 'VALUE_LE 3 198~' DATEVALUE=3 END=1989
242 qtestcase 'VALUE_LE 3 198~' DATEVALUE=3 END=198912
243 qtestcase 'VALUE_LE 3 198~' DATEVALUE=3 END=19891231
244 qtestcase 'VALUE_RANGE 4 1974 ~' DATEVALUE=4 START=1974
245 qtestcase 'VALUE_RANGE 4 1974 ~' DATEVALUE=4 START=197401
246 qtestcase 'VALUE_RANGE 4 1974 ~' DATEVALUE=4 START=19740101
247 qtestcase 'VALUE_LE 5 1974~' DATEVALUE=5 END=1974
248 qtestcase 'VALUE_LE 5 1974~' DATEVALUE=5 END=197412
249 qtestcase 'VALUE_LE 5 1974~' DATEVALUE=5 END=19741231
250 qtestcase 'VALUE_RANGE 6 20151 ~' DATEVALUE=6 START=201510
251 qtestcase 'VALUE_RANGE 6 20151 ~' DATEVALUE=6 START=20151001
252 qtestcase 'VALUE_LE 7 19870~' DATEVALUE=7 END=198709
253 qtestcase 'VALUE_LE 7 19870~' DATEVALUE=7 END=19870930
254 qtestcase 'VALUE_RANGE 8 201512 ~' DATEVALUE=8 START=201512
255 qtestcase 'VALUE_RANGE 8 201512 ~' DATEVALUE=8 START=20151201
256 qtestcase 'VALUE_LE 9 201511~' DATEVALUE=9 END=201511
257 qtestcase 'VALUE_LE 9 201511~' DATEVALUE=9 END=20151130
258 qtestcase 'VALUE_RANGE 10 2015021 ~' DATEVALUE=10 START=20150210
259 qtestcase 'VALUE_RANGE 10 2000022 ~' DATEVALUE=10 START=20000220
260 qtestcase 'VALUE_LE 11 19840401~' DATEVALUE=11 END=19840401
261 qtestcase 'VALUE_LE 11 19881128~' DATEVALUE=11 END=19881128
263 # Leap year tests:
264 qtestcase 'VALUE_LE 1 201502~' DATEVALUE=1 END=20150228
265 qtestcase 'VALUE_LE 1 198802~' DATEVALUE=1 END=19880229
266 qtestcase 'VALUE_LE 1 19880228~' DATEVALUE=1 END=19880228
267 qtestcase 'VALUE_LE 1 200002~' DATEVALUE=1 END=20000229
268 qtestcase 'VALUE_LE 1 20000228~' DATEVALUE=1 END=20000228
269 # FIXME: These two currently require 64-bit time_t:
270 #qtestcase 'VALUE_LE 1 190002~' DATEVALUE=1 END=19000228
271 #qtestcase 'VALUE_LE 1 210002~' DATEVALUE=1 END=21000228
273 # Month starts and ends:
274 qtestcase 'VALUE_RANGE 0 2015 201501~' DATEVALUE=0 START=20150101 END=20150131
275 qtestcase 'VALUE_RANGE 0 2015 20150130~' DATEVALUE=0 START=20150101 END=20150130
276 qtestcase 'VALUE_RANGE 0 201502 201502~' DATEVALUE=0 START=20150201 END=20150228
277 qtestcase 'VALUE_RANGE 0 201502 20150227~' DATEVALUE=0 START=20150201 END=20150227
278 qtestcase 'VALUE_RANGE 0 201503 201503~' DATEVALUE=0 START=20150301 END=20150331
279 qtestcase 'VALUE_RANGE 0 201503 20150330~' DATEVALUE=0 START=20150301 END=20150330
280 qtestcase 'VALUE_RANGE 0 201504 201504~' DATEVALUE=0 START=20150401 END=20150430
281 qtestcase 'VALUE_RANGE 0 201504 2015042~' DATEVALUE=0 START=20150401 END=20150429
282 qtestcase 'VALUE_RANGE 0 201505 201505~' DATEVALUE=0 START=20150501 END=20150531
283 qtestcase 'VALUE_RANGE 0 201505 20150530~' DATEVALUE=0 START=20150501 END=20150530
284 qtestcase 'VALUE_RANGE 0 201506 201506~' DATEVALUE=0 START=20150601 END=20150630
285 qtestcase 'VALUE_RANGE 0 201506 2015062~' DATEVALUE=0 START=20150601 END=20150629
286 qtestcase 'VALUE_RANGE 0 201507 201507~' DATEVALUE=0 START=20150701 END=20150731
287 qtestcase 'VALUE_RANGE 0 201507 20150730~' DATEVALUE=0 START=20150701 END=20150730
288 qtestcase 'VALUE_RANGE 0 201508 201508~' DATEVALUE=0 START=20150801 END=20150831
289 qtestcase 'VALUE_RANGE 0 201508 20150830~' DATEVALUE=0 START=20150801 END=20150830
290 qtestcase 'VALUE_RANGE 0 201509 20150~' DATEVALUE=0 START=20150901 END=20150930
291 qtestcase 'VALUE_RANGE 0 201509 2015092~' DATEVALUE=0 START=20150901 END=20150929
292 qtestcase 'VALUE_RANGE 0 20151 201510~' DATEVALUE=0 START=20151001 END=20151031
293 qtestcase 'VALUE_RANGE 0 20151 20151030~' DATEVALUE=0 START=20151001 END=20151030
294 qtestcase 'VALUE_RANGE 0 201511 201511~' DATEVALUE=0 START=20151101 END=20151130
295 qtestcase 'VALUE_RANGE 0 201511 2015112~' DATEVALUE=0 START=20151101 END=20151129
296 qtestcase 'VALUE_RANGE 0 201512 2015~' DATEVALUE=0 START=20151201 END=20151231
297 qtestcase 'VALUE_RANGE 0 201512 20151230~' DATEVALUE=0 START=20151201 END=20151230
299 # Forward spans:
300 qtestcase 'VALUE_RANGE 0 20151104 20151106~' DATEVALUE=0 START=20151104 SPAN=3
301 qtestcase 'VALUE_RANGE 0 20141104 20151103~' DATEVALUE=0 START=20141104 SPAN=365
303 # Backward spans:
304 qtestcase 'VALUE_RANGE 0 20151104 20151106~' DATEVALUE=0 END=20151106 SPAN=3
305 qtestcase 'VALUE_RANGE 0 20141104 20151103~' DATEVALUE=0 END=20151103 SPAN=365
307 # Check that if START, END and SPAN are all passed, START is ignored:
308 qtestcase 'VALUE_RANGE 0 20151104 20151106~' DATEVALUE=0 START=19700101 END=20151106 SPAN=3
310 # Test date value ranges using newer ".SLOT" parameters.
311 qtestcase 'VALUE_RANGE 0 2 ~' START.0=2000
312 qtestcase 'VALUE_RANGE 0 2 ~' START.0=200001
313 qtestcase 'VALUE_RANGE 0 2 ~' START.0=20000101
314 qtestcase 'VALUE_LE 1 1~' END.1=1999
315 qtestcase 'VALUE_LE 1 1~' END.1=199912
316 qtestcase 'VALUE_LE 1 1~' END.1=19991231
317 qtestcase 'VALUE_RANGE 2 201 ~' START.2=2010
318 qtestcase 'VALUE_RANGE 2 201 ~' START.2=201001
319 qtestcase 'VALUE_RANGE 2 201 ~' START.2=20100101
320 qtestcase 'VALUE_LE 3 198~' END.3=1989
321 qtestcase 'VALUE_LE 3 198~' END.3=198912
322 qtestcase 'VALUE_LE 3 198~' END.3=19891231
323 qtestcase 'VALUE_RANGE 4 1974 ~' START.4=1974
324 qtestcase 'VALUE_RANGE 4 1974 ~' START.4=197401
325 qtestcase 'VALUE_RANGE 4 1974 ~' START.4=19740101
326 qtestcase 'VALUE_LE 5 1974~' END.5=1974
327 qtestcase 'VALUE_LE 5 1974~' END.5=197412
328 qtestcase 'VALUE_LE 5 1974~' END.5=19741231
329 qtestcase 'VALUE_RANGE 6 20151 ~' START.6=201510
330 qtestcase 'VALUE_RANGE 6 20151 ~' START.6=20151001
331 qtestcase 'VALUE_LE 7 19870~' END.7=198709
332 qtestcase 'VALUE_LE 7 19870~' END.7=19870930
333 qtestcase 'VALUE_RANGE 8 201512 ~' START.8=201512
334 qtestcase 'VALUE_RANGE 8 201512 ~' START.8=20151201
335 qtestcase 'VALUE_LE 9 201511~' END.9=201511
336 qtestcase 'VALUE_LE 9 201511~' END.9=20151130
337 qtestcase 'VALUE_RANGE 10 2015021 ~' START.10=20150210
338 qtestcase 'VALUE_RANGE 10 2000022 ~' START.10=20000220
339 qtestcase 'VALUE_LE 11 19840401~' END.11=19840401
340 qtestcase 'VALUE_LE 11 19881128~' END.11=19881128
342 # Leap year tests:
343 qtestcase 'VALUE_LE 1 201502~' END.1=20150228
344 qtestcase 'VALUE_LE 1 198802~' END.1=19880229
345 qtestcase 'VALUE_LE 1 19880228~' END.1=19880228
346 qtestcase 'VALUE_LE 1 200002~' END.1=20000229
347 qtestcase 'VALUE_LE 1 20000228~' END.1=20000228
348 # FIXME: These two currently require 64-bit time_t:
349 #qtestcase 'VALUE_LE 1 190002~' END.1=19000228
350 #qtestcase 'VALUE_LE 1 210002~' END.1=21000228
352 # Month starts and ends:
353 qtestcase 'VALUE_RANGE 0 2015 201501~' START.0=20150101 END.0=20150131
354 qtestcase 'VALUE_RANGE 0 2015 20150130~' START.0=20150101 END.0=20150130
355 qtestcase 'VALUE_RANGE 0 201502 201502~' START.0=20150201 END.0=20150228
356 qtestcase 'VALUE_RANGE 0 201502 20150227~' START.0=20150201 END.0=20150227
357 qtestcase 'VALUE_RANGE 0 201503 201503~' START.0=20150301 END.0=20150331
358 qtestcase 'VALUE_RANGE 0 201503 20150330~' START.0=20150301 END.0=20150330
359 qtestcase 'VALUE_RANGE 0 201504 201504~' START.0=20150401 END.0=20150430
360 qtestcase 'VALUE_RANGE 0 201504 2015042~' START.0=20150401 END.0=20150429
361 qtestcase 'VALUE_RANGE 0 201505 201505~' START.0=20150501 END.0=20150531
362 qtestcase 'VALUE_RANGE 0 201505 20150530~' START.0=20150501 END.0=20150530
363 qtestcase 'VALUE_RANGE 0 201506 201506~' START.0=20150601 END.0=20150630
364 qtestcase 'VALUE_RANGE 0 201506 2015062~' START.0=20150601 END.0=20150629
365 qtestcase 'VALUE_RANGE 0 201507 201507~' START.0=20150701 END.0=20150731
366 qtestcase 'VALUE_RANGE 0 201507 20150730~' START.0=20150701 END.0=20150730
367 qtestcase 'VALUE_RANGE 0 201508 201508~' START.0=20150801 END.0=20150831
368 qtestcase 'VALUE_RANGE 0 201508 20150830~' START.0=20150801 END.0=20150830
369 qtestcase 'VALUE_RANGE 0 201509 20150~' START.0=20150901 END.0=20150930
370 qtestcase 'VALUE_RANGE 0 201509 2015092~' START.0=20150901 END.0=20150929
371 qtestcase 'VALUE_RANGE 0 20151 201510~' START.0=20151001 END.0=20151031
372 qtestcase 'VALUE_RANGE 0 20151 20151030~' START.0=20151001 END.0=20151030
373 qtestcase 'VALUE_RANGE 0 201511 201511~' START.0=20151101 END.0=20151130
374 qtestcase 'VALUE_RANGE 0 201511 2015112~' START.0=20151101 END.0=20151129
375 qtestcase 'VALUE_RANGE 0 201512 2015~' START.0=20151201 END.0=20151231
376 qtestcase 'VALUE_RANGE 0 201512 20151230~' START.0=20151201 END.0=20151230
378 # Forward spans:
379 qtestcase 'VALUE_RANGE 0 20151104 20151106~' START.0=20151104 SPAN.0=3
380 qtestcase 'VALUE_RANGE 0 20141104 20151103~' START.0=20141104 SPAN.0=365
382 # Backward spans:
383 qtestcase 'VALUE_RANGE 0 20151104 20151106~' END.0=20151106 SPAN.0=3
384 qtestcase 'VALUE_RANGE 0 20141104 20151103~' END.0=20151103 SPAN.0=365
386 # Empty spans:
387 qtestcase '' START.0=20180919 END.0=19991225
388 # Check that the empty span dominates other spans:
389 qtestcase '' START.0=20180919 END.0=19991225 START.1=20180901
390 # Check that the empty span dominates a filter term:
391 qtestcase '' START.0=20180919 END.0=19991225 B=Ktag
392 # Check that the empty span dominates a negated filter term:
393 qtestcase '' START.0=20180919 END.0=19991225 N=Kneg
394 # Check that the empty span dominates a term-based date range filter:
395 qtestcase '' START.0=20180919 END.0=19991225 START=20000101 END=20001231
397 # Check that if START, END and SPAN are all passed, START is ignored:
398 qtestcase 'VALUE_RANGE 0 20151104 20151106~' START.0=19700101 END.0=20151106 SPAN.0=3
400 # Check multiple .SLOT filters:
401 qtestcase '(VALUE_RANGE 0 201512 2015~ AND VALUE_LE 5 1974~)' START.0=20151201 END.0=20151231 END.5=1974
402 qtestcase '(VALUE_RANGE 0 201512 20151207~ AND VALUE_RANGE 5 19740102 1974~)' START.0=20151201 SPAN.0=7 END.5=1974 SPAN.5=364
404 # Check .SLOT and old-style value date range filter:
405 qtestcase '(VALUE_RANGE 0 201512 2015~ AND VALUE_LE 5 1974~)' START.0=20151201 END.0=20151231 DATEVALUE=5 END=1974
407 # Check .SLOT and old-style value date range filter on same slot.
408 # (We don't promise anything for this case, but it shouldn't crash).
409 qtestcase '(VALUE_RANGE 0 201512 2015~ AND VALUE_LE 0 1974~)' START.0=20151201 END.0=20151231 DATEVALUE=0 END=1974
411 # Tests of term-based date range filtering:
413 qtestcase '(Y1970 OR Y1971 OR Y1972 OR Y1973 OR Y1974 OR Y1975 OR Y1976 OR Y1977 OR Y1978 OR Y1979 OR Y1980 OR Y1981 OR Y1982 OR Y1983 OR Y1984 OR Y1985 OR Y1986 OR Y1987 OR Y1988 OR Y1989 OR Y1990 OR Y1991 OR Y1992 OR Y1993 OR Y1994 OR Y1995 OR Y1996 OR Y1997 OR Y1998 OR Y1999 OR Dlatest)' END=19991231
414 qtestcase '(Y1970 OR Y1971 OR Y1972 OR Y1973 OR Y1974 OR Y1975 OR Y1976 OR Y1977 OR Y1978 OR Y1979 OR Y1980 OR Y1981 OR Y1982 OR Y1983 OR Y1984 OR Y1985 OR Y1986 OR Y1987 OR Y1988 OR Y1989 OR Dlatest)' END=19891231
415 qtestcase '(Y1970 OR Y1971 OR Y1972 OR Y1973 OR Y1974 OR Dlatest)' END=19741231
416 qtestcase '(Y1970 OR Y1971 OR Y1972 OR Y1973 OR Y1974 OR Y1975 OR Y1976 OR Y1977 OR Y1978 OR Y1979 OR Y1980 OR Y1981 OR Y1982 OR Y1983 OR Y1984 OR Y1985 OR Y1986 OR M198701 OR M198702 OR M198703 OR M198704 OR M198705 OR M198706 OR M198707 OR M198708 OR M198709 OR Dlatest)' END=19870930
417 qtestcase '(Y1970 OR Y1971 OR Y1972 OR Y1973 OR Y1974 OR Y1975 OR Y1976 OR Y1977 OR Y1978 OR Y1979 OR Y1980 OR Y1981 OR Y1982 OR Y1983 OR Y1984 OR Y1985 OR Y1986 OR Y1987 OR Y1988 OR Y1989 OR Y1990 OR Y1991 OR Y1992 OR Y1993 OR Y1994 OR Y1995 OR Y1996 OR Y1997 OR Y1998 OR Y1999 OR Y2000 OR Y2001 OR Y2002 OR Y2003 OR Y2004 OR Y2005 OR Y2006 OR Y2007 OR Y2008 OR Y2009 OR Y2010 OR Y2011 OR Y2012 OR Y2013 OR Y2014 OR M201501 OR M201502 OR M201503 OR M201504 OR M201505 OR M201506 OR M201507 OR M201508 OR M201509 OR M201510 OR M201511 OR Dlatest)' END=20151130
418 qtestcase '(Y1970 OR Y1971 OR Y1972 OR Y1973 OR Y1974 OR Y1975 OR Y1976 OR Y1977 OR Y1978 OR Y1979 OR Y1980 OR Y1981 OR Y1982 OR Y1983 OR M198401 OR M198402 OR M198403 OR D19840401 OR Dlatest)' END=19840401
419 qtestcase '(Y1970 OR Y1971 OR Y1972 OR Y1973 OR Y1974 OR Y1975 OR Y1976 OR Y1977 OR Y1978 OR Y1979 OR Y1980 OR Y1981 OR Y1982 OR Y1983 OR Y1984 OR Y1985 OR Y1986 OR Y1987 OR M198801 OR M198802 OR M198803 OR M198804 OR M198805 OR M198806 OR M198807 OR M198808 OR M198809 OR M198810 OR D19881101 OR D19881102 OR D19881103 OR D19881104 OR D19881105 OR D19881106 OR D19881107 OR D19881108 OR D19881109 OR D19881110 OR D19881111 OR D19881112 OR D19881113 OR D19881114 OR D19881115 OR D19881116 OR D19881117 OR D19881118 OR D19881119 OR D19881120 OR D19881121 OR D19881122 OR D19881123 OR D19881124 OR D19881125 OR D19881126 OR D19881127 OR D19881128 OR Dlatest)' END=19881128
421 # Leap year tests:
422 qtestcase '(Y1970 OR Y1971 OR Y1972 OR Y1973 OR Y1974 OR Y1975 OR Y1976 OR Y1977 OR Y1978 OR Y1979 OR Y1980 OR Y1981 OR Y1982 OR Y1983 OR Y1984 OR Y1985 OR Y1986 OR Y1987 OR Y1988 OR Y1989 OR Y1990 OR Y1991 OR Y1992 OR Y1993 OR Y1994 OR Y1995 OR Y1996 OR Y1997 OR Y1998 OR Y1999 OR Y2000 OR Y2001 OR Y2002 OR Y2003 OR Y2004 OR Y2005 OR Y2006 OR Y2007 OR Y2008 OR Y2009 OR Y2010 OR Y2011 OR Y2012 OR Y2013 OR Y2014 OR M201501 OR M201502 OR Dlatest)' END=20150228
423 qtestcase '(Y1970 OR Y1971 OR Y1972 OR Y1973 OR Y1974 OR Y1975 OR Y1976 OR Y1977 OR Y1978 OR Y1979 OR Y1980 OR Y1981 OR Y1982 OR Y1983 OR Y1984 OR Y1985 OR Y1986 OR Y1987 OR M198801 OR M198802 OR Dlatest)' END=19880229
424 qtestcase '(Y1970 OR Y1971 OR Y1972 OR Y1973 OR Y1974 OR Y1975 OR Y1976 OR Y1977 OR Y1978 OR Y1979 OR Y1980 OR Y1981 OR Y1982 OR Y1983 OR Y1984 OR Y1985 OR Y1986 OR Y1987 OR M198801 OR D19880201 OR D19880202 OR D19880203 OR D19880204 OR D19880205 OR D19880206 OR D19880207 OR D19880208 OR D19880209 OR D19880210 OR D19880211 OR D19880212 OR D19880213 OR D19880214 OR D19880215 OR D19880216 OR D19880217 OR D19880218 OR D19880219 OR D19880220 OR D19880221 OR D19880222 OR D19880223 OR D19880224 OR D19880225 OR D19880226 OR D19880227 OR D19880228 OR Dlatest)' END=19880228
425 qtestcase '(Y1970 OR Y1971 OR Y1972 OR Y1973 OR Y1974 OR Y1975 OR Y1976 OR Y1977 OR Y1978 OR Y1979 OR Y1980 OR Y1981 OR Y1982 OR Y1983 OR Y1984 OR Y1985 OR Y1986 OR Y1987 OR Y1988 OR Y1989 OR Y1990 OR Y1991 OR Y1992 OR Y1993 OR Y1994 OR Y1995 OR Y1996 OR Y1997 OR Y1998 OR Y1999 OR M200001 OR M200002 OR Dlatest)' END=20000229
426 qtestcase '(Y1970 OR Y1971 OR Y1972 OR Y1973 OR Y1974 OR Y1975 OR Y1976 OR Y1977 OR Y1978 OR Y1979 OR Y1980 OR Y1981 OR Y1982 OR Y1983 OR Y1984 OR Y1985 OR Y1986 OR Y1987 OR Y1988 OR Y1989 OR Y1990 OR Y1991 OR Y1992 OR Y1993 OR Y1994 OR Y1995 OR Y1996 OR Y1997 OR Y1998 OR Y1999 OR M200001 OR D20000201 OR D20000202 OR D20000203 OR D20000204 OR D20000205 OR D20000206 OR D20000207 OR D20000208 OR D20000209 OR D20000210 OR D20000211 OR D20000212 OR D20000213 OR D20000214 OR D20000215 OR D20000216 OR D20000217 OR D20000218 OR D20000219 OR D20000220 OR D20000221 OR D20000222 OR D20000223 OR D20000224 OR D20000225 OR D20000226 OR D20000227 OR D20000228 OR Dlatest)' END=20000228
427 # FIXME: These two currently require 64-bit time_t:
428 #qtestcase 'Dlatest' END=19000228 # Assumed start is 19700101
429 #qtestcase '(Y1970 OR Y1971 OR Y1972 OR Y1973 OR Y1974 OR Y1975 OR Y1976 OR Y1977 OR Y1978 OR Y1979 OR Y1980 OR Y1981 OR Y1982 OR Y1983 OR Y1984 OR Y1985 OR Y1986 OR Y1987 OR Y1988 OR Y1989 OR Y1990 OR Y1991 OR Y1992 OR Y1993 OR Y1994 OR Y1995 OR Y1996 OR Y1997 OR Y1998 OR Y1999 OR Y2000 OR Y2001 OR Y2002 OR Y2003 OR Y2004 OR Y2005 OR Y2006 OR Y2007 OR Y2008 OR Y2009 OR Y2010 OR Y2011 OR Y2012 OR Y2013 OR Y2014 OR Y2015 OR Y2016 OR Y2017 OR Y2018 OR Y2019 OR Y2020 OR Y2021 OR Y2022 OR Y2023 OR Y2024 OR Y2025 OR Y2026 OR Y2027 OR Y2028 OR Y2029 OR Y2030 OR Y2031 OR Y2032 OR Y2033 OR Y2034 OR Y2035 OR Y2036 OR Y2037 OR Y2038 OR Y2039 OR Y2040 OR Y2041 OR Y2042 OR Y2043 OR Y2044 OR Y2045 OR Y2046 OR Y2047 OR Y2048 OR Y2049 OR Y2050 OR Y2051 OR Y2052 OR Y2053 OR Y2054 OR Y2055 OR Y2056 OR Y2057 OR Y2058 OR Y2059 OR Y2060 OR Y2061 OR Y2062 OR Y2063 OR Y2064 OR Y2065 OR Y2066 OR Y2067 OR Y2068 OR Y2069 OR Y2070 OR Y2071 OR Y2072 OR Y2073 OR Y2074 OR Y2075 OR Y2076 OR Y2077 OR Y2078 OR Y2079 OR Y2080 OR Y2081 OR Y2082 OR Y2083 OR Y2084 OR Y2085 OR Y2086 OR Y2087 OR Y2088 OR Y2089 OR Y2090 OR Y2091 OR Y2092 OR Y2093 OR Y2094 OR Y2095 OR Y2096 OR Y2097 OR Y2098 OR Y2099 OR M210001 OR M210002 OR Dlatest)' END=21000228
431 # Month starts and ends:
432 qtestcase '(M201501 OR Dlatest)' START=20150101 END=20150131
433 qtestcase '(D20150101 OR D20150102 OR D20150103 OR D20150104 OR D20150105 OR D20150106 OR D20150107 OR D20150108 OR D20150109 OR D20150110 OR D20150111 OR D20150112 OR D20150113 OR D20150114 OR D20150115 OR D20150116 OR D20150117 OR D20150118 OR D20150119 OR D20150120 OR D20150121 OR D20150122 OR D20150123 OR D20150124 OR D20150125 OR D20150126 OR D20150127 OR D20150128 OR D20150129 OR D20150130 OR Dlatest)' START=20150101 END=20150130
434 qtestcase '(M201502 OR Dlatest)' START=20150201 END=20150228
435 qtestcase '(D20150201 OR D20150202 OR D20150203 OR D20150204 OR D20150205 OR D20150206 OR D20150207 OR D20150208 OR D20150209 OR D20150210 OR D20150211 OR D20150212 OR D20150213 OR D20150214 OR D20150215 OR D20150216 OR D20150217 OR D20150218 OR D20150219 OR D20150220 OR D20150221 OR D20150222 OR D20150223 OR D20150224 OR D20150225 OR D20150226 OR D20150227 OR Dlatest)' START=20150201 END=20150227
436 qtestcase '(M201503 OR Dlatest)' START=20150301 END=20150331
437 qtestcase '(D20150301 OR D20150302 OR D20150303 OR D20150304 OR D20150305 OR D20150306 OR D20150307 OR D20150308 OR D20150309 OR D20150310 OR D20150311 OR D20150312 OR D20150313 OR D20150314 OR D20150315 OR D20150316 OR D20150317 OR D20150318 OR D20150319 OR D20150320 OR D20150321 OR D20150322 OR D20150323 OR D20150324 OR D20150325 OR D20150326 OR D20150327 OR D20150328 OR D20150329 OR D20150330 OR Dlatest)' START=20150301 END=20150330
438 qtestcase '(M201504 OR Dlatest)' START=20150401 END=20150430
439 qtestcase '(D20150401 OR D20150402 OR D20150403 OR D20150404 OR D20150405 OR D20150406 OR D20150407 OR D20150408 OR D20150409 OR D20150410 OR D20150411 OR D20150412 OR D20150413 OR D20150414 OR D20150415 OR D20150416 OR D20150417 OR D20150418 OR D20150419 OR D20150420 OR D20150421 OR D20150422 OR D20150423 OR D20150424 OR D20150425 OR D20150426 OR D20150427 OR D20150428 OR D20150429 OR Dlatest)' START=20150401 END=20150429
440 qtestcase '(M201505 OR Dlatest)' START=20150501 END=20150531
441 qtestcase '(D20150501 OR D20150502 OR D20150503 OR D20150504 OR D20150505 OR D20150506 OR D20150507 OR D20150508 OR D20150509 OR D20150510 OR D20150511 OR D20150512 OR D20150513 OR D20150514 OR D20150515 OR D20150516 OR D20150517 OR D20150518 OR D20150519 OR D20150520 OR D20150521 OR D20150522 OR D20150523 OR D20150524 OR D20150525 OR D20150526 OR D20150527 OR D20150528 OR D20150529 OR D20150530 OR Dlatest)' START=20150501 END=20150530
442 qtestcase '(M201506 OR Dlatest)' START=20150601 END=20150630
443 qtestcase '(D20150601 OR D20150602 OR D20150603 OR D20150604 OR D20150605 OR D20150606 OR D20150607 OR D20150608 OR D20150609 OR D20150610 OR D20150611 OR D20150612 OR D20150613 OR D20150614 OR D20150615 OR D20150616 OR D20150617 OR D20150618 OR D20150619 OR D20150620 OR D20150621 OR D20150622 OR D20150623 OR D20150624 OR D20150625 OR D20150626 OR D20150627 OR D20150628 OR D20150629 OR Dlatest)' START=20150601 END=20150629
444 qtestcase '(M201507 OR Dlatest)' START=20150701 END=20150731
445 qtestcase '(D20150701 OR D20150702 OR D20150703 OR D20150704 OR D20150705 OR D20150706 OR D20150707 OR D20150708 OR D20150709 OR D20150710 OR D20150711 OR D20150712 OR D20150713 OR D20150714 OR D20150715 OR D20150716 OR D20150717 OR D20150718 OR D20150719 OR D20150720 OR D20150721 OR D20150722 OR D20150723 OR D20150724 OR D20150725 OR D20150726 OR D20150727 OR D20150728 OR D20150729 OR D20150730 OR Dlatest)' START=20150701 END=20150730
446 qtestcase '(M201508 OR Dlatest)' START=20150801 END=20150831
447 qtestcase '(D20150801 OR D20150802 OR D20150803 OR D20150804 OR D20150805 OR D20150806 OR D20150807 OR D20150808 OR D20150809 OR D20150810 OR D20150811 OR D20150812 OR D20150813 OR D20150814 OR D20150815 OR D20150816 OR D20150817 OR D20150818 OR D20150819 OR D20150820 OR D20150821 OR D20150822 OR D20150823 OR D20150824 OR D20150825 OR D20150826 OR D20150827 OR D20150828 OR D20150829 OR D20150830 OR Dlatest)' START=20150801 END=20150830
448 qtestcase '(M201509 OR Dlatest)' START=20150901 END=20150930
449 qtestcase '(D20150901 OR D20150902 OR D20150903 OR D20150904 OR D20150905 OR D20150906 OR D20150907 OR D20150908 OR D20150909 OR D20150910 OR D20150911 OR D20150912 OR D20150913 OR D20150914 OR D20150915 OR D20150916 OR D20150917 OR D20150918 OR D20150919 OR D20150920 OR D20150921 OR D20150922 OR D20150923 OR D20150924 OR D20150925 OR D20150926 OR D20150927 OR D20150928 OR D20150929 OR Dlatest)' START=20150901 END=20150929
450 qtestcase '(M201510 OR Dlatest)' START=20151001 END=20151031
451 qtestcase '(D20151001 OR D20151002 OR D20151003 OR D20151004 OR D20151005 OR D20151006 OR D20151007 OR D20151008 OR D20151009 OR D20151010 OR D20151011 OR D20151012 OR D20151013 OR D20151014 OR D20151015 OR D20151016 OR D20151017 OR D20151018 OR D20151019 OR D20151020 OR D20151021 OR D20151022 OR D20151023 OR D20151024 OR D20151025 OR D20151026 OR D20151027 OR D20151028 OR D20151029 OR D20151030 OR Dlatest)' START=20151001 END=20151030
452 qtestcase '(M201511 OR Dlatest)' START=20151101 END=20151130
453 qtestcase '(D20151101 OR D20151102 OR D20151103 OR D20151104 OR D20151105 OR D20151106 OR D20151107 OR D20151108 OR D20151109 OR D20151110 OR D20151111 OR D20151112 OR D20151113 OR D20151114 OR D20151115 OR D20151116 OR D20151117 OR D20151118 OR D20151119 OR D20151120 OR D20151121 OR D20151122 OR D20151123 OR D20151124 OR D20151125 OR D20151126 OR D20151127 OR D20151128 OR D20151129 OR Dlatest)' START=20151101 END=20151129
454 qtestcase '(M201512 OR Dlatest)' START=20151201 END=20151231
455 qtestcase '(D20151201 OR D20151202 OR D20151203 OR D20151204 OR D20151205 OR D20151206 OR D20151207 OR D20151208 OR D20151209 OR D20151210 OR D20151211 OR D20151212 OR D20151213 OR D20151214 OR D20151215 OR D20151216 OR D20151217 OR D20151218 OR D20151219 OR D20151220 OR D20151221 OR D20151222 OR D20151223 OR D20151224 OR D20151225 OR D20151226 OR D20151227 OR D20151228 OR D20151229 OR D20151230 OR Dlatest)' START=20151201 END=20151230
457 # Forward spans:
458 qtestcase '(D20151104 OR D20151105 OR D20151106 OR D20151107 OR Dlatest)' START=20151104 SPAN=3
459 qtestcase '(D20141104 OR D20141105 OR D20141106 OR D20141107 OR D20141108 OR D20141109 OR D20141110 OR D20141111 OR D20141112 OR D20141113 OR D20141114 OR D20141115 OR D20141116 OR D20141117 OR D20141118 OR D20141119 OR D20141120 OR D20141121 OR D20141122 OR D20141123 OR D20141124 OR D20141125 OR D20141126 OR D20141127 OR D20141128 OR D20141129 OR D20141130 OR M201412 OR M201501 OR M201502 OR M201503 OR M201504 OR M201505 OR M201506 OR M201507 OR M201508 OR M201509 OR M201510 OR D20151101 OR D20151102 OR D20151103 OR D20151104 OR Dlatest)' START=20141104 SPAN=365
461 # Backward spans:
462 qtestcase '(D20151103 OR D20151104 OR D20151105 OR D20151106 OR Dlatest)' END=20151106 SPAN=3
463 qtestcase '(D20141103 OR D20141104 OR D20141105 OR D20141106 OR D20141107 OR D20141108 OR D20141109 OR D20141110 OR D20141111 OR D20141112 OR D20141113 OR D20141114 OR D20141115 OR D20141116 OR D20141117 OR D20141118 OR D20141119 OR D20141120 OR D20141121 OR D20141122 OR D20141123 OR D20141124 OR D20141125 OR D20141126 OR D20141127 OR D20141128 OR D20141129 OR D20141130 OR M201412 OR M201501 OR M201502 OR M201503 OR M201504 OR M201505 OR M201506 OR M201507 OR M201508 OR M201509 OR M201510 OR D20151101 OR D20151102 OR D20151103 OR Dlatest)' END=20151103 SPAN=365
465 # Check that if START, END and SPAN are all passed, START is ignored:
466 qtestcase '(D20151103 OR D20151104 OR D20151105 OR D20151106 OR Dlatest)' START=19700101 END=20151106 SPAN=3
468 # Check that YYYYMM and YYYY are accepted and handled appropriately:
469 qtestcase '(Y1980 OR Y1981 OR Dlatest)' START=1980 END=1981
470 qtestcase '(M198012 OR M198101 OR M198102 OR Dlatest)' START=198012 END=198102
472 # Check .SLOT combined with term based date range filter:
473 qtestcase '(VALUE_RANGE 0 201512 2015~ AND (Y1970 OR Y1971 OR Y1972 OR Y1973 OR Y1974 OR Dlatest))' START.0=20151201 END.0=20151231 END=19741231
475 # Check combining of filter terms:
476 qtestcase '(Horg AND Len)' B=Len B=Horg
477 qtestcase '(Len OR Lde)' B=Len B=Lde
478 qtestcase '((Horg OR Hcom) AND (Len OR Lfr))' B=Len B=Lfr B=Horg B=Hcom
480 # Check combining of filter terms with filter_op set:
481 printf '$setmap{nonexclusiveprefix,L,1,XAND,1}$setmap{boolprefix,lang,L,and,XAND,host,H,year,Y}$querydescription' > "$TEST_TEMPLATE"
482 qtestcase 'Len' B=Len
483 qtestcase '0 * Len' P=lang:en
484 qtestcase 'XANDtest' B=XANDtest
485 qtestcase '0 * XANDtest' P=and:test
486 qtestcase '(Len AND XANDtest)' B=Len B=XANDtest
487 qtestcase '0 * (Len AND XANDtest)' P='lang:en and:test'
488 qtestcase '(Len AND Lde)' B=Len B=Lde
489 qtestcase '0 * (Len AND Lde)' P='lang:en lang:de'
490 qtestcase '((Horg OR Hcom) AND (Len AND Lfr))' B=Len B=Lfr B=Horg B=Hcom
491 qtestcase '0 * ((Len AND Lfr) AND (Horg OR Hcom))' P='lang:en lang:fr host:org host:com'
492 qtestcase '((XANDa AND XANDb AND XANDc) AND (Y1998 OR Y2001))' B=Y1998 B=Y2001 B=XANDa B=XANDb B=XANDc
493 qtestcase '0 * ((XANDa AND XANDb AND XANDc) AND (Y1998 OR Y2001))' P='year:1998 year:2001 and:a and:b and:c'
495 # Check combining of filters around CGI parameter 'N':
496 qtestcase '(Ztruth@1 AND_NOT Epdf)' P=truth N=Epdf
497 qtestcase '(Ztruth@1 AND_NOT (Ehtm OR Epdf))' P=truth N=Epdf N=Ehtm
498 qtestcase '(Ztruth@1 AND_NOT (Ehtm OR Epdf OR Lde OR Lfr))' P=truth N=Lfr N=Epdf N=Ehtm N=Lde
499 qtestcase '((Ztruth@1 FILTER (Lfr AND Lzh)) AND_NOT (Lde OR Len))' P=truth N=Lde N=Len B=Lfr B=Lzh
500 qtestcase '((Ztruth@1 FILTER Lfr) AND_NOT (Ehtm OR Epdf))' P=truth N=Epdf N=Ehtm B=Lfr
501 qtestcase '(<alldocuments> AND_NOT (Len OR Lfr))' N=Lfr N=Len
502 qtestcase '(VALUE_RANGE 0 2015 201501~ AND_NOT Len)' DATEVALUE=0 START=20150101 END=20150131 N=Len
504 # If faketime is available and works, test cases where the output depends on
505 # "now".
506 rc=0
507 out=`[ -n "$FAKETIME" ] && $FAKETIME -f '1980-12-08 00:00:00' date +%Y 2>&1` || rc=$?
508 if [ "$rc:$out" = "0:1980" ] ; then
509 FAKE_NOW='2015-11-28 06:07:08'
510 TZ=UTC qtestcase 'VALUE_RANGE 0 20151127060709 20151128060708' DATEVALUE=0 SPAN=1
512 # Tests of term-based date range filtering:
513 qtestcase '(Y2000 OR Y2001 OR Y2002 OR Y2003 OR Y2004 OR Y2005 OR Y2006 OR Y2007 OR Y2008 OR Y2009 OR Y2010 OR Y2011 OR Y2012 OR Y2013 OR Y2014 OR M201501 OR M201502 OR M201503 OR M201504 OR M201505 OR M201506 OR M201507 OR M201508 OR M201509 OR M201510 OR D20151101 OR D20151102 OR D20151103 OR D20151104 OR D20151105 OR D20151106 OR D20151107 OR D20151108 OR D20151109 OR D20151110 OR D20151111 OR D20151112 OR D20151113 OR D20151114 OR D20151115 OR D20151116 OR D20151117 OR D20151118 OR D20151119 OR D20151120 OR D20151121 OR D20151122 OR D20151123 OR D20151124 OR D20151125 OR D20151126 OR D20151127 OR D20151128 OR Dlatest)' START=20000101
514 qtestcase '(Y2010 OR Y2011 OR Y2012 OR Y2013 OR Y2014 OR M201501 OR M201502 OR M201503 OR M201504 OR M201505 OR M201506 OR M201507 OR M201508 OR M201509 OR M201510 OR D20151101 OR D20151102 OR D20151103 OR D20151104 OR D20151105 OR D20151106 OR D20151107 OR D20151108 OR D20151109 OR D20151110 OR D20151111 OR D20151112 OR D20151113 OR D20151114 OR D20151115 OR D20151116 OR D20151117 OR D20151118 OR D20151119 OR D20151120 OR D20151121 OR D20151122 OR D20151123 OR D20151124 OR D20151125 OR D20151126 OR D20151127 OR D20151128 OR Dlatest)' START=20100101
515 qtestcase '(Y1974 OR Y1975 OR Y1976 OR Y1977 OR Y1978 OR Y1979 OR Y1980 OR Y1981 OR Y1982 OR Y1983 OR Y1984 OR Y1985 OR Y1986 OR Y1987 OR Y1988 OR Y1989 OR Y1990 OR Y1991 OR Y1992 OR Y1993 OR Y1994 OR Y1995 OR Y1996 OR Y1997 OR Y1998 OR Y1999 OR Y2000 OR Y2001 OR Y2002 OR Y2003 OR Y2004 OR Y2005 OR Y2006 OR Y2007 OR Y2008 OR Y2009 OR Y2010 OR Y2011 OR Y2012 OR Y2013 OR Y2014 OR M201501 OR M201502 OR M201503 OR M201504 OR M201505 OR M201506 OR M201507 OR M201508 OR M201509 OR M201510 OR D20151101 OR D20151102 OR D20151103 OR D20151104 OR D20151105 OR D20151106 OR D20151107 OR D20151108 OR D20151109 OR D20151110 OR D20151111 OR D20151112 OR D20151113 OR D20151114 OR D20151115 OR D20151116 OR D20151117 OR D20151118 OR D20151119 OR D20151120 OR D20151121 OR D20151122 OR D20151123 OR D20151124 OR D20151125 OR D20151126 OR D20151127 OR D20151128 OR Dlatest)' START=19740101
516 qtestcase '(M201510 OR D20151101 OR D20151102 OR D20151103 OR D20151104 OR D20151105 OR D20151106 OR D20151107 OR D20151108 OR D20151109 OR D20151110 OR D20151111 OR D20151112 OR D20151113 OR D20151114 OR D20151115 OR D20151116 OR D20151117 OR D20151118 OR D20151119 OR D20151120 OR D20151121 OR D20151122 OR D20151123 OR D20151124 OR D20151125 OR D20151126 OR D20151127 OR D20151128 OR Dlatest)' START=20151001
517 # Date range with start after end:
518 qtestcase 'Dlatest' START=201512
519 qtestcase 'Dlatest' START=20151201
520 qtestcase '(D20150210 OR D20150211 OR D20150212 OR D20150213 OR D20150214 OR D20150215 OR D20150216 OR D20150217 OR D20150218 OR D20150219 OR D20150220 OR D20150221 OR D20150222 OR D20150223 OR D20150224 OR D20150225 OR D20150226 OR D20150227 OR D20150228 OR M201503 OR M201504 OR M201505 OR M201506 OR M201507 OR M201508 OR M201509 OR M201510 OR D20151101 OR D20151102 OR D20151103 OR D20151104 OR D20151105 OR D20151106 OR D20151107 OR D20151108 OR D20151109 OR D20151110 OR D20151111 OR D20151112 OR D20151113 OR D20151114 OR D20151115 OR D20151116 OR D20151117 OR D20151118 OR D20151119 OR D20151120 OR D20151121 OR D20151122 OR D20151123 OR D20151124 OR D20151125 OR D20151126 OR D20151127 OR D20151128 OR Dlatest)' START=20150210
521 qtestcase '(D20000220 OR D20000221 OR D20000222 OR D20000223 OR D20000224 OR D20000225 OR D20000226 OR D20000227 OR D20000228 OR D20000229 OR M200003 OR M200004 OR M200005 OR M200006 OR M200007 OR M200008 OR M200009 OR M200010 OR M200011 OR M200012 OR Y2001 OR Y2002 OR Y2003 OR Y2004 OR Y2005 OR Y2006 OR Y2007 OR Y2008 OR Y2009 OR Y2010 OR Y2011 OR Y2012 OR Y2013 OR Y2014 OR M201501 OR M201502 OR M201503 OR M201504 OR M201505 OR M201506 OR M201507 OR M201508 OR M201509 OR M201510 OR D20151101 OR D20151102 OR D20151103 OR D20151104 OR D20151105 OR D20151106 OR D20151107 OR D20151108 OR D20151109 OR D20151110 OR D20151111 OR D20151112 OR D20151113 OR D20151114 OR D20151115 OR D20151116 OR D20151117 OR D20151118 OR D20151119 OR D20151120 OR D20151121 OR D20151122 OR D20151123 OR D20151124 OR D20151125 OR D20151126 OR D20151127 OR D20151128 OR Dlatest)' START=20000220
522 unset FAKE_NOW
523 else
524 if [ "$rc" = 127 ] ; then
525 echo "Skipping testcases which need 'faketime' tool installed"
526 elif [ -z "$FAKETIME" ] ; then
527 echo "Skipping testcases which need 'faketime' tool - \$FAKETIME is empty"
528 else
529 echo "Skipping testcases which need 'faketime' tool - it's installed but doesn't work"
533 # Check clamping of out of range dates:
534 printf '%s\n' 'DATE : field valuepacked=0' > "$TEST_INDEXSCRIPT"
535 rm -rf "$TEST_DB"
536 $SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" > /dev/null <<'END'
537 DATE=0
539 DATE=1617069804
541 qtestcase 'VALUE_LE 0 V\x84o\xff' START.0=10010101 END.0=20151230
542 qtestcase 'VALUE_RANGE 0 V\x83\x1e\x80 \xff\xff\xff\xff' START.0=20151230 END.0=21060301
543 qtestcase 'VALUE_LE 0 \xff\xff\xff\xff' START.0=19691230 END.0=21060301
545 # Test stem_all and stem_strategy.
546 printf '$if{$cgi{stem_all},$set{stem_all,$cgi{stem_all}}}$if{$cgi{stem_strategy},$set{stem_strategy,$cgi{stem_strategy}}}$querydescription' > "$TEST_TEMPLATE"
547 qtestcase '(capitalised@1 AND tests@2 AND Zstem@3)' P='Capitalised "tests" stemmed'
548 qtestcase '(nearing@1 NEAR 11 distances@2)' P='nearing NEAR distances'
549 qtestcase '(capitalis@1 AND test@2 AND stem@3)' P='Capitalised "tests" stemmed' stem_all=true
550 qtestcase '(near@1 NEAR 11 distanc@2)' P='nearing NEAR distances' stem_all=true
551 qtestcase '(capitalis@1 AND test@2 AND stem@3)' P='Capitalised "tests" stemmed' stem_strategy=all
552 qtestcase '(near@1 NEAR 11 distanc@2)' P='nearing NEAR distances' stem_strategy=all
553 qtestcase '(Zcapitalis@1 AND Ztest@2 AND Zstem@3)' P='Capitalised "tests" stemmed' stem_strategy=all_z
554 qtestcase '(Znear@1 NEAR 11 Zdistanc@2)' P='nearing NEAR distances' stem_strategy=all_z
555 qtestcase '(capitalised@1 AND tests@2 AND stemmed@3)' P='Capitalised "tests" stemmed' stem_strategy=none
556 qtestcase '(nearing@1 NEAR 11 distances@2)' P='nearing NEAR distances' stem_strategy=none
557 qtestcase '(capitalised@1 AND tests@2 AND Zstem@3)' P='Capitalised "tests" stemmed' stem_strategy=some
558 qtestcase '(nearing@1 NEAR 11 distances@2)' P='nearing NEAR distances' stem_strategy=some
559 qtestcase '(capitalised@1 AND tests@2 AND Zstem@3)' P='Capitalised "tests" stemmed' stem_strategy=some_full_pos
560 qtestcase '(Znear@1 NEAR 11 Zdistanc@2)' P='nearing NEAR distances' stem_strategy=some_full_pos
561 qtestcase '(capitalised@1 AND tests@2 AND Zstem@3)' P='Capitalised "tests" stemmed' stem_strategy=some stem_all=true
562 qtestcase '(nearing@1 NEAR 11 distances@2)' P='nearing NEAR distances' stem_strategy=some stem_all=true
564 # Feature tests for $contains.
565 printf '$contains{$cgi{a},$cgi{b}}' > "$TEST_TEMPLATE"
566 testcase '6' P=text a=fish b="Hello fish"
567 testcase '' P=text a="Example" b="random"
569 NEWLINE='
572 # Feature tests for boolprefix and prefix maps.
573 printf '$set{stemmer,}$setmap{boolprefix,lang,L,host,H}$setmap{prefix,,XDEFAULT}$querydescription' > "$TEST_TEMPLATE"
574 qtestcase '((XDEFAULTfoo@1 AND XDEFAULTbar@2) FILTER (Hexample.org AND Lzh))' P='host:example.org foo bar lang:zh'
576 # Feature tests for $addfilter.
577 printf '$addfilter{Hexample.org}$addfilter{Hexample.com,}$addfilter{XFOObar,B}$querydescription' > "$TEST_TEMPLATE"
578 qtestcase '((Hexample.org OR Hexample.com) AND XFOObar)' P=
579 printf '$addfilter{Hexample.org}$addfilter{Hexample.com,N}$addfilter{Hexample.net,N}$querydescription' > "$TEST_TEMPLATE"
580 qtestcase '(Hexample.org AND_NOT (Hexample.com OR Hexample.net))' P=
582 # Feature tests for $if.
583 printf '$if{$set{w,1}}$if{a,$set{x,1}}$if{b,$set{y,1},$set{y,2}}$if{,$set{x,0}}$if{,$set{z,2},$set{z,1}}$opt{w}$opt{x}$opt{y}$opt{z}' > "$TEST_TEMPLATE"
584 testcase '1111'
586 # Feature tests for $cond.
587 printf '$cond{$cgi{one},1,$cgi{two},2,$cgi{three},3}' > "$TEST_TEMPLATE"
588 testcase '1' one=true
589 testcase '2' two=true
590 testcase '3' three=true
591 testcase '' nothing=true
592 testcase '1' one=true two=true three=true
593 testcase '2' two=true three=true
594 printf '$cond{$cgi{one},1,$cgi{two},2,$cgi{alt}}' > "$TEST_TEMPLATE"
595 testcase '1' one=true
596 testcase '2' two=true
597 testcase 'none' alt=none
598 # Check evaluation is lazy.
599 printf '$cond{$cgi{one},$seterror{err1},$cgi{two},2,$cgi{alt}}$error' > "$TEST_TEMPLATE"
600 testcase 'err1' one=true
601 testcase '2' two=true
602 testcase 'none' alt=none
603 printf '$cond{$cgi{one},1,$cgi{two},$seterror{err2},$cgi{alt}}$error' > "$TEST_TEMPLATE"
604 testcase '1' one=true
605 testcase 'err2' two=true
606 testcase 'none' alt=none
607 printf '$cond{$cgi{one},1,$cgi{two},2,$seterror{erralt}}$error' > "$TEST_TEMPLATE"
608 testcase '1' one=true
609 testcase '2' two=true
610 testcase 'erralt' alt=none
612 # Feature tests for $switch.
613 printf '$switch{$cgi{x},1,one,2,two}' > "$TEST_TEMPLATE"
614 testcase 'one' x=1
615 testcase 'two' x=2
616 testcase '' x=3
617 printf '$switch{$cgi{x},1,one,2,two,default}' > "$TEST_TEMPLATE"
618 testcase 'one' x=1
619 testcase 'two' x=2
620 testcase 'default' x=3
621 # Check evaluation is lazy.
622 printf '$switch{$cgi{x},1,$seterror{err1},2,two}$error' > "$TEST_TEMPLATE"
623 testcase 'err1' x=1
624 testcase 'two' x=2
625 testcase '' x=3
626 printf '$switch{$cgi{x},1,one,2,$seterror{err2},default}$error' > "$TEST_TEMPLATE"
627 testcase 'one' x=1
628 testcase 'err2' x=2
629 testcase 'default' x=3
630 printf '$switch{$cgi{x},1,one,2,two,$seterror{errdefault}}$error' > "$TEST_TEMPLATE"
631 testcase 'one' x=1
632 testcase 'two' x=2
633 testcase 'errdefault' x=3
635 # Feature tests for $include.
636 # Test inclusion works and evaluates the included file.
637 printf '$set{c,$add{$or{$opt{c},0},1}}$opt{c},$if{$lt{$opt{c},10},$include{'"$TEST_TEMPLATE"'}}X' > "$TEST_TEMPLATE"
638 testcase '1,2,3,4,5,6,7,8,9,10,XXXXXXXXXX'
639 # Test fallback action when trying to $include a file which doesn't exist or
640 # with a prohibited name.
641 printf '$include{$cgi{template},foo$set{data,bar}}-$opt{data}' > "$TEST_TEMPLATE"
642 testcase 'foo-bar' template=non_existent.template
643 testcase 'foo-bar' template=../secret/file
644 # Test exception is thrown when there's no fallback action when trying to
645 # $include a file which doesn't exist or with a prohibited name.
646 printf '$include{$cgi{template}}-$opt{data}' > "$TEST_TEMPLATE"
647 testcase "Exception: Couldn't read format template 'non_existent.template' (No such file or directory)" template=non_existent.template
648 testcase "Exception: Couldn't read format template '../secret/file' (name contains '..')" template=../secret/file
650 # Feature tests for $foreach.
651 printf '$foreach{$split{.,$cgi{a}},$chr{$add{$_,64}}}' > "$TEST_TEMPLATE"
652 testcase 'OMEGA' a=15.13.5.7.1
653 # Check that the outer $_ is restored after the inner $foreach.
654 printf '$foreach{$split{.,$cgi{a}},$foreach{$split{.,$cgi{$_}},$chr{$add{$_,64}}}$_}' > "$TEST_TEMPLATE"
655 testcase 'OMbEGcAd' a=b.c.d b=15.13 c=5.7 d=1
657 # Feature tests for $map.
658 printf '$list{$map{$split{-,$cgi{a}},$list{$map{$split{,$cgi{b}},$_},-}},|}' > "$TEST_TEMPLATE"
659 testcase '1-2-3|1-2-3' P=text a=ab-cd b=123
660 printf '$list{$map{$split{-,$cgi{a}},$set{__,$_}$list{$map{$split{,$cgi{b}},$opt{__}$_},-}},|}' > "$TEST_TEMPLATE"
661 testcase 'a1-a2-a3|b1-b2-b3' P=text a=a-b b=123
662 printf '$list{$map{$split{-,$cgi{a}},$list{$map{$split{$_,$cgi{b}},$_},-}},|}' > "$TEST_TEMPLATE"
663 testcase '1-2,3|1:2-3' P=text a=':-,' b='1:2,3'
664 # Check that the outer $_ is restored after the inner $map.
665 printf '$list{$map{$split{-,$cgi{a}},$list{$map{$split{,$cgi{b}},$_},-}$_},|}' > "$TEST_TEMPLATE"
666 testcase '1-2-3a|1-2-3b' P=text a='a-b' b='123'
668 # Feature tests for $match.
669 printf '$match{$cgi{a},$cgi{b},$cgi{c}}' > "$TEST_TEMPLATE"
670 testcase 'true' P=text a="ab*c+" b="ac"
671 testcase '' P=text a="acb" b="abc"
672 testcase 'true' P=text a="[A-Z]bcD" b="abcd" c="i"
673 testcase '' P=text a="[A-Z]bcD" b="abcd"
674 testcase 'true' P=text a="^abc$" b="${NEWLINE}abc${NEWLINE}def" c="m"
675 testcase '' P=text a="^abc$" b="${NEWLINE}abc${NEWLINE}def"
676 testcase 'true' P=text a="abc." b="abc${NEWLINE}" c="s"
677 testcase '' P=text a="abc." b="abc${NEWLINE}"
678 testcase 'true' P=text a=" ABC #test_comment " b="ABC" c="x"
679 testcase '' P=text a=" ABC #test_comment " b="ABC"
681 # Feature tests for $sort.
682 printf '$list{$sort{$split{|,$cgi{input}}},|}' > "$TEST_TEMPLATE"
683 testcase 'pineapple' input="pineapple"
684 testcase 'apple|banana|coconut' input="coconut|banana|apple"
685 testcase '1|b|b|c' input="b|c|b|1"
686 printf '$list{$sort{$split{|,$cgi{input}},$cgi{opt}},|}' > "$TEST_TEMPLATE"
687 testcase 'pineapple' input="pineapple" opt=
688 testcase 'pineapple' input="pineapple" opt=r
689 testcase 'pineapple' input="pineapple" opt=ru
690 testcase '1|b|c' input="b|c|b|1" opt=u
691 testcase 'c|b|b|1' input="b|c|b|1" opt=r
692 testcase 'c|b|1' input="b|c|b|1" opt=ur
693 testcase '-2|-.01|+99.99|+999|.0|0.0|.1|1|2|3|3.0|3.01|12|23|30' input='+999|2|1|12|23|3|30|3.01|3.0|.1|.0|0.0|-2|-.01|+99.99' opt=n
694 testcase '-2|-.01|+999|.1|1|2|3|3.01|12|23|30' input='+999|2|1|12|23|3|30|3.01|3.0|.1|.0|0.0|-2|-.01|+99.99' opt=nu
695 testcase '-2|-.01|+99.99|.1|1|2|3.0|3.01|12|23|30' input='+99.99|-.01|-2|0.0|.0|.1|3.0|3.01|30|3|23|12|1|2|+999' opt=nu
696 testcase '30|23|12|3.01|3.0|3|2|1|.1|0.0|.0|+999|+99.99|-.01|-2' input='+999|2|1|12|23|3|30|3.01|3.0|.1|.0|0.0|-2|-.01|+99.99' opt=nr
697 testcase '30|23|12|3.01|3|2|1|.1|+999|-.01|-2' input='+999|2|1|12|23|3|30|3.01|3.0|.1|.0|0.0|-2|-.01|+99.99' opt=nur
698 testcase '30|23|12|3.01|3.0|2|1|.1|+99.99|-.01|-2' input='+99.99|-.01|-2|0.0|.0|.1|3.0|3.01|30|3|23|12|1|2|+999' opt=nur
699 testcase 't 42|t 42:|t 42:1|t 42:09|t 42:9|t 42:11|t 42~' input='t 42:1|t 42|t 42:11|t 42:9|t 42~|t 42:|t 42:09' opt='#'
700 testcase 'A7R1:2|A7R2:6|A7R2:9|A7R2:11|A7R2:19|A7R2:47A|A7R11:1|AA|R7:1.09|R7:4A|R7:6|R7:7A|R7:404|R7:444-10|R7:1521' \
701 input='A7R1:2|R7:1521|AA|R7:4A|R7:7A|A7R2:9|R7:444-10|A7R2:6|R7:1.09|A7R2:47A|A7R11:1|R7:6|A7R2:11|R7:404|A7R2:19' \
702 opt='#'
703 testcase '30|23|12|3|03|2|1|01|0|00' input='2|1|23|12|23|3|30|0|00|0|01|03' opt='#ru'
704 testcase 'Exception: Unknown $sort option: x' input="b|c|b|1" opt=urx
705 testcase 'Exception: Invalid $sort option combination: n#' input="b|c" opt='n#'
706 testcase 'Exception: Invalid $sort option combination: #rn' input="b|1" opt='#rn'
708 # Regression test to test suppression of Content-Type header for early
709 # exception.
710 rm -rf "$TEST_DB"
711 echo 'inmemory' > "$TEST_DB"
712 testcase 'Exception: DocNotFoundError: Docid 1 not found' MORELIKE=1
714 # Regression test for $sort bug fixed in 1.4.12.
715 # Check $sort doesn't ensure_match (or ensure_query).
716 printf '$sort{test} $addfilter{Test}$querydescription' > "$TEST_TEMPLATE"
717 testcase 'test Query(Test)'
719 # Feature tests for $keys.
720 printf '$setmap{x,bee,1,eel,6,dog,4,ant,2,fox,5,cat,3}/$list{$keys{x},|}/$keys{nosuch}/' > "$TEST_TEMPLATE"
721 testcase '/ant|bee|cat|dog|eel|fox//'
723 # Feature tests for $terms.
724 printf 'text : index\nhost : boolean=H\nfoo : boolean=XFOO' > "$TEST_INDEXSCRIPT"
725 rm -rf "$TEST_DB"
726 $SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" > /dev/null <<'END'
727 text=This is some text.
728 host=example.org
729 foo=bar
731 printf '$hitlist{$list{$if{$eq{$cgi{prefix},null},$terms,$terms{$cgi{prefix}}},|}}' > "$TEST_TEMPLATE"
732 testcase 'Ztext' P=text B=Hexample.org B=Hexample.com prefix=null
733 testcase 'Hexample.org|Ztext' P=text B=Hexample.org B=Hexample.com prefix=
734 testcase 'Hexample.org' P=text B=Hexample.org B=Hexample.com prefix=H
735 testcase 'Ztext' P=text B=Hexample.org B=Hexample.com prefix=Z
736 testcase '' P=text B=Hexample.org B=Hexample.com prefix=E
738 printf '$msizelower $msize $msizeupper $msizeexact' > "$TEST_TEMPLATE"
739 testcase '1 1 1 true' P=this
740 testcase '1 1 1 true' P='Some text'
741 testcase '0 0 0 true' P=potato
743 printf '$set{weighting,coord}$hitlist{$weight.}' > "$TEST_TEMPLATE"
744 testcase '' P=aardvark
745 testcase '1.000000.' P=texting
746 testcase '' P='texting while driving'
747 testcase '' P='texting while driving' DEFAULTOP=AND
748 testcase '1.000000.' P='texting while driving' DEFAULTOP=OR
749 testcase '2.000000.' P='Some text'
750 # "this" and "is" are stopwords.
751 testcase '2.000000.' P='This is some text'
752 testcase '4.000000.' P='"This" "is" some text'
753 testcase '4.000000.' P='+This +is some text'
754 testcase '4.000000.' P='"This is some text"'
756 printf '$set{weightingpurefilter,coord}$hitlist{$weight.}' > "$TEST_TEMPLATE"
757 testcase '' B=XFOOfoo
758 testcase '1.000000.' B=Hexample.org
759 testcase '' B=Hexample.org B=XFOOfoo
760 testcase '1.000000.' B=Hexample.org B=Hexample.net
761 testcase '2.000000.' B=Hexample.org B=XFOObar
762 testcase '3.000000.' B=Hexample.org B=XFOObar B=XFOObar
764 printf '$filters' > "$TEST_TEMPLATE"
765 testcase 'Hexample.net~Hexample.org~.~~' B=Hexample.org B=Hexample.net
766 testcase '!Gmisc.test~.~~' N=Gmisc.test
767 testcase 'Hexample.net~Hexample.org~!Gmisc.test~.~~' B=Hexample.org B=Hexample.net N=Gmisc.test
768 testcase '.20040612~~~1~' DATEVALUE=1 START=20040612
769 testcase '.20040612~~~1~2' DATEVALUE=1 START=20040612 COLLAPSE=2
770 testcase '.20040612~~30~2' START=20040612 SPAN=30 COLLAPSE=2
771 testcase '.20040612~20160412~' START=20040612 END=20160412
772 testcase '.~~~2' COLLAPSE=2
773 testcase '.~~'
774 testcase '.~~1' SORT=1
775 testcase '.~~1f' SORT=+1
776 testcase '.~~1' SORT=-1
777 testcase '.~~1-2+3-27' SORT=+1-2+03,-27
778 testcase '.~~' SORTREVERSE=1
779 testcase '.~~1f' SORT=1 SORTREVERSE=1
780 testcase '.~~1' SORT=+1 SORTREVERSE=1
781 testcase '.~~1f' SORT=-1 SORTREVERSE=1
782 testcase '.~~1-2+3-27f' SORT=+1-2+03,-27 SORTREVERSE=1
783 testcase '.~~' SORTAFTER=1
784 testcase '.~~1R' SORT=1 SORTAFTER=1
785 testcase '.~~1F' SORT=+1 SORTAFTER=1
786 testcase '.~~1R' SORT=-1 SORTAFTER=1
787 testcase '.~~1-2+3-27R' SORT=+1-2+03,-27 SORTAFTER=1
788 testcase '.~~' SORTREVERSE=1 SORTAFTER=1
789 testcase '.~~1F' SORT=1 SORTREVERSE=1 SORTAFTER=1
790 testcase '.~~1R' SORT=+1 SORTREVERSE=1 SORTAFTER=1
791 testcase '.~~1F' SORT=-1 SORTREVERSE=1 SORTAFTER=1
792 testcase '.~~1-2+3-27F' SORT=+1-2+03,-27 SORTREVERSE=1 SORTAFTER=1
793 testcase '.~~X' DOCIDORDER=A # Buggy, but kept for compatibility.
794 testcase '.~~D' DOCIDORDER=D
795 testcase '.~~' DOCIDORDER=X # Buggy, but kept for compatibility.
796 testcase '.~~' DOCIDORDER=x # Buggy, but kept for compatibility.
798 tab=`printf '\t'`
799 printf '$cgi{AZ}|$cgi{AZ B}|$cgi{AZ.x}|$cgi{AZ.y}|$cgi{[}|$cgi{#}' > "$TEST_TEMPLATE"
800 testcase 'AZ|||||' AZ.x=3 AZ.y=4
801 testcase 'B|||||' 'AZ B.x=5' 'AZ B.y=12'
802 testcase 'B|||||' "AZ${tab}B.x=5" "AZ${tab}B.y=12"
803 testcase '||||2 ]|' '[ 2 ].x=123'
804 testcase '||||2 ]|' "[${tab}2 ].x=123"
805 testcase "||||2${tab}]|" "[ 2${tab}].x=123"
806 testcase "||||2${tab}]|" "[${tab}2${tab}].x=123"
807 testcase '|||||12' '12.x=37'
808 testcase 'DE|||||' 'AZ BC=DE'
809 testcase 'DE|||||' 'AZ B C=DE'
810 testcase 'DE|||||' "AZ${tab}BC=DE"
811 testcase 'DE|||||' "AZ B${tab}C=DE"
812 testcase 'DE|||||' "AZ${tab}B C=DE"
813 testcase 'DE|||||' "AZ${tab}B${tab}C=DE"
815 printf '$cgi{Search}|$cgi{Type}|$cgi{Search Type}' > "$TEST_TEMPLATE"
816 testcase 'Discover-List||' 'Search Type=Discover-List'
818 printf '$cgiparams' > "$TEST_TEMPLATE"
819 # We can't test the "no cgi parameters" case via testcase, as it passes a
820 # "dummy" parameter if there aren't any real ones.
821 #testcase ""
822 testcase "" =1
823 testcase "ABC" ABC=1
824 testcase "ABC" ABC=1 ABC=2
825 testcase "A${tab}AZ${tab}Z" A=1 A=2 A=3 AZ=1 AZ=2 Z=xxx
826 testcase "${tab}abc" =1 abc=1
827 testcase "${tab}abc${tab}def" =1 abc=1 def=7
829 # Feature tests for $highlight{}.
830 printf '$highlight{$cgi{text},$cgi{list}}' > "$TEST_TEMPLATE"
831 testcase 'A <b style="color:black;background-color:#ffff66">list</b> of <b style="color:black;background-color:#99ff99">words</b>' list="list${tab}words" text="A list of words"
833 printf '$highlight{$cgi{text},$cgi{list},$cgi{open}}' > "$TEST_TEMPLATE"
834 testcase 'A list of <b>words</b>' list="words" text="A list of words" open="<b>"
835 testcase 'A list of <span>words</span>' list="words" text="A list of words" open="<span>"
837 printf '$highlight{$cgi{text},$cgi{list},$cgi{open},$cgi{close}}' > "$TEST_TEMPLATE"
838 testcase 'A list of <b>words</b>' list="words" text="A list of words" open="<b>" close="</b>"
839 testcase 'A *list* of *words*' list="words${tab}list" text="A list of words" open="*" close="*"
841 # Test setting seterror and mset size, should not run the query after setting error.
842 printf '$if{$cgi{ERR},$seterror{$cgi{ERR}}}$msize$if{$error,!$error!}' > "$TEST_TEMPLATE"
843 testcase '1' P=text
844 testcase '0!boo!' P=text ERR=boo
846 # Test arguments inside seterror are evaluated
847 printf '$set{error,sample error}$seterror{$opt{error}}$msize$if{$error,!$error!}' > "$TEST_TEMPLATE"
848 testcase '0!sample error!' P=text
850 # Test error message doesn't get sent through HTML entity encoding.
851 printf '$seterror{{ "error": true, "error_message": "Parameter cannot be > 9" }}$if{$error,$error}' > "$TEST_TEMPLATE"
852 testcase '{ "error": true, "error_message": "Parameter cannot be > 9" }' P=text
854 # Test msize when error set after running query, should not affect running of query.
855 printf '$last$if{$cgi{ERR},$seterror{$cgi{ERR}}}$msize$if{$error,!$error!}' > "$TEST_TEMPLATE"
856 testcase '11' P=text
857 testcase '11!boo!' P=text ERR=boo
859 # Feature tests for $base64{}
860 printf '$base64{$cgi{in}}' > "$TEST_TEMPLATE"
861 testcase '' in=""
862 testcase 'IQ==' in='!'
863 testcase 'T2s=' in='Ok'
864 testcase 'aGA+aGA/' in='h`>h`?'
865 testcase 'YmFzZTY0IHRlc3Q=' in='base64 test'
867 # Regression test: $setrelevant crashed with no argument list prior to 1.4.16.
868 printf '$setrelevant$or{$error,No error}' > "$TEST_TEMPLATE"
869 testcase 'Exception: too few arguments to $setrelevant' P=text
870 printf '$setrelevant{}$or{$error,No error}' > "$TEST_TEMPLATE"
871 testcase 'No error' P=text
873 # Feature tests for $uniq and $unique{}.
874 printf '$list{$uniq{$split{$cgi{text}}},:}|$list{$unique{$split{$cgi{text}}},:}' > "$TEST_TEMPLATE"
875 testcase '|' text=''
876 testcase 'foo|foo' text='foo'
877 testcase 'apple:banana:cherry|apple:banana:cherry' text='apple apple banana banana banana cherry'
878 testcase 'a:b:r:a:c:a:d:a:b:r:a|a:b:r:c:d' text='a b r a c a d a b r a'
879 testcase 'x:y:z:y|x:y:z' text='x y z z y'
881 # Regression test - $map with one argument wasn't rejected cleanly.
882 printf '$map{foo}' > "$TEST_TEMPLATE"
883 testcase 'Exception: too few arguments to $map'
885 # Omit trailing \n on dump file as regression test for bug fixed in 1.4.20
886 # where a final line without a newline was ignored.
887 printf 'a b : index field' > "$TEST_INDEXSCRIPT"
888 rm -rf "$TEST_DB"
889 printf 'a=1\nb=2' | $SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" > /dev/null
890 printf '$record{1}' > "$TEST_TEMPLATE"
891 testcase 'a=1
892 b=2'
894 # Test MORELIKE CGI parameter.
895 printf '%s\n' 'id : boolean=Q' 'text : index field' > "$TEST_INDEXSCRIPT"
896 rm -rf "$TEST_DB"
897 $SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" > /dev/null <<'END'
898 id=a1
899 text=First document
901 id=b2
902 text=Second article
904 id=c3
905 text=Piece of writing three
907 id=dummy
908 text=Inflating termfreqs since Omega excludes terms with termfreq of one
909 =first document second piece of writing three
911 printf '$querydescription|$query' > "$TEST_TEMPLATE"
912 testcase 'Query((Zfirst@1 OR Zdocument@2))|first document' MORELIKE='Qa1' DEFAULTOP=or
913 testcase 'Query((Zfirst@1 OR Zdocument@2))|first OR document' MORELIKE='Qa1'
914 testcase 'Query((Zfirst@1 OR Zdocument@2))|first OR document' MORELIKE='Qa1' DEFAULTOP=and
915 # Test with docid.
916 testcase 'Query((Zfirst@1 OR Zdocument@2))|first document' MORELIKE='1' DEFAULTOP=OR
917 testcase 'Query((Zfirst@1 OR Zdocument@2))|first OR document' MORELIKE='1'
918 testcase 'Query((Zfirst@1 OR Zdocument@2))|first OR document' MORELIKE='1' DEFAULTOP=phrase
919 # "article" is excluded by OmegaExpandDecider because it has termfreq 1.
920 testcase 'Query(Zsecond@1)|second' MORELIKE='Qb2' DEFAULTOP=or
921 testcase 'Query(Zsecond@1)|second' MORELIKE='Qb2'
922 # "of" is excluded because it's a stopword.
923 testcase 'Query((Zwrite@1 OR Zthree@2 OR Zpiec@3))|writing OR three OR piece' MORELIKE='Qc3'
924 # Test with absent term.
925 testcase 'Query()|' MORELIKE='Qx9'
926 # Test multiple MORELIKE parameters. We need to include the dummy document for
927 # any terms to get a positive weight and be returned.
928 testcase 'Query((Zsecond@1 OR Zfirst@2 OR Zdocument@3))|second OR first OR document' MORELIKE=1 MORELIKE=2 MORELIKE=4
929 testcase 'Query((Zsecond@1 OR Zfirst@2 OR Zdocument@3))|second OR first OR document' MORELIKE=Qa1 MORELIKE=2 MORELIKE=4
930 testcase 'Query((Zsecond@1 OR Zfirst@2 OR Zdocument@3))|second OR first OR document' MORELIKE=Qa1 MORELIKE=Qb2 MORELIKE=Qdummy
932 # Test errors for scriptindex input format issues.
933 printf 'f : index field' > "$TEST_INDEXSCRIPT"
934 test_scriptindex_error "no = in input line" \
935 "<stdin>:1: error: Expected = somewhere in this line" \
936 "a\nb=y\nc=z\n"
937 test_scriptindex_error "no = in input line" \
938 "<stdin>:2: error: Expected = somewhere in this line" \
939 "a=x\nby\nc=z\n"
940 test_scriptindex_error "no = in input line" \
941 "<stdin>:3: error: Expected = somewhere in this line" \
942 "a=x\n=yz\nbcd\ne=q"
944 # Test handling of extra blank lines.
945 printf 'id : unique=Q boolean=Q\nf : field' > "$TEST_INDEXSCRIPT"
946 test_scriptindex "extra blank lines" \
947 "\nid=1\nf=a\n\n\nid=2\nf=b\n\n"
948 test_scriptindex "extra blank lines with CRs" \
949 "\r\nid=1\r\nf=a\r\n\r\n\r\nid=2\r\nf=b\r\n\r\n"
951 # Feature tests for scriptindex `index` and `indexnopos` actions.
952 printf '%s\n' 't : index=XT' 'n : indexnopos=XN' > "$TEST_INDEXSCRIPT"
953 test_scriptindex 'INDEX and INDEXNOPOS actions' \
954 't=positional text\nn=no pos here'
955 printf '$msize' > "$TEST_TEMPLATE"
956 testcase '1' P.XT='"positional text"'
957 testcase '1' P.XN='no AND pos'
958 testcase '0' P.XN='"no pos"'
960 # Feature tests for scriptindex `split` action.
961 printf 'STATUS : field split=| field=SPLITSTATUS\nSTATUS : field=x' > "$TEST_INDEXSCRIPT"
962 test_scriptindex 'SPLIT action' \
963 'STATUS=PENDING|REVIEW'
964 printf '$field{STATUS,1}/$field{x,1}/$list{$field{SPLITSTATUS,1},$.}' > "$TEST_TEMPLATE"
965 testcase 'PENDING|REVIEW/PENDING|REVIEW/PENDING,REVIEW' P=text
967 # Feature test for scriptindex `split` action with `dedup` operation.
968 printf 'STATUS : field split=|,dedup field=SPLITSTATUS\n' > "$TEST_INDEXSCRIPT"
969 test_scriptindex 'test SPLIT with DEDUP' \
970 'STATUS=REVIEW|PENDING|PENDING|REVIEW'
971 printf '$field{STATUS,1}/$list{$field{SPLITSTATUS,1},$.}' > "$TEST_TEMPLATE"
972 testcase 'REVIEW|PENDING|PENDING|REVIEW/REVIEW,PENDING' P=text
974 # Feature test for scriptindex `split` action with `sort` operation.
975 printf 'STATUS : field split=|,sort field=SPLITSTATUS\n' > "$TEST_INDEXSCRIPT"
976 test_scriptindex 'test SPLIT with SORT' \
977 'STATUS=REVIEW|PENDING|PENDING|REVIEW'
978 printf '$field{STATUS,1}/$list{$field{SPLITSTATUS,1},$.}' > "$TEST_TEMPLATE"
979 testcase 'REVIEW|PENDING|PENDING|REVIEW/PENDING,PENDING,REVIEW,REVIEW' P=text
981 # Feature test for scriptindex `split` action with `none` operation.
982 printf 'STATUS : field split=|,none field=SPLITSTATUS\n' > "$TEST_INDEXSCRIPT"
983 test_scriptindex 'test SPLIT with NONE' \
984 'STATUS=REVIEW|PENDING|PENDING|REVIEW'
985 printf '$field{STATUS,1}/$list{$field{SPLITSTATUS,1},$.}' > "$TEST_TEMPLATE"
986 testcase 'REVIEW|PENDING|PENDING|REVIEW/REVIEW,PENDING,PENDING,REVIEW' P=text
988 # Feature test for scriptindex `split` action with `prefixes` operation.
989 printf 'STATUS : field split=|,prefixes field=SPLITSTATUS\n' > "$TEST_INDEXSCRIPT"
990 test_scriptindex 'test SPLIT with PREFIXES' \
991 'STATUS=REVIEW|PENDING|PENDING|REVIEW'
992 printf '$field{STATUS,1}/$list{$field{SPLITSTATUS,1},$.}' > "$TEST_TEMPLATE"
993 testcase 'REVIEW|PENDING|PENDING|REVIEW/REVIEW,REVIEW|PENDING,REVIEW|PENDING|PENDING,REVIEW|PENDING|PENDING|REVIEW' P=text
995 # Feature tests for scriptindex `split` action with no explicit operation.
996 printf 'STATUS : field split=| field=SPLITSTATUS\n' > "$TEST_INDEXSCRIPT"
997 test_scriptindex 'test SPLIT with implicit op' \
998 'STATUS=PENDING|REVIEW|PENDING|REVIEW'
999 printf '$field{STATUS,1}/$list{$field{SPLITSTATUS,1},$.}' > "$TEST_TEMPLATE"
1000 testcase 'PENDING|REVIEW|PENDING|REVIEW/PENDING,REVIEW,PENDING,REVIEW' P=text
1002 # Feature test for scriptindex `split` action with multi-character delimiter.
1003 printf 'STATUS : field split=$. field=SPLITSTATUS\n' > "$TEST_INDEXSCRIPT"
1004 test_scriptindex 'test SPLIT with multi-char delimiter' \
1005 'STATUS=PENDING$.$.REVIEW,PENDING$.REVIEW'
1006 printf '$field{STATUS,1}/$list{$field{SPLITSTATUS,1},|}' > "$TEST_TEMPLATE"
1007 testcase 'PENDING$.$.REVIEW,PENDING$.REVIEW/PENDING|REVIEW,PENDING|REVIEW' P=text
1009 # Feature test for scriptindex `split` action with multi-character delimiter
1010 # with potential overlap.
1011 printf 'STATUS : field split=:: field=SPLITSTATUS\n' > "$TEST_INDEXSCRIPT"
1012 test_scriptindex 'test SPLIT with overlapping multi-char delimiter' \
1013 'STATUS=::Foo::::Bar:Baz:::Hello::'
1014 printf '$field{STATUS,1}/$list{$field{SPLITSTATUS,1},|}' > "$TEST_TEMPLATE"
1015 testcase '::Foo::::Bar:Baz:::Hello::/Foo|Bar:Baz|:Hello' P=text
1017 # Feature test for scriptindex `split` action with multi-character delimiter
1018 # with `prefixes` operation.
1019 printf 'STATUS : field split=::,prefixes field=SPLITSTATUS\n' > "$TEST_INDEXSCRIPT"
1020 test_scriptindex 'test SPLIT with PREFIXES and multi-char delimiter' \
1021 'STATUS=::Foo::::Bar:Baz:::Hello::'
1022 printf '$field{STATUS,1}/$list{$field{SPLITSTATUS,1},|}' > "$TEST_TEMPLATE"
1023 testcase '::Foo::::Bar:Baz:::Hello::/::Foo|::Foo::|::Foo::::Bar:Baz|::Foo::::Bar:Baz:::Hello|::Foo::::Bar:Baz:::Hello::' P=text
1025 # Feature test for scriptindex `split` action with quoted `,` delimiter.
1026 printf 'STATUS : field split="," field=SPLITSTATUS\n' > "$TEST_INDEXSCRIPT"
1027 test_scriptindex 'test SPLIT with quoted comma delimiter' \
1028 'STATUS=PENDING,REVIEW,PENDING,REVIEW'
1029 printf '$field{STATUS,1}/$list{$field{SPLITSTATUS,1},|}' > "$TEST_TEMPLATE"
1030 testcase 'PENDING,REVIEW,PENDING,REVIEW/PENDING|REVIEW|PENDING|REVIEW' P=text
1032 # Feature test for nested scriptindex `split` action.
1033 printf 'in : split=; field=one lower split="," field=two\nin : field' > "$TEST_INDEXSCRIPT"
1034 test_scriptindex 'nested SPLIT action' \
1035 'in=a,b,c;10,21,32;XY,YZ'
1036 printf '$field{in,1}/$list{$field{one,1},|}/$list{$field{two,1},|}' > "$TEST_TEMPLATE"
1037 testcase 'a,b,c;10,21,32;XY,YZ/a,b,c|10,21,32|XY,YZ/a|b|c|10|21|32|xy|yz' P=text
1039 # Test scriptindex `split` action error cases.
1040 printf 'in : split="" field=one\nin : field' > "$TEST_INDEXSCRIPT"
1041 test_scriptindex_error "'split' error for empty separator" \
1042 "$TEST_INDEXSCRIPT:1:13: error: Split delimiter can't be empty"
1043 printf 'in : split=|,foo field=one\nin : field' > "$TEST_INDEXSCRIPT"
1044 test_scriptindex_error "'split' error for invalid operation" \
1045 "$TEST_INDEXSCRIPT:1:14: error: Bad split operation 'foo'"
1047 # Feature tests for scriptindex `hextobin` action.
1048 printf 'hex : hextobin value=0' > "$TEST_INDEXSCRIPT"
1049 test_scriptindex 'HEXTOBIN action' \
1050 'hex=
1052 hex=41
1054 hex=54657374
1056 hex=4b696C6c
1058 printf '$list{$map{$split{$cgi{DOCIDS}},$value{0,$_}},|}' > "$TEST_TEMPLATE"
1059 testcase '|A|Test|Kill' DOCIDS='1 2 3 4'
1061 # Feature test error cases for scriptindex `hextobin` action.
1062 test_scriptindex_error 'bad hex digit' \
1063 "<stdin>:1: error: hextobin: input must be all hex digits" \
1064 'hex=7g'
1065 test_scriptindex_error 'bad hex length' \
1066 "<stdin>:1: error: hextobin: input must have even length" \
1067 'hex=404'
1069 # Feature test for scriptindex `spell` action.
1070 printf '%s\n' 's : spell index' 'n : index' > "$TEST_INDEXSCRIPT"
1071 test_scriptindex 'SPELL action' \
1072 's=some words test\n\nn=tent\n\n'
1073 printf '$set{flag_spelling_correction,true}$suggestion' > "$TEST_TEMPLATE"
1074 testcase 'some test' P='home nest'
1075 testcase 'a test' P='a tent'
1076 testcase '' P='gent'
1078 # Feature tests for scriptindex `squash` and `ltrim`/`rtrim`/`trim` actions.
1079 printf 'squash : squash field\nltrim : ltrim field\nrtrim : rtrim field\ntrim : trim field\n' > "$TEST_INDEXSCRIPT"
1080 whitespace_test=`printf "\t lots\v\fof\t whitespace\f "`
1081 test_scriptindex 'SQUASH and trim actions' \
1082 "squash=$whitespace_test
1083 ltrim=$whitespace_test
1084 rtrim=$whitespace_test
1085 trim=$whitespace_test
1087 squash=a b
1088 ltrim=a b
1089 rtrim=a b
1090 trim=a b
1092 squash=xyz
1093 ltrim=xyz
1094 rtrim=xyz
1095 trim=xyz
1097 printf '$json{$field{$cgi{F},$cgi{ID}}}' > "$TEST_TEMPLATE"
1098 testcase 'lots of whitespace' F=squash ID=1
1099 testcase 'lots\u000b\fof\t whitespace\f ' F=ltrim ID=1
1100 testcase '\t lots\u000b\fof\t whitespace' F=rtrim ID=1
1101 testcase 'lots\u000b\fof\t whitespace' F=trim ID=1
1102 for f in squash ltrim rtrim trim ; do
1103 testcase 'a b' F=$f ID=2
1104 testcase 'xyz' F=$f ID=3
1105 done
1107 # Feature tests for scriptindex `truncate` action.
1108 printf 'x : field=x truncate=9 field=9 truncate=3 field=3 truncate=2 field=2 truncate=1 field=1 truncate=0 field=0\n' > "$TEST_INDEXSCRIPT"
1109 test_scriptindex 'TRUNCATE action' \
1110 'x=really long field
1112 x=xö xxxxö x
1114 x=ö xxxxö x
1116 x=x x xx🥝 x
1118 x=a test
1120 x=tri
1122 x=du
1128 printf '$foreach{$split{1 2 3 4 5 6 7 8 9},$set{d,$_}$list{$map{$split{x 9 3 2 1 0},$field{$_,$opt{d}}},|}:}' > "$TEST_TEMPLATE"
1129 testcase 'really long field|really|rea|re|r|:xö xxxxö x|xö|xö|x|x|:ö xxxxö x|ö xxxxö|ö|ö||:x x xx🥝 x|x x|x x|x|x|:a test|a test|a|a|a|:tri|tri|tri|tr|t|:du|du|du|du|d|:1|1|1|1|1|:|||||:'
1131 # Feature tests for scriptindex `unhtml` action.
1132 printf '%s\n' 't : unhtml field=h' > "$TEST_INDEXSCRIPT"
1133 test_scriptindex 'UNHTML action' \
1134 't=<b>No</b>table
1136 t=<p>foo</p>d<p>bar<B>b</B></p>
1138 printf '$list{$map{$split{$cgi{DOCIDS}},$field{h,$_}},|}' > "$TEST_TEMPLATE"
1139 testcase "`printf 'Notable|foo\rd\rbarb'`" DOCIDS='1 2'
1141 # Feature test for scriptindex `weight` action.
1142 printf '%s\n' 't : index' 'w : weight=2 index' > "$TEST_INDEXSCRIPT"
1143 test_scriptindex 'WEIGHT action' \
1144 't=test
1146 w=test
1148 t=test test test'
1149 printf '|$hitlist{$id|}' > "$TEST_TEMPLATE"
1150 testcase '|3|2|1|' P=test
1152 # Test bad parameter values to `weight` action.
1153 printf 'foo : weight=-2 index weight=1.5 index=A weight=-1.5 index=B' > "$TEST_INDEXSCRIPT"
1154 test_scriptindex_error "bad 'weight' parameter" \
1155 "$TEST_INDEXSCRIPT:1:14: error: Index action 'weight' takes a non-negative integer argument
1156 $TEST_INDEXSCRIPT:1:30: error: Index action 'weight' takes a non-negative integer argument
1157 $TEST_INDEXSCRIPT:1:49: error: Index action 'weight' takes a non-negative integer argument"
1159 # Test useless action warnings.
1160 printf 'foo : index weight=2' > "$TEST_INDEXSCRIPT"
1161 test_scriptindex_warning "useless 'weight' action" \
1162 "$TEST_INDEXSCRIPT:1:13: warning: Index action 'weight' has no effect*"
1164 printf 'foo : weight=2 weight=3 index' > "$TEST_INDEXSCRIPT"
1165 test_scriptindex_warning "useless 'weight' action" \
1166 "$TEST_INDEXSCRIPT:1:7: warning: Index action 'weight' has no effect*"
1168 printf 'foo : index lower' > "$TEST_INDEXSCRIPT"
1169 test_scriptindex_warning "useless 'lower' action" \
1170 "$TEST_INDEXSCRIPT:1:13: warning: Index action 'lower' has no effect*"
1172 # Test bad fieldname errors.
1173 printf 'foo *bar _bar b!ar: index' > "$TEST_INDEXSCRIPT"
1174 test_scriptindex_error 'bad field names' \
1175 "$TEST_INDEXSCRIPT:1:5: error: field name must start with alphanumeric
1176 $TEST_INDEXSCRIPT:1:10: error: field name must start with alphanumeric
1177 $TEST_INDEXSCRIPT:1:16: error: bad character '!' in field name"
1179 # Test unwanted action argument.
1180 printf 'foo : spell=test index' > "$TEST_INDEXSCRIPT"
1181 test_scriptindex_error 'unwanted action argument' \
1182 "$TEST_INDEXSCRIPT:1:12: error: Index action 'spell' doesn't take an argument"
1184 # Test missing closing quote.
1185 printf '%s\n' 'foo : index="XFOO' 'bar : index="XFOO\"' > "$TEST_INDEXSCRIPT"
1186 test_scriptindex_error 'missing closing quote' \
1187 "$TEST_INDEXSCRIPT:1:18: error: No closing quote
1188 $TEST_INDEXSCRIPT:2:20: error: No closing quote"
1190 # Feature tests for scriptindex `termprefix` and `unprefix` actions.
1191 printf '$termprefix{$cgi{B}}|$unprefix{$cgi{B}}' > "$TEST_TEMPLATE"
1192 testcase '|' B=''
1193 testcase '|something' B='something'
1194 testcase '|42' B='42'
1195 testcase '|3bad' B='3bad'
1196 testcase '|&something' B='&something'
1197 testcase '|:something' B=':something'
1198 testcase 'H|example.org' B='Hexample.org'
1199 testcase 'K|tag' B='Ktag'
1200 testcase 'K|Capital' B='KCapital'
1201 testcase 'K|:colon-tag' B='K:colon-tag'
1202 testcase 'K|:Capital' B='K:Capital'
1203 testcase 'XCOLOUR|red' B='XCOLOURred'
1204 testcase 'XPUNC|:colon' B='XPUNC::colon'
1205 testcase 'XPUNC|internal:colon' B='XPUNC:internal:colon'
1206 testcase 'XPUNC|:Colon' B='XPUNC::Colon'
1207 testcase 'XCASE|Upper' B='XCASE:Upper'
1208 testcase 'XCASE|TITLE' B='XCASE:TITLE'
1209 testcase 'XNUM|42' B='XNUM42'
1210 testcase 'XNUM|3bad' B='XNUM3bad'
1212 # Regression test for $truncate with maxlen < the length of the indicator
1213 # string.
1214 printf '$truncate{$cgi{input},$cgi{maxlen},$cgi{ind},$cgi{ind2}}$seterror{$opt{error}}' > "$TEST_TEMPLATE"
1215 testcase 'w...' input='wwwwww' maxlen=4 ind='...' ind2='...'
1216 testcase '' input='s' maxlen=0 ind='...' ind2='...'
1218 # Feature tests for scriptindex `unique` action.
1219 printf '%s\n' 'id : boolean=Q unique=Q' 'id f : field' > "$TEST_INDEXSCRIPT"
1220 test_scriptindex 'UNIQUE action' \
1221 'id=1
1222 f=wan
1224 id=2
1225 f=too
1227 id=3
1228 f=free
1230 id=4
1231 f=fore
1233 id=1
1234 f=one
1236 id=2
1238 id=4
1241 id=3
1242 dummy='
1243 printf '$field{id,$cgi{id}}|$field{f,$cgi{id}}$error' > "$TEST_TEMPLATE"
1244 testcase '1|one' id=1
1245 # Since 1.5.0, document 2 gets deleted instead.
1246 testcase '2|' id=2
1247 testcase '3|' id=3
1248 testcase '4|' id=4
1250 # Test `unique` action warning.
1251 printf '%s\n' 'id : unique=Q boolean=W' 'id f : field' > "$TEST_INDEXSCRIPT"
1252 test_scriptindex_warning 'unique without boolean' \
1253 "$TEST_INDEXSCRIPT:1:6: warning: Index action 'unique=Q' without 'boolean=Q'
1254 $TEST_INDEXSCRIPT:1:6: note: 'unique' doesn't implicitly add a boolean term"
1256 # Test `unique` action gives error when not used for a record.
1257 printf '%s\n' 'id : boolean=Q unique=Q' 'id f : field' > "$TEST_INDEXSCRIPT"
1258 test_scriptindex_warning 'missing unique field' \
1259 "<stdin>:4: warning: UNIQUE action unused in this record" \
1260 'id=1\nf=wan\n\nf=\n'
1262 # Test $subdb and $subid.
1263 rm -rf "$TEST_DB"
1264 printf 'inmemory' > "$TEST_DB"
1265 printf 'inmemory' > "${TEST_DB}2"
1266 printf 'inmemory\ninmemory\n' > "${TEST_DB}3"
1267 printf '$subdb{$cgi{ID}}|$subid{$cgi{ID}}' > "$TEST_TEMPLATE"
1268 testcase "$TEST_DB|1" ID=1
1269 testcase "$TEST_DB|1" ID=1 DB="$TEST_DB/${TEST_DB}2"
1270 testcase "${TEST_DB}2|1" ID=2 DB="$TEST_DB/${TEST_DB}2"
1271 testcase "${TEST_DB}|2" ID=3 DB="$TEST_DB/${TEST_DB}2"
1272 testcase "${TEST_DB}3|1" ID=1 DB="${TEST_DB}3"
1273 testcase "${TEST_DB}3|999" ID=999 DB="${TEST_DB}3"
1274 testcase "$TEST_DB|1" ID=1 DB="$TEST_DB" DB="${TEST_DB}3"
1275 testcase "${TEST_DB}3|1" ID=2 DB="$TEST_DB" DB="${TEST_DB}3"
1276 testcase "${TEST_DB}3|2" ID=3 DB="$TEST_DB" DB="${TEST_DB}3"
1277 testcase "$TEST_DB|2" ID=4 DB="$TEST_DB" DB="${TEST_DB}3"
1278 testcase "${TEST_DB}3|3" ID=5 DB="$TEST_DB" DB="${TEST_DB}3"
1279 rm -rf "${TEST_DB}2" "${TEST_DB}3"
1281 # Feature tests for $field.
1282 printf 'in : field="zer\0byte" hextobin field="field28\x02\x08"' > "$TEST_INDEXSCRIPT"
1283 rm -rf "$TEST_DB"
1284 $SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" > /dev/null <<'END'
1285 in=4071004f3456
1287 printf '$json{$field{zer$chr{0}byte,1}}|$json{$field{field28$chr{2}$chr{8},1}}|$error' > "$TEST_TEMPLATE"
1288 testcase '4071004f3456|@q\u0000O4V|'
1290 # Feature tests for $jsonarray.
1291 printf '%s, %s, %s, %s, %s' \
1292 '$jsonarray{}' \
1293 '$jsonarray{,$upper{$_}}' \
1294 '$jsonarray{$split{b4 k9},"$json{$upper{$_}}"}' \
1295 '$jsonarray{$split{a "b" c:\}}' \
1296 '$jsonarray{$split{2 3 5 7},$mul{$_,$_}}' > "$TEST_TEMPLATE"
1297 testcase '[], [], ["B4","K9"], ["a","\"b\"","c:\\"], [4,9,25,49]'
1299 # Feature tests for $jsonbool
1300 printf '%s' '$jsonbool{} $jsonbool{$eq{a,b}} $jsonbool{x} $jsonbool{0}' > "$TEST_TEMPLATE"
1301 testcase 'false false true true'
1303 # Feature tests for $jsonobject
1304 printf '%s' '$jsonobject{foo}' > "$TEST_TEMPLATE"
1305 testcase '{}'
1306 printf '%s' '$setmap{foo,Han,Solo}$jsonobject{foo}' > "$TEST_TEMPLATE"
1307 testcase '{"Han":"Solo"}'
1308 printf '%s' '$setmap{foo,key 1,value1,key"2,value\2,key3,value3}$jsonobject{foo}' > "$TEST_TEMPLATE"
1309 testcase '{"key 1":"value1","key\"2":"value\\2","key3":"value3"}'
1310 printf '%s' '$setmap{foo,key 1,1,key"2,$split{1 2},key3,$split{2 3 5}}$jsonobject{foo,,$jsonarray{$_,$add{$_,1}}}' > "$TEST_TEMPLATE"
1311 testcase '{"key 1":[2],"key\"2":[2,3],"key3":[3,4,6]}'
1312 printf '%s' '$setmap{foo,key 1,,key"2,1,key3,0}$jsonobject{foo,$upper{$_},$jsonarray{$_,$add{$_}}}' > "$TEST_TEMPLATE"
1313 testcase '{"KEY 1":[],"KEY\"2":[1],"KEY3":[0]}'
1315 # Feature tests for $stoplist
1316 printf '%s' '$setmap{prefix,foo,XFOO}[$list{$stoplist,|}]' > "$TEST_TEMPLATE"
1317 testcase '[a|the]' P.XFOO='the test' P='a test'
1319 # Feature tests for $unstem
1320 printf '%s' '$setmap{prefix,foo,XFOO}[$list{$unstem{$cgi{TERM}},|}]' > "$TEST_TEMPLATE"
1321 testcase '[pots|pot|potting]' P.XFOO='(foo:pot OR luck) (potting OR shed)' P='flower OR foo:pots' TERM=ZXFOOpot
1323 # Feature tests of scriptindex.
1325 # Regression test: non-zero exit status for unknown option.
1326 if $SCRIPTINDEX --to-be-or-not-to-be "$TEST_DB" "$TEST_INDEXSCRIPT" > /dev/null < /dev/null 2>&1; then
1327 echo "scriptindex didn't give error for unknown option"
1328 failed=`expr $failed + 1`
1331 # Regression test: error given for multiple `unique` actions.
1332 printf 'id : boolean=Q unique=Q\nguid : boolean=G unique=G' > "$TEST_INDEXSCRIPT"
1333 test_scriptindex_error 'UNIQUE used more than once'\
1334 "$TEST_INDEXSCRIPT:2:18: error: Index action 'unique' used more than once
1335 $TEST_INDEXSCRIPT:1:16: note: Previously used here"
1337 # Test we check for hash's argument being an integer (new in 1.4.6).
1338 printf 'url : hash=37.3 boolean=Q unique=Q' > "$TEST_INDEXSCRIPT"
1339 test_scriptindex_error "'hash' with a non-integer argument" \
1340 "$TEST_INDEXSCRIPT:1:14: error: Index action 'hash' takes an integer argument"
1342 # Test we give a helpful error for an action with a digit in (regression
1343 # test for fix in 1.4.6).
1345 # This used to give the confusing:
1346 # Unknown index action ''
1347 printf 'url : index4' > "$TEST_INDEXSCRIPT"
1348 test_scriptindex_error 'bad index action with a digit' \
1349 "$TEST_INDEXSCRIPT:1:7: error: Unknown index action 'index4'"
1351 # Test we give a helpful error if an = sign is missed out before an optional
1352 # numeric argument (regression test for fix in 1.4.6).
1354 # This used to give the confusing:
1355 # Unknown index action ''
1356 printf 'url : hash 42' > "$TEST_INDEXSCRIPT"
1357 test_scriptindex_error 'missing equals sign' \
1358 "$TEST_INDEXSCRIPT:1:12: error: Unknown index action '42'"
1360 # Test we warn about spaces before and after '='.
1362 # This has never been documented as supported, and was deprecated in 1.4.6
1363 # because it resulted in this quietly using `hash` as the field name, which is
1364 # probably not what was intended:
1366 # url : field= hash boolean=Q unique=Q
1367 printf 'url : field= hash boolean=Q unique=Q' > "$TEST_INDEXSCRIPT"
1368 test_scriptindex_warning 'space after "="' \
1369 "$TEST_INDEXSCRIPT:1:13: warning: putting spaces between '=' and the argument is deprecated"
1371 printf 'url : field =link' > "$TEST_INDEXSCRIPT"
1372 test_scriptindex_warning 'space before "="' \
1373 "$TEST_INDEXSCRIPT:1:12: warning: putting spaces between the action and '=' is deprecated"
1375 # Feature tests for scriptindex `date` action.
1376 printf '%s\n' 'd : date=unix' 'g : date=unixutc' > "$TEST_INDEXSCRIPT"
1377 # `date=unix` works in the current timezone, so set that explicitly so the
1378 # build doesn't fail if run in a timezone which is behind UTC.
1379 TZ=UTC test_scriptindex 'DATE action' \
1380 'd=\n\nd=0\n\nd=1541478429'
1381 printf '$list{$map{$range{1,3},$list{$allterms{$_}, }},|}' > "$TEST_TEMPLATE"
1382 testcase '|D19700101 M197001 Y1970|D20181106 M201811 Y2018'
1384 # `date=unixutc` should always work in UTC regardless of the current timezone.
1385 test_scriptindex 'DATE action with unixutc' \
1386 'g=\n\ng=0\n\ng=1541478429'
1387 testcase '|D19700101 M197001 Y1970|D20181106 M201811 Y2018'
1389 # Check nested $hitlist{} doesn't result in an infinite loop.
1390 # Regression test for bug fixed in 1.4.12.
1391 printf '<|$hitlist{$id(:$hitlist{$id:})|}>' > "$TEST_TEMPLATE"
1392 testcase '<|2(:2:3:)|3(:2:3:)|>' B=Y1970 B=Y2018
1394 # Feature tests for scriptindex `parsedate` action.
1395 printf '%s\n' 'DATE : field parsedate=%Y%m%d valuepacked=13' > "$TEST_INDEXSCRIPT"
1396 test_scriptindex 'PARSEDATE action' \
1397 'DATE=19891204'
1398 printf '$field{DATE,1}|$unpack{$value{13,1}}|$date{$unpack{$value{13,1}}}' > "$TEST_TEMPLATE"
1399 testcase '19891204|628732800|1989-12-04' P=text
1401 # Feature tests for scriptindex `parsedate` action.
1402 printf '%s\n' \
1403 'DATE: parsedate="%Y%m%d %T" field=time' \
1404 'TIME_T: parsedate=%s field=time' > "$TEST_INDEXSCRIPT"
1405 test_scriptindex_warning 'PARSEDATE action' \
1406 '<stdin>:2: warning: "20161202 12:04:22.000000" not fully matched by format "%Y%m%d %T" (".000000" left over) but indexing anyway' \
1407 'DATE=20161202 12:04:22.000000\n\nTIME_T=1480680263'
1408 printf '$field{time,$cgi{id}}' > "$TEST_TEMPLATE"
1409 # Test format which contains a space.
1410 testcase '1480680262' id=1
1411 # Regression test - we used to add on the local timezone offset.
1412 testcase '1480680263' id=2
1414 if grep -q 'define HAVE_STRUCT_TM_TM_GMTOFF 1' config.h ; then
1415 # Feature tests for scriptindex `parsedate` action.
1416 printf '%s\n' 'DATE: parsedate="%Y%m%d %T %z" field=time' > "$TEST_INDEXSCRIPT"
1417 test_scriptindex 'PARSEDATE action with %z' \
1418 'DATE=20161202 21:34:22 +0930'
1419 printf '$field{time,$cgi{id}}' > "$TEST_TEMPLATE"
1420 # Test that timezone adjustment is applied.
1421 testcase '1480680262' id=1
1422 else
1423 echo "Skipping testcases which need tm_gmtoff member in struct tm"
1426 # Feature tests for scriptindex `valuenumeric` action.
1427 printf '%s\n' 'n : field valuenumeric=0' > "$TEST_INDEXSCRIPT"
1428 test_scriptindex 'VALUENUMERIC action' \
1429 'n=0\n\nn=1.75\n\nn=-1000000000'
1430 printf '$list{$map{$range{1,3},$url{$value{0,$_}}},:}' > "$TEST_TEMPLATE"
1431 testcase '%80:%A3:%1F%A4FS%60'
1433 # Feature tests for scriptindex `load` action.
1434 printf '%s\n' 'file : load field' > "$TEST_INDEXSCRIPT"
1435 test_scriptindex_warning 'empty filename in load action' \
1436 "<stdin>:1: warning: Empty filename in LOAD action" \
1437 'file='
1439 # Feature tests for quoted arguments.
1440 printf 'DATE : field=" spaces " date="yyyymmdd"\nTEXT: index="S"\n' > "$TEST_INDEXSCRIPT"
1441 test_scriptindex 'quoted arguments' \
1442 'DATE=19891204\nTEXT=This is sample text.\nNEXT=work'
1443 printf '$freq{D19891204}|$field{ spaces ,1}' > "$TEST_TEMPLATE"
1444 testcase '1|19891204' P.S=text
1445 # Use $time to force the match to run.
1446 printf '$if{x$time,$freq{D19891204}}|$field{ spaces ,1}' > "$TEST_TEMPLATE"
1447 testcase '1|19891204' P=
1449 # Feature tests for escaping in quoted arguments.
1450 printf '%s\n' 'esc : field="\tesca\x70e,test\\\""' > "$TEST_INDEXSCRIPT"
1451 test_scriptindex 'escaping in quoted arguments' \
1452 'esc=test'
1453 printf '$field{$chr{9}escape$.test\\",1}' > "$TEST_TEMPLATE"
1454 testcase 'test' P=
1455 printf '%s\n' 'x: split="xx\' 'y: split="xx\q"' > "$TEST_INDEXSCRIPT"
1456 test_scriptindex_error "bad escape sequences" \
1457 "$TEST_INDEXSCRIPT:1:14: error: Bad escaping in quoted action argument
1458 $TEST_INDEXSCRIPT:2:14: error: Bad escape sequence '\\\\q'"
1459 # Ensure the location of the problem is always in the same column so we can
1460 # test against a fixed error message including line and column.
1461 for badesc in \
1462 '"\x1"' \
1463 '"z\xg1"' \
1464 '"z\xg"' \
1465 '"z\x"' \
1466 '"\x1g"' \
1467 ; do
1468 printf '%s' "x: split=$badesc" > "$TEST_INDEXSCRIPT"
1469 test_scriptindex_error "bad hex digit in escape: '$badesc'" \
1470 "$TEST_INDEXSCRIPT:1:14: error: Bad hex digit in escaping"
1471 done
1473 # Regression test that a closing " with junk after is flagged.
1474 printf 'date : field="test"index' > "$TEST_INDEXSCRIPT"
1475 test_scriptindex_error "junk after closing quote" \
1476 "$TEST_INDEXSCRIPT:1:20: error: Unexpected character 'i' after closing quote"
1478 # Test we warn about useless actions.
1479 printf 'date : field parsedate=%%Y%%m%%d' > "$TEST_INDEXSCRIPT"
1480 test_scriptindex_warning "useless 'parsedate'" \
1481 "$TEST_INDEXSCRIPT:1:14: warning: Index action 'parsedate' has no effect*"
1483 # Test a `parsedate` format error.
1484 printf 'date : parsedate="%%Y\t%%m\t%%d\t%%Z" field' > "$TEST_INDEXSCRIPT"
1485 test_scriptindex_error "'%Z' in 'parsedate' format" \
1486 "$TEST_INDEXSCRIPT:1:28: error: Parsing timezone names with %Z is not supported"
1488 # Test scriptindex `gap` action inserts a termpos gap.
1489 printf 'text : index gap=5' > "$TEST_INDEXSCRIPT"
1490 test_scriptindex 'GAP action' \
1491 'text=foo\ntext=bar\ntext=baz'
1492 echo '|$hitlist{$id|}' > "$TEST_TEMPLATE"
1493 testcase '|' 'P="foo bar"'
1494 testcase '|' 'P=foo NEAR/5 bar'
1495 testcase '|' 'P=foo NEAR/11 baz'
1496 testcase '|1|' 'P=foo NEAR/6 bar'
1497 testcase '|1|' 'P=foo NEAR/12 baz'
1499 # The scriptindex `hash` action should require its argument is >= 6, so test 5
1500 # is rejected.
1501 printf 'url : hash=5 boolean=Q unique=Q' > "$TEST_INDEXSCRIPT"
1502 test_scriptindex_error 'bad HASH argument' \
1503 "$TEST_INDEXSCRIPT:1:12: error: Index action 'hash' takes an integer argument which must be at least 6"
1505 # And that 6 is accepted.
1506 printf 'url : hash=6 boolean=Q unique=Q' > "$TEST_INDEXSCRIPT"
1507 test_scriptindex 'hash=6' \
1508 'url=http://xapian.org'
1510 # Regression test to check `hash` works without argument (it was failing with
1511 # an assertion in unreleased versions prior to 1.4.6).
1512 printf 'url : hash boolean=Q unique=Q' > "$TEST_INDEXSCRIPT"
1513 test_scriptindex 'HASH without argument' \
1514 'url=http://xapian.org'
1516 # Test the same actions for multiple fields works (briefly broken in git master
1517 # before 1.5.0).
1518 printf 'tag1 tag2 tag3 : boolean=T field' > "$TEST_INDEXSCRIPT"
1519 test_scriptindex 'multiple fields on an action line' \
1520 'tag1=one\ntag2=two\ntag3=three'
1521 printf '$hitlist{$list{$terms{T},|}/$field{tag1}|$field{tag2}|$field{tag3}}' > "$TEST_TEMPLATE"
1522 testcase 'Tone/one|two|three' B=Tone
1523 testcase 'Tthree|Ttwo/one|two|three' B=Ttwo B=Tthree
1525 rm "$OMEGA_CONFIG_FILE" "$TEST_INDEXSCRIPT" "$TEST_TEMPLATE"
1526 rm -rf "$TEST_DB"
1527 if [ "$failed" = 0 ] ; then
1528 exit 0
1530 echo "Failed $failed test(s)"
1531 exit 1