blob: ecf8c65772fcafcd4ed0935f02a11018a3912681 [file]
/*------------------------------------------------------------------------------
* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team
*
* Distributable under the terms of either the Apache License (Version 2.0) or
* the GNU Lesser General Public License, as specified in the COPYING file.
------------------------------------------------------------------------------*/
#include "test.h"
class MQPTestFilter: public TokenFilter {
public:
bool inPhrase;
int32_t savedStart, savedEnd;
/**
* Filter which discards the token 'stop' and which expands the
* token 'phrase' into 'phrase1 phrase2'
*/
MQPTestFilter(TokenStream* in):
TokenFilter(in,true),
inPhrase(false),
savedStart(0),
savedEnd(0)
{
}
CL_NS(analysis)::Token* next(CL_NS(analysis)::Token* token) {
if (inPhrase) {
inPhrase = false;
token->set( _T("phrase2"), savedStart, savedEnd);
return token;
}else{
while( input->next(token) ){
if ( _tcscmp(token->termBuffer<TCHAR> (), _T("phrase")) == 0 ) {
inPhrase = true;
savedStart = token->startOffset();
savedEnd = token->endOffset();
token->set( _T("phrase1"), savedStart, savedEnd);
return token;
}else if ( _tcscmp(token->termBuffer<TCHAR> (), _T("stop") ) !=0 ){
return token;
}
}
}
return NULL;
}
};
class MQPTestAnalyzer: public Analyzer {
public:
MQPTestAnalyzer() {
}
/** Filters LowerCaseTokenizer with StopFilter. */
TokenStream* tokenStream(const TCHAR* /*fieldName*/, Reader* reader) {
return _CLNEW MQPTestFilter(_CLNEW LowerCaseTokenizer<TCHAR> (reader));
}
};
void assertQueryEquals(CuTest *tc,const TCHAR* result, Query* q) {
if ( q == NULL )
return;
TCHAR* s = q->toString();
int ret = _tcscmp(s,result);
_CLDELETE(q);
if ( ret != 0 ) {
TCHAR buf[HUGE_STRING_LEN];
_sntprintf(buf, HUGE_STRING_LEN, _T("FAILED Query yielded /%s/, expecting /%s/\n"), s, result);
_CLDELETE_LCARRAY(s);
CuFail(tc, buf);
return;
}
_CLDELETE_LCARRAY(s);
}
// verify parsing of query using a stopping analyzer
void assertStopQueryEquals(CuTest *tc, const TCHAR* qtxt, const TCHAR* expectedRes) {
const TCHAR* fields[] = {_T("b"), _T("t"), NULL };
const uint8_t occur[] = {BooleanClause::SHOULD, BooleanClause::SHOULD, NULL};
MQPTestAnalyzer *a = _CLNEW MQPTestAnalyzer();
MultiFieldQueryParser mfqp(fields, a);
Query *q = mfqp.parse(qtxt);
assertQueryEquals(tc, expectedRes, q);
q = MultiFieldQueryParser::parse(qtxt, reinterpret_cast<const TCHAR**>(&fields),
reinterpret_cast<const uint8_t*>(&occur), a);
assertQueryEquals(tc, expectedRes, q);
_CLDELETE(a);
}
/** test stop words arsing for both the non static form, and for the
* corresponding static form (qtxt, fields[]). */
void tesStopwordsParsing(CuTest *tc) {
assertStopQueryEquals(tc, _T("one"), _T("b:one t:one"));
assertStopQueryEquals(tc, _T("one stop"), _T("b:one t:one"));
assertStopQueryEquals(tc, _T("one (stop)"), _T("b:one t:one"));
assertStopQueryEquals(tc, _T("one ((stop))"), _T("b:one t:one"));
assertStopQueryEquals(tc, _T("stop"), _T(""));
assertStopQueryEquals(tc, _T("(stop)"), _T(""));
assertStopQueryEquals(tc, _T("((stop))"), _T(""));
}
void testMFQPSimple(CuTest *tc) {
const TCHAR* fields[] = {_T("b"), _T("t"), NULL};
Analyzer* a = _CLNEW StandardAnalyzer();
MultiFieldQueryParser mfqp(fields, a);
Query *q = mfqp.parse(_T("one"));
assertQueryEquals(tc, _T("b:one t:one"), q);
q = mfqp.parse(_T("one two"));
assertQueryEquals(tc, _T("(b:one t:one) (b:two t:two)"),q);
q = mfqp.parse(_T("+one +two"));
assertQueryEquals(tc, _T("+(b:one t:one) +(b:two t:two)"), q);
q = mfqp.parse(_T("+one -two -three"));
assertQueryEquals(tc, _T("+(b:one t:one) -(b:two t:two) -(b:three t:three)"), q);
q = mfqp.parse(_T("one^2 two"));
assertQueryEquals(tc, _T("((b:one t:one)^2.0) (b:two t:two)"), q);
q = mfqp.parse(_T("one~ two"));
assertQueryEquals(tc, _T("(b:one~0.5 t:one~0.5) (b:two t:two)"), q);
q = mfqp.parse(_T("one~0.8 two^2"));
assertQueryEquals(tc, _T("(b:one~0.8 t:one~0.8) ((b:two t:two)^2.0)"), q);
q = mfqp.parse(_T("one* two*"));
assertQueryEquals(tc, _T("(b:one* t:one*) (b:two* t:two*)"), q);
q = mfqp.parse(_T("[a TO c] two"));
assertQueryEquals(tc, _T("(b:[a TO c] t:[a TO c]) (b:two t:two)"), q);
q = mfqp.parse(_T("w?ldcard"));
assertQueryEquals(tc, _T("b:w?ldcard t:w?ldcard"), q);
q = mfqp.parse(_T("\"foo bar\""));
assertQueryEquals(tc, _T("b:\"foo bar\" t:\"foo bar\""), q);
q = mfqp.parse(_T("\"aa bb cc\" \"dd ee\""));
assertQueryEquals(tc, _T("(b:\"aa bb cc\" t:\"aa bb cc\") (b:\"dd ee\" t:\"dd ee\")"), q);
q = mfqp.parse(_T("\"foo bar\"~4"));
assertQueryEquals(tc, _T("b:\"foo bar\"~4 t:\"foo bar\"~4"), q);
// make sure that terms which have a field are not touched:
q = mfqp.parse(_T("one f:two"));
assertQueryEquals(tc, _T("(b:one t:one) f:two"), q);
// AND mode:
mfqp.setDefaultOperator(QueryParser::AND_OPERATOR);
q = mfqp.parse(_T("one two"));
assertQueryEquals(tc, _T("+(b:one t:one) +(b:two t:two)"), q);
q = mfqp.parse(_T("\"aa bb cc\" \"dd ee\""));
assertQueryEquals(tc, _T("+(b:\"aa bb cc\" t:\"aa bb cc\") +(b:\"dd ee\" t:\"dd ee\")"), q);
_CLDELETE(a);
}
CuSuite *testMultiFieldQueryParser(void)
{
CuSuite *suite = CuSuiteNew(_T("CLucene Multi-Field QP Test"));
SUITE_ADD_TEST(suite, tesStopwordsParsing);
SUITE_ADD_TEST(suite, testMFQPSimple);
return suite;
}