/*******************************************************************************
* Copyright (c) 2012 BREDEX GmbH.
* 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
*
* Contributors:
* BREDEX GmbH - initial API and implementation
*******************************************************************************/
package org.eclipse.jubula.rc.common.tester;
import static org.eclipse.jubula.rc.common.driver.CheckWithTimeoutQueuer.invokeAndWait;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.eclipse.jubula.rc.common.driver.ClickOptions;
import org.eclipse.jubula.rc.common.driver.ClickOptions.ClickModifier;
import org.eclipse.jubula.rc.common.driver.DragAndDropHelper;
import org.eclipse.jubula.rc.common.exception.StepExecutionException;
import org.eclipse.jubula.rc.common.tester.adapter.interfaces.IListComponent;
import org.eclipse.jubula.rc.common.util.IndexConverter;
import org.eclipse.jubula.rc.common.util.ListSelectionVerifier;
import org.eclipse.jubula.rc.common.util.MatchUtil;
import org.eclipse.jubula.rc.common.util.SelectionUtil;
import org.eclipse.jubula.rc.common.util.Verifier;
import org.eclipse.jubula.toolkit.enums.ValueSets.SearchType;
import org.eclipse.jubula.tools.internal.constants.StringConstants;
import org.eclipse.jubula.tools.internal.constants.TestDataConstants;
import org.eclipse.jubula.tools.internal.objects.event.EventFactory;
import org.eclipse.jubula.tools.internal.objects.event.TestErrorEvent;
import org.eclipse.jubula.tools.internal.utils.StringParsing;
/**
* @author BREDEX GmbH
*/
public class ListTester extends AbstractTextVerifiableTester {
/**
* Splits the enumeration of values.
* @param values The values to split
* @param separator The separator, may be <code>null</code>
* @return The array of values
*/
private String[] split(String values, String separator) {
String[] list = StringParsing.splitToArray(values, ((separator == null)
|| (separator.length() == 0) ? INDEX_LIST_SEP_CHAR
: separator.charAt(0)),
TestDataConstants.ESCAPE_CHAR_DEFAULT);
list = StringUtils.stripAll(list);
return list;
}
/**
* @return The array of selected indices
* @throws StepExecutionException If there are no indices selected
*/
private int[] getCheckedSelectedIndices() throws StepExecutionException {
int[] selected = getListAdapter().getSelectedIndices();
SelectionUtil.validateSelection(selected);
return selected;
}
/**
*
* @return the List Adapter
*/
private IListComponent getListAdapter() {
return ((IListComponent) getComponent());
}
/**
* Verifies if the passed index is selected.
*
* @param index The index to verify
* @param expectSelected Whether the index should be selected.
* @param timeout the maximum amount of time to wait for the index's
* selection to be verified
*/
public void rcVerifySelectedIndex(final String index,
final boolean expectSelected, int timeout) {
invokeAndWait("rcVerifySelectedIndex", timeout, new Runnable() { //$NON-NLS-1$
public void run() {
int[] selected = getCheckedSelectedIndices();
int implIndex = IndexConverter.toImplementationIndex(
Integer.parseInt(index));
boolean isSelected = ArrayUtils.contains(selected, implIndex);
if (expectSelected != isSelected) {
throw new StepExecutionException(
"Selection check failed for index: " + index, //$NON-NLS-1$
EventFactory.createVerifyFailed(
String.valueOf(expectSelected),
String.valueOf(isSelected)));
}
}
});
}
/**
* Verifies if the passed value or enumeration of values is selected. By
* default, the enumeration separator is <code>,</code>
* @param valueList The value or list of values to verify
* @param timeout the maximum amount of time to wait for the check whether
* the passed value is selected to be performed
*/
public void rcVerifySelectedValue(String valueList, int timeout) {
rcVerifySelectedValue(valueList, MatchUtil.DEFAULT_OPERATOR, true,
timeout);
}
/**
* Verifies if the passed value is selected.
*
* @param value The value to verify
* @param operator The operator to use when comparing the
* expected and actual values.
* @param isSelected if the value should be selected or not.
* @param timeout the maximum amount of time to wait for the check whether
* the passed value is selected to be performed
*/
public void rcVerifySelectedValue(final String value, final String operator,
final boolean isSelected, int timeout) {
invokeAndWait("rcVerifySelectedValue", timeout, new Runnable() { //$NON-NLS-1$
public void run() {
final String[] current = getListAdapter().getSelectedValues();
final ListSelectionVerifier listSelVerifier =
new ListSelectionVerifier();
for (int i = 0; i < current.length; i++) {
listSelVerifier.addItem(i, current[i], true);
}
listSelVerifier.verifySelection(value, operator,
isSelected);
}
});
}
/**
* Verifies if all selected elements of a list match a text.
* @param text The text to verify
* @param operator The operator used to verify
* @param timeout the maximum amount of time to wait to verify whether all
* selected elements of the list matches the text
*/
public void rcVerifyText(final String text, final String operator,
int timeout) {
invokeAndWait("rcVerifyText", timeout, new Runnable() { //$NON-NLS-1$
public void run() {
String[] selected = getListAdapter().getSelectedValues();
final int selCount = selected.length;
SelectionUtil.validateSelection(selected);
for (int i = 0; i < selCount; i++) {
Verifier.match(selected[i], text, operator);
}
}
});
}
/**
* Selects the passed index or enumeration of indices. The enumeration must
* be separated by <code>,</code>, e.g. <code>1, 3,6</code>.
* @param indexList The index or indices to select
* @param extendSelection Whether this selection extends a previous
* selection.
* @param button what mouse button should be used
* @param clickCount the click count
*/
public void rcSelectIndex(String indexList, final String extendSelection,
int button, int clickCount) {
selectIndices(IndexConverter.toImplementationIndices(
parseIndices(indexList)),
ClickOptions.create()
.setClickCount(clickCount)
.setMouseButton(button)
.setClickModifier(getClickModifier(extendSelection)));
}
/**
* Selects the passed value or enumeration of values. By default, the
* enumeration separator is <code>,</code>.
* @param valueList The value or list of values to select
* @param operator If regular expressions are used
* @param searchType Determines where the search begins ("relative" or "absolute")
* @param extendSelection Whether this selection extends a previous
* selection. If <code>true</code>, the first
* element will be selected with CONTROL as a
* modifier.
* @param button what mouse button should be used
* @param clickCount the click count
*/
public void rcSelectValue(String valueList, String operator,
String searchType, final String extendSelection, int button,
int clickCount) {
selectValue(valueList, String.valueOf(VALUE_SEPARATOR), operator,
searchType, ClickOptions.create()
.setClickCount(clickCount)
.setMouseButton(button)
.setClickModifier(getClickModifier(extendSelection)));
}
/**
* Verifies if the list contains an element that renders <code>value</code>.
* @param value The text to verify
* @param timeout the maximum amount to wait to check whether the component
* contains the specified text
*/
public void rcVerifyContainsValue(final String value, int timeout) {
invokeAndWait("rcVerifyContainsValue", timeout, new Runnable() { //$NON-NLS-1$
public void run() {
Verifier.equals(true, containsValue(value));
}
});
}
/**
* Verifies if the list contains an element that renders <code>value</code>.
* @param value The text to verify
* @param operator The operator used to verify
* @param exists if the wanted value should exist or not.
* @param timeout the maximum amount to wait to check whether the component
* contains the specified text
*/
public void rcVerifyContainsValue(final String value, final String operator,
final boolean exists, int timeout) {
invokeAndWait("rcVerifyContainsValue", timeout, new Runnable() { //$NON-NLS-1$
public void run() {
Verifier.equals(exists, containsValue(value, operator));
}
});
}
/**
* Action to read the value of the current selected item of the JList
* to store it in a variable in the Client
* @param variable the name of the variable
* @return the text value.
*/
public String rcReadValue(String variable) {
String[] selected = getListAdapter().getSelectedValues();
SelectionUtil.validateSelection(selected);
return selected[0];
}
/**
* Drags the passed value.
*
* @param mouseButton the mouseButton.
* @param modifier the modifier.
* @param value The value to drag
* @param operator If regular expressions are used
* @param searchType Determines where the search begins ("relative" or "absolute")
*/
public void rcDragValue(int mouseButton, String modifier, String value,
String operator, final String searchType) {
DragAndDropHelper dndHelper = DragAndDropHelper.getInstance();
dndHelper.setModifier(modifier);
dndHelper.setMouseButton(mouseButton);
Integer [] indices = findIndicesOfValues(
new String [] {value}, operator, searchType);
selectIndices(ArrayUtils.toPrimitive(indices),
ClickOptions.create().setClickCount(0));
pressOrReleaseModifiers(modifier, true);
getRobot().mousePress(null, null, mouseButton);
}
/**
* Drops on the passed value.
*
* @param value The value on which to drop
* @param operator If regular expressions are used
* @param searchType Determines where the search begins ("relative" or "absolute")
* @param delayBeforeDrop the amount of time (in milliseconds) to wait
* between moving the mouse to the drop point and
* releasing the mouse button
*/
public void rcDropValue(String value, String operator,
final String searchType, int delayBeforeDrop) {
DragAndDropHelper dndHelper = DragAndDropHelper.getInstance();
try {
Integer [] indices = findIndicesOfValues(
new String [] {value}, operator, searchType);
selectIndices(ArrayUtils.toPrimitive(indices),
ClickOptions.create().setClickCount(0));
waitBeforeDrop(delayBeforeDrop);
} finally {
getRobot().mouseRelease(null, null, dndHelper.getMouseButton());
pressOrReleaseModifiers(dndHelper.getModifier(), false);
}
}
/**
* Drags the passed index.
*
* @param mouseButton the mouseButton.
* @param modifier the modifier.
* @param index The index to drag
*/
public void rcDragIndex(final int mouseButton, final String modifier,
int index) {
DragAndDropHelper dndHelper = DragAndDropHelper.getInstance();
dndHelper.setModifier(modifier);
dndHelper.setMouseButton(mouseButton);
selectIndices(
new int [] {IndexConverter.toImplementationIndex(index)},
ClickOptions.create().setClickCount(0));
pressOrReleaseModifiers(modifier, true);
getRobot().mousePress(null, null, mouseButton);
}
/**
* Drops onto the passed index.
*
* @param index The index on which to drop
* @param delayBeforeDrop the amount of time (in milliseconds) to wait
* between moving the mouse to the drop point and
* releasing the mouse button
*/
public void rcDropIndex(final int index, int delayBeforeDrop) {
DragAndDropHelper dndHelper = DragAndDropHelper.getInstance();
try {
selectIndices(
new int [] {IndexConverter.toImplementationIndex(index)},
ClickOptions.create().setClickCount(0));
waitBeforeDrop(delayBeforeDrop);
} finally {
getRobot().mouseRelease(null, null, dndHelper.getMouseButton());
pressOrReleaseModifiers(dndHelper.getModifier(), false);
}
}
/**
* @param value The value
* @return <code>true</code> if the list contains an element that is rendered with <code>value</code>
*/
public boolean containsValue(String value) {
Integer[] indices = findIndicesOfValues(
new String[] { value },
MatchUtil.EQUALS, SearchType.absolute.rcValue());
return indices.length > 0;
}
/**
* @param value The value
* @param operator The operator used to verify
* @return <code>true</code> if the list contains an element that is rendered with <code>value</code>
*/
public boolean containsValue(String value, String operator) {
Integer[] indices = null;
if (operator.equals(MatchUtil.NOT_EQUALS)) {
indices = findIndicesOfValues(
new String[] { value },
MatchUtil.EQUALS, SearchType.absolute.rcValue());
return indices.length == 0;
}
indices = findIndicesOfValues(new String[] { value },
operator, SearchType.absolute.rcValue());
return indices.length > 0;
}
/**
* Selects the passed value or enumeration of values. By default, the
* enumeration separator is <code>,</code>, but may be changed by
* <code>separator</code>.
* @param valueList The value or list of values to select
* @param separator The separator, optional
* @param operator If regular expressions are used
* @param searchType Determines where the search begins ("relative" or "absolute")
* @param co the click options to use
*/
private void selectValue(String valueList, String separator,
String operator, final String searchType, ClickOptions co) {
String[] values = null;
if (StringConstants.EMPTY.equals(valueList)) {
values = new String[1];
values[0] = StringConstants.EMPTY;
} else {
values = split(valueList, separator);
}
Integer[] indices = findIndicesOfValues(values,
operator, searchType);
Arrays.sort(indices);
if (!operator.equals(MatchUtil.NOT_EQUALS)
&& (indices.length < values.length)) {
throw new StepExecutionException("One or more values not found of set: " //$NON-NLS-1$
+ Arrays.asList(values).toString(),
EventFactory.createActionError(TestErrorEvent.NOT_FOUND));
}
selectIndices(ArrayUtils.toPrimitive(indices), co);
}
/**
* Parses the enumeration of indices.
* @param indexList The enumeration of indices
* @return The array of parsed indices
*/
private int[] parseIndices(String indexList) {
String[] list = StringParsing.splitToArray(indexList,
INDEX_LIST_SEP_CHAR, TestDataConstants.ESCAPE_CHAR_DEFAULT);
int[] indices = new int[list.length];
for (int i = 0; i < list.length; i++) {
indices[i] = IndexConverter.intValue(list[i]);
}
return indices;
}
/**
* @param indices
* The indices to select
* @param co
* the click options to use
*/
private void selectIndices(int[] indices, ClickOptions co) {
int indexToStart = 0;
final int noOfItemsToSelect = indices.length;
final ClickModifier currentClickModifier = co.getClickModifier();
boolean isExtendSelection = currentClickModifier
.hasModifiers(ClickModifier.M1);
final IListComponent listAdapter = getListAdapter();
if (!isExtendSelection) {
if (noOfItemsToSelect > 0) {
// set a new first selection
listAdapter.clickOnIndex(indices[0], co);
}
indexToStart++;
}
// if multiple items should be selected at once implicitly extend selection
if (noOfItemsToSelect > 1) {
currentClickModifier.add(ClickModifier.M1);
}
for (int i = indexToStart; i < noOfItemsToSelect; i++) {
listAdapter.clickOnIndex(indices[i], co);
}
}
/**
* {@inheritDoc}
*/
public String[] getTextArrayFromComponent() {
return null;
}
/**
* Finds the indices of the list elements that are rendered with the passed
* values.
*
* @param values
* The values
* @param operator
* operator to use
* @param searchType
* Determines where the search begins ("relative" or "absolute")
* @return The array of indices. It's length is equal to the length of the
* values array, but may contains <code>null</code> elements for all
* values that are not found in the list
*/
private Integer[] findIndicesOfValues(final String[] values,
final String operator, final String searchType) {
String[] listValues = getListAdapter().getValues();
int startIndex = getStartingIndex(searchType);
final int valuesCount = values.length;
final List<Integer> indexList = new LinkedList<Integer>();
final MatchUtil matchUtil = MatchUtil.getInstance();
for (int i = 0; i < valuesCount; i++) {
final String value = values[i];
for (int j = startIndex; j < listValues.length; j++) {
final String listItem = listValues[j];
if (matchUtil.match(listItem, value, operator)) {
indexList.add(j);
}
}
}
return indexList.toArray(new Integer[indexList.size()]);
}
/**
* @param searchType Determines where the search begins ("relative" or "absolute")
* @return The index from which to begin a search, based on the search type
* and (if appropriate) the currently selected cell.
*/
private int getStartingIndex(final String searchType) {
int startingIndex = 0;
if (searchType.equalsIgnoreCase(SearchType.relative.rcValue())) {
int [] selectedIndices = getListAdapter().getSelectedIndices();
// Start from the last selected item, if any item(s) are selected
if (selectedIndices.length > 0) {
startingIndex = selectedIndices[selectedIndices.length - 1] + 1;
}
}
return startingIndex;
}
/**
* Verifies the value of the property with the name <code>name</code>
* of the tree item at the current mouse position.
* The name of the property has be specified according to the JavaBean
* specification. The value returned by the property is converted into a
* string by calling <code>toString()</code> and is compared to the passed
* <code>value</code>.
*
* @param name The name of the property
* @param value The value of the property as a string
* @param operator The operator used to verify
* @param timeout the maximum amount of time to wait for the property
* at mouse position to be checked
*/
public void rcCheckPropertyAtMousePosition(final String name,
final String value, final String operator, int timeout) {
invokeAndWait("rcCheckPropertyAtMousePosition", timeout, //$NON-NLS-1$
new Runnable() {
public void run() {
final Object cell = getNodeAtMousePosition();
final IListComponent bean = getListAdapter();
final String propToStr =
bean.getPropertyValueOfCell(name, cell);
Verifier.match(propToStr, value, operator);
}
});
}
/**
* @return the object under the current mouse position.
* @throws StepExecutionException If no cell is found.
*/
protected Object getNodeAtMousePosition() throws StepExecutionException {
StepExecutionException.throwUnsupportedAction();
return null;
}
}