www.pudn.com > bluecove-1.2.1-src.zip > APIDeclarationsTester.java, change:2007-01-07,size:15323b


package org.microemu;


import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Vector;

import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtField;
import junit.framework.AssertionFailedError;
import junit.framework.TestCase;

import org.codehaus.classworlds.ClassRealm;
import org.codehaus.classworlds.ClassWorld;

public class APIDeclarationsTester extends TestCase {

	protected boolean verbose = false;

	protected boolean reportOnly = true;

	protected boolean reportConstructors = true;
	
	protected boolean reportExtra = true;
	
	private int classDiffCount = 0;
	
	public APIDeclarationsTester() {

	}

	public APIDeclarationsTester(String name) {
		super(name);
	}

	
	protected ClassLoader getClassLoader(List jarURLList) throws Exception {
		ClassWorld world = new ClassWorld();
		ClassRealm containerRealm = world.newRealm("container");
		for (Iterator i = jarURLList.iterator(); i.hasNext();) {
			containerRealm.addConstituent((URL) i.next());
		}
		return containerRealm.getClassLoader();
	}

	protected ClassPool getClassPool(List jarURLList) throws Exception {
		ClassPool refClassPool = new ClassPool();
		for (Iterator i = jarURLList.iterator(); i.hasNext();) {
			refClassPool.appendClassPath(((URL) i.next()).getFile());
		}
		return refClassPool;
	}

	protected void verifyClassList(List names, ClassLoader refLoader, ClassLoader implLoader, ClassPool refClassPool)
			throws Exception {
		for (Iterator i = names.iterator(); i.hasNext();) {
			verifyClass(refLoader, implLoader, (String) i.next(), refClassPool);
		}
	}

	protected void verifyClass(ClassLoader refLoader, ClassLoader implLoader, String className, ClassPool refClassPool)
			throws Exception {
		classDiffCount = 0;
		if (verbose) {
			System.out.println("Testing class " + className);
		}

		Class refClass = refLoader.loadClass(className);
		Class implClass;
		try {
			implClass = implLoader.loadClass(className);
		} catch (ClassNotFoundException e) {
			reportFail(className + " not implemented");
			return;
		}

		String classResourceName = className.replace('.', '/') + ".class";
		URL implURL = implLoader.getResource(classResourceName);
		URL refURL = refLoader.getResource(classResourceName);

		if (verbose) {
			System.out.println("Found ref class " + refURL);
			System.out.println("Found impl class " + implURL);
		}

		reportTrue(className + " Reference class not in jar", refURL.toExternalForm().startsWith("jar"));

		reportFalse(className + " Implementation and Reference classes are mixed-up", refURL.sameFile(implURL));

		compareClasses(refClass, implClass, className, refClassPool);
//		if ((classDiffCount > 0) && (!verbose)) {
//			System.out.println("Found impl class " + implURL);
//		}
	}

	public void reportFail(String message) {
		if (reportOnly) {
			System.out.println(message);
			classDiffCount++;
		} else {
			fail(message);
		}
	}

	public void reportTrue(String message, boolean condition) {
		try {
			assertTrue(message, condition);
		} catch (AssertionFailedError e) {
			if (reportOnly) {
				System.out.println(e.getMessage());
				classDiffCount++;
			} else {
				throw e;
			}
		}
	}

	public void reportFalse(String message, boolean condition) {
		try {
			assertFalse(message, condition);
		} catch (AssertionFailedError e) {
			if (reportOnly) {
				System.out.println(e.getMessage());
				classDiffCount++;
			} else {
				throw e;
			}
		}
	}

	public void reportEquals(String message, boolean expected, boolean actual) {
		try {
			assertEquals(message, expected, actual);
		} catch (AssertionFailedError e) {
			if (reportOnly) {
				System.out.println(e.getMessage());
				classDiffCount++;
			} else {
				throw e;
			}
		}
	}

	public void reportEquals(String message, int expected, int actual) {
		try {
			assertEquals(message, expected, actual);
		} catch (AssertionFailedError e) {
			if (reportOnly) {
				System.out.println(e.getMessage());
				classDiffCount++;
			} else {
				throw e;
			}
		}
	}

	public void reportEquals(String message, String expected, String actual) {
		try {
			assertEquals(message, expected, actual);
		} catch (AssertionFailedError e) {
			if (reportOnly) {
				System.out.println(e.getMessage());
				classDiffCount++;
			} else {
				throw e;
			}
		}
	}

	public void reportNotNull(String message, Object object) {
		try {
			assertNotNull(message, object);
		} catch (AssertionFailedError e) {
			if (reportOnly) {
				System.out.println(e.getMessage());
				classDiffCount++;
			} else {
				throw e;
			}
		}
	}

	public void reportNull(String message, Object object) {
		try {
			assertNull(message, object);
		} catch (AssertionFailedError e) {
			if (reportOnly) {
				System.out.println(e.getMessage());
				classDiffCount++;
			} else {
				throw e;
			}
		}
	}
	
	public static String getSimpleName(Object obj) {
		// Java 1.5
		// obj.getClass().getSimpleName()
        String simpleName = obj.getClass().getName();
        // strip the package name
        return simpleName.substring(simpleName.lastIndexOf(".") + 1);
    }

	private void compareClasses(Class refClass, Class implClass, String className, ClassPool refClassPool)
			throws Exception {

		reportEquals(className + " isInterface", refClass.isInterface(), implClass.isInterface());
		reportEquals(className + " getModifiers", refClass.getModifiers(), implClass.getModifiers());

		Class[] refInterfaces = refClass.getInterfaces();
		Class[] implInterfaces = implClass.getInterfaces();

		if (verbose) {
			System.out.println("interfaces implemented " + implInterfaces.length);
		}

		reportEquals(className + " interfaces implemented", refInterfaces.length, implInterfaces.length);
		compareInterfaces(refInterfaces, implInterfaces, className);

		if (refClass.getSuperclass() != null) {
			reportEquals(className + "Superclass", refClass.getSuperclass().getName(), implClass.getSuperclass()
					.getName());
		} else {
			reportNull(className + "Superclass", implClass.getSuperclass());
		}

		// Constructors
		Constructor[] refConstructors = refClass.getDeclaredConstructors();
		Constructor[] implConstructors = implClass.getDeclaredConstructors();
		compareConstructors(refConstructors, implConstructors, className);

		// Methods
		Method[] refMethods = refClass.getDeclaredMethods();
		Method[] implMethods = implClass.getDeclaredMethods();
		compareMethods(refMethods, implMethods, className);

		// all accessible public fields
		Field[] refFields = refClass.getFields();
		Field[] implFields = implClass.getFields();
		compareFields(refFields, implFields, className, refClass, implClass, refClassPool);
	}

	private void compareInterfaces(Class[] refInterfaces, Class[] implInterfacess, String className) throws Exception {
		List implNames = new Vector();
		for (int i = 0; i  implInterfacess.length; i++) {
			implNames.add(implInterfacess[i].getName());
		}
		for (int i = 0; i  refInterfaces.length; i++) {
			String interfaceName = refInterfaces[i].getName();
			reportTrue(className + "Interface " + interfaceName, implNames.contains(interfaceName));
		}
	}

	private Map buildNameMap(Member[] members, String className) throws Exception {
		Map namesMap = new Hashtable();
		for (int i = 0; i  members.length; i++) {
			if (ignoreMember(members[i])) {
				//System.out.println("ignore " + members[i].getName());
				continue;
			}
			String name = getName4Map(members[i]);
			if (namesMap.containsKey(name)) {
				Member exists = (Member)namesMap.get(name);
				if (exists.getDeclaringClass().getName().equals(className)) {
					continue;
				}
				//throw new Error("duplicate member name " + name + " " + members[i].getName()+ " = " + ((Member)namesMap.get(name)).getName());
			}
			namesMap.put(name, members[i]);
		}
		return namesMap;
	}

	private boolean ignoreMember(Member member) {
		if (Modifier.isPublic(member.getModifiers())) {
			return false;
		} else if (Modifier.isProtected(member.getModifiers())) {
			return false;
		} else {
			return true;
		}
	}

	private int getModifiers(Member member) {
		int mod = member.getModifiers();
		if (Modifier.isNative(mod)) {
			mod = mod - Modifier.NATIVE;
		}
		return mod;
	}

	private void compareConstructors(Constructor[] refConstructors, Constructor[] implConstructors, String className)
			throws Exception {
		Map implNames = buildNameMap(implConstructors, className);
		int compared = 0;
		for (int i = 0; i  refConstructors.length; i++) {
			if (ignoreMember(refConstructors[i])) {
				continue;
			}
			compareConstructor(refConstructors[i], (Constructor) implNames.get(getName4Map(refConstructors[i])),
					className);
			compared++;
			implNames.remove(getName4Map(refConstructors[i]));
		}
		if (!reportConstructors) {
			return;
		}
		reportEquals(className + " number of Constructors ", compared, implNames.size() + compared);
		for (Iterator i = implNames.keySet().iterator(); i.hasNext();) {
			System.out.println("   extra constructor " + i.next());
		}

	}

	private void compareConstructor(Constructor refConstructor, Constructor implConstructor, String className)
			throws Exception {
		String name = refConstructor.getName();
		reportNotNull(className + " Constructor " + name + " is Missing", implConstructor);
		if (implConstructor == null) {
			return;
		}
		reportEquals(className + ". Constructor " + name + " getModifiers", Modifier
				.toString(getModifiers(refConstructor)), Modifier.toString(getModifiers(implConstructor)));
	}

	private void compareMember(Member refMember, Member implMember, String className) throws Exception {
		String name = refMember.getName();
		reportNotNull(className + "." + name + " is Missing", implMember);
		if (implMember == null) {
			return;
		}
		reportEquals(className + "." + name + " getModifiers", Modifier.toString(getModifiers(refMember)), Modifier
				.toString(getModifiers(implMember)));
	}

	private String getName4Map(Member member) {
		StringBuffer name = new StringBuffer();
		name.append(member.getName());
		if ((member instanceof Method) || (member instanceof Constructor)) {
			// Overloaded Methods should have different names
			Class[] param;
			if (member instanceof Method) {
				param = ((Method) member).getParameterTypes();
			} else if (member instanceof Constructor) {
				param = ((Constructor) member).getParameterTypes();
			} else {
				throw new Error("intenal test error");
			}
			name.append("(");
			for (int i = 0; i  param.length; i++) {
				if (i != 0) {
					name.append(" ,");
				}
				name.append(param[i].getName());
			}
			name.append(")");
		}
		return name.toString();
	}

	private void compareMethods(Method[] refMethods, Method[] implMethods, String className) throws Exception {
		Map implNames = buildNameMap(implMethods, className);
		int compared = 0;
		for (int i = 0; i  refMethods.length; i++) {
			if (ignoreMember(refMethods[i])) {
				continue;
			}
			compareMethod(refMethods[i], (Method) implNames.get(getName4Map(refMethods[i])), className);
			compared++;
			implNames.remove(getName4Map(refMethods[i]));
		}
		if (!reportExtra) {
			return;
		}
		reportEquals(className + " number of Methods ", compared, implNames.size() + compared);
		for (Iterator i = implNames.keySet().iterator(); i.hasNext();) {
			System.out.println("   extra method " + i.next());
		}
	}

	private void compareMethod(Method refMethod, Method implMethod, String className) throws Exception {
		compareMember(refMethod, implMethod, className);
		if (implMethod == null) {
			return;
		}
		String name = refMethod.getName();
		reportEquals(className + "." + name + " getReturnType", refMethod.getReturnType().getName(), implMethod
				.getReturnType().getName());
	}

	private void compareFields(Field[] refFields, Field[] implFields, String className, Class refClass,
			Class implClass, ClassPool refClassPool) throws Exception {
		Map implNames = buildNameMap(implFields, className);
		Map implNamesTested = new Hashtable();
		int compared = 0;
		for (int i = 0; i  refFields.length; i++) {
			if (ignoreMember(refFields[i])) {
				continue;
			}
			String name = getName4Map(refFields[i]);
			if (verbose) {
				System.out.println("compareField " + className + "." + refFields[i].getName());
			}
			Field impl = (Field) implNames.get(name);
			if ((impl == null) && (implNamesTested.containsKey(name))) {
				continue;
			}
			compareField(refFields[i], impl, className, refClass, implClass, refClassPool);
			compared++;
			implNamesTested.put(name, impl);
			implNames.remove(name);
		}
		if (!reportExtra) {
			return;
		}
		reportEquals(className + " number of Fields ", compared, implNames.size() + compared);
		for (Iterator i = implNames.keySet().iterator(); i.hasNext();) {
			System.out.println("   extra field " + i.next());
		}
	}
	
	private void compareField(Field refField, Field implField, String className, Class refClass, Class implClass,
			ClassPool refClassPool) throws Exception {
		String name = refField.getName();
		compareMember(refField, implField, className);
		if (implField == null) {
			return;
		}
		reportEquals(className + "." + name + " getType", refField.getType().getName(), implField.getType().getName());
		if ((Modifier.isFinal(refField.getModifiers())) && (Modifier.isStatic(refField.getModifiers()))) {
			// Compare value
			CtClass klass = refClassPool.get(className);
			CtField field = klass.getField(name);
			Object refConstValue = field.getConstantValue();
			Object implConstValue = implField.get(implClass);
			if (refConstValue == null) {
				if (implConstValue != null) {
					if (verbose) {
						System.out.println("Not implemented comparison for " + refField.getType().getName() + " of "
								+ className + "." + name);
					}
				}
				return;
			}

			String value = refConstValue.toString();
			String implValue = null;
			if (refField.getType().getName().equals("int")) {
				implValue = String.valueOf(implField.getInt(implClass));
			} else if (refField.getType().getName().equals("byte")) {
				implValue = String.valueOf(implField.getByte(implClass));
			} else if (refField.getType().getName().equals("long")) {
				implValue = String.valueOf(implField.getLong(implClass));
			} else if (refField.getType().getName().equals("java.lang.String")) {
				implValue = implField.get(implClass).toString();
			} else {
				System.out.println("Not implemented comparison for " + refField.getType().getName() + " of "
						+ className + "." + name);
			}
			reportEquals(className + "." + name + " value ", value, implValue);

			// //java.lang.UnsatisfiedLinkError: isNetworkMonitorActive
			// //at
            // javax.microedition.io.Connector.isNetworkMonitorActive(Native
            // Method)
			// if (refField.getType().getName().equals("int")) {
			// reportEquals(className + "." + name + " value ",
			// refField.getInt(refClass),
			// implField.getInt(implClass));
			// } else {
			// System.out.println("Not implemented comparison for " +
            // refField.getType().getName() + " of " + className + "." + name);
			// }
		} else {
			System.out.println("ignore comparison for " + className + "." + name);
		}
	}
}