/******************************************************************************* | |
* Copyright (c) 1998, 2013 Oracle and/or its affiliates. All rights reserved. | |
* This program and the accompanying materials are made available under the | |
* terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 | |
* which accompanies this distribution. | |
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html | |
* and the Eclipse Distribution License is available at | |
* http://www.eclipse.org/org/documents/edl-v10.php. | |
* | |
* Contributors: | |
* Oracle - initial API and implementation from Oracle TopLink | |
******************************************************************************/ | |
package org.eclipse.persistence.testing.framework; | |
import java.lang.reflect.Field; | |
import java.lang.reflect.Method; | |
import java.util.Enumeration; | |
import java.util.Vector; | |
/** | |
* <p>Purpose<b></b>:Creates several variations of the passed TestCase | |
* (or of each member of a Vector of TestCases) using all combinations | |
* of values of the specified boolean attributes on the specified object. | |
* Suppose we want to run an existing test with four different DatabasePlatform settings: | |
* shouldBindAllParameters shouldCacheAllStatements | |
* false false | |
* false true | |
* true false | |
* true true | |
* All we should do is to substitute: | |
* testSuite.addTest(test); | |
* for: | |
* Object obj = getSession().getPlatform(); | |
* String str = "shouldBindAllParameters shouldCacheAllStatements" | |
* testSuite.addTests(TestVariation.get(obj, str, test)); | |
* The attributes names should be separated by a space. | |
* Reflection is used to find a getter and a setter for the specified attribute: | |
* the list of all the methods with appropriate signature is examined, and the first | |
* method with a name containing the specified name (case insensitive comparison) is used. | |
* Therefore if the name passed is "foo", both "getFoo" and "setFoo" will be found, | |
* but if there also a "getFooo" and "setFooo" methods, they could be wrongly picked up. | |
* If the getter/setter pair, or a field for the specified name is not found, | |
* a TestWarningException is thrown. | |
*/ | |
public class TestVariation { | |
protected static char separator = ' '; | |
public static Vector get(Object object, String str, TestCase test) { | |
Vector testsIn = new Vector(1); | |
testsIn.add(test); | |
return get(object, str, testsIn); | |
} | |
public static Vector get(Object object, String str, Vector testsIn) { | |
Vector names = getNames(str); | |
Vector testsOut = new Vector(); | |
if (names.isEmpty() || testsIn.isEmpty()) { | |
return testsOut; | |
} | |
Vector getters = new Vector(); | |
Vector setters = new Vector(); | |
Vector fields = new Vector(); | |
getMembers(object.getClass(), names, getters, setters, fields, true); | |
int numberOfTests = (int)java.lang.Math.pow(2, names.size()); | |
for (int i = 0; i < numberOfTests; i++) { | |
Enumeration enumtr = testsIn.elements(); | |
while (enumtr.hasMoreElements()) { | |
TestWrapper testWrapper = createTest(i, object, names, getters, setters, fields, (TestCase)enumtr.nextElement()); | |
testsOut.addElement(testWrapper); | |
} | |
} | |
return testsOut; | |
} | |
protected static Vector getNames(String str) { | |
Vector names = new Vector(); | |
String[] strPair = splitString(str); | |
while (strPair[0] != null) { | |
names.addElement(strPair[0]); | |
strPair = splitString(strPair[1]); | |
} | |
return names; | |
} | |
protected static InnerTestWrapper createTest(int index, Object object, Vector names, Vector getters, Vector setters, Vector fields, TestCase test) { | |
boolean[] values = new boolean[names.size()]; | |
int i = 0; | |
while (index > 0) { | |
values[i] = (index % 2) == 1; | |
i++; | |
index = index / 2; | |
} | |
String[] namesArray = new String[names.size()]; | |
namesArray = (String[])names.toArray(namesArray); | |
Method[] gettersArray = new Method[names.size()]; | |
gettersArray = (Method[])getters.toArray(gettersArray); | |
Method[] settersArray = new Method[names.size()]; | |
settersArray = (Method[])setters.toArray(settersArray); | |
Field[] fieldsArray = new Field[names.size()]; | |
fieldsArray = (Field[])fields.toArray(fieldsArray); | |
return new InnerTestWrapper(test, object, values, namesArray, gettersArray, settersArray, fieldsArray); | |
} | |
protected static String[] splitString(String str) { | |
String[] out = new String[2]; | |
out[0] = null; | |
out[1] = null; | |
if (str == null) { | |
return out; | |
} | |
int first = -1; | |
int lastPlusOne = str.length(); | |
for (int i = 0; i < str.length(); i++) { | |
char ch = str.charAt(i); | |
if (first == -1) { | |
if (ch != separator) { | |
first = i; | |
} | |
} else { | |
if (ch == separator) { | |
lastPlusOne = i; | |
break; | |
} | |
} | |
} | |
if (first == -1) { | |
return out; | |
} | |
out[0] = str.substring(first, lastPlusOne); | |
out[1] = str.substring(lastPlusOne, str.length()); | |
return out; | |
} | |
protected static void getMembers(Class cls, Vector names, Vector getters, Vector setters, Vector fields, boolean throwExceptionIfNotFound) { | |
Method[] allMethods = cls.getMethods(); | |
Field[] allFields = cls.getFields(); | |
Vector candidateGetters = new Vector(); | |
Vector candidateSetters = new Vector(); | |
Vector candidateFields = new Vector(); | |
// Need those to save lower case names | |
Vector candidateGettersNames = new Vector(); | |
Vector candidateSettersNames = new Vector(); | |
Vector candidateFieldsNames = new Vector(); | |
for (int i = 0; i < allMethods.length; i++) { | |
Class returnType = allMethods[i].getReturnType(); | |
Class[] parameterTypes = allMethods[i].getParameterTypes(); | |
if (returnType.equals(boolean.class) && (parameterTypes.length == 0)) { | |
candidateGetters.addElement(allMethods[i]); | |
candidateGettersNames.addElement(allMethods[i].getName().toLowerCase()); | |
} else if (returnType.equals(void.class) && (parameterTypes.length == 1)) { | |
if (parameterTypes[0].equals(boolean.class)) { | |
candidateSetters.addElement(allMethods[i]); | |
candidateSettersNames.addElement(allMethods[i].getName().toLowerCase()); | |
} | |
} | |
} | |
for (int i = 0; i < allFields.length; i++) { | |
Class type = allFields[i].getType(); | |
if (type.equals(boolean.class)) { | |
candidateFields.addElement(allFields[i]); | |
candidateFieldsNames.addElement(allFields[i].getName().toLowerCase()); | |
} | |
} | |
for (int i = 0; i < names.size(); i++) { | |
Object getter = null; | |
Object setter = null; | |
Object field = null; | |
String name = ((String)names.elementAt(i)).toLowerCase(); | |
for (int j = 0; j < candidateGetters.size(); j++) { | |
if (((String)candidateGettersNames.elementAt(j)).indexOf(name) != -1) { | |
getter = candidateGetters.elementAt(j); | |
candidateGetters.remove(j); | |
candidateGettersNames.remove(j); | |
break; | |
} | |
} | |
for (int j = 0; j < candidateSetters.size(); j++) { | |
if (((String)candidateSettersNames.elementAt(j)).indexOf(name) != -1) { | |
setter = candidateSetters.elementAt(j); | |
candidateSetters.remove(j); | |
candidateSettersNames.remove(j); | |
break; | |
} | |
} | |
for (int j = 0; j < candidateFields.size(); j++) { | |
if (((String)candidateFieldsNames.elementAt(j)).indexOf(name) != -1) { | |
field = candidateFields.elementAt(j); | |
candidateFields.remove(j); | |
candidateFieldsNames.remove(j); | |
break; | |
} | |
} | |
if ((field != null) || ((setter != null) && (getter != null))) { | |
setters.add(setter); | |
getters.add(getter); | |
fields.add(field); | |
} else { | |
if (throwExceptionIfNotFound) { | |
throw new TestWarningException("Can't find a setter/getter or field for " + names.elementAt(i)); | |
} else { | |
names.remove(i); | |
i--; | |
} | |
} | |
} | |
} | |
protected static class InnerTestWrapper extends TestWrapper { | |
protected Object object; | |
private Field[] fields; | |
private Method[] getters; | |
private Method[] setters; | |
private boolean[] required; | |
private boolean[] original; | |
public InnerTestWrapper(TestCase test, Object object, boolean[] values, String[] names, Method[] getters, Method[] setters, Field[] fields) { | |
super(test); | |
this.object = object; | |
original = new boolean[values.length]; | |
required = new boolean[values.length]; | |
this.getters = getters; | |
this.setters = setters; | |
this.fields = fields; | |
System.arraycopy(values, 0, required, 0, values.length); | |
for (int i = 0; i < values.length; i++) { | |
String name; | |
if (fields[i] != null) { | |
name = fields[i].getName(); | |
} else { | |
name = names[i]; | |
} | |
setName(getName() + " " + name + "=" + values[i]); | |
} | |
} | |
protected void setup() throws Throwable { | |
for (int i = 0; i < required.length; i++) { | |
if (getters[i] != null) { | |
Object[] args = { }; | |
Boolean res = (Boolean)getters[i].invoke(object, args); | |
original[i] = res.booleanValue(); | |
} else { | |
original[i] = fields[i].getBoolean(object); | |
} | |
if (setters[i] != null) { | |
Object[] args = { new Boolean(required[i]) }; | |
setters[i].invoke(object, args); | |
} else { | |
fields[i].setBoolean(object, required[i]); | |
} | |
} | |
super.setup(); | |
} | |
public void reset() throws Throwable { | |
super.reset(); | |
for (int i = required.length - 1; i >= 0; i--) { | |
if (setters[i] != null) { | |
Object[] args = { new Boolean(original[i]) }; | |
setters[i].invoke(object, args); | |
} else { | |
fields[i].setBoolean(object, original[i]); | |
} | |
} | |
} | |
} | |
} |