2 # omegatest: Test omega CGI
4 # Copyright (C) 2015-2024 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
24 use File
::Path
qw(make_path remove_tree);
28 my ($filename, $contents) = @_;
29 open my $fh, '>', $filename or die $!;
34 my $omega = $ENV{OMEGA
} // './omega';
35 my $scriptindex = $ENV{SCRIPTINDEX
} // './scriptindex';
36 my $faketime = $ENV{FAKETIME
} // 'faketime';
37 my $srcdir = ($0 =~ m
,(.*)/,)[0] // '.';
39 # Suppress HTTP Content-Type header.
40 $ENV{SERVER_PROTOCOL
} = 'INCLUDED';
42 # Don't complain about memory left allocated on exit - the OS will reclaim
43 # all memory at that point.
44 $ENV{LSAN_OPTIONS
} = 'leak_check_at_exit=0';
46 # Turn off msys2's argument conversion as we shouldn't need it and it breaks
48 $ENV{MSYS2_ARG_CONV_EXCL
} = '*';
50 # Enable suppressions for UBSan (these are for defined-but-dubious behaviours
51 # such as unsigned overflow which UBSan can also catch - code in system library
52 # headers may trigger these checks). If UBSan isn't in use, setting this is
54 $ENV{UBSAN_OPTIONS
} = "suppressions=$srcdir/ubsan.supp";
56 # Set up an empty database.
57 my $test_db = 'test-db';
58 remove_tree
($test_db);
60 # Simple template which just shows the parsed query.
61 my $test_template = 'test-template';
62 print_to_file
$test_template, "\$querydescription\n";
64 my $test_indexscript = 'test-indexscript';
66 my $test_log = 'test-log';
68 open my $devnull, '>', ($^O
eq 'MSWin32' ?
'nul' : '/dev/null') or die $!;
70 my $OMEGA_CONFIG_FILE = 'test-omega.conf';
71 $ENV{OMEGA_CONFIG_FILE
} = $OMEGA_CONFIG_FILE;
72 print_to_file
$OMEGA_CONFIG_FILE, <<__END__
;
76 default_template
$test_template
80 # Glob pattern matching scriptindex summary line.
82 qr/records \(added, replaced, deleted, skipped\) = \(\d+, \d+, \d+, \d+\)$/;
84 # Some testcases don't work with 32-bit time_t.
85 my $have_32bit_time_t = 0;
87 open my $fh, '<', 'config.h' or die $!;
89 if (/^#define SIZEOF_TIME_T\s*(\d+)/) {
91 $have_32bit_time_t = 1;
92 print "Skipping testcases which need > 32-bit time_t\n";
102 sub run_scriptindex
{
104 remove_tree
($test_db);
105 my $pid = open2
($devnull, my $in, $scriptindex, $test_db, $test_indexscript) or die $!;
110 print "scriptindex gave non-zero exit status $?\n";
116 my $expected = shift;
120 # If there are no positional parameters, pass one as otherwise omega will
121 # wait for parameters on stdin.
122 my $args = @_ > 0 ? \
@_ : ['dummy'];
123 my $pid = open my $out, '-|', ref $omega ? @
$omega : $omega, @
$args
129 $output =~ s/\r\n/\n/g;
132 if ($output ne $expected) {
133 print "$omega @_:\n";
134 print " expected: «${expected}»\n";
135 print " received: «${output}»\n";
141 my $query_desc = shift;
142 return testcase
("Query($query_desc)", @_);
145 # Test scriptindex gives expected error.
148 # * what: text to report to describe situation
149 # * expect: expected text or regexp stdout+stderr should match
150 # * (optional) input: input to feed scriptindex (default: /dev/null)
152 # Uses database $test_db and index script $test_indexscript.
153 sub test_scriptindex_error
{
154 my ($what, $expect, $input) = @_;
155 remove_tree
($test_db);
157 if (!defined $input) {
158 $out = `$scriptindex '$test_db' '$test_indexscript' < /dev/null 2>&1`;
160 $out = `$scriptindex '$test_db' '$test_indexscript' <<'__END__' 2>&1
168 print "scriptindex didn't exit with non-zero return code for $what\n";
169 print "Output: $out\n";
171 } elsif ($out ne $expect) {
172 print "scriptindex didn't give expected error for $what\n";
173 print "Expect: $expect\n";
174 print "Output: $out\n";
179 # Test scriptindex either works or gives an expected error.
182 # * what: text to report to describe situation
183 # * expect: expected text or regexp stdout+stderr should match
184 # * (optional) input: input to feed scriptindex (default: /dev/null)
186 # Return value is the exit code from scriptindex.
188 # Uses database $test_db and index script $test_indexscript.
189 sub test_scriptindex_optional_error
{
190 my ($what, $expect, $input) = @_;
191 remove_tree
($test_db);
193 if (!defined $input) {
194 $out = `$scriptindex '$test_db' '$test_indexscript' < /dev/null 2>&1`;
196 $out = `$scriptindex '$test_db' '$test_indexscript' <<'__END__' 2>&1
204 if ($out !~ $summary_re) {
205 print "scriptindex gave unexpected output for $what\n";
206 print "Output: $out\n";
210 if ($out ne $expect) {
211 print "scriptindex didn't give expected error for $what\n";
212 print "Expect: $expect\n";
213 print "Output: $out\n";
220 # Test scriptindex gives expected warning.
223 # * what: text to report to describe situation
224 # * expect: expected text or regexp stdout+stderr should match
225 # * (optional) input: input to feed scriptindex (default: /dev/null)
227 # Uses database $test_db and index script $test_indexscript.
228 sub test_scriptindex_warning
{
229 my ($what, $expect, $input) = @_;
230 remove_tree
($test_db);
232 if (!defined $input) {
233 $out = `$scriptindex '$test_db' '$test_indexscript' < /dev/null 2>&1`;
235 $out = `$scriptindex '$test_db' '$test_indexscript' <<'__END__' 2>&1
242 if ($out !~ s/$summary_re//) {
243 print "scriptindex output lacked summary line for $what\n";
244 print "Output: $out\n";
250 print "scriptindex gave an error rather than the expected warning for $what\n";
251 print "Output: $out\n";
253 } elsif ($out ne $expect) {
254 print "scriptindex didn't give expected warning for $what\n";
255 print "Expect: $expect\n";
256 print "Output: $out\n";
261 # Test scriptindex runs cleanly
264 # * what: text to report to describe situation
265 # * (optional) input: input to feed scriptindex (default: /dev/null)
267 # Uses database $test_db and index script $test_indexscript.
268 sub test_scriptindex
{
269 my ($what, $input) = @_;
270 remove_tree
($test_db);
272 if (!defined $input) {
273 $out = `$scriptindex '$test_db' '$test_indexscript' < /dev/null 2>&1`;
275 $out = `$scriptindex '$test_db' '$test_indexscript' <<'__END__' 2>&1
283 print "scriptindex gave an error for $what\n";
284 print "Output: $out\n";
286 } elsif ($out !~ $summary_re) {
287 print "scriptindex gave unexpected output for $what\n";
288 print "Output: $out\n";
293 # Test a few simple things.
294 qtestcase
('Zsimpl@1', 'P=simple');
295 qtestcase
('(chocolate@1 FILTER Tconfectionary/fudge)', 'P=Chocolate', 'B=Tconfectionary/fudge');
297 # Test date value ranges.
298 qtestcase
('VALUE_RANGE 0 2 ~', 'DATEVALUE=0', 'START=2000');
299 qtestcase
('VALUE_RANGE 0 2 ~', 'DATEVALUE=0', 'START=200001');
300 qtestcase
('VALUE_RANGE 0 2 ~', 'DATEVALUE=0', 'START=20000101');
301 qtestcase
('VALUE_LE 1 1~', 'DATEVALUE=1', 'END=1999');
302 qtestcase
('VALUE_LE 1 1~', 'DATEVALUE=1', 'END=199912');
303 qtestcase
('VALUE_LE 1 1~', 'DATEVALUE=1', 'END=19991231');
304 qtestcase
('VALUE_RANGE 2 201 ~', 'DATEVALUE=2', 'START=2010');
305 qtestcase
('VALUE_RANGE 2 201 ~', 'DATEVALUE=2', 'START=201001');
306 qtestcase
('VALUE_RANGE 2 201 ~', 'DATEVALUE=2', 'START=20100101');
307 qtestcase
('VALUE_LE 3 198~', 'DATEVALUE=3', 'END=1989');
308 qtestcase
('VALUE_LE 3 198~', 'DATEVALUE=3', 'END=198912');
309 qtestcase
('VALUE_LE 3 198~', 'DATEVALUE=3', 'END=19891231');
310 qtestcase
('VALUE_RANGE 4 1974 ~', 'DATEVALUE=4', 'START=1974');
311 qtestcase
('VALUE_RANGE 4 1974 ~', 'DATEVALUE=4', 'START=197401');
312 qtestcase
('VALUE_RANGE 4 1974 ~', 'DATEVALUE=4', 'START=19740101');
313 qtestcase
('VALUE_LE 5 1974~', 'DATEVALUE=5', 'END=1974');
314 qtestcase
('VALUE_LE 5 1974~', 'DATEVALUE=5', 'END=197412');
315 qtestcase
('VALUE_LE 5 1974~', 'DATEVALUE=5', 'END=19741231');
316 qtestcase
('VALUE_RANGE 6 20151 ~', 'DATEVALUE=6', 'START=201510');
317 qtestcase
('VALUE_RANGE 6 20151 ~', 'DATEVALUE=6', 'START=20151001');
318 qtestcase
('VALUE_LE 7 19870~', 'DATEVALUE=7', 'END=198709');
319 qtestcase
('VALUE_LE 7 19870~', 'DATEVALUE=7', 'END=19870930');
320 qtestcase
('VALUE_RANGE 8 201512 ~', 'DATEVALUE=8', 'START=201512');
321 qtestcase
('VALUE_RANGE 8 201512 ~', 'DATEVALUE=8', 'START=20151201');
322 qtestcase
('VALUE_LE 9 201511~', 'DATEVALUE=9', 'END=201511');
323 qtestcase
('VALUE_LE 9 201511~', 'DATEVALUE=9', 'END=20151130');
324 qtestcase
('VALUE_RANGE 10 2015021 ~', 'DATEVALUE=10', 'START=20150210');
325 qtestcase
('VALUE_RANGE 10 2000022 ~', 'DATEVALUE=10', 'START=20000220');
326 qtestcase
('VALUE_LE 11 19840401~', 'DATEVALUE=11', 'END=19840401');
327 qtestcase
('VALUE_LE 11 19881128~', 'DATEVALUE=11', 'END=19881128');
330 qtestcase
('VALUE_LE 1 201502~', 'DATEVALUE=1', 'END=20150228');
331 qtestcase
('VALUE_LE 1 198802~', 'DATEVALUE=1', 'END=19880229');
332 qtestcase
('VALUE_LE 1 19880228~', 'DATEVALUE=1', 'END=19880228');
333 qtestcase
('VALUE_LE 1 200002~', 'DATEVALUE=1', 'END=20000229');
334 qtestcase
('VALUE_LE 1 20000228~', 'DATEVALUE=1', 'END=20000228');
335 if (!$have_32bit_time_t) {
336 qtestcase
('VALUE_LE 1 190002~', 'DATEVALUE=1', 'END=19000228');
337 qtestcase
('VALUE_LE 1 210002~', 'DATEVALUE=1', 'END=21000228');
340 # Month starts and ends:
341 qtestcase
('VALUE_RANGE 0 2015 201501~', 'DATEVALUE=0', 'START=20150101', 'END=20150131');
342 qtestcase
('VALUE_RANGE 0 2015 20150130~', 'DATEVALUE=0', 'START=20150101', 'END=20150130');
343 qtestcase
('VALUE_RANGE 0 201502 201502~', 'DATEVALUE=0', 'START=20150201', 'END=20150228');
344 qtestcase
('VALUE_RANGE 0 201502 20150227~', 'DATEVALUE=0', 'START=20150201', 'END=20150227');
345 qtestcase
('VALUE_RANGE 0 201503 201503~', 'DATEVALUE=0', 'START=20150301', 'END=20150331');
346 qtestcase
('VALUE_RANGE 0 201503 20150330~', 'DATEVALUE=0', 'START=20150301', 'END=20150330');
347 qtestcase
('VALUE_RANGE 0 201504 201504~', 'DATEVALUE=0', 'START=20150401', 'END=20150430');
348 qtestcase
('VALUE_RANGE 0 201504 2015042~', 'DATEVALUE=0', 'START=20150401', 'END=20150429');
349 qtestcase
('VALUE_RANGE 0 201505 201505~', 'DATEVALUE=0', 'START=20150501', 'END=20150531');
350 qtestcase
('VALUE_RANGE 0 201505 20150530~', 'DATEVALUE=0', 'START=20150501', 'END=20150530');
351 qtestcase
('VALUE_RANGE 0 201506 201506~', 'DATEVALUE=0', 'START=20150601', 'END=20150630');
352 qtestcase
('VALUE_RANGE 0 201506 2015062~', 'DATEVALUE=0', 'START=20150601', 'END=20150629');
353 qtestcase
('VALUE_RANGE 0 201507 201507~', 'DATEVALUE=0', 'START=20150701', 'END=20150731');
354 qtestcase
('VALUE_RANGE 0 201507 20150730~', 'DATEVALUE=0', 'START=20150701', 'END=20150730');
355 qtestcase
('VALUE_RANGE 0 201508 201508~', 'DATEVALUE=0', 'START=20150801', 'END=20150831');
356 qtestcase
('VALUE_RANGE 0 201508 20150830~', 'DATEVALUE=0', 'START=20150801', 'END=20150830');
357 qtestcase
('VALUE_RANGE 0 201509 20150~', 'DATEVALUE=0', 'START=20150901', 'END=20150930');
358 qtestcase
('VALUE_RANGE 0 201509 2015092~', 'DATEVALUE=0', 'START=20150901', 'END=20150929');
359 qtestcase
('VALUE_RANGE 0 20151 201510~', 'DATEVALUE=0', 'START=20151001', 'END=20151031');
360 qtestcase
('VALUE_RANGE 0 20151 20151030~', 'DATEVALUE=0', 'START=20151001', 'END=20151030');
361 qtestcase
('VALUE_RANGE 0 201511 201511~', 'DATEVALUE=0', 'START=20151101', 'END=20151130');
362 qtestcase
('VALUE_RANGE 0 201511 2015112~', 'DATEVALUE=0', 'START=20151101', 'END=20151129');
363 qtestcase
('VALUE_RANGE 0 201512 2015~', 'DATEVALUE=0', 'START=20151201', 'END=20151231');
364 qtestcase
('VALUE_RANGE 0 201512 20151230~', 'DATEVALUE=0', 'START=20151201', 'END=20151230');
367 qtestcase
('VALUE_RANGE 0 20151104 20151106~', 'DATEVALUE=0', 'START=20151104', 'SPAN=3');
368 qtestcase
('VALUE_RANGE 0 20141104 20151103~', 'DATEVALUE=0', 'START=20141104', 'SPAN=365');
371 qtestcase
('VALUE_RANGE 0 20151104 20151106~', 'DATEVALUE=0', 'END=20151106', 'SPAN=3');
372 qtestcase
('VALUE_RANGE 0 20141104 20151103~', 'DATEVALUE=0', 'END=20151103', 'SPAN=365');
374 # Check that if START, END and SPAN are all passed, START is ignored:
375 qtestcase
('VALUE_RANGE 0 20151104 20151106~', 'DATEVALUE=0', 'START=19700101', 'END=20151106', 'SPAN=3');
377 # Test date value ranges using newer ".SLOT" parameters.
378 qtestcase
('VALUE_RANGE 0 2 ~', 'START.0=2000');
379 qtestcase
('VALUE_RANGE 0 2 ~', 'START.0=200001');
380 qtestcase
('VALUE_RANGE 0 2 ~', 'START.0=20000101');
381 qtestcase
('VALUE_LE 1 1~', 'END.1=1999');
382 qtestcase
('VALUE_LE 1 1~', 'END.1=199912');
383 qtestcase
('VALUE_LE 1 1~', 'END.1=19991231');
384 qtestcase
('VALUE_RANGE 2 201 ~', 'START.2=2010');
385 qtestcase
('VALUE_RANGE 2 201 ~', 'START.2=201001');
386 qtestcase
('VALUE_RANGE 2 201 ~', 'START.2=20100101');
387 qtestcase
('VALUE_LE 3 198~', 'END.3=1989');
388 qtestcase
('VALUE_LE 3 198~', 'END.3=198912');
389 qtestcase
('VALUE_LE 3 198~', 'END.3=19891231');
390 qtestcase
('VALUE_RANGE 4 1974 ~', 'START.4=1974');
391 qtestcase
('VALUE_RANGE 4 1974 ~', 'START.4=197401');
392 qtestcase
('VALUE_RANGE 4 1974 ~', 'START.4=19740101');
393 qtestcase
('VALUE_LE 5 1974~', 'END.5=1974');
394 qtestcase
('VALUE_LE 5 1974~', 'END.5=197412');
395 qtestcase
('VALUE_LE 5 1974~', 'END.5=19741231');
396 qtestcase
('VALUE_RANGE 6 20151 ~', 'START.6=201510');
397 qtestcase
('VALUE_RANGE 6 20151 ~', 'START.6=20151001');
398 qtestcase
('VALUE_LE 7 19870~', 'END.7=198709');
399 qtestcase
('VALUE_LE 7 19870~', 'END.7=19870930');
400 qtestcase
('VALUE_RANGE 8 201512 ~', 'START.8=201512');
401 qtestcase
('VALUE_RANGE 8 201512 ~', 'START.8=20151201');
402 qtestcase
('VALUE_LE 9 201511~', 'END.9=201511');
403 qtestcase
('VALUE_LE 9 201511~', 'END.9=20151130');
404 qtestcase
('VALUE_RANGE 10 2015021 ~', 'START.10=20150210');
405 qtestcase
('VALUE_RANGE 10 2000022 ~', 'START.10=20000220');
406 qtestcase
('VALUE_LE 11 19840401~', 'END.11=19840401');
407 qtestcase
('VALUE_LE 11 19881128~', 'END.11=19881128');
410 qtestcase
('VALUE_LE 1 201502~', 'END.1=20150228');
411 qtestcase
('VALUE_LE 1 198802~', 'END.1=19880229');
412 qtestcase
('VALUE_LE 1 19880228~', 'END.1=19880228');
413 qtestcase
('VALUE_LE 1 200002~', 'END.1=20000229');
414 qtestcase
('VALUE_LE 1 20000228~', 'END.1=20000228');
415 if (!$have_32bit_time_t) {
416 qtestcase
('VALUE_LE 1 190002~', 'END.1=19000228');
417 qtestcase
('VALUE_LE 1 210002~', 'END.1=21000228');
420 # Month starts and ends:
421 qtestcase
('VALUE_RANGE 0 2015 201501~', 'START.0=20150101', 'END.0=20150131');
422 qtestcase
('VALUE_RANGE 0 2015 20150130~', 'START.0=20150101', 'END.0=20150130');
423 qtestcase
('VALUE_RANGE 0 201502 201502~', 'START.0=20150201', 'END.0=20150228');
424 qtestcase
('VALUE_RANGE 0 201502 20150227~', 'START.0=20150201', 'END.0=20150227');
425 qtestcase
('VALUE_RANGE 0 201503 201503~', 'START.0=20150301', 'END.0=20150331');
426 qtestcase
('VALUE_RANGE 0 201503 20150330~', 'START.0=20150301', 'END.0=20150330');
427 qtestcase
('VALUE_RANGE 0 201504 201504~', 'START.0=20150401', 'END.0=20150430');
428 qtestcase
('VALUE_RANGE 0 201504 2015042~', 'START.0=20150401', 'END.0=20150429');
429 qtestcase
('VALUE_RANGE 0 201505 201505~', 'START.0=20150501', 'END.0=20150531');
430 qtestcase
('VALUE_RANGE 0 201505 20150530~', 'START.0=20150501', 'END.0=20150530');
431 qtestcase
('VALUE_RANGE 0 201506 201506~', 'START.0=20150601', 'END.0=20150630');
432 qtestcase
('VALUE_RANGE 0 201506 2015062~', 'START.0=20150601', 'END.0=20150629');
433 qtestcase
('VALUE_RANGE 0 201507 201507~', 'START.0=20150701', 'END.0=20150731');
434 qtestcase
('VALUE_RANGE 0 201507 20150730~', 'START.0=20150701', 'END.0=20150730');
435 qtestcase
('VALUE_RANGE 0 201508 201508~', 'START.0=20150801', 'END.0=20150831');
436 qtestcase
('VALUE_RANGE 0 201508 20150830~', 'START.0=20150801', 'END.0=20150830');
437 qtestcase
('VALUE_RANGE 0 201509 20150~', 'START.0=20150901', 'END.0=20150930');
438 qtestcase
('VALUE_RANGE 0 201509 2015092~', 'START.0=20150901', 'END.0=20150929');
439 qtestcase
('VALUE_RANGE 0 20151 201510~', 'START.0=20151001', 'END.0=20151031');
440 qtestcase
('VALUE_RANGE 0 20151 20151030~', 'START.0=20151001', 'END.0=20151030');
441 qtestcase
('VALUE_RANGE 0 201511 201511~', 'START.0=20151101', 'END.0=20151130');
442 qtestcase
('VALUE_RANGE 0 201511 2015112~', 'START.0=20151101', 'END.0=20151129');
443 qtestcase
('VALUE_RANGE 0 201512 2015~', 'START.0=20151201', 'END.0=20151231');
444 qtestcase
('VALUE_RANGE 0 201512 20151230~', 'START.0=20151201', 'END.0=20151230');
447 qtestcase
('VALUE_RANGE 0 20151104 20151106~', 'START.0=20151104', 'SPAN.0=3');
448 qtestcase
('VALUE_RANGE 0 20141104 20151103~', 'START.0=20141104', 'SPAN.0=365');
451 qtestcase
('VALUE_RANGE 0 20151104 20151106~', 'END.0=20151106', 'SPAN.0=3');
452 qtestcase
('VALUE_RANGE 0 20141104 20151103~', 'END.0=20151103', 'SPAN.0=365');
455 qtestcase
('', 'START.0=20180919', 'END.0=19991225');
456 # Check that the empty span dominates other spans:
457 qtestcase
('', 'START.0=20180919', 'END.0=19991225', 'START.1=20180901');
458 # Check that the empty span dominates a filter term:
459 qtestcase
('', 'START.0=20180919', 'END.0=19991225', 'B=Ktag');
460 # Check that the empty span dominates a negated filter term:
461 qtestcase
('', 'START.0=20180919', 'END.0=19991225', 'N=Kneg');
462 # Check that the empty span dominates a term-based date range filter:
463 qtestcase
('', 'START.0=20180919', 'END.0=19991225', 'START=20000101', 'END=20001231');
465 # Check that if START, END and SPAN are all passed, START is ignored:
466 qtestcase
('VALUE_RANGE 0 20151104 20151106~', 'START.0=19700101', 'END.0=20151106', 'SPAN.0=3');
468 # Check multiple .SLOT filters:
469 qtestcase
('(VALUE_RANGE 0 201512 2015~ AND VALUE_LE 5 1974~)', 'START.0=20151201', 'END.0=20151231', 'END.5=1974');
470 qtestcase
('(VALUE_RANGE 0 201512 20151207~ AND VALUE_RANGE 5 19740102 1974~)', 'START.0=20151201', 'SPAN.0=7', 'END.5=1974', 'SPAN.5=364');
472 # Check .SLOT and old-style value date range filter:
473 qtestcase
('(VALUE_RANGE 0 201512 2015~ AND VALUE_LE 5 1974~)', 'START.0=20151201', 'END.0=20151231', 'DATEVALUE=5', 'END=1974');
475 # Check .SLOT and old-style value date range filter on same slot.
476 # (We don't promise anything for this case, but it shouldn't crash).
477 qtestcase
('VALUE_RANGE 0 201512 2015~', 'START.0=20151201', 'END.0=20151231', 'DATEVALUE=0', 'END=1974');
479 # Tests of term-based date range filtering:
481 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');
482 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');
483 qtestcase
('(Y1970 OR Y1971 OR Y1972 OR Y1973 OR Y1974 OR Dlatest)', 'END=19741231');
484 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');
485 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');
486 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');
487 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');
490 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');
491 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');
492 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');
493 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');
494 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');
495 if (!$have_32bit_time_t) {
496 qtestcase
('Dlatest', 'END=19000228'); # Assumed start is 19700101
497 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');
500 # Month starts and ends:
501 qtestcase
('(M201501 OR Dlatest)', 'START=20150101', 'END=20150131');
502 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');
503 qtestcase
('(M201502 OR Dlatest)', 'START=20150201', 'END=20150228');
504 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');
505 qtestcase
('(M201503 OR Dlatest)', 'START=20150301', 'END=20150331');
506 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');
507 qtestcase
('(M201504 OR Dlatest)', 'START=20150401', 'END=20150430');
508 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');
509 qtestcase
('(M201505 OR Dlatest)', 'START=20150501', 'END=20150531');
510 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');
511 qtestcase
('(M201506 OR Dlatest)', 'START=20150601', 'END=20150630');
512 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');
513 qtestcase
('(M201507 OR Dlatest)', 'START=20150701', 'END=20150731');
514 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');
515 qtestcase
('(M201508 OR Dlatest)', 'START=20150801', 'END=20150831');
516 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');
517 qtestcase
('(M201509 OR Dlatest)', 'START=20150901', 'END=20150930');
518 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');
519 qtestcase
('(M201510 OR Dlatest)', 'START=20151001', 'END=20151031');
520 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');
521 qtestcase
('(M201511 OR Dlatest)', 'START=20151101', 'END=20151130');
522 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');
523 qtestcase
('(M201512 OR Dlatest)', 'START=20151201', 'END=20151231');
524 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');
527 qtestcase
('(D20151104 OR D20151105 OR D20151106 OR D20151107 OR Dlatest)', 'START=20151104', 'SPAN=3');
528 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');
531 qtestcase
('(D20151103 OR D20151104 OR D20151105 OR D20151106 OR Dlatest)', 'END=20151106', 'SPAN=3');
532 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');
534 # Check that if START, END and SPAN are all passed, START is ignored:
535 qtestcase
('(D20151103 OR D20151104 OR D20151105 OR D20151106 OR Dlatest)', 'START=19700101', 'END=20151106', 'SPAN=3');
537 # Check that YYYYMM and YYYY are accepted and handled appropriately:
538 qtestcase
('(Y1980 OR Y1981 OR Dlatest)', 'START=1980', 'END=1981');
539 qtestcase
('(M198012 OR M198101 OR M198102 OR Dlatest)', 'START=198012', 'END=198102');
541 # Check .SLOT combined with term based date range filter:
542 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');
544 # Check combining of filter terms:
545 qtestcase
('(Horg AND Len)', 'B=Len', 'B=Horg');
546 qtestcase
('(Len OR Lde)', 'B=Len', 'B=Lde');
547 qtestcase
('((Horg OR Hcom) AND (Len OR Lfr))', 'B=Len', 'B=Lfr', 'B=Horg', 'B=Hcom');
549 # Check combining of filter terms with filter_op set:
550 print_to_file
$test_template,('$setmap{nonexclusiveprefix,L,1,XAND,1}$setmap{boolprefix,lang,L,and,XAND,host,H,year,Y}$querydescription');
551 qtestcase
('Len', 'B=Len');
552 qtestcase
('0 * Len', 'P=lang:en');
553 qtestcase
('XANDtest', 'B=XANDtest');
554 qtestcase
('0 * XANDtest', 'P=and:test');
555 qtestcase
('(Len AND XANDtest)', 'B=Len', 'B=XANDtest');
556 qtestcase
('0 * (Len AND XANDtest)', 'P=lang:en and:test');
557 qtestcase
('(Len AND Lde)', 'B=Len', 'B=Lde');
558 qtestcase
('0 * (Len AND Lde)', 'P=lang:en lang:de');
559 qtestcase
('((Horg OR Hcom) AND (Len AND Lfr))', 'B=Len', 'B=Lfr', 'B=Horg', 'B=Hcom');
560 qtestcase
('0 * ((Len AND Lfr) AND (Horg OR Hcom))', 'P=lang:en lang:fr host:org host:com');
561 qtestcase
('((XANDa AND XANDb AND XANDc) AND (Y1998 OR Y2001))', 'B=Y1998', 'B=Y2001', 'B=XANDa', 'B=XANDb', 'B=XANDc');
562 qtestcase
('0 * ((XANDa AND XANDb AND XANDc) AND (Y1998 OR Y2001))', 'P=year:1998 year:2001 and:a and:b and:c');
564 # Check combining of filters around CGI parameter 'N':
565 qtestcase
('(Ztruth@1 AND_NOT Epdf)', 'P=truth', 'N=Epdf');
566 qtestcase
('(Ztruth@1 AND_NOT (Ehtm OR Epdf))', 'P=truth', 'N=Epdf', 'N=Ehtm');
567 qtestcase
('(Ztruth@1 AND_NOT (Ehtm OR Epdf OR Lde OR Lfr))', 'P=truth', 'N=Lfr', 'N=Epdf', 'N=Ehtm', 'N=Lde');
568 qtestcase
('((Ztruth@1 FILTER (Lfr AND Lzh)) AND_NOT (Lde OR Len))', 'P=truth', 'N=Lde', 'N=Len', 'B=Lfr', 'B=Lzh');
569 qtestcase
('((Ztruth@1 FILTER Lfr) AND_NOT (Ehtm OR Epdf))', 'P=truth', 'N=Epdf', 'N=Ehtm', 'B=Lfr');
570 qtestcase
('(<alldocuments> AND_NOT (Len OR Lfr))', 'N=Lfr', 'N=Len');
571 qtestcase
('(VALUE_RANGE 0 2015 201501~ AND_NOT Len)', 'DATEVALUE=0', 'START=20150101', 'END=20150131', 'N=Len');
573 if ($faketime ne '') {
574 my $out = `$faketime -f '1980-12-08 00:00:00' date +%Y 2>&1`;
578 print "Skipping testcases which need 'faketime' tool installed\n";
580 print "Skipping testcases which need 'faketime' tool - it's installed but doesn't work (test exited with return code $rc)\n";
581 } elsif ($out ne '1980') {
582 print "Skipping testcases which need 'faketime' tool - it's installed but doesn't work (got year '$out' instead of '1980')\n";
584 # We have faketime and it seems to work so use it to run test cases where
585 # the output depends on the current time.
586 my $save_omega = $omega;
587 $omega = [$faketime, '-f', '2015-11-28 06:07:08', $omega];
589 my $save_TZ = $ENV{TZ
};
591 qtestcase
('VALUE_RANGE 0 20151127060709 20151128060708', 'DATEVALUE=0', 'SPAN=1');
592 if (defined $save_TZ) {
598 # Tests of term-based date range filtering:
599 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');
600 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');
601 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');
602 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');
603 # Date range with start after end:
604 qtestcase
('Dlatest', 'START=201512');
605 qtestcase
('Dlatest', 'START=20151201');
606 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');
607 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');
608 $omega = $save_omega;
611 print "Skipping testcases which need 'faketime' tool - \$FAKETIME is empty\n";
614 # Check clamping of out of range dates:
615 print_to_file
$test_indexscript, "DATE : field valuepacked=0\n";
616 run_scriptindex
(<<'END');
621 qtestcase
('VALUE_LE 0 V\x84o\xff', 'START.0=10010101', 'END.0=20151230');
622 if (!$have_32bit_time_t) {
623 qtestcase
('VALUE_RANGE 0 V\x83\x1e\x80 \xff\xff\xff\xff', 'START.0=20151230', 'END.0=21060301');
624 qtestcase
('VALUE_LE 0 \xff\xff\xff\xff', 'START.0=19691230', 'END.0=21060301');
627 # Test stem_all and stem_strategy.
628 print_to_file
$test_template, '$if{$cgi{stem_all},$set{stem_all,$cgi{stem_all}}}$if{$cgi{stem_strategy},$set{stem_strategy,$cgi{stem_strategy}}}$querydescription';
630 qtestcase
('(capitalised@1 AND tests@2 AND Zstem@3)', 'P=Capitalised "tests" stemmed');
631 qtestcase
('(nearing@1 NEAR 11 distances@2)', 'P=nearing NEAR distances');
632 qtestcase
('(capitalis@1 AND test@2 AND stem@3)', 'P=Capitalised "tests" stemmed', 'stem_all=true');
633 qtestcase
('(near@1 NEAR 11 distanc@2)', 'P=nearing NEAR distances', 'stem_all=true');
634 qtestcase
('(capitalis@1 AND test@2 AND stem@3)', 'P=Capitalised "tests" stemmed', 'stem_strategy=all');
635 qtestcase
('(near@1 NEAR 11 distanc@2)', 'P=nearing NEAR distances', 'stem_strategy=all');
636 qtestcase
('(Zcapitalis@1 AND Ztest@2 AND Zstem@3)', 'P=Capitalised "tests" stemmed', 'stem_strategy=all_z');
637 qtestcase
('(Znear@1 NEAR 11 Zdistanc@2)', 'P=nearing NEAR distances', 'stem_strategy=all_z');
638 qtestcase
('(capitalised@1 AND tests@2 AND stemmed@3)', 'P=Capitalised "tests" stemmed', 'stem_strategy=none');
639 qtestcase
('(nearing@1 NEAR 11 distances@2)', 'P=nearing NEAR distances', 'stem_strategy=none');
640 qtestcase
('(capitalised@1 AND tests@2 AND Zstem@3)', 'P=Capitalised "tests" stemmed', 'stem_strategy=some');
641 qtestcase
('(nearing@1 NEAR 11 distances@2)', 'P=nearing NEAR distances', 'stem_strategy=some');
642 qtestcase
('(capitalised@1 AND tests@2 AND Zstem@3)', 'P=Capitalised "tests" stemmed', 'stem_strategy=some_full_pos');
643 qtestcase
('(Znear@1 NEAR 11 Zdistanc@2)', 'P=nearing NEAR distances', 'stem_strategy=some_full_pos');
644 qtestcase
('(capitalised@1 AND tests@2 AND Zstem@3)', 'P=Capitalised "tests" stemmed', 'stem_strategy=some', 'stem_all=true');
645 qtestcase
('(nearing@1 NEAR 11 distances@2)', 'P=nearing NEAR distances', 'stem_strategy=some', 'stem_all=true');
647 # Test intra_query_op.
648 print_to_file
$test_template, '$if{$cgi{iqop},$set{intra_query_op,$cgi{iqop}}}$querydescription';
649 qtestcase
'testing@1', 'P=Testing', 'iqop=OR';
650 qtestcase
'(Ztest@1 AND ZStitl@1)', 'P=testing', 'P.S=title';
651 qtestcase
'(Ztest@1 OR ZStitl@1)', 'P=testing', 'P.S=title', 'iqop=OR';
652 qtestcase
'(Ztest@1 OR ZStitl@1)', 'P=testing', 'P.S=title', 'iqop=or';
653 qtestcase
'(Ztest@1 AND ZStitl@1)', 'P=testing', 'P.S=title', 'iqop=invalid';
655 # Feature tests for $contains.
656 print_to_file
$test_template, '$contains{$cgi{a},$cgi{b}}';
657 testcase
('6', 'P=text', 'a=fish', 'b=Hello fish');
658 testcase
('', 'P=text', 'a=Example', 'b=random');
660 # Feature tests for boolprefix and prefix maps.
661 print_to_file
$test_template, '$set{stemmer,}$setmap{boolprefix,lang,L,host,H}$setmap{prefix,,XDEFAULT}$querydescription';
662 qtestcase
('((XDEFAULTfoo@1 AND XDEFAULTbar@2) FILTER (Hexample.org AND Lzh))', 'P=host:example.org foo bar lang:zh');
664 # Feature tests for $addfilter.
665 print_to_file
$test_template, '$addfilter{Hexample.org}$addfilter{Hexample.com,}$addfilter{XFOObar,B}$querydescription';
666 qtestcase
('((Hexample.org OR Hexample.com) AND XFOObar)', 'P=');
667 print_to_file
$test_template, '$addfilter{Hexample.org}$addfilter{Hexample.com,N}$addfilter{Hexample.net,N}$querydescription';
668 qtestcase
('(Hexample.org AND_NOT (Hexample.com OR Hexample.net))', 'P=');
670 # Feature tests for $if.
671 print_to_file
$test_template, '$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}';
674 # Feature tests for $cond.
675 print_to_file
$test_template, '$cond{$cgi{one},1,$cgi{two},2,$cgi{three},3}';
676 testcase
('1', 'one=true');
677 testcase
('2', 'two=true');
678 testcase
('3', 'three=true');
679 testcase
('', 'nothing=true');
680 testcase
('1', 'one=true', 'two=true', 'three=true');
681 testcase
('2', 'two=true', 'three=true');
682 print_to_file
$test_template, '$cond{$cgi{one},1,$cgi{two},2,$cgi{alt}}';
683 testcase
('1', 'one=true');
684 testcase
('2', 'two=true');
685 testcase
('none', 'alt=none');
686 # Check evaluation is lazy.
687 print_to_file
$test_template, '$cond{$cgi{one},$seterror{err1},$cgi{two},2,$cgi{alt}}$error';
688 testcase
('err1', 'one=true');
689 testcase
('2', 'two=true');
690 testcase
('none', 'alt=none');
691 print_to_file
$test_template, '$cond{$cgi{one},1,$cgi{two},$seterror{err2},$cgi{alt}}$error';
692 testcase
('1', 'one=true');
693 testcase
('err2', 'two=true');
694 testcase
('none', 'alt=none');
695 print_to_file
$test_template, '$cond{$cgi{one},1,$cgi{two},2,$seterror{erralt}}$error';
696 testcase
('1', 'one=true');
697 testcase
('2', 'two=true');
698 testcase
('erralt', 'alt=none');
700 # Feature tests for $switch.
701 print_to_file
$test_template, '$switch{$cgi{x},1,one,2,two}';
702 testcase
('one', 'x=1');
703 testcase
('two', 'x=2');
705 print_to_file
$test_template, '$switch{$cgi{x},1,one,2,two,default}';
706 testcase
('one', 'x=1');
707 testcase
('two', 'x=2');
708 testcase
('default', 'x=3');
709 # Check evaluation is lazy.
710 print_to_file
$test_template, '$switch{$cgi{x},1,$seterror{err1},2,two}$error';
711 testcase
('err1', 'x=1');
712 testcase
('two', 'x=2');
714 print_to_file
$test_template, '$switch{$cgi{x},1,one,2,$seterror{err2},default}$error';
715 testcase
('one', 'x=1');
716 testcase
('err2', 'x=2');
717 testcase
('default', 'x=3');
718 print_to_file
$test_template, '$switch{$cgi{x},1,one,2,two,$seterror{errdefault}}$error';
719 testcase
('one', 'x=1');
720 testcase
('two', 'x=2');
721 testcase
('errdefault', 'x=3');
723 # Feature tests for $include.
724 # Test inclusion works and evaluates the included file.
725 print_to_file
$test_template, '$set{c,$add{$or{$opt{c},0},1}}$opt{c},$if{$lt{$opt{c},10},$include{' . $test_template . '}}X';
726 testcase
('1,2,3,4,5,6,7,8,9,10,XXXXXXXXXX');
727 # Test fallback action when trying to $include a file which doesn't exist or
728 # with a prohibited name.
729 print_to_file
$test_template, '$include{$cgi{template},foo$set{data,bar}}-$opt{data}';
730 testcase
('foo-bar', 'template=non_existent.template');
731 testcase
('foo-bar', 'template=../secret/file');
732 # Test exception is thrown when there's no fallback action when trying to
733 # $include a file which doesn't exist or with a prohibited name.
734 print_to_file
$test_template, '$include{$cgi{template}}-$opt{data}';
735 testcase
("Exception: Couldn't read format template 'non_existent.template' (No such file or directory)", 'template=non_existent.template');
736 testcase
("Exception: Couldn't read format template '../secret/file' (name contains '..')", 'template=../secret/file');
738 # Feature tests for $foreach.
739 print_to_file
$test_template, '$foreach{$split{.,$cgi{a}},$chr{$add{$_,64}}}';
740 testcase
('OMEGA', 'a=15.13.5.7.1');
741 # Check that the outer $_ is restored after the inner $foreach.
742 print_to_file
$test_template, '$foreach{$split{.,$cgi{a}},$foreach{$split{.,$cgi{$_}},$chr{$add{$_,64}}}$_}';
743 testcase
('OMbEGcAd', 'a=b.c.d', 'b=15.13', 'c=5.7', 'd=1');
745 # Feature tests for $map.
746 print_to_file
$test_template, '$list{$map{$split{-,$cgi{a}},$list{$map{$split{,$cgi{b}},$_},-}},|}';
747 testcase
('1-2-3|1-2-3', 'P=text', 'a=ab-cd', 'b=123');
748 print_to_file
$test_template, '$list{$map{$split{-,$cgi{a}},$set{__,$_}$list{$map{$split{,$cgi{b}},$opt{__}$_},-}},|}';
749 testcase
('a1-a2-a3|b1-b2-b3', 'P=text', 'a=a-b', 'b=123');
750 print_to_file
$test_template, '$list{$map{$split{-,$cgi{a}},$list{$map{$split{$_,$cgi{b}},$_},-}},|}';
751 testcase
('1-2,3|1:2-3', 'P=text', 'a=:-,', 'b=1:2,3');
752 # Check that the outer $_ is restored after the inner $map.
753 print_to_file
$test_template, '$list{$map{$split{-,$cgi{a}},$list{$map{$split{,$cgi{b}},$_},-}$_},|}';
754 testcase
('1-2-3a|1-2-3b', 'P=text', 'a=a-b', 'b=123');
756 # Feature tests for $match.
757 print_to_file
$test_template, '$match{$cgi{a},$cgi{b},$cgi{c}}';
758 testcase
('true', 'P=text', 'a=ab*c+', 'b=ac');
759 testcase
('', 'P=text', 'a=acb', 'b=abc');
760 testcase
('true', 'P=text', 'a=[A-Z]bcD', 'b=abcd', 'c=i');
761 testcase
('', 'P=text', 'a=[A-Z]bcD', 'b=abcd');
762 testcase
('true', 'P=text', 'a=^abc$', "b=\nabc\ndef", 'c=m');
763 testcase
('', 'P=text', 'a=^abc$', "b=\nabc\ndef");
764 testcase
('true', 'P=text', 'a=abc.', "b=abc\n", 'c=s');
765 testcase
('', 'P=text', 'a=abc.', "b=abc\n");
766 testcase
('true', 'P=text', 'a= ABC #test_comment ', 'b=ABC', 'c=x');
767 testcase
('', 'P=text', 'a= ABC #test_comment ', 'b=ABC');
769 # Feature tests for $sort.
770 print_to_file
$test_template, '$list{$sort{$split{|,$cgi{input}}},|}';
771 testcase
('pineapple', 'input=pineapple');
772 testcase
('apple|banana|coconut', 'input=coconut|banana|apple');
773 testcase
('1|b|b|c', 'input=b|c|b|1');
774 print_to_file
$test_template, '$list{$sort{$split{|,$cgi{input}},$cgi{opt}},|}';
775 testcase
('pineapple', 'input=pineapple', 'opt=');
776 testcase
('pineapple', 'input=pineapple', 'opt=r');
777 testcase
('pineapple', 'input=pineapple', 'opt=ru');
778 testcase
('1|b|c', 'input=b|c|b|1', 'opt=u');
779 testcase
('c|b|b|1', 'input=b|c|b|1', 'opt=r');
780 testcase
('c|b|1', 'input=b|c|b|1', 'opt=ur');
781 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');
782 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');
783 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');
784 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');
785 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');
786 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');
787 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=#');
789 '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',
790 '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',
792 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');
793 testcase
('Exception: Unknown $sort option: x', 'input=b|c|b|1', 'opt=urx');
794 testcase
('Exception: Invalid $sort option combination: n#', 'input=b|c', 'opt=n#');
795 testcase
('Exception: Invalid $sort option combination: #rn', 'input=b|1', 'opt=#rn');
797 # Regression test to test suppression of Content-Type header for early
799 testcase
('Exception: HITSPERPAGE parameter must be >= 0', 'HITSPERPAGE=-1');
801 # Regression test for $sort bug fixed in 1.4.12.
802 # Check $sort doesn't ensure_match (or ensure_query).
803 print_to_file
$test_template, '$sort{test} $addfilter{Test}$querydescription';
804 testcase
('test Query(Test)');
806 # Feature tests for $filesize.
807 print_to_file
$test_template, '$filesize{$cgi{size}}';
808 testcase
('', 'size=');
809 testcase
('', 'size=-1');
810 testcase
('0 bytes', 'size=0');
811 testcase
('1 byte', 'size=1');
812 testcase
('2 bytes', 'size=2');
813 testcase
('1023 bytes', 'size=1023');
814 testcase
('1.0K', 'size=1024');
815 testcase
('1.1K', 'size=1127');
816 testcase
('16.0K', 'size=16384');
817 testcase
('1.0M', 'size=1048576');
818 testcase
('1.8G', 'size=2000000000');
819 testcase
('Exception: Filesize must be an integer', 'size=foo');
820 testcase
('Exception: Filesize must be an integer', 'size=1a');
821 testcase
('Exception: Filesize must be an integer', 'size=1.1');
823 # Feature tests for $keys.
824 print_to_file
$test_template, '$setmap{x,bee,1,eel,6,dog,4,ant,2,fox,5,cat,3}/$list{$keys{x},|}/$keys{nosuch}/';
825 testcase
('/ant|bee|cat|dog|eel|fox//');
827 # Feature tests for $log.
828 remove_tree
($test_log);
829 # Chop off any error message at ": " so the test output doesn't depend on
830 # strerror() output, which can vary with platform and locale.
831 print_to_file
$test_template, '$slice{$split{: ,$log{$cgi{LOG},$log{' . $test_log . '}}},0}';
832 testcase
('filename can\'t contain ".."', 'LOG=evil/parent/..');
834 remove_tree
($test_log);
835 print "log entry not lazily evaluated for bad log file name\n";
838 testcase
('open failed', 'LOG=open/should/fail', 'ENTRY=$log{' . $test_log . '}');
840 remove_tree
($test_log);
841 print "log entry not lazily evaluated for open failure\n";
844 print_to_file
$test_template, '$log{' . $test_log . ',$lower{TEST}}';
847 open my $log, '<', $test_log or die $!;
849 my $log_entry = <$log>;
851 if ($log_entry !~ /^test\r?\n$/) {
852 print "log entry not written correctly\n";
856 unlink $test_log or die $!;
858 # Feature tests for $terms.
859 print_to_file
$test_indexscript, "text : index\nhost : boolean=H\nfoo : boolean=XFOO";
860 run_scriptindex
(<<'END');
861 text=This is some text.
865 print_to_file
$test_template, '$hitlist{$list{$if{$eq{$cgi{prefix},null},$terms,$terms{$cgi{prefix}}},|}}';
866 testcase
('Ztext', 'P=text', 'B=Hexample.org', 'B=Hexample.com', 'prefix=null');
867 testcase
('Hexample.org|Ztext', 'P=text', 'B=Hexample.org', 'B=Hexample.com', 'prefix=');
868 testcase
('Hexample.org', 'P=text', 'B=Hexample.org', 'B=Hexample.com', 'prefix=H');
869 testcase
('Ztext', 'P=text', 'B=Hexample.org', 'B=Hexample.com', 'prefix=Z');
870 testcase
('', 'P=text', 'B=Hexample.org', 'B=Hexample.com', 'prefix=E');
872 print_to_file
$test_template, '$msizelower $msize $msizeupper $msizeexact';
873 testcase
('1 1 1 true', 'P=this');
874 testcase
('1 1 1 true', 'P=Some text');
875 testcase
('0 0 0 true', 'P=potato');
877 print_to_file
$test_template, '$set{weighting,$cgi{w}}$hitlist{$weight.}$or{$error,OK}';
878 testcase
('OK', 'w=bb2');
879 testcase
('OK', 'w=bb2 .5');
880 testcase
("InvalidArgumentError: Parameter is invalid: 'bb2 x'", 'w=bb2 x');
881 testcase
("InvalidArgumentError: Extra data after parameter: 'bb2 .5 .5'", 'w=bb2 .5 .5');
882 testcase
('OK', 'w=bm25');
883 testcase
('OK', 'w=bm25 1 1 1 1 1');
884 testcase
("InvalidArgumentError: Parameter 5 (min_normlen) is invalid: 'bm25 1 1 1 1 x'", 'w=bm25 1 1 1 1 x');
885 testcase
("InvalidArgumentError: Extra data after parameter 5: 'bm25 1 1 1 1 1 1'", 'w=bm25 1 1 1 1 1 1');
886 testcase
('OK', 'w=bm25+');
887 testcase
('OK', 'w=bm25+ 1 1 1 1 1 1');
888 testcase
("InvalidArgumentError: Parameter 6 (delta) is invalid: 'bm25+ 1 1 1 1 1 x'", 'w=bm25+ 1 1 1 1 1 x');
889 testcase
("InvalidArgumentError: Extra data after parameter 6: 'bm25+ 1 1 1 1 1 1 1'", 'w=bm25+ 1 1 1 1 1 1 1');
890 testcase
('OK', 'w=bool');
891 testcase
('InvalidArgumentError: No parameters are required for BoolWeight', 'w=bool 1');
892 testcase
('OK', 'w=coord');
893 testcase
('InvalidArgumentError: No parameters are required for CoordWeight', 'w=coord 1');
894 testcase
('OK', 'w=dlh');
895 testcase
('InvalidArgumentError: No parameters are required for DLHWeight', 'w=dlh 1');
896 testcase
('OK', 'w=dph');
897 testcase
('InvalidArgumentError: No parameters are required for DPHWeight', 'w=dph 1');
898 testcase
('OK', 'w=ifb2');
899 testcase
('OK', 'w=ifb2 .5');
900 testcase
("InvalidArgumentError: Parameter is invalid: 'ifb2 x'", 'w=ifb2 x');
901 testcase
("InvalidArgumentError: Extra data after parameter: 'ifb2 .5 1'", 'w=ifb2 .5 1');
902 testcase
('OK', 'w=ineb2');
903 testcase
('OK', 'w=ineb2 .5');
904 testcase
("InvalidArgumentError: Parameter is invalid: 'ineb2 x'", 'w=ineb2 x');
905 testcase
("InvalidArgumentError: Extra data after parameter: 'ineb2 .5 1'", 'w=ineb2 .5 1');
906 testcase
('OK', 'w=inl2');
907 testcase
('OK', 'w=inl2 .5');
908 testcase
("InvalidArgumentError: Parameter is invalid: 'inl2 x'", 'w=inl2 x');
909 testcase
("InvalidArgumentError: Extra data after parameter: 'inl2 .5 1'", 'w=inl2 .5 1');
910 testcase
('OK', 'w=pl2');
911 testcase
('OK', 'w=pl2 .5');
912 testcase
("InvalidArgumentError: Parameter is invalid: 'pl2 x'", 'w=pl2 x');
913 testcase
("InvalidArgumentError: Extra data after parameter: 'pl2 .5 1'", 'w=pl2 .5 1');
914 testcase
('OK', 'w=pl2+');
915 testcase
('OK', 'w=pl2+ .5 .5');
916 testcase
("InvalidArgumentError: Parameter 2 (delta) is invalid: 'pl2+ .5 x'", 'w=pl2+ .5 x');
917 testcase
("InvalidArgumentError: Extra data after parameter 2: 'pl2+ .5 .5 1'", 'w=pl2+ .5 .5 1');
918 testcase
('OK', 'w=tfidf');
919 testcase
('OK', 'w=tfidf ntn');
920 testcase
("InvalidArgumentError: Parameter 1 (wdf_normalisation) is invalid: 'tfidf ntn 1'", 'w=tfidf ntn 1');
921 testcase
('OK', 'w=trad');
922 testcase
('OK', 'w=trad 1.5');
923 testcase
("InvalidArgumentError: Parameter is invalid: 'trad x'", 'w=trad x');
924 testcase
("InvalidArgumentError: Extra data after parameter: 'trad 1.5 1'", 'w=trad 1.5 1');
925 testcase
('InvalidArgumentError: Unknown weighting scheme: invalid', 'w=invalid');
927 print_to_file
$test_template, '$set{weighting,coord}$hitlist{$weight.}';
928 testcase
('', 'P=aardvark');
929 testcase
('1.000000.', 'P=texting');
930 testcase
('', 'P=texting while driving');
931 testcase
('', 'P=texting while driving', 'DEFAULTOP=AND');
932 testcase
('1.000000.', 'P=texting while driving', 'DEFAULTOP=OR');
933 testcase
('2.000000.', 'P=Some text');
934 # "this" and "is" are stopwords.
935 testcase
('2.000000.', 'P=This is some text');
936 testcase
('4.000000.', 'P="This" "is" some text');
937 testcase
('4.000000.', 'P=+This +is some text');
938 testcase
('4.000000.', 'P="This is some text"');
940 print_to_file
$test_template, '$set{weightingpurefilter,coord}$hitlist{$weight.}';
941 testcase
('', 'B=XFOOfoo');
942 testcase
('1.000000.', 'B=Hexample.org');
943 testcase
('', 'B=Hexample.org', 'B=XFOOfoo');
944 testcase
('1.000000.', 'B=Hexample.org', 'B=Hexample.net');
945 testcase
('2.000000.', 'B=Hexample.org', 'B=XFOObar');
946 testcase
('3.000000.', 'B=Hexample.org', 'B=XFOObar', 'B=XFOObar');
948 # Test filter encoding.
949 print_to_file
$test_template, '$filters';
950 testcase
('CHexample.net93org5', 'B=Hexample.org', 'B=Hexample.net');
951 testcase
('!AGmisc.test5', 'N=Gmisc.test');
952 testcase
('CHexample.net93org!AGmisc.misc64test5', 'B=Hexample.org', 'B=Hexample.net', 'N=Gmisc.test', 'N=Gmisc.misc');
953 testcase
('$1!200406125', 'DATEVALUE=1', 'START=20040612');
954 testcase
('$1!200406125', 'START.1=20040612');
955 testcase
('.2$1!200406125', 'DATEVALUE=1', 'START=20040612', 'COLLAPSE=2');
956 testcase
('.2$1!200406125', 'START.1=20040612', 'COLLAPSE=2');
957 testcase
('.2$!20040612~305', 'START=20040612', 'SPAN=30', 'COLLAPSE=2');
958 testcase
('$!20040612.201604125', 'START=20040612', 'END=20160412');
959 testcase
('.25', 'COLLAPSE=2');
961 testcase
('15', 'SORT=1');
962 testcase
('14', 'SORT=+1');
963 testcase
('15', 'SORT=-1');
964 testcase
('1-2+3-R5', 'SORT=+1-2+03,-27');
965 testcase
('5', 'SORTREVERSE=1');
966 testcase
('14', 'SORT=1', 'SORTREVERSE=1');
967 testcase
('15', 'SORT=+1', 'SORTREVERSE=1');
968 testcase
('14', 'SORT=-1', 'SORTREVERSE=1');
969 testcase
('1-2+3-R4', 'SORT=+1-2+03,-27', 'SORTREVERSE=1');
970 testcase
('5', 'SORTAFTER=1');
971 testcase
('17', 'SORT=1', 'SORTAFTER=1');
972 testcase
('16', 'SORT=+1', 'SORTAFTER=1');
973 testcase
('17', 'SORT=-1', 'SORTAFTER=1');
974 testcase
('1-2+3-R7', 'SORT=+1-2+03,-27', 'SORTAFTER=1');
975 testcase
('5', 'SORTREVERSE=1', 'SORTAFTER=1');
976 testcase
('16', 'SORT=1', 'SORTREVERSE=1', 'SORTAFTER=1');
977 testcase
('17', 'SORT=+1', 'SORTREVERSE=1', 'SORTAFTER=1');
978 testcase
('16', 'SORT=-1', 'SORTREVERSE=1', 'SORTAFTER=1');
979 testcase
('1-2+3-R6', 'SORT=+1-2+03,-27', 'SORTREVERSE=1', 'SORTAFTER=1');
980 testcase
('5', 'DOCIDORDER=A');
981 testcase
('1', 'DOCIDORDER=D');
982 testcase
('9', 'DOCIDORDER=X');
983 testcase
('9', 'DOCIDORDER=x');
985 # Test old filter encoding.
986 print_to_file
$test_template, '$filters{x}';
987 testcase
('Hexample.net~Hexample.org~.~~', 'B=Hexample.org', 'B=Hexample.net');
988 testcase
('!Gmisc.test~.~~', 'N=Gmisc.test');
989 testcase
('Hexample.net~Hexample.org~!Gmisc.misc~!Gmisc.test~.~~', 'B=Hexample.org', 'B=Hexample.net', 'N=Gmisc.test', 'N=Gmisc.misc');
990 testcase
('.20040612~~~1~', 'DATEVALUE=1', 'START=20040612');
991 testcase
('.20040612~~~1~2', 'DATEVALUE=1', 'START=20040612', 'COLLAPSE=2');
992 testcase
('.20040612~~30~2', 'START=20040612', 'SPAN=30', 'COLLAPSE=2');
993 testcase
('.20040612~20160412~', 'START=20040612', 'END=20160412');
994 testcase
('.~~~2', 'COLLAPSE=2');
996 testcase
('.~~1', 'SORT=1');
997 testcase
('.~~1f', 'SORT=+1');
998 testcase
('.~~1', 'SORT=-1');
999 testcase
('.~~1-2+3-27', 'SORT=+1-2+03,-27');
1000 testcase
('.~~', 'SORTREVERSE=1');
1001 testcase
('.~~1f', 'SORT=1', 'SORTREVERSE=1');
1002 testcase
('.~~1', 'SORT=+1', 'SORTREVERSE=1');
1003 testcase
('.~~1f', 'SORT=-1', 'SORTREVERSE=1');
1004 testcase
('.~~1-2+3-27f', 'SORT=+1-2+03,-27', 'SORTREVERSE=1');
1005 testcase
('.~~', 'SORTAFTER=1');
1006 testcase
('.~~1R', 'SORT=1', 'SORTAFTER=1');
1007 testcase
('.~~1F', 'SORT=+1', 'SORTAFTER=1');
1008 testcase
('.~~1R', 'SORT=-1', 'SORTAFTER=1');
1009 testcase
('.~~1-2+3-27R', 'SORT=+1-2+03,-27', 'SORTAFTER=1');
1010 testcase
('.~~', 'SORTREVERSE=1', 'SORTAFTER=1');
1011 testcase
('.~~1F', 'SORT=1', 'SORTREVERSE=1', 'SORTAFTER=1');
1012 testcase
('.~~1R', 'SORT=+1', 'SORTREVERSE=1', 'SORTAFTER=1');
1013 testcase
('.~~1F', 'SORT=-1', 'SORTREVERSE=1', 'SORTAFTER=1');
1014 testcase
('.~~1-2+3-27F', 'SORT=+1-2+03,-27', 'SORTREVERSE=1', 'SORTAFTER=1');
1015 testcase
('.~~X', 'DOCIDORDER=A'); # Buggy, but kept for compatibility.
1016 testcase
('.~~D', 'DOCIDORDER=D');
1017 testcase
('.~~', 'DOCIDORDER=X'); # Buggy, but kept for compatibility.
1018 testcase
('.~~', 'DOCIDORDER=x'); # Buggy, but kept for compatibility.
1020 print_to_file
$test_template, '$cgi{AZ}|$cgi{AZ B}|$cgi{AZ.x}|$cgi{AZ.y}|$cgi{[}|$cgi{#}';
1021 testcase
('AZ|||||', 'AZ.x=3', 'AZ.y=4');
1022 testcase
('B|||||', 'AZ B.x=5', 'AZ B.y=12');
1023 testcase
('B|||||', "AZ\tB.x=5", "AZ\tB.y=12");
1024 testcase
('||||2 ]|', '[ 2 ].x=123');
1025 testcase
('||||2 ]|', "[\t2 ].x=123");
1026 testcase
("||||2\t]|", "[ 2\t].x=123");
1027 testcase
("||||2\t]|", "[\t2\t].x=123");
1028 testcase
('|||||12', '12.x=37');
1029 testcase
('DE|||||', 'AZ BC=DE');
1030 testcase
('DE|||||', 'AZ B C=DE');
1031 testcase
('DE|||||', "AZ\tBC=DE");
1032 testcase
('DE|||||', "AZ B\tC=DE");
1033 testcase
('DE|||||', "AZ\tB C=DE");
1034 testcase
('DE|||||', "AZ\tB\tC=DE");
1036 print_to_file
$test_template, '$cgi{Search}|$cgi{Type}|$cgi{Search Type}';
1037 testcase
('Discover-List||', 'Search Type=Discover-List');
1039 print_to_file
$test_template, '$cgiparams';
1040 # We can't test the "no cgi parameters" case via testcase, as it passes a
1041 # "dummy" parameter if there aren't any real ones.
1044 testcase
("ABC", 'ABC=1');
1045 testcase
("ABC", 'ABC=1', 'ABC=2');
1046 testcase
("A\tAZ\tZ", 'A=1', 'A=2', 'A=3', 'AZ=1', 'AZ=2', 'Z=xxx');
1047 testcase
("\tabc", '=1', 'abc=1');
1048 testcase
("\tabc\tdef", '=1', 'abc=1', 'def=7');
1050 # Feature tests for $highlight{}.
1051 print_to_file
$test_template, '$highlight{$cgi{text},$cgi{list}}';
1052 testcase
('A <b style="color:black;background-color:#ffff66">list</b> of <b style="color:black;background-color:#99ff99">words</b>', "list=list\twords", "text=A list of words");
1054 print_to_file
$test_template, '$highlight{$cgi{text},$cgi{list},$cgi{open}}';
1055 testcase
('A list of <b>words</b>', "list=words", "text=A list of words", "open=<b>");
1056 testcase
('A list of <span>words</span>', "list=words", "text=A list of words", "open=<span>");
1058 print_to_file
$test_template, '$highlight{$cgi{text},$cgi{list},$cgi{open},$cgi{close}}';
1059 testcase
('A list of <b>words</b>', "list=words", "text=A list of words", "open=<b>", "close=</b>");
1060 testcase
('A *list* of *words*', "list=words\tlist", "text=A list of words", "open=*", "close=*");
1062 # Test setting seterror and mset size, should not run the query after setting error.
1063 print_to_file
$test_template, '$if{$cgi{ERR},$seterror{$cgi{ERR}}}$msize$if{$error,!$error!}';
1064 testcase
('1', 'P=text');
1065 testcase
('0!boo!', 'P=text', 'ERR=boo');
1067 # Test arguments inside seterror are evaluated
1068 print_to_file
$test_template, '$set{error,sample error}$seterror{$opt{error}}$msize$if{$error,!$error!}';
1069 testcase
('0!sample error!', 'P=text');
1071 # Test error message doesn't get sent through HTML entity encoding.
1072 print_to_file
$test_template, '$seterror{{ "error": true, "error_message": "Parameter cannot be > 9" }}$if{$error,$error}';
1073 testcase
('{ "error": true, "error_message": "Parameter cannot be > 9" }', 'P=text');
1075 # Test msize when error set after running query, should not affect running of query.
1076 print_to_file
$test_template, '$last$if{$cgi{ERR},$seterror{$cgi{ERR}}}$msize$if{$error,!$error!}';
1077 testcase
('11', 'P=text');
1078 testcase
('11!boo!', 'P=text', 'ERR=boo');
1080 # Feature tests for $hash{}
1081 print_to_file
$test_template, '$hash{$cgi{text},md5}';
1082 testcase
('098f6bcd4621d373cade4e832627b4f6', "text=test");
1083 testcase
('b4c216e4da73d1d01277ef46d0514821', "text=simple query");
1084 testcase
('d41d8cd98f00b204e9800998ecf8427e', "text=");
1085 testcase
('3302c94d3500c3f695b7e09b7acd420d', "text= test ");
1087 # Feature tests for $base64{}
1088 print_to_file
$test_template, '$base64{$cgi{in}}';
1089 testcase
('', "in=");
1090 testcase
('IQ==', 'in=!');
1091 testcase
('T2s=', 'in=Ok');
1092 testcase
('aGA+aGA/', 'in=h`>h`?');
1093 testcase
('YmFzZTY0IHRlc3Q=', 'in=base64 test');
1095 # Feature tests for $random{}
1096 print_to_file
$test_template, '$or{$list{$map{$range{1,100},$set{num,$random{$cgi{x}}}$or{$lt{$opt{num},0},$gt{$opt{num},$cgi{x}}}},},OK}';
1097 testcase
('OK', 'x=6');
1099 # Regression test - original implementation truncated data at first zero byte.
1100 print_to_file
$test_template, '$hash{$cgi{text}$chr{0},md5}';
1101 testcase
('e2a3e68d23ce348b8f68b3079de3d4c9', "text=test");
1103 print_to_file
$test_template, '$hash{$cgi{text},invalidhash}';
1104 testcase
('Exception: Unknown hash function: invalidhash', "text=test");
1106 # Regression test: $setrelevant crashed with no argument list prior to 1.4.16.
1107 print_to_file
$test_template, '$setrelevant$or{$error,No error}';
1108 testcase
('Exception: too few arguments to $setrelevant', 'P=text');
1109 print_to_file
$test_template, '$setrelevant{}$or{$error,No error}';
1110 testcase
('No error', 'P=text');
1112 # Feature tests for $uniq and $unique{}.
1113 print_to_file
$test_template, '$list{$uniq{$split{$cgi{text}}},:}|$list{$unique{$split{$cgi{text}}},:}';
1114 testcase
('|', 'text=');
1115 testcase
('foo|foo', 'text=foo');
1116 testcase
('apple:banana:cherry|apple:banana:cherry', 'text=apple apple banana banana banana cherry');
1117 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');
1118 testcase
('x:y:z:y|x:y:z', 'text=x y z z y');
1120 # Regression test - $map with one argument wasn't rejected cleanly.
1121 print_to_file
$test_template, '$map{foo}';
1122 testcase
('Exception: too few arguments to $map');
1124 # Feature tests for $snippet{}.
1125 print_to_file
$test_indexscript, 'text : index field';
1126 # Omit trailing \n on dump file as regression test for bug fixed in 1.4.20
1127 # where a final line without a newline was ignored.
1128 run_scriptindex
("dummy=\ntext=A sentence is more than just a list of words - there is structure to it.");
1130 print_to_file
$test_template, '$hitlist{$snippet{$field{text},20}}';
1131 testcase
('...just a <strong>list</strong> of <strong>words</strong>...', 'P=word listing');
1133 print_to_file
$test_template, '$hitlist{$snippet{$field{text},30,,<b>,</b>,}}';
1134 testcase
('<b>words</b> - there is structure to', 'P=words');
1135 testcase
('a <b>list of words</b> - there is', 'P="list of words"');
1137 # Test MORELIKE CGI parameter.
1138 print_to_file
$test_indexscript, "id : boolean=Q\ntext : index field\n";
1139 run_scriptindex
(<<'END');
1147 text=Piece of writing three
1150 text=Inflating termfreqs since Omega excludes terms with termfreq of one
1151 =first document second piece of writing three
1153 print_to_file
$test_template, '$querydescription|$query';
1154 testcase
('Query((Zfirst@1 OR Zdocument@2))|first document', 'MORELIKE=Qa1', 'DEFAULTOP=or');
1155 testcase
('Query((Zfirst@1 OR Zdocument@2))|first OR document', 'MORELIKE=Qa1');
1156 testcase
('Query((Zfirst@1 OR Zdocument@2))|first OR document', 'MORELIKE=Qa1', 'DEFAULTOP=and');
1158 testcase
('Query((Zfirst@1 OR Zdocument@2))|first document', 'MORELIKE=1', 'DEFAULTOP=OR');
1159 testcase
('Query((Zfirst@1 OR Zdocument@2))|first OR document', 'MORELIKE=1');
1160 testcase
('Query((Zfirst@1 OR Zdocument@2))|first OR document', 'MORELIKE=1', 'DEFAULTOP=phrase');
1161 # "article" is excluded by OmegaExpandDecider because it has termfreq 1.
1162 testcase
('Query(Zsecond@1)|second', 'MORELIKE=Qb2', 'DEFAULTOP=or');
1163 testcase
('Query(Zsecond@1)|second', 'MORELIKE=Qb2');
1164 # "of" is excluded because it's a stopword.
1165 testcase
('Query((Zwrite@1 OR Zthree@2 OR Zpiec@3))|writing OR three OR piece', 'MORELIKE=Qc3');
1166 # Test with absent term.
1167 testcase
('Query()|', 'MORELIKE=Qx9');
1168 # Test multiple MORELIKE parameters. We need to include the dummy document for
1169 # any terms to get a positive weight and be returned.
1170 testcase
('Query((Zsecond@1 OR Zfirst@2 OR Zdocument@3))|second OR first OR document', 'MORELIKE=1', 'MORELIKE=2', 'MORELIKE=4');
1171 testcase
('Query((Zsecond@1 OR Zfirst@2 OR Zdocument@3))|second OR first OR document', 'MORELIKE=Qa1', 'MORELIKE=2', 'MORELIKE=4');
1172 testcase
('Query((Zsecond@1 OR Zfirst@2 OR Zdocument@3))|second OR first OR document', 'MORELIKE=Qa1', 'MORELIKE=Qb2', 'MORELIKE=Qdummy');
1174 # Test errors for scriptindex input format issues.
1175 print_to_file
$test_indexscript, 'f : index field';
1176 test_scriptindex_error
"no = in input line",
1177 "<stdin>:1: error: Expected = somewhere in this line",
1179 test_scriptindex_error
"no = in input line",
1180 "<stdin>:2: error: Expected = somewhere in this line",
1182 test_scriptindex_error
"no = in input line",
1183 "<stdin>:3: error: Expected = somewhere in this line",
1184 "a=x\n=yz\nbcd\ne=q";
1186 # Test handling of extra blank lines.
1187 print_to_file
$test_indexscript, "id : unique=Q boolean=Q\nf : field";
1188 test_scriptindex
"extra blank lines",
1189 "\nid=1\nf=a\n\n\nid=2\nf=b\n\n";
1190 test_scriptindex
"extra blank lines with CRs",
1191 "\r\nid=1\r\nf=a\r\n\r\n\r\nid=2\r\nf=b\r\n\r\n";
1193 # Regression test for handling of no newline on final line, fixed in 1.4.22.
1195 # This used to report a bogus error on the last line:
1196 # error: Expected = somewhere in this line
1197 test_scriptindex
"no newline on final line",
1198 "id=1\nf=hello\n=world";
1200 # Feature tests for scriptindex `index` and `indexnopos` actions.
1201 print_to_file
$test_indexscript, "t : index=XT\nn : indexnopos=XN\n";
1202 test_scriptindex
'INDEX and INDEXNOPOS actions',
1203 "t=positional text\nn=no pos here";
1204 print_to_file
$test_template, '$msize';
1205 testcase
('1', 'P.XT="positional text"');
1206 testcase
('1', 'P.XN=no AND pos');
1207 testcase
('0', 'P.XN="no pos"');
1209 # Feature tests for scriptindex `split` action.
1210 print_to_file
$test_indexscript, "STATUS : field split=| field=SPLITSTATUS\nSTATUS : field=x";
1211 test_scriptindex
'SPLIT action',
1212 'STATUS=PENDING|REVIEW';
1213 print_to_file
$test_template, '$field{STATUS,1}/$field{x,1}/$list{$field{SPLITSTATUS,1},$.}';
1214 testcase
('PENDING|REVIEW/PENDING|REVIEW/PENDING,REVIEW', 'P=text');
1216 # Feature test for scriptindex `split` action with `dedup` operation.
1217 print_to_file
$test_indexscript, "STATUS : field split=|,dedup field=SPLITSTATUS\n";
1218 test_scriptindex
'test SPLIT with DEDUP',
1219 'STATUS=REVIEW|PENDING|PENDING|REVIEW';
1220 print_to_file
$test_template, '$field{STATUS,1}/$list{$field{SPLITSTATUS,1},$.}';
1221 testcase
('REVIEW|PENDING|PENDING|REVIEW/REVIEW,PENDING', 'P=text');
1223 # Feature test for scriptindex `split` action with `sort` operation.
1224 print_to_file
$test_indexscript, "STATUS : field split=|,sort field=SPLITSTATUS\n";
1225 test_scriptindex
'test SPLIT with SORT',
1226 'STATUS=REVIEW|PENDING|PENDING|REVIEW';
1227 print_to_file
$test_template, '$field{STATUS,1}/$list{$field{SPLITSTATUS,1},$.}';
1228 testcase
('REVIEW|PENDING|PENDING|REVIEW/PENDING,PENDING,REVIEW,REVIEW', 'P=text');
1230 # Feature test for scriptindex `split` action with `none` operation.
1231 print_to_file
$test_indexscript, "STATUS : field split=|,none field=SPLITSTATUS\n";
1232 test_scriptindex
'test SPLIT with NONE',
1233 'STATUS=REVIEW|PENDING|PENDING|REVIEW';
1234 print_to_file
$test_template, '$field{STATUS,1}/$list{$field{SPLITSTATUS,1},$.}';
1235 testcase
('REVIEW|PENDING|PENDING|REVIEW/REVIEW,PENDING,PENDING,REVIEW', 'P=text');
1237 # Feature test for scriptindex `split` action with `prefixes` operation.
1238 print_to_file
$test_indexscript, "STATUS : field split=|,prefixes field=SPLITSTATUS\n";
1239 test_scriptindex
'test SPLIT with PREFIXES',
1240 'STATUS=REVIEW|PENDING|PENDING|REVIEW';
1241 print_to_file
$test_template, '$field{STATUS,1}/$list{$field{SPLITSTATUS,1},$.}';
1242 testcase
('REVIEW|PENDING|PENDING|REVIEW/REVIEW,REVIEW|PENDING,REVIEW|PENDING|PENDING,REVIEW|PENDING|PENDING|REVIEW', 'P=text');
1244 # Feature tests for scriptindex `split` action with no explicit operation.
1245 print_to_file
$test_indexscript, "STATUS : field split=| field=SPLITSTATUS\n";
1246 test_scriptindex
'test SPLIT with implicit op',
1247 'STATUS=PENDING|REVIEW|PENDING|REVIEW';
1248 print_to_file
$test_template, '$field{STATUS,1}/$list{$field{SPLITSTATUS,1},$.}';
1249 testcase
('PENDING|REVIEW|PENDING|REVIEW/PENDING,REVIEW,PENDING,REVIEW', 'P=text');
1251 # Feature test for scriptindex `split` action with multi-character delimiter.
1252 print_to_file
$test_indexscript, 'STATUS : field split=$. field=SPLITSTATUS';
1253 test_scriptindex
'test SPLIT with multi-char delimiter',
1254 'STATUS=PENDING$.$.REVIEW,PENDING$.REVIEW';
1255 print_to_file
$test_template, '$field{STATUS,1}/$list{$field{SPLITSTATUS,1},|}';
1256 testcase
('PENDING$.$.REVIEW,PENDING$.REVIEW/PENDING|REVIEW,PENDING|REVIEW', 'P=text');
1258 # Feature test for scriptindex `split` action with multi-character delimiter
1259 # with potential overlap.
1260 print_to_file
$test_indexscript, "STATUS : field split=:: field=SPLITSTATUS\n";
1261 test_scriptindex
'test SPLIT with overlapping multi-char delimiter',
1262 'STATUS=::Foo::::Bar:Baz:::Hello::';
1263 print_to_file
$test_template, '$field{STATUS,1}/$list{$field{SPLITSTATUS,1},|}';
1264 testcase
('::Foo::::Bar:Baz:::Hello::/Foo|Bar:Baz|:Hello', 'P=text');
1266 # Feature test for scriptindex `split` action with multi-character delimiter
1267 # with `prefixes` operation.
1268 print_to_file
$test_indexscript, "STATUS : field split=::,prefixes field=SPLITSTATUS\n";
1269 test_scriptindex
'test SPLIT with PREFIXES and multi-char delimiter',
1270 'STATUS=::Foo::::Bar:Baz:::Hello::';
1271 print_to_file
$test_template, '$field{STATUS,1}/$list{$field{SPLITSTATUS,1},|}';
1272 testcase
('::Foo::::Bar:Baz:::Hello::/::Foo|::Foo::|::Foo::::Bar:Baz|::Foo::::Bar:Baz:::Hello|::Foo::::Bar:Baz:::Hello::', 'P=text');
1274 # Feature test for scriptindex `split` action with quoted `,` delimiter.
1275 print_to_file
$test_indexscript, "STATUS : field split=\",\" field=SPLITSTATUS\n";
1276 test_scriptindex
'test SPLIT with quoted comma delimiter',
1277 'STATUS=PENDING,REVIEW,PENDING,REVIEW';
1278 print_to_file
$test_template, '$field{STATUS,1}/$list{$field{SPLITSTATUS,1},|}';
1279 testcase
('PENDING,REVIEW,PENDING,REVIEW/PENDING|REVIEW|PENDING|REVIEW', 'P=text');
1281 # Feature test for nested scriptindex `split` action.
1282 print_to_file
$test_indexscript, "in : split=; field=one lower split=\",\" field=two\nin : field";
1283 test_scriptindex
'nested SPLIT action',
1284 'in=a,b,c;10,21,32;XY,YZ';
1285 print_to_file
$test_template, '$field{in,1}/$list{$field{one,1},|}/$list{$field{two,1},|}';
1286 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');
1288 # Test scriptindex `split` action error cases.
1289 print_to_file
$test_indexscript, "in : split=\"\" field=one\nin : field";
1290 test_scriptindex_error
"'split' error for empty separator",
1291 "$test_indexscript:1:13: error: Split delimiter can't be empty";
1292 print_to_file
$test_indexscript, "in : split=|,foo field=one\nin : field";
1293 test_scriptindex_error
"'split' error for invalid operation",
1294 "$test_indexscript:1:14: error: Bad split operation 'foo'";
1296 # Feature tests for scriptindex `hextobin` action.
1297 print_to_file
$test_indexscript, 'hex : hextobin value=0';
1298 test_scriptindex
'HEXTOBIN action',
1307 print_to_file
$test_template, '$valuelowerbound{0}$list{$map{$split{$cgi{DOCIDS}},$value{0,$_}},|}|$valueupperbound{0}';
1308 testcase
('A|A|Test|Kill|Test', 'DOCIDS=1 2 3 4');
1310 # Feature test error cases for scriptindex `hextobin` action.
1311 test_scriptindex_error
'bad hex digit',
1312 "<stdin>:1: error: hextobin: input must be all hex digits",
1314 test_scriptindex_error
'bad hex length',
1315 "<stdin>:1: error: hextobin: input must have even length",
1318 # Feature test for scriptindex `spell` action.
1319 print_to_file
$test_indexscript, "s : spell index\nn : index\n";
1320 test_scriptindex
'SPELL action',
1321 "s=some words test\n\nn=tent\n\n";
1322 print_to_file
$test_template, '$set{flag_spelling_correction,true}$suggestion';
1323 testcase
('some test', 'P=home nest');
1324 testcase
('a test', 'P=a tent');
1325 testcase
('', 'P=gent');
1327 # Feature tests for scriptindex `squash` and `ltrim`/`rtrim`/`trim` actions.
1328 print_to_file
$test_indexscript, "squash : squash field\nltrim : ltrim field\nrtrim : rtrim field\ntrim : trim field\n";
1329 my $whitespace_test="\t lots\x0b\fof\t whitespace\f ";
1330 test_scriptindex
'SQUASH and trim actions',
1331 "squash=$whitespace_test
1332 ltrim=$whitespace_test
1333 rtrim=$whitespace_test
1334 trim=$whitespace_test
1346 print_to_file
$test_template, '$json{$field{$cgi{F},$cgi{ID}}}';
1347 testcase
('lots of whitespace', 'F=squash', 'ID=1');
1348 testcase
('lots\u000b\fof\t whitespace\f ', 'F=ltrim', 'ID=1');
1349 testcase
('\t lots\u000b\fof\t whitespace', 'F=rtrim', 'ID=1');
1350 testcase
('lots\u000b\fof\t whitespace', 'F=trim', 'ID=1');
1351 for my $f (qw(squash ltrim rtrim trim)) {
1352 testcase
('a b', "F=$f", 'ID=2');
1353 testcase
('xyz', "F=$f", 'ID=3');
1356 # Feature tests for scriptindex `truncate` action.
1357 print_to_file
$test_indexscript, "x : field=x truncate=9 field=9 truncate=3 field=3 truncate=2 field=2 truncate=1 field=1 truncate=0 field=0\n";
1358 test_scriptindex
'TRUNCATE action',
1359 'x=really long field
1377 print_to_file
$test_template, '$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}}},|}:}';
1378 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|:|||||:');
1380 # Feature tests for scriptindex `unhtml` and `unxml` actions.
1381 print_to_file
$test_indexscript, "t : unhtml field=h\nt : unxml field=x\n";
1382 test_scriptindex
'UNHTML and UNXML actions',
1385 t=<p>foo</p>d<p>bar<B>b</B></p>
1387 print_to_file
$test_template, '$list{$map{$split{$cgi{DOCIDS}},$field{h,$_}:$field{x,$_}},|}';
1388 testcase
('Notable:No table|foo d barb:foo d bar b', 'DOCIDS=1 2');
1390 # Feature test for scriptindex `weight` action.
1391 print_to_file
$test_indexscript, "t : index\nw : weight=2 index\n";
1392 test_scriptindex
'WEIGHT action',
1398 print_to_file
$test_template, '|$hitlist{$id|}';
1399 testcase
('|3|2|1|', 'P=test');
1401 # Test bad parameter values to `weight` action.
1402 print_to_file
$test_indexscript, 'foo : weight=-2 index weight=1.5 index=A weight=-1.5 index=B';
1403 test_scriptindex_error
"bad 'weight' parameter",
1404 "$test_indexscript:1:14: error: Index action 'weight' takes a non-negative integer argument
1405 $test_indexscript:1:30: error: Index action 'weight' takes a non-negative integer argument
1406 $test_indexscript:1:49: error: Index action 'weight' takes a non-negative integer argument";
1408 # Test useless action warnings.
1409 print_to_file
$test_indexscript, 'foo : index weight=2';
1410 test_scriptindex_warning
"useless 'weight' action",
1411 "$test_indexscript:1:13: warning: Index action 'weight' has no effect
1412 $test_indexscript:1:13: note: Actions are executed from left to right";
1414 print_to_file
$test_indexscript, 'foo : weight=2 weight=3 index';
1415 test_scriptindex_warning
"useless 'weight' action",
1416 "$test_indexscript:1:7: warning: Index action 'weight' has no effect
1417 $test_indexscript:1:7: note: Actions are executed from left to right";
1419 print_to_file
$test_indexscript, 'foo : index lower';
1420 test_scriptindex_warning
"useless 'lower' action",
1421 "$test_indexscript:1:13: warning: Index action 'lower' has no effect
1422 $test_indexscript:1:13: note: Actions are executed from left to right";
1424 # Test bad fieldname errors.
1425 print_to_file
$test_indexscript, 'foo *bar _bar b!ar: index';
1426 test_scriptindex_error
'bad field names',
1427 "$test_indexscript:1:5: error: field name must start with alphanumeric
1428 $test_indexscript:1:10: error: field name must start with alphanumeric
1429 $test_indexscript:1:16: error: bad character '!' in field name";
1431 # Test unwanted action argument.
1432 print_to_file
$test_indexscript, 'foo : spell=test index';
1433 test_scriptindex_error
'unwanted action argument',
1434 "$test_indexscript:1:12: error: Index action 'spell' doesn't take an argument";
1436 # Test missing closing quote.
1437 print_to_file
$test_indexscript, "foo : index=\"XFOO\nbar : index=\"XFOO\\\"\n";
1438 test_scriptindex_error
'missing closing quote',
1439 "$test_indexscript:1:18: error: No closing quote
1440 $test_indexscript:2:20: error: No closing quote";
1442 # Feature tests for scriptindex `termprefix` and `unprefix` actions.
1443 print_to_file
$test_template, '$termprefix{$cgi{B}}|$unprefix{$cgi{B}}';
1444 testcase
('|', 'B=');
1445 testcase
('|something', 'B=something');
1446 testcase
('|42', 'B=42');
1447 testcase
('|3bad', 'B=3bad');
1448 testcase
('|&something', 'B=&something');
1449 testcase
('|:something', 'B=:something');
1450 testcase
('H|example.org', 'B=Hexample.org');
1451 testcase
('K|tag', 'B=Ktag');
1452 testcase
('K|Capital', 'B=KCapital');
1453 testcase
('K|:colon-tag', 'B=K:colon-tag');
1454 testcase
('K|:Capital', 'B=K:Capital');
1455 testcase
('XCOLOUR|red', 'B=XCOLOURred');
1456 testcase
('XPUNC|:colon', 'B=XPUNC::colon');
1457 testcase
('XPUNC|internal:colon', 'B=XPUNC:internal:colon');
1458 testcase
('XPUNC|:Colon', 'B=XPUNC::Colon');
1459 testcase
('XCASE|Upper', 'B=XCASE:Upper');
1460 testcase
('XCASE|TITLE', 'B=XCASE:TITLE');
1461 testcase
('XNUM|42', 'B=XNUM42');
1462 testcase
('XNUM|3bad', 'B=XNUM3bad');
1464 # Regression test for $truncate with maxlen < the length of the indicator
1466 print_to_file
$test_template, '$truncate{$cgi{input},$cgi{maxlen},$cgi{ind},$cgi{ind2}}$seterror{$opt{error}}';
1467 testcase
('w...', 'input=wwwwww', 'maxlen=4', 'ind=...', 'ind2=...');
1468 testcase
('', 'input=s', 'maxlen=0', 'ind=...', 'ind2=...');
1470 # Feature tests for scriptindex `unique` action.
1471 print_to_file
$test_indexscript, "id : boolean=Q unique=Q\nid f : field\n";
1472 test_scriptindex
'UNIQUE action',
1495 print_to_file
$test_template, '$field{id,$cgi{id}}|$field{f,$cgi{id}}$error';
1496 testcase
('1|one', 'id=1');
1497 testcase
('|DocNotFoundError: Document 2 not found', 'id=2');
1498 testcase
('3|', 'id=3');
1499 testcase
('4|', 'id=4');
1501 # Test `unique` action warning.
1502 print_to_file
$test_indexscript, "id : unique=Q boolean=W\nid f : field\n";
1503 test_scriptindex_warning
'unique without boolean',
1504 "$test_indexscript:1:6: warning: Index action 'unique=Q' without 'boolean=Q'
1505 $test_indexscript:1:6: note: 'unique' doesn't implicitly add a boolean term";
1507 # Test `unique` action gives error when not used for a record.
1508 print_to_file
$test_indexscript, "id : boolean=Q unique=Q\nid f : field\n";
1509 test_scriptindex_error
'missing unique field',
1510 "<stdin>:4: error: UNIQUE action unused in this record",
1511 "id=1\nf=wan\n\nf=";
1513 # Test $subdb and $subid.
1514 remove_tree
($test_db);
1515 print_to_file
$test_db, 'inmemory';
1516 print_to_file
"${test_db}2", 'inmemory';
1517 print_to_file
"${test_db}3", "inmemory\ninmemory\n";
1518 print_to_file
$test_template, '$subdb{$cgi{ID}}|$subid{$cgi{ID}}';
1519 testcase
("$test_db|1", 'ID=1');
1520 testcase
("$test_db|1", 'ID=1', "DB=$test_db/${test_db}2");
1521 testcase
("${test_db}2|1", 'ID=2', "DB=$test_db/${test_db}2");
1522 testcase
("${test_db}|2", 'ID=3', "DB=$test_db/${test_db}2");
1523 testcase
("${test_db}3|1", 'ID=1', "DB=${test_db}3");
1524 testcase
("${test_db}3|999", 'ID=999', "DB=${test_db}3");
1525 testcase
("$test_db|1", 'ID=1', "DB=$test_db", "DB=${test_db}3");
1526 testcase
("${test_db}3|1", 'ID=2', "DB=$test_db", "DB=${test_db}3");
1527 testcase
("${test_db}3|2", 'ID=3', "DB=$test_db", "DB=${test_db}3");
1528 testcase
("$test_db|2", 'ID=4', "DB=$test_db", "DB=${test_db}3");
1529 testcase
("${test_db}3|3", 'ID=5', "DB=$test_db", "DB=${test_db}3");
1530 remove_tree
("${test_db}2","${test_db}3");
1532 # Feature tests for $field.
1533 print_to_file
$test_indexscript, 'in : field="zer\0byte" hextobin field="field28\x02\x08"';
1534 run_scriptindex
("in=4071004f3456\n");
1535 print_to_file
$test_template, '$json{$field{zer$chr{0}byte,1}}|$json{$field{field28$chr{2}$chr{8},1}}|$error';
1536 testcase
('4071004f3456|@q\u0000O4V|');
1538 # Feature tests for $jsonarray.
1539 print_to_file
$test_template,
1542 '$jsonarray{,$upper{$_}}',
1543 '$jsonarray{$split{b4 k9},"$json{$upper{$_}}"}',
1544 '$jsonarray{$split{a "b" c:\}}',
1545 '$jsonarray{$split{2 3 5 7},$mul{$_,$_}}');
1546 testcase
('[], [], ["B4","K9"], ["a","\"b\"","c:\\\\"], [4,9,25,49]');
1548 # Feature tests for $jsonbool
1549 print_to_file
$test_template, '$jsonbool{} $jsonbool{$eq{a,b}} $jsonbool{x} $jsonbool{0}';
1550 testcase
('false false true true');
1552 # Feature tests for $jsonobject
1553 print_to_file
$test_template, '$jsonobject{foo}';
1555 print_to_file
$test_template, '$setmap{foo,Han,Solo}$jsonobject{foo}';
1556 testcase
('{"Han":"Solo"}');
1557 print_to_file
$test_template, '$setmap{foo,key 1,value1,key"2,value\2,key3,value3}$jsonobject{foo}';
1558 testcase
('{"key 1":"value1","key\"2":"value\\\\2","key3":"value3"}');
1559 print_to_file
$test_template, '$setmap{foo,key 1,1,key"2,$split{1 2},key3,$split{2 3 5}}$jsonobject{foo,,$jsonarray{$_,$add{$_,1}}}';
1560 testcase
('{"key 1":[2],"key\"2":[2,3],"key3":[3,4,6]}');
1561 print_to_file
$test_template, '$setmap{foo,key 1,,key"2,1,key3,0}$jsonobject{foo,$upper{$_},$jsonarray{$_,$add{$_}}}';
1562 testcase
('{"KEY 1":[],"KEY\"2":[1],"KEY3":[0]}');
1564 # Feature tests for $jsonobject2
1565 print_to_file
$test_template, '$jsonobject2{$split{$cgi{K}},$split{$cgi{V}},,"$json{$upper{$_}}"}$error';
1566 testcase
'{"k1":"VALUE1","k2":"VAL2","key3":"V3"}', 'K=k1 k2 key3', 'V=value1 val2 v3';
1567 testcase
'Exception: $jsonobject2: Different number of keys and values', 'K=1 2', 'V=one';
1568 testcase
'Exception: $jsonobject2: Different number of keys and values', 'K=1', 'V=one two';
1569 testcase
'{"k1":""}', 'K=k1', 'V=';
1570 testcase
'{}', 'K=', 'V=';
1572 # Feature tests for $stoplist
1573 print_to_file
$test_template, '$setmap{prefix,foo,XFOO}[$list{$stoplist,|}]';
1574 testcase
('[a|the]', 'P.XFOO=the test', 'P=a test');
1576 # Feature tests for $unstem
1577 print_to_file
$test_template, '$setmap{prefix,foo,XFOO}[$list{$unstem{$cgi{TERM}},|}]';
1578 testcase
('[pots|pot|potting]', 'P.XFOO=(foo:pot OR luck) (potting OR shed)', 'P=flower OR foo:pots', 'TERM=ZXFOOpot');
1580 # Feature tests of scriptindex.
1582 # Regression test: non-zero exit status for unknown option.
1583 if (system("$scriptindex --to-be-or-not-to-be '$test_db' '$test_indexscript' > /dev/null < /dev/null 2>&1") == 0) {
1584 print "scriptindex didn't give error for unknown option\n";
1588 # Regression test: error given for multiple `unique` actions.
1589 print_to_file
$test_indexscript, "id : boolean=Q unique=Q\nguid : boolean=G unique=G";
1590 test_scriptindex_error
'UNIQUE used more than once',
1591 "$test_indexscript:2:18: error: Index action 'unique' used more than once
1592 $test_indexscript:1:16: note: Previously used here";
1594 # Test we check for hash's argument being an integer (new in 1.4.6).
1595 print_to_file
$test_indexscript, 'url : hash=37.3 boolean=Q unique=Q';
1596 test_scriptindex_error
"'hash' with a non-integer argument",
1597 "$test_indexscript:1:14: error: Index action 'hash' takes an integer argument";
1599 # Test we give a helpful error for an action with a digit in (regression
1600 # test for fix in 1.4.6).
1602 # This used to give the confusing:
1603 # Unknown index action ''
1604 print_to_file
$test_indexscript, 'url : index4';
1605 test_scriptindex_error
'bad index action with a digit',
1606 "$test_indexscript:1:7: error: Unknown index action 'index4'";
1608 # Test we give a helpful error when we're expecting an action but don't get
1609 # an identifier (regression test for fix in 1.4.23; this triggered an
1610 # infinitely repeating `error: Unknown index action ''` before that).
1611 print_to_file
$test_indexscript, 'url :: index ?!';
1612 test_scriptindex_error
'bad syntax when expecting index action',
1613 "$test_indexscript:1:6: error: Expected index action, found ':'\n".
1614 "$test_indexscript:1:14: error: Expected index action, found '?!'";
1616 # Test we give a helpful error if an = sign is missed out before an optional
1617 # numeric argument (regression test for fix in 1.4.6).
1619 # This used to give the confusing:
1620 # Unknown index action ''
1621 print_to_file
$test_indexscript, 'url : hash 42';
1622 test_scriptindex_error
'missing equals sign',
1623 "$test_indexscript:1:12: error: Unknown index action '42'";
1625 # Test we warn about spaces before and after '='.
1627 # This has never been documented as supported, and was deprecated in 1.4.6
1628 # because it resulted in this quietly using `hash` as the field name, which is
1629 # probably not what was intended:
1631 # url : field= hash boolean=Q unique=Q
1632 print_to_file
$test_indexscript, 'url : field= hash boolean=Q unique=Q';
1633 test_scriptindex_warning
'space after "="',
1634 "$test_indexscript:1:13: warning: putting spaces between '=' and the argument is deprecated";
1636 print_to_file
$test_indexscript, 'url : field =link';
1637 test_scriptindex_warning
'space before "="',
1638 "$test_indexscript:1:12: warning: putting spaces between the action and '=' is deprecated";
1640 # Feature tests for scriptindex `date` action.
1641 print_to_file
$test_indexscript, "d : date=unix\ng : date=unixutc\n";
1642 # `date=unix` works in the current timezone, so set that explicitly so the
1643 # build doesn't fail if run in a timezone which is behind UTC.
1645 my $save_TZ = $ENV{TZ
};
1647 test_scriptindex
'DATE action', "d=\n\nd=0\n\nd=1541478429";
1648 if (defined $save_TZ) {
1649 $ENV{TZ
} = $save_TZ;
1654 print_to_file
$test_template, '$list{$map{$range{1,3},$list{$allterms{$_}, }},|}';
1655 testcase
'|D19700101 M197001 Y1970|D20181106 M201811 Y2018';
1657 # `date=unixutc` should always work in UTC regardless of the current timezone.
1658 test_scriptindex
'DATE action with unixutc',
1659 "g=\n\ng=0\n\ng=1541478429";
1660 testcase
'|D19700101 M197001 Y1970|D20181106 M201811 Y2018';
1662 # Check nested $hitlist{} doesn't result in an infinite loop.
1663 # Regression test for bug fixed in 1.4.12.
1664 print_to_file
$test_template, '<|$hitlist{$id(:$hitlist{$id:})|}>';
1665 testcase
'<|2(:2:3:)|3(:2:3:)|>', 'B=Y1970', 'B=Y2018';
1667 # Feature tests for scriptindex `parsedate` action.
1668 print_to_file
$test_indexscript, "DATE : field parsedate=%Y%m%d valuepacked=13\n";
1669 test_scriptindex
'PARSEDATE action',
1671 print_to_file
$test_template, '$field{DATE,1}|$unpack{$value{13,1}}|$date{$unpack{$value{13,1}}}';
1672 testcase
'19891204|628732800|1989-12-04', 'P=text';
1674 # Feature tests for scriptindex `parsedate` action.
1675 print_to_file
$test_indexscript, 'DATE: parsedate="%Y%m%d %H:%M:%S" field=time';
1676 test_scriptindex_warning
'PARSEDATE action',
1677 '<stdin>:1: warning: "20161202 12:04:22.000000" not fully matched by format "%Y%m%d %H:%M:%S" (".000000" left over) but indexing anyway',
1678 'DATE=20161202 12:04:22.000000';
1679 print_to_file
$test_template, '$field{time,$cgi{id}}';
1680 # Test format which contains a space.
1681 testcase
'1480680262', 'id=1';
1683 # Feature tests for scriptindex `parsedate` action.
1684 print_to_file
$test_indexscript, 'DATE: parsedate="%Y%m%d %H:%M:%S %z" field=time';
1685 if (test_scriptindex_optional_error
('PARSEDATE action with %z',
1686 'test-indexscript:1:34: error: Parsing timezone offsets with %z is not supported on this platform',
1687 'DATE=20161202 21:34:24 +0930') == 0) {
1688 print_to_file
$test_template, '$field{time,$cgi{id}}';
1689 # Test that timezone adjustment is applied.
1690 testcase
'1480680264', 'id=1';
1693 # Feature tests for scriptindex `valuenumeric` action.
1694 print_to_file
$test_indexscript, "n : field valuenumeric=0\n";
1695 test_scriptindex
'VALUENUMERIC action',
1696 "n=0\n\nn=1.75\n\nn=-1000000000";
1697 print_to_file
$test_template, '$sortableunserialise{$valuelowerbound{0}}|$list{$map{$range{1,3},$url{$value{0,$_}}},:}|$sortableunserialise{$valueupperbound{0}}';
1698 testcase
'-1000000000.000000|%80:%A3:%1F%A4FS%60|1.750000';
1700 # Feature tests for scriptindex `load` action.
1701 print_to_file
$test_indexscript, "file : load field\n";
1702 test_scriptindex_warning
'empty filename in load action',
1703 "<stdin>:1: warning: Empty filename in LOAD action",
1706 # Feature tests for quoted arguments.
1707 print_to_file
$test_indexscript, <<'END';
1708 DATE : field=" spaces " date="yyyymmdd"
1711 test_scriptindex
'quoted arguments', <<'END';
1713 TEXT=This is sample text.
1716 print_to_file
$test_template, '$freq{D19891204}|$field{ spaces ,1}';
1717 testcase
'1|19891204', 'P.S=text';
1718 # Use $time to force the match to run.
1719 print_to_file
$test_template, '$if{x$time,$freq{D19891204}}|$field{ spaces ,1}';
1720 testcase
'1|19891204', 'P=';
1722 # Feature tests for escaping in quoted arguments.
1723 print_to_file
$test_indexscript, 'esc : field="\tesca\x70e,test\\\\\\""' . "\n";
1724 test_scriptindex
'escaping in quoted arguments',
1726 print_to_file
$test_template, '$field{$chr{9}escape$.test\\",1}';
1727 testcase
'test', 'P=';
1728 print_to_file
$test_indexscript, 'x: split="xx\\' . "\n" . 'y: split="xx\q"' . "\n";
1729 test_scriptindex_error
"bad escape sequences",
1730 "$test_indexscript:1:14: error: Bad escaping in quoted action argument
1731 $test_indexscript:2:14: error: Bad escape sequence '\\q'";
1732 # Ensure the location of the problem is always in the same column so we can
1733 # test against a fixed error message including line and column.
1740 print_to_file
$test_indexscript, "x: split=$badesc";
1741 test_scriptindex_error
"bad hex digit in escape: '$badesc'",
1742 "$test_indexscript:1:14: error: Bad hex digit in escaping";
1745 # Regression test that a closing " with junk after is flagged.
1746 print_to_file
$test_indexscript, 'date : field="test"index';
1747 test_scriptindex_error
"junk after closing quote",
1748 "$test_indexscript:1:20: error: Unexpected character 'i' after closing quote";
1750 # Test we warn about useless actions.
1751 print_to_file
$test_indexscript, 'date : field parsedate=%%Y%%m%%d';
1752 test_scriptindex_warning
"useless 'parsedate'",
1753 "$test_indexscript:1:14: warning: Index action 'parsedate' has no effect
1754 $test_indexscript:1:14: note: Actions are executed from left to right";
1756 # Test a `parsedate` format error.
1757 print_to_file
$test_indexscript, 'date : parsedate="%Y-%m-%d %Z" field';
1758 test_scriptindex_error
"'%Z' in 'parsedate' format",
1759 "$test_indexscript:1:28: error: Parsing timezone names with %Z is not supported";
1761 # Test scriptindex `gap` action inserts a termpos gap.
1762 print_to_file
$test_indexscript, 'text : index gap=5';
1763 test_scriptindex
'GAP action',
1764 "text=foo\ntext=bar\ntext=baz";
1765 print_to_file
$test_template, '|$hitlist{$id|}';
1766 testcase
('|', 'P="foo bar"');
1767 testcase
('|', 'P=foo NEAR/5 bar');
1768 testcase
('|', 'P=foo NEAR/11 baz');
1769 testcase
('|1|', 'P=foo NEAR/6 bar');
1770 testcase
('|1|', 'P=foo NEAR/12 baz');
1772 # The scriptindex `hash` action should require its argument is >= 6, so test 5
1774 print_to_file
$test_indexscript, 'url : hash=5 boolean=Q unique=Q';
1775 test_scriptindex_error
'bad HASH argument',
1776 "$test_indexscript:1:12: error: Index action 'hash' takes an integer argument which must be at least 6";
1778 # And that 6 is accepted.
1779 print_to_file
$test_indexscript, 'url : hash=6 boolean=Q unique=Q';
1780 test_scriptindex
'hash=6',
1781 'url=http://xapian.org';
1783 # Regression test to check `hash` works without argument (it was failing with
1784 # an assertion in unreleased versions prior to 1.4.6).
1785 print_to_file
$test_indexscript, 'url : hash boolean=Q unique=Q';
1786 test_scriptindex
'HASH without argument',
1787 'url=http://xapian.org';
1789 # Test the same actions for multiple fields works (briefly broken in git master
1791 print_to_file
$test_indexscript, 'tag1 tag2 tag3 : boolean=T field';
1792 test_scriptindex
'multiple fields on an action line',
1793 "tag1=one\ntag2=two\ntag3=three";
1794 print_to_file
$test_template, '$hitlist{$list{$terms{T},|}/$field{tag1}|$field{tag2}|$field{tag3}}';
1795 testcase
('Tone/one|two|three', 'B=Tone');
1796 testcase
('Tthree|Ttwo/one|two|three', 'B=Ttwo', 'B=Tthree');
1798 unlink $OMEGA_CONFIG_FILE, $test_indexscript, $test_template;
1799 remove_tree
($test_db);
1803 print "Failed $failed test(s)\n";