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