/*******************************************************************************
* Copyright (c) 2013 Rene Schneider, GEBIT Solutions GmbH and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package de.gebit.integrity.eclipse.search;
import java.util.ArrayList;
import java.util.List;
import de.gebit.integrity.remoting.entities.setlist.SetList;
import de.gebit.integrity.remoting.entities.setlist.SetListEntry;
import de.gebit.integrity.remoting.entities.setlist.SetListEntryAttributeKeys;
import de.gebit.integrity.remoting.entities.setlist.SetListEntryResultStates;
import de.gebit.integrity.remoting.entities.setlist.SetListEntryTypes;
import de.gebit.integrity.remoting.entities.setlist.SetListUtil;
/**
* This is a very simple "search engine" used to search for text parts in a {@link SetList}. It searches for suite
* titles as well as visible comments. The algorithm used is pretty simple, and it remains to be seen whether it is fast
* enough even for larger setlists or if some kind of more efficient way to search has to be introduced here.
*
* @author Rene Schneider - initial API and implementation
*
*/
public class SetListSearch {
/**
* This contains all indexed entries.
*/
private List<SearchResult> entries = new ArrayList<SearchResult>();
/**
* This contains the setlist the index was built upon.
*/
private SetList setList;
/**
* Creates a new instance. This causes an indexing process over the {@link SetListEntry} tree.
*
* @param aSetList
* the setlist to index
*/
public SetListSearch(SetList aSetList) {
setList = aSetList;
createIndex(aSetList.getRootEntry(), aSetList);
}
/**
* Creates an index over the given entry from the given setlist. Called recursively to traverse the whole tree.
*
* @param anEntry
* the entry to look at
* @param aSetList
* the setlist where the entry came from
*/
protected void createIndex(SetListEntry anEntry, SetList aSetList) {
boolean tempRecurse = false;
if (anEntry.getType() == SetListEntryTypes.SUITE) {
String tempSuiteName = anEntry.getAttribute(String.class, SetListEntryAttributeKeys.NAME);
if (tempSuiteName != null) {
SetListEntryResultStates tempResultState = setList.getResultStateForEntry(anEntry);
if (tempResultState != null) {
entries.add(new SearchResult(tempSuiteName, !tempResultState.isUnsuccessful(), true, anEntry));
}
}
tempRecurse = true;
} else if (anEntry.getType() == SetListEntryTypes.COMMENT) {
String tempCommentText = (String) anEntry.getAttribute(SetListEntryAttributeKeys.VALUE);
if (tempCommentText != null) {
// Comments can't "fail"
entries.add(new SearchResult(tempCommentText, true, false, anEntry));
}
} else if (anEntry.getType() == SetListEntryTypes.EXECUTION) {
// Always recurse into the root entry
tempRecurse = true;
} else if (anEntry.getType() == SetListEntryTypes.TEST || anEntry.getType() == SetListEntryTypes.CALL) {
String tempTestText = (String) anEntry.getAttribute(SetListEntryAttributeKeys.DESCRIPTION);
if (tempTestText != null) {
SetListEntryResultStates tempResultState = setList.getResultStateForEntry(anEntry);
if (tempResultState != null) {
entries.add(new SearchResult(tempTestText, !tempResultState.isUnsuccessful(), false, anEntry));
}
}
} else if (anEntry.getType() == SetListEntryTypes.TABLETEST) {
String tempTestText = (String) anEntry.getAttribute(SetListEntryAttributeKeys.DESCRIPTION);
if (tempTestText != null) {
SetListEntryResultStates tempResultState = setList.getResultStateForEntry(anEntry);
if (tempResultState != null) {
entries.add(new SearchResult(tempTestText, !tempResultState.isUnsuccessful(), true, anEntry));
}
}
// For tabletests, we fetch all sub-entries with the results for each line here and index them instead of
// triggering on "result" elements and finding out whether they belong to a tabletest.
List<SetListEntry> tempResultEntries = SetListUtil.getSetListEntryChilds((SetListEntry) anEntry, aSetList);
for (SetListEntry tempResultEntry : tempResultEntries) {
if (tempResultEntry.getType() == SetListEntryTypes.RESULT) {
String tempLineText = (String) tempResultEntry.getAttribute(SetListEntryAttributeKeys.DESCRIPTION);
if (tempLineText != null) {
SetListEntryResultStates tempResultState = setList.getResultStateForEntry(tempResultEntry);
if (tempResultState != null) {
entries.add(new SearchResult(tempLineText, !tempResultState.isUnsuccessful(), false,
tempResultEntry));
}
}
}
}
}
if (tempRecurse) {
for (SetListEntry tempChild : SetListUtil.getSetListEntryChilds(anEntry, aSetList)) {
createIndex(tempChild, aSetList);
}
}
}
/**
* Finds matching entries for the given query.
*
* @param aQuery
* the string to search for
* @return matching entries (returns an empty list if no matches were found)
*/
public List<SetListEntry> findEntries(String aQuery) {
List<SetListEntry> tempResults = new ArrayList<SetListEntry>();
for (SearchResult tempPossibleResult : entries) {
if (tempPossibleResult.matches(aQuery)) {
tempResults.add(tempPossibleResult.getEntry());
}
}
return tempResults;
}
/**
* Finds entries which are considered "unsuccessful" (failed tests, tests with exceptions etc.).
*
* @return matching entries (returns an empty list if no matches were found)
*/
public List<SetListEntry> findUnsuccessfulEntries(boolean anIncludeSubResultDependentEntries) {
List<SetListEntry> tempResults = new ArrayList<SetListEntry>();
for (SearchResult tempPossibleResult : entries) {
if (!tempPossibleResult.isSuccessful()) {
if (!tempPossibleResult.isSubResultDependent() || anIncludeSubResultDependentEntries) {
tempResults.add(tempPossibleResult.getEntry());
}
}
}
return tempResults;
}
private class SearchResult {
/**
* The textual representation.
*/
private String text;
/**
* Whether the element is considered "successful" (ex.: passed test).
*/
private boolean successful;
/**
* Whether this is an element whose success status depends on the success of sub-elements (ex.: suites).
*/
private boolean subResultDependent;
/**
* The entry.
*/
private SetListEntry entry;
SearchResult(String aText, boolean aSuccessfulFlag, boolean aSubResultDependentFlag, SetListEntry anEntry) {
text = aText;
successful = aSuccessfulFlag;
subResultDependent = aSubResultDependentFlag;
entry = anEntry;
}
public SetListEntry getEntry() {
return entry;
}
public boolean matches(String aQuery) {
return text.contains(aQuery);
}
public boolean isSuccessful() {
return successful;
}
public boolean isSubResultDependent() {
return subResultDependent;
}
}
}