1 /*******************************************************************************
2 * Copyright (c) 2015 Ericsson
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
10 * Matthew Khouzam - Initial API and implementation
11 *******************************************************************************/
13 package org
.eclipse
.tracecompass
.tmf
.ui
.swtbot
.tests
.viewers
.events
;
15 import static org
.junit
.Assert
.assertEquals
;
16 import static org
.junit
.Assert
.assertNotNull
;
19 import java
.io
.IOException
;
20 import java
.util
.Arrays
;
22 import org
.apache
.log4j
.ConsoleAppender
;
23 import org
.apache
.log4j
.Logger
;
24 import org
.apache
.log4j
.SimpleLayout
;
25 import org
.eclipse
.swt
.SWT
;
26 import org
.eclipse
.swt
.custom
.SashForm
;
27 import org
.eclipse
.swt
.graphics
.Point
;
28 import org
.eclipse
.swt
.widgets
.Sash
;
29 import org
.eclipse
.swtbot
.eclipse
.finder
.SWTWorkbenchBot
;
30 import org
.eclipse
.swtbot
.eclipse
.finder
.widgets
.SWTBotView
;
31 import org
.eclipse
.swtbot
.swt
.finder
.finders
.UIThreadRunnable
;
32 import org
.eclipse
.swtbot
.swt
.finder
.junit
.SWTBotJunit4ClassRunner
;
33 import org
.eclipse
.swtbot
.swt
.finder
.results
.VoidResult
;
34 import org
.eclipse
.swtbot
.swt
.finder
.utils
.SWTBotPreferences
;
35 import org
.eclipse
.tracecompass
.tmf
.core
.io
.BufferedRandomAccessFile
;
36 import org
.eclipse
.tracecompass
.tmf
.ui
.project
.wizards
.NewTmfProjectWizard
;
37 import org
.eclipse
.tracecompass
.tmf
.ui
.swtbot
.tests
.shared
.SWTBotSash
;
38 import org
.eclipse
.tracecompass
.tmf
.ui
.swtbot
.tests
.shared
.SWTBotUtils
;
39 import org
.eclipse
.tracecompass
.tmf
.ui
.tests
.shared
.WaitUtils
;
40 import org
.eclipse
.tracecompass
.tmf
.ui
.views
.callstack
.CallStackView
;
41 import org
.eclipse
.tracecompass
.tmf
.ui
.views
.histogram
.HistogramView
;
42 import org
.eclipse
.tracecompass
.tmf
.ui
.views
.timechart
.TimeChartView
;
43 import org
.eclipse
.ui
.IFolderLayout
;
44 import org
.eclipse
.ui
.IPageLayout
;
45 import org
.eclipse
.ui
.IPerspectiveFactory
;
46 import org
.hamcrest
.BaseMatcher
;
47 import org
.hamcrest
.Description
;
48 import org
.junit
.After
;
49 import org
.junit
.AfterClass
;
50 import org
.junit
.Before
;
51 import org
.junit
.BeforeClass
;
52 import org
.junit
.Test
;
53 import org
.junit
.runner
.RunWith
;
56 * Test common time axis for views
58 * @author Matthew Khouzam
60 @RunWith(SWTBotJunit4ClassRunner
.class)
61 public class TmfAlignTimeAxisTest
{
64 * wait for throttler (2x the throttler time)
66 private static final int SYNC_DELAY
= 1000;
67 private static final String TRACE_START
= "<trace>";
68 private static final String EVENT_BEGIN
= "<event timestamp=\"";
69 private static final String EVENT_MIDDLE
= " \" name=\"event\"><field name=\"field\" value=\"";
70 private static final String EVENT_END
= "\" type=\"int\" />" + "</event>";
71 private static final String TRACE_END
= "</trace>";
73 private static final String PROJET_NAME
= "TestAxisAlignment";
74 private static final int NUM_EVENTS
= 100;
76 * Using a small ratio for the editor so that other views have enough space
77 * to be drawn, even when a low screen resolution is used.
79 private static final float EDITOR_AREA_RATIO
= 0.10f
;
81 /** The Log4j logger instance. */
82 private static final Logger fLogger
= Logger
.getRootLogger();
83 private static SWTWorkbenchBot fBot
;
85 private static String
makeEvent(int ts
, int val
) {
86 return EVENT_BEGIN
+ Integer
.toString(ts
) + EVENT_MIDDLE
+ Integer
.toString(val
) + EVENT_END
+ "\n";
89 private static File fLocation
;
90 private static final BaseMatcher
<Sash
> SASH_MATCHER
= new SashMatcher();
93 * Initialization, creates a temp trace
99 public static void init() throws IOException
{
100 SWTBotUtils
.initialize();
101 Thread
.currentThread().setName("SWTBot Thread"); // for the debugger
102 /* set up for swtbot */
103 SWTBotPreferences
.TIMEOUT
= 20000; /* 20 second timeout */
104 fLogger
.removeAllAppenders();
105 fLogger
.addAppender(new ConsoleAppender(new SimpleLayout()));
106 SWTWorkbenchBot bot
= new SWTWorkbenchBot();
108 SWTBotUtils
.closeView("welcome", bot
);
110 SWTBotUtils
.switchToTracingPerspective();
111 /* finish waiting for eclipse to load */
112 WaitUtils
.waitForJobs();
113 fLocation
= File
.createTempFile("sample", ".xml");
114 try (BufferedRandomAccessFile braf
= new BufferedRandomAccessFile(fLocation
, "rw")) {
115 braf
.writeBytes(TRACE_START
);
116 for (int i
= 0; i
< NUM_EVENTS
; i
++) {
117 braf
.writeBytes(makeEvent(i
* 100, i
% 4));
119 braf
.writeBytes(TRACE_END
);
121 SWTBotUtils
.createProject(PROJET_NAME
);
122 SWTBotUtils
.selectTracesFolder(bot
, PROJET_NAME
);
129 public static void cleanup() {
130 SWTBotUtils
.deleteProject(PROJET_NAME
, new SWTWorkbenchBot());
132 fLogger
.removeAllAppenders();
139 public void before() {
140 SWTBotUtils
.openTrace(PROJET_NAME
, fLocation
.getAbsolutePath(), "org.eclipse.linuxtools.tmf.core.tests.xmlstub");
147 public void after() {
148 SWTWorkbenchBot bot
= new SWTWorkbenchBot();
149 SWTBotUtils
.activeEventsEditor(bot
).close();
150 /* Switch back to Tracing perspective since several tests change the perspective */
151 SWTBotUtils
.switchToTracingPerspective();
152 SWTBotUtils
.closeSecondaryShells(fBot
);
156 * Test 3 views, none overlap, the histogram, the callstack and the
157 * timechart are aligned, the histogram is moved, callstack and timechart
161 public void testMoveHistogramCallstackFollows() {
162 fBot
= new SWTWorkbenchBot();
163 SWTBotUtils
.switchToPerspective(AlignPerspectiveFactory1
.ID
);
164 testOverlap(HistogramView
.ID
, CallStackView
.ID
);
168 * Test 3 views, none overlap, the histogram, the callstack and the
169 * timechart are aligned, the callstack is moved, histogram and timechart
173 public void testMoveCallstackHistogramFollows() {
174 fBot
= new SWTWorkbenchBot();
175 SWTBotUtils
.switchToPerspective(AlignPerspectiveFactory1
.ID
);
176 testOverlap(CallStackView
.ID
, HistogramView
.ID
);
180 * Test 3 views, overlap on the resizing view. The timechart and callstack
181 * are overlapping. Test that when the histogram moves, the timechart
182 * follows. Hidden views are not tested as their state does not matter until
186 public void testOverlappingHistogramMove() {
187 fBot
= new SWTWorkbenchBot();
188 SWTBotUtils
.switchToPerspective(AlignPerspectiveFactory2
.ID
);
189 testOverlap(HistogramView
.ID
, CallStackView
.ID
);
193 * Test 3 views, overlap on the resizing view. The timechart and callstack
194 * are overlapping. Test that when the timechart moves, the histogram
195 * follows. Hidden views are not tested as their state does not matter until
199 public void testOverlappingTimechartMove() {
200 fBot
= new SWTWorkbenchBot();
201 SWTBotUtils
.switchToPerspective(AlignPerspectiveFactory2
.ID
);
202 testOverlap(CallStackView
.ID
, HistogramView
.ID
);
206 * Test 3 views. No overlap. The callstack is not aligned with the
207 * histogram, the histogram is moved, we check that the callstack does NOT
211 public void testNotOverlappingHistogramMove() {
212 fBot
= new SWTWorkbenchBot();
213 testNonOverlap(HistogramView
.ID
, CallStackView
.ID
);
217 * Test 3 views. No overlap. The callstack is not aligned with the
218 * histogram, the callstack is moved, we check that the histogram does NOT
222 public void testNotOverlappingCallstackMove() {
223 fBot
= new SWTWorkbenchBot();
224 testNonOverlap(CallStackView
.ID
, HistogramView
.ID
);
227 private static void testNonOverlap(String vId1
, String vId2
) {
228 final int offset
= 100;
229 // switch to the proper perspective and wait for views to align
230 SWTBotUtils
.switchToPerspective(AlignPerspectiveFactory3
.ID
);
231 WaitUtils
.waitForJobs();
232 SWTBotUtils
.delay(SYNC_DELAY
);
234 SWTBotView masterView
= fBot
.viewById(vId1
);
235 SWTBotView slaveView
= fBot
.viewById(vId2
);
236 final Sash slaveSash
= slaveView
.bot().widget(SASH_MATCHER
, 0);
237 SWTBotSash slaveSashBot
= new SWTBotSash(slaveSash
, null);
238 Point before
= slaveSashBot
.getPoint();
239 // move master and wait for slaves to follow
240 drag(masterView
, offset
);
241 WaitUtils
.waitForJobs();
242 SWTBotUtils
.delay(SYNC_DELAY
);
243 // verify that the slave did not follow
244 assertEquals(before
, slaveSashBot
.getPoint());
245 // put everything back the way it was
246 drag(masterView
, -offset
);
247 SWTBotUtils
.delay(SYNC_DELAY
);
250 private static final class SashMatcher
extends BaseMatcher
<Sash
> {
252 public boolean matches(Object item
) {
253 return (item
instanceof Sash
);
257 public void describeTo(Description description
) {
261 private static final class SashFormMatcher
extends BaseMatcher
<SashForm
> {
263 public boolean matches(Object item
) {
264 return (item
instanceof SashForm
);
268 public void describeTo(Description description
) {
273 * Simulate a drag operation using "setWeights"
275 private static void drag(final SWTBotView view
, final int offset
) {
276 // this is the final sash form
277 final SashForm sashForm
= view
.bot().widget(new SashFormMatcher(), 0);
278 assertNotNull(sashForm
);
279 // resize widgets using sashform
280 UIThreadRunnable
.syncExec(new VoidResult() {
283 int[] originalWeights
= sashForm
.getWeights();
284 int[] newWeights
= Arrays
.copyOf(originalWeights
, originalWeights
.length
);
285 newWeights
[0] += offset
;
286 newWeights
[1] -= offset
;
287 sashForm
.setWeights(newWeights
);
288 sashForm
.getParent().layout();
291 // send update signals
292 UIThreadRunnable
.syncExec(new VoidResult() {
295 sashForm
.getChildren()[0].notifyListeners(SWT
.Resize
, null);
296 sashForm
.getChildren()[1].notifyListeners(SWT
.Resize
, null);
298 * This one is the most important, the previous two are added to
299 * be a good citizen, this event (selection) is the one that
300 * triggers an alignment
302 sashForm
.getChildren()[2].notifyListeners(SWT
.Selection
, null);
307 private static void testOverlap(String masterView
, String slaveView
) {
308 final int offset
= 100;
309 final int delta
= offset
/ 2;
310 // wait for the perspective switch to propagate alignments
311 WaitUtils
.waitForJobs();
312 SWTBotUtils
.delay(SYNC_DELAY
);
313 // select master and slave parts to observe
314 SWTBotView masterViewBot
= fBot
.viewById(masterView
);
315 final Sash masterSash
= masterViewBot
.bot().widget(SASH_MATCHER
, 0);
316 SWTBotSash masterSashBot
= new SWTBotSash(masterSash
, null);
318 SWTBotView slaveViewBot
= fBot
.viewById(slaveView
);
319 final Sash slaveSash
= slaveViewBot
.bot().widget(SASH_MATCHER
, 0);
320 SWTBotSash slaveSashBot
= new SWTBotSash(slaveSash
, null);
322 double masterOriginalSashX
= masterSashBot
.getPoint().x
;
323 // check that the views are already aligned
324 assertEquals("Approx align", masterOriginalSashX
, slaveSashBot
.getPoint().x
, delta
);
325 // move sash and wait for alignment
326 drag(masterViewBot
, offset
);
327 WaitUtils
.waitForJobs();
328 SWTBotUtils
.delay(SYNC_DELAY
);
330 double masterNewSashX
= masterSashBot
.getPoint().x
;
331 assertEquals("Approx align", masterNewSashX
, slaveSashBot
.getPoint().x
, delta
);
332 assertEquals(masterOriginalSashX
, masterNewSashX
- offset
, delta
);
333 // put things back the way they were
334 drag(masterViewBot
, -offset
);
335 SWTBotUtils
.delay(SYNC_DELAY
);
339 * Histogram, Callstack and timechart aligned but in different sites
341 public static class AlignPerspectiveFactory1
implements IPerspectiveFactory
{
343 /** The Perspective ID */
344 public static final String ID
= "org.eclipse.linuxtools.tmf.test.align.1"; //$NON-NLS-1$
347 public void createInitialLayout(IPageLayout layout
) {
348 if (layout
== null) {
353 layout
.setEditorAreaVisible(true);
356 layout
.setEditorAreaVisible(true);
358 // Create the top left folder
359 IFolderLayout topLeftFolder
= layout
.createFolder("topLeftFolder", IPageLayout
.LEFT
, 0.15f
, IPageLayout
.ID_EDITOR_AREA
); //$NON-NLS-1$
360 topLeftFolder
.addView(IPageLayout
.ID_PROJECT_EXPLORER
);
362 // Create the top right folder
363 IFolderLayout topRightFolder
= layout
.createFolder("topRightFolder", IPageLayout
.BOTTOM
, EDITOR_AREA_RATIO
, IPageLayout
.ID_EDITOR_AREA
); //$NON-NLS-1$
364 topRightFolder
.addView(HistogramView
.ID
);
366 // Create the middle right folder
367 IFolderLayout middleRightFolder
= layout
.createFolder("middleRightFolder", IPageLayout
.BOTTOM
, 0.50f
, "topRightFolder"); //$NON-NLS-1$
368 middleRightFolder
.addView(CallStackView
.ID
);
370 // Create the bottom right folder
371 IFolderLayout bottomRightFolder
= layout
.createFolder("bottomRightFolder", IPageLayout
.BOTTOM
, 0.65f
, "middleRightFolder"); //$NON-NLS-1$ //$NON-NLS-2$
372 bottomRightFolder
.addView(TimeChartView
.ID
);
374 // Populate menus, etc
375 layout
.addPerspectiveShortcut(ID
);
376 layout
.addNewWizardShortcut(NewTmfProjectWizard
.ID
);
382 * Timechart and Histogram share a site, all views aligned
384 public static class AlignPerspectiveFactory2
implements IPerspectiveFactory
{
386 /** The Perspective ID */
387 public static final String ID
= "org.eclipse.linuxtools.tmf.test.align.2"; //$NON-NLS-1$
390 public void createInitialLayout(IPageLayout layout
) {
391 if (layout
== null) {
396 layout
.setEditorAreaVisible(true);
399 layout
.setEditorAreaVisible(true);
401 // Create the top left folder
402 IFolderLayout topLeftFolder
= layout
.createFolder("topLeftFolder", IPageLayout
.LEFT
, 0.15f
, IPageLayout
.ID_EDITOR_AREA
); //$NON-NLS-1$
403 topLeftFolder
.addView(IPageLayout
.ID_PROJECT_EXPLORER
);
405 // Create the middle right folder
406 IFolderLayout middleRightFolder
= layout
.createFolder("middleRightFolder", IPageLayout
.BOTTOM
, EDITOR_AREA_RATIO
, IPageLayout
.ID_EDITOR_AREA
); //$NON-NLS-1$
407 middleRightFolder
.addView(HistogramView
.ID
);
408 middleRightFolder
.addView(TimeChartView
.ID
);
410 // Create the bottom right folder
411 IFolderLayout bottomRightFolder
= layout
.createFolder("bottomRightFolder", IPageLayout
.BOTTOM
, 0.65f
, "middleRightFolder"); //$NON-NLS-1$ //$NON-NLS-2$
412 bottomRightFolder
.addView(CallStackView
.ID
);
414 // Populate menus, etc
415 layout
.addPerspectiveShortcut(ID
);
416 layout
.addNewWizardShortcut(NewTmfProjectWizard
.ID
);
422 * Histogram and timechart aligned, callstack not aligned
424 public static class AlignPerspectiveFactory3
implements IPerspectiveFactory
{
426 /** The Perspective ID */
427 public static final String ID
= "org.eclipse.linuxtools.tmf.test.align.3"; //$NON-NLS-1$
430 public void createInitialLayout(IPageLayout layout
) {
431 if (layout
== null) {
436 layout
.setEditorAreaVisible(true);
439 layout
.setEditorAreaVisible(true);
441 // Create the top left folder
442 IFolderLayout topLeftFolder
= layout
.createFolder("topLeftFolder", IPageLayout
.LEFT
, 0.15f
, IPageLayout
.ID_EDITOR_AREA
); //$NON-NLS-1$
443 topLeftFolder
.addView(IPageLayout
.ID_PROJECT_EXPLORER
);
445 IFolderLayout bottomLeftFolder
= layout
.createFolder("bottomLeftFolder", IPageLayout
.BOTTOM
, 0.5f
, "topLeftFolder"); //$NON-NLS-1$
446 bottomLeftFolder
.addView(CallStackView
.ID
);
448 // Create the middle right folder
449 IFolderLayout middleRightFolder
= layout
.createFolder("middleRightFolder", IPageLayout
.BOTTOM
, EDITOR_AREA_RATIO
, IPageLayout
.ID_EDITOR_AREA
); //$NON-NLS-1$
450 middleRightFolder
.addView(HistogramView
.ID
);
452 // Create the bottom right folder
453 IFolderLayout bottomRightFolder
= layout
.createFolder("bottomRightFolder", IPageLayout
.BOTTOM
, 0.65f
, "middleRightFolder"); //$NON-NLS-1$ //$NON-NLS-2$
454 bottomRightFolder
.addView(TimeChartView
.ID
);
456 // Populate menus, etc
457 layout
.addPerspectiveShortcut(ID
);
458 layout
.addNewWizardShortcut(NewTmfProjectWizard
.ID
);