package org.basex.util;
import static org.basex.util.Token.*;
import static org.junit.Assert.*;
import java.util.*;
import org.basex.query.*;
import org.basex.query.expr.ft.*;
import org.basex.util.ft.*;
import org.basex.util.ft.FTBitapSearch.TokenComparator;
import org.basex.util.list.*;
import org.junit.*;
/**
* Test {@link FTBitapSearch} methods.
*
* @author BaseX Team 2005-17, BSD License
* @author Dimitar Popov
*/
public final class FTBitapSearchTest {
/** Simple comparator. */
private static final TokenComparator CMP = new TokenComparator() {
@Override
public boolean equal(final byte[] o1, final byte[] o2) {
return eq(o1, o2);
}
};
/**
* Test data.
* @author Dimitar Popov
*/
public static class TestData {
/** Set to search in. */
public final FTIterator haystack;
/** Set to search for. */
public final FTTokens needles;
/** Indices of expected hits. */
public final int[] expected;
/**
* Constructor.
* @param hay hay stack
* @param needle needles
* @param expected expected hits
*/
public TestData(final String[] hay, final String[][] needle, final int[] expected) {
this.expected = expected;
final int hl = hay.length;
final byte[][] hs = new byte[hl][];
for(int h = 0; h < hay.length; h++) hs[h] = token(hay[h]);
haystack = new FTIterator() {
/** Index of current element. */
private int cnt;
@Override
public boolean hasNext() {
return cnt < hl;
}
@Override
public byte[] nextToken() {
if(hasNext()) return hs[cnt++];
throw new NoSuchElementException();
}
@Override
public FTSpan next() {
return null;
}
@Override
public FTIterator init(final byte[] text) {
return this;
}
};
needles = new FTTokens();
for(final String[] s : needle) {
final TokenList tl = new TokenList(s.length);
for(final String t : s) tl.add(t);
needles.add(tl);
}
}
}
/** Test data. */
private static final TestData[] TESTS = {
new TestData(
new String[] { "token1", "token1", "token2", "token3", "token4",
"token1", "token2", "token3", "token3" },
new String[][] { { "token1", "token2" } },
new int[] { 1, 5 }),
new TestData(
new String[] { "token1" },
new String[][] { { "token1" } },
new int[] { 0 }),
new TestData(
new String[] { "token1" },
new String[][] { { "token2" } },
new int[] { }),
new TestData(
new String[] { "token1" },
new String[][] { { } },
new int[] { }),
new TestData(
new String[] { "token1", "token2", "token1", "token2", "token1" },
new String[][] { { "token1", "token2", "token1" } },
new int[] { 0, 2 }),
new TestData(
new String[] { "token", "token", "token" },
new String[][] { { "token", "token" } },
new int[] { 0, 1}),
new TestData(
new String[] { },
new String[][] { { "token", "token" } },
new int[] { }),
new TestData(
new String[] { },
new String[][] { { } },
new int[] { }),
new TestData(
new String[] { "token" },
new String[][] { },
new int[] { }),
new TestData(
new String[] { "token1", "token2", "token3" },
new String[][] { { "token2", "token3" }, { "token2" } },
new int[] { 1, 1}),
new TestData(
new String[] { "token1", "token2", "token3" },
new String[][] { { "token2" }, { "token2", "token3" } },
new int[] { 1, 1 }),
new TestData(
new String[] { "token1", "token2", "token3" },
new String[][] { { "token2" }, { "token1", "token2" } },
new int[] { 0})};
/** Pre-initialized {@link FTBitapSearch} objects. */
private FTBitapSearch[] searches;
/** Set up method. */
@Before
public void setUp() {
final int tl = TESTS.length;
searches = new FTBitapSearch[tl];
for(int t = 0; t < tl; t++) {
searches[t] = new FTBitapSearch(TESTS[t].haystack, TESTS[t].needles, CMP);
}
}
/** Test search. */
@Test
public void searchIter() {
try {
final int tl = TESTS.length;
for(int t = 0; t < tl; t++) {
final FTBitapSearch s = searches[t];
final TestData test = TESTS[t];
final int el = test.expected.length;
for(int e = 0; e < el; e++) {
final int exp = test.expected[e];
if(!s.hasNext())
fail("Test " + t + ": expected " + el + " hits, got only " + (e + 1));
final int pos = s.next();
if(pos != exp)
fail("Test " + t + ", result " + e + ": expected " + exp + ", got " + pos);
}
if(s.hasNext())
fail("Test " + t + ": expected " + el + " hits, got more!");
}
} catch(final QueryException ex) {
fail(Util.message(ex));
}
}
}