From 645be13508008b30ec1309c895e6a54b2647ad9f Mon Sep 17 00:00:00 2001 From: Rene Schneider Date: Mon, 20 Jun 2016 13:18:42 +0200 Subject: [PATCH] fixed #113: Pushing 'null' as entity into suites fails tests Pushing 'null' as an entity into suites via suite params fails when comparing with a null value returned by a test fixture. --- .../integrity/utils/IntegrityDSLUtil.java | 1436 +++++++++-------- .../comparator/DefaultResultComparator.java | 83 +- .../suiteCallsWithParameters.integrity | 145 +- .../suitecalls/SuiteCallsWithParameters.java | 131 +- ....suitecalls.suiteCallWithNullParameter.xml | 62 + 5 files changed, 991 insertions(+), 866 deletions(-) create mode 100644 de.gebit.integrity.tests/results/integrity.basic.suitecalls.suiteCallWithNullParameter.xml diff --git a/de.gebit.integrity.dsl/src/de/gebit/integrity/utils/IntegrityDSLUtil.java b/de.gebit.integrity.dsl/src/de/gebit/integrity/utils/IntegrityDSLUtil.java index dd41fa71e..fb4380462 100644 --- a/de.gebit.integrity.dsl/src/de/gebit/integrity/utils/IntegrityDSLUtil.java +++ b/de.gebit.integrity.dsl/src/de/gebit/integrity/utils/IntegrityDSLUtil.java @@ -1,707 +1,729 @@ -/******************************************************************************* - * Copyright (c) 2013 Rene Schneider, GEBIT Solutions GmbH and others. - * 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 - *******************************************************************************/ -package de.gebit.integrity.utils; - -import java.util.ArrayList; -import java.util.List; -import java.util.NoSuchElementException; - -import org.eclipse.emf.ecore.EObject; -import org.eclipse.xtext.common.types.JvmAnnotationReference; -import org.eclipse.xtext.common.types.JvmAnnotationValue; -import org.eclipse.xtext.common.types.JvmArrayType; -import org.eclipse.xtext.common.types.JvmConstructor; -import org.eclipse.xtext.common.types.JvmEnumerationLiteral; -import org.eclipse.xtext.common.types.JvmEnumerationType; -import org.eclipse.xtext.common.types.JvmField; -import org.eclipse.xtext.common.types.JvmFormalParameter; -import org.eclipse.xtext.common.types.JvmGenericType; -import org.eclipse.xtext.common.types.JvmOperation; -import org.eclipse.xtext.common.types.JvmStringAnnotationValue; -import org.eclipse.xtext.common.types.JvmType; -import org.eclipse.xtext.common.types.JvmTypeReference; - -import de.gebit.integrity.dsl.ArbitraryParameterOrResultName; -import de.gebit.integrity.dsl.Call; -import de.gebit.integrity.dsl.CallDefinition; -import de.gebit.integrity.dsl.ConstantDefinition; -import de.gebit.integrity.dsl.FixedParameterName; -import de.gebit.integrity.dsl.FixedResultName; -import de.gebit.integrity.dsl.ForkDefinition; -import de.gebit.integrity.dsl.KeyValuePair; -import de.gebit.integrity.dsl.MethodReference; -import de.gebit.integrity.dsl.NamedCallResult; -import de.gebit.integrity.dsl.NamedResult; -import de.gebit.integrity.dsl.PackageDefinition; -import de.gebit.integrity.dsl.Parameter; -import de.gebit.integrity.dsl.ParameterName; -import de.gebit.integrity.dsl.ParameterTableValue; -import de.gebit.integrity.dsl.ResultName; -import de.gebit.integrity.dsl.Suite; -import de.gebit.integrity.dsl.SuiteDefinition; -import de.gebit.integrity.dsl.SuiteParameter; -import de.gebit.integrity.dsl.TableTest; -import de.gebit.integrity.dsl.TableTestRow; -import de.gebit.integrity.dsl.Test; -import de.gebit.integrity.dsl.TestDefinition; -import de.gebit.integrity.dsl.ValueOrEnumValueOrOperationCollection; -import de.gebit.integrity.dsl.VariableDefinition; -import de.gebit.integrity.dsl.VariableOrConstantEntity; -import de.gebit.integrity.dsl.VariantDefinition; -import de.gebit.integrity.dsl.VariantValue; -import de.gebit.integrity.dsl.VisibleMultiLineComment; -import de.gebit.integrity.dsl.VisibleSingleLineComment; -import de.gebit.integrity.exceptions.ThisShouldNeverHappenException; -import de.gebit.integrity.fixtures.FixtureParameter; -import de.gebit.integrity.forker.ForkerParameter; - -/** - * A utility class providing various helper functions. - * - * @author Rene Schneider - initial API and implementation - * - */ -public final class IntegrityDSLUtil { - - private IntegrityDSLUtil() { - // nothing to do - } - - /** - * Returns a list of all defined parameter names in a given fixture method, each of the results linked to the - * annotation reference that's connected to the parameter in the method signature. - * - * @param aMethod - * the method to inspect - * @return a list of parameters and annotation references - */ - public static List getAllParamNamesFromFixtureMethod(MethodReference aMethod) { - ArrayList tempList = new ArrayList(); - JvmOperation tempOperation = aMethod.getMethod(); - if (tempOperation != null) { - for (JvmFormalParameter tempParam : tempOperation.getParameters()) { - for (JvmAnnotationReference tempAnnotation : tempParam.getAnnotations()) { - String tempParamName = getParamNameFromAnnotation(tempAnnotation); - if (tempParamName != null) { - tempList.add(new ParamAnnotationTypeTriplet(tempParamName, tempParam.getQualifiedName(), - tempAnnotation, tempParam.getParameterType())); - } - } - } - } - - return tempList; - } - - /** - * Returns the name of a single parameter defined by a given annotation reference. - * - * @param anAnnotation - * the annotation reference - * @return the name - */ - public static String getParamNameFromAnnotation(JvmAnnotationReference anAnnotation) { - if (anAnnotation.getAnnotation() != null) { - if (anAnnotation.getAnnotation().getQualifiedName().equals(FixtureParameter.class.getCanonicalName()) - || anAnnotation.getAnnotation().getQualifiedName() - .equals(ForkerParameter.class.getCanonicalName())) { - for (JvmAnnotationValue tempValue : anAnnotation.getValues()) { - if (tempValue instanceof JvmStringAnnotationValue && "name".equals(tempValue.getValueName())) { - return ((JvmStringAnnotationValue) tempValue).getValues().get(0); - } - } - } - } - - return null; - } - - /** - * Returns a list of all defined parameter names in a given forker, each of the results linked to the annotation - * reference that's connected to the parameter in the constructor signature. Only one constructor is supported. - * - * @param aForkerType - * the forker to inspect - * @return a list of parameters and annotation references - */ - public static List getAllParamNamesFromForker(JvmGenericType aForkerType) { - ArrayList tempList = new ArrayList(); - try { - JvmConstructor tempConstructor = aForkerType.getDeclaredConstructors().iterator().next(); - if (tempConstructor != null) { - for (JvmFormalParameter tempParam : tempConstructor.getParameters()) { - for (JvmAnnotationReference tempAnnotation : tempParam.getAnnotations()) { - String tempParamName = getParamNameFromAnnotation(tempAnnotation); - if (tempParamName != null) { - tempList.add(new ParamAnnotationTypeTriplet(tempParamName, tempParam.getQualifiedName(), - tempAnnotation, tempParam.getParameterType())); - } - } - } - } - } catch (NoSuchElementException exc) { - // expected if no constructor is available - } - - return tempList; - } - - /** - * Returns the name of a single given parameter defined by a {@link ParameterName} instance. - * - * @param aParameterName - * the parameter name instance - * @return the parameter name string - */ - public static String getParamNameStringFromParameterName(ParameterName aParameterName) { - if (aParameterName instanceof FixedParameterName) { - return getParamNameFromAnnotation(((FixedParameterName) aParameterName).getAnnotation()); - } else if (aParameterName instanceof ArbitraryParameterOrResultName) { - return IntegrityDSLUtil - .getIdentifierFromArbitraryParameterOrResultName((ArbitraryParameterOrResultName) aParameterName); - } else { - throw new UnsupportedOperationException("This subtype of ParameterName (" - + aParameterName.getClass().toString() + ") is not supported yet!"); - } - } - - /** - * Returns a list of all valid enumeration literals for a given parameter in a given fixture method. - * - * @param aMethod - * the fixture method reference - * @param aParamAnnotation - * the parameter annotation reference - * @return a list of enumeration literals, or null if the parameter is not an enum parameter - */ - public static List getAllEnumLiteralsFromFixtureMethodParam(MethodReference aMethod, - JvmAnnotationReference aParamAnnotation) { - JvmOperation tempOperation = aMethod.getMethod(); - if (tempOperation != null) { - for (JvmFormalParameter tempParam : tempOperation.getParameters()) { - for (JvmAnnotationReference tempAnnotation : tempParam.getAnnotations()) { - if (aParamAnnotation == tempAnnotation) { - JvmTypeReference tempTypeRef = tempParam.getParameterType(); - return getAllEnumLiteralsFromJvmTypeReference(tempTypeRef); - } - } - } - } - - return null; - } - - /** - * Returns a list of all valid enumeration literals that are defined in the given type reference. - * - * @param aTypeRef - * the type reference - * @return the enumeration literals, or none if the type reference doesn't refer to an enum type - */ - public static List getAllEnumLiteralsFromJvmTypeReference(JvmTypeReference aTypeRef) { - JvmType tempType = aTypeRef.getType(); - - if (tempType instanceof JvmArrayType) { - // might be an array of enums! We need to extract the raw type then. - JvmArrayType tempArrayType = (JvmArrayType) tempType; - tempType = tempArrayType.getComponentType(); - } - - if (tempType instanceof JvmEnumerationType) { - JvmEnumerationType tempEnumType = (JvmEnumerationType) tempType; - return tempEnumType.getLiterals(); - } - - return null; - } - - /** - * Returns a list of named results defined by a given fixture method. - * - * @param aMethod - * the method - * @return the list of results - */ - public static List getAllResultNamesFromFixtureMethod(MethodReference aMethod) { - ArrayList tempList = new ArrayList(); - - JvmOperation tempOperation = aMethod.getMethod(); - if (tempOperation != null) { - JvmTypeReference tempReturnType = tempOperation.getReturnType(); - if ((tempReturnType.getType() instanceof JvmGenericType) - && !tempReturnType.getType().getQualifiedName().startsWith("java.") - && ((JvmGenericType) tempReturnType.getType()).isInstantiateable()) { - JvmGenericType tempTypeInFocus = (JvmGenericType) tempReturnType.getType(); - - while (tempTypeInFocus != null) { - for (JvmField tempField : tempTypeInFocus.getDeclaredFields()) { - if (!"java.util.Map".equals(tempField.getType().getType().getQualifiedName())) { - tempList.add(new ResultFieldTuple(tempField.getSimpleName(), tempField)); - } - } - - JvmGenericType tempOldType = tempTypeInFocus; - tempTypeInFocus = null; - for (JvmTypeReference tempSuperType : tempOldType.getSuperTypes()) { - if ((tempSuperType.getType() instanceof JvmGenericType) - && !((JvmGenericType) tempSuperType.getType()).isInterface()) { - tempTypeInFocus = (JvmGenericType) tempSuperType.getType(); - break; - } - } - } - } - } - - return tempList; - } - - /** - * Returns the fully qualified name of the fixture method referenced by the given method reference. - * - * @param aReference - * the method reference - * @return the fully qualified name, including the name of the class and the method itself - */ - public static String getQualifiedNameOfFixtureMethod(MethodReference aReference) { - String tempName = aReference.getMethod().getQualifiedName(); - return tempName.replace("." + aReference.getMethod().getSimpleName(), - "#" + aReference.getMethod().getSimpleName()); - } - - /** - * Returns the fully qualified name of a given {@link SuiteDefinition}. - * - * @param aSuite - * the suite - * @return the fully qualified name - */ - public static String getQualifiedSuiteName(SuiteDefinition aSuite) { - if (aSuite.eContainer() instanceof PackageDefinition) { - PackageDefinition tempPackageDef = (PackageDefinition) aSuite.eContainer(); - return tempPackageDef.getName() + "." + aSuite.getName(); - } else { - return aSuite.getName(); - } - } - - /** - * Returns the fully qualified name of a given {@link VariantDefinition}. - * - * @param aVariant - * the variant - * @return the fully qualified name - */ - public static String getQualifiedVariantName(VariantDefinition aVariant) { - if (aVariant.eContainer() instanceof PackageDefinition) { - PackageDefinition tempPackageDef = (PackageDefinition) aVariant.eContainer(); - return tempPackageDef.getName() + "." + aVariant.getName(); - } else { - return aVariant.getName(); - } - } - - /** - * Returns the fully qualified name of a given {@link ForkDefinition}. - * - * @param aFork - * the fork - * @return the fully qualified name - */ - public static String getQualifiedForkName(ForkDefinition aFork) { - if (aFork.eContainer() instanceof PackageDefinition) { - PackageDefinition tempPackageDef = (PackageDefinition) aFork.eContainer(); - return tempPackageDef.getName() + "." + aFork.getName(); - } else { - return aFork.getName(); - } - } - - /** - * Returns the fully qualified name of a given {@link CallDefinition}. - * - * @param aCall - * the call definition - * @return the fully qualified name - */ - public static String getQualifiedCallName(CallDefinition aCall) { - if (aCall.eContainer() instanceof PackageDefinition) { - PackageDefinition tempPackageDef = (PackageDefinition) aCall.eContainer(); - return tempPackageDef.getName() + "." + aCall.getName(); - } else { - return aCall.getName(); - } - } - - /** - * Returns the fully qualified name of a given {@link TestDefinition}. - * - * @param aTest - * the test definition - * @return the fully qualified name - */ - public static String getQualifiedTestName(TestDefinition aTest) { - if (aTest.eContainer() instanceof PackageDefinition) { - PackageDefinition tempPackageDef = (PackageDefinition) aTest.eContainer(); - return tempPackageDef.getName() + "." + aTest.getName(); - } else { - return aTest.getName(); - } - } - - /** - * Returns the fully qualified name of the given {@link VariableOrConstantEntity}. - * - * @param aVariable - * the variable - * @return the fully qualified name - */ - public static String getQualifiedVariableEntityName(VariableOrConstantEntity aVariable, - boolean aQualifyLocalVariables) { - if (aVariable.eContainer().eContainer() instanceof PackageDefinition) { - PackageDefinition tempPackageDef = (PackageDefinition) aVariable.eContainer().eContainer(); - return tempPackageDef.getName() + "." + aVariable.getName(); - } else { - if (aQualifyLocalVariables && aVariable.eContainer().eContainer() instanceof SuiteDefinition) { - // This covers both: variables defined in suites and suite parameters/returns (which are also variables) - // We use the container of the variable to discern between these. - String tempType = aVariable.eContainer().eClass().getName(); - SuiteDefinition tempSuiteDef = (SuiteDefinition) aVariable.eContainer().eContainer(); - return getQualifiedSuiteName(tempSuiteDef) + "$" + tempType + "$" + aVariable.getName(); - } else { - return aVariable.getName(); - } - } - } - - /** - * Returns the name of a specific test result value. - * - * @param aName - * the result name object - * @return the name string - */ - public static String getExpectedResultNameStringFromTestResultName(ResultName aName) { - if (aName instanceof FixedResultName) { - return ((FixedResultName) aName).getField().getSimpleName(); - } else if (aName instanceof ArbitraryParameterOrResultName) { - return IntegrityDSLUtil - .getIdentifierFromArbitraryParameterOrResultName((ArbitraryParameterOrResultName) aName); - } else { - throw new UnsupportedOperationException( - "This subtype of TestResultName (" + aName.getClass().getName() + ") is not supported yet!"); - } - } - - /** - * Removes the prefix as well as any trailing newlines from visible single-line comment text. - * - * @param aComment - * the comment - * @return the cleaned text - */ - public static String cleanSingleLineComment(VisibleSingleLineComment aComment) { - String tempString = aComment.getContent().trim(); - int tempCharsToTrim = 0; - if (tempString.startsWith("--- ")) { - tempCharsToTrim = 4; - } else if (tempString.startsWith("-- ")) { - tempCharsToTrim = 3; - } - - if (tempCharsToTrim > 0) { - if (tempString.length() > tempCharsToTrim) { - return tempString.substring(tempCharsToTrim); - } else { - return ""; - } - } - - throw new IllegalArgumentException("The given single-line comment does not start with the expected literal."); - } - - /** - * Removes prefix and suffix from visible single-line comment text, as well as any newlines in between. - * - * @param aComment - * the comment - * @return the cleaned text - */ - public static String cleanMultiLineComment(VisibleMultiLineComment aComment) { - String tempString = aComment.getContent().trim(); - int tempCharsToTrimStart = 0; - int tempCharsToTrimEnd = 0; - - if (tempString.startsWith("/--") && tempString.endsWith("--/")) { - tempCharsToTrimStart = 4; - tempCharsToTrimEnd = 3; - } else if (tempString.startsWith("/- ") && tempString.endsWith("-/")) { - tempCharsToTrimStart = 3; - tempCharsToTrimEnd = 2; - } - - if (tempCharsToTrimStart > 0) { - StringBuilder tempBuilder = new StringBuilder(); - boolean tempSpaceWasAdded = false; - for (int i = tempCharsToTrimStart; i < tempString.length() - tempCharsToTrimEnd; i++) { - char tempChar = tempString.charAt(i); - if (!Character.isWhitespace(tempChar)) { - tempSpaceWasAdded = false; - tempBuilder.append(tempChar); - } else { - if (!tempSpaceWasAdded) { - tempBuilder.append(' '); - tempSpaceWasAdded = true; - } - } - } - - return tempBuilder.toString().trim(); - } - - throw new IllegalArgumentException( - "The given multi-line comment does not start and end with the expected literals."); - } - - /** - * Determines whether a given {@link EObject} is part of a result of a test/call/tabletest. - * - * @param anObject - * the object to look at - * @return true if it is a result, false if not. Null if not determinable. - */ - public static Boolean isResult(EObject anObject) { - if (anObject instanceof ValueOrEnumValueOrOperationCollection) { - ValueOrEnumValueOrOperationCollection tempCollection = (ValueOrEnumValueOrOperationCollection) anObject; - if (tempCollection.eContainer() instanceof Test) { - return ((Test) tempCollection.eContainer()).getResult() == tempCollection; - } else if (tempCollection.eContainer() instanceof Suite) { - return false; - } else if (tempCollection.eContainer() instanceof NamedResult) { - NamedResult tempResult = (NamedResult) tempCollection.eContainer(); - if (tempResult.eContainer() instanceof Test || tempResult.eContainer() instanceof TableTest) { - return true; - } - } else if (tempCollection.eContainer() instanceof ParameterTableValue) { - ParameterTableValue tempParameter = (ParameterTableValue) tempCollection.eContainer(); - TableTestRow tempRow = (TableTestRow) tempParameter.eContainer(); - int tempColumnNumber = tempRow.getValues().indexOf(tempParameter); - if (tempColumnNumber >= 0) { - TableTest tempTest = (TableTest) tempRow.eContainer(); - return (tempColumnNumber >= tempTest.getParameterHeaders().size()); - } - } else if (tempCollection.eContainer() instanceof Parameter) { - Parameter tempParameter = (Parameter) tempCollection.eContainer(); - if (tempParameter.eContainer() instanceof Test || tempParameter.eContainer() instanceof Call - || tempParameter.eContainer() instanceof TableTest) { - return false; - } - } - } else if (anObject instanceof Call) { - return ((Call) anObject).getResult() == anObject; - } else if (anObject instanceof NamedCallResult) { - return true; - } else if (anObject instanceof SuiteParameter) { - return false; - } - - if (anObject != null && !(anObject instanceof SuiteDefinition)) { - return isResult(anObject.eContainer()); - } else { - return null; - } - } - - /** - * Finds the corresponding table header element to a given table cell element. - * - * @param aTableCell - * the table cell element - * @return the table header element if one exists, the table itself in case of the default result column or null if - * nothing was found - */ - public static EObject getTableHeaderForTableCell(ParameterTableValue aTableCell) { - int tempColumn = ((TableTestRow) aTableCell.eContainer()).getValues().indexOf(aTableCell); - - if (tempColumn >= 0) { - TableTestRow tempRow = (TableTestRow) aTableCell.eContainer(); - TableTest tempTest = (TableTest) tempRow.eContainer(); - if (tempColumn < tempTest.getParameterHeaders().size()) { - return tempTest.getParameterHeaders().get(tempColumn); - } else { - // we might be in the range of the result columns - int tempResultColumn = tempColumn - tempTest.getParameterHeaders().size(); - boolean tempDefaultResultExists = tempTest.getDefaultResultColumn() != null; - if (tempResultColumn >= 0 - && tempResultColumn < tempTest.getResultHeaders().size() + (tempDefaultResultExists ? 1 : 0)) { - - if (tempResultColumn < tempTest.getResultHeaders().size()) { - return tempTest.getResultHeaders().get(tempResultColumn); - } else if (tempResultColumn == tempTest.getResultHeaders().size()) { - return tempTest; - } - } - } - } - - return null; - } - - /** - * Finds the matching method reference for a given {@link Test}, {@link Call} or {@link TableTest}. - * - * @param anAction - * the action to find a method for - * @return the method or null if none was found - */ - public static MethodReference getMethodReferenceForAction(EObject anAction) { - if (anAction instanceof Test) { - TestDefinition tempDefinition = ((Test) anAction).getDefinition(); - if (tempDefinition != null) { - return tempDefinition.getFixtureMethod(); - } - } else if (anAction instanceof Call) { - CallDefinition tempDefinition = ((Call) anAction).getDefinition(); - if (tempDefinition != null) { - return tempDefinition.getFixtureMethod(); - } - } else if (anAction instanceof TableTest) { - TestDefinition tempDefinition = ((TableTest) anAction).getDefinition(); - if (tempDefinition != null) { - return tempDefinition.getFixtureMethod(); - } - } - - return null; - } - - /** - * Determines the initial value to use for the given {@link VariableOrConstantEntity}. - * - * @param anEntity - * the entity to explore - * @param aVariant - * the current variant being executed (null if no variant is used) - * @return the initial value, or null if none was given - */ - public static ValueOrEnumValueOrOperationCollection getInitialValueForVariableOrConstantEntity( - VariableOrConstantEntity anEntity, VariantDefinition aVariant) { - EObject tempDefiningStatement = anEntity.eContainer(); - if (tempDefiningStatement instanceof VariableDefinition) { - return ((VariableDefinition) tempDefiningStatement).getInitialValue(); - } else if (tempDefiningStatement instanceof ConstantDefinition) { - return getInitialValueForConstant((ConstantDefinition) tempDefiningStatement, aVariant); - } - - throw new ThisShouldNeverHappenException(); - } - - /** - * Determines the initial value for the given constant. - * - * @param aConstant - * the constant to explore - * @param aVariant - * the current variant being executed (null if no variant is used) - * @return the initial value, or null if none was given - */ - public static ValueOrEnumValueOrOperationCollection getInitialValueForConstant(ConstantDefinition aConstant, - VariantDefinition aVariant) { - ValueOrEnumValueOrOperationCollection tempValue = aConstant.getValue(); - if (aVariant != null) { - outer: for (VariantValue tempVariantValue : aConstant.getVariantValues()) { - for (VariantDefinition tempDefinition : tempVariantValue.getNames()) { - if (tempDefinition == aVariant) { - tempValue = tempVariantValue.getValue(); - break outer; - } - } - } - } - - return tempValue; - } - - /** - * Checks whether the given variable/constant entity is defined in a global (package) context. - * - * @param anEntity - * the entity to check - * @return true if globally defined, false if defined in a suite - */ - public static boolean isGlobalVariableOrConstant(VariableOrConstantEntity anEntity) { - return (anEntity.eContainer().eContainer() instanceof PackageDefinition); - } - - /** - * Finds an upstream container matching a provided container class. - * - * @param aContainerClass - * the class to find - * @param aSource - * the starting point for the search - * @return the upstream container, or null if nothing was found - */ - @SuppressWarnings("unchecked") - public static T findUpstreamContainer(Class aContainerClass, EObject aSource) { - EObject tempParent = aSource; - - while (tempParent != null && !aContainerClass.isAssignableFrom(tempParent.getClass())) { - tempParent = tempParent.eContainer(); - } - - return (T) tempParent; - } - - /** - * {@link KeyValuePair}s can be identified either by a free-form String (enclosed in quotes) or by a more restricted - * ID (without quotes). This method abstracts aways the decision where to get the final identifier from. - * - * @param aPair - * the key-value pair - * @return the identifier - */ - public static String getIdentifierFromKeyValuePair(KeyValuePair aPair) { - return aPair.getIdentifier() != null ? aPair.getIdentifier() : aPair.getStringIdentifier(); - } - - /** - * {@link ArbitraryParameterOrResultName}s can be identified either by a free-form String (enclosed in quotes) or by - * a more restricted ID (without quotes). This method abstracts aways the decision where to get the final identifier - * from. - * - * @param aName - * the name - * @return the identifier - */ - public static String getIdentifierFromArbitraryParameterOrResultName(ArbitraryParameterOrResultName aName) { - return aName.getIdentifier() != null ? aName.getIdentifier() : aName.getStringIdentifier(); - } - - /** - * Checks whether the given {@link EObject} is of private visibility. - * - * @param anObject - * the object to check - * @return true or false (will return false on objects which don't support a visibility modifier) - */ - public static boolean isPrivate(EObject anObject) { - if (anObject instanceof VariableDefinition) { - return ((VariableDefinition) anObject).getPrivate() != null; - } else if (anObject instanceof ConstantDefinition) { - return ((ConstantDefinition) anObject).getPrivate() != null; - } else if (anObject instanceof SuiteDefinition) { - return ((SuiteDefinition) anObject).getPrivate() != null; - } else if (anObject instanceof ForkDefinition) { - return ((ForkDefinition) anObject).getPrivate() != null; - } - - return false; - } - -} +/******************************************************************************* + * Copyright (c) 2013 Rene Schneider, GEBIT Solutions GmbH and others. + * 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 + *******************************************************************************/ +package de.gebit.integrity.utils; + +import java.util.ArrayList; +import java.util.List; +import java.util.NoSuchElementException; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.xtext.common.types.JvmAnnotationReference; +import org.eclipse.xtext.common.types.JvmAnnotationValue; +import org.eclipse.xtext.common.types.JvmArrayType; +import org.eclipse.xtext.common.types.JvmConstructor; +import org.eclipse.xtext.common.types.JvmEnumerationLiteral; +import org.eclipse.xtext.common.types.JvmEnumerationType; +import org.eclipse.xtext.common.types.JvmField; +import org.eclipse.xtext.common.types.JvmFormalParameter; +import org.eclipse.xtext.common.types.JvmGenericType; +import org.eclipse.xtext.common.types.JvmOperation; +import org.eclipse.xtext.common.types.JvmStringAnnotationValue; +import org.eclipse.xtext.common.types.JvmType; +import org.eclipse.xtext.common.types.JvmTypeReference; + +import de.gebit.integrity.dsl.ArbitraryParameterOrResultName; +import de.gebit.integrity.dsl.Call; +import de.gebit.integrity.dsl.CallDefinition; +import de.gebit.integrity.dsl.Constant; +import de.gebit.integrity.dsl.ConstantDefinition; +import de.gebit.integrity.dsl.FixedParameterName; +import de.gebit.integrity.dsl.FixedResultName; +import de.gebit.integrity.dsl.ForkDefinition; +import de.gebit.integrity.dsl.KeyValuePair; +import de.gebit.integrity.dsl.MethodReference; +import de.gebit.integrity.dsl.NamedCallResult; +import de.gebit.integrity.dsl.NamedResult; +import de.gebit.integrity.dsl.PackageDefinition; +import de.gebit.integrity.dsl.Parameter; +import de.gebit.integrity.dsl.ParameterName; +import de.gebit.integrity.dsl.ParameterTableValue; +import de.gebit.integrity.dsl.ResultName; +import de.gebit.integrity.dsl.Suite; +import de.gebit.integrity.dsl.SuiteDefinition; +import de.gebit.integrity.dsl.SuiteParameter; +import de.gebit.integrity.dsl.TableTest; +import de.gebit.integrity.dsl.TableTestRow; +import de.gebit.integrity.dsl.Test; +import de.gebit.integrity.dsl.TestDefinition; +import de.gebit.integrity.dsl.ValueOrEnumValueOrOperation; +import de.gebit.integrity.dsl.ValueOrEnumValueOrOperationCollection; +import de.gebit.integrity.dsl.Variable; +import de.gebit.integrity.dsl.VariableDefinition; +import de.gebit.integrity.dsl.VariableOrConstantEntity; +import de.gebit.integrity.dsl.VariantDefinition; +import de.gebit.integrity.dsl.VariantValue; +import de.gebit.integrity.dsl.VisibleMultiLineComment; +import de.gebit.integrity.dsl.VisibleSingleLineComment; +import de.gebit.integrity.exceptions.ThisShouldNeverHappenException; +import de.gebit.integrity.fixtures.FixtureParameter; +import de.gebit.integrity.forker.ForkerParameter; + +/** + * A utility class providing various helper functions. + * + * @author Rene Schneider - initial API and implementation + * + */ +public final class IntegrityDSLUtil { + + private IntegrityDSLUtil() { + // nothing to do + } + + /** + * Returns a list of all defined parameter names in a given fixture method, each of the results linked to the + * annotation reference that's connected to the parameter in the method signature. + * + * @param aMethod + * the method to inspect + * @return a list of parameters and annotation references + */ + public static List getAllParamNamesFromFixtureMethod(MethodReference aMethod) { + ArrayList tempList = new ArrayList(); + JvmOperation tempOperation = aMethod.getMethod(); + if (tempOperation != null) { + for (JvmFormalParameter tempParam : tempOperation.getParameters()) { + for (JvmAnnotationReference tempAnnotation : tempParam.getAnnotations()) { + String tempParamName = getParamNameFromAnnotation(tempAnnotation); + if (tempParamName != null) { + tempList.add(new ParamAnnotationTypeTriplet(tempParamName, tempParam.getQualifiedName(), + tempAnnotation, tempParam.getParameterType())); + } + } + } + } + + return tempList; + } + + /** + * Returns the name of a single parameter defined by a given annotation reference. + * + * @param anAnnotation + * the annotation reference + * @return the name + */ + public static String getParamNameFromAnnotation(JvmAnnotationReference anAnnotation) { + if (anAnnotation.getAnnotation() != null) { + if (anAnnotation.getAnnotation().getQualifiedName().equals(FixtureParameter.class.getCanonicalName()) + || anAnnotation.getAnnotation().getQualifiedName() + .equals(ForkerParameter.class.getCanonicalName())) { + for (JvmAnnotationValue tempValue : anAnnotation.getValues()) { + if (tempValue instanceof JvmStringAnnotationValue && "name".equals(tempValue.getValueName())) { + return ((JvmStringAnnotationValue) tempValue).getValues().get(0); + } + } + } + } + + return null; + } + + /** + * Returns a list of all defined parameter names in a given forker, each of the results linked to the annotation + * reference that's connected to the parameter in the constructor signature. Only one constructor is supported. + * + * @param aForkerType + * the forker to inspect + * @return a list of parameters and annotation references + */ + public static List getAllParamNamesFromForker(JvmGenericType aForkerType) { + ArrayList tempList = new ArrayList(); + try { + JvmConstructor tempConstructor = aForkerType.getDeclaredConstructors().iterator().next(); + if (tempConstructor != null) { + for (JvmFormalParameter tempParam : tempConstructor.getParameters()) { + for (JvmAnnotationReference tempAnnotation : tempParam.getAnnotations()) { + String tempParamName = getParamNameFromAnnotation(tempAnnotation); + if (tempParamName != null) { + tempList.add(new ParamAnnotationTypeTriplet(tempParamName, tempParam.getQualifiedName(), + tempAnnotation, tempParam.getParameterType())); + } + } + } + } + } catch (NoSuchElementException exc) { + // expected if no constructor is available + } + + return tempList; + } + + /** + * Returns the name of a single given parameter defined by a {@link ParameterName} instance. + * + * @param aParameterName + * the parameter name instance + * @return the parameter name string + */ + public static String getParamNameStringFromParameterName(ParameterName aParameterName) { + if (aParameterName instanceof FixedParameterName) { + return getParamNameFromAnnotation(((FixedParameterName) aParameterName).getAnnotation()); + } else if (aParameterName instanceof ArbitraryParameterOrResultName) { + return IntegrityDSLUtil + .getIdentifierFromArbitraryParameterOrResultName((ArbitraryParameterOrResultName) aParameterName); + } else { + throw new UnsupportedOperationException("This subtype of ParameterName (" + + aParameterName.getClass().toString() + ") is not supported yet!"); + } + } + + /** + * Returns a list of all valid enumeration literals for a given parameter in a given fixture method. + * + * @param aMethod + * the fixture method reference + * @param aParamAnnotation + * the parameter annotation reference + * @return a list of enumeration literals, or null if the parameter is not an enum parameter + */ + public static List getAllEnumLiteralsFromFixtureMethodParam(MethodReference aMethod, + JvmAnnotationReference aParamAnnotation) { + JvmOperation tempOperation = aMethod.getMethod(); + if (tempOperation != null) { + for (JvmFormalParameter tempParam : tempOperation.getParameters()) { + for (JvmAnnotationReference tempAnnotation : tempParam.getAnnotations()) { + if (aParamAnnotation == tempAnnotation) { + JvmTypeReference tempTypeRef = tempParam.getParameterType(); + return getAllEnumLiteralsFromJvmTypeReference(tempTypeRef); + } + } + } + } + + return null; + } + + /** + * Returns a list of all valid enumeration literals that are defined in the given type reference. + * + * @param aTypeRef + * the type reference + * @return the enumeration literals, or none if the type reference doesn't refer to an enum type + */ + public static List getAllEnumLiteralsFromJvmTypeReference(JvmTypeReference aTypeRef) { + JvmType tempType = aTypeRef.getType(); + + if (tempType instanceof JvmArrayType) { + // might be an array of enums! We need to extract the raw type then. + JvmArrayType tempArrayType = (JvmArrayType) tempType; + tempType = tempArrayType.getComponentType(); + } + + if (tempType instanceof JvmEnumerationType) { + JvmEnumerationType tempEnumType = (JvmEnumerationType) tempType; + return tempEnumType.getLiterals(); + } + + return null; + } + + /** + * Returns a list of named results defined by a given fixture method. + * + * @param aMethod + * the method + * @return the list of results + */ + public static List getAllResultNamesFromFixtureMethod(MethodReference aMethod) { + ArrayList tempList = new ArrayList(); + + JvmOperation tempOperation = aMethod.getMethod(); + if (tempOperation != null) { + JvmTypeReference tempReturnType = tempOperation.getReturnType(); + if ((tempReturnType.getType() instanceof JvmGenericType) + && !tempReturnType.getType().getQualifiedName().startsWith("java.") + && ((JvmGenericType) tempReturnType.getType()).isInstantiateable()) { + JvmGenericType tempTypeInFocus = (JvmGenericType) tempReturnType.getType(); + + while (tempTypeInFocus != null) { + for (JvmField tempField : tempTypeInFocus.getDeclaredFields()) { + if (!"java.util.Map".equals(tempField.getType().getType().getQualifiedName())) { + tempList.add(new ResultFieldTuple(tempField.getSimpleName(), tempField)); + } + } + + JvmGenericType tempOldType = tempTypeInFocus; + tempTypeInFocus = null; + for (JvmTypeReference tempSuperType : tempOldType.getSuperTypes()) { + if ((tempSuperType.getType() instanceof JvmGenericType) + && !((JvmGenericType) tempSuperType.getType()).isInterface()) { + tempTypeInFocus = (JvmGenericType) tempSuperType.getType(); + break; + } + } + } + } + } + + return tempList; + } + + /** + * Returns the fully qualified name of the fixture method referenced by the given method reference. + * + * @param aReference + * the method reference + * @return the fully qualified name, including the name of the class and the method itself + */ + public static String getQualifiedNameOfFixtureMethod(MethodReference aReference) { + String tempName = aReference.getMethod().getQualifiedName(); + return tempName.replace("." + aReference.getMethod().getSimpleName(), + "#" + aReference.getMethod().getSimpleName()); + } + + /** + * Returns the fully qualified name of a given {@link SuiteDefinition}. + * + * @param aSuite + * the suite + * @return the fully qualified name + */ + public static String getQualifiedSuiteName(SuiteDefinition aSuite) { + if (aSuite.eContainer() instanceof PackageDefinition) { + PackageDefinition tempPackageDef = (PackageDefinition) aSuite.eContainer(); + return tempPackageDef.getName() + "." + aSuite.getName(); + } else { + return aSuite.getName(); + } + } + + /** + * Returns the fully qualified name of a given {@link VariantDefinition}. + * + * @param aVariant + * the variant + * @return the fully qualified name + */ + public static String getQualifiedVariantName(VariantDefinition aVariant) { + if (aVariant.eContainer() instanceof PackageDefinition) { + PackageDefinition tempPackageDef = (PackageDefinition) aVariant.eContainer(); + return tempPackageDef.getName() + "." + aVariant.getName(); + } else { + return aVariant.getName(); + } + } + + /** + * Returns the fully qualified name of a given {@link ForkDefinition}. + * + * @param aFork + * the fork + * @return the fully qualified name + */ + public static String getQualifiedForkName(ForkDefinition aFork) { + if (aFork.eContainer() instanceof PackageDefinition) { + PackageDefinition tempPackageDef = (PackageDefinition) aFork.eContainer(); + return tempPackageDef.getName() + "." + aFork.getName(); + } else { + return aFork.getName(); + } + } + + /** + * Returns the fully qualified name of a given {@link CallDefinition}. + * + * @param aCall + * the call definition + * @return the fully qualified name + */ + public static String getQualifiedCallName(CallDefinition aCall) { + if (aCall.eContainer() instanceof PackageDefinition) { + PackageDefinition tempPackageDef = (PackageDefinition) aCall.eContainer(); + return tempPackageDef.getName() + "." + aCall.getName(); + } else { + return aCall.getName(); + } + } + + /** + * Returns the fully qualified name of a given {@link TestDefinition}. + * + * @param aTest + * the test definition + * @return the fully qualified name + */ + public static String getQualifiedTestName(TestDefinition aTest) { + if (aTest.eContainer() instanceof PackageDefinition) { + PackageDefinition tempPackageDef = (PackageDefinition) aTest.eContainer(); + return tempPackageDef.getName() + "." + aTest.getName(); + } else { + return aTest.getName(); + } + } + + /** + * Returns the fully qualified name of the given {@link VariableOrConstantEntity}. + * + * @param aVariable + * the variable + * @return the fully qualified name + */ + public static String getQualifiedVariableEntityName(VariableOrConstantEntity aVariable, + boolean aQualifyLocalVariables) { + if (aVariable.eContainer().eContainer() instanceof PackageDefinition) { + PackageDefinition tempPackageDef = (PackageDefinition) aVariable.eContainer().eContainer(); + return tempPackageDef.getName() + "." + aVariable.getName(); + } else { + if (aQualifyLocalVariables && aVariable.eContainer().eContainer() instanceof SuiteDefinition) { + // This covers both: variables defined in suites and suite parameters/returns (which are also variables) + // We use the container of the variable to discern between these. + String tempType = aVariable.eContainer().eClass().getName(); + SuiteDefinition tempSuiteDef = (SuiteDefinition) aVariable.eContainer().eContainer(); + return getQualifiedSuiteName(tempSuiteDef) + "$" + tempType + "$" + aVariable.getName(); + } else { + return aVariable.getName(); + } + } + } + + /** + * Returns the name of a specific test result value. + * + * @param aName + * the result name object + * @return the name string + */ + public static String getExpectedResultNameStringFromTestResultName(ResultName aName) { + if (aName instanceof FixedResultName) { + return ((FixedResultName) aName).getField().getSimpleName(); + } else if (aName instanceof ArbitraryParameterOrResultName) { + return IntegrityDSLUtil + .getIdentifierFromArbitraryParameterOrResultName((ArbitraryParameterOrResultName) aName); + } else { + throw new UnsupportedOperationException( + "This subtype of TestResultName (" + aName.getClass().getName() + ") is not supported yet!"); + } + } + + /** + * Removes the prefix as well as any trailing newlines from visible single-line comment text. + * + * @param aComment + * the comment + * @return the cleaned text + */ + public static String cleanSingleLineComment(VisibleSingleLineComment aComment) { + String tempString = aComment.getContent().trim(); + int tempCharsToTrim = 0; + if (tempString.startsWith("--- ")) { + tempCharsToTrim = 4; + } else if (tempString.startsWith("-- ")) { + tempCharsToTrim = 3; + } + + if (tempCharsToTrim > 0) { + if (tempString.length() > tempCharsToTrim) { + return tempString.substring(tempCharsToTrim); + } else { + return ""; + } + } + + throw new IllegalArgumentException("The given single-line comment does not start with the expected literal."); + } + + /** + * Removes prefix and suffix from visible single-line comment text, as well as any newlines in between. + * + * @param aComment + * the comment + * @return the cleaned text + */ + public static String cleanMultiLineComment(VisibleMultiLineComment aComment) { + String tempString = aComment.getContent().trim(); + int tempCharsToTrimStart = 0; + int tempCharsToTrimEnd = 0; + + if (tempString.startsWith("/--") && tempString.endsWith("--/")) { + tempCharsToTrimStart = 4; + tempCharsToTrimEnd = 3; + } else if (tempString.startsWith("/- ") && tempString.endsWith("-/")) { + tempCharsToTrimStart = 3; + tempCharsToTrimEnd = 2; + } + + if (tempCharsToTrimStart > 0) { + StringBuilder tempBuilder = new StringBuilder(); + boolean tempSpaceWasAdded = false; + for (int i = tempCharsToTrimStart; i < tempString.length() - tempCharsToTrimEnd; i++) { + char tempChar = tempString.charAt(i); + if (!Character.isWhitespace(tempChar)) { + tempSpaceWasAdded = false; + tempBuilder.append(tempChar); + } else { + if (!tempSpaceWasAdded) { + tempBuilder.append(' '); + tempSpaceWasAdded = true; + } + } + } + + return tempBuilder.toString().trim(); + } + + throw new IllegalArgumentException( + "The given multi-line comment does not start and end with the expected literals."); + } + + /** + * Determines whether a given {@link EObject} is part of a result of a test/call/tabletest. + * + * @param anObject + * the object to look at + * @return true if it is a result, false if not. Null if not determinable. + */ + public static Boolean isResult(EObject anObject) { + if (anObject instanceof ValueOrEnumValueOrOperationCollection) { + ValueOrEnumValueOrOperationCollection tempCollection = (ValueOrEnumValueOrOperationCollection) anObject; + if (tempCollection.eContainer() instanceof Test) { + return ((Test) tempCollection.eContainer()).getResult() == tempCollection; + } else if (tempCollection.eContainer() instanceof Suite) { + return false; + } else if (tempCollection.eContainer() instanceof NamedResult) { + NamedResult tempResult = (NamedResult) tempCollection.eContainer(); + if (tempResult.eContainer() instanceof Test || tempResult.eContainer() instanceof TableTest) { + return true; + } + } else if (tempCollection.eContainer() instanceof ParameterTableValue) { + ParameterTableValue tempParameter = (ParameterTableValue) tempCollection.eContainer(); + TableTestRow tempRow = (TableTestRow) tempParameter.eContainer(); + int tempColumnNumber = tempRow.getValues().indexOf(tempParameter); + if (tempColumnNumber >= 0) { + TableTest tempTest = (TableTest) tempRow.eContainer(); + return (tempColumnNumber >= tempTest.getParameterHeaders().size()); + } + } else if (tempCollection.eContainer() instanceof Parameter) { + Parameter tempParameter = (Parameter) tempCollection.eContainer(); + if (tempParameter.eContainer() instanceof Test || tempParameter.eContainer() instanceof Call + || tempParameter.eContainer() instanceof TableTest) { + return false; + } + } + } else if (anObject instanceof Call) { + return ((Call) anObject).getResult() == anObject; + } else if (anObject instanceof NamedCallResult) { + return true; + } else if (anObject instanceof SuiteParameter) { + return false; + } + + if (anObject != null && !(anObject instanceof SuiteDefinition)) { + return isResult(anObject.eContainer()); + } else { + return null; + } + } + + /** + * Finds the corresponding table header element to a given table cell element. + * + * @param aTableCell + * the table cell element + * @return the table header element if one exists, the table itself in case of the default result column or null if + * nothing was found + */ + public static EObject getTableHeaderForTableCell(ParameterTableValue aTableCell) { + int tempColumn = ((TableTestRow) aTableCell.eContainer()).getValues().indexOf(aTableCell); + + if (tempColumn >= 0) { + TableTestRow tempRow = (TableTestRow) aTableCell.eContainer(); + TableTest tempTest = (TableTest) tempRow.eContainer(); + if (tempColumn < tempTest.getParameterHeaders().size()) { + return tempTest.getParameterHeaders().get(tempColumn); + } else { + // we might be in the range of the result columns + int tempResultColumn = tempColumn - tempTest.getParameterHeaders().size(); + boolean tempDefaultResultExists = tempTest.getDefaultResultColumn() != null; + if (tempResultColumn >= 0 + && tempResultColumn < tempTest.getResultHeaders().size() + (tempDefaultResultExists ? 1 : 0)) { + + if (tempResultColumn < tempTest.getResultHeaders().size()) { + return tempTest.getResultHeaders().get(tempResultColumn); + } else if (tempResultColumn == tempTest.getResultHeaders().size()) { + return tempTest; + } + } + } + } + + return null; + } + + /** + * Finds the matching method reference for a given {@link Test}, {@link Call} or {@link TableTest}. + * + * @param anAction + * the action to find a method for + * @return the method or null if none was found + */ + public static MethodReference getMethodReferenceForAction(EObject anAction) { + if (anAction instanceof Test) { + TestDefinition tempDefinition = ((Test) anAction).getDefinition(); + if (tempDefinition != null) { + return tempDefinition.getFixtureMethod(); + } + } else if (anAction instanceof Call) { + CallDefinition tempDefinition = ((Call) anAction).getDefinition(); + if (tempDefinition != null) { + return tempDefinition.getFixtureMethod(); + } + } else if (anAction instanceof TableTest) { + TestDefinition tempDefinition = ((TableTest) anAction).getDefinition(); + if (tempDefinition != null) { + return tempDefinition.getFixtureMethod(); + } + } + + return null; + } + + /** + * Determines the initial value to use for the given {@link VariableOrConstantEntity}. + * + * @param anEntity + * the entity to explore + * @param aVariant + * the current variant being executed (null if no variant is used) + * @return the initial value, or null if none was given + */ + public static ValueOrEnumValueOrOperationCollection getInitialValueForVariableOrConstantEntity( + VariableOrConstantEntity anEntity, VariantDefinition aVariant) { + EObject tempDefiningStatement = anEntity.eContainer(); + if (tempDefiningStatement instanceof VariableDefinition) { + return ((VariableDefinition) tempDefiningStatement).getInitialValue(); + } else if (tempDefiningStatement instanceof ConstantDefinition) { + return getInitialValueForConstant((ConstantDefinition) tempDefiningStatement, aVariant); + } + + throw new ThisShouldNeverHappenException(); + } + + /** + * Determines the initial value for the given constant. + * + * @param aConstant + * the constant to explore + * @param aVariant + * the current variant being executed (null if no variant is used) + * @return the initial value, or null if none was given + */ + public static ValueOrEnumValueOrOperationCollection getInitialValueForConstant(ConstantDefinition aConstant, + VariantDefinition aVariant) { + ValueOrEnumValueOrOperationCollection tempValue = aConstant.getValue(); + if (aVariant != null) { + outer: for (VariantValue tempVariantValue : aConstant.getVariantValues()) { + for (VariantDefinition tempDefinition : tempVariantValue.getNames()) { + if (tempDefinition == aVariant) { + tempValue = tempVariantValue.getValue(); + break outer; + } + } + } + } + + return tempValue; + } + + /** + * Checks whether the given variable/constant entity is defined in a global (package) context. + * + * @param anEntity + * the entity to check + * @return true if globally defined, false if defined in a suite + */ + public static boolean isGlobalVariableOrConstant(VariableOrConstantEntity anEntity) { + return (anEntity.eContainer().eContainer() instanceof PackageDefinition); + } + + /** + * Finds an upstream container matching a provided container class. + * + * @param aContainerClass + * the class to find + * @param aSource + * the starting point for the search + * @return the upstream container, or null if nothing was found + */ + @SuppressWarnings("unchecked") + public static T findUpstreamContainer(Class aContainerClass, EObject aSource) { + EObject tempParent = aSource; + + while (tempParent != null && !aContainerClass.isAssignableFrom(tempParent.getClass())) { + tempParent = tempParent.eContainer(); + } + + return (T) tempParent; + } + + /** + * {@link KeyValuePair}s can be identified either by a free-form String (enclosed in quotes) or by a more restricted + * ID (without quotes). This method abstracts aways the decision where to get the final identifier from. + * + * @param aPair + * the key-value pair + * @return the identifier + */ + public static String getIdentifierFromKeyValuePair(KeyValuePair aPair) { + return aPair.getIdentifier() != null ? aPair.getIdentifier() : aPair.getStringIdentifier(); + } + + /** + * {@link ArbitraryParameterOrResultName}s can be identified either by a free-form String (enclosed in quotes) or by + * a more restricted ID (without quotes). This method abstracts aways the decision where to get the final identifier + * from. + * + * @param aName + * the name + * @return the identifier + */ + public static String getIdentifierFromArbitraryParameterOrResultName(ArbitraryParameterOrResultName aName) { + return aName.getIdentifier() != null ? aName.getIdentifier() : aName.getStringIdentifier(); + } + + /** + * Checks whether the given {@link EObject} is of private visibility. + * + * @param anObject + * the object to check + * @return true or false (will return false on objects which don't support a visibility modifier) + */ + public static boolean isPrivate(EObject anObject) { + if (anObject instanceof VariableDefinition) { + return ((VariableDefinition) anObject).getPrivate() != null; + } else if (anObject instanceof ConstantDefinition) { + return ((ConstantDefinition) anObject).getPrivate() != null; + } else if (anObject instanceof SuiteDefinition) { + return ((SuiteDefinition) anObject).getPrivate() != null; + } else if (anObject instanceof ForkDefinition) { + return ((ForkDefinition) anObject).getPrivate() != null; + } + + return false; + } + + /** + * Attempts to extract a {@link VariableOrConstantEntity} from the provided {@link ValueOrEnumValueOrOperation}. + * + * @param anInput + * the input value + * @return the entity if one is found, null if the input value was something else + */ + public static VariableOrConstantEntity extractVariableOrConstantEntity(ValueOrEnumValueOrOperation anInput) { + if (anInput instanceof VariableOrConstantEntity) { + return (VariableOrConstantEntity) anInput; + } else if (anInput instanceof Variable) { + return ((Variable) anInput).getName(); + } else if (anInput instanceof Constant) { + return ((Constant) anInput).getName(); + } + + return null; + } + +} diff --git a/de.gebit.integrity.runner/src/de/gebit/integrity/runner/comparator/DefaultResultComparator.java b/de.gebit.integrity.runner/src/de/gebit/integrity/runner/comparator/DefaultResultComparator.java index 1487a1e3b..3810b0471 100644 --- a/de.gebit.integrity.runner/src/de/gebit/integrity/runner/comparator/DefaultResultComparator.java +++ b/de.gebit.integrity.runner/src/de/gebit/integrity/runner/comparator/DefaultResultComparator.java @@ -30,12 +30,14 @@ import de.gebit.integrity.dsl.ValueOrEnumValueOrOperation; import de.gebit.integrity.dsl.ValueOrEnumValueOrOperationCollection; import de.gebit.integrity.dsl.Variable; +import de.gebit.integrity.dsl.VariableOrConstantEntity; import de.gebit.integrity.fixtures.FixtureWrapper; import de.gebit.integrity.operations.UnexecutableException; import de.gebit.integrity.parameter.conversion.UnresolvableVariableHandling; import de.gebit.integrity.parameter.conversion.ValueConverter; import de.gebit.integrity.parameter.resolving.ParameterResolver; import de.gebit.integrity.utils.DateUtil; +import de.gebit.integrity.utils.IntegrityDSLUtil; import de.gebit.integrity.utils.ParameterUtil.UnresolvableVariableException; /** @@ -59,17 +61,31 @@ public class DefaultResultComparator implements ResultComparator { protected ParameterResolver parameterResolver; @Override - public ComparisonResult compareResult(Object aFixtureResult, - ValueOrEnumValueOrOperationCollection anExpectedResult, FixtureWrapper aFixtureInstance, - MethodReference aFixtureMethod, String aPropertyName) throws ClassNotFoundException, UnexecutableException, - InstantiationException { + public ComparisonResult compareResult(Object aFixtureResult, ValueOrEnumValueOrOperationCollection anExpectedResult, + FixtureWrapper aFixtureInstance, MethodReference aFixtureMethod, String aPropertyName) + throws ClassNotFoundException, UnexecutableException, InstantiationException { if (anExpectedResult != null) { if (aFixtureResult == null) { if (anExpectedResult.getMoreValues().size() > 0) { // if there's more than one value expected, this can never equal a single null value return SimpleComparisonResult.NOT_EQUAL; } else { - return SimpleComparisonResult.valueOf(anExpectedResult.getValue() instanceof NullValue); + boolean tempIsNull = false; + // This is only true if the expected result is also null. That could be directly... + if (anExpectedResult.getValue() instanceof NullValue) { + tempIsNull = true; + } else { + // ...or indirectly by the value being a variable/constant that resolves to a null value + VariableOrConstantEntity tempEntity = IntegrityDSLUtil + .extractVariableOrConstantEntity(anExpectedResult.getValue()); + if (tempEntity != null) { + Object tempResult = parameterResolver.resolveParameterValue(anExpectedResult, + UnresolvableVariableHandling.RESOLVE_TO_NULL_VALUE); + tempIsNull = (tempResult == null || (tempResult instanceof NullValue)); + } + } + + return SimpleComparisonResult.valueOf(tempIsNull); } } else { if (aFixtureInstance.isCustomComparatorFixture()) { @@ -82,8 +98,8 @@ public ComparisonResult compareResult(Object aFixtureResult, tempConversionTargetType = aFixtureInstance.determineCustomConversionTargetType(aFixtureResult, tempMethodName, aPropertyName); } else { - tempConversionTargetType = aFixtureResult.getClass().isArray() ? aFixtureResult.getClass() - .getComponentType() : aFixtureResult.getClass(); + tempConversionTargetType = aFixtureResult.getClass().isArray() + ? aFixtureResult.getClass().getComponentType() : aFixtureResult.getClass(); } if (anExpectedResult.getMoreValues().size() > 0) { @@ -94,8 +110,8 @@ public ComparisonResult compareResult(Object aFixtureResult, tempConvertedResult = Array.newInstance(tempArrayType, anExpectedResult.getMoreValues().size() + 1); for (int i = 0; i < Array.getLength(tempConvertedResult); i++) { - ValueOrEnumValueOrOperation tempSingleExpectedResult = (i == 0 ? anExpectedResult - .getValue() : anExpectedResult.getMoreValues().get(i - 1)); + ValueOrEnumValueOrOperation tempSingleExpectedResult = (i == 0 ? anExpectedResult.getValue() + : anExpectedResult.getMoreValues().get(i - 1)); Array.set(tempConvertedResult, i, valueConverter.convertValue(tempConversionTargetType, tempSingleExpectedResult, null)); } @@ -110,15 +126,15 @@ public ComparisonResult compareResult(Object aFixtureResult, // Standard comparation compares each value for itself in case of arrays if (anExpectedResult.getMoreValues().size() > 0) { // multiple result values were given -> fixture result must be an array of same size - if (!(aFixtureResult.getClass().isArray() && Array.getLength(aFixtureResult) == anExpectedResult - .getMoreValues().size() + 1)) { + if (!(aFixtureResult.getClass().isArray() + && Array.getLength(aFixtureResult) == anExpectedResult.getMoreValues().size() + 1)) { return SimpleComparisonResult.NOT_EQUAL; } // now compare all values for (int i = 0; i < Array.getLength(aFixtureResult); i++) { Object tempSingleFixtureResult = Array.get(aFixtureResult, i); - ValueOrEnumValueOrOperation tempSingleExpectedResult = (i == 0 ? anExpectedResult - .getValue() : anExpectedResult.getMoreValues().get(i - 1)); + ValueOrEnumValueOrOperation tempSingleExpectedResult = (i == 0 ? anExpectedResult.getValue() + : anExpectedResult.getMoreValues().get(i - 1)); if (tempSingleFixtureResult == null) { // The fixture returned a null, we need to expect a null if (!(tempSingleExpectedResult instanceof NullValue)) { @@ -142,13 +158,13 @@ public ComparisonResult compareResult(Object aFixtureResult, if (tempSingleFixtureResult instanceof byte[]) { byte[] tempConvertedExpectedResult = (byte[]) valueConverter.convertValue(byte[].class, tempSingleExpectedResult, null); - return SimpleComparisonResult.valueOf(Arrays.equals((byte[]) tempSingleFixtureResult, - tempConvertedExpectedResult)); + return SimpleComparisonResult.valueOf( + Arrays.equals((byte[]) tempSingleFixtureResult, tempConvertedExpectedResult)); } else if (tempSingleFixtureResult instanceof Byte[]) { Byte[] tempConvertedExpectedResult = (Byte[]) valueConverter.convertValue(Byte[].class, tempSingleExpectedResult, null); - return SimpleComparisonResult.valueOf(Arrays.equals((Byte[]) tempSingleFixtureResult, - tempConvertedExpectedResult)); + return SimpleComparisonResult.valueOf( + Arrays.equals((Byte[]) tempSingleFixtureResult, tempConvertedExpectedResult)); } // The fixture might still have returned an array. @@ -188,8 +204,8 @@ public ComparisonResult compareResult(Object aFixtureResult, } } else { if (aFixtureInstance.isCustomComparatorFixture()) { - return aFixtureInstance.performCustomComparation(null, aFixtureResult, aFixtureMethod.getMethod() - .getSimpleName(), aPropertyName); + return aFixtureInstance.performCustomComparation(null, aFixtureResult, + aFixtureMethod.getMethod().getSimpleName(), aPropertyName); } else { if (aFixtureResult instanceof Boolean) { return SimpleComparisonResult.valueOf((Boolean) aFixtureResult); @@ -283,11 +299,9 @@ protected ComparisonResult convertAndPerformEqualityCheck(Object aSingleFixtureR protected ComparisonResult performEqualityCheck(Object aConvertedResult, Object aConvertedExpectedResult, ValueOrEnumValueOrOperation aRawExpectedResult) { if (aConvertedResult == null) { - return SimpleComparisonResult - .valueOf(aConvertedExpectedResult == null - || (aConvertedExpectedResult.getClass().isArray() - && Array.getLength(aConvertedExpectedResult) == 1 && Array.get( - aConvertedExpectedResult, 0) == null)); + return SimpleComparisonResult.valueOf(aConvertedExpectedResult == null + || (aConvertedExpectedResult.getClass().isArray() && Array.getLength(aConvertedExpectedResult) == 1 + && Array.get(aConvertedExpectedResult, 0) == null)); } else { if (aConvertedResult instanceof Date && aConvertedExpectedResult instanceof Date) { return performEqualityCheckForDates((Date) aConvertedResult, (Date) aConvertedExpectedResult, @@ -375,8 +389,9 @@ protected MapComparisonResult performEqualityCheckForMaps(Map aResult, Map // since even though both outer values are maps, their inner values have not been necessarily converted // to the same types try { - tempConvertedReferenceValue = (tempActualValue != null) ? valueConverter.convertValue( - tempActualValue.getClass(), tempReferenceValue, null) : tempReferenceValue; + tempConvertedReferenceValue = (tempActualValue != null) + ? valueConverter.convertValue(tempActualValue.getClass(), tempReferenceValue, null) + : tempReferenceValue; } catch (UnresolvableVariableException exc) { exc.printStackTrace(); } catch (UnexecutableException exc) { @@ -384,11 +399,9 @@ protected MapComparisonResult performEqualityCheckForMaps(Map aResult, Map } } - ComparisonResult tempInnerResult = performEqualityCheck( - tempActualValue, - tempConvertedReferenceValue, - (tempReferenceValue instanceof ValueOrEnumValueOrOperation) ? (ValueOrEnumValueOrOperation) tempReferenceValue - : null); + ComparisonResult tempInnerResult = performEqualityCheck(tempActualValue, tempConvertedReferenceValue, + (tempReferenceValue instanceof ValueOrEnumValueOrOperation) + ? (ValueOrEnumValueOrOperation) tempReferenceValue : null); if (!tempInnerResult.isSuccessful()) { tempSuccess = false; @@ -423,12 +436,12 @@ protected ComparisonResult performEqualityCheckForDates(Date aResult, Date anExp Object aRawExpectedResult) { if (aRawExpectedResult instanceof DateValue) { // compare only the date part - return SimpleComparisonResult.valueOf(DateUtil.stripTimeFromDate((Date) anExpectedResult).equals( - DateUtil.stripTimeFromDate((Date) aResult))); + return SimpleComparisonResult.valueOf(DateUtil.stripTimeFromDate((Date) anExpectedResult) + .equals(DateUtil.stripTimeFromDate((Date) aResult))); } else if (aRawExpectedResult instanceof TimeValue) { // compare only the time part - return SimpleComparisonResult.valueOf(DateUtil.stripDateFromTime((Date) anExpectedResult).equals( - DateUtil.stripDateFromTime((Date) aResult))); + return SimpleComparisonResult.valueOf(DateUtil.stripDateFromTime((Date) anExpectedResult) + .equals(DateUtil.stripDateFromTime((Date) aResult))); } else { // compare both parts return SimpleComparisonResult.valueOf(anExpectedResult.equals(aResult)); diff --git a/de.gebit.integrity.tests/integrity/suites/basic/suitecalls/suiteCallsWithParameters.integrity b/de.gebit.integrity.tests/integrity/suites/basic/suitecalls/suiteCallsWithParameters.integrity index 03bb4f0a5..56061cd92 100644 --- a/de.gebit.integrity.tests/integrity/suites/basic/suitecalls/suiteCallsWithParameters.integrity +++ b/de.gebit.integrity.tests/integrity/suites/basic/suitecalls/suiteCallsWithParameters.integrity @@ -1,67 +1,80 @@ -packagedef integrity.basic.suitecalls with - - suitedef simpleSuiteCallsWithParameters with - // Call with no parameters at all - suite testSuiteSingleParam - suite testSuiteMultiParam - - // Call with one parameter - suite testSuiteSingleParam param1: "Foobar" - suite testSuiteMultiParam param1: "Foobar" - - // Call with two parameters - suite testSuiteMultiParam param1: "Foo" param2: "Bar" - - // Call with constant - constant testConstant "Foobar" - suite testSuiteSingleParam param1: testConstant - - // Call with variable - variable testVariable initially "Foobar" - suite testSuiteSingleParam param1: testVariable - suiteend - - // This test is similar to the above one, but it uses sub-suites that have defaults given for their parameters - suitedef defaultUsingSuiteCallsWithParameters with - // Call with no parameters at all - suite testSuiteSingleParamWithDefault - suite testSuiteMultiParamWithDefault - - // Call with one parameter - suite testSuiteSingleParamWithDefault param1: "Foobar" - suite testSuiteMultiParamWithDefault param1: "Foobar" - - // Call with two parameters - suite testSuiteMultiParamWithDefault param1: "Foo" param2: "Bar" - - // Call with constant - constant testConstant "Foobar" - suite testSuiteSingleParamWithDefault param1: testConstant - - // Call with variable - variable testVariable initially "Foobar" - suite testSuiteSingleParamWithDefault param1: testVariable - suiteend - - - suitedef testSuiteSingleParam gets param1 with - call integrity.fixtures.basic.noop.echoString string: param1 - suiteend - - suitedef testSuiteMultiParam gets param1 param2 with - call integrity.fixtures.basic.noop.echoString string: param1 - call integrity.fixtures.basic.noop.echoString string: param2 - suiteend - - suitedef testSuiteSingleParamWithDefault gets param1 by default "FOOBAR!" with - call integrity.fixtures.basic.noop.echoString string: param1 - suiteend - - constant testPackageConstant "BAR!" - - suitedef testSuiteMultiParamWithDefault gets param1 by default "FOO!" param2 by default testPackageConstant with - call integrity.fixtures.basic.noop.echoString string: param1 - call integrity.fixtures.basic.noop.echoString string: param2 - suiteend - +packagedef integrity.basic.suitecalls with + + suitedef simpleSuiteCallsWithParameters with + // Call with no parameters at all + suite testSuiteSingleParam + suite testSuiteMultiParam + + // Call with one parameter + suite testSuiteSingleParam param1: "Foobar" + suite testSuiteMultiParam param1: "Foobar" + + // Call with two parameters + suite testSuiteMultiParam param1: "Foo" param2: "Bar" + + // Call with constant + constant testConstant "Foobar" + suite testSuiteSingleParam param1: testConstant + + // Call with variable + variable testVariable initially "Foobar" + suite testSuiteSingleParam param1: testVariable + suiteend + + // This test is similar to the above one, but it uses sub-suites that have defaults given for their parameters + suitedef defaultUsingSuiteCallsWithParameters with + // Call with no parameters at all + suite testSuiteSingleParamWithDefault + suite testSuiteMultiParamWithDefault + + // Call with one parameter + suite testSuiteSingleParamWithDefault param1: "Foobar" + suite testSuiteMultiParamWithDefault param1: "Foobar" + + // Call with two parameters + suite testSuiteMultiParamWithDefault param1: "Foo" param2: "Bar" + + // Call with constant + constant testConstant "Foobar" + suite testSuiteSingleParamWithDefault param1: testConstant + + // Call with variable + variable testVariable initially "Foobar" + suite testSuiteSingleParamWithDefault param1: testVariable + suiteend + + + suitedef testSuiteSingleParam gets param1 with + call integrity.fixtures.basic.noop.echoString string: param1 + suiteend + + suitedef testSuiteMultiParam gets param1 param2 with + call integrity.fixtures.basic.noop.echoString string: param1 + call integrity.fixtures.basic.noop.echoString string: param2 + suiteend + + suitedef testSuiteSingleParamWithDefault gets param1 by default "FOOBAR!" with + call integrity.fixtures.basic.noop.echoString string: param1 + suiteend + + constant testPackageConstant "BAR!" + + suitedef testSuiteMultiParamWithDefault gets param1 by default "FOO!" param2 by default testPackageConstant with + call integrity.fixtures.basic.noop.echoString string: param1 + call integrity.fixtures.basic.noop.echoString string: param2 + suiteend + + + suitedef suiteCallWithNullParameter with + // Tests the problem described in issue #113: Pushing 'null' as an entity into suites via suite params converts it to the string 'null' + + suite suiteCallWithNullParameterTestSuite param: "foo" // this is expected to fail + suite suiteCallWithNullParameterTestSuite param: null // this test should succeed + suiteend + + suitedef suiteCallWithNullParameterTestSuite gets param with + test integrity.fixtures.basic.noop.echoStringTest string: null = param + suiteend + + packageend \ No newline at end of file diff --git a/de.gebit.integrity.tests/junit/de/gebit/integrity/tests/junit/basic/suitecalls/SuiteCallsWithParameters.java b/de.gebit.integrity.tests/junit/de/gebit/integrity/tests/junit/basic/suitecalls/SuiteCallsWithParameters.java index 8c8054afc..89c83024f 100644 --- a/de.gebit.integrity.tests/junit/de/gebit/integrity/tests/junit/basic/suitecalls/SuiteCallsWithParameters.java +++ b/de.gebit.integrity.tests/junit/de/gebit/integrity/tests/junit/basic/suitecalls/SuiteCallsWithParameters.java @@ -1,58 +1,73 @@ -/******************************************************************************* - * Copyright (c) 2013 Rene Schneider, GEBIT Solutions GmbH and others. - * 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 - *******************************************************************************/ -package de.gebit.integrity.tests.junit.basic.suitecalls; - -import java.io.IOException; - -import org.jdom.Document; -import org.jdom.JDOMException; -import org.junit.Test; - -import de.gebit.integrity.runner.exceptions.ModelLoadException; -import de.gebit.integrity.tests.junit.IntegrityJUnitTest; - -/** - * JUnit test which performs some suite call tests. - * - * - * @author Rene Schneider - initial API and implementation - * - */ -public class SuiteCallsWithParameters extends IntegrityJUnitTest { - - /** - * Tests suite calls with parameters. - * - * @throws ModelLoadException - * @throws IOException - * @throws JDOMException - */ - @Test - public void testSimpleSuiteCallsWithParameters() throws ModelLoadException, IOException, JDOMException { - Document tempResult = executeIntegritySuite( - new String[] { "integrity/suites/basic/suitecalls/suiteCallsWithParameters.integrity" }, - "integrity.basic.suitecalls.simpleSuiteCallsWithParameters", null); - assertDocumentMatchesReference(tempResult); - } - - /** - * Tests suite calls with parameters which have defaults. - * - * @throws ModelLoadException - * @throws IOException - * @throws JDOMException - */ - @Test - public void testDefaultUsingSuiteCallsWithParameters() throws ModelLoadException, IOException, JDOMException { - Document tempResult = executeIntegritySuite( - new String[] { "integrity/suites/basic/suitecalls/suiteCallsWithParameters.integrity" }, - "integrity.basic.suitecalls.defaultUsingSuiteCallsWithParameters", null); - assertDocumentMatchesReference(tempResult); - } - -} +/******************************************************************************* + * Copyright (c) 2013 Rene Schneider, GEBIT Solutions GmbH and others. + * 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 + *******************************************************************************/ +package de.gebit.integrity.tests.junit.basic.suitecalls; + +import java.io.IOException; + +import org.jdom.Document; +import org.jdom.JDOMException; +import org.junit.Test; + +import de.gebit.integrity.runner.exceptions.ModelLoadException; +import de.gebit.integrity.tests.junit.IntegrityJUnitTest; + +/** + * JUnit test which performs some suite call tests. + * + * + * @author Rene Schneider - initial API and implementation + * + */ +public class SuiteCallsWithParameters extends IntegrityJUnitTest { + + /** + * Tests suite calls with parameters. + * + * @throws ModelLoadException + * @throws IOException + * @throws JDOMException + */ + @Test + public void testSimpleSuiteCallsWithParameters() throws ModelLoadException, IOException, JDOMException { + Document tempResult = executeIntegritySuite( + new String[] { "integrity/suites/basic/suitecalls/suiteCallsWithParameters.integrity" }, + "integrity.basic.suitecalls.simpleSuiteCallsWithParameters", null); + assertDocumentMatchesReference(tempResult); + } + + /** + * Tests suite calls with parameters which have defaults. + * + * @throws ModelLoadException + * @throws IOException + * @throws JDOMException + */ + @Test + public void testDefaultUsingSuiteCallsWithParameters() throws ModelLoadException, IOException, JDOMException { + Document tempResult = executeIntegritySuite( + new String[] { "integrity/suites/basic/suitecalls/suiteCallsWithParameters.integrity" }, + "integrity.basic.suitecalls.defaultUsingSuiteCallsWithParameters", null); + assertDocumentMatchesReference(tempResult); + } + + /** + * Tests suite calls with parameter of null value. See issue #113. + * + * @throws ModelLoadException + * @throws IOException + * @throws JDOMException + */ + @Test + public void testSuiteCallWithNullParameter() throws ModelLoadException, IOException, JDOMException { + Document tempResult = executeIntegritySuite( + new String[] { "integrity/suites/basic/suitecalls/suiteCallsWithParameters.integrity" }, + "integrity.basic.suitecalls.suiteCallWithNullParameter", null); + assertDocumentMatchesReference(tempResult); + } + +} diff --git a/de.gebit.integrity.tests/results/integrity.basic.suitecalls.suiteCallWithNullParameter.xml b/de.gebit.integrity.tests/results/integrity.basic.suitecalls.suiteCallWithNullParameter.xml new file mode 100644 index 000000000..e8dbf4063 --- /dev/null +++ b/de.gebit.integrity.tests/results/integrity.basic.suitecalls.suiteCallWithNullParameter.xml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +