swtbot: Stabilize use of SWTBotUtils.maximizeTable()
[deliverable/tracecompass.git] / tmf / org.eclipse.tracecompass.tmf.ui.swtbot.tests / shared / org / eclipse / tracecompass / tmf / ui / swtbot / tests / shared / SWTBotUtils.java
index 07f5049c83c326795a31fe6d869a4ccd9ec364c9..3e0638adeccb254ed24315291d4048191106aebe 100644 (file)
@@ -17,20 +17,28 @@ import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
 import java.util.List;
+import java.util.TimeZone;
+import java.util.concurrent.atomic.AtomicBoolean;
 
+import org.eclipse.core.resources.IFolder;
 import org.eclipse.core.resources.IProject;
 import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IResourceVisitor;
 import org.eclipse.core.resources.ResourcesPlugin;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.NullProgressMonitor;
 import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.jdt.annotation.NonNull;
 import org.eclipse.jface.bindings.keys.IKeyLookup;
 import org.eclipse.jface.bindings.keys.KeyStroke;
 import org.eclipse.jface.bindings.keys.ParseException;
+import org.eclipse.swt.events.ControlAdapter;
+import org.eclipse.swt.events.ControlEvent;
 import org.eclipse.swt.graphics.Point;
 import org.eclipse.swt.graphics.Rectangle;
 import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
 import org.eclipse.swt.widgets.Table;
 import org.eclipse.swt.widgets.TableItem;
 import org.eclipse.swtbot.eclipse.finder.SWTWorkbenchBot;
@@ -41,7 +49,9 @@ import org.eclipse.swtbot.swt.finder.SWTBot;
 import org.eclipse.swtbot.swt.finder.finders.UIThreadRunnable;
 import org.eclipse.swtbot.swt.finder.results.Result;
 import org.eclipse.swtbot.swt.finder.results.VoidResult;
+import org.eclipse.swtbot.swt.finder.utils.SWTUtils;
 import org.eclipse.swtbot.swt.finder.waits.Conditions;
+import org.eclipse.swtbot.swt.finder.waits.DefaultCondition;
 import org.eclipse.swtbot.swt.finder.widgets.SWTBotButton;
 import org.eclipse.swtbot.swt.finder.widgets.SWTBotCheckBox;
 import org.eclipse.swtbot.swt.finder.widgets.SWTBotMenu;
@@ -49,9 +59,15 @@ import org.eclipse.swtbot.swt.finder.widgets.SWTBotShell;
 import org.eclipse.swtbot.swt.finder.widgets.SWTBotTable;
 import org.eclipse.swtbot.swt.finder.widgets.SWTBotTree;
 import org.eclipse.swtbot.swt.finder.widgets.SWTBotTreeItem;
+import org.eclipse.swtbot.swt.finder.widgets.TimeoutException;
+import org.eclipse.tracecompass.internal.tmf.ui.project.operations.NewExperimentOperation;
 import org.eclipse.tracecompass.tmf.ui.editors.TmfEventsEditor;
+import org.eclipse.tracecompass.tmf.ui.project.model.TmfExperimentElement;
+import org.eclipse.tracecompass.tmf.ui.project.model.TmfExperimentFolder;
 import org.eclipse.tracecompass.tmf.ui.project.model.TmfOpenTraceHelper;
+import org.eclipse.tracecompass.tmf.ui.project.model.TmfProjectElement;
 import org.eclipse.tracecompass.tmf.ui.project.model.TmfProjectRegistry;
+import org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceElement;
 import org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceFolder;
 import org.eclipse.tracecompass.tmf.ui.project.model.TmfTracesFolder;
 import org.eclipse.tracecompass.tmf.ui.swtbot.tests.shared.ConditionHelpers.ProjectElementHasChild;
@@ -69,8 +85,13 @@ import org.hamcrest.Matcher;
  *
  * @author Matthew Khouzam
  */
+@SuppressWarnings("restriction")
 public final class SWTBotUtils {
 
+    private static final String WINDOW_MENU = "Window";
+    private static final String PREFERENCES_MENU_ITEM = "Preferences";
+    private static boolean fPrintedEnvironment = false;
+
     private SWTBotUtils() {
     }
 
@@ -175,6 +196,39 @@ public final class SWTBotUtils {
         deleteProject(projectName, true, bot);
     }
 
+    /**
+     * Creates an experiment
+     *
+     * @param bot
+     *            a given workbench bot
+     * @param projectName
+     *            the name of the project, creates the project if needed
+     * @param expName
+     *            the experiment name
+     */
+    public static void createExperiment(SWTWorkbenchBot bot, String projectName, final @NonNull String expName) {
+        IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName);
+        TmfProjectElement tmfProject = TmfProjectRegistry.getProject(project, true);
+        TmfExperimentFolder expFolder = tmfProject.getExperimentsFolder();
+        assertNotNull(expFolder);
+        NewExperimentOperation operation = new NewExperimentOperation(expFolder, expName);
+        operation.run(new NullProgressMonitor());
+
+        bot.waitUntil(new DefaultCondition() {
+            @Override
+            public boolean test() throws Exception {
+                TmfExperimentElement experiment = expFolder.getExperiment(expName);
+                return experiment != null;
+            }
+
+            @Override
+            public String getFailureMessage() {
+                return "Experiment (" + expName + ") couldn't be created";
+            }
+        });
+    }
+
+
     /**
      * Focus on the main window
      *
@@ -248,15 +302,89 @@ public final class SWTBotUtils {
         });
     }
 
+    /**
+     * Initialize the environment for SWTBot
+     */
+    public static void initialize() {
+        failIfUIThread();
+
+        SWTWorkbenchBot bot = new SWTWorkbenchBot();
+        UIThreadRunnable.syncExec(() -> {
+            printEnvironment();
+
+            // There seems to be problems on some system where the main shell is
+            // not in focus initially. This was seen using Xvfb and Xephyr on some occasions.
+            focusMainWindow(bot.shells());
+
+            Shell shell = bot.activeShell().widget;
+
+            // Only adjust shell if it appears to be the top-most
+            if (shell.getParent() == null) {
+                makeShellFullyVisible(shell);
+            }
+        });
+    }
+
+    private static void printEnvironment() {
+        if (fPrintedEnvironment) {
+            return;
+        }
+
+        // Print some information about the environment that could affect test outcome
+        Rectangle bounds = Display.getDefault().getBounds();
+        System.out.println("Display size: " + bounds.width + "x" + bounds.height);
+
+        String osVersion = System.getProperty("os.version");
+        if (osVersion != null) {
+            System.out.println("OS version=" + osVersion);
+        }
+        String gtkVersion = System.getProperty("org.eclipse.swt.internal.gtk.version");
+        if (gtkVersion != null) {
+            System.out.println("GTK version=" + gtkVersion);
+            String overlayScrollbar = System.getenv("LIBOVERLAY_SCROLLBAR");
+            if (overlayScrollbar != null) {
+                System.out.println("LIBOVERLAY_SCROLLBAR=" + overlayScrollbar);
+            }
+            String ubuntuMenuProxy = System.getenv("UBUNTU_MENUPROXY");
+            if (ubuntuMenuProxy != null) {
+                System.out.println("UBUNTU_MENUPROXY=" + ubuntuMenuProxy);
+            }
+        }
+
+        System.out.println("Time zone: " + TimeZone.getDefault().getDisplayName());
+
+        fPrintedEnvironment = true;
+    }
+
     /**
      * If the test is running in the UI thread then fail
      */
-    public static void failIfUIThread() {
+    private static void failIfUIThread() {
         if (Display.getCurrent() != null && Display.getCurrent().getThread() == Thread.currentThread()) {
             fail("SWTBot test needs to run in a non-UI thread. Make sure that \"Run in UI thread\" is unchecked in your launch configuration or"
                     + " that useUIThread is set to false in the pom.xml");
         }
+    }
 
+    /**
+     * Try to make the shell fully visible in the display. If the shell cannot
+     * fit the display, it will be positioned so that top-left corner is at
+     * <code>(0, 0)</code> in display-relative coordinates.
+     *
+     * @param shell
+     *            the shell to make fully visible
+     */
+    private static void makeShellFullyVisible(Shell shell) {
+        Rectangle displayBounds = shell.getDisplay().getBounds();
+        Point absCoord = shell.toDisplay(0, 0);
+        Point shellSize = shell.getSize();
+
+        Point newLocation = new Point(absCoord.x, absCoord.y);
+        newLocation.x = Math.max(0, Math.min(absCoord.x, displayBounds.width - shellSize.x));
+        newLocation.y = Math.max(0, Math.min(absCoord.y, displayBounds.height - shellSize.y));
+        if (!newLocation.equals(absCoord)) {
+            shell.setLocation(newLocation);
+        }
     }
 
     /**
@@ -411,6 +539,101 @@ public final class SWTBotUtils {
         return tracesFolderItem;
     }
 
+    /**
+     * Clear the traces folder
+     *
+     * @param bot
+     *            a given workbench bot
+     * @param projectName
+     *            the name of the project (needs to exist)
+     */
+    public static void clearTracesFolder(SWTWorkbenchBot bot, String projectName) {
+        IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName);
+        TmfProjectElement tmfProject = TmfProjectRegistry.getProject(project, false);
+        TmfTraceFolder tracesFolder = tmfProject.getTracesFolder();
+        try {
+            for (TmfTraceElement traceElement : tracesFolder.getTraces()) {
+                traceElement.delete(null);
+            }
+
+            final IFolder resource = tracesFolder.getResource();
+            resource.accept(new IResourceVisitor() {
+                @Override
+                public boolean visit(IResource visitedResource) throws CoreException {
+                    if (visitedResource != resource) {
+                        visitedResource.delete(true, null);
+                    }
+                    return true;
+                }
+            }, IResource.DEPTH_ONE, 0);
+        } catch (CoreException e) {
+            fail(e.getMessage());
+        }
+
+        bot.waitUntil(new DefaultCondition() {
+            private int fTraceNb = 0;
+
+            @Override
+            public boolean test() throws Exception {
+                List<TmfTraceElement> traces = tracesFolder.getTraces();
+                fTraceNb = traces.size();
+                return fTraceNb == 0;
+            }
+
+            @Override
+            public String getFailureMessage() {
+                return "Traces Folder not empty (" + fTraceNb + ")";
+            }
+        });
+    }
+
+    /**
+     * Clear the experiment folder
+     *
+     * @param bot
+     *            a given workbench bot
+     * @param projectName
+     *            the name of the project (needs to exist)
+     */
+    public static void clearExperimentFolder(SWTWorkbenchBot bot, String projectName) {
+        IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName);
+        TmfProjectElement tmfProject = TmfProjectRegistry.getProject(project, false);
+        TmfExperimentFolder expFolder = tmfProject.getExperimentsFolder();
+        expFolder.getExperiments().forEach(experiment -> {
+            IResource resource = experiment.getResource();
+            try {
+                // Close the experiment if open
+                experiment.closeEditors();
+
+                IPath path = resource.getLocation();
+                if (path != null) {
+                    // Delete supplementary files
+                    experiment.deleteSupplementaryFolder();
+                }
+                // Finally, delete the experiment
+                resource.delete(true, null);
+            } catch (CoreException e) {
+                fail(e.getMessage());
+            }
+        });
+
+        bot.waitUntil(new DefaultCondition() {
+            private int fExperimentNb = 0;
+
+            @Override
+            public boolean test() throws Exception {
+                List<TmfExperimentElement> experiments = expFolder.getExperiments();
+                fExperimentNb = experiments.size();
+                return fExperimentNb == 0;
+            }
+
+            @Override
+            public String getFailureMessage() {
+                return "Experiment Folder not empty (" + fExperimentNb + ")";
+            }
+        });
+    }
+
     /**
      * Select the project in Project Explorer
      *
@@ -459,11 +682,35 @@ public final class SWTBotUtils {
      *            the {@link SWTBotTable} table
      */
     public static void maximizeTable(SWTBotTable tableBot) {
+        final AtomicBoolean controlResized = new AtomicBoolean();
+        UIThreadRunnable.syncExec(new VoidResult() {
+            @Override
+            public void run() {
+                tableBot.widget.addControlListener(new ControlAdapter() {
+                    @Override
+                    public void controlResized(ControlEvent e) {
+                        tableBot.widget.removeControlListener(this);
+                        controlResized.set(true);
+                    }
+                });
+            }
+        });
         try {
             tableBot.pressShortcut(KeyStroke.getInstance(IKeyLookup.CTRL_NAME + "+"), KeyStroke.getInstance("M"));
         } catch (ParseException e) {
             fail();
         }
+        new SWTBot().waitUntil(new DefaultCondition() {
+            @Override
+            public boolean test() throws Exception {
+                return controlResized.get();
+            }
+
+            @Override
+            public String getFailureMessage() {
+                return "Control was not resized";
+            }
+        });
     }
 
     /**
@@ -514,11 +761,75 @@ public final class SWTBotUtils {
             currentNode.expand();
 
             String nodeName = nodeNames[i];
-            bot.waitUntil(ConditionHelpers.IsTreeChildNodeAvailable(nodeName, currentNode));
+            try {
+                bot.waitUntil(ConditionHelpers.IsTreeChildNodeAvailable(nodeName, currentNode));
+            } catch (TimeoutException e) {
+                //FIXME: Sometimes in a JFace TreeViewer, it expands to nothing. Need to find out why.
+                currentNode.collapse();
+                currentNode.expand();
+                bot.waitUntil(ConditionHelpers.IsTreeChildNodeAvailable(nodeName, currentNode));
+            }
+
             SWTBotTreeItem newNode = currentNode.getNode(nodeName);
             currentNode = newNode;
         }
 
         return currentNode;
     }
+
+    /**
+     * Get the active events editor. Note that this will wait until such editor
+     * is available.
+     *
+     * @param workbenchBot
+     *            a given workbench bot
+     * @return the active events editor
+     */
+    public static SWTBotEditor activeEventsEditor(final SWTWorkbenchBot workbenchBot) {
+        final SWTBotEditor editor[] = new SWTBotEditor[1];
+        workbenchBot.waitUntil(new DefaultCondition() {
+            @Override
+            public boolean test() throws Exception {
+                List<SWTBotEditor> editors = workbenchBot.editors(WidgetMatcherFactory.withPartId(TmfEventsEditor.ID));
+                for (SWTBotEditor e : editors) {
+                    if (e.isActive() && !e.getWidget().isDisposed()) {
+                        editor[0] = e;
+                        return true;
+                    }
+                }
+                return false;
+            }
+
+            @Override
+            public String getFailureMessage() {
+                return "Active events editor not found";
+            }
+        });
+        return editor[0];
+    }
+
+    /**
+     * Open the preferences dialog and return the corresponding shell.
+     *
+     * @param bot
+     *            a given workbench bot
+     * @return the preferences shell
+     */
+    public static SWTBotShell openPreferences(SWTBot bot) {
+        if (SWTUtils.isMac()) {
+            // On Mac, the Preferences menu item is under the application name.
+            // For some reason, we can't access the application menu anymore so
+            // we use the keyboard shortcut.
+            try {
+                bot.activeShell().pressShortcut(KeyStroke.getInstance(IKeyLookup.COMMAND_NAME + "+"), KeyStroke.getInstance(","));
+            } catch (ParseException e) {
+                fail();
+            }
+        } else {
+            bot.menu(WINDOW_MENU).menu(PREFERENCES_MENU_ITEM).click();
+        }
+
+        bot.waitUntil(Conditions.shellIsActive(PREFERENCES_MENU_ITEM));
+        return bot.activeShell();
+    }
 }
This page took 0.030331 seconds and 5 git commands to generate.