/*******************************************************************************
* Copyright (c) 2016 Ericsson 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 org.eclipse.tracecompass.lttng2.kernel.ui.swtbot.tests;
import static org.junit.Assert.assertTrue;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jface.bindings.keys.KeyStroke;
import org.eclipse.swtbot.eclipse.finder.widgets.SWTBotView;
import org.eclipse.swtbot.swt.finder.SWTBot;
import org.eclipse.swtbot.swt.finder.finders.UIThreadRunnable;
import org.eclipse.swtbot.swt.finder.junit.SWTBotJunit4ClassRunner;
import org.eclipse.swtbot.swt.finder.keyboard.Keyboard;
import org.eclipse.swtbot.swt.finder.keyboard.KeyboardFactory;
import org.eclipse.swtbot.swt.finder.keyboard.Keystrokes;
import org.eclipse.swtbot.swt.finder.matchers.WidgetOfType;
import org.eclipse.swtbot.swt.finder.utils.SWTUtils;
import org.eclipse.swtbot.swt.finder.waits.Conditions;
import org.eclipse.swtbot.swt.finder.widgets.SWTBotButton;
import org.eclipse.swtbot.swt.finder.widgets.SWTBotCheckBox;
import org.eclipse.swtbot.swt.finder.widgets.SWTBotCombo;
import org.eclipse.swtbot.swt.finder.widgets.SWTBotLabel;
import org.eclipse.swtbot.swt.finder.widgets.SWTBotRadio;
import org.eclipse.swtbot.swt.finder.widgets.SWTBotShell;
import org.eclipse.tracecompass.tmf.core.signal.TmfSelectionRangeUpdatedSignal;
import org.eclipse.tracecompass.tmf.core.signal.TmfSignalManager;
import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimestamp;
import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimeRange;
import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestamp;
import org.eclipse.tracecompass.tmf.ui.swtbot.tests.shared.ConditionHelpers;
import org.eclipse.tracecompass.tmf.ui.swtbot.tests.shared.SWTBotUtils;
import org.eclipse.tracecompass.tmf.ui.views.timegraph.AbstractTimeGraphView;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeGraphEntry;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.TimeGraphControl;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
/**
* Abstract class to build SWTBot test for time graph find dialog. Test the time
* graph view find dialog and its options.
*
* @author Jean-Christian Kouame
*/
@RunWith(SWTBotJunit4ClassRunner.class)
public abstract class FindDialogTestBase extends KernelTestBase {
private static final Keyboard KEYBOARD = KeyboardFactory.getSWTKeyboard();
private static final @NonNull ITmfTimestamp START_TIME = TmfTimestamp.create(1368000272650993664L, ITmfTimestamp.NANOSECOND_SCALE);
private static final @NonNull String SPACE = " ";
private static final String REGEX_PREFIX = "\\A";
private static final String DIALOG_TITLE = "Find";
private String fFindText;
private SWTBotView fViewBot;
private static int fSelectionIndex;
/**
* Get the title of the time graph view the find dialog will use
*
* @return The view title
*/
protected abstract String getViewTitle();
/**
* Get the string that will be used for the search
*
* @return The string
*/
protected abstract String getFindText();
/**
* Initialize the test and open the timegraph view and the find dialog
*/
@Before
public void init() {
String title = getViewTitle();
fViewBot = fBot.viewByTitle(title);
fViewBot.show();
fViewBot.setFocus();
TmfSignalManager.dispatchSignal(new TmfSelectionRangeUpdatedSignal(this, START_TIME));
fBot.waitUntil(ConditionHelpers.timeGraphIsReadyCondition((AbstractTimeGraphView) fViewBot.getViewReference().getPart(false), new TmfTimeRange(START_TIME, START_TIME), START_TIME));
openDialog(fViewBot);
fFindText = getFindText();
}
/**
* After method to close the dialog
*/
@After
public void afterTest() {
closeDialog(getDialogBot());
}
private static void openDialog(SWTBotView view) {
view.setFocus();
SWTBotUtils.pressShortcutGoToTreeTop(KEYBOARD);
if (SWTUtils.isMac()) {
KEYBOARD.pressShortcut(Keystrokes.COMMAND, KeyStroke.getInstance('F'));
} else {
KEYBOARD.pressShortcut(Keystrokes.CTRL, KeyStroke.getInstance('F'));
}
fBot.waitUntil(Conditions.shellIsActive(DIALOG_TITLE));
}
/**
* Test wrap search option
*/
@Test
public void testWrapSearch() {
SWTBot bot = getDialogBot();
SWTBotButton findButton = bot.button("Find");
SearchOptions options = getOptions(false, false, true, false, false);
search(fFindText, options, findButton, bot);
assertTrue(isWrapped(bot));
verifySelection(fFindText, options, fViewBot, isWrapped(bot));
options = getOptions(true, false, true, false, false);
search(fFindText, options, findButton, bot);
assertTrue(isWrapped(bot));
}
/**
* Test the direction search option
*/
@Test
public void testDirection() {
SWTBot bot = getDialogBot();
SWTBotButton findButton = bot.button("Find");
// forward
testDirectionSearch(true, fFindText, bot, findButton, fViewBot);
testDirectionSearch(false, fFindText, bot, findButton, fViewBot);
}
private void testDirectionSearch(boolean forward, String findText, SWTBot bot, SWTBotButton findButton, SWTBotView view) {
SearchOptions options = getOptions(forward, false, true, false, false);
fSelectionIndex = getSelectionIndex(view);
search(findText, options, findButton, bot);
verifySelection(findText, options, view, isWrapped(bot));
}
/**
* Test the case sensitive search option
*/
@Test
public void testCaseSensitive() {
SWTBot bot = getDialogBot();
SWTBotButton findButton = bot.button("Find");
SearchOptions options = getOptions(true, true, false, false, false);
search(fFindText, options, findButton, bot);
verifyStatusLabel(bot, true);
search(fFindText.toLowerCase(), options, findButton, bot);
verifyStatusLabel(bot, false);
}
/**
* Test the whole word search option
*/
@Test
public void testWholeWord() {
SWTBot bot = getDialogBot();
SWTBotButton findButton = bot.button("Find");
@NonNull
String text = fFindText.split(SPACE)[0];
System.out.println("Reg ex : " + text);
SearchOptions options = getOptions(true, false, false, true, false);
search(text, options, findButton, bot);
verifyStatusLabel(bot, true);
search(text.substring(0, text.length() - 1), options, findButton, bot);
verifyStatusLabel(bot, false);
}
/**
* Test the regular expression search option
*/
@Test
public void testRegEx() {
SWTBot bot = getDialogBot();
SWTBotButton findButton = bot.button("Find");
final String text = REGEX_PREFIX + fFindText.split(SPACE)[0];
System.out.println("Reg ex : " + text);
SearchOptions options = getOptions(true, false, false, false, true);
search(text, options, findButton, bot);
verifyStatusLabel(bot, true);
options = getOptions(true, false, false, false, false);
search(text, options, findButton, bot);
verifyStatusLabel(bot, false);
}
/**
* Test open/close the find dialog
*/
@Test
public void testOpenCloseDialog() {
SWTBotShell shell = getDialogShell();
closeDialog(getDialogBot());
fBot.waitUntil(Conditions.shellCloses(shell));
openDialog(fViewBot);
}
private static void verifyStatusLabel(SWTBot bot, boolean shouldBeFound) {
// Get the second label in the dialog
SWTBotLabel statusLabel = bot.label(1);
assertTrue("status label", shouldBeFound == !statusLabel.getText().equals("Entry not found"));
}
/**
* Get the find dialog bot
*
* @return The bot
*/
private static SWTBot getDialogBot() {
return getDialogShell().bot();
}
/**
* Get the find dialog shell bot
*
* @return The shell bot
*/
private static SWTBotShell getDialogShell() {
return fBot.shell(DIALOG_TITLE);
}
private static void closeDialog(SWTBot bot) {
bot.button("Close").click();
}
private static void search(String findText, SearchOptions options, SWTBotButton findButton, SWTBot bot) {
// set the text to search
SWTBotCombo findFieldCombo = bot.comboBox();
findFieldCombo.setText(findText);
assertTrue("Find combo", findFieldCombo.getText().equals(findText));
// set the options
SWTBotRadio directions = options.forwardSearch ? bot.radio("Forward").click() : bot.radio("Backward").click();
assertTrue("direction", directions.isSelected());
setCheckButton("Case sensitive", options.caseSensitive, bot);
setCheckButton("Wrap search", options.wrapSearch, bot);
setCheckButton("Whole word", options.wholeWord, bot);
setCheckButton("Regular expression", options.regExSearch, bot);
findButton.click();
}
private SearchOptions getOptions(boolean forward, boolean caseSensitive, boolean wrapSearch, boolean wholeWord, boolean regEx) {
SearchOptions options = new SearchOptions();
options.forwardSearch = forward;
options.caseSensitive = caseSensitive;
options.wrapSearch = wrapSearch;
options.wholeWord = wholeWord;
options.regExSearch = regEx;
return options;
}
private static void setCheckButton(String mnemonic, boolean option, SWTBot bot) {
final SWTBotCheckBox checkBox = bot.checkBox(mnemonic);
if (checkBox.isEnabled()) {
if (option) {
checkBox.select();
} else {
checkBox.deselect();
}
}
}
private static void verifySelection(String name, SearchOptions options, SWTBotView view, boolean isWrapped) {
final String entryName = getTimegraphSelectionName(view);
assertTrue("entry name", entryName != null && entryName.contains(name));
final int selectionIndex = getSelectionIndex(view);
if (!isWrapped) {
assertTrue("selection index", options.forwardSearch ? selectionIndex > fSelectionIndex : selectionIndex < fSelectionIndex);
} else {
assertTrue("selection index", options.forwardSearch ? selectionIndex <= fSelectionIndex : selectionIndex >= fSelectionIndex);
}
fSelectionIndex = selectionIndex;
}
private static boolean isWrapped(final SWTBot bot) {
return bot.label(1).getText().equals("Wrapped search");
}
/**
* Get the timegraph view selected entry
*
* @param viewBot
* The timegraph view bot
* @return The selected entry
*/
private static String getTimegraphSelectionName(final SWTBotView view) {
final TimeGraphControl timegraph = view.bot().widget(WidgetOfType.widgetOfType(TimeGraphControl.class));
return UIThreadRunnable.syncExec(() -> {
ITimeGraphEntry entry = timegraph.getSelectedTrace();
if (entry != null) {
return entry.getName();
}
return null;
});
}
/**
* Get the index of the entry selected in the timegraph view
*
* @param viewBot
* The timegraph view bot
* @return
*/
private static Integer getSelectionIndex(SWTBotView viewBot) {
final TimeGraphControl timegraph = viewBot.bot().widget(WidgetOfType.widgetOfType(TimeGraphControl.class));
return UIThreadRunnable.syncExec(() -> {
return timegraph.getSelectedIndex();
});
}
private class SearchOptions {
boolean forwardSearch;
boolean caseSensitive;
boolean wrapSearch;
boolean wholeWord;
boolean regExSearch;
}
}