package test.org.korsakow.command;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import org.junit.Assert;
import org.dsrg.soenea.uow.UoW;
import org.junit.Test;
import org.korsakow.domain.KeywordFactory;
import org.korsakow.domain.SnuFactory;
import org.korsakow.domain.command.Request;
import org.korsakow.domain.command.Response;
import org.korsakow.domain.command.SimulatedSearchCommand;
import org.korsakow.domain.interf.IKeyword;
import org.korsakow.domain.interf.IRule;
import org.korsakow.domain.interf.ISnu;
import org.korsakow.ide.DataRegistry;
import test.org.korsakow.domain.AbstractDomainObjectTestCase;
import test.util.DOFactory;
import test.util.DomainTestUtil;
public class TestSimulatedSearchCommand extends AbstractDomainObjectTestCase
{
private static final int MIN_KEYWORD_LENGTH = 10; // should be not-too-small to avoid possibility of collisions
private static final int MAX_KEYWORD_LENGTH = 32;
@Test public void testSearchFindsSingleSnuBySingleKeyword() throws Exception
{
final String keyword = DomainTestUtil.getRandomString(MIN_KEYWORD_LENGTH, MAX_KEYWORD_LENGTH);
ISnu searchSnu = createSnuWithKeywordLookup(parentDir, keyword);
// expected search result
ISnu toFind1 = SnuFactory.createNew(DataRegistry.getMaxId(), 0);
DomainTestUtil.initializeRandom(toFind1);
toFind1.setName(""); // avoid search hits by name
toFind1.setKeywords(Arrays.asList((IKeyword)KeywordFactory.createNew(keyword)));
// generate some potential false positives
for (int i = 0; i < 10; ++i) {
final String nonExistant = DomainTestUtil.getRandomString(MIN_KEYWORD_LENGTH, MAX_KEYWORD_LENGTH);
Assert.assertFalse(keyword.equals(nonExistant));
ISnu toNotFind = SnuFactory.createNew(DataRegistry.getMaxId(), 0);
DomainTestUtil.initializeRandom(toNotFind);
toNotFind.setName(""); // avoid search hits by name
toNotFind.setKeywords(Arrays.asList((IKeyword)KeywordFactory.createNew(nonExistant)));
}
UoW.getCurrent().commit();
UoW.newCurrent();
Request request = new Request();
request.set("id", searchSnu.getId());
Response response = new Response();
new SimulatedSearchCommand(request, response).execute();
List<ISnu> results = (List<ISnu>)response.get("results");
Assert.assertEquals(1, results.size());
DomainTestUtil.assertEqual(toFind1, results.get(0));
}
@Test public void testSearchNonExistantKeywordFindsNothing() throws Exception
{
final String nonExistant = DomainTestUtil.getRandomString(MIN_KEYWORD_LENGTH, MAX_KEYWORD_LENGTH);
ISnu searchSnu = createSnuWithKeywordLookup(parentDir, nonExistant);
// generate some potential false positives
for (int i = 0; i < 10; ++i) {
final String keyword = DomainTestUtil.getRandomString(MIN_KEYWORD_LENGTH, MAX_KEYWORD_LENGTH);
Assert.assertFalse(keyword.equals(nonExistant));
ISnu toNotFind = SnuFactory.createNew();
DomainTestUtil.initializeRandom(toNotFind);
toNotFind.setName(""); // avoid search hits by name
toNotFind.setKeywords(Arrays.asList((IKeyword)KeywordFactory.createNew(keyword)));
}
UoW.getCurrent().commit();
UoW.newCurrent();
Request request = new Request();
request.set("id", searchSnu.getId());
Response response = new Response();
new SimulatedSearchCommand(request, response).execute();
List<ISnu> results = (List<ISnu>)response.get("results");
Assert.assertEquals(0, results.size());
}
@Test public void testSearchFindsSeveralSnusByKeywords() throws Exception
{
List<String> keywordsToFind = Arrays.asList(
DomainTestUtil.getRandomString(MIN_KEYWORD_LENGTH, MAX_KEYWORD_LENGTH),
DomainTestUtil.getRandomString(MIN_KEYWORD_LENGTH, MAX_KEYWORD_LENGTH),
DomainTestUtil.getRandomString(MIN_KEYWORD_LENGTH, MAX_KEYWORD_LENGTH),
DomainTestUtil.getRandomString(MIN_KEYWORD_LENGTH, MAX_KEYWORD_LENGTH),
DomainTestUtil.getRandomString(MIN_KEYWORD_LENGTH, MAX_KEYWORD_LENGTH)
);
// expected search result
Collection<ISnu> snusToFind = new ArrayList<ISnu>();
for (int i = 0; i < 5; ++i)
{
ISnu toFind = SnuFactory.createNew();
DomainTestUtil.initializeRandom(toFind);
toFind.setName(""); // avoid search hits by name
List<String> keywords = getRandomNonEmptySublist(keywordsToFind);
toFind.setKeywords(DOFactory.createKeywords(keywords));
snusToFind.add(toFind);
}
// generate some potential false positives
for (int i = 0; i < 10; ++i) {
final String keyword = DomainTestUtil.getRandomString(MIN_KEYWORD_LENGTH, MAX_KEYWORD_LENGTH);
Assert.assertFalse(keywordsToFind.contains(keyword)); // basically these kinds of things are unlikely enough that i assert instead of handling the possibility
ISnu toNotFind = SnuFactory.createNew();
DomainTestUtil.initializeRandom(toNotFind);
toNotFind.setName(""); // avoid search hits by name
toNotFind.setKeywords(Arrays.asList((IKeyword)KeywordFactory.createNew(keyword)));
}
ISnu searchSnu = createSnuWithKeywordLookup(parentDir, keywordsToFind);
UoW.getCurrent().commit();
UoW.newCurrent();
Request request = new Request();
request.set("id", searchSnu.getId());
Response response = new Response();
new SimulatedSearchCommand(request, response).execute();
List<ISnu> results = (List<ISnu>)response.get("results");
Assert.assertEquals(snusToFind.size(), results.size());
for (ISnu expected : snusToFind)
Assert.assertTrue(results.contains(expected)); // DO equality by id
}
@Test public void testSearchResultRanking() throws Exception
{
List<String> keywordsToFind = Arrays.asList(
DomainTestUtil.getRandomString(MIN_KEYWORD_LENGTH, MAX_KEYWORD_LENGTH),
DomainTestUtil.getRandomString(MIN_KEYWORD_LENGTH, MAX_KEYWORD_LENGTH),
DomainTestUtil.getRandomString(MIN_KEYWORD_LENGTH, MAX_KEYWORD_LENGTH),
DomainTestUtil.getRandomString(MIN_KEYWORD_LENGTH, MAX_KEYWORD_LENGTH),
DomainTestUtil.getRandomString(MIN_KEYWORD_LENGTH, MAX_KEYWORD_LENGTH)
);
// System.out.println(Util.join(keywordsToFind));
// the expected results each have a different number of matching keywords
// with the first having one and the last having all
// except we want to eliminate order of creation/setup as a possible source
// of ordering so we generate and shuffle the indices in advance
List<Integer> keywordCount = new ArrayList<Integer>();
for (int i = 0; i < keywordsToFind.size(); ++i)
keywordCount.add(i+1);
Collections.shuffle(keywordCount);
final Map<ISnu, Float> expectedOrdering = new HashMap<ISnu, Float>();
// expected search result
List<ISnu> snusToFind = new ArrayList<ISnu>();
for (int i = 0; i < keywordsToFind.size(); ++i)
{
ISnu toFind = SnuFactory.createNew();
DomainTestUtil.initializeRandom(toFind); // rating is randomized.
toFind.setName(""); // avoid search hits by name
List<String> keywords = new ArrayList<String>();
int count = keywordCount.get(i);
for (int j = 0; j < count; ++j)
keywords.add(keywordsToFind.get(j));
toFind.setKeywords(DOFactory.createKeywords(keywords));
snusToFind.add(toFind);
// System.out.println("E"+toFind.getId()+"\t"+count);
expectedOrdering.put(toFind, count * toFind.getRating());
}
// put them in the order we expect to find them
Collections.sort(snusToFind, new Comparator<ISnu>() {
public int compare(ISnu o1, ISnu o2) {
return expectedOrdering.get(o2).compareTo(expectedOrdering.get(o1));
}
});
// generate some potential false positives
for (int i = 0; i < 10; ++i) {
final String keyword = DomainTestUtil.getRandomString(MIN_KEYWORD_LENGTH, MAX_KEYWORD_LENGTH);
if (keywordsToFind.contains(keyword)) {
// this is unlikely if the length & seed of keywords is large enough, so just try again
--i;
continue;
}
Assert.assertFalse(""+keyword.length(), keywordsToFind.contains(keyword)); // basically these kinds of things are unlikely enough that i assert instead of handling the possibility
ISnu toNotFind = SnuFactory.createNew();
DomainTestUtil.initializeRandom(toNotFind);
toNotFind.setName(""); // avoid search hits by name
toNotFind.setKeywords(Arrays.asList((IKeyword)KeywordFactory.createNew(keyword)));
}
ISnu searchSnu = createSnuWithKeywordLookup(parentDir, keywordsToFind);
UoW.getCurrent().commit();
UoW.newCurrent();
Request request = new Request();
request.set("id", searchSnu.getId());
Response response = new Response();
new SimulatedSearchCommand(request, response).execute();
List<ISnu> results = (List<ISnu>)response.get("results");
// for (ISnu result : snusToFind)
// System.out.println("Expected=" + result.getId() + Util.join(result.getKeywords()));
// for (ISnu result : results)
// System.out.println("Actual=" + result.getId() + Util.join(result.getKeywords()));
Assert.assertEquals(snusToFind.size(), results.size());
// we found them, and in the expected order
for (int i = 0; i < snusToFind.size(); ++i)
{
long expected = snusToFind.get(i).getId();
long actual = results.get(i).getId();
// System.out.println("#"+i+"; Expected=" + expected + " \tActual=" + actual);
Assert.assertEquals(expected, actual); // DO.equals is currently fuxed
}
}
private static <T> List<T> getRandomNonEmptySublist(List<T> list)
{
List<T> shuffled = new ArrayList<T>(list);
if (list.isEmpty())
return shuffled;
Collections.shuffle(shuffled);
Random random = new Random();
shuffled = shuffled.subList(1, 1+random.nextInt(list.size()-1)+1); // 1 guarantees non-empty
Assert.assertTrue(!shuffled.isEmpty());
return shuffled;
}
private static ISnu createSnuWithKeywordLookup(File parentDir, Collection<String> keywords) throws Exception
{
return createSnuWithKeywordLookup(parentDir, keywords.toArray(new String[0]));
}
private static ISnu createSnuWithKeywordLookup(File parentDir, String... keywords) throws Exception
{
ISnu snu = DOFactory.createSnuWithDummyMedia(parentDir);
List<IRule> searchRules = new ArrayList<IRule>();
searchRules.add(DOFactory.createSearchRule(DOFactory.createKeywordLookupRule(keywords)));
snu.setRules(searchRules);
return snu;
}
}