#!/bin/sh
# omegatest: Test omega CGI
#
# Copyright (C) 2015,2016 Olly Betts
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
# USA
set -e

: ${OMEGA=./omega}
: ${SCRIPTINDEX=./scriptindex}

# Suppress HTTP Content-Type header.
SERVER_PROTOCOL=INCLUDED
export SERVER_PROTOCOL

# Set up an empty database.
TEST_DB=test-db
rm -rf "$TEST_DB"
echo 'inmemory' > "$TEST_DB"

# Simple template which just shows the parsed query.
TEST_TEMPLATE=test-template
printf '$querydescription' > "$TEST_TEMPLATE"

TEST_INDEXSCRIPT=test-indexscript

OMEGA_CONFIG_FILE=test-omega.conf
export OMEGA_CONFIG_FILE
cat > "$OMEGA_CONFIG_FILE" <<__END__
database_dir .
template_dir .
log_dir tmplog
default_template $TEST_TEMPLATE
default_db $TEST_DB
__END__

failed=0

testcase() {
    expected=$1
    shift
    # If there are no positional parameters, pass one as otherwise omega will
    # wait for parameters on stdin.
    [ "$#" != 0 ] || set - dummy
    output=`$FAKETIME ${FAKE_NOW+"$FAKE_NOW"} "$OMEGA" "$@"`
    if [ "$output" != "$expected" ] ; then
	echo "$OMEGA $@:"
	echo "  expected: «$expected»"
	echo "  received: «$output»"
	failed=`expr $failed + 1`
    fi
}

qtestcase() {
    expected="Query($1)"
    shift
    testcase "$expected" "$@"
}

FAKETIME=
unset FAKE_NOW

# Test a few simple things.
qtestcase 'Zsimpl@1' P=simple
qtestcase '(chocolate@1 FILTER Tconfectionary/fudge)' P=Chocolate B=Tconfectionary/fudge

# Test date value ranges.
qtestcase 'VALUE_RANGE 0 2 ~' DATEVALUE=0 START=2000
qtestcase 'VALUE_RANGE 0 2 ~' DATEVALUE=0 START=200001
qtestcase 'VALUE_RANGE 0 2 ~' DATEVALUE=0 START=20000101
qtestcase 'VALUE_LE 1 1~' DATEVALUE=1 END=1999
qtestcase 'VALUE_LE 1 1~' DATEVALUE=1 END=199912
qtestcase 'VALUE_LE 1 1~' DATEVALUE=1 END=19991231
qtestcase 'VALUE_RANGE 2 201 ~' DATEVALUE=2 START=2010
qtestcase 'VALUE_RANGE 2 201 ~' DATEVALUE=2 START=201001
qtestcase 'VALUE_RANGE 2 201 ~' DATEVALUE=2 START=20100101
qtestcase 'VALUE_LE 3 198~' DATEVALUE=3 END=1989
qtestcase 'VALUE_LE 3 198~' DATEVALUE=3 END=198912
qtestcase 'VALUE_LE 3 198~' DATEVALUE=3 END=19891231
qtestcase 'VALUE_RANGE 4 1974 ~' DATEVALUE=4 START=1974
qtestcase 'VALUE_RANGE 4 1974 ~' DATEVALUE=4 START=197401
qtestcase 'VALUE_RANGE 4 1974 ~' DATEVALUE=4 START=19740101
qtestcase 'VALUE_LE 5 1974~' DATEVALUE=5 END=1974
qtestcase 'VALUE_LE 5 1974~' DATEVALUE=5 END=197412
qtestcase 'VALUE_LE 5 1974~' DATEVALUE=5 END=19741231
qtestcase 'VALUE_RANGE 6 20151 ~' DATEVALUE=6 START=201510
qtestcase 'VALUE_RANGE 6 20151 ~' DATEVALUE=6 START=20151001
qtestcase 'VALUE_LE 7 19870~' DATEVALUE=7 END=198709
qtestcase 'VALUE_LE 7 19870~' DATEVALUE=7 END=19870930
qtestcase 'VALUE_RANGE 8 201512 ~' DATEVALUE=8 START=201512
qtestcase 'VALUE_RANGE 8 201512 ~' DATEVALUE=8 START=20151201
qtestcase 'VALUE_LE 9 201511~' DATEVALUE=9 END=201511
qtestcase 'VALUE_LE 9 201511~' DATEVALUE=9 END=20151130
qtestcase 'VALUE_RANGE 10 2015021 ~' DATEVALUE=10 START=20150210
qtestcase 'VALUE_RANGE 10 2000022 ~' DATEVALUE=10 START=20000220
qtestcase 'VALUE_LE 11 19840401~' DATEVALUE=11 END=19840401
qtestcase 'VALUE_LE 11 19881128~' DATEVALUE=11 END=19881128

# Leap year tests:
qtestcase 'VALUE_LE 1 201502~' DATEVALUE=1 END=20150228
qtestcase 'VALUE_LE 1 198802~' DATEVALUE=1 END=19880229
qtestcase 'VALUE_LE 1 19880228~' DATEVALUE=1 END=19880228
qtestcase 'VALUE_LE 1 200002~' DATEVALUE=1 END=20000229
qtestcase 'VALUE_LE 1 20000228~' DATEVALUE=1 END=20000228
# FIXME: These two currently require 64-bit time_t:
#testcase 'VALUE_LE 1 190002~' DATEVALUE=1 END=19000228
#testcase 'VALUE_LE 1 210002~' DATEVALUE=1 END=21000228

# Month starts and ends:
qtestcase 'VALUE_RANGE 0 2015 201501~' DATEVALUE=0 START=20150101 END=20150131
qtestcase 'VALUE_RANGE 0 2015 20150130~' DATEVALUE=0 START=20150101 END=20150130
qtestcase 'VALUE_RANGE 0 201502 201502~' DATEVALUE=0 START=20150201 END=20150228
qtestcase 'VALUE_RANGE 0 201502 20150227~' DATEVALUE=0 START=20150201 END=20150227
qtestcase 'VALUE_RANGE 0 201503 201503~' DATEVALUE=0 START=20150301 END=20150331
qtestcase 'VALUE_RANGE 0 201503 20150330~' DATEVALUE=0 START=20150301 END=20150330
qtestcase 'VALUE_RANGE 0 201504 201504~' DATEVALUE=0 START=20150401 END=20150430
qtestcase 'VALUE_RANGE 0 201504 2015042~' DATEVALUE=0 START=20150401 END=20150429
qtestcase 'VALUE_RANGE 0 201505 201505~' DATEVALUE=0 START=20150501 END=20150531
qtestcase 'VALUE_RANGE 0 201505 20150530~' DATEVALUE=0 START=20150501 END=20150530
qtestcase 'VALUE_RANGE 0 201506 201506~' DATEVALUE=0 START=20150601 END=20150630
qtestcase 'VALUE_RANGE 0 201506 2015062~' DATEVALUE=0 START=20150601 END=20150629
qtestcase 'VALUE_RANGE 0 201507 201507~' DATEVALUE=0 START=20150701 END=20150731
qtestcase 'VALUE_RANGE 0 201507 20150730~' DATEVALUE=0 START=20150701 END=20150730
qtestcase 'VALUE_RANGE 0 201508 201508~' DATEVALUE=0 START=20150801 END=20150831
qtestcase 'VALUE_RANGE 0 201508 20150830~' DATEVALUE=0 START=20150801 END=20150830
qtestcase 'VALUE_RANGE 0 201509 20150~' DATEVALUE=0 START=20150901 END=20150930
qtestcase 'VALUE_RANGE 0 201509 2015092~' DATEVALUE=0 START=20150901 END=20150929
qtestcase 'VALUE_RANGE 0 20151 201510~' DATEVALUE=0 START=20151001 END=20151031
qtestcase 'VALUE_RANGE 0 20151 20151030~' DATEVALUE=0 START=20151001 END=20151030
qtestcase 'VALUE_RANGE 0 201511 201511~' DATEVALUE=0 START=20151101 END=20151130
qtestcase 'VALUE_RANGE 0 201511 2015112~' DATEVALUE=0 START=20151101 END=20151129
qtestcase 'VALUE_RANGE 0 201512 2015~' DATEVALUE=0 START=20151201 END=20151231
qtestcase 'VALUE_RANGE 0 201512 20151230~' DATEVALUE=0 START=20151201 END=20151230

# Forward spans:
qtestcase 'VALUE_RANGE 0 20151104 20151106~' DATEVALUE=0 START=20151104 SPAN=3
qtestcase 'VALUE_RANGE 0 20141104 20151103~' DATEVALUE=0 START=20141104 SPAN=365

# Backward spans:
qtestcase 'VALUE_RANGE 0 20151104 20151106~' DATEVALUE=0 END=20151106 SPAN=3
qtestcase 'VALUE_RANGE 0 20141104 20151103~' DATEVALUE=0 END=20151103 SPAN=365

# Check that if START, END and SPAN are all passed, START is ignored:
qtestcase 'VALUE_RANGE 0 20151104 20151106~' DATEVALUE=0 START=19700101 END=20151106 SPAN=3

# Check combining of filter terms:
qtestcase '(Horg AND Len)' B=Len B=Horg
qtestcase '(Len OR Lde)' B=Len B=Lde
qtestcase '((Horg OR Hcom) AND (Len OR Lfr))' B=Len B=Lfr B=Horg B=Hcom

# Check combining of filter terms with filter_op set:
printf '$setmap{nonexclusiveprefix,L,1,XAND,1}$setmap{boolprefix,lang,L,and,XAND,host,H,year,Y}$querydescription' > "$TEST_TEMPLATE"
qtestcase 'Len' B=Len
qtestcase '0 * Len' P=lang:en
qtestcase 'XANDtest' B=XANDtest
qtestcase '0 * XANDtest' P=and:test
qtestcase '(Len AND XANDtest)' B=Len B=XANDtest
qtestcase '0 * (Len AND XANDtest)' P='lang:en and:test'
qtestcase '(Len AND Lde)' B=Len B=Lde
qtestcase '0 * (Len AND Lde)' P='lang:en lang:de'
qtestcase '((Horg OR Hcom) AND (Len AND Lfr))' B=Len B=Lfr B=Horg B=Hcom
qtestcase '0 * ((Len AND Lfr) AND (Horg OR Hcom))' P='lang:en lang:fr host:org host:com'
qtestcase '((XANDa AND XANDb AND XANDc) AND (Y1998 OR Y2001))' B=Y1998 B=Y2001 B=XANDa B=XANDb B=XANDc
qtestcase '0 * (((XANDa AND XANDb) AND XANDc) AND (Y1998 OR Y2001))' P='year:1998 year:2001 and:a and:b and:c'

# Check combining of filters around CGI parameter 'N':
qtestcase '(Ztruth@1 AND_NOT Epdf)' P=truth N=Epdf
qtestcase '(Ztruth@1 AND_NOT (Ehtm OR Epdf))' P=truth N=Epdf N=Ehtm
qtestcase '(Ztruth@1 AND_NOT (Ehtm OR Epdf OR Lde OR Lfr))' P=truth N=Lfr N=Epdf N=Ehtm N=Lde
qtestcase '((Ztruth@1 FILTER (Lfr AND Lzh)) AND_NOT (Lde OR Len))' P=truth N=Lde N=Len B=Lfr B=Lzh
qtestcase '((Ztruth@1 FILTER Lfr) AND_NOT (Ehtm OR Epdf))' P=truth N=Epdf N=Ehtm B=Lfr
qtestcase '(<alldocuments> AND_NOT (Len OR Lfr))' N=Lfr N=Len
qtestcase '(VALUE_RANGE 0 2015 201501~ AND_NOT Len)' DATEVALUE=0 START=20150101 END=20150131 N=Len

# If faketime is available and works, test a range back from now.
if [ "`faketime '1980-12-08' date +%Y 2>&1`" = 1980 ] ; then
    TZ=UTC
    export TZ
    FAKETIME=faketime
    FAKE_NOW='2015-11-28 06:07:08'
    qtestcase 'VALUE_RANGE 0 20151127060709 20151128060708' DATEVALUE=0 SPAN=1
    FAKETIME=
    unset FAKE_NOW
else
    if [ $? = 127 ] ; then
	echo "Skipping testcases which need 'faketime' tool installed"
    else
	echo "Skipping testcases which need 'faketime' tool - it's installed but doesn't work"
    fi
fi

# Feature tests for $contains.
printf '$contains{$cgi{a},$cgi{b}}' > "$TEST_TEMPLATE"
testcase '6' P=text a=fish b="Hello fish"
testcase '' P=text a="Example" b="random"

NEWLINE='
'

# Feature tests for boolprefix and prefix maps.
printf '$set{stemmer,}$setmap{boolprefix,lang,L,host,H}$setmap{prefix,,XDEFAULT}$querydescription' > "$TEST_TEMPLATE"
qtestcase '((XDEFAULTfoo@1 AND XDEFAULTbar@2) FILTER (Hexample.org AND Lzh))' P='host:example.org foo bar lang:zh'

# Feature tests for $match.
printf '$match{$cgi{a},$cgi{b},$cgi{c}}' > "$TEST_TEMPLATE"
testcase 'true' P=text a="ab*c+" b="ac"
testcase '' P=text a="acb" b="abc"
testcase 'true' P=text a="[A-Z]bcD" b="abcd" c="i"
testcase '' P=text a="[A-Z]bcD" b="abcd"
testcase 'true' P=text a="^abc$" b="${NEWLINE}abc${NEWLINE}def" c="m"
testcase '' P=text a="^abc$" b="${NEWLINE}abc${NEWLINE}def"
testcase 'true' P=text a="abc." b="abc${NEWLINE}" c="s"
testcase '' P=text a="abc." b="abc${NEWLINE}"
testcase 'true' P=text a="    ABC #test_comment " b="ABC" c="x"
testcase '' P=text a="    ABC #test_comment " b="ABC"

# Feature tests for $terms.
printf 'text : index\nhost : boolean=H\nfoo : boolean=XFOO' > "$TEST_INDEXSCRIPT"
rm -f "$TEST_DB"
$SCRIPTINDEX "$TEST_DB" "$TEST_INDEXSCRIPT" > /dev/null <<'END'
text=This is some text.
host=example.org
foo=bar
END
printf '$hitlist{$list{$if{$eq{$cgi{prefix},null},$terms,$terms{$cgi{prefix}}},|}}' > "$TEST_TEMPLATE"
testcase 'Ztext' P=text B=Hexample.org B=Hexample.com prefix=null
testcase 'Hexample.org|Ztext' P=text B=Hexample.org B=Hexample.com prefix=
testcase 'Hexample.org' P=text B=Hexample.org B=Hexample.com prefix=H
testcase 'Ztext' P=text B=Hexample.org B=Hexample.com prefix=Z
testcase '' P=text B=Hexample.org B=Hexample.com prefix=E

printf '$msizelower $msize $msizeupper $msizeexact' > "$TEST_TEMPLATE"
testcase '1 1 1 true' P=this
testcase '1 1 1 true' P='Some text'
testcase '0 0 0 true' P=potato

printf '$set{weighting,coord}$hitlist{$weight.}' > "$TEST_TEMPLATE"
testcase '' P=aardvark
testcase '1.000000.' P=texting
testcase '' P='texting while driving'
testcase '' P='texting while driving' DEFAULTOP=AND
testcase '1.000000.' P='texting while driving' DEFAULTOP=OR
testcase '2.000000.' P='Some text'
# "this" and "is" are stopwords.
testcase '2.000000.' P='This is some text'
testcase '4.000000.' P='"This" "is" some text'
testcase '4.000000.' P='+This +is some text'
testcase '4.000000.' P='"This is some text"'

printf '$set{weightingpurefilter,coord}$hitlist{$weight.}' > "$TEST_TEMPLATE"
testcase '' B=XFOOfoo
testcase '1.000000.' B=Hexample.org
testcase '' B=Hexample.org B=XFOOfoo
testcase '1.000000.' B=Hexample.org B=Hexample.net
testcase '2.000000.' B=Hexample.org B=XFOObar
testcase '3.000000.' B=Hexample.org B=XFOObar B=XFOObar

printf '$filters' > "$TEST_TEMPLATE"
testcase 'Hexample.net~Hexample.org~.~~' B=Hexample.org B=Hexample.net
testcase '!Gmisc.test~.~~' N=Gmisc.test
testcase 'Hexample.net~Hexample.org~!Gmisc.test~.~~' B=Hexample.org B=Hexample.net N=Gmisc.test
testcase '.20040612~~~1~' DATEVALUE=1 START=20040612
testcase '.20040612~~~1~2' DATEVALUE=1 START=20040612 COLLAPSE=2
testcase '.20040612~~30~2' START=20040612 SPAN=30 COLLAPSE=2
testcase '.20040612~20160412~' START=20040612 END=20160412
testcase '.~~~2' COLLAPSE=2
testcase '.~~'
testcase '.~~1' SORT=1
testcase '.~~1f' SORT=+1
testcase '.~~1' SORT=-1
testcase '.~~1-2+3-27' SORT=+1-2+03,-27
testcase '.~~' SORTREVERSE=1
testcase '.~~1f' SORT=1 SORTREVERSE=1
testcase '.~~1' SORT=+1 SORTREVERSE=1
testcase '.~~1f' SORT=-1 SORTREVERSE=1
testcase '.~~1-2+3-27f' SORT=+1-2+03,-27 SORTREVERSE=1
testcase '.~~' SORTAFTER=1
testcase '.~~1R' SORT=1 SORTAFTER=1
testcase '.~~1F' SORT=+1 SORTAFTER=1
testcase '.~~1R' SORT=-1 SORTAFTER=1
testcase '.~~1-2+3-27R' SORT=+1-2+03,-27 SORTAFTER=1
testcase '.~~' SORTREVERSE=1 SORTAFTER=1
testcase '.~~1F' SORT=1 SORTREVERSE=1 SORTAFTER=1
testcase '.~~1R' SORT=+1 SORTREVERSE=1 SORTAFTER=1
testcase '.~~1F' SORT=-1 SORTREVERSE=1 SORTAFTER=1
testcase '.~~1-2+3-27F' SORT=+1-2+03,-27 SORTREVERSE=1 SORTAFTER=1
testcase '.~~X' DOCIDORDER=A # Buggy, but kept for compatibility.
testcase '.~~D' DOCIDORDER=D
testcase '.~~' DOCIDORDER=X # Buggy, but kept for compatibility.
testcase '.~~' DOCIDORDER=x # Buggy, but kept for compatibility.

rm "$OMEGA_CONFIG_FILE" "$TEST_INDEXSCRIPT" "$TEST_TEMPLATE"
rm -rf "$TEST_DB"
if [ "$failed" = 0 ] ; then
    exit 0
fi
echo "Failed $failed test(s)"
exit 1
