// Copyright 2012 Google Inc. All Rights Reserved.
package com.google.api.explorer.client.search;
import com.google.api.explorer.client.search.SearchResultIndex.KeywordCallback;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.SetMultimap;
import com.google.common.collect.Sets;
import junit.framework.TestCase;
import org.easymock.EasyMock;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Test the search result indexer.
*
*/
public class SearchResultIndexTest extends TestCase {
/**
* Simple passthrough indexing strategy that convert and index to the stream that will eventually
* become the same index.
*/
private static class PassthroughIndex
implements IndexingStrategy<SetMultimap<String, SearchResult>> {
@Override
public Iterable<SearchEntry> index(SetMultimap<String, SearchResult> fragment) {
// Invert the map to extract all keywords for each result.
SetMultimap<SearchResult, String> resultToKeywords = HashMultimap.create();
for (Map.Entry<String, SearchResult> mapping : fragment.entries()) {
resultToKeywords.put(mapping.getValue(), mapping.getKey());
}
List<SearchEntry> entries = Lists.newArrayListWithCapacity(resultToKeywords.keySet().size());
for (SearchResult result : resultToKeywords.keySet()) {
entries.add(new SearchEntry(result, resultToKeywords.get(result)));
}
return entries;
}
}
private SearchResultIndex index = new SearchResultIndex();
private PassthroughIndex strategy = new PassthroughIndex();
/** Test the most basic query. */
public void testSingleWordQuery() {
SearchResult result1 = createUniqueSearchResult();
SetMultimap<String, SearchResult> fragment = HashMultimap.create();
fragment.put("keyword", result1);
index.addDocument(fragment, strategy);
assertEquals(result1, index.search("keyword").iterator().next());
assertTrue(!index.search("notakeyword").iterator().hasNext());
}
/** Test queries that multiple documents. */
public void testMultipleDocuments() {
SearchResult result1 = createUniqueSearchResult();
SearchResult result2 = createUniqueSearchResult();
SetMultimap<String, SearchResult> fragment = HashMultimap.create();
fragment.put("keyword", result1);
fragment.put("keyword2", result2);
fragment.putAll("commonkeyword", ImmutableSet.of(result1, result2));
index.addDocument(fragment, strategy);
verifyMultipleDocumentQueries(result1, result2);
}
/** Test queries that involve multiple documents from different indexing strategies. */
public void testMergeIndexes() {
SearchResult result1 = createUniqueSearchResult();
SetMultimap<String, SearchResult> fragment1 = HashMultimap.create();
fragment1.put("keyword", result1);
fragment1.put("commonkeyword", result1);
index.addDocument(fragment1, strategy);
assertEquals(ImmutableSet.of(result1), ImmutableSet.copyOf(index.search("keyword")));
assertEquals(ImmutableSet.of(), ImmutableSet.copyOf(index.search("keyword2")));
SearchResult result2 = createUniqueSearchResult();
SetMultimap<String, SearchResult> fragment2 = HashMultimap.create();
fragment2.put("keyword2", result2);
fragment2.put("commonkeyword", result2);
index.addDocument(fragment2, strategy);
verifyMultipleDocumentQueries(result1, result2);
}
/** Test that querying an empty index works. */
public void testEmptyIndex() {
assertTrue(ImmutableSet.copyOf(index.search("keyword")).isEmpty());
}
/** Test that our keyword update callback works properly. */
public void testKeywordUpdates() {
final Set<String> lastKeywords = Sets.newHashSet();
index.setKeywordCallback(new KeywordCallback() {
@Override
public void newKeywordsAdded(Set<String> keywords) {
lastKeywords.clear();
lastKeywords.addAll(keywords);
}
});
assertTrue(lastKeywords.isEmpty());
SearchResult result1 = createUniqueSearchResult();
SetMultimap<String, SearchResult> fragment1 = HashMultimap.create();
fragment1.put("keyword", result1);
fragment1.put("commonkeyword", result1);
index.addDocument(fragment1, strategy);
assertEquals(ImmutableSet.of("keyword", "commonkeyword"), lastKeywords);
SearchResult result2 = createUniqueSearchResult();
SetMultimap<String, SearchResult> fragment2 = HashMultimap.create();
fragment2.put("keyword2", result2);
fragment2.put("commonkeyword", result2);
index.addDocument(fragment2, strategy);
assertEquals(ImmutableSet.of("keyword2"), lastKeywords);
SearchResult result3 = createUniqueSearchResult();
SetMultimap<String, SearchResult> fragment3 = HashMultimap.create();
fragment3.put("commonkeyword", result3);
index.addDocument(fragment3, strategy);
assertTrue(lastKeywords.isEmpty());
}
private void verifyMultipleDocumentQueries(SearchResult result1, SearchResult result2) {
// Test a few single word queries.
assertEquals(ImmutableSet.of(result1), ImmutableSet.copyOf(index.search("keyword")));
assertEquals(ImmutableSet.of(result2), ImmutableSet.copyOf(index.search("keyword2")));
assertEquals(
ImmutableSet.of(result1, result2), ImmutableSet.copyOf(index.search("commonkeyword")));
// Test the valid multiple word queries.
assertEquals(
ImmutableSet.of(result1), ImmutableSet.copyOf(index.search("keyword commonkeyword")));
assertEquals(
ImmutableSet.of(result2), ImmutableSet.copyOf(index.search("keyword2 commonkeyword")));
assertTrue(Iterables.isEmpty(index.search("commonkeyword keyword keyword2")));
}
private SearchResult createUniqueSearchResult() {
SearchResult result = EasyMock.createMock(SearchResult.class);
EasyMock.replay(result);
return result;
}
}