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