+package org.simantics.tests.modelled.ui;\r
+\r
+import java.util.List;\r
+import java.util.concurrent.Executors;\r
+\r
+import javax.annotation.PostConstruct;\r
+import javax.annotation.PreDestroy;\r
+\r
+import org.eclipse.e4.ui.di.Focus;\r
+import org.eclipse.jface.layout.TreeColumnLayout;\r
+import org.eclipse.jface.viewers.CellLabelProvider;\r
+import org.eclipse.jface.viewers.ColumnWeightData;\r
+import org.eclipse.jface.viewers.ISelection;\r
+import org.eclipse.jface.viewers.ISelectionChangedListener;\r
+import org.eclipse.jface.viewers.OwnerDrawLabelProvider;\r
+import org.eclipse.jface.viewers.SelectionChangedEvent;\r
+import org.eclipse.jface.viewers.TreeSelection;\r
+import org.eclipse.jface.viewers.TreeViewer;\r
+import org.eclipse.jface.viewers.TreeViewerColumn;\r
+import org.eclipse.jface.viewers.ViewerCell;\r
+import org.eclipse.swt.SWT;\r
+import org.eclipse.swt.custom.CTabFolder;\r
+import org.eclipse.swt.custom.CTabItem;\r
+import org.eclipse.swt.custom.SashForm;\r
+import org.eclipse.swt.custom.StyledText;\r
+import org.eclipse.swt.custom.ViewForm;\r
+import org.eclipse.swt.graphics.Point;\r
+import org.eclipse.swt.layout.FormAttachment;\r
+import org.eclipse.swt.layout.FormData;\r
+import org.eclipse.swt.layout.GridData;\r
+import org.eclipse.swt.layout.GridLayout;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.eclipse.swt.widgets.Event;\r
+import org.eclipse.swt.widgets.Layout;\r
+import org.eclipse.swt.widgets.Tree;\r
+import org.eclipse.swt.widgets.TreeColumn;\r
+import org.eclipse.ui.part.PageBook;\r
+import org.simantics.db.Resource;\r
+import org.simantics.scl.compiler.module.coverage.Coverage;\r
+\r
+public class STSTestRunnerView {\r
+ \r
+ public static final String ID = "org.simantics.tests.modelled.ui.stsTestRunnerView";\r
+\r
+ private Resource test;\r
+ private SashForm sashForm;\r
+ private PageBook viewerbook;\r
+ private TreeViewer treeViewer;\r
+// private ITreeContentProvider treeContentProvider;\r
+ private STSTestSuiteProvider provider;\r
+ private StyledText output;\r
+ private STSCounterPanel counterPanel;\r
+ private STSProgressBar progressBar;\r
+ private Composite counterComposite;\r
+\r
+ @PostConstruct\r
+ void createView(Composite parent) {\r
+ \r
+ GridLayout gridLayout= new GridLayout();\r
+ gridLayout.marginWidth= 0;\r
+ gridLayout.marginHeight= 0;\r
+ parent.setLayout(gridLayout);\r
+ \r
+ counterComposite= createProgressCountPanel(parent);\r
+ counterComposite.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL));\r
+ counterComposite.pack();\r
+ \r
+ SashForm sashForm = createSashForm(parent);\r
+ sashForm.setLayoutData(new GridData(GridData.FILL_BOTH));\r
+ }\r
+ \r
+ private SashForm createSashForm(Composite parent) {\r
+ sashForm = new SashForm(parent, SWT.VERTICAL);\r
+\r
+ ViewForm top = new ViewForm(sashForm, SWT.NONE);\r
+\r
+ Composite empty = new Composite(top, SWT.NONE);\r
+ empty.setLayout(new Layout() {\r
+ @Override\r
+ protected Point computeSize(Composite composite, int wHint, int hHint, boolean flushCache) {\r
+ return new Point(1, 1); // (0, 0) does not work with super-intelligent ViewForm\r
+ }\r
+ @Override\r
+ protected void layout(Composite composite, boolean flushCache) {\r
+ }\r
+ });\r
+ top.setTopLeft(empty); // makes ViewForm draw the horizontal separator line ...\r
+// fTestViewer= new TestViewer(top, fClipboard, this);\r
+ createTestViewers(top);\r
+ top.setContent(viewerbook);\r
+ treeViewer.setInput(test);\r
+\r
+ ViewForm bottom = new ViewForm(sashForm, SWT.NONE);\r
+\r
+ CTabFolder folder = new CTabFolder(bottom, SWT.BORDER);\r
+ folder.setLayoutData(new GridData(GridData.FILL_BOTH));\r
+ \r
+ CTabItem item1 = new CTabItem(folder, SWT.NONE);\r
+ item1.setText("Execution");\r
+// PageBook fViewerbook2= new PageBook(bottom, SWT.NULL);\r
+ // Upper\r
+ output = new StyledText(folder, SWT.MULTI | SWT.READ_ONLY | SWT.V_SCROLL | SWT.H_SCROLL);\r
+// output.setFont(textFont);\r
+ {\r
+ FormData formData = new FormData();\r
+ formData.top = new FormAttachment(0); \r
+// formData.bottom = new FormAttachment(sash);\r
+ formData.left = new FormAttachment(0);\r
+ formData.right = new FormAttachment(100);\r
+ output.setLayoutData(formData);\r
+ }\r
+ item1.setControl(output);\r
+// fViewerbook2.showPage(output);\r
+ bottom.setContent(folder);\r
+ folder.setSelection(0);\r
+\r
+ CTabItem item2 = new CTabItem(folder, SWT.NONE);\r
+ item2.setText("Coverage");\r
+ \r
+ Composite treeComposite = new Composite(folder, SWT.NONE);\r
+ \r
+ TreeViewer viewer = createCoverageViewer(treeComposite);\r
+ item2.setControl(treeComposite);\r
+ \r
+ treeViewer.addSelectionChangedListener(new ISelectionChangedListener() {\r
+ \r
+ @Override\r
+ public void selectionChanged(SelectionChangedEvent event) {\r
+ ISelection selection = event.getSelection();\r
+ TreeSelection sel = (TreeSelection) selection;\r
+ List<String> testOutput = provider.getModel().getOutput(sel.getFirstElement());\r
+ \r
+ viewer.setInput(sel.getFirstElement());\r
+ \r
+ StringBuilder sb = new StringBuilder();\r
+ for (String o : testOutput) {\r
+ sb.append(o);\r
+ }\r
+ output.setText(sb.toString());\r
+ }\r
+ });\r
+ \r
+ sashForm.setWeights(new int[] {50, 50});\r
+ return sashForm;\r
+ }\r
+ \r
+ protected static final int COLUMN_ELEMENT = 0;\r
+ protected static final int COLUMN_RATIO = 1;\r
+ protected static final int COLUMN_COVERED = 2;\r
+ protected static final int COLUMN_MISSED = 3;\r
+ protected static final int COLUMN_TOTAL = 4;\r
+ \r
+ private TreeViewer createCoverageViewer(Composite parent) {\r
+ // Composite treeViewerComposite = new Composite(parent, SWT.NONE);\r
+\r
+ TreeColumnLayout layout = new TreeColumnLayout();\r
+ parent.setLayout(layout);\r
+ \r
+ Tree tree = new Tree(parent, SWT.MULTI | SWT.FULL_SELECTION);\r
+ tree.setHeaderVisible(true);\r
+ tree.setLinesVisible(true);\r
+ \r
+ STSCoverageProvider provider = new STSCoverageProvider();\r
+\r
+ TreeViewer viewer = new TreeViewer(tree);\r
+ \r
+ CoverageViewSorter sorter = new CoverageViewSorter(viewer);\r
+ \r
+ final TreeViewerColumn column0 = new TreeViewerColumn(viewer, SWT.LEFT);\r
+ \r
+ column0.setLabelProvider(new CellLabelProvider() {\r
+\r
+ \r
+ @Override\r
+ public void update(ViewerCell cell) {\r
+ cell.setText(provider.getText(cell.getElement()));\r
+ cell.setImage(provider.getImage(cell.getElement()));\r
+ }\r
+ });\r
+ sorter.addColumn(column0, COLUMN_ELEMENT);\r
+\r
+ final TreeViewerColumn column1 = new TreeViewerColumn(viewer, SWT.RIGHT);\r
+ column1.setLabelProvider(new OwnerDrawLabelProvider() {\r
+\r
+ @Override\r
+ public void update(ViewerCell cell) {\r
+ cell.setText(provider.getRatio(cell.getElement()));\r
+ }\r
+\r
+ @Override\r
+ protected void erase(Event event, Object element) {\r
+ }\r
+\r
+ @Override\r
+ protected void measure(Event event, Object element) {\r
+ }\r
+\r
+ @Override\r
+ protected void paint(Event event, Object element) {\r
+ final Coverage coverage = (Coverage) element;\r
+ if (coverage != null) {\r
+ RedGreenBar.draw(event, column1.getColumn().getWidth(), coverage);\r
+ }\r
+ }\r
+ });\r
+ sorter.addColumn(column1, COLUMN_RATIO);\r
+\r
+ final TreeViewerColumn column2 = new TreeViewerColumn(viewer, SWT.RIGHT);\r
+ column2.setLabelProvider(new CellLabelProvider() {\r
+\r
+ @Override\r
+ public void update(ViewerCell cell) {\r
+ cell.setText(provider.getCovered(cell.getElement()));\r
+ }\r
+ });\r
+ sorter.addColumn(column2, COLUMN_COVERED);\r
+\r
+ final TreeViewerColumn column3 = new TreeViewerColumn(viewer, SWT.RIGHT);\r
+ column3.setLabelProvider(new CellLabelProvider() {\r
+\r
+ @Override\r
+ public void update(ViewerCell cell) {\r
+ cell.setText(provider.getMissed(cell.getElement()));\r
+ }\r
+ });\r
+ sorter.addColumn(column3, COLUMN_MISSED);\r
+\r
+ final TreeViewerColumn column4 = new TreeViewerColumn(viewer, SWT.RIGHT);\r
+ column4.setLabelProvider(new CellLabelProvider() {\r
+\r
+ @Override\r
+ public void update(ViewerCell cell) {\r
+ cell.setText(provider.getTotal(cell.getElement()));\r
+ }\r
+ });\r
+ sorter.addColumn(column4, COLUMN_TOTAL);\r
+\r
+// viewer.addFilter(new ViewerFilter() {\r
+// public boolean select(Viewer viewer, Object parentElement, Object element) {\r
+// if (element == LOADING_ELEMENT) {\r
+// return true;\r
+// } else {\r
+// final ICoverageNode c = CoverageTools.getCoverageInfo(element);\r
+// if (c == null) {\r
+// return false;\r
+// }\r
+// final ICounter instructions = c.getInstructionCounter();\r
+// if (instructions.getTotalCount() == 0) {\r
+// return false;\r
+// }\r
+// if (settings.getHideUnusedElements() && instructions.getCoveredCount() == 0) {\r
+// return false;\r
+// }\r
+// return true;\r
+// }\r
+// }\r
+// });\r
+ viewer.setComparator(sorter);\r
+ \r
+ layout.setColumnData(column0.getColumn(), new ColumnWeightData(0, 50, false));\r
+ layout.setColumnData(column1.getColumn(), new ColumnWeightData(0, 50, false));\r
+ layout.setColumnData(column2.getColumn(), new ColumnWeightData(0, 50, false));\r
+ layout.setColumnData(column3.getColumn(), new ColumnWeightData(0, 50, false));\r
+ layout.setColumnData(column4.getColumn(), new ColumnWeightData(0, 50, false));\r
+ \r
+ String[] columns = new String[] {"Module", "Coverage", "Covered Instructions", "Missed Instructions", "Total Instructions"};\r
+ TreeColumn[] columns2 = viewer.getTree().getColumns();\r
+ for (int i = 0; i < columns2.length; i++) {\r
+ columns2[i].setText(columns[i]);\r
+ }\r
+ restoreColumnWidth(viewer);\r
+ viewer.setContentProvider(provider);\r
+ return viewer;\r
+\r
+// viewer.addOpenListener(new IOpenListener() {\r
+// public void open(OpenEvent event) {\r
+// openAction.run((IStructuredSelection) event.getSelection());\r
+// }\r
+// });\r
+\r
+// MenuManager menuMgr = new MenuManager("#PopupMenu"); //$NON-NLS-1$\r
+// menuMgr.setRemoveAllWhenShown(true);\r
+// tree.setMenu(menuMgr.createContextMenu(tree));\r
+// getSite().registerContextMenu(menuMgr, viewer);\r
+//\r
+// CoverageTools.getSessionManager().addSessionListener(descriptionUpdater);\r
+// CoverageTools.addJavaCoverageListener(coverageListener);\r
+ }\r
+ \r
+ private static final int[] DEFAULT_COLUMNWIDTH = new int[] { 200, 100, 120,\r
+ 120, 120 };\r
+ \r
+ public void restoreColumnWidth(TreeViewer viewer) {\r
+ final TreeColumn[] columns = viewer.getTree().getColumns();\r
+ for (int i = 0; i < DEFAULT_COLUMNWIDTH.length; i++) {\r
+ columns[i].setWidth(DEFAULT_COLUMNWIDTH[i]);\r
+ }\r
+ }\r
+\r
+ protected Composite createProgressCountPanel(Composite parent) {\r
+ Composite composite= new Composite(parent, SWT.NONE);\r
+ GridLayout layout= new GridLayout();\r
+ composite.setLayout(layout);\r
+ layout.numColumns = 1;\r
+\r
+ counterPanel = new STSCounterPanel(composite);\r
+ counterPanel.setLayoutData(\r
+ new GridData(GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL));\r
+ progressBar = new STSProgressBar(composite);\r
+ progressBar.setLayoutData(\r
+ new GridData(GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL));\r
+ return composite;\r
+ }\r
+ \r
+ private void createTestViewers(Composite parent) {\r
+ viewerbook = new PageBook(parent, SWT.NULL);\r
+\r
+ treeViewer = new TreeViewer(viewerbook, SWT.V_SCROLL | SWT.SINGLE);\r
+ treeViewer.setUseHashlookup(true);\r
+ \r
+ STSTestSuiteModel model = new STSTestSuiteModel();\r
+ model.addListener(new STSExecutionListener() {\r
+ \r
+ @Override\r
+ public void testExecuted() {\r
+ treeViewer.getControl().getDisplay().syncExec(() -> {\r
+ refreshCounters();\r
+ treeViewer.refresh();\r
+ });\r
+ }\r
+ });\r
+ \r
+ provider = new STSTestSuiteProvider(model);\r
+ \r
+ treeViewer.setContentProvider(provider);\r
+ treeViewer.setLabelProvider(provider);\r
+\r
+\r
+ viewerbook.showPage(treeViewer.getTree());\r
+ \r
+ }\r
+ \r
+\r
+ @Focus\r
+ void setFocus() {\r
+ sashForm.setFocus();\r
+ }\r
+\r
+ public void currentTest(Resource test) {\r
+ treeViewer.setInput(test);\r
+ refreshCounters();\r
+ }\r
+ \r
+ private void refreshCounters() {\r
+ // TODO: Inefficient. Either\r
+ // - keep a boolean fHasTestRun and update only on changes, or\r
+ // - improve components to only redraw on changes (once!).\r
+\r
+ int startedCount;\r
+ int ignoredCount;\r
+ int totalCount;\r
+ int errorCount;\r
+ int failureCount;\r
+ int assumptionFailureCount;\r
+ boolean hasErrorsOrFailures;\r
+ boolean stopped;\r
+\r
+ STSTestSuiteModel model = provider.getModel();\r
+ if (model != null) {\r
+ startedCount= model.getStartedCount();\r
+ ignoredCount= model.getIgnoredCount();\r
+ totalCount= model.getTotalCount();\r
+ errorCount= model.getErrorCount();\r
+ failureCount= model.getFailureCount();\r
+ assumptionFailureCount = model.getAssumptionFailureCount();\r
+ hasErrorsOrFailures= errorCount + failureCount > 0;\r
+ stopped= model.isStopped();\r
+ } else {\r
+ startedCount= 0;\r
+ ignoredCount= 0;\r
+ totalCount= 0;\r
+ errorCount= 0;\r
+ failureCount= 0;\r
+ assumptionFailureCount = 0;\r
+ hasErrorsOrFailures= false;\r
+ stopped= false;\r
+ }\r
+\r
+ counterPanel.setTotal(totalCount);\r
+ counterPanel.setRunValue(startedCount, ignoredCount, assumptionFailureCount);\r
+ counterPanel.setErrorValue(errorCount);\r
+ counterPanel.setFailureValue(failureCount);\r
+\r
+ int ticksDone;\r
+ if (startedCount == 0)\r
+ ticksDone= 0;\r
+ else if (startedCount == totalCount && model.isStopped())\r
+ ticksDone= totalCount;\r
+ else\r
+ ticksDone= startedCount - 1;\r
+\r
+ progressBar.reset(hasErrorsOrFailures, stopped, ticksDone, totalCount);\r
+ }\r
+\r
+ public void execute() {\r
+ Executors.newSingleThreadExecutor().submit(new Runnable() {\r
+\r
+ @Override\r
+ public void run() {\r
+ provider.getModel().execute();\r
+ }\r
+ });\r
+ }\r
+ \r
+ @PreDestroy\r
+ public void destroy() {\r
+ provider.dispose();\r
+ }\r
+}\r