5559e6db044c5d1b1f2a0d949d8d563d245e493c
[deliverable/tracecompass.git] / tmf / org.eclipse.tracecompass.tmf.ui.swtbot.tests / shared / org / eclipse / tracecompass / tmf / ui / swtbot / tests / shared / ConditionHelpers.java
1 /*******************************************************************************
2 * Copyright (c) 2013, 2016 Ericsson
3 *
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
8 *
9 * Contributors:
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 *******************************************************************************/
14
15 package org.eclipse.tracecompass.tmf.ui.swtbot.tests.shared;
16
17 import static org.eclipse.swtbot.eclipse.finder.matchers.WidgetMatcherFactory.withPartName;
18
19 import java.util.Arrays;
20 import java.util.List;
21 import java.util.regex.Pattern;
22
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.views.timegraph.AbstractTimeGraphView;
49 import org.eclipse.ui.IEditorReference;
50 import org.hamcrest.Matcher;
51 import org.swtchart.Chart;
52
53 /**
54 * Is a tree node available
55 *
56 * @author Matthew Khouzam
57 */
58 public final class ConditionHelpers {
59
60 private ConditionHelpers() {}
61
62 /**
63 * Provide default implementations for some {@link ICondition} methods.
64 */
65 public abstract static class SWTBotTestCondition implements ICondition {
66
67 @Override
68 public abstract boolean test() throws Exception;
69
70 @Override
71 public final void init(SWTBot bot) {
72 }
73
74 @Override
75 public String getFailureMessage() {
76 return null;
77 }
78 }
79
80 /**
81 * Is a tree node available
82 *
83 * @param name
84 * the name of the node
85 * @param tree
86 * the parent tree
87 * @return true or false, it should swallow all exceptions
88 */
89 public static ICondition IsTreeNodeAvailable(final String name, final SWTBotTree tree) {
90 return new SWTBotTestCondition() {
91 @Override
92 public boolean test() throws Exception {
93 try {
94 final SWTBotTreeItem[] treeItems = tree.getAllItems();
95 for (SWTBotTreeItem ti : treeItems) {
96 final String text = ti.getText();
97 if (text.equals(name)) {
98 return true;
99 }
100 }
101 } catch (Exception e) {
102 }
103 return false;
104 }
105
106 @Override
107 public String getFailureMessage() {
108 return NLS.bind("No child of tree {0} found with text {1}. Child items: {2}",
109 new String[] { tree.toString(), name, Arrays.toString(tree.getAllItems()) });
110 }
111 };
112 }
113
114 /**
115 * Is a table item available
116 *
117 * @param name
118 * the name of the item
119 * @param table
120 * the parent table
121 * @return true or false, it should swallow all exceptions
122 */
123 public static ICondition isTableItemAvailable(final String name, final SWTBotTable table) {
124 return new SWTBotTestCondition() {
125 @Override
126 public boolean test() throws Exception {
127 try {
128 return table.containsItem(name);
129 } catch (Exception e) {
130 }
131 return false;
132 }
133
134 @Override
135 public String getFailureMessage() {
136 return NLS.bind("No child of table {0} found with text ''{1}''.", table, name);
137 }
138 };
139 }
140
141 /**
142 * Is the treeItem's node available
143 *
144 * @param name
145 * the name of the node
146 * @param treeItem
147 * the treeItem
148 * @return true or false, it should swallow all exceptions
149 */
150 public static ICondition IsTreeChildNodeAvailable(final String name, final SWTBotTreeItem treeItem) {
151 return new SWTBotTestCondition() {
152 @Override
153 public boolean test() throws Exception {
154 try {
155 return treeItem.getNode(name) != null;
156 } catch (Exception e) {
157 }
158 return false;
159 }
160
161 @Override
162 public String getFailureMessage() {
163 return NLS.bind("No child of tree item {0} found with text ''{1}''. Child items: {2}",
164 new String[] { treeItem.toString(), name, Arrays.toString(treeItem.getItems()) });
165 }
166 };
167 }
168
169 /**
170 * Is the treeItem's node removed
171 *
172 * @param length
173 * length of the node after removal
174 * @param treeItem
175 * the treeItem
176 * @return true or false, it should swallow all exceptions
177 */
178 public static ICondition isTreeChildNodeRemoved(final int length, final SWTBotTreeItem treeItem) {
179 return new SWTBotTestCondition() {
180 @Override
181 public boolean test() throws Exception {
182 try {
183 return treeItem.getNodes().size() == length;
184 } catch (Exception e) {
185 }
186 return false;
187 }
188
189 @Override
190 public String getFailureMessage() {
191 return NLS.bind("Child of tree item {0} found with text ''{1}'' not removed. Child items: {2}",
192 new String[] { treeItem.toString(), String.valueOf(length), Arrays.toString(treeItem.getItems()) });
193 }
194 };
195 }
196
197 /**
198 * Condition to check if the number of direct children of the
199 * provided tree item equals the specified count.
200 *
201 * @param treeItem
202 * the SWTBot tree item
203 * @param count
204 * the expected count
205 * @return ICondition for verification
206 */
207 public static ICondition treeItemCount(final SWTBotTreeItem treeItem, int count) {
208 return new SWTBotTestCondition() {
209 @Override
210 public boolean test() throws Exception {
211 return treeItem.rowCount() == count;
212 }
213
214 @Override
215 public String getFailureMessage() {
216 return NLS.bind("Tree item count: {0} expected: {1}",
217 treeItem.rowCount(), count);
218 }
219 };
220 }
221
222 /**
223 * Checks if the wizard's shell is null
224 *
225 * @param wizard
226 * the null
227 * @return false if either are null
228 */
229 public static ICondition isWizardReady(final Wizard wizard) {
230 return new SWTBotTestCondition() {
231 @Override
232 public boolean test() throws Exception {
233 if (wizard.getShell() == null) {
234 return false;
235 }
236 return true;
237 }
238 };
239 }
240
241 /**
242 * Is the wizard on the page you want?
243 *
244 * @param wizard
245 * wizard
246 * @param page
247 * the desired page
248 * @return true or false
249 */
250 public static ICondition isWizardOnPage(final Wizard wizard, final IWizardPage page) {
251 return new SWTBotTestCondition() {
252 @Override
253 public boolean test() throws Exception {
254 if (wizard == null || page == null) {
255 return false;
256 }
257 final IWizardContainer container = wizard.getContainer();
258 if (container == null) {
259 return false;
260 }
261 IWizardPage currentPage = container.getCurrentPage();
262 return page.equals(currentPage);
263 }
264 };
265 }
266
267 /**
268 * Wait for a view to close
269 *
270 * @param view
271 * bot view for the view
272 * @return true if the view is closed, false if it's active.
273 */
274 public static ICondition ViewIsClosed(final SWTBotView view) {
275 return new SWTBotTestCondition() {
276 @Override
277 public boolean test() throws Exception {
278 return (view != null) && (!view.isActive());
279 }
280 };
281 }
282
283 /**
284 * Wait till table cell has a given content.
285 *
286 * @param table
287 * the table bot reference
288 * @param content
289 * the content to check
290 * @param row
291 * the row of the cell
292 * @param column
293 * the column of the cell
294 * @return ICondition for verification
295 */
296 public static ICondition isTableCellFilled(final SWTBotTable table,
297 final String content, final int row, final int column) {
298 return new SWTBotTestCondition() {
299 @Override
300 public boolean test() throws Exception {
301 try {
302 String cell = table.cell(row, column);
303 if( cell == null ) {
304 return false;
305 }
306 return cell.contains(content);
307 } catch (Exception e) {
308 }
309 return false;
310 }
311 };
312 }
313
314 /**
315 * Condition to check if a tracing project element has a child with the
316 * specified name. A project element label may have a count suffix in the
317 * format ' [n]'.
318 */
319 public static class ProjectElementHasChild extends DefaultCondition {
320
321 private final SWTBotTreeItem fParentItem;
322 private final String fName;
323 private final String fRegex;
324 private SWTBotTreeItem fItem = null;
325
326 /**
327 * Constructor.
328 *
329 * @param parentItem
330 * the parent item
331 * @param name
332 * the child name to look for
333 */
334 public ProjectElementHasChild(final SWTBotTreeItem parentItem, final String name) {
335 fParentItem = parentItem;
336 fName = name;
337 /* Project element labels may have count suffix */
338 fRegex = Pattern.quote(name) + "(\\s\\[(\\d)+\\])?";
339 }
340
341 @Override
342 public boolean test() throws Exception {
343 fParentItem.expand();
344 for (SWTBotTreeItem item : fParentItem.getItems()) {
345 if (item.getText().matches(fRegex)) {
346 fItem = item;
347 return true;
348 }
349 }
350 return false;
351 }
352
353 @Override
354 public String getFailureMessage() {
355 return NLS.bind("No child of {0} found with name {1}", fParentItem.getText(), fName);
356 }
357
358 /**
359 * Returns the matching child item if the condition returned true.
360 *
361 * @return the matching item
362 */
363 public SWTBotTreeItem getItem() {
364 return fItem;
365 }
366 }
367
368 /**
369 * Condition to check if an editor with the specified title is opened.
370 *
371 * @param bot
372 * a workbench bot
373 * @param title
374 * the editor title
375 * @return ICondition for verification
376 */
377 public static ICondition isEditorOpened(final SWTWorkbenchBot bot, final String title) {
378 return new SWTBotTestCondition() {
379 @Override
380 public boolean test() throws Exception {
381 Matcher<IEditorReference> withPartName = withPartName(title);
382 return !bot.editors(withPartName).isEmpty();
383 }
384 };
385 }
386
387 /**
388 * Condition to check if the selection range equals the specified range.
389 *
390 * @param range
391 * the selection range
392 * @return ICondition for verification
393 */
394 public static ICondition selectionRange(final TmfTimeRange range) {
395 return new SWTBotTestCondition() {
396 @Override
397 public boolean test() throws Exception {
398 return TmfTraceManager.getInstance().getCurrentTraceContext().getSelectionRange().equals(range);
399 }
400
401 @Override
402 public String getFailureMessage() {
403 return NLS.bind("Selection range: {0} expected: {1}",
404 TmfTraceManager.getInstance().getCurrentTraceContext().getSelectionRange(), range);
405 }
406 };
407 }
408
409 /**
410 * Condition to check if the window range equals the specified range.
411 *
412 * @param range
413 * the window range
414 * @return ICondition for verification
415 */
416 public static ICondition windowRange(final TmfTimeRange range) {
417 return new SWTBotTestCondition() {
418 @Override
419 public boolean test() throws Exception {
420 return TmfTraceManager.getInstance().getCurrentTraceContext().getWindowRange().equals(range);
421 }
422
423 @Override
424 public String getFailureMessage() {
425 return NLS.bind("Window range: {0} expected: {1}",
426 TmfTraceManager.getInstance().getCurrentTraceContext().getWindowRange(), range);
427 }
428 };
429 }
430
431 /**
432 * Condition to check if the selection contains the specified text at the
433 * specified column. The text is checked in any item of the tree selection.
434 *
435 * @param tree
436 * the SWTBot tree
437 * @param column
438 * the column index
439 * @param text
440 * the expected text
441 * @return ICondition for verification
442 */
443 public static ICondition treeSelectionContains(final SWTBotTree tree, final int column, final String text) {
444 return new SWTBotTestCondition() {
445 @Override
446 public boolean test() throws Exception {
447 TableCollection selection = tree.selection();
448 for (int row = 0; row < selection.rowCount(); row++) {
449 if (selection.get(row, column).equals(text)) {
450 return true;
451 }
452 }
453 return false;
454 }
455
456 @Override
457 public String getFailureMessage() {
458 return NLS.bind("Tree selection [0,{0}]: {1} expected: {2}",
459 new Object[] { column, tree.selection().get(0, column), text});
460 }
461 };
462 }
463
464 private static class EventsTableSelectionCondition extends DefaultCondition {
465 private long fSelectionTime;
466 private SWTWorkbenchBot fBot;
467 private long fCurValue;
468
469 private EventsTableSelectionCondition(SWTWorkbenchBot bot, long selectionTime) {
470 fBot = bot;
471 fSelectionTime = selectionTime;
472 }
473
474 @Override
475 public boolean test() throws Exception {
476 StructuredSelection eventsTableSelection = getEventsTableSelection();
477 if (eventsTableSelection.isEmpty()) {
478 return false;
479 }
480 fCurValue = ((ITmfEvent) eventsTableSelection.getFirstElement()).getTimestamp().getValue();
481 return fCurValue == fSelectionTime;
482 }
483
484 @Override
485 public String getFailureMessage() {
486 return "The selection in the table was not an event with timestamp " + fSelectionTime + ". Actual is " + fCurValue;
487 }
488
489 private StructuredSelection getEventsTableSelection() {
490 return UIThreadRunnable.syncExec(new Result<StructuredSelection>() {
491
492 @Override
493 public StructuredSelection run() {
494 SWTBotEditor eventsEditor = SWTBotUtils.activeEventsEditor(fBot);
495 TmfEventsEditor part = (TmfEventsEditor) eventsEditor.getReference().getPart(false);
496 StructuredSelection selection = (StructuredSelection) part.getSelection();
497 return selection;
498 }
499 });
500 }
501 }
502
503 /**
504 * Wait until the events table selection matches the specified time stamp.
505 *
506 * @param bot
507 * a workbench bot
508 *
509 * @param selectionTime
510 * the selection time
511 * @return ICondition for verification
512 */
513 public static ICondition selectionInEventsTable(final SWTWorkbenchBot bot, long selectionTime) {
514 return new EventsTableSelectionCondition(bot, selectionTime);
515 }
516
517 private static class TimeGraphIsReadyCondition extends DefaultCondition {
518
519 private @NonNull TmfTimeRange fSelectionRange;
520 private @NonNull ITmfTimestamp fVisibleTime;
521 private AbstractTimeGraphView fView;
522 private String fFailureMessage;
523
524 private TimeGraphIsReadyCondition(AbstractTimeGraphView view, @NonNull TmfTimeRange selectionRange, @NonNull ITmfTimestamp visibleTime) {
525 fView = view;
526 fSelectionRange = selectionRange;
527 fVisibleTime = visibleTime;
528 }
529
530 @Override
531 public boolean test() throws Exception {
532 ICondition selectionRangeCondition = ConditionHelpers.selectionRange(fSelectionRange);
533 if (!selectionRangeCondition.test()) {
534 fFailureMessage = selectionRangeCondition.getFailureMessage();
535 return false;
536 }
537 @NonNull TmfTimeRange curWindowRange = TmfTraceManager.getInstance().getCurrentTraceContext().getWindowRange();
538 if (!curWindowRange.contains(fVisibleTime)) {
539 fFailureMessage = "Current window range " + curWindowRange + " does not contain " + fVisibleTime;
540 return false;
541 }
542
543 if (fView.isDirty()) {
544 fFailureMessage = "Time graph is dirty";
545 return false;
546
547 }
548 return true;
549 }
550
551 @Override
552 public String getFailureMessage() {
553 return fFailureMessage;
554 }
555 }
556
557 /**
558 *
559 * Wait until the Time Graph view is ready. The Time Graph view is
560 * considered ready if the selectionRange is selected, the visibleTime is
561 * visible and the view is not dirty (its model is done updating).
562 *
563 * @param view
564 * the time graph view
565 * @param selectionRange
566 * the selection that the time graph should have
567 * @param visibleTime
568 * the visible time that the time graph should have
569 * @return ICondition for verification
570 */
571 public static ICondition timeGraphIsReadyCondition(AbstractTimeGraphView view, @NonNull TmfTimeRange selectionRange, @NonNull ITmfTimestamp visibleTime) {
572 return new TimeGraphIsReadyCondition(view, selectionRange, visibleTime);
573 }
574
575 private static class NumberOfEventsCondition extends DefaultCondition {
576
577 private ITmfTrace fTrace;
578 private long fNbEvents;
579
580 private NumberOfEventsCondition(ITmfTrace trace, long nbEvents) {
581 fTrace = trace;
582 fNbEvents = nbEvents;
583 }
584
585 @Override
586 public boolean test() throws Exception {
587 return fTrace.getNbEvents() == fNbEvents;
588 }
589
590 @Override
591 public String getFailureMessage() {
592 return fTrace.getName() + " did not contain the expected number of " + fNbEvents + " events. Current: " + fTrace.getNbEvents();
593 }
594 }
595
596 /**
597 * Wait until the trace contains the specified number of events.
598 *
599 * @param trace
600 * the trace
601 * @param nbEvents
602 * the number of events to wait for
603 * @return ICondition for verification
604 */
605 public static ICondition numberOfEventsInTrace(ITmfTrace trace, long nbEvents) {
606 return new NumberOfEventsCondition(trace, nbEvents);
607 }
608
609 /**
610 * Wait until there is an active events editor. A title can also be
611 * specified to wait until a more specific editor.
612 */
613 public static final class ActiveEventsEditor extends DefaultCondition {
614 private final SWTWorkbenchBot fWorkbenchBot;
615 private SWTBotEditor fEditor;
616 private String fEditorTitle;
617
618 /**
619 * Wait until there is an active events editor.
620 *
621 * @param workbenchBot
622 * a workbench bot
623 * @param editorTitle
624 * If specified, wait until an active events editor with this
625 * title. Can be set to null.
626 */
627 public ActiveEventsEditor(SWTWorkbenchBot workbenchBot, String editorTitle) {
628 fWorkbenchBot = workbenchBot;
629 fEditorTitle = editorTitle;
630 }
631
632 @Override
633 public boolean test() throws Exception {
634 List<SWTBotEditor> editors = fWorkbenchBot.editors(WidgetMatcherFactory.withPartId(TmfEventsEditor.ID));
635 for (SWTBotEditor e : editors) {
636 // We are careful not to call e.getWidget() here because it actually forces the editor to show.
637 // This is especially a problem for cases where we wait until there is no active editor.
638 if (e.isActive()) {
639 if (fEditorTitle != null && !fEditorTitle.equals(e.getTitle())) {
640 return false;
641 }
642 fEditor = e;
643 return true;
644 }
645 }
646 return false;
647 }
648
649 @Override
650 public String getFailureMessage() {
651 String editorMessage = fEditorTitle != null ? " " + fEditorTitle : "";
652 return "Active events editor" + editorMessage + " not found";
653 }
654
655 /**
656 * @return The active editor found
657 */
658 public SWTBotEditor getActiveEditor() {
659 return fEditor;
660 }
661 }
662
663 private static class NumberOfSeries extends DefaultCondition {
664 private String fFailureMessage;
665 private Chart fChart;
666 private final int fNumberOfSeries;
667
668 public NumberOfSeries(Chart chart, int numberOfSeries) {
669 fChart = chart;
670 fNumberOfSeries = numberOfSeries;
671 }
672
673 @Override
674 public boolean test() throws Exception {
675 int length = fChart.getSeriesSet().getSeries().length;
676 if (length != fNumberOfSeries){
677 fFailureMessage = "Chart did not contain the expected number series. Actual " + length + ", expected " + fNumberOfSeries;
678 return false;
679 }
680
681 return true;
682 }
683
684 @Override
685 public String getFailureMessage() {
686 return fFailureMessage;
687 }
688 }
689
690 /**
691 * Wait until the chart has the specified number of series.
692 *
693 * @param chart
694 * the chart
695 * @param numberOfSeries
696 * the number of expected series
697 *
698 * @return ICondition for verification
699 */
700 public static ICondition numberOfSeries(Chart chart, int numberOfSeries) {
701 return new NumberOfSeries(chart, numberOfSeries);
702 }
703
704 /**
705 * Condition to check if the tree item has children
706 *
707 * @param treeItem
708 * the tree item that should have children
709 * @return ICondition for verification
710 */
711 public static ICondition treeItemHasChildren(SWTBotTreeItem treeItem) {
712 return new TreeItemHasChildren(treeItem);
713 }
714
715 private static final class TreeItemHasChildren extends DefaultCondition {
716 private SWTBotTreeItem fTreeItem;
717
718 public TreeItemHasChildren(SWTBotTreeItem treeItem) {
719 fTreeItem = treeItem;
720 }
721
722 @Override
723 public boolean test() throws Exception {
724 return fTreeItem.getItems().length > 0;
725 }
726
727 @Override
728 public String getFailureMessage() {
729 return NLS.bind("No child of tree item {0} found.", new String[] { fTreeItem.toString() });
730 }
731 }
732 }
This page took 0.053762 seconds and 4 git commands to generate.