| /******************************************************************************* |
| * Copyright (c) 2017, 2019 Ericsson |
| * |
| * All rights reserved. This program and the accompanying materials are |
| * made available under the terms of the Eclipse Public License 2.0 which |
| * accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| *******************************************************************************/ |
| |
| package org.eclipse.tracecompass.tmf.ui.swtbot.tests; |
| |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertNotNull; |
| import static org.junit.Assert.assertTrue; |
| import static org.junit.Assert.fail; |
| |
| import java.io.File; |
| import java.net.URI; |
| import java.net.URL; |
| import java.util.Arrays; |
| import java.util.LinkedHashMap; |
| import java.util.Map; |
| import java.util.Objects; |
| |
| import org.apache.log4j.ConsoleAppender; |
| import org.apache.log4j.Logger; |
| import org.apache.log4j.SimpleLayout; |
| import org.eclipse.core.runtime.FileLocator; |
| import org.eclipse.core.runtime.Path; |
| import org.eclipse.jdt.annotation.NonNull; |
| import org.eclipse.jdt.annotation.Nullable; |
| import org.eclipse.swt.graphics.RGB; |
| import org.eclipse.swtbot.eclipse.finder.SWTWorkbenchBot; |
| import org.eclipse.swtbot.eclipse.finder.widgets.SWTBotView; |
| import org.eclipse.swtbot.swt.finder.finders.UIThreadRunnable; |
| import org.eclipse.swtbot.swt.finder.junit.SWTBotJunit4ClassRunner; |
| import org.eclipse.swtbot.swt.finder.matchers.WidgetOfType; |
| import org.eclipse.swtbot.swt.finder.utils.FileUtils; |
| import org.eclipse.swtbot.swt.finder.utils.SWTBotPreferences; |
| import org.eclipse.tracecompass.tmf.core.model.TmfCommonXAxisModel; |
| import org.eclipse.tracecompass.tmf.core.model.YModel; |
| import org.eclipse.tracecompass.tmf.core.model.xy.IYModel; |
| import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; |
| import org.eclipse.tracecompass.tmf.ui.swtbot.tests.shared.SWTBotUtils; |
| import org.eclipse.tracecompass.tmf.ui.tests.shared.WaitUtils; |
| import org.eclipse.tracecompass.tmf.ui.viewers.xycharts.TmfXYChartViewer; |
| import org.eclipse.tracecompass.tmf.ui.views.TmfChartView; |
| import org.eclipse.ui.IViewPart; |
| import org.hamcrest.Matcher; |
| import org.junit.After; |
| import org.junit.AfterClass; |
| import org.junit.Before; |
| import org.junit.BeforeClass; |
| import org.junit.runner.RunWith; |
| import org.osgi.framework.Bundle; |
| import org.osgi.framework.FrameworkUtil; |
| import org.swtchart.Chart; |
| import org.swtchart.IBarSeries; |
| import org.swtchart.ILineSeries; |
| import org.swtchart.ISeries; |
| import org.swtchart.LineStyle; |
| |
| import com.google.common.primitives.Doubles; |
| import com.google.common.primitives.Longs; |
| import com.google.gson.Gson; |
| import com.google.gson.GsonBuilder; |
| |
| /** |
| * SWTBot tests for viewers using XY data provider |
| * |
| * @author Yonni Chen |
| */ |
| @RunWith(SWTBotJunit4ClassRunner.class) |
| public abstract class XYDataProviderBaseTest { |
| |
| /** The workbench bot */ |
| protected static SWTWorkbenchBot fBot; |
| |
| /** The Log4j logger instance. */ |
| private static final Logger fLogger = Logger.getRootLogger(); |
| |
| /** Default project name */ |
| protected static final String TRACE_PROJECT_NAME = "test"; |
| |
| private static Gson fGson = new GsonBuilder().setPrettyPrinting().create(); |
| |
| private SWTBotView fViewBot; |
| private Chart fChart; |
| |
| /** |
| * Before Class |
| */ |
| @BeforeClass |
| public static void beforeClass() { |
| SWTBotUtils.initialize(); |
| |
| /* set up for swtbot */ |
| SWTBotPreferences.TIMEOUT = 20000; /* 20 second timeout */ |
| SWTBotPreferences.KEYBOARD_LAYOUT = "EN_US"; |
| fLogger.removeAllAppenders(); |
| fLogger.addAppender(new ConsoleAppender(new SimpleLayout(), ConsoleAppender.SYSTEM_OUT)); |
| fBot = new SWTWorkbenchBot(); |
| SWTBotUtils.closeView("welcome", fBot); |
| /* Create the trace project */ |
| SWTBotUtils.createProject(TRACE_PROJECT_NAME); |
| /* Finish waiting for eclipse to load */ |
| WaitUtils.waitForJobs(); |
| } |
| |
| /** |
| * Close the editor |
| */ |
| @AfterClass |
| public static void tearDown() { |
| SWTBotUtils.deleteProject(TRACE_PROJECT_NAME, fBot); |
| fLogger.removeAllAppenders(); |
| } |
| |
| /** |
| * Set up |
| */ |
| @Before |
| public void setup() { |
| SWTBotUtils.openView(getViewID()); |
| fViewBot = fBot.viewById(getViewID()); |
| fViewBot.show(); |
| |
| Matcher<Chart> widgetOfType = WidgetOfType.widgetOfType(Chart.class); |
| fChart = fViewBot.bot().widget(widgetOfType); |
| ITmfTrace trace = getTestTrace(); |
| |
| File file = new File(trace.getPath()); |
| SWTBotUtils.openTrace(TRACE_PROJECT_NAME, file.getAbsolutePath(), trace.getTraceTypeId()); |
| SWTBotUtils.activateEditor(fBot, trace.getName()); |
| } |
| |
| /** |
| * After Test |
| */ |
| @After |
| public void after() { |
| fBot.closeAllEditors(); |
| SWTBotUtils.closeSecondaryShells(fBot); |
| disposeTestTrace(); |
| } |
| |
| /** |
| * Get the full path to a test file from this class's bundle. |
| * |
| * @param bundlePath |
| * path from the bundle |
| * @return the absolute path |
| */ |
| private String getFullPath(String bundlePath) { |
| try { |
| Bundle bundle = FrameworkUtil.getBundle(this.getClass()); |
| URL location = FileLocator.find(bundle, new Path(bundlePath), null); |
| URI uri = FileLocator.toFileURL(location).toURI(); |
| return new File(uri).getAbsolutePath(); |
| } catch (Exception e) { |
| fail(e.toString()); |
| return null; |
| } |
| } |
| |
| /** |
| * Based on a SWT Chart, we check if data shown is valid with a JSON file. |
| * Comparison with the main series and other series if exists |
| * |
| * @param chart |
| * A SWT Chart |
| * @param otherSeries |
| * An array of other series name to check other than the main series |
| * @param expectedJson |
| * The path of the JSON file relative to this class's bundle |
| * @return True if the serialized chart data matches the JSON file content |
| */ |
| protected boolean isChartDataValid(final Chart chart, String expectedJson, String... otherSeries) { |
| /** |
| * FIXME : Once CQ for Jackson is approved, use deserialization instead of |
| * comparing strings |
| */ |
| String expected = FileUtils.read(getFullPath(expectedJson)); |
| TmfCommonXAxisModel model = extractModelFromChart(chart, otherSeries); |
| String current = fGson.toJson(model); |
| return expected.equals(current); |
| } |
| |
| /** |
| * From a SWT Chart, this method extract a {@link TmfCommonXAxisModel} that |
| * represents the chart. Since, we unfortunately have no mecanism to deserialize |
| * with GSON, we have to compare strings. So, once the model is extract from the |
| * Chart, we serialize it and compare with a string |
| * |
| * @param chart |
| * A SWT Chart |
| * @param otherSeries |
| * Name of other series to extract from Chart |
| * @return A {@link TmfCommonXAxisModel} |
| */ |
| protected TmfCommonXAxisModel extractModelFromChart(final Chart chart, String... otherSeries) { |
| String mainSeriesName = getMainSeriesName(); |
| ISeries mainSeries = chart.getSeriesSet().getSeries(mainSeriesName); |
| if (mainSeries == null) { |
| System.out.println("Main Series " + mainSeriesName + " not found in chart"); |
| return null; |
| } |
| |
| /* X and Y Values shown in chart */ |
| double[] xMain = mainSeries.getXSeries(); |
| double[] yMain = mainSeries.getYSeries(); |
| |
| Map<@NonNull String, @NonNull IYModel> yModels = new LinkedHashMap<>(); |
| yModels.put(mainSeriesName, new YModel(-1, mainSeriesName, Objects.requireNonNull(yMain))); |
| |
| for (String other : otherSeries) { |
| if (other != null) { |
| ISeries series = chart.getSeriesSet().getSeries(other); |
| if (series == null) { |
| System.out.println("Series " + other + " not found in chart"); |
| return null; |
| } |
| |
| /* X and Y Values shown in chart */ |
| double[] xSeries = series.getXSeries(); |
| double[] ySeries = series.getYSeries(); |
| |
| /* Series should have the same x axis values, not finished updating all series*/ |
| if (!Arrays.equals(xMain, xSeries)) { |
| System.out.println("Series don't currently have the same x axis values"); |
| return null; |
| } |
| yModels.put(other, new YModel(-1, other, Objects.requireNonNull(ySeries))); |
| } |
| } |
| |
| long[] x = Longs.toArray(Doubles.asList(xMain)); |
| assertNotNull(x); |
| return new TmfCommonXAxisModel(getTitle(), x, yModels); |
| } |
| |
| /** |
| * Gets the ChartViewer from a TmfChartView |
| * |
| * @param viewPart |
| * The IViewPart |
| * @return The ChartViewer from the IViewPart |
| */ |
| protected static TmfXYChartViewer getChartViewer(IViewPart viewPart) { |
| if (viewPart instanceof TmfChartView) { |
| return ((TmfChartView) viewPart).getChartViewer(); |
| } |
| return null; |
| } |
| |
| /** |
| * Verify the style of a series in the XY chart |
| * |
| * @param seriesName |
| * The name of the series |
| * @param expectedType |
| * Expected type of the series |
| * @param expectedColor |
| * Expected color of the series. If the color is arbitrary, a value |
| * of <code>null</code> will skip color check |
| * @param expectedLineStyle |
| * Expected line style of the series |
| * @param isArea |
| * Parameter should be true if expected series show area, false |
| * either |
| */ |
| protected void verifySeriesStyle(String seriesName, ISeries.SeriesType expectedType, @Nullable RGB expectedColor, LineStyle expectedLineStyle, boolean isArea) { |
| /* Make sure the UI update is complete */ |
| UIThreadRunnable.syncExec(() -> {}); |
| |
| ISeries series = fChart.getSeriesSet().getSeries(seriesName); |
| assertNotNull(series); |
| assertTrue(series.isVisible()); |
| |
| /* Color, type and style */ |
| assertEquals(expectedType, series.getType()); |
| |
| if (expectedType == ISeries.SeriesType.LINE) { |
| ILineSeries line = (ILineSeries) series; |
| if (expectedColor != null) { |
| assertEquals(expectedColor, line.getLineColor().getRGB()); |
| } |
| assertEquals(expectedLineStyle, line.getLineStyle()); |
| assertEquals(isArea, line.isAreaEnabled()); |
| } else if (expectedType == ISeries.SeriesType.BAR) { |
| IBarSeries bar = (IBarSeries) series; |
| if (expectedColor != null) { |
| assertEquals(expectedColor, bar.getBarColor().getRGB()); |
| } |
| assertTrue(bar.isStackEnabled()); |
| } |
| } |
| |
| /** |
| * Gets the SWT Chart |
| * |
| * @return The chart |
| * |
| */ |
| protected Chart getChart() { |
| return fChart; |
| } |
| |
| /** |
| * Gets the SWT Bot View |
| * |
| * @return The SWT Bot View |
| * |
| */ |
| protected SWTBotView getSWTBotView() { |
| return fViewBot; |
| } |
| |
| /** |
| * Gets the main series name of the XY |
| * |
| * @return The main series name |
| */ |
| protected abstract @NonNull String getMainSeriesName(); |
| |
| /** |
| * Gets the title of the XY |
| * |
| * @return The title |
| */ |
| protected abstract @NonNull String getTitle(); |
| |
| /** |
| * Gets the view ID |
| * |
| * @return The view ID |
| */ |
| protected abstract String getViewID(); |
| |
| /** |
| * Gets the trace on which the test will be run |
| * |
| * @return The trace |
| */ |
| protected abstract ITmfTrace getTestTrace(); |
| |
| /** |
| * Disposes the trace on which the test was run |
| */ |
| protected abstract void disposeTestTrace(); |
| } |