1 /*******************************************************************************
2 * Copyright (c) 2013, 2016 Ericsson
4 * All rights reserved. This program and the accompanying materials are
5 * made available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * Matthew Khouzam - Initial API and implementation
11 * Alexandre Montplaisir - Replaced separate Condition objects by anonymous classes
12 * Patrick Tasse - Add projectElementHasChild and isEditorOpened conditions
13 *******************************************************************************/
15 package org
.eclipse
.tracecompass
.tmf
.ui
.swtbot
.tests
.shared
;
17 import static org
.eclipse
.swtbot
.eclipse
.finder
.matchers
.WidgetMatcherFactory
.withPartName
;
19 import java
.util
.Arrays
;
20 import java
.util
.List
;
21 import java
.util
.regex
.Pattern
;
23 import org
.eclipse
.jdt
.annotation
.NonNull
;
24 import org
.eclipse
.jface
.viewers
.StructuredSelection
;
25 import org
.eclipse
.jface
.wizard
.IWizardContainer
;
26 import org
.eclipse
.jface
.wizard
.IWizardPage
;
27 import org
.eclipse
.jface
.wizard
.Wizard
;
28 import org
.eclipse
.osgi
.util
.NLS
;
29 import org
.eclipse
.swtbot
.eclipse
.finder
.SWTWorkbenchBot
;
30 import org
.eclipse
.swtbot
.eclipse
.finder
.matchers
.WidgetMatcherFactory
;
31 import org
.eclipse
.swtbot
.eclipse
.finder
.widgets
.SWTBotEditor
;
32 import org
.eclipse
.swtbot
.eclipse
.finder
.widgets
.SWTBotView
;
33 import org
.eclipse
.swtbot
.swt
.finder
.SWTBot
;
34 import org
.eclipse
.swtbot
.swt
.finder
.finders
.UIThreadRunnable
;
35 import org
.eclipse
.swtbot
.swt
.finder
.results
.Result
;
36 import org
.eclipse
.swtbot
.swt
.finder
.utils
.TableCollection
;
37 import org
.eclipse
.swtbot
.swt
.finder
.waits
.DefaultCondition
;
38 import org
.eclipse
.swtbot
.swt
.finder
.waits
.ICondition
;
39 import org
.eclipse
.swtbot
.swt
.finder
.widgets
.SWTBotTable
;
40 import org
.eclipse
.swtbot
.swt
.finder
.widgets
.SWTBotTree
;
41 import org
.eclipse
.swtbot
.swt
.finder
.widgets
.SWTBotTreeItem
;
42 import org
.eclipse
.tracecompass
.tmf
.core
.event
.ITmfEvent
;
43 import org
.eclipse
.tracecompass
.tmf
.core
.timestamp
.ITmfTimestamp
;
44 import org
.eclipse
.tracecompass
.tmf
.core
.timestamp
.TmfTimeRange
;
45 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.ITmfTrace
;
46 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.TmfTraceManager
;
47 import org
.eclipse
.tracecompass
.tmf
.ui
.editors
.TmfEventsEditor
;
48 import org
.eclipse
.tracecompass
.tmf
.ui
.viewers
.xycharts
.TmfXYChartViewer
;
49 import org
.eclipse
.tracecompass
.tmf
.ui
.views
.timegraph
.AbstractTimeGraphView
;
50 import org
.eclipse
.ui
.IEditorReference
;
51 import org
.hamcrest
.Matcher
;
52 import org
.swtchart
.Chart
;
55 * Is a tree node available
57 * @author Matthew Khouzam
59 public final class ConditionHelpers
{
61 private ConditionHelpers() {}
64 * Provide default implementations for some {@link ICondition} methods.
66 public abstract static class SWTBotTestCondition
implements ICondition
{
69 public abstract boolean test() throws Exception
;
72 public final void init(SWTBot bot
) {
76 public String
getFailureMessage() {
82 * Is a tree node available
85 * the name of the node
88 * @return true or false, it should swallow all exceptions
90 public static ICondition
IsTreeNodeAvailable(final String name
, final SWTBotTree tree
) {
91 return new SWTBotTestCondition() {
93 public boolean test() throws Exception
{
95 final SWTBotTreeItem
[] treeItems
= tree
.getAllItems();
96 for (SWTBotTreeItem ti
: treeItems
) {
97 final String text
= ti
.getText();
98 if (text
.equals(name
)) {
102 } catch (Exception e
) {
108 public String
getFailureMessage() {
109 return NLS
.bind("No child of tree {0} found with text {1}. Child items: {2}",
110 new String
[] { tree
.toString(), name
, Arrays
.toString(tree
.getAllItems()) });
116 * Is a table item available
119 * the name of the item
122 * @return true or false, it should swallow all exceptions
124 public static ICondition
isTableItemAvailable(final String name
, final SWTBotTable table
) {
125 return new SWTBotTestCondition() {
127 public boolean test() throws Exception
{
129 return table
.containsItem(name
);
130 } catch (Exception e
) {
136 public String
getFailureMessage() {
137 return NLS
.bind("No child of table {0} found with text ''{1}''.", table
, name
);
143 * Is the treeItem's node available
146 * the name of the node
149 * @return true or false, it should swallow all exceptions
151 public static ICondition
IsTreeChildNodeAvailable(final String name
, final SWTBotTreeItem treeItem
) {
152 return new SWTBotTestCondition() {
154 public boolean test() throws Exception
{
156 return treeItem
.getNode(name
) != null;
157 } catch (Exception e
) {
163 public String
getFailureMessage() {
164 return NLS
.bind("No child of tree item {0} found with text ''{1}''. Child items: {2}",
165 new String
[] { treeItem
.toString(), name
, Arrays
.toString(treeItem
.getItems()) });
171 * Is the treeItem's node removed
174 * length of the node after removal
177 * @return true or false, it should swallow all exceptions
179 public static ICondition
isTreeChildNodeRemoved(final int length
, final SWTBotTreeItem treeItem
) {
180 return new SWTBotTestCondition() {
182 public boolean test() throws Exception
{
184 return treeItem
.getNodes().size() == length
;
185 } catch (Exception e
) {
191 public String
getFailureMessage() {
192 return NLS
.bind("Child of tree item {0} found with text ''{1}'' not removed. Child items: {2}",
193 new String
[] { treeItem
.toString(), String
.valueOf(length
), Arrays
.toString(treeItem
.getItems()) });
199 * Condition to check if the number of direct children of the
200 * provided tree item equals the specified count.
203 * the SWTBot tree item
206 * @return ICondition for verification
208 public static ICondition
treeItemCount(final SWTBotTreeItem treeItem
, int count
) {
209 return new SWTBotTestCondition() {
211 public boolean test() throws Exception
{
212 return treeItem
.rowCount() == count
;
216 public String
getFailureMessage() {
217 return NLS
.bind("Tree item count: {0} expected: {1}",
218 treeItem
.rowCount(), count
);
224 * Checks if the wizard's shell is null
228 * @return false if either are null
230 public static ICondition
isWizardReady(final Wizard wizard
) {
231 return new SWTBotTestCondition() {
233 public boolean test() throws Exception
{
234 if (wizard
.getShell() == null) {
243 * Is the wizard on the page you want?
249 * @return true or false
251 public static ICondition
isWizardOnPage(final Wizard wizard
, final IWizardPage page
) {
252 return new SWTBotTestCondition() {
254 public boolean test() throws Exception
{
255 if (wizard
== null || page
== null) {
258 final IWizardContainer container
= wizard
.getContainer();
259 if (container
== null) {
262 IWizardPage currentPage
= container
.getCurrentPage();
263 return page
.equals(currentPage
);
269 * Wait for a view to close
272 * bot view for the view
273 * @return true if the view is closed, false if it's active.
275 public static ICondition
ViewIsClosed(final SWTBotView view
) {
276 return new SWTBotTestCondition() {
278 public boolean test() throws Exception
{
279 return (view
!= null) && (!view
.isActive());
285 * Wait till table cell has a given content.
288 * the table bot reference
290 * the content to check
292 * the row of the cell
294 * the column of the cell
295 * @return ICondition for verification
297 public static ICondition
isTableCellFilled(final SWTBotTable table
,
298 final String content
, final int row
, final int column
) {
299 return new SWTBotTestCondition() {
301 public boolean test() throws Exception
{
303 String cell
= table
.cell(row
, column
);
307 return cell
.contains(content
);
308 } catch (Exception e
) {
314 public String
getFailureMessage() {
315 String cell
= table
.cell(row
, column
);
317 return NLS
.bind("Cell absent, expected: {0}", content
);
319 return NLS
.bind("Cell content: {0} expected: {1}", cell
, content
);
325 * Condition to check if a tracing project element has a child with the
326 * specified name. A project element label may have a count suffix in the
329 public static class ProjectElementHasChild
extends DefaultCondition
{
331 private final SWTBotTreeItem fParentItem
;
332 private final String fName
;
333 private final String fRegex
;
334 private SWTBotTreeItem fItem
= null;
342 * the child name to look for
344 public ProjectElementHasChild(final SWTBotTreeItem parentItem
, final String name
) {
345 fParentItem
= parentItem
;
347 /* Project element labels may have count suffix */
348 fRegex
= Pattern
.quote(name
) + "(\\s\\[(\\d)+\\])?";
352 public boolean test() throws Exception
{
353 fParentItem
.expand();
354 for (SWTBotTreeItem item
: fParentItem
.getItems()) {
355 if (item
.getText().matches(fRegex
)) {
364 public String
getFailureMessage() {
365 return NLS
.bind("No child of {0} found with name {1}", fParentItem
.getText(), fName
);
369 * Returns the matching child item if the condition returned true.
371 * @return the matching item
373 public SWTBotTreeItem
getItem() {
379 * Condition to check if an editor with the specified title is opened.
385 * @return ICondition for verification
387 public static ICondition
isEditorOpened(final SWTWorkbenchBot bot
, final String title
) {
388 return new SWTBotTestCondition() {
390 public boolean test() throws Exception
{
391 Matcher
<IEditorReference
> withPartName
= withPartName(title
);
392 return !bot
.editors(withPartName
).isEmpty();
398 * Condition to check if the selection range equals the specified range.
401 * the selection range
402 * @return ICondition for verification
404 public static ICondition
selectionRange(final TmfTimeRange range
) {
405 return new SWTBotTestCondition() {
407 public boolean test() throws Exception
{
408 return TmfTraceManager
.getInstance().getCurrentTraceContext().getSelectionRange().equals(range
);
412 public String
getFailureMessage() {
413 return NLS
.bind("Selection range: {0} expected: {1}",
414 TmfTraceManager
.getInstance().getCurrentTraceContext().getSelectionRange(), range
);
420 * Condition to check if the window range equals the specified range.
424 * @return ICondition for verification
426 public static ICondition
windowRange(final TmfTimeRange range
) {
427 return new SWTBotTestCondition() {
429 public boolean test() throws Exception
{
430 return TmfTraceManager
.getInstance().getCurrentTraceContext().getWindowRange().equals(range
);
434 public String
getFailureMessage() {
435 return NLS
.bind("Window range: {0} expected: {1}",
436 TmfTraceManager
.getInstance().getCurrentTraceContext().getWindowRange(), range
);
442 * Condition to check if the selection contains the specified text at the
443 * specified column. The text is checked in any item of the tree selection.
451 * @return ICondition for verification
453 public static ICondition
treeSelectionContains(final SWTBotTree tree
, final int column
, final String text
) {
454 return new SWTBotTestCondition() {
456 public boolean test() throws Exception
{
457 TableCollection selection
= tree
.selection();
458 for (int row
= 0; row
< selection
.rowCount(); row
++) {
459 if (selection
.get(row
, column
).equals(text
)) {
467 public String
getFailureMessage() {
468 return NLS
.bind("Tree selection [0,{0}]: {1} expected: {2}",
469 new Object
[] { column
, tree
.selection().get(0, column
), text
});
474 private static class EventsTableSelectionCondition
extends DefaultCondition
{
475 private long fSelectionTime
;
476 private SWTWorkbenchBot fBot
;
477 private long fCurValue
;
479 private EventsTableSelectionCondition(SWTWorkbenchBot bot
, long selectionTime
) {
481 fSelectionTime
= selectionTime
;
485 public boolean test() throws Exception
{
486 StructuredSelection eventsTableSelection
= getEventsTableSelection();
487 if (eventsTableSelection
.isEmpty()) {
490 fCurValue
= ((ITmfEvent
) eventsTableSelection
.getFirstElement()).getTimestamp().getValue();
491 return fCurValue
== fSelectionTime
;
495 public String
getFailureMessage() {
496 return "The selection in the table was not an event with timestamp " + fSelectionTime
+ ". Actual is " + fCurValue
;
499 private StructuredSelection
getEventsTableSelection() {
500 return UIThreadRunnable
.syncExec(new Result
<StructuredSelection
>() {
503 public StructuredSelection
run() {
504 SWTBotEditor eventsEditor
= SWTBotUtils
.activeEventsEditor(fBot
);
505 TmfEventsEditor part
= (TmfEventsEditor
) eventsEditor
.getReference().getPart(false);
506 StructuredSelection selection
= (StructuredSelection
) part
.getSelection();
514 * Wait until the events table selection matches the specified time stamp.
519 * @param selectionTime
521 * @return ICondition for verification
523 public static ICondition
selectionInEventsTable(final SWTWorkbenchBot bot
, long selectionTime
) {
524 return new EventsTableSelectionCondition(bot
, selectionTime
);
527 private static class TimeGraphIsReadyCondition
extends DefaultCondition
{
529 private @NonNull TmfTimeRange fSelectionRange
;
530 private @NonNull ITmfTimestamp fVisibleTime
;
531 private AbstractTimeGraphView fView
;
532 private String fFailureMessage
;
534 private TimeGraphIsReadyCondition(AbstractTimeGraphView view
, @NonNull TmfTimeRange selectionRange
, @NonNull ITmfTimestamp visibleTime
) {
536 fSelectionRange
= selectionRange
;
537 fVisibleTime
= visibleTime
;
541 public boolean test() throws Exception
{
542 ICondition selectionRangeCondition
= ConditionHelpers
.selectionRange(fSelectionRange
);
543 if (!selectionRangeCondition
.test()) {
544 fFailureMessage
= selectionRangeCondition
.getFailureMessage();
547 @NonNull TmfTimeRange curWindowRange
= TmfTraceManager
.getInstance().getCurrentTraceContext().getWindowRange();
548 if (!curWindowRange
.contains(fVisibleTime
)) {
549 fFailureMessage
= "Current window range " + curWindowRange
+ " does not contain " + fVisibleTime
;
553 if (fView
.isDirty()) {
554 fFailureMessage
= "Time graph is dirty";
562 public String
getFailureMessage() {
563 return fFailureMessage
;
569 * Wait until the Time Graph view is ready. The Time Graph view is
570 * considered ready if the selectionRange is selected, the visibleTime is
571 * visible and the view is not dirty (its model is done updating).
574 * the time graph view
575 * @param selectionRange
576 * the selection that the time graph should have
578 * the visible time that the time graph should have
579 * @return ICondition for verification
581 public static ICondition
timeGraphIsReadyCondition(AbstractTimeGraphView view
, @NonNull TmfTimeRange selectionRange
, @NonNull ITmfTimestamp visibleTime
) {
582 return new TimeGraphIsReadyCondition(view
, selectionRange
, visibleTime
);
585 private static class XYViewerIsReadyCondition
extends DefaultCondition
{
587 private TmfXYChartViewer fViewer
;
588 private String fFailureMessage
;
590 private XYViewerIsReadyCondition(TmfXYChartViewer view
) {
595 public boolean test() throws Exception
{
597 if (fViewer
.isDirty()) {
598 fFailureMessage
= "Time graph is dirty";
605 public String
getFailureMessage() {
606 return fFailureMessage
;
612 * Wait until the XY chart viewer is ready. The XY chart viewer is
613 * considered ready when it is not updating.
616 * the XY chart viewer
617 * @return ICondition for verification
619 public static ICondition
xyViewerIsReadyCondition(TmfXYChartViewer viewer
) {
620 return new XYViewerIsReadyCondition(viewer
);
623 private static class NumberOfEventsCondition
extends DefaultCondition
{
625 private ITmfTrace fTrace
;
626 private long fNbEvents
;
628 private NumberOfEventsCondition(ITmfTrace trace
, long nbEvents
) {
630 fNbEvents
= nbEvents
;
634 public boolean test() throws Exception
{
635 return fTrace
.getNbEvents() == fNbEvents
;
639 public String
getFailureMessage() {
640 return fTrace
.getName() + " did not contain the expected number of " + fNbEvents
+ " events. Current: " + fTrace
.getNbEvents();
645 * Wait until the trace contains the specified number of events.
650 * the number of events to wait for
651 * @return ICondition for verification
653 public static ICondition
numberOfEventsInTrace(ITmfTrace trace
, long nbEvents
) {
654 return new NumberOfEventsCondition(trace
, nbEvents
);
658 * Wait until there is an active events editor. A title can also be
659 * specified to wait until a more specific editor.
661 public static final class ActiveEventsEditor
extends DefaultCondition
{
662 private final SWTWorkbenchBot fWorkbenchBot
;
663 private SWTBotEditor fEditor
;
664 private String fEditorTitle
;
667 * Wait until there is an active events editor.
669 * @param workbenchBot
672 * If specified, wait until an active events editor with this
673 * title. Can be set to null.
675 public ActiveEventsEditor(SWTWorkbenchBot workbenchBot
, String editorTitle
) {
676 fWorkbenchBot
= workbenchBot
;
677 fEditorTitle
= editorTitle
;
681 public boolean test() throws Exception
{
682 List
<SWTBotEditor
> editors
= fWorkbenchBot
.editors(WidgetMatcherFactory
.withPartId(TmfEventsEditor
.ID
));
683 for (SWTBotEditor e
: editors
) {
684 // We are careful not to call e.getWidget() here because it actually forces the editor to show.
685 // This is especially a problem for cases where we wait until there is no active editor.
687 if (fEditorTitle
!= null && !fEditorTitle
.equals(e
.getTitle())) {
698 public String
getFailureMessage() {
699 String editorMessage
= fEditorTitle
!= null ?
" " + fEditorTitle
: "";
700 return "Active events editor" + editorMessage
+ " not found";
704 * @return The active editor found
706 public SWTBotEditor
getActiveEditor() {
711 private static class NumberOfSeries
extends DefaultCondition
{
712 private String fFailureMessage
;
713 private Chart fChart
;
714 private final int fNumberOfSeries
;
716 public NumberOfSeries(Chart chart
, int numberOfSeries
) {
718 fNumberOfSeries
= numberOfSeries
;
722 public boolean test() throws Exception
{
723 int length
= fChart
.getSeriesSet().getSeries().length
;
724 if (length
!= fNumberOfSeries
){
725 fFailureMessage
= "Chart did not contain the expected number series. Actual " + length
+ ", expected " + fNumberOfSeries
;
733 public String
getFailureMessage() {
734 return fFailureMessage
;
739 * Wait until the chart has the specified number of series.
743 * @param numberOfSeries
744 * the number of expected series
746 * @return ICondition for verification
748 public static ICondition
numberOfSeries(Chart chart
, int numberOfSeries
) {
749 return new NumberOfSeries(chart
, numberOfSeries
);
753 * Condition to check if the tree item has children
756 * the tree item that should have children
757 * @return ICondition for verification
759 public static ICondition
treeItemHasChildren(SWTBotTreeItem treeItem
) {
760 return new TreeItemHasChildren(treeItem
);
763 private static final class TreeItemHasChildren
extends DefaultCondition
{
764 private SWTBotTreeItem fTreeItem
;
766 public TreeItemHasChildren(SWTBotTreeItem treeItem
) {
767 fTreeItem
= treeItem
;
771 public boolean test() throws Exception
{
772 return fTreeItem
.getItems().length
> 0;
776 public String
getFailureMessage() {
777 return NLS
.bind("No child of tree item {0} found.", new String
[] { fTreeItem
.toString() });