blob: 2d68e46b16000de3d9a60234c8ccb4f881e1680a [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using NUnit.Framework;
using Document = Lucene.Net.Documents.Document;
using Field = Lucene.Net.Documents.Field;
using IndexReader = Lucene.Net.Index.IndexReader;
using IndexWriter = Lucene.Net.Index.IndexWriter;
using Term = Lucene.Net.Index.Term;
using ParseException = Lucene.Net.QueryParsers.ParseException;
using QueryParser = Lucene.Net.QueryParsers.QueryParser;
using RAMDirectory = Lucene.Net.Store.RAMDirectory;
using WhitespaceAnalyzer = Lucene.Net.Analysis.WhitespaceAnalyzer;
using Lucene.Net.Search.Spans;
using LuceneTestCase = Lucene.Net.Util.LuceneTestCase;
namespace Lucene.Net.Search
{
/// <summary> Tests primative queries (ie: that rewrite to themselves) to
/// insure they match the expected set of docs, and that the score of each
/// match is equal to the value of the scores explanation.
///
/// <p>
/// The assumption is that if all of the "primative" queries work well,
/// then anythingthat rewrites to a primative will work well also.
/// </p>
///
/// </summary>
/// <seealso cref=""Subclasses for actual tests"">
/// </seealso>
[TestFixture]
public class TestExplanations : LuceneTestCase
{
protected internal IndexSearcher searcher;
public const System.String FIELD = "field";
public static readonly Lucene.Net.QueryParsers.QueryParser qp = new Lucene.Net.QueryParsers.QueryParser(FIELD, new WhitespaceAnalyzer());
[TearDown]
public override void TearDown()
{
base.TearDown();
if (searcher != null)
{
searcher.Close();
searcher = null;
}
}
[SetUp]
public override void SetUp()
{
base.SetUp();
RAMDirectory directory = new RAMDirectory();
IndexWriter writer = new IndexWriter(directory, new WhitespaceAnalyzer(), true);
for (int i = 0; i < docFields.Length; i++)
{
Document doc = new Document();
doc.Add(new Field(FIELD, docFields[i], Field.Store.NO, Field.Index.TOKENIZED));
writer.AddDocument(doc);
}
writer.Close();
searcher = new IndexSearcher(directory);
}
protected internal System.String[] docFields = new System.String[]{"w1 w2 w3 w4 w5", "w1 w3 w2 w3 zz", "w1 xx w2 yy w3", "w1 w3 xx w2 yy w3 zz"};
public virtual Query MakeQuery(System.String queryText)
{
return qp.Parse(queryText);
}
/// <summary>check the expDocNrs first, then check the query (and the explanations) </summary>
public virtual void Qtest(System.String queryText, int[] expDocNrs)
{
Qtest(MakeQuery(queryText), expDocNrs);
}
/// <summary>check the expDocNrs first, then check the query (and the explanations) </summary>
public virtual void Qtest(Query q, int[] expDocNrs)
{
CheckHits.CheckHitCollector(q, FIELD, searcher, expDocNrs);
}
/// <summary> Tests a query using qtest after wrapping it with both optB and reqB</summary>
/// <seealso cref="Qtest">
/// </seealso>
/// <seealso cref="ReqB">
/// </seealso>
/// <seealso cref="OptB">
/// </seealso>
public virtual void Bqtest(Query q, int[] expDocNrs)
{
Qtest(ReqB(q), expDocNrs);
Qtest(OptB(q), expDocNrs);
}
/// <summary> Tests a query using qtest after wrapping it with both optB and reqB</summary>
/// <seealso cref="Qtest">
/// </seealso>
/// <seealso cref="ReqB">
/// </seealso>
/// <seealso cref="OptB">
/// </seealso>
public virtual void Bqtest(System.String queryText, int[] expDocNrs)
{
Bqtest(MakeQuery(queryText), expDocNrs);
}
/// <summary>A filter that only lets the specified document numbers pass </summary>
[Serializable]
public class ItemizedFilter : Filter
{
internal int[] docs;
public ItemizedFilter(int[] docs)
{
this.docs = docs;
}
public override System.Collections.BitArray Bits(IndexReader r)
{
System.Collections.BitArray b = new System.Collections.BitArray((r.MaxDoc() % 64 == 0?r.MaxDoc() / 64:r.MaxDoc() / 64 + 1) * 64);
for (int i = 0; i < docs.Length; i++)
{
b.Set(docs[i], true);
}
return b;
}
}
/// <summary>helper for generating MultiPhraseQueries </summary>
public static Term[] Ta(System.String[] s)
{
Term[] t = new Term[s.Length];
for (int i = 0; i < s.Length; i++)
{
t[i] = new Term(FIELD, s[i]);
}
return t;
}
/// <summary>MACRO for SpanTermQuery </summary>
public virtual SpanTermQuery St(System.String s)
{
return new SpanTermQuery(new Term(FIELD, s));
}
/// <summary>MACRO for SpanNotQuery </summary>
public virtual SpanNotQuery Snot(SpanQuery i, SpanQuery e)
{
return new SpanNotQuery(i, e);
}
/// <summary>MACRO for SpanOrQuery containing two SpanTerm queries </summary>
public virtual SpanOrQuery Sor(System.String s, System.String e)
{
return Sor(St(s), St(e));
}
/// <summary>MACRO for SpanOrQuery containing two SpanQueries </summary>
public virtual SpanOrQuery Sor(SpanQuery s, SpanQuery e)
{
return new SpanOrQuery(new SpanQuery[]{s, e});
}
/// <summary>MACRO for SpanOrQuery containing three SpanTerm queries </summary>
public virtual SpanOrQuery Sor(System.String s, System.String m, System.String e)
{
return Sor(St(s), St(m), St(e));
}
/// <summary>MACRO for SpanOrQuery containing two SpanQueries </summary>
public virtual SpanOrQuery Sor(SpanQuery s, SpanQuery m, SpanQuery e)
{
return new SpanOrQuery(new SpanQuery[]{s, m, e});
}
/// <summary>MACRO for SpanNearQuery containing two SpanTerm queries </summary>
public virtual SpanNearQuery Snear(System.String s, System.String e, int slop, bool inOrder)
{
return Snear(St(s), St(e), slop, inOrder);
}
/// <summary>MACRO for SpanNearQuery containing two SpanQueries </summary>
public virtual SpanNearQuery Snear(SpanQuery s, SpanQuery e, int slop, bool inOrder)
{
return new SpanNearQuery(new SpanQuery[]{s, e}, slop, inOrder);
}
/// <summary>MACRO for SpanNearQuery containing three SpanTerm queries </summary>
public virtual SpanNearQuery Snear(System.String s, System.String m, System.String e, int slop, bool inOrder)
{
return Snear(St(s), St(m), St(e), slop, inOrder);
}
/// <summary>MACRO for SpanNearQuery containing three SpanQueries </summary>
public virtual SpanNearQuery Snear(SpanQuery s, SpanQuery m, SpanQuery e, int slop, bool inOrder)
{
return new SpanNearQuery(new SpanQuery[]{s, m, e}, slop, inOrder);
}
/// <summary>MACRO for SpanFirst(SpanTermQuery) </summary>
public virtual SpanFirstQuery Sf(System.String s, int b)
{
return new SpanFirstQuery(St(s), b);
}
/// <summary> MACRO: Wraps a Query in a BooleanQuery so that it is optional, along
/// with a second prohibited clause which will never match anything
/// </summary>
public virtual Query OptB(System.String q)
{
return OptB(MakeQuery(q));
}
/// <summary> MACRO: Wraps a Query in a BooleanQuery so that it is optional, along
/// with a second prohibited clause which will never match anything
/// </summary>
public virtual Query OptB(Query q)
{
BooleanQuery bq = new BooleanQuery(true);
bq.Add(q, BooleanClause.Occur.SHOULD);
bq.Add(new TermQuery(new Term("NEVER", "MATCH")), BooleanClause.Occur.MUST_NOT);
return bq;
}
/// <summary> MACRO: Wraps a Query in a BooleanQuery so that it is required, along
/// with a second optional clause which will match everything
/// </summary>
public virtual Query ReqB(System.String q)
{
return ReqB(MakeQuery(q));
}
/// <summary> MACRO: Wraps a Query in a BooleanQuery so that it is required, along
/// with a second optional clause which will match everything
/// </summary>
public virtual Query ReqB(Query q)
{
BooleanQuery bq = new BooleanQuery(true);
bq.Add(q, BooleanClause.Occur.MUST);
bq.Add(new TermQuery(new Term(FIELD, "w1")), BooleanClause.Occur.SHOULD);
return bq;
}
/// <summary> Placeholder: JUnit freaks if you don't have one test ... making
/// class abstract doesn't help
/// </summary>
[Test]
public virtual void TestNoop()
{
/* NOOP */
}
}
}