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