/******************************************************************************* * Copyright (c) 2004, 2010 BREDEX GmbH. * 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: * BREDEX GmbH - initial API and implementation and/or initial documentation *******************************************************************************/ package org.eclipse.jubula.client.core.model; import java.util.ArrayList; import java.util.List; import org.apache.commons.lang.StringUtils; import org.eclipse.jubula.client.core.ClientTest; import org.eclipse.jubula.client.core.businessprocess.ExternalTestDataBP; import org.eclipse.jubula.client.core.businessprocess.ParamNameBP; import org.eclipse.jubula.client.core.businessprocess.TestExecution; import org.eclipse.jubula.client.core.i18n.Messages; import org.eclipse.jubula.client.core.utils.ExecObject; import org.eclipse.jubula.client.core.utils.ModelParamValueConverter; import org.eclipse.jubula.client.core.utils.ParamValueConverter; import org.eclipse.jubula.client.core.utils.Traverser; import org.eclipse.jubula.tools.internal.constants.StringConstants; import org.eclipse.jubula.tools.internal.exception.InvalidDataException; import org.eclipse.jubula.tools.internal.exception.JBException; import org.eclipse.jubula.tools.internal.i18n.CompSystemI18n; import org.eclipse.jubula.tools.internal.messagehandling.MessageIDs; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * class for tracking of result tree for display of test results * @author BREDEX GmbH * @created 14.04.2005 */ public class ResultTreeTracker implements IExecStackModificationListener { /** the logger */ private static Logger log = LoggerFactory.getLogger(ResultTreeTracker.class); /** Whether to throw away children of successful Test Result Nodes */ private boolean m_trimTree; /** * <code>m_endNode</code> last result node in resultTree, which is associated * with last execTestCase or with the testsuite */ private TestResultNode m_endNode; /** * <code>m_lastCap</code> resultNode to actual executed cap */ private TestResultNode m_lastNonCap; /** * here is saved how much extra hierarchy lvl we have caused by event * handler */ private int m_eventHierarchy = 0; /** business process for retrieving test data */ private ExternalTestDataBP m_externalTestDataBP; /** * @param root traverser for associated testexecution tree * @param externalTestDataBP business process for retrieving test data */ public ResultTreeTracker(TestResultNode root, ExternalTestDataBP externalTestDataBP) { m_endNode = root; m_lastNonCap = root; m_externalTestDataBP = externalTestDataBP; m_trimTree = ClientTest.instance().isTrimming(); } /** * {@inheritDoc} */ public void stackIncremented(INodePO node) { if (m_lastNonCap.getStatus() == TestResultNode.NOT_YET_TESTED) { m_lastNonCap.setResult(TestResultNode.TESTING, null); } if (node instanceof IEventExecTestCasePO || m_eventHierarchy > 0) { m_eventHierarchy++; } if (node instanceof IAbstractContainerPO && m_eventHierarchy == 0) { handleContainer((IAbstractContainerPO) node); } else if (m_eventHierarchy > 0) { int nextIndex = m_lastNonCap.getNextChildIndex(); m_lastNonCap = new TestResultNode( node, m_lastNonCap, nextIndex); m_lastNonCap.getParent().updateResultNode(nextIndex, m_lastNonCap); } else { TestResultNode nextNonCap = m_lastNonCap.getResultNodeList(). get(m_lastNonCap.getNextChildIndex()); while (nextNonCap.getNode() != node) { nextNonCap = m_lastNonCap.getResultNodeList(). get(m_lastNonCap.getNextChildIndex()); } m_lastNonCap = nextNonCap; } m_endNode = m_lastNonCap; handleLastNonCap(node); } /** * Adding a container to the TestResultTree * @param cont the container */ private void handleContainer(IAbstractContainerPO cont) { // we use the fact that Controller Test Result Nodes cannot have Event Handlers // so the next child is either the expected one or nothing Integer ind = m_lastNonCap.getNextChildIndex(); if (m_lastNonCap.getResultNodeList().size() == ind) { addSubtree(cont, ind); } else { m_lastNonCap = m_lastNonCap.getResultNodeList().get(ind); } } /** * {@inheritDoc} */ public void stackDecremented() { if (m_eventHierarchy > 0) { m_eventHierarchy--; } if (m_lastNonCap.getStatus() == TestResultNode.NOT_YET_TESTED || m_lastNonCap.getStatus() == TestResultNode.TESTING) { if (isAllSkipped(m_lastNonCap)) { m_lastNonCap.setResult(TestResultNode.SUCCESS_ONLY_SKIPPED, null); } else { m_lastNonCap.setResult(TestResultNode.SUCCESS, null); } if (m_trimTree) { m_lastNonCap.removeChildren(); } if (m_endNode.getStatus() == TestResultNode.NOT_YET_TESTED || m_endNode.getStatus() == TestResultNode.TESTING) { m_endNode.setResult(TestResultNode.SUCCESS, null); } } m_lastNonCap = m_lastNonCap.getParent(); m_endNode = m_lastNonCap; } /** * Checks whether the node's child nodes are all skipped * @param node the node whose children should be checked * @return <code>true</code> if the node's child nodes are all skipped, * <code>false</code> otherwise. */ private boolean isAllSkipped(TestResultNode node) { List<TestResultNode> children = node.getResultNodeList(); if (children.size() > 0) { for (TestResultNode child : children) { if (child.getStatus() != TestResultNode.SUCCESS_ONLY_SKIPPED && child.getStatus() != TestResultNode.SKIPPED) { return false; } } return true; } return false; } /** * {@inheritDoc} */ public void nextDataSetIteration() { if (m_lastNonCap.getStatus() == TestResultNode.NOT_YET_TESTED || m_lastNonCap.getStatus() == TestResultNode.TESTING) { if (isAllSkipped(m_lastNonCap)) { m_lastNonCap.setResult(TestResultNode.SUCCESS_ONLY_SKIPPED, null); } else { m_lastNonCap.setResult(TestResultNode.SUCCESS, null); } if (m_trimTree) { m_lastNonCap.removeChildren(); } if (m_endNode.getStatus() == TestResultNode.NOT_YET_TESTED || m_endNode.getStatus() == TestResultNode.TESTING) { m_endNode.setResult(TestResultNode.SUCCESS, null); } } int nextIndex = m_lastNonCap.getParent().getNextChildIndex(); if (m_eventHierarchy > 0) { m_lastNonCap = new TestResultNode(m_lastNonCap.getNode(), m_lastNonCap.getParent(), nextIndex); m_lastNonCap.getParent().updateResultNode(nextIndex, m_lastNonCap); } else { m_lastNonCap = m_lastNonCap.getParent(). getResultNodeList(). get(nextIndex); } handleLastNonCap(m_lastNonCap.getNode()); } /** * Adds parameters and sets the result of the newly created last non cap * @param node the node */ private void handleLastNonCap(INodePO node) { if (m_lastNonCap.getStatus() == TestResultNode.NOT_YET_TESTED) { if (node instanceof IParamNodePO) { addParameters((IParamNodePO)node, m_lastNonCap); } m_lastNonCap.setResult(TestResultNode.TESTING, null); } if (node instanceof ICondStructPO) { m_lastNonCap.addParameter(new TestResultParameter( "IsNegated", //$NON-NLS-1$ "java.lang.Boolean", //$NON-NLS-1$ Boolean.toString(((ICondStructPO) node).isNegate()))); } if (m_lastNonCap.getParent().getStatus() == TestResultNode.NOT_YET_TESTED) { m_lastNonCap.getParent().setResult(TestResultNode.TESTING, null); } } /** * {@inheritDoc} */ public void nextCap(ICapPO cap) { int nextIndex = m_lastNonCap.getNextChildIndex(); if (m_eventHierarchy > 0) { m_endNode = new TestResultNode(cap, m_lastNonCap); m_endNode.getParent().updateResultNode(nextIndex, m_endNode); m_endNode.setActionName( CompSystemI18n.getString(cap.getActionName())); m_endNode.setComponentType( CompSystemI18n.getString(cap.getComponentType())); } else { m_endNode = m_lastNonCap.getResultNodeList(). get(nextIndex); while (m_endNode.getNode() != cap) { nextIndex = m_lastNonCap.getNextChildIndex(); m_endNode = m_lastNonCap.getResultNodeList(). get(nextIndex); } } if (m_endNode.getStatus() == TestResultNode.NOT_YET_TESTED) { m_endNode.setResult(TestResultNode.TESTING, null); } addParameters(cap, m_endNode); } /** * Adds the parameters from the given cap to the given result node. * * @param paramNode The node from which to copy the parameter info. * @param resultNode The result node to which the parameter info will * be copied. */ private void addParameters(IParamNodePO paramNode, TestResultNode resultNode) { List<IParamDescriptionPO> parameterList = paramNode.getParameterList(); for (IParamDescriptionPO desc : parameterList) { List<ExecObject> execList = TestExecution.getInstance().getTrav().getExecStackAsList(); ExecObject currentExecObj = execList.get(execList.size() - 1); boolean shouldAddParameter = true; String value = currentExecObj.getParameterValue(desc.getUniqueId()); if (paramNode instanceof ICapPO) { ICapPO cap = (ICapPO) paramNode; shouldAddParameter = !(ParamNameBP.isOptionalParameter(cap, desc.getUniqueId()) && StringUtils.isEmpty(value)); } if (shouldAddParameter) { resultNode.addParameter(new TestResultParameter(desc.getName(), CompSystemI18n.getString(desc.getType()), value)); } } } /** * Adds the parameters from the given Test Step to the given result node. * * @param testStep The Test Step from which to copy the parameter info. * @param resultNode The result node to which the parameter info will * be copied. */ private void addParameters(ICapPO testStep, TestResultNode resultNode) { List<IParamDescriptionPO> parameterList = testStep.getParameterList(); String value = null; for (IParamDescriptionPO desc : parameterList) { ITDManager tdManager = null; try { tdManager = m_externalTestDataBP.getExternalCheckedTDManager( testStep); } catch (JBException e) { log.error( Messages.TestDataNotAvailable + StringConstants.DOT, e); } TestExecution te = TestExecution.getInstance(); List <ExecObject> stackList = new ArrayList<ExecObject>(te.getTrav().getExecStackAsList()); // Special handling for Test Steps. Their test data manager has // information about multiple Data Sets, but we are only interested // in the first one. int dataSetIndex = 0; if (tdManager.findColumnForParam(desc.getUniqueId()) == -1) { IParameterInterfacePO referencedDataCube = testStep .getReferencedDataCube(); if (referencedDataCube != null) { desc = referencedDataCube.getParameterForName(desc .getName()); } } String date = tdManager.getCell(dataSetIndex, desc); ParamValueConverter conv = new ModelParamValueConverter( date, testStep, desc); try { value = conv.getExecutionString(stackList); } catch (InvalidDataException e) { log.error(e.getMessage()); value = MessageIDs.getMessageObject(e.getErrorId()). getMessage(new String[] {e.getLocalizedMessage()}); } if (!(ParamNameBP.isOptionalParameter(testStep, desc.getUniqueId()) && StringUtils.isEmpty(value))) { resultNode.addParameter(new TestResultParameter( CompSystemI18n.getString(desc.getUniqueId()), CompSystemI18n.getString(desc.getType()), StringUtils.defaultString(value))); } } } /** * @return Returns the endNode. */ public TestResultNode getEndNode() { return m_endNode; } /** * {@inheritDoc} */ public void retryCap(ICapPO cap) { int nextIndex = m_lastNonCap.getNextChildIndex(); m_endNode = new TestResultNode(cap, m_lastNonCap, nextIndex); if (m_endNode.getStatus() == TestResultNode.NOT_YET_TESTED) { m_endNode.setResult(TestResultNode.TESTING, null); } m_endNode.getParent().updateResultNode(nextIndex, m_endNode); addParameters(cap, m_endNode); } /** * Adds a new subtree into the Result Tree * @param root the root * @param nextIndex the next index */ private void addSubtree(INodePO root, int nextIndex) { TestResultNode node = getRTBuilder(root).getRootNode(); m_lastNonCap.addChild(node); node.getParent().updateResultNode(nextIndex, node); node.setActionName(null); node.setResult(TestResultNode.TESTING, null); m_lastNonCap = node; } /** * @param root node * @return result tree builder * @throws JBException */ public static ResultTreeBuilder getRTBuilder(INodePO root) { Traverser traverser = new Traverser(root); traverser.setBuilding(true); ResultTreeBuilder resultTreeBuilder = new ResultTreeBuilder(traverser); traverser.addExecStackModificationListener(resultTreeBuilder); try { INodePO iterNode = traverser.next(); while (iterNode != null) { iterNode = traverser.next(); } } catch (JBException e) { log.error(Messages.TestDataNotAvailable + StringConstants.DOT, e); } return resultTreeBuilder; } /** {@inheritDoc} */ public void infiniteLoop() { m_lastNonCap.setResult(TestResultNode.INFINITE_LOOP, null); } }