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
});
475 * Condition to check if the selection contains the specified text at the
476 * specified column. The text is checked in any item of the tree selection.
484 * @return ICondition for verification
486 public static ICondition
timeGraphSelectionContains(final SWTBotTimeGraph timeGraph
, final int column
, final String text
) {
487 return new SWTBotTestCondition() {
489 public boolean test() throws Exception
{
490 TableCollection selection
= timeGraph
.selection();
491 for (int row
= 0; row
< selection
.rowCount(); row
++) {
492 if (selection
.get(row
, column
).equals(text
)) {
500 public String
getFailureMessage() {
501 return NLS
.bind("Time graph selection [0,{0}]: {1} expected: {2}",
502 new Object
[] { column
, timeGraph
.selection().get(0, column
), text
});
507 private static class EventsTableSelectionCondition
extends DefaultCondition
{
508 private long fSelectionTime
;
509 private SWTWorkbenchBot fBot
;
510 private long fCurValue
;
512 private EventsTableSelectionCondition(SWTWorkbenchBot bot
, long selectionTime
) {
514 fSelectionTime
= selectionTime
;
518 public boolean test() throws Exception
{
519 StructuredSelection eventsTableSelection
= getEventsTableSelection();
520 if (eventsTableSelection
.isEmpty()) {
523 fCurValue
= ((ITmfEvent
) eventsTableSelection
.getFirstElement()).getTimestamp().getValue();
524 return fCurValue
== fSelectionTime
;
528 public String
getFailureMessage() {
529 return "The selection in the table was not an event with timestamp " + fSelectionTime
+ ". Actual is " + fCurValue
;
532 private StructuredSelection
getEventsTableSelection() {
533 return UIThreadRunnable
.syncExec(new Result
<StructuredSelection
>() {
536 public StructuredSelection
run() {
537 SWTBotEditor eventsEditor
= SWTBotUtils
.activeEventsEditor(fBot
);
538 TmfEventsEditor part
= (TmfEventsEditor
) eventsEditor
.getReference().getPart(false);
539 StructuredSelection selection
= (StructuredSelection
) part
.getSelection();
547 * Wait until the events table selection matches the specified time stamp.
552 * @param selectionTime
554 * @return ICondition for verification
556 public static ICondition
selectionInEventsTable(final SWTWorkbenchBot bot
, long selectionTime
) {
557 return new EventsTableSelectionCondition(bot
, selectionTime
);
560 private static class TimeGraphIsReadyCondition
extends DefaultCondition
{
562 private @NonNull TmfTimeRange fSelectionRange
;
563 private @NonNull ITmfTimestamp fVisibleTime
;
564 private AbstractTimeGraphView fView
;
565 private String fFailureMessage
;
567 private TimeGraphIsReadyCondition(AbstractTimeGraphView view
, @NonNull TmfTimeRange selectionRange
, @NonNull ITmfTimestamp visibleTime
) {
569 fSelectionRange
= selectionRange
;
570 fVisibleTime
= visibleTime
;
574 public boolean test() throws Exception
{
575 ICondition selectionRangeCondition
= ConditionHelpers
.selectionRange(fSelectionRange
);
576 if (!selectionRangeCondition
.test()) {
577 fFailureMessage
= selectionRangeCondition
.getFailureMessage();
580 @NonNull TmfTimeRange curWindowRange
= TmfTraceManager
.getInstance().getCurrentTraceContext().getWindowRange();
581 if (!curWindowRange
.contains(fVisibleTime
)) {
582 fFailureMessage
= "Current window range " + curWindowRange
+ " does not contain " + fVisibleTime
;
586 if (fView
.isDirty()) {
587 fFailureMessage
= "Time graph is dirty";
595 public String
getFailureMessage() {
596 return fFailureMessage
;
602 * Wait until the Time Graph view is ready. The Time Graph view is
603 * considered ready if the selectionRange is selected, the visibleTime is
604 * visible and the view is not dirty (its model is done updating).
607 * the time graph view
608 * @param selectionRange
609 * the selection that the time graph should have
611 * the visible time that the time graph should have
612 * @return ICondition for verification
614 public static ICondition
timeGraphIsReadyCondition(AbstractTimeGraphView view
, @NonNull TmfTimeRange selectionRange
, @NonNull ITmfTimestamp visibleTime
) {
615 return new TimeGraphIsReadyCondition(view
, selectionRange
, visibleTime
);
618 private static class XYViewerIsReadyCondition
extends DefaultCondition
{
620 private TmfXYChartViewer fViewer
;
621 private String fFailureMessage
;
623 private XYViewerIsReadyCondition(TmfXYChartViewer view
) {
628 public boolean test() throws Exception
{
630 if (fViewer
.isDirty()) {
631 fFailureMessage
= "Time graph is dirty";
638 public String
getFailureMessage() {
639 return fFailureMessage
;
645 * Wait until the XY chart viewer is ready. The XY chart viewer is
646 * considered ready when it is not updating.
649 * the XY chart viewer
650 * @return ICondition for verification
652 public static ICondition
xyViewerIsReadyCondition(TmfXYChartViewer viewer
) {
653 return new XYViewerIsReadyCondition(viewer
);
656 private static class NumberOfEventsCondition
extends DefaultCondition
{
658 private ITmfTrace fTrace
;
659 private long fNbEvents
;
661 private NumberOfEventsCondition(ITmfTrace trace
, long nbEvents
) {
663 fNbEvents
= nbEvents
;
667 public boolean test() throws Exception
{
668 return fTrace
.getNbEvents() == fNbEvents
;
672 public String
getFailureMessage() {
673 return fTrace
.getName() + " did not contain the expected number of " + fNbEvents
+ " events. Current: " + fTrace
.getNbEvents();
678 * Wait until the trace contains the specified number of events.
683 * the number of events to wait for
684 * @return ICondition for verification
686 public static ICondition
numberOfEventsInTrace(ITmfTrace trace
, long nbEvents
) {
687 return new NumberOfEventsCondition(trace
, nbEvents
);
691 * Wait until there is an active events editor. A title can also be
692 * specified to wait until a more specific editor.
694 public static final class ActiveEventsEditor
extends DefaultCondition
{
695 private final SWTWorkbenchBot fWorkbenchBot
;
696 private SWTBotEditor fEditor
;
697 private String fEditorTitle
;
700 * Wait until there is an active events editor.
702 * @param workbenchBot
705 * If specified, wait until an active events editor with this
706 * title. Can be set to null.
708 public ActiveEventsEditor(SWTWorkbenchBot workbenchBot
, String editorTitle
) {
709 fWorkbenchBot
= workbenchBot
;
710 fEditorTitle
= editorTitle
;
714 public boolean test() throws Exception
{
715 List
<SWTBotEditor
> editors
= fWorkbenchBot
.editors(WidgetMatcherFactory
.withPartId(TmfEventsEditor
.ID
));
716 for (SWTBotEditor e
: editors
) {
717 // We are careful not to call e.getWidget() here because it actually forces the editor to show.
718 // This is especially a problem for cases where we wait until there is no active editor.
720 if (fEditorTitle
!= null && !fEditorTitle
.equals(e
.getTitle())) {
731 public String
getFailureMessage() {
732 String editorMessage
= fEditorTitle
!= null ?
" " + fEditorTitle
: "";
733 return "Active events editor" + editorMessage
+ " not found";
737 * @return The active editor found
739 public SWTBotEditor
getActiveEditor() {
744 private static class NumberOfSeries
extends DefaultCondition
{
745 private String fFailureMessage
;
746 private Chart fChart
;
747 private final int fNumberOfSeries
;
749 public NumberOfSeries(Chart chart
, int numberOfSeries
) {
751 fNumberOfSeries
= numberOfSeries
;
755 public boolean test() throws Exception
{
756 int length
= fChart
.getSeriesSet().getSeries().length
;
757 if (length
!= fNumberOfSeries
){
758 fFailureMessage
= "Chart did not contain the expected number series. Actual " + length
+ ", expected " + fNumberOfSeries
;
766 public String
getFailureMessage() {
767 return fFailureMessage
;
772 * Wait until the chart has the specified number of series.
776 * @param numberOfSeries
777 * the number of expected series
779 * @return ICondition for verification
781 public static ICondition
numberOfSeries(Chart chart
, int numberOfSeries
) {
782 return new NumberOfSeries(chart
, numberOfSeries
);
786 * Condition to check if the tree item has children
789 * the tree item that should have children
790 * @return ICondition for verification
792 public static ICondition
treeItemHasChildren(SWTBotTreeItem treeItem
) {
793 return new TreeItemHasChildren(treeItem
);
796 private static final class TreeItemHasChildren
extends DefaultCondition
{
797 private SWTBotTreeItem fTreeItem
;
799 public TreeItemHasChildren(SWTBotTreeItem treeItem
) {
800 fTreeItem
= treeItem
;
804 public boolean test() throws Exception
{
805 return fTreeItem
.getItems().length
> 0;
809 public String
getFailureMessage() {
810 return NLS
.bind("No child of tree item {0} found.", new String
[] { fTreeItem
.toString() });