Fix comment typo
[xapian.git] / xapian-applications / omega / omegatest
blob05926576485426360abc33f6ad558644d3f71de9
1 #!/bin/sh
2 # omegatest: Test omega CGI
4 # Copyright (C) 2015,2016,2017,2018,2019,2020,2021 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 failed=0
58 testcase() {
59 expected=$1
60 shift
61 # If there are no positional parameters, pass one as otherwise omega will
62 # wait for parameters on stdin.
63 [ "$#" != 0 ] || { set x dummy; shift; }
65 if [ -n "$FAKE_NOW" ] ; then
66 if [ -n "${TZ+set}" ] ; then
67 output=`TZ=$TZ $FAKETIME -f "$FAKE_NOW" "$OMEGA" "$@"`
68 else
69 output=`$FAKETIME -f "$FAKE_NOW" "$OMEGA" "$@"`
71 else
72 output=`"$OMEGA" "$@"`
75 if [ "$output" != "$expected" ] ; then
76 echo "$OMEGA $@:"
77 printf '%s\n' " expected: «${expected}»"
78 printf '%s\n' " received: «${output}»"
79 failed=`expr $failed + 1`
83 qtestcase() {
84 expected="Query($1)"
85 shift
86 testcase "$expected" "$@"
89 unset FAKE_NOW
91 # Test a few simple things.
92 qtestcase 'Zsimpl@1' P=simple
93 qtestcase '(chocolate@1 FILTER Tconfectionary/fudge)' P=Chocolate B=Tconfectionary/fudge
95 # Test date value ranges.
96 qtestcase 'VALUE_RANGE 0 2 ~' DATEVALUE=0 START=2000
97 qtestcase 'VALUE_RANGE 0 2 ~' DATEVALUE=0 START=200001
98 qtestcase 'VALUE_RANGE 0 2 ~' DATEVALUE=0 START=20000101
99 qtestcase 'VALUE_LE 1 1~' DATEVALUE=1 END=1999
100 qtestcase 'VALUE_LE 1 1~' DATEVALUE=1 END=199912
101 qtestcase 'VALUE_LE 1 1~' DATEVALUE=1 END=19991231
102 qtestcase 'VALUE_RANGE 2 201 ~' DATEVALUE=2 START=2010
103 qtestcase 'VALUE_RANGE 2 201 ~' DATEVALUE=2 START=201001
104 qtestcase 'VALUE_RANGE 2 201 ~' DATEVALUE=2 START=20100101
105 qtestcase 'VALUE_LE 3 198~' DATEVALUE=3 END=1989
106 qtestcase 'VALUE_LE 3 198~' DATEVALUE=3 END=198912
107 qtestcase 'VALUE_LE 3 198~' DATEVALUE=3 END=19891231
108 qtestcase 'VALUE_RANGE 4 1974 ~' DATEVALUE=4 START=1974
109 qtestcase 'VALUE_RANGE 4 1974 ~' DATEVALUE=4 START=197401
110 qtestcase 'VALUE_RANGE 4 1974 ~' DATEVALUE=4 START=19740101
111 qtestcase 'VALUE_LE 5 1974~' DATEVALUE=5 END=1974
112 qtestcase 'VALUE_LE 5 1974~' DATEVALUE=5 END=197412
113 qtestcase 'VALUE_LE 5 1974~' DATEVALUE=5 END=19741231
114 qtestcase 'VALUE_RANGE 6 20151 ~' DATEVALUE=6 START=201510
115 qtestcase 'VALUE_RANGE 6 20151 ~' DATEVALUE=6 START=20151001
116 qtestcase 'VALUE_LE 7 19870~' DATEVALUE=7 END=198709
117 qtestcase 'VALUE_LE 7 19870~' DATEVALUE=7 END=19870930
118 qtestcase 'VALUE_RANGE 8 201512 ~' DATEVALUE=8 START=201512
119 qtestcase 'VALUE_RANGE 8 201512 ~' DATEVALUE=8 START=20151201
120 qtestcase 'VALUE_LE 9 201511~' DATEVALUE=9 END=201511
121 qtestcase 'VALUE_LE 9 201511~' DATEVALUE=9 END=20151130
122 qtestcase 'VALUE_RANGE 10 2015021 ~' DATEVALUE=10 START=20150210
123 qtestcase 'VALUE_RANGE 10 2000022 ~' DATEVALUE=10 START=20000220
124 qtestcase 'VALUE_LE 11 19840401~' DATEVALUE=11 END=19840401
125 qtestcase 'VALUE_LE 11 19881128~' DATEVALUE=11 END=19881128
127 # Leap year tests:
128 qtestcase 'VALUE_LE 1 201502~' DATEVALUE=1 END=20150228
129 qtestcase 'VALUE_LE 1 198802~' DATEVALUE=1 END=19880229
130 qtestcase 'VALUE_LE 1 19880228~' DATEVALUE=1 END=19880228
131 qtestcase 'VALUE_LE 1 200002~' DATEVALUE=1 END=20000229
132 qtestcase 'VALUE_LE 1 20000228~' DATEVALUE=1 END=20000228
133 # FIXME: These two currently require 64-bit time_t:
134 #qtestcase 'VALUE_LE 1 190002~' DATEVALUE=1 END=19000228
135 #qtestcase 'VALUE_LE 1 210002~' DATEVALUE=1 END=21000228
137 # Month starts and ends:
138 qtestcase 'VALUE_RANGE 0 2015 201501~' DATEVALUE=0 START=20150101 END=20150131
139 qtestcase 'VALUE_RANGE 0 2015 20150130~' DATEVALUE=0 START=20150101 END=20150130
140 qtestcase 'VALUE_RANGE 0 201502 201502~' DATEVALUE=0 START=20150201 END=20150228
141 qtestcase 'VALUE_RANGE 0 201502 20150227~' DATEVALUE=0 START=20150201 END=20150227
142 qtestcase 'VALUE_RANGE 0 201503 201503~' DATEVALUE=0 START=20150301 END=20150331
143 qtestcase 'VALUE_RANGE 0 201503 20150330~' DATEVALUE=0 START=20150301 END=20150330
144 qtestcase 'VALUE_RANGE 0 201504 201504~' DATEVALUE=0 START=20150401 END=20150430
145 qtestcase 'VALUE_RANGE 0 201504 2015042~' DATEVALUE=0 START=20150401 END=20150429
146 qtestcase 'VALUE_RANGE 0 201505 201505~' DATEVALUE=0 START=20150501 END=20150531
147 qtestcase 'VALUE_RANGE 0 201505 20150530~' DATEVALUE=0 START=20150501 END=20150530
148 qtestcase 'VALUE_RANGE 0 201506 201506~' DATEVALUE=0 START=20150601 END=20150630
149 qtestcase 'VALUE_RANGE 0 201506 2015062~' DATEVALUE=0 START=20150601 END=20150629
150 qtestcase 'VALUE_RANGE 0 201507 201507~' DATEVALUE=0 START=20150701 END=20150731
151 qtestcase 'VALUE_RANGE 0 201507 20150730~' DATEVALUE=0 START=20150701 END=20150730
152 qtestcase 'VALUE_RANGE 0 201508 201508~' DATEVALUE=0 START=20150801 END=20150831
153 qtestcase 'VALUE_RANGE 0 201508 20150830~' DATEVALUE=0 START=20150801 END=20150830
154 qtestcase 'VALUE_RANGE 0 201509 20150~' DATEVALUE=0 START=20150901 END=20150930
155 qtestcase 'VALUE_RANGE 0 201509 2015092~' DATEVALUE=0 START=20150901 END=20150929
156 qtestcase 'VALUE_RANGE 0 20151 201510~' DATEVALUE=0 START=20151001 END=20151031
157 qtestcase 'VALUE_RANGE 0 20151 20151030~' DATEVALUE=0 START=20151001 END=20151030
158 qtestcase 'VALUE_RANGE 0 201511 201511~' DATEVALUE=0 START=20151101 END=20151130
159 qtestcase 'VALUE_RANGE 0 201511 2015112~' DATEVALUE=0 START=20151101 END=20151129
160 qtestcase 'VALUE_RANGE 0 201512 2015~' DATEVALUE=0 START=20151201 END=20151231
161 qtestcase 'VALUE_RANGE 0 201512 20151230~' DATEVALUE=0 START=20151201 END=20151230
163 # Forward spans:
164 qtestcase 'VALUE_RANGE 0 20151104 20151106~' DATEVALUE=0 START=20151104 SPAN=3
165 qtestcase 'VALUE_RANGE 0 20141104 20151103~' DATEVALUE=0 START=20141104 SPAN=365
167 # Backward spans:
168 qtestcase 'VALUE_RANGE 0 20151104 20151106~' DATEVALUE=0 END=20151106 SPAN=3
169 qtestcase 'VALUE_RANGE 0 20141104 20151103~' DATEVALUE=0 END=20151103 SPAN=365
171 # Check that if START, END and SPAN are all passed, START is ignored:
172 qtestcase 'VALUE_RANGE 0 20151104 20151106~' DATEVALUE=0 START=19700101 END=20151106 SPAN=3
174 # Test date value ranges using newer ".SLOT" parameters.
175 qtestcase 'VALUE_RANGE 0 2 ~' START.0=2000
176 qtestcase 'VALUE_RANGE 0 2 ~' START.0=200001
177 qtestcase 'VALUE_RANGE 0 2 ~' START.0=20000101
178 qtestcase 'VALUE_LE 1 1~' END.1=1999
179 qtestcase 'VALUE_LE 1 1~' END.1=199912
180 qtestcase 'VALUE_LE 1 1~' END.1=19991231
181 qtestcase 'VALUE_RANGE 2 201 ~' START.2=2010
182 qtestcase 'VALUE_RANGE 2 201 ~' START.2=201001
183 qtestcase 'VALUE_RANGE 2 201 ~' START.2=20100101
184 qtestcase 'VALUE_LE 3 198~' END.3=1989
185 qtestcase 'VALUE_LE 3 198~' END.3=198912
186 qtestcase 'VALUE_LE 3 198~' END.3=19891231
187 qtestcase 'VALUE_RANGE 4 1974 ~' START.4=1974
188 qtestcase 'VALUE_RANGE 4 1974 ~' START.4=197401
189 qtestcase 'VALUE_RANGE 4 1974 ~' START.4=19740101
190 qtestcase 'VALUE_LE 5 1974~' END.5=1974
191 qtestcase 'VALUE_LE 5 1974~' END.5=197412
192 qtestcase 'VALUE_LE 5 1974~' END.5=19741231
193 qtestcase 'VALUE_RANGE 6 20151 ~' START.6=201510
194 qtestcase 'VALUE_RANGE 6 20151 ~' START.6=20151001
195 qtestcase 'VALUE_LE 7 19870~' END.7=198709
196 qtestcase 'VALUE_LE 7 19870~' END.7=19870930
197 qtestcase 'VALUE_RANGE 8 201512 ~' START.8=201512
198 qtestcase 'VALUE_RANGE 8 201512 ~' START.8=20151201
199 qtestcase 'VALUE_LE 9 201511~' END.9=201511
200 qtestcase 'VALUE_LE 9 201511~' END.9=20151130
201 qtestcase 'VALUE_RANGE 10 2015021 ~' START.10=20150210
202 qtestcase 'VALUE_RANGE 10 2000022 ~' START.10=20000220
203 qtestcase 'VALUE_LE 11 19840401~' END.11=19840401
204 qtestcase 'VALUE_LE 11 19881128~' END.11=19881128
206 # Leap year tests:
207 qtestcase 'VALUE_LE 1 201502~' END.1=20150228
208 qtestcase 'VALUE_LE 1 198802~' END.1=19880229
209 qtestcase 'VALUE_LE 1 19880228~' END.1=19880228
210 qtestcase 'VALUE_LE 1 200002~' END.1=20000229
211 qtestcase 'VALUE_LE 1 20000228~' END.1=20000228
212 # FIXME: These two currently require 64-bit time_t:
213 #qtestcase 'VALUE_LE 1 190002~' END.1=19000228
214 #qtestcase 'VALUE_LE 1 210002~' END.1=21000228
216 # Month starts and ends:
217 qtestcase 'VALUE_RANGE 0 2015 201501~' START.0=20150101 END.0=20150131
218 qtestcase 'VALUE_RANGE 0 2015 20150130~' START.0=20150101 END.0=20150130
219 qtestcase 'VALUE_RANGE 0 201502 201502~' START.0=20150201 END.0=20150228
220 qtestcase 'VALUE_RANGE 0 201502 20150227~' START.0=20150201 END.0=20150227
221 qtestcase 'VALUE_RANGE 0 201503 201503~' START.0=20150301 END.0=20150331
222 qtestcase 'VALUE_RANGE 0 201503 20150330~' START.0=20150301 END.0=20150330
223 qtestcase 'VALUE_RANGE 0 201504 201504~' START.0=20150401 END.0=20150430
224 qtestcase 'VALUE_RANGE 0 201504 2015042~' START.0=20150401 END.0=20150429
225 qtestcase 'VALUE_RANGE 0 201505 201505~' START.0=20150501 END.0=20150531
226 qtestcase 'VALUE_RANGE 0 201505 20150530~' START.0=20150501 END.0=20150530
227 qtestcase 'VALUE_RANGE 0 201506 201506~' START.0=20150601 END.0=20150630
228 qtestcase 'VALUE_RANGE 0 201506 2015062~' START.0=20150601 END.0=20150629
229 qtestcase 'VALUE_RANGE 0 201507 201507~' START.0=20150701 END.0=20150731
230 qtestcase 'VALUE_RANGE 0 201507 20150730~' START.0=20150701 END.0=20150730
231 qtestcase 'VALUE_RANGE 0 201508 201508~' START.0=20150801 END.0=20150831
232 qtestcase 'VALUE_RANGE 0 201508 20150830~' START.0=20150801 END.0=20150830
233 qtestcase 'VALUE_RANGE 0 201509 20150~' START.0=20150901 END.0=20150930
234 qtestcase 'VALUE_RANGE 0 201509 2015092~' START.0=20150901 END.0=20150929
235 qtestcase 'VALUE_RANGE 0 20151 201510~' START.0=20151001 END.0=20151031
236 qtestcase 'VALUE_RANGE 0 20151 20151030~' START.0=20151001 END.0=20151030
237 qtestcase 'VALUE_RANGE 0 201511 201511~' START.0=20151101 END.0=20151130
238 qtestcase 'VALUE_RANGE 0 201511 2015112~' START.0=20151101 END.0=20151129
239 qtestcase 'VALUE_RANGE 0 201512 2015~' START.0=20151201 END.0=20151231
240 qtestcase 'VALUE_RANGE 0 201512 20151230~' START.0=20151201 END.0=20151230
242 # Forward spans:
243 qtestcase 'VALUE_RANGE 0 20151104 20151106~' START.0=20151104 SPAN.0=3
244 qtestcase 'VALUE_RANGE 0 20141104 20151103~' START.0=20141104 SPAN.0=365
246 # Backward spans:
247 qtestcase 'VALUE_RANGE 0 20151104 20151106~' END.0=20151106 SPAN.0=3
248 qtestcase 'VALUE_RANGE 0 20141104 20151103~' END.0=20151103 SPAN.0=365
250 # Empty spans:
251 qtestcase '' START.0=20180919 END.0=19991225
252 # Check that the empty span dominates other spans:
253 qtestcase '' START.0=20180919 END.0=19991225 START.1=20180901
254 # Check that the empty span dominates a filter term:
255 qtestcase '' START.0=20180919 END.0=19991225 B=Ktag
256 # Check that the empty span dominates a negated filter term:
257 qtestcase '' START.0=20180919 END.0=19991225 N=Kneg
258 # Check that the empty span dominates a term-based date range filter:
259 qtestcase '' START.0=20180919 END.0=19991225 START=20000101 END=20001231
261 # Check that if START, END and SPAN are all passed, START is ignored:
262 qtestcase 'VALUE_RANGE 0 20151104 20151106~' START.0=19700101 END.0=20151106 SPAN.0=3
264 # Check multiple .SLOT filters:
265 qtestcase '(VALUE_RANGE 0 201512 2015~ AND VALUE_LE 5 1974~)' START.0=20151201 END.0=20151231 END.5=1974
266 qtestcase '(VALUE_RANGE 0 201512 20151207~ AND VALUE_RANGE 5 19740102 1974~)' START.0=20151201 SPAN.0=7 END.5=1974 SPAN.5=364
268 # Check .SLOT and old-style value date range filter:
269 qtestcase '(VALUE_RANGE 0 201512 2015~ AND VALUE_LE 5 1974~)' START.0=20151201 END.0=20151231 DATEVALUE=5 END=1974
271 # Check .SLOT and old-style value date range filter on same slot.
272 # (We don't promise anything for this case, but it shouldn't crash).
273 qtestcase '(VALUE_RANGE 0 201512 2015~ AND VALUE_LE 0 1974~)' START.0=20151201 END.0=20151231 DATEVALUE=0 END=1974
275 # Tests of term-based date range filtering:
277 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
278 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
279 qtestcase '(Y1970 OR Y1971 OR Y1972 OR Y1973 OR Y1974 OR Dlatest)' END=19741231
280 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
281 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
282 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
283 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
285 # Leap year tests:
286 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
287 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
288 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
289 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
290 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
291 # FIXME: These two currently require 64-bit time_t:
292 #qtestcase 'Dlatest' END=19000228 # Assumed start is 19700101
293 #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
295 # Month starts and ends:
296 qtestcase '(M201501 OR Dlatest)' START=20150101 END=20150131
297 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
298 qtestcase '(M201502 OR Dlatest)' START=20150201 END=20150228
299 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
300 qtestcase '(M201503 OR Dlatest)' START=20150301 END=20150331
301 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
302 qtestcase '(M201504 OR Dlatest)' START=20150401 END=20150430
303 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
304 qtestcase '(M201505 OR Dlatest)' START=20150501 END=20150531
305 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
306 qtestcase '(M201506 OR Dlatest)' START=20150601 END=20150630
307 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
308 qtestcase '(M201507 OR Dlatest)' START=20150701 END=20150731
309 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
310 qtestcase '(M201508 OR Dlatest)' START=20150801 END=20150831
311 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
312 qtestcase '(M201509 OR Dlatest)' START=20150901 END=20150930
313 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
314 qtestcase '(M201510 OR Dlatest)' START=20151001 END=20151031
315 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
316 qtestcase '(M201511 OR Dlatest)' START=20151101 END=20151130
317 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
318 qtestcase '(M201512 OR Dlatest)' START=20151201 END=20151231
319 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
321 # Forward spans:
322 qtestcase '(D20151104 OR D20151105 OR D20151106 OR D20151107 OR Dlatest)' START=20151104 SPAN=3
323 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
325 # Backward spans:
326 qtestcase '(D20151103 OR D20151104 OR D20151105 OR D20151106 OR Dlatest)' END=20151106 SPAN=3
327 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
329 # Check that if START, END and SPAN are all passed, START is ignored:
330 qtestcase '(D20151103 OR D20151104 OR D20151105 OR D20151106 OR Dlatest)' START=19700101 END=20151106 SPAN=3
332 # Check that YYYYMM and YYYY are accepted and handled appropriately:
333 qtestcase '(Y1980 OR Y1981 OR Dlatest)' START=1980 END=1981
334 qtestcase '(M198012 OR M198101 OR M198102 OR Dlatest)' START=198012 END=198102
336 # Check .SLOT combined with term based date range filter:
337 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
339 # Check combining of filter terms:
340 qtestcase '(Horg AND Len)' B=Len B=Horg
341 qtestcase '(Len OR Lde)' B=Len B=Lde
342 qtestcase '((Horg OR Hcom) AND (Len OR Lfr))' B=Len B=Lfr B=Horg B=Hcom
344 # Check combining of filter terms with filter_op set:
345 printf '$setmap{nonexclusiveprefix,L,1,XAND,1}$setmap{boolprefix,lang,L,and,XAND,host,H,year,Y}$querydescription' > "$TEST_TEMPLATE"
346 qtestcase 'Len' B=Len
347 qtestcase '0 * Len' P=lang:en
348 qtestcase 'XANDtest' B=XANDtest
349 qtestcase '0 * XANDtest' P=and:test
350 qtestcase '(Len AND XANDtest)' B=Len B=XANDtest
351 qtestcase '0 * (Len AND XANDtest)' P='lang:en and:test'
352 qtestcase '(Len AND Lde)' B=Len B=Lde
353 qtestcase '0 * (Len AND Lde)' P='lang:en lang:de'
354 qtestcase '((Horg OR Hcom) AND (Len AND Lfr))' B=Len B=Lfr B=Horg B=Hcom
355 qtestcase '0 * ((Len AND Lfr) AND (Horg OR Hcom))' P='lang:en lang:fr host:org host:com'
356 qtestcase '((XANDa AND XANDb AND XANDc) AND (Y1998 OR Y2001))' B=Y1998 B=Y2001 B=XANDa B=XANDb B=XANDc
357 qtestcase '0 * ((XANDa AND XANDb AND XANDc) AND (Y1998 OR Y2001))' P='year:1998 year:2001 and:a and:b and:c'
359 # Check combining of filters around CGI parameter 'N':
360 qtestcase '(Ztruth@1 AND_NOT Epdf)' P=truth N=Epdf
361 qtestcase '(Ztruth@1 AND_NOT (Ehtm OR Epdf))' P=truth N=Epdf N=Ehtm
362 qtestcase '(Ztruth@1 AND_NOT (Ehtm OR Epdf OR Lde OR Lfr))' P=truth N=Lfr N=Epdf N=Ehtm N=Lde
363 qtestcase '((Ztruth@1 FILTER (Lfr AND Lzh)) AND_NOT (Lde OR Len))' P=truth N=Lde N=Len B=Lfr B=Lzh
364 qtestcase '((Ztruth@1 FILTER Lfr) AND_NOT (Ehtm OR Epdf))' P=truth N=Epdf N=Ehtm B=Lfr
365 qtestcase '(<alldocuments> AND_NOT (Len OR Lfr))' N=Lfr N=Len
366 qtestcase '(VALUE_RANGE 0 2015 201501~ AND_NOT Len)' DATEVALUE=0 START=20150101 END=20150131 N=Len
368 # If faketime is available and works, test cases where the output depends on
369 # "now".
370 rc=0
371 out=`[ -n "$FAKETIME" ] && $FAKETIME -f '1980-12-08 00:00:00' date +%Y 2>&1` || rc=$?
372 if [ "$rc:$out" = "0:1980" ] ; then
373 FAKE_NOW='2015-11-28 06:07:08'
374 TZ=UTC qtestcase 'VALUE_RANGE 0 20151127060709 20151128060708' DATEVALUE=0 SPAN=1
376 # Tests of term-based date range filtering:
377 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
378 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
379 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
380 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
381 # Date range with start after end:
382 qtestcase 'Dlatest' START=201512
383 qtestcase 'Dlatest' START=20151201
384 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
385 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
386 unset FAKE_NOW
387 else
388 if [ "$rc" = 127 ] ; then
389 echo "Skipping testcases which need 'faketime' tool installed"
390 elif [ -z "$FAKETIME" ] ; then
391 echo "Skipping testcases which need 'faketime' tool - \$FAKETIME is empty"
392 else
393 echo "Skipping testcases which need 'faketime' tool - it's installed but doesn't work"
397 # Check clamping of out of range dates:
398 printf '%s\n' 'DATE : field valuepacked=0' > "$TEST_INDEXSCRIPT"
399 rm -rf "$TEST_DB"
400 $SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" > /dev/null <<'END'
401 DATE=0
403 DATE=1617069804
405 qtestcase 'VALUE_LE 0 V\x84o\xff' START.0=10010101 END.0=20151230
406 qtestcase 'VALUE_RANGE 0 V\x83\x1e\x80 \xff\xff\xff\xff' START.0=20151230 END.0=21060301
407 qtestcase 'VALUE_LE 0 \xff\xff\xff\xff' START.0=19691230 END.0=21060301
409 # Test stem_all and stem_strategy.
410 printf '$if{$cgi{stem_all},$set{stem_all,$cgi{stem_all}}}$if{$cgi{stem_strategy},$set{stem_strategy,$cgi{stem_strategy}}}$querydescription' > "$TEST_TEMPLATE"
411 qtestcase '(capitalised@1 AND tests@2 AND Zstem@3)' P='Capitalised "tests" stemmed'
412 qtestcase '(nearing@1 NEAR 11 distances@2)' P='nearing NEAR distances'
413 qtestcase '(capitalis@1 AND test@2 AND stem@3)' P='Capitalised "tests" stemmed' stem_all=true
414 qtestcase '(near@1 NEAR 11 distanc@2)' P='nearing NEAR distances' stem_all=true
415 qtestcase '(capitalis@1 AND test@2 AND stem@3)' P='Capitalised "tests" stemmed' stem_strategy=all
416 qtestcase '(near@1 NEAR 11 distanc@2)' P='nearing NEAR distances' stem_strategy=all
417 qtestcase '(Zcapitalis@1 AND Ztest@2 AND Zstem@3)' P='Capitalised "tests" stemmed' stem_strategy=all_z
418 qtestcase '(Znear@1 NEAR 11 Zdistanc@2)' P='nearing NEAR distances' stem_strategy=all_z
419 qtestcase '(capitalised@1 AND tests@2 AND stemmed@3)' P='Capitalised "tests" stemmed' stem_strategy=none
420 qtestcase '(nearing@1 NEAR 11 distances@2)' P='nearing NEAR distances' stem_strategy=none
421 qtestcase '(capitalised@1 AND tests@2 AND Zstem@3)' P='Capitalised "tests" stemmed' stem_strategy=some
422 qtestcase '(nearing@1 NEAR 11 distances@2)' P='nearing NEAR distances' stem_strategy=some
423 qtestcase '(capitalised@1 AND tests@2 AND Zstem@3)' P='Capitalised "tests" stemmed' stem_strategy=some_full_pos
424 qtestcase '(Znear@1 NEAR 11 Zdistanc@2)' P='nearing NEAR distances' stem_strategy=some_full_pos
425 qtestcase '(capitalised@1 AND tests@2 AND Zstem@3)' P='Capitalised "tests" stemmed' stem_strategy=some stem_all=true
426 qtestcase '(nearing@1 NEAR 11 distances@2)' P='nearing NEAR distances' stem_strategy=some stem_all=true
428 # Feature tests for $contains.
429 printf '$contains{$cgi{a},$cgi{b}}' > "$TEST_TEMPLATE"
430 testcase '6' P=text a=fish b="Hello fish"
431 testcase '' P=text a="Example" b="random"
433 NEWLINE='
436 # Feature tests for boolprefix and prefix maps.
437 printf '$set{stemmer,}$setmap{boolprefix,lang,L,host,H}$setmap{prefix,,XDEFAULT}$querydescription' > "$TEST_TEMPLATE"
438 qtestcase '((XDEFAULTfoo@1 AND XDEFAULTbar@2) FILTER (Hexample.org AND Lzh))' P='host:example.org foo bar lang:zh'
440 # Feature tests for $addfilter.
441 printf '$addfilter{Hexample.org}$addfilter{Hexample.com,}$addfilter{XFOObar,B}$querydescription' > "$TEST_TEMPLATE"
442 qtestcase '((Hexample.org OR Hexample.com) AND XFOObar)' P=
443 printf '$addfilter{Hexample.org}$addfilter{Hexample.com,N}$addfilter{Hexample.net,N}$querydescription' > "$TEST_TEMPLATE"
444 qtestcase '(Hexample.org AND_NOT (Hexample.com OR Hexample.net))' P=
446 # Feature tests for $if.
447 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"
448 testcase '1111'
450 # Feature tests for $cond.
451 printf '$cond{$cgi{one},1,$cgi{two},2,$cgi{three},3}' > "$TEST_TEMPLATE"
452 testcase '1' one=true
453 testcase '2' two=true
454 testcase '3' three=true
455 testcase '' nothing=true
456 testcase '1' one=true two=true three=true
457 testcase '2' two=true three=true
458 printf '$cond{$cgi{one},1,$cgi{two},2,$cgi{alt}}' > "$TEST_TEMPLATE"
459 testcase '1' one=true
460 testcase '2' two=true
461 testcase 'none' alt=none
462 # Check evaluation is lazy.
463 printf '$cond{$cgi{one},$seterror{err1},$cgi{two},2,$cgi{alt}}$error' > "$TEST_TEMPLATE"
464 testcase 'err1' one=true
465 testcase '2' two=true
466 testcase 'none' alt=none
467 printf '$cond{$cgi{one},1,$cgi{two},$seterror{err2},$cgi{alt}}$error' > "$TEST_TEMPLATE"
468 testcase '1' one=true
469 testcase 'err2' two=true
470 testcase 'none' alt=none
471 printf '$cond{$cgi{one},1,$cgi{two},2,$seterror{erralt}}$error' > "$TEST_TEMPLATE"
472 testcase '1' one=true
473 testcase '2' two=true
474 testcase 'erralt' alt=none
476 # Feature tests for $switch.
477 printf '$switch{$cgi{x},1,one,2,two}' > "$TEST_TEMPLATE"
478 testcase 'one' x=1
479 testcase 'two' x=2
480 testcase '' x=3
481 printf '$switch{$cgi{x},1,one,2,two,default}' > "$TEST_TEMPLATE"
482 testcase 'one' x=1
483 testcase 'two' x=2
484 testcase 'default' x=3
485 # Check evaluation is lazy.
486 printf '$switch{$cgi{x},1,$seterror{err1},2,two}$error' > "$TEST_TEMPLATE"
487 testcase 'err1' x=1
488 testcase 'two' x=2
489 testcase '' x=3
490 printf '$switch{$cgi{x},1,one,2,$seterror{err2},default}$error' > "$TEST_TEMPLATE"
491 testcase 'one' x=1
492 testcase 'err2' x=2
493 testcase 'default' x=3
494 printf '$switch{$cgi{x},1,one,2,two,$seterror{errdefault}}$error' > "$TEST_TEMPLATE"
495 testcase 'one' x=1
496 testcase 'two' x=2
497 testcase 'errdefault' x=3
499 # Feature tests for $include.
500 # Test inclusion works and evaluates the included file.
501 printf '$set{c,$add{$or{$opt{c},0},1}}$opt{c},$if{$lt{$opt{c},10},$include{'"$TEST_TEMPLATE"'}}X' > "$TEST_TEMPLATE"
502 testcase '1,2,3,4,5,6,7,8,9,10,XXXXXXXXXX'
503 # Test fallback action when trying to $include a file which doesn't exist or
504 # with a prohibited name.
505 printf '$include{$cgi{template},foo$set{data,bar}}-$opt{data}' > "$TEST_TEMPLATE"
506 testcase 'foo-bar' template=non_existent.template
507 testcase 'foo-bar' template=../secret/file
508 # Test exception is thrown when there's no fallback action when trying to
509 # $include a file which doesn't exist or with a prohibited name.
510 printf '$include{$cgi{template}}-$opt{data}' > "$TEST_TEMPLATE"
511 testcase "Exception: Couldn't read format template 'non_existent.template' (No such file or directory)" template=non_existent.template
512 testcase "Exception: Couldn't read format template '../secret/file' (name contains '..')" template=../secret/file
514 # Feature tests for $foreach.
515 printf '$foreach{$split{.,$cgi{a}},$chr{$add{$_,64}}}' > "$TEST_TEMPLATE"
516 testcase 'OMEGA' a=15.13.5.7.1
517 # Check that the outer $_ is restored after the inner $foreach.
518 printf '$foreach{$split{.,$cgi{a}},$foreach{$split{.,$cgi{$_}},$chr{$add{$_,64}}}$_}' > "$TEST_TEMPLATE"
519 testcase 'OMbEGcAd' a=b.c.d b=15.13 c=5.7 d=1
521 # Feature tests for $map.
522 printf '$list{$map{$split{-,$cgi{a}},$list{$map{$split{,$cgi{b}},$_},-}},|}' > "$TEST_TEMPLATE"
523 testcase '1-2-3|1-2-3' P=text a=ab-cd b=123
524 printf '$list{$map{$split{-,$cgi{a}},$set{__,$_}$list{$map{$split{,$cgi{b}},$opt{__}$_},-}},|}' > "$TEST_TEMPLATE"
525 testcase 'a1-a2-a3|b1-b2-b3' P=text a=a-b b=123
526 printf '$list{$map{$split{-,$cgi{a}},$list{$map{$split{$_,$cgi{b}},$_},-}},|}' > "$TEST_TEMPLATE"
527 testcase '1-2,3|1:2-3' P=text a=':-,' b='1:2,3'
528 # Check that the outer $_ is restored after the inner $map.
529 printf '$list{$map{$split{-,$cgi{a}},$list{$map{$split{,$cgi{b}},$_},-}$_},|}' > "$TEST_TEMPLATE"
530 testcase '1-2-3a|1-2-3b' P=text a='a-b' b='123'
532 # Feature tests for $match.
533 printf '$match{$cgi{a},$cgi{b},$cgi{c}}' > "$TEST_TEMPLATE"
534 testcase 'true' P=text a="ab*c+" b="ac"
535 testcase '' P=text a="acb" b="abc"
536 testcase 'true' P=text a="[A-Z]bcD" b="abcd" c="i"
537 testcase '' P=text a="[A-Z]bcD" b="abcd"
538 testcase 'true' P=text a="^abc$" b="${NEWLINE}abc${NEWLINE}def" c="m"
539 testcase '' P=text a="^abc$" b="${NEWLINE}abc${NEWLINE}def"
540 testcase 'true' P=text a="abc." b="abc${NEWLINE}" c="s"
541 testcase '' P=text a="abc." b="abc${NEWLINE}"
542 testcase 'true' P=text a=" ABC #test_comment " b="ABC" c="x"
543 testcase '' P=text a=" ABC #test_comment " b="ABC"
545 # Feature tests for $sort.
546 printf '$list{$sort{$split{|,$cgi{input}}},|}' > "$TEST_TEMPLATE"
547 testcase 'pineapple' input="pineapple"
548 testcase 'apple|banana|coconut' input="coconut|banana|apple"
549 testcase '1|b|b|c' input="b|c|b|1"
550 printf '$list{$sort{$split{|,$cgi{input}},$cgi{opt}},|}' > "$TEST_TEMPLATE"
551 testcase 'pineapple' input="pineapple" opt=
552 testcase 'pineapple' input="pineapple" opt=r
553 testcase 'pineapple' input="pineapple" opt=ru
554 testcase '1|b|c' input="b|c|b|1" opt=u
555 testcase 'c|b|b|1' input="b|c|b|1" opt=r
556 testcase 'c|b|1' input="b|c|b|1" opt=ur
557 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
558 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
559 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
560 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
561 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
562 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
563 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='#'
564 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' \
565 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' \
566 opt='#'
567 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'
568 testcase 'Exception: Unknown $sort option: x' input="b|c|b|1" opt=urx
569 testcase 'Exception: Invalid $sort option combination: n#' input="b|c" opt='n#'
570 testcase 'Exception: Invalid $sort option combination: #rn' input="b|1" opt='#rn'
572 # Regression test to test suppression of Content-Type header for early
573 # exception.
574 rm -rf "$TEST_DB"
575 echo 'inmemory' > "$TEST_DB"
576 testcase 'Exception: DocNotFoundError: Docid 1 not found' MORELIKE=1
578 # Regression test for $sort bug fixed in 1.4.12.
579 # Check $sort doesn't ensure_match (or ensure_query).
580 printf '$sort{test} $addfilter{Test}$querydescription' > "$TEST_TEMPLATE"
581 testcase 'test Query(Test)'
583 # Feature tests for $keys.
584 printf '$setmap{x,bee,1,eel,6,dog,4,ant,2,fox,5,cat,3}/$list{$keys{x},|}/$keys{nosuch}/' > "$TEST_TEMPLATE"
585 testcase '/ant|bee|cat|dog|eel|fox//'
587 # Feature tests for $terms.
588 printf 'text : index\nhost : boolean=H\nfoo : boolean=XFOO' > "$TEST_INDEXSCRIPT"
589 rm -rf "$TEST_DB"
590 $SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" > /dev/null <<'END'
591 text=This is some text.
592 host=example.org
593 foo=bar
595 printf '$hitlist{$list{$if{$eq{$cgi{prefix},null},$terms,$terms{$cgi{prefix}}},|}}' > "$TEST_TEMPLATE"
596 testcase 'Ztext' P=text B=Hexample.org B=Hexample.com prefix=null
597 testcase 'Hexample.org|Ztext' P=text B=Hexample.org B=Hexample.com prefix=
598 testcase 'Hexample.org' P=text B=Hexample.org B=Hexample.com prefix=H
599 testcase 'Ztext' P=text B=Hexample.org B=Hexample.com prefix=Z
600 testcase '' P=text B=Hexample.org B=Hexample.com prefix=E
602 printf '$msizelower $msize $msizeupper $msizeexact' > "$TEST_TEMPLATE"
603 testcase '1 1 1 true' P=this
604 testcase '1 1 1 true' P='Some text'
605 testcase '0 0 0 true' P=potato
607 printf '$set{weighting,coord}$hitlist{$weight.}' > "$TEST_TEMPLATE"
608 testcase '' P=aardvark
609 testcase '1.000000.' P=texting
610 testcase '' P='texting while driving'
611 testcase '' P='texting while driving' DEFAULTOP=AND
612 testcase '1.000000.' P='texting while driving' DEFAULTOP=OR
613 testcase '2.000000.' P='Some text'
614 # "this" and "is" are stopwords.
615 testcase '2.000000.' P='This is some text'
616 testcase '4.000000.' P='"This" "is" some text'
617 testcase '4.000000.' P='+This +is some text'
618 testcase '4.000000.' P='"This is some text"'
620 printf '$set{weightingpurefilter,coord}$hitlist{$weight.}' > "$TEST_TEMPLATE"
621 testcase '' B=XFOOfoo
622 testcase '1.000000.' B=Hexample.org
623 testcase '' B=Hexample.org B=XFOOfoo
624 testcase '1.000000.' B=Hexample.org B=Hexample.net
625 testcase '2.000000.' B=Hexample.org B=XFOObar
626 testcase '3.000000.' B=Hexample.org B=XFOObar B=XFOObar
628 printf '$filters' > "$TEST_TEMPLATE"
629 testcase 'Hexample.net~Hexample.org~.~~' B=Hexample.org B=Hexample.net
630 testcase '!Gmisc.test~.~~' N=Gmisc.test
631 testcase 'Hexample.net~Hexample.org~!Gmisc.test~.~~' B=Hexample.org B=Hexample.net N=Gmisc.test
632 testcase '.20040612~~~1~' DATEVALUE=1 START=20040612
633 testcase '.20040612~~~1~2' DATEVALUE=1 START=20040612 COLLAPSE=2
634 testcase '.20040612~~30~2' START=20040612 SPAN=30 COLLAPSE=2
635 testcase '.20040612~20160412~' START=20040612 END=20160412
636 testcase '.~~~2' COLLAPSE=2
637 testcase '.~~'
638 testcase '.~~1' SORT=1
639 testcase '.~~1f' SORT=+1
640 testcase '.~~1' SORT=-1
641 testcase '.~~1-2+3-27' SORT=+1-2+03,-27
642 testcase '.~~' SORTREVERSE=1
643 testcase '.~~1f' SORT=1 SORTREVERSE=1
644 testcase '.~~1' SORT=+1 SORTREVERSE=1
645 testcase '.~~1f' SORT=-1 SORTREVERSE=1
646 testcase '.~~1-2+3-27f' SORT=+1-2+03,-27 SORTREVERSE=1
647 testcase '.~~' SORTAFTER=1
648 testcase '.~~1R' SORT=1 SORTAFTER=1
649 testcase '.~~1F' SORT=+1 SORTAFTER=1
650 testcase '.~~1R' SORT=-1 SORTAFTER=1
651 testcase '.~~1-2+3-27R' SORT=+1-2+03,-27 SORTAFTER=1
652 testcase '.~~' SORTREVERSE=1 SORTAFTER=1
653 testcase '.~~1F' SORT=1 SORTREVERSE=1 SORTAFTER=1
654 testcase '.~~1R' SORT=+1 SORTREVERSE=1 SORTAFTER=1
655 testcase '.~~1F' SORT=-1 SORTREVERSE=1 SORTAFTER=1
656 testcase '.~~1-2+3-27F' SORT=+1-2+03,-27 SORTREVERSE=1 SORTAFTER=1
657 testcase '.~~X' DOCIDORDER=A # Buggy, but kept for compatibility.
658 testcase '.~~D' DOCIDORDER=D
659 testcase '.~~' DOCIDORDER=X # Buggy, but kept for compatibility.
660 testcase '.~~' DOCIDORDER=x # Buggy, but kept for compatibility.
662 tab=`printf '\t'`
663 printf '$cgi{AZ}|$cgi{AZ B}|$cgi{AZ.x}|$cgi{AZ.y}|$cgi{[}|$cgi{#}' > "$TEST_TEMPLATE"
664 testcase 'AZ|||||' AZ.x=3 AZ.y=4
665 testcase 'B|||||' 'AZ B.x=5' 'AZ B.y=12'
666 testcase 'B|||||' "AZ${tab}B.x=5" "AZ${tab}B.y=12"
667 testcase '||||2 ]|' '[ 2 ].x=123'
668 testcase '||||2 ]|' "[${tab}2 ].x=123"
669 testcase "||||2${tab}]|" "[ 2${tab}].x=123"
670 testcase "||||2${tab}]|" "[${tab}2${tab}].x=123"
671 testcase '|||||12' '12.x=37'
672 testcase 'DE|||||' 'AZ BC=DE'
673 testcase 'DE|||||' 'AZ B C=DE'
674 testcase 'DE|||||' "AZ${tab}BC=DE"
675 testcase 'DE|||||' "AZ B${tab}C=DE"
676 testcase 'DE|||||' "AZ${tab}B C=DE"
677 testcase 'DE|||||' "AZ${tab}B${tab}C=DE"
679 printf '$cgi{Search}|$cgi{Type}|$cgi{Search Type}' > "$TEST_TEMPLATE"
680 testcase 'Discover-List||' 'Search Type=Discover-List'
682 printf '$cgiparams' > "$TEST_TEMPLATE"
683 # We can't test the "no cgi parameters" case via testcase, as it passes a
684 # "dummy" parameter if there aren't any real ones.
685 #testcase ""
686 testcase "" =1
687 testcase "ABC" ABC=1
688 testcase "ABC" ABC=1 ABC=2
689 testcase "A${tab}AZ${tab}Z" A=1 A=2 A=3 AZ=1 AZ=2 Z=xxx
690 testcase "${tab}abc" =1 abc=1
691 testcase "${tab}abc${tab}def" =1 abc=1 def=7
693 # Feature tests for $highlight{}.
694 printf '$highlight{$cgi{text},$cgi{list}}' > "$TEST_TEMPLATE"
695 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"
697 printf '$highlight{$cgi{text},$cgi{list},$cgi{open}}' > "$TEST_TEMPLATE"
698 testcase 'A list of <b>words</b>' list="words" text="A list of words" open="<b>"
699 testcase 'A list of <span>words</span>' list="words" text="A list of words" open="<span>"
701 printf '$highlight{$cgi{text},$cgi{list},$cgi{open},$cgi{close}}' > "$TEST_TEMPLATE"
702 testcase 'A list of <b>words</b>' list="words" text="A list of words" open="<b>" close="</b>"
703 testcase 'A *list* of *words*' list="words${tab}list" text="A list of words" open="*" close="*"
705 # Test setting seterror and mset size, should not run the query after setting error.
706 printf '$if{$cgi{ERR},$seterror{$cgi{ERR}}}$msize$if{$error,!$error!}' > "$TEST_TEMPLATE"
707 testcase '1' P=text
708 testcase '0!boo!' P=text ERR=boo
710 # Test arguments inside seterror are evaluated
711 printf '$set{error,sample error}$seterror{$opt{error}}$msize$if{$error,!$error!}' > "$TEST_TEMPLATE"
712 testcase '0!sample error!' P=text
714 # Test error message doesn't get sent through HTML entity encoding.
715 printf '$seterror{{ "error": true, "error_message": "Parameter cannot be > 9" }}$if{$error,$error}' > "$TEST_TEMPLATE"
716 testcase '{ "error": true, "error_message": "Parameter cannot be > 9" }' P=text
718 # Test msize when error set after running query, should not affect running of query.
719 printf '$last$if{$cgi{ERR},$seterror{$cgi{ERR}}}$msize$if{$error,!$error!}' > "$TEST_TEMPLATE"
720 testcase '11' P=text
721 testcase '11!boo!' P=text ERR=boo
723 # Feature tests for $base64{}
724 printf '$base64{$cgi{in}}' > "$TEST_TEMPLATE"
725 testcase '' in=""
726 testcase 'IQ==' in='!'
727 testcase 'T2s=' in='Ok'
728 testcase 'aGA+aGA/' in='h`>h`?'
729 testcase 'YmFzZTY0IHRlc3Q=' in='base64 test'
731 # Regression test: $setrelevant crashed with no argument list prior to 1.4.16.
732 printf '$setrelevant$or{$error,No error}' > "$TEST_TEMPLATE"
733 testcase 'Exception: too few arguments to $setrelevant' P=text
734 printf '$setrelevant{}$or{$error,No error}' > "$TEST_TEMPLATE"
735 testcase 'No error' P=text
737 # Feature tests for $uniq and $unique{}.
738 printf '$list{$uniq{$split{$cgi{text}}},:}|$list{$unique{$split{$cgi{text}}},:}' > "$TEST_TEMPLATE"
739 testcase '|' text=''
740 testcase 'foo|foo' text='foo'
741 testcase 'apple:banana:cherry|apple:banana:cherry' text='apple apple banana banana banana cherry'
742 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'
743 testcase 'x:y:z:y|x:y:z' text='x y z z y'
745 # Regression test - $map with one argument wasn't rejected cleanly.
746 printf '$map{foo}' > "$TEST_TEMPLATE"
747 testcase 'Exception: too few arguments to $map'
749 # Test MORELIKE CGI parameter.
750 printf '%s\n' 'id : boolean=Q' 'text : index field' > "$TEST_INDEXSCRIPT"
751 rm -rf "$TEST_DB"
752 $SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" > /dev/null <<'END'
753 id=a1
754 text=First document
756 id=b2
757 text=Second article
759 id=c3
760 text=Piece of writing three
762 id=dummy
763 text=Inflating termfreqs since Omega excludes terms with termfreq of one
764 =first document second piece of writing three
766 printf '$querydescription|$query' > "$TEST_TEMPLATE"
767 testcase 'Query((Zfirst@1 OR Zdocument@2))|first document' MORELIKE='Qa1' DEFAULTOP=or
768 testcase 'Query((Zfirst@1 OR Zdocument@2))|first OR document' MORELIKE='Qa1'
769 testcase 'Query((Zfirst@1 OR Zdocument@2))|first OR document' MORELIKE='Qa1' DEFAULTOP=and
770 # Test with docid.
771 testcase 'Query((Zfirst@1 OR Zdocument@2))|first document' MORELIKE='1' DEFAULTOP=OR
772 testcase 'Query((Zfirst@1 OR Zdocument@2))|first OR document' MORELIKE='1'
773 testcase 'Query((Zfirst@1 OR Zdocument@2))|first OR document' MORELIKE='1' DEFAULTOP=phrase
774 # "article" is excluded by OmegaExpandDecider because it has termfreq 1.
775 testcase 'Query(Zsecond@1)|second' MORELIKE='Qb2' DEFAULTOP=or
776 testcase 'Query(Zsecond@1)|second' MORELIKE='Qb2'
777 # "of" is excluded because it's a stopword.
778 testcase 'Query((Zwrite@1 OR Zthree@2 OR Zpiec@3))|writing OR three OR piece' MORELIKE='Qc3'
779 # Test with absent term.
780 testcase 'Query()|' MORELIKE='Qx9'
781 # Test multiple MORELIKE parameters. We need to include the dummy document for
782 # any terms to get a positive weight and be returned.
783 testcase 'Query((Zsecond@1 OR Zfirst@2 OR Zdocument@3))|second OR first OR document' MORELIKE=1 MORELIKE=2 MORELIKE=4
784 testcase 'Query((Zsecond@1 OR Zfirst@2 OR Zdocument@3))|second OR first OR document' MORELIKE=Qa1 MORELIKE=2 MORELIKE=4
785 testcase 'Query((Zsecond@1 OR Zfirst@2 OR Zdocument@3))|second OR first OR document' MORELIKE=Qa1 MORELIKE=Qb2 MORELIKE=Qdummy
787 # Feature tests for scriptindex `index` and `indexnopos` actions.
788 printf '%s\n' 't : index=XT' 'n : indexnopos=XN' > "$TEST_INDEXSCRIPT"
789 rm -rf "$TEST_DB"
790 $SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" > /dev/null <<'END'
791 t=positional text
792 n=no pos here
794 printf '$msize' > "$TEST_TEMPLATE"
795 testcase '1' P.XT='"positional text"'
796 testcase '1' P.XN='no AND pos'
797 testcase '0' P.XN='"no pos"'
799 # Feature tests for scriptindex `split` action.
800 printf 'STATUS : field split=| field=SPLITSTATUS\nSTATUS : field=x' > "$TEST_INDEXSCRIPT"
801 rm -rf "$TEST_DB"
802 $SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" > /dev/null <<'END'
803 STATUS=PENDING|REVIEW
805 printf '$field{STATUS,1}/$field{x,1}/$list{$field{SPLITSTATUS,1},$.}' > "$TEST_TEMPLATE"
806 testcase 'PENDING|REVIEW/PENDING|REVIEW/PENDING,REVIEW' P=text
808 # Feature test for scriptindex `split` action with `dedup` operation.
809 printf 'STATUS : field split=|,dedup field=SPLITSTATUS\n' > "$TEST_INDEXSCRIPT"
810 rm -rf "$TEST_DB"
811 $SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" > /dev/null <<'END'
812 STATUS=REVIEW|PENDING|PENDING|REVIEW
814 printf '$field{STATUS,1}/$list{$field{SPLITSTATUS,1},$.}' > "$TEST_TEMPLATE"
815 testcase 'REVIEW|PENDING|PENDING|REVIEW/REVIEW,PENDING' P=text
817 # Feature test for scriptindex `split` action with `sort` operation.
818 printf 'STATUS : field split=|,sort field=SPLITSTATUS\n' > "$TEST_INDEXSCRIPT"
819 rm -rf "$TEST_DB"
820 $SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" > /dev/null <<'END'
821 STATUS=REVIEW|PENDING|PENDING|REVIEW
823 printf '$field{STATUS,1}/$list{$field{SPLITSTATUS,1},$.}' > "$TEST_TEMPLATE"
824 testcase 'REVIEW|PENDING|PENDING|REVIEW/PENDING,PENDING,REVIEW,REVIEW' P=text
826 # Feature test for scriptindex `split` action with `none` operation.
827 printf 'STATUS : field split=|,none field=SPLITSTATUS\n' > "$TEST_INDEXSCRIPT"
828 rm -rf "$TEST_DB"
829 $SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" > /dev/null <<'END'
830 STATUS=REVIEW|PENDING|PENDING|REVIEW
832 printf '$field{STATUS,1}/$list{$field{SPLITSTATUS,1},$.}' > "$TEST_TEMPLATE"
833 testcase 'REVIEW|PENDING|PENDING|REVIEW/REVIEW,PENDING,PENDING,REVIEW' P=text
835 # Feature test for scriptindex `split` action with `prefixes` operation.
836 printf 'STATUS : field split=|,prefixes field=SPLITSTATUS\n' > "$TEST_INDEXSCRIPT"
837 rm -rf "$TEST_DB"
838 $SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" > /dev/null <<'END'
839 STATUS=REVIEW|PENDING|PENDING|REVIEW
841 printf '$field{STATUS,1}/$list{$field{SPLITSTATUS,1},$.}' > "$TEST_TEMPLATE"
842 testcase 'REVIEW|PENDING|PENDING|REVIEW/REVIEW,REVIEW|PENDING,REVIEW|PENDING|PENDING,REVIEW|PENDING|PENDING|REVIEW' P=text
844 # Feature tests for scriptindex `split` action with no explicit operation.
845 printf 'STATUS : field split=| field=SPLITSTATUS\n' > "$TEST_INDEXSCRIPT"
846 rm -rf "$TEST_DB"
847 $SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" > /dev/null <<'END'
848 STATUS=PENDING|REVIEW|PENDING|REVIEW
850 printf '$field{STATUS,1}/$list{$field{SPLITSTATUS,1},$.}' > "$TEST_TEMPLATE"
851 testcase 'PENDING|REVIEW|PENDING|REVIEW/PENDING,REVIEW,PENDING,REVIEW' P=text
853 # Feature test for scriptindex `split` action with multi-character delimiter.
854 printf 'STATUS : field split=$. field=SPLITSTATUS\n' > "$TEST_INDEXSCRIPT"
855 rm -rf "$TEST_DB"
856 $SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" > /dev/null <<'END'
857 STATUS=PENDING$.$.REVIEW,PENDING$.REVIEW
859 printf '$field{STATUS,1}/$list{$field{SPLITSTATUS,1},|}' > "$TEST_TEMPLATE"
860 testcase 'PENDING$.$.REVIEW,PENDING$.REVIEW/PENDING|REVIEW,PENDING|REVIEW' P=text
862 # Feature test for scriptindex `split` action with multi-character delimiter
863 # with potential overlap.
864 printf 'STATUS : field split=:: field=SPLITSTATUS\n' > "$TEST_INDEXSCRIPT"
865 rm -rf "$TEST_DB"
866 $SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" > /dev/null <<'END'
867 STATUS=::Foo::::Bar:Baz:::Hello::
869 printf '$field{STATUS,1}/$list{$field{SPLITSTATUS,1},|}' > "$TEST_TEMPLATE"
870 testcase '::Foo::::Bar:Baz:::Hello::/Foo|Bar:Baz|:Hello' P=text
872 # Feature test for scriptindex `split` action with multi-character delimiter
873 # with `prefixes` operation.
874 printf 'STATUS : field split=::,prefixes field=SPLITSTATUS\n' > "$TEST_INDEXSCRIPT"
875 rm -rf "$TEST_DB"
876 $SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" > /dev/null <<'END'
877 STATUS=::Foo::::Bar:Baz:::Hello::
879 printf '$field{STATUS,1}/$list{$field{SPLITSTATUS,1},|}' > "$TEST_TEMPLATE"
880 testcase '::Foo::::Bar:Baz:::Hello::/::Foo|::Foo::|::Foo::::Bar:Baz|::Foo::::Bar:Baz:::Hello|::Foo::::Bar:Baz:::Hello::' P=text
882 # Feature test for scriptindex `split` action with quoted `,` delimiter.
883 printf 'STATUS : field split="," field=SPLITSTATUS\n' > "$TEST_INDEXSCRIPT"
884 rm -rf "$TEST_DB"
885 $SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" > /dev/null <<'END'
886 STATUS=PENDING,REVIEW,PENDING,REVIEW
888 printf '$field{STATUS,1}/$list{$field{SPLITSTATUS,1},|}' > "$TEST_TEMPLATE"
889 testcase 'PENDING,REVIEW,PENDING,REVIEW/PENDING|REVIEW|PENDING|REVIEW' P=text
891 # Feature test for nested scriptindex `split` action.
892 printf 'in : split=; field=one lower split="," field=two\nin : field' > "$TEST_INDEXSCRIPT"
893 rm -rf "$TEST_DB"
894 $SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" > /dev/null <<'END'
895 in=a,b,c;10,21,32;XY,YZ
897 printf '$field{in,1}/$list{$field{one,1},|}/$list{$field{two,1},|}' > "$TEST_TEMPLATE"
898 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
900 # Feature tests for scriptindex `hextobin` action.
901 printf 'hex : hextobin value=0' > "$TEST_INDEXSCRIPT"
902 rm -rf "$TEST_DB"
903 $SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" > /dev/null <<'END'
904 hex=
906 hex=41
908 hex=54657374
910 hex=4b696C6c
912 printf '$list{$map{$split{$cgi{DOCIDS}},$value{0,$_}},|}' > "$TEST_TEMPLATE"
913 testcase '|A|Test|Kill' DOCIDS='1 2 3 4'
915 # Feature test error cases for scriptindex `hextobin` action.
916 rm -rf "$TEST_DB"
917 echo hex=7g |\
918 $SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" 2>&1 > /dev/null |\
919 grep -q ":1: error: hextobin: input must be all hex digits" ||\
920 { echo "scriptindex hextobin didn't give error for bad hex digit";\
921 failed=`expr $failed + 1`; }
922 echo hex=404 |\
923 $SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" 2>&1 > /dev/null |\
924 grep -q ":1: error: hextobin: input must have even length" ||\
925 { echo "scriptindex hextobin didn't give error for odd length hex string";\
926 failed=`expr $failed + 1`; }
927 testcase '7g|404' DOCIDS='1 2'
929 # Feature test for scriptindex `spell` action.
930 printf '%s\n' 's : spell index' 'n : index' > "$TEST_INDEXSCRIPT"
931 rm -rf "$TEST_DB"
932 printf '%s\n\n' 's=some words test' 'n=tent'|$SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" > /dev/null
933 printf '$set{flag_spelling_correction,true}$suggestion' > "$TEST_TEMPLATE"
934 testcase 'some test' P='home nest'
935 testcase 'a test' P='a tent'
936 testcase '' P='gent'
938 # Feature tests for scriptindex `squash` and `ltrim`/`rtrim`/`trim` actions.
939 printf 'squash : squash field\nltrim : ltrim field\nrtrim : rtrim field\ntrim : trim field\n' > "$TEST_INDEXSCRIPT"
940 rm -rf "$TEST_DB"
941 whitespace_test=`printf "\t lots\v\fof\t whitespace\f "`
942 $SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" > /dev/null <<END
943 squash=$whitespace_test
944 ltrim=$whitespace_test
945 rtrim=$whitespace_test
946 trim=$whitespace_test
948 squash=a b
949 ltrim=a b
950 rtrim=a b
951 trim=a b
953 squash=xyz
954 ltrim=xyz
955 rtrim=xyz
956 trim=xyz
958 printf '$json{$field{$cgi{F},$cgi{ID}}}' > "$TEST_TEMPLATE"
959 testcase 'lots of whitespace' F=squash ID=1
960 testcase 'lots\u000b\fof\t whitespace\f ' F=ltrim ID=1
961 testcase '\t lots\u000b\fof\t whitespace' F=rtrim ID=1
962 testcase 'lots\u000b\fof\t whitespace' F=trim ID=1
963 for f in squash ltrim rtrim trim ; do
964 testcase 'a b' F=$f ID=2
965 testcase 'xyz' F=$f ID=3
966 done
968 # Feature tests for scriptindex `truncate` action.
969 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"
970 rm -rf "$TEST_DB"
971 $SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" > /dev/null <<END
972 x=really long field
974 x=xö xxxxö x
976 x=ö xxxxö x
978 x=x x xx🥝 x
980 x=a test
982 x=tri
984 x=du
990 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"
991 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|:|||||:'
993 # Feature tests for scriptindex `unhtml` action.
994 printf '%s\n' 't : unhtml field=h' > "$TEST_INDEXSCRIPT"
995 rm -rf "$TEST_DB"
996 $SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" > /dev/null <<'END'
997 t=<b>No</b>table
999 t=<p>foo</p>d<p>bar<B>b</B></p>
1001 printf '$list{$map{$split{$cgi{DOCIDS}},$field{h,$_}},|}' > "$TEST_TEMPLATE"
1002 testcase "`printf 'Notable|foo\rd\rbarb'`" DOCIDS='1 2'
1004 # Feature test for scriptindex `weight` action.
1005 printf '%s\n' 't : index' 'w : weight=2 index' > "$TEST_INDEXSCRIPT"
1006 rm -rf "$TEST_DB"
1007 printf '%s\n\n' 't=test' 'w=test' 't=test test test'|$SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" > /dev/null
1008 printf '|$hitlist{$id|}' > "$TEST_TEMPLATE"
1009 testcase '|3|2|1|' P=test
1011 # Test useless action warnings.
1012 printf 'foo : index weight=2' > "$TEST_INDEXSCRIPT"
1013 rm -rf "$TEST_DB"
1014 if $SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" < /dev/null 2>&1 \
1015 | grep -q ":1:13: warning: Index action 'weight' has no effect" ; then
1016 : # OK
1017 else
1018 echo "scriptindex didn't give expected warning for useless 'weight' action"
1019 failed=`expr $failed + 1`
1021 printf 'foo : weight=2 weight=3 index' > "$TEST_INDEXSCRIPT"
1022 rm -rf "$TEST_DB"
1023 if $SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" < /dev/null 2>&1 \
1024 | grep -q ":1:7: warning: Index action 'weight' has no effect" ; then
1025 : # OK
1026 else
1027 echo "scriptindex didn't give expected warning for useless 'weight' action"
1028 failed=`expr $failed + 1`
1030 printf 'foo : index lower' > "$TEST_INDEXSCRIPT"
1031 rm -rf "$TEST_DB"
1032 if $SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" < /dev/null 2>&1 \
1033 | grep -q ":1:13: warning: Index action 'lower' has no effect" ; then
1034 : # OK
1035 else
1036 echo "scriptindex didn't give expected warning for useless 'lower' action"
1037 failed=`expr $failed + 1`
1040 # Test bad fieldname errors.
1041 printf 'foo *bar : index' > "$TEST_INDEXSCRIPT"
1042 rm -rf "$TEST_DB"
1043 rc=0
1044 out=`$SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" < /dev/null 2>&1` || rc=$?
1045 if [ $rc -eq 0 ] ; then
1046 echo "scriptindex didn't exit with non-zero return code on bad fieldname"
1047 failed=`expr $failed + 1`
1048 elif printf '%s' "$out" \
1049 | grep -q ":1:5: error: field name must start with alphanumeric" ; then
1050 : # OK
1051 else
1052 echo "scriptindex didn't give expected error for a bad fieldname"
1053 failed=`expr $failed + 1`
1055 printf 'foo b!ar : index' > "$TEST_INDEXSCRIPT"
1056 rm -rf "$TEST_DB"
1057 rc=0
1058 out=`$SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" < /dev/null 2>&1` || rc=$?
1059 if [ $rc -eq 0 ] ; then
1060 echo "scriptindex didn't exit with non-zero return code on bad fieldname"
1061 failed=`expr $failed + 1`
1062 elif printf '%s' "$out" \
1063 | grep -q ":1:6: error: bad character '!' in fieldname" ; then
1064 : # OK
1065 else
1066 echo "scriptindex didn't give expected error for a bad fieldname"
1067 failed=`expr $failed + 1`
1070 # Test unwanted action argument.
1071 printf 'foo : spell=test index' > "$TEST_INDEXSCRIPT"
1072 rm -rf "$TEST_DB"
1073 rc=0
1074 out=`$SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" < /dev/null 2>&1` || rc=$?
1075 if [ $rc -eq 0 ] ; then
1076 echo "scriptindex didn't exit with non-zero return code on unwanted action argument"
1077 failed=`expr $failed + 1`
1078 elif printf '%s' "$out" \
1079 | grep -q ":1:12: error: Index action 'spell' doesn't take an argument" ; then
1080 : # OK
1081 else
1082 echo "scriptindex didn't give expected error for unwanted action argument"
1083 failed=`expr $failed + 1`
1086 # Test missing closing quote.
1087 printf 'foo : index="XFOO' > "$TEST_INDEXSCRIPT"
1088 rm -rf "$TEST_DB"
1089 rc=0
1090 out=`$SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" < /dev/null 2>&1` || rc=$?
1091 if [ $rc -eq 0 ] ; then
1092 echo "scriptindex didn't exit with non-zero return code for missing closing quote"
1093 failed=`expr $failed + 1`
1094 elif printf '%s' "$out" \
1095 | grep -q ":1:18: error: No closing quote" ; then
1096 : # OK
1097 else
1098 echo "scriptindex didn't give expected error for missing closing quote"
1099 failed=`expr $failed + 1`
1102 # Feature tests for scriptindex `termprefix` and `unprefix` actions.
1103 printf '$termprefix{$cgi{B}}|$unprefix{$cgi{B}}' > "$TEST_TEMPLATE"
1104 testcase '|' B=''
1105 testcase '|something' B='something'
1106 testcase '|42' B='42'
1107 testcase '|3bad' B='3bad'
1108 testcase '|&something' B='&something'
1109 testcase '|:something' B=':something'
1110 testcase 'H|example.org' B='Hexample.org'
1111 testcase 'K|tag' B='Ktag'
1112 testcase 'K|Capital' B='KCapital'
1113 testcase 'K|:colon-tag' B='K:colon-tag'
1114 testcase 'K|:Capital' B='K:Capital'
1115 testcase 'XCOLOUR|red' B='XCOLOURred'
1116 testcase 'XPUNC|:colon' B='XPUNC::colon'
1117 testcase 'XPUNC|internal:colon' B='XPUNC:internal:colon'
1118 testcase 'XPUNC|:Colon' B='XPUNC::Colon'
1119 testcase 'XCASE|Upper' B='XCASE:Upper'
1120 testcase 'XCASE|TITLE' B='XCASE:TITLE'
1121 testcase 'XNUM|42' B='XNUM42'
1122 testcase 'XNUM|3bad' B='XNUM3bad'
1124 # Regression test for $truncate with maxlen < the length of the indicator
1125 # string.
1126 printf '$truncate{$cgi{input},$cgi{maxlen},$cgi{ind},$cgi{ind2}}$seterror{$opt{error}}' > "$TEST_TEMPLATE"
1127 testcase 'w...' input='wwwwww' maxlen=4 ind='...' ind2='...'
1128 testcase '' input='s' maxlen=0 ind='...' ind2='...'
1130 # Test $subdb and $subid.
1131 rm -rf "$TEST_DB"
1132 printf 'inmemory' > "$TEST_DB"
1133 printf 'inmemory' > "${TEST_DB}2"
1134 printf 'inmemory\ninmemory\n' > "${TEST_DB}3"
1135 printf '$subdb{$cgi{ID}}|$subid{$cgi{ID}}' > "$TEST_TEMPLATE"
1136 testcase "$TEST_DB|1" ID=1
1137 testcase "$TEST_DB|1" ID=1 DB="$TEST_DB/${TEST_DB}2"
1138 testcase "${TEST_DB}2|1" ID=2 DB="$TEST_DB/${TEST_DB}2"
1139 testcase "${TEST_DB}|2" ID=3 DB="$TEST_DB/${TEST_DB}2"
1140 testcase "${TEST_DB}3|1" ID=1 DB="${TEST_DB}3"
1141 testcase "${TEST_DB}3|999" ID=999 DB="${TEST_DB}3"
1142 testcase "$TEST_DB|1" ID=1 DB="$TEST_DB" DB="${TEST_DB}3"
1143 testcase "${TEST_DB}3|1" ID=2 DB="$TEST_DB" DB="${TEST_DB}3"
1144 testcase "${TEST_DB}3|2" ID=3 DB="$TEST_DB" DB="${TEST_DB}3"
1145 testcase "$TEST_DB|2" ID=4 DB="$TEST_DB" DB="${TEST_DB}3"
1146 testcase "${TEST_DB}3|3" ID=5 DB="$TEST_DB" DB="${TEST_DB}3"
1147 rm -rf "${TEST_DB}2" "${TEST_DB}3"
1149 # Feature tests for $field.
1150 printf 'in : field="zer\0byte" hextobin field="field28\x02\x08"' > "$TEST_INDEXSCRIPT"
1151 rm -rf "$TEST_DB"
1152 $SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" > /dev/null <<'END'
1153 in=4071004f3456
1155 printf '$json{$field{zer$chr{0}byte,1}}|$json{$field{field28$chr{2}$chr{8},1}}|$error' > "$TEST_TEMPLATE"
1156 testcase '4071004f3456|@q\u0000O4V|'
1158 # Feature tests for $jsonarray.
1159 printf '%s, %s, %s, %s, %s' \
1160 '$jsonarray{}' \
1161 '$jsonarray{,$upper{$_}}' \
1162 '$jsonarray{$split{b4 k9},"$json{$upper{$_}}"}' \
1163 '$jsonarray{$split{a "b" c:\}}' \
1164 '$jsonarray{$split{2 3 5 7},$mul{$_,$_}}' > "$TEST_TEMPLATE"
1165 testcase '[], [], ["B4","K9"], ["a","\"b\"","c:\\"], [4,9,25,49]'
1167 # Feature tests for $jsonbool
1168 printf '%s' '$jsonbool{} $jsonbool{$eq{a,b}} $jsonbool{x} $jsonbool{0}' > "$TEST_TEMPLATE"
1169 testcase 'false false true true'
1171 # Feature tests for $jsonobject
1172 printf '%s' '$jsonobject{foo}' > "$TEST_TEMPLATE"
1173 testcase '{}'
1174 printf '%s' '$setmap{foo,Han,Solo}$jsonobject{foo}' > "$TEST_TEMPLATE"
1175 testcase '{"Han":"Solo"}'
1176 printf '%s' '$setmap{foo,key 1,value1,key"2,value\2,key3,value3}$jsonobject{foo}' > "$TEST_TEMPLATE"
1177 testcase '{"key 1":"value1","key\"2":"value\\2","key3":"value3"}'
1178 printf '%s' '$setmap{foo,key 1,1,key"2,$split{1 2},key3,$split{2 3 5}}$jsonobject{foo,,$jsonarray{$_,$add{$_,1}}}' > "$TEST_TEMPLATE"
1179 testcase '{"key 1":[2],"key\"2":[2,3],"key3":[3,4,6]}'
1180 printf '%s' '$setmap{foo,key 1,,key"2,1,key3,0}$jsonobject{foo,$upper{$_},$jsonarray{$_,$add{$_}}}' > "$TEST_TEMPLATE"
1181 testcase '{"KEY 1":[],"KEY\"2":[1],"KEY3":[0]}'
1183 # Feature tests for $stoplist
1184 printf '%s' '$setmap{prefix,foo,XFOO}[$list{$stoplist,|}]' > "$TEST_TEMPLATE"
1185 testcase '[a|the]' P.XFOO='the test' P='a test'
1187 # Feature tests for $unstem
1188 printf '%s' '$setmap{prefix,foo,XFOO}[$list{$unstem{$cgi{TERM}},|}]' > "$TEST_TEMPLATE"
1189 testcase '[pots|pot|potting]' P.XFOO='(foo:pot OR luck) (potting OR shed)' P='flower OR foo:pots' TERM=ZXFOOpot
1191 # Feature tests of scriptindex.
1193 # Regression test: non-zero exit status for unknown option.
1194 if $SCRIPTINDEX --to-be-or-not-to-be "$TEST_DB" "$TEST_INDEXSCRIPT" > /dev/null < /dev/null 2>&1; then
1195 echo "scriptindex didn't give error for unknown option"
1196 failed=`expr $failed + 1`
1199 # Regression test: error given for multiple `unique` actions.
1200 printf 'uuid : boolean=Q unique=Q\nguid : boolean=G unique=G' > "$TEST_INDEXSCRIPT"
1201 rm -rf "$TEST_DB"
1202 if $SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" > /dev/null < /dev/null 2>&1; then
1203 echo "scriptindex didn't reject 'unique' action being used more than once"
1204 failed=`expr $failed + 1`
1207 # Test we check for hash's argument being an integer (new in 1.4.6).
1208 printf 'url : hash=37.3 boolean=Q unique=Q' > "$TEST_INDEXSCRIPT"
1209 rm -rf "$TEST_DB"
1210 if $SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" < /dev/null 2>&1 \
1211 | grep -q ":1:14: warning: Index action 'hash' takes an integer argument" ; then
1212 : # OK
1213 else
1214 echo "scriptindex didn't reject 'hash' with a non-integer argument"
1215 failed=`expr $failed + 1`
1218 # Test we give a helpful error for an action with a digit in (regression
1219 # test for fix in 1.4.6).
1221 # This used to give the confusing:
1222 # Unknown index action ''
1223 printf 'url : index4' > "$TEST_INDEXSCRIPT"
1224 rm -rf "$TEST_DB"
1225 rc=0
1226 out=`$SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" < /dev/null 2>&1` || rc=$?
1227 if [ $rc -eq 0 ] ; then
1228 echo "scriptindex didn't exit with non-zero return code for bad index action with a digit"
1229 failed=`expr $failed + 1`
1230 elif printf '%s' "$out" \
1231 | grep -q ":1:7: error: Unknown index action 'index4'" ; then
1232 : # OK
1233 else
1234 echo "scriptindex didn't give expected error for bad index action with a digit"
1235 failed=`expr $failed + 1`
1238 # Test we give a helpful error if an = sign is missed out before an optional
1239 # numeric argument (regression test for fix in 1.4.6).
1241 # This used to give the confusing:
1242 # Unknown index action ''
1243 printf 'url : hash 42' > "$TEST_INDEXSCRIPT"
1244 rm -rf "$TEST_DB"
1245 rc=0
1246 out=`$SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" < /dev/null 2>&1` || rc=$?
1247 if [ $rc -eq 0 ] ; then
1248 echo "scriptindex didn't exit with non-zero return code for a missing equals sign"
1249 failed=`expr $failed + 1`
1250 elif printf '%s' "$out" \
1251 | grep -q ":1:12: error: Unknown index action '42'" ; then
1252 : # OK
1253 else
1254 echo "scriptindex didn't give expected error for a missing equals sign"
1255 failed=`expr $failed + 1`
1258 # Test we warn about spaces before and after '='.
1260 # This has never been documented as supported, and was deprecated in 1.4.6
1261 # because it resulted in this quietly using `hash` as the field name, which is
1262 # probably not what was intended:
1264 # url : field= hash boolean=Q unique=Q
1265 printf 'url : field= hash boolean=Q unique=Q' > "$TEST_INDEXSCRIPT"
1266 rm -rf "$TEST_DB"
1267 if $SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" < /dev/null 2>&1 \
1268 | grep -q ":1:13: warning: putting spaces between '=' and the argument is deprecated" ; then
1269 : # OK
1270 else
1271 echo "scriptindex didn't give expected warning for space after '='"
1272 failed=`expr $failed + 1`
1274 printf 'url : field =link' > "$TEST_INDEXSCRIPT"
1275 rm -rf "$TEST_DB"
1276 if $SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" < /dev/null 2>&1 \
1277 | grep -q ":1:12: warning: putting spaces between the action and '=' is deprecated" ; then
1278 : # OK
1279 else
1280 echo "scriptindex didn't give expected warning for space before '='"
1281 failed=`expr $failed + 1`
1284 # Feature tests for scriptindex `date` action.
1285 printf '%s\n' 'd : date=unix' 'g : date=unixutc' > "$TEST_INDEXSCRIPT"
1286 rm -rf "$TEST_DB"
1287 # `date=unix` works in the current timezone, so set that explicitly so the
1288 # build doesn't fail if run in a timezone which is behind UTC.
1289 TZ=UTC $SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" > /dev/null <<'END'
1294 d=1541478429
1296 printf '$list{$map{$range{1,3},$list{$allterms{$_}, }},|}' > "$TEST_TEMPLATE"
1297 testcase '|D19700101 M197001 Y1970|D20181106 M201811 Y2018'
1299 # `date=unixutc` should always work in UTC regardless of the current timezone.
1300 rm -rf "$TEST_DB"
1301 $SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" > /dev/null <<'END'
1306 g=1541478429
1308 testcase '|D19700101 M197001 Y1970|D20181106 M201811 Y2018'
1310 # Check nested $hitlist{} doesn't result in an infinite loop.
1311 # Regression test for bug fixed in 1.4.12.
1312 printf '<|$hitlist{$id(:$hitlist{$id:})|}>' > "$TEST_TEMPLATE"
1313 testcase '<|2(:2:3:)|3(:2:3:)|>' B=Y1970 B=Y2018
1315 # Feature tests for scriptindex `parsedate` action.
1316 printf '%s\n' 'DATE : field parsedate=%Y%m%d valuepacked=13' > "$TEST_INDEXSCRIPT"
1317 rm -rf "$TEST_DB"
1318 $SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" > /dev/null <<'END'
1319 DATE=19891204
1321 printf '$field{DATE,1}|$unpack{$value{13,1}}|$date{$unpack{$value{13,1}}}' > "$TEST_TEMPLATE"
1322 testcase '19891204|628732800|1989-12-04' P=text
1324 # Feature tests for scriptindex `parsedate` action.
1325 printf '%s\n' \
1326 'DATE: parsedate="%Y%m%d %T" field=time' \
1327 'TIME_T: parsedate=%s field=time' > "$TEST_INDEXSCRIPT"
1328 rm -rf "$TEST_DB"
1329 $SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" > /dev/null 2>&1 <<'END'
1330 DATE=20161202 12:04:22.000000
1332 TIME_T=1480680263
1334 printf '$field{time,$cgi{id}}' > "$TEST_TEMPLATE"
1335 # Test format which contains a space.
1336 testcase '1480680262' id=1
1337 # Regression test - we used to add on the local timezone offset.
1338 testcase '1480680263' id=2
1340 if grep -q 'define HAVE_STRUCT_TM_TM_GMTOFF 1' config.h ; then
1341 # Feature tests for scriptindex `parsedate` action.
1342 printf '%s\n' 'DATE: parsedate="%Y%m%d %T %z" field=time' > "$TEST_INDEXSCRIPT"
1343 rm -rf "$TEST_DB"
1344 echo 'DATE=20161202 21:34:22 +0930' | \
1345 $SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" > /dev/null 2>&1
1346 printf '$field{time,$cgi{id}}' > "$TEST_TEMPLATE"
1347 # Test that timezone adjustment is applied.
1348 testcase '1480680262' id=1
1349 else
1350 echo "Skipping testcases which need tm_gmtoff member in struct tm"
1353 # Feature tests for scriptindex `valuenumeric` action.
1354 printf '%s\n' 'n : field valuenumeric=0' > "$TEST_INDEXSCRIPT"
1355 rm -rf "$TEST_DB"
1356 $SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" > /dev/null <<'END'
1359 n=1.75
1361 n=-1000000000
1363 printf '$list{$map{$range{1,3},$url{$value{0,$_}}},:}' > "$TEST_TEMPLATE"
1364 testcase '%80:%A3:%1F%A4FS%60'
1366 # Feature tests for scriptindex `load` action.
1367 printf '%s\n' 'file : load field' > "$TEST_INDEXSCRIPT"
1368 rm -rf "$TEST_DB"
1369 rc=0
1370 out=`echo 'file='|$SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" 2>&1 > /dev/null || rc=$?`
1371 if [ $rc -ne 0 ] ; then
1372 echo "scriptindex gave error for empty filename in load action"
1373 printf '%s\n' "$out"
1374 failed=`expr $failed + 1`
1375 else
1376 case $out in
1377 *':1: warning: Empty filename in LOAD action') ;;
1379 echo "scriptindex didn't give expected warning for empty filename in load action"
1380 printf '%s\n' "$out"
1381 failed=`expr $failed + 1`
1383 esac
1386 # Feature tests for quoted arguments.
1387 printf 'DATE : field=" spaces " date="yyyymmdd"\nTEXT: index="S"\n' > "$TEST_INDEXSCRIPT"
1388 rm -rf "$TEST_DB"
1389 $SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" > /dev/null <<'END'
1390 DATE=19891204
1391 TEXT=This is sample text.
1392 NEXT=work
1394 printf '$freq{D19891204}|$field{ spaces ,1}' > "$TEST_TEMPLATE"
1395 testcase '1|19891204' P.S=text
1396 # Use $time to force the match to run.
1397 printf '$if{x$time,$freq{D19891204}}|$field{ spaces ,1}' > "$TEST_TEMPLATE"
1398 testcase '1|19891204' P=
1400 # Feature tests for escaping in quoted arguments.
1401 printf '%s\n' 'esc : field="\tesca\x70e,test\\\""' > "$TEST_INDEXSCRIPT"
1402 rm -rf "$TEST_DB"
1403 $SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" > /dev/null <<'END'
1404 esc=test
1406 printf '$field{$chr{9}escape$.test\\",1}' > "$TEST_TEMPLATE"
1407 testcase 'test' P=
1408 # Ensure the location of the problem is always in the same column so we can
1409 # test against a fixed error message including line and column.
1410 for badesc in \
1411 '"xx\' \
1412 '"xx\q"' \
1413 '"\x"' \
1414 '"\x1"' \
1415 '"\xg"' \
1416 '"\x1g"' \
1417 '"\x1g"' \
1418 ; do
1419 printf '%s' "x: split=$badesc" > "$TEST_INDEXSCRIPT"
1420 rm -rf "$TEST_DB"
1421 rc=0
1422 out=`$SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" < /dev/null 2>&1` || rc=$?
1423 if [ $rc -eq 0 ] ; then
1424 echo "scriptindex didn't exit with non-zero return code on bad escaping"
1425 failed=`expr $failed + 1`
1426 elif printf '%s' "$out" \
1427 | grep -q ":1:14: error: Bad escaping in quoted action argument" ; then
1428 : # OK
1429 else
1430 echo "scriptindex didn't give expected error for bad escaping"
1431 printf '%s\n' "badesc=$badesc" "got: $out"
1432 failed=`expr $failed + 1`
1434 done
1436 # Regression test that a closing " with junk after is flagged.
1437 printf 'date : field="test"index' > "$TEST_INDEXSCRIPT"
1438 rm -rf "$TEST_DB"
1439 rc=0
1440 out=`$SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" < /dev/null 2>&1` || rc=$?
1441 if [ $rc -eq 0 ] ; then
1442 echo "scriptindex didn't exit with non-zero return code for junk after closing quote"
1443 failed=`expr $failed + 1`
1444 elif printf '%s' "$out" \
1445 | grep -q ":1:20: error: Unexpected character 'i' after closing quote" ; then
1446 : # OK
1447 else
1448 echo "scriptindex didn't give expected error for junk after closing quote"
1449 failed=`expr $failed + 1`
1452 # Test we warn about useless actions.
1453 printf 'date : field parsedate=%%Y%%m%%d' > "$TEST_INDEXSCRIPT"
1454 rm -rf "$TEST_DB"
1455 if $SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" < /dev/null 2>&1 \
1456 | grep -q ":1:14: warning: Index action 'parsedate' has no effect" ; then
1457 : # OK
1458 else
1459 echo "scriptindex didn't give expected warning for useless 'parsedate'"
1460 failed=`expr $failed + 1`
1463 # Test scriptindex `gap` action inserts a termpos gap.
1464 printf 'text : index gap=5' > "$TEST_INDEXSCRIPT"
1465 rm -rf "$TEST_DB"
1466 printf 'text=%s\n' foo bar baz|$SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" > /dev/null
1467 echo '|$hitlist{$id|}' > "$TEST_TEMPLATE"
1468 testcase '|' 'P="foo bar"'
1469 testcase '|' 'P=foo NEAR/5 bar'
1470 testcase '|' 'P=foo NEAR/11 baz'
1471 testcase '|1|' 'P=foo NEAR/6 bar'
1472 testcase '|1|' 'P=foo NEAR/12 baz'
1474 # The scriptindex `hash` action should require its argument is >= 6, so test 5
1475 # is rejected.
1476 printf 'url : hash=5 boolean=Q unique=Q' > "$TEST_INDEXSCRIPT"
1477 rm -rf "$TEST_DB"
1478 if $SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" < /dev/null > /dev/null 2>&1 ; then
1479 echo "scriptindex didn't reject 'hash=5'"
1480 failed=`expr $failed + 1`
1483 # And that 6 is accepted.
1484 printf 'url : hash=6 boolean=Q unique=Q' > "$TEST_INDEXSCRIPT"
1485 rm -rf "$TEST_DB"
1486 if echo 'url=http://xapian.org' | $SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" > /dev/null 2>&1 ; then
1487 : # OK
1488 else
1489 echo "scriptindex rejected 'hash=6'"
1490 failed=`expr $failed + 1`
1493 # Regression test to check `hash` works without argument (it was failing with
1494 # an assertion in unreleased versions prior to 1.4.6).
1495 printf 'url : hash boolean=Q unique=Q' > "$TEST_INDEXSCRIPT"
1496 rm -rf "$TEST_DB"
1497 if echo 'url=http://xapian.org' | $SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" > /dev/null 2>&1 ; then
1498 : # OK
1499 else
1500 echo "scriptindex rejected 'hash'"
1501 failed=`expr $failed + 1`
1504 # Test the same actions for multiple fields works (briefly broken in git master
1505 # before 1.5.0).
1506 printf 'tag1 tag2 tag3 : boolean=T field' > "$TEST_INDEXSCRIPT"
1507 rm -rf "$TEST_DB"
1508 $SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" > /dev/null <<'END'
1509 tag1=one
1510 tag2=two
1511 tag3=three
1513 printf '$hitlist{$list{$terms{T},|}/$field{tag1}|$field{tag2}|$field{tag3}}' > "$TEST_TEMPLATE"
1514 testcase 'Tone/one|two|three' B=Tone
1515 testcase 'Tthree|Ttwo/one|two|three' B=Ttwo B=Tthree
1517 rm "$OMEGA_CONFIG_FILE" "$TEST_INDEXSCRIPT" "$TEST_TEMPLATE"
1518 rm -rf "$TEST_DB"
1519 if [ "$failed" = 0 ] ; then
1520 exit 0
1522 echo "Failed $failed test(s)"
1523 exit 1