/*******************************************************************************
* 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.businessprocess.compcheck;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jubula.client.core.Activator;
import org.eclipse.jubula.client.core.businessprocess.db.TestSuiteBP;
import org.eclipse.jubula.client.core.businessprocess.problems.IProblem;
import org.eclipse.jubula.client.core.businessprocess.problems.ProblemFactory;
import org.eclipse.jubula.client.core.businessprocess.problems.ProblemType;
import org.eclipse.jubula.client.core.i18n.Messages;
import org.eclipse.jubula.client.core.model.ICommentPO;
import org.eclipse.jubula.client.core.model.ICondStructPO;
import org.eclipse.jubula.client.core.model.IExecTestCasePO;
import org.eclipse.jubula.client.core.model.IIteratePO;
import org.eclipse.jubula.client.core.model.INodePO;
import org.eclipse.jubula.client.core.model.IParamNodePO;
import org.eclipse.jubula.client.core.model.ISpecTestCasePO;
import org.eclipse.jubula.client.core.model.ITestSuitePO;
import org.eclipse.jubula.client.core.persistence.GeneralStorage;
import org.eclipse.jubula.client.core.utils.AbstractNonPostOperatingTreeNodeOperation;
import org.eclipse.jubula.client.core.utils.ITreeTraverserContext;
import org.eclipse.jubula.client.core.utils.TreeTraverser;
/**
* @author BREDEX GmbH
* @created 10.05.2005
*/
public final class CompletenessGuard {
/**
* Operation to set the CompleteSpecTc flag for a node
*/
private static class CheckMissingTestCaseReferences extends
AbstractNonPostOperatingTreeNodeOperation<INodePO> {
/** {@inheritDoc} */
public boolean operate(ITreeTraverserContext<INodePO> ctx,
INodePO parent, INodePO node, boolean alreadyVisited) {
if (node instanceof IExecTestCasePO) {
IExecTestCasePO execTc = (IExecTestCasePO) node;
boolean isMissingSpecTc = execTc.getSpecTestCase() == null;
setCompletenessMissingTestCase(execTc, !isMissingSpecTc);
}
return !alreadyVisited;
}
}
/**
* Operation to remove problems from inactive nodes
*/
private static class InactiveNodesOperation extends
AbstractNonPostOperatingTreeNodeOperation<INodePO> {
/** {@inheritDoc} */
public boolean operate(ITreeTraverserContext<INodePO> ctx,
INodePO parent, INodePO node, boolean alreadyVisited) {
if (!node.isActive()) {
Set<IProblem> problemsToRemove = new HashSet<IProblem>(
node.getProblems());
for (IProblem problem : problemsToRemove) {
node.removeProblem(problem);
}
}
return !alreadyVisited;
}
}
/**
* Operation to check for empty conditions
*/
private static class CheckEmptyConditions extends
AbstractNonPostOperatingTreeNodeOperation<INodePO> {
/** {@inheritDoc} */
public boolean operate(ITreeTraverserContext<INodePO> ctx,
INodePO parent, INodePO node, boolean alreadyVisited) {
if (alreadyVisited) {
return false;
}
if (node instanceof ITestSuitePO
|| node instanceof ISpecTestCasePO) {
checkEmptyContainer(node);
return false; // We stop...
}
return true;
}
}
/**
* Operation to set the CompleteTestData flag at TDManager.
*
* @author BREDEX GmbH
* @created 10.10.2005
*/
private static class CheckTestDataCompleteness extends
AbstractNonPostOperatingTreeNodeOperation<INodePO> {
/**
* Sets the CompleteTDFlag in all ParamNodePOs. {@inheritDoc}
*/
public boolean operate(ITreeTraverserContext<INodePO> ctx,
INodePO parent, INodePO node, boolean alreadyVisited) {
if (alreadyVisited) {
return false;
}
checkLocalTestData(node);
return true;
}
}
/**
* private constructor
*/
private CompletenessGuard() {
// nothing
}
/**
* Runs all relevant checks for a single node (can be the Project itself)
*
* @param root
* INodePO
* @param monitor
* the progress monitor to use
*/
public static void checkAll(INodePO root, IProgressMonitor monitor) {
// Iterate Execution tree
TreeTraverser traverser = new TreeTraverser(root);
traverser.setTraverseSpecPart(true);
traverser.setMonitor(monitor);
traverser.setTraverseIntoExecs(false);
traverser.setTraverseSpecPart(true);
traverser.addOperation(new CheckTestDataCompleteness());
traverser.addOperation(new CheckMissingTestCaseReferences());
traverser.addOperation(new InactiveNodesOperation());
traverser.addOperation(new CheckEmptyConditions());
traverser.traverse(true);
List<ITestSuitePO> tsList = null;
if (root.equals(GeneralStorage.getInstance().getProject())) {
tsList = TestSuiteBP.getListOfTestSuites();
} else if (root instanceof ITestSuitePO) {
tsList = new ArrayList<>();
tsList.add((ITestSuitePO) root);
}
if (tsList != null && !tsList.isEmpty()) {
CompCheck check = new CompCheck(tsList);
check.traverse();
check.addProblems();
}
}
/**
* checks TD Completeness of all TS
*
* @param root
* INodePO
*/
public static void checkTestData(INodePO root) {
new TreeTraverser(root, new CheckTestDataCompleteness()).traverse(true);
}
/**
* @param node
* the node
* @param problem
* the problem
* @param deleteOrAdd
* true to delete; false to add problem to node
*/
private static void setNodeProblem(INodePO node, IProblem problem,
boolean deleteOrAdd) {
if (deleteOrAdd) {
node.removeProblem(problem);
} else {
node.addProblem(problem);
}
}
/**
* @param node
* the node
* @param completeTCFlag
* true to delete; false to add problem to node
*/
private static void setCompletenessMissingTestCase(INodePO node,
boolean completeTCFlag) {
setNodeProblem(node, ProblemFactory.MISSING_NODE, completeTCFlag);
}
/**
* method to set the sumTdFlag for a given Locale
*
* @param node
* the node
* @param flag
* the state of sumTdFlag to set
*/
public static void setCompletenessTestData(INodePO node, boolean flag) {
setNodeProblem(node,
ProblemFactory.createIncompleteTestDataProblem(node), flag);
}
/**
* @param node
* the node to check
*/
public static void checkLocalTestData(INodePO node) {
INodePO possibleDataSourceNode = node;
if (node instanceof IExecTestCasePO) {
IExecTestCasePO execTc = (IExecTestCasePO) node;
if (execTc.getHasReferencedTD()) {
possibleDataSourceNode = execTc.getSpecTestCase();
}
}
if (possibleDataSourceNode instanceof IParamNodePO) {
IParamNodePO dataSourceNode = (IParamNodePO) possibleDataSourceNode;
INodePO nodeToModify = null;
if (!(node instanceof ISpecTestCasePO)) {
nodeToModify = node;
}
if (nodeToModify != null) {
setCompletenessTestData(nodeToModify,
dataSourceNode.isTestDataComplete());
}
}
}
/**
* marking the node if it is an empty condition
* @param node the node
*/
public static void checkEmptyContainer(INodePO node) {
// Marking incomplete conditions
List<INodePO> list = node.getUnmodifiableNodeList();
for (INodePO child : list) {
if (child instanceof ICondStructPO || child instanceof IIteratePO) {
boolean ok = false;
INodePO branch = null;
if (child instanceof ICondStructPO) {
branch = ((ICondStructPO) child).getCondition();
} else {
branch = ((IIteratePO) child).getDoBranch();
}
for (Iterator<INodePO> it = branch.getNodeListIterator();
it.hasNext(); ) {
INodePO branchChild = it.next();
if (branchChild.isActive()
&& !(branchChild instanceof ICommentPO)) {
ok = true;
break;
}
}
if (!ok) {
String message = Messages.ProblemIncompleteBranch;
child.addProblem(ProblemFactory.createProblemWithMarker(
new Status(IStatus.ERROR,
Activator.PLUGIN_ID, message), message,
child, ProblemType.REASON_IF_WITHOUT_TEST));
}
}
}
}
}