/******************************************************************************* * Copyright (c) 2012-2017 Codenvy, S.A. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ package org.eclipse.che.plugin.testing.ide.view; import static org.eclipse.che.plugin.maven.shared.MavenAttributes.DEFAULT_TEST_SOURCE_FOLDER; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import javax.validation.constraints.NotNull; import com.google.common.base.Optional; import com.google.gwt.core.client.GWT; import com.google.gwt.dom.client.Style; import com.google.gwt.event.logical.shared.SelectionEvent; import com.google.gwt.event.logical.shared.SelectionHandler; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; import com.google.gwt.user.client.Timer; import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.SplitLayoutPanel; import com.google.gwt.user.client.ui.Widget; import com.google.inject.Inject; import com.google.inject.Singleton; import org.eclipse.che.api.promises.client.Operation; import org.eclipse.che.api.promises.client.OperationException; import org.eclipse.che.api.promises.client.Promise; import org.eclipse.che.api.promises.client.PromiseError; import org.eclipse.che.api.testing.shared.TestCase; import org.eclipse.che.api.testing.shared.TestResult; import org.eclipse.che.ide.api.app.AppContext; import org.eclipse.che.ide.api.data.tree.Node; import org.eclipse.che.ide.api.data.tree.NodeInterceptor; import org.eclipse.che.ide.api.editor.EditorAgent; import org.eclipse.che.ide.api.editor.EditorPartPresenter; import org.eclipse.che.ide.api.editor.document.Document; import org.eclipse.che.ide.api.editor.text.TextPosition; import org.eclipse.che.ide.api.editor.texteditor.TextEditor; import org.eclipse.che.ide.api.parts.PartStackUIResources; import org.eclipse.che.ide.api.parts.base.BaseView; import org.eclipse.che.ide.api.resources.File; import org.eclipse.che.ide.ext.java.client.navigation.service.JavaNavigationService; import org.eclipse.che.ide.ext.java.shared.dto.Region; import org.eclipse.che.ide.ext.java.shared.dto.model.CompilationUnit; import org.eclipse.che.ide.ext.java.shared.dto.model.Method; import org.eclipse.che.ide.ext.java.shared.dto.model.Type; import org.eclipse.che.ide.ui.smartTree.NodeLoader; import org.eclipse.che.ide.ui.smartTree.NodeStorage; import org.eclipse.che.ide.ui.smartTree.NodeUniqueKeyProvider; import org.eclipse.che.ide.ui.smartTree.Tree; import org.eclipse.che.ide.util.loging.Log; import org.eclipse.che.plugin.testing.ide.TestResources; import org.eclipse.che.plugin.testing.ide.view.navigation.TestClassNavigation; import org.eclipse.che.plugin.testing.ide.view.navigation.factory.TestResultNodeFactory; import org.eclipse.che.plugin.testing.ide.view.navigation.nodes.TestResultClassNode; import org.eclipse.che.plugin.testing.ide.view.navigation.nodes.TestResultGroupNode; import org.eclipse.che.plugin.testing.ide.view.navigation.nodes.TestResultMethodNode; /** * Implementation for TestResult view. Uses tree for presenting test results. * * @author Mirage Abeysekara */ @Singleton public class TestResultViewImpl extends BaseView<TestResultView.ActionDelegate> implements TestResultView, TestClassNavigation { interface TestResultViewImplUiBinder extends UiBinder<Widget, TestResultViewImpl> { } private static final TestResultViewImplUiBinder UI_BINDER = GWT.create(TestResultViewImplUiBinder.class); private final JavaNavigationService javaNavigationService; private final AppContext appContext; private final EditorAgent editorAgent; private final TestResultNodeFactory nodeFactory; private TestResult lastTestResult; private Tree resultTree; private int lastWentLine = 0; private boolean showFailuresOnly = false; @UiField(provided = true) SplitLayoutPanel splitLayoutPanel; @UiField Label outputResult; @UiField FlowPanel navigationPanel; @Inject public TestResultViewImpl(TestResources testResources, PartStackUIResources resources, JavaNavigationService javaNavigationService, EditorAgent editorAgent, AppContext appContext, TestResultNodeFactory nodeFactory) { super(resources); this.javaNavigationService = javaNavigationService; this.editorAgent = editorAgent; this.appContext = appContext; this.nodeFactory = nodeFactory; splitLayoutPanel = new SplitLayoutPanel(1); setContentWidget(UI_BINDER.createAndBindUi(this)); NodeUniqueKeyProvider idProvider = new NodeUniqueKeyProvider() { @NotNull @Override public String getKey(@NotNull Node item) { return String.valueOf(item.hashCode()); } }; NodeStorage nodeStorage = new NodeStorage(idProvider); NodeLoader nodeLoader = new NodeLoader(Collections.<NodeInterceptor> emptySet()); resultTree = new Tree(nodeStorage, nodeLoader); resultTree.getSelectionModel().addSelectionHandler(new SelectionHandler<Node>() { @Override public void onSelection(SelectionEvent<Node> event) { Node methodNode = event.getSelectedItem(); if (methodNode instanceof TestResultMethodNode) { outputResult.setText(((TestResultMethodNode)methodNode).getStackTrace()); } } }); resultTree.getElement().getStyle().setWidth(100, Style.Unit.PCT); resultTree.getElement().getStyle().setHeight(100, Style.Unit.PCT); navigationPanel.add(resultTree); } /** * {@inheritDoc} */ @Override protected void focusView() { } /** * {@inheritDoc} */ @Override public void showResults(TestResult result) { this.lastTestResult = result; setTitle("Test Results (Framework: " + result.getTestFramework() + ")"); buildTree(); focusView(); } private void buildTree() { resultTree.getNodeStorage().clear(); outputResult.setText(""); TestResultGroupNode root = nodeFactory.getTestResultGroupNode(lastTestResult, showFailuresOnly, new Runnable() { @Override public void run() { showFailuresOnly = !showFailuresOnly; buildTree(); } }); HashMap<String, List<Node>> classNodeHashMap = new LinkedHashMap<>(); for (TestCase testCase : lastTestResult.getTestCases()) { if (!testCase.isFailed() && showFailuresOnly) { continue; } if (!classNodeHashMap.containsKey(testCase.getClassName())) { List<Node> methodNodes = new ArrayList<>(); classNodeHashMap.put(testCase.getClassName(), methodNodes); } classNodeHashMap.get(testCase.getClassName()) .add(nodeFactory.getTestResultMethodNodeNode(!testCase.isFailed(), testCase.getMethod(), testCase.getTrace(), testCase.getMessage(), testCase.getFailingLine(), this)); } List<Node> classNodes = new ArrayList<>(); for (Map.Entry<String, List<Node>> entry : classNodeHashMap.entrySet()) { TestResultClassNode classNode = nodeFactory.getTestResultClassNodeNode(entry.getKey()); classNode.setChildren(entry.getValue()); classNodes.add(classNode); } root.setChildren(classNodes); resultTree.getNodeStorage().add(root); resultTree.expandAll(); } @Override public void gotoClass(final String packagePath, String className, String methodName, int line) { if (lastTestResult == null) { return; } String projectPath = lastTestResult.getProjectPath(); if (projectPath == null) { return; } lastWentLine = line; String testSrcPath = projectPath + "/" + DEFAULT_TEST_SOURCE_FOLDER; appContext.getWorkspaceRoot().getFile(testSrcPath + "/" + packagePath).then(new Operation<Optional<File>>() { @Override public void apply(Optional<File> maybeFile) throws OperationException { if (maybeFile.isPresent()) { File file = maybeFile.get(); editorAgent.openEditor(file); Timer t = new Timer() { @Override public void run() { EditorPartPresenter editorPart = editorAgent.getActiveEditor(); final Document doc = ((TextEditor)editorPart).getDocument(); if (line == -1 && className != null && methodName != null) { Promise<CompilationUnit> cuPromise = javaNavigationService.getCompilationUnit(file.getProject().getLocation(), className, true); cuPromise.then(new Operation<CompilationUnit>() { @Override public void apply(CompilationUnit cu) throws OperationException { for (Type type : cu.getTypes()) { if (type.isPrimary()) { for (Method m : type.getMethods()) { if (methodName.equals(m.getElementName())) { Region methodRegion = m.getFileRegion(); if (methodRegion != null) { lastWentLine = doc.getLineAtOffset(methodRegion.getOffset()); doc.setCursorPosition(new TextPosition(lastWentLine - 1, 0)); } } } } } } }); } else { doc.setCursorPosition(new TextPosition(lastWentLine - 1, 0)); } } }; t.schedule(1000); } } }).catchError(new Operation<PromiseError>() { @Override public void apply(PromiseError error) throws OperationException { Log.info(TestResultViewImpl.class, error); } }); } }