Java tutorial
/* * Copyright 2010-2012 VMware and contributors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springsource.loaded.test; import static org.junit.Assert.fail; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.OutputStream; import java.io.PrintStream; import java.lang.reflect.Array; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Properties; import java.util.StringTokenizer; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.objectweb.asm.ClassReader; import org.objectweb.asm.Type; import org.objectweb.asm.tree.AnnotationNode; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.FieldNode; import org.objectweb.asm.tree.LocalVariableNode; import org.objectweb.asm.tree.MethodNode; import org.springsource.loaded.ClassRenamer; import org.springsource.loaded.Constants; import org.springsource.loaded.ISMgr; import org.springsource.loaded.MethodMember; import org.springsource.loaded.NameRegistry; import org.springsource.loaded.ReloadableType; import org.springsource.loaded.SSMgr; import org.springsource.loaded.TypeDescriptor; import org.springsource.loaded.TypeRegistry; import org.springsource.loaded.Utils; import org.springsource.loaded.agent.SpringLoadedPreProcessor; import org.springsource.loaded.test.ReloadingJVM.JVMOutput; import org.springsource.loaded.test.infra.ClassPrinter; import org.springsource.loaded.test.infra.MethodPrinter; import org.springsource.loaded.test.infra.Result; import org.springsource.loaded.test.infra.ResultException; import org.springsource.loaded.test.infra.TestClassLoader; /** * Abstract root test class containing helper functions. * * @author Andy Clement * @since 1.0 */ public abstract class SpringLoadedTests implements Constants { /** * Classloader that can be used to see things in the bin directory, it is initialised ready for each test to use. */ protected ClassLoader binLoader; protected String TestDataPath = TestUtils.getPathToClasses("../testdata"); protected String TestDataAspectJPath = TestUtils.getPathToClasses("../testdata-aspectj"); protected String GroovyTestDataPath = TestUtils.getPathToClasses("../testdata-groovy"); protected String AspectjrtJar = "../testdata/aspectjrt.jar"; protected String CodeJar = "../testdata/code.jar"; // TODO [java8] replace this with project dependency when Java8 is out protected String Java8CodeJar = findJar("../testdata-java8/build/libs", "testdata-java8"); protected String GroovyrtJar = "../testdata-groovy/groovy-all-1.8.6.jar"; protected Result result; protected TypeRegistry registry; @Before public void setup() throws Exception { SpringLoadedPreProcessor.disabled = true; NameRegistry.reset(); binLoader = new TestClassLoader( toURLs(TestDataPath, TestDataAspectJPath, AspectjrtJar, CodeJar, Java8CodeJar), this.getClass().getClassLoader()); } @After public void teardown() throws Exception { SpringLoadedPreProcessor.disabled = false; } public void switchToGroovy() { binLoader = new TestClassLoader(toURLs(GroovyTestDataPath, GroovyrtJar), this.getClass().getClassLoader()); // Thread.currentThread().setContextClassLoader(binLoader); } /** * Convert an array of string paths to an array of URLs * * @param paths the string paths * @return the converted URLs */ public URL[] toURLs(String... paths) { URL[] urls = new URL[paths.length]; int i = 0; for (String path : paths) { try { urls[i++] = new File(path).toURI().toURL(); } catch (MalformedURLException e) { Assert.fail(e.toString()); } } return urls; } public Object run(Class<?> clazz, String methodname, Object... params) { try { // System.out.println("Calling method " + methodname + " on " + clazz.getName()); Object o = clazz.newInstance(); Method m = null; Method[] ms = clazz.getMethods(); for (Method mm : ms) { if (mm.getName().equals(methodname)) { m = mm; break; } } // Method m = clazz.getDeclaredMethod(methodname); return m.invoke(o, params); } catch (Exception e) { e.printStackTrace(); Assert.fail(e.toString()); return null; } } public Object run(Class<?> clazz, Object o, String methodname, Object... params) { try { System.out.println("Calling method " + methodname + " on " + clazz.getName()); Method m = null; Method[] ms = clazz.getMethods(); for (Method mm : ms) { if (mm.getName().equals(methodname)) { m = mm; break; } } // Method m = clazz.getDeclaredMethod(methodname); return m.invoke(o, params); } catch (Exception e) { e.printStackTrace(); Assert.fail(e.toString()); return null; } } public static boolean capture = true; public Result runUnguardedWithCCL(Class<?> clazz, ClassLoader ccl, String methodname, Object... params) throws InstantiationException, IllegalAccessException, SecurityException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException { ClassLoader oldCCL = Thread.currentThread().getContextClassLoader(); try { Thread.currentThread().setContextClassLoader(ccl); return runUnguarded(clazz, methodname, params); } finally { Thread.currentThread().setContextClassLoader(oldCCL); } } public Result runUnguarded(Class<?> clazz, String methodname, Object... params) throws InstantiationException, IllegalAccessException, SecurityException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException { PrintStream oldo = System.out; PrintStream olde = System.err; Object result = null; ByteArrayOutputStream oso = new ByteArrayOutputStream(); ByteArrayOutputStream ose = new ByteArrayOutputStream(); try { if (capture) { System.setOut(new PrintStream(oso)); System.setErr(new PrintStream(ose)); } Object o = clazz.newInstance(); Method m = null; Method[] ms = clazz.getMethods(); for (Method mm : ms) { if (mm.getName().equals(methodname)) { m = mm; break; } } if (m == null) { Assert.fail("Invocation failure: could not find method '" + methodname + "' on type '" + clazz.getName()); } m.setAccessible(true); result = m.invoke(o, params); } finally { if (capture) { System.setOut(oldo); System.setErr(olde); } } return new Result(result, oso.toString().replace("\r", ""), ose.toString().replace("\r", "")); } public Result runStaticUnguarded(Class<?> clazz, String methodname, Object... params) throws InstantiationException, IllegalAccessException, SecurityException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException { PrintStream oldo = System.out; PrintStream olde = System.err; Object result = null; ByteArrayOutputStream oso = new ByteArrayOutputStream(); ByteArrayOutputStream ose = new ByteArrayOutputStream(); try { if (capture) { System.setOut(new PrintStream(oso)); System.setErr(new PrintStream(ose)); } Method m = null; Method[] ms = clazz.getMethods(); for (Method mm : ms) { if (mm.getName().equals(methodname)) { m = mm; break; } } if (m == null) { Assert.fail("Invocation failure: could not find method '" + methodname + "' on type '" + clazz.getName()); } m.setAccessible(true); result = m.invoke(null, params); } finally { if (capture) { System.setOut(oldo); System.setErr(olde); } } return new Result(result, oso.toString().replace("\r", ""), ose.toString().replace("\r", "")); } public Result runConstructor(Class<?> clazz, int whichConstructor, Object... params) throws InstantiationException, IllegalAccessException, SecurityException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException { PrintStream oldo = System.out; PrintStream olde = System.err; Object result = null; ByteArrayOutputStream oso = new ByteArrayOutputStream(); ByteArrayOutputStream ose = new ByteArrayOutputStream(); Constructor<?> c = null; try { if (capture) { System.setOut(new PrintStream(oso)); System.setErr(new PrintStream(ose)); } Constructor<?>[] cs = clazz.getConstructors(); c = cs[whichConstructor]; System.out.println(c); if (c == null) { Assert.fail("Invocation failure: could not find constructor " + whichConstructor + " on type '" + clazz.getName()); } c.setAccessible(true); result = c.newInstance(params); } finally { if (capture) { System.setOut(oldo); System.setErr(olde); } } return new Result(result, oso.toString().replace("\r", ""), ose.toString().replace("\r", "")); } public Result runConstructor(Class<?> clazz, String paramDescriptor, Object... params) throws InstantiationException, IllegalAccessException, SecurityException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException { PrintStream oldo = System.out; PrintStream olde = System.err; Object result = null; ByteArrayOutputStream oso = new ByteArrayOutputStream(); ByteArrayOutputStream ose = new ByteArrayOutputStream(); try { if (capture) { System.setOut(new PrintStream(oso)); System.setErr(new PrintStream(ose)); } Constructor<?>[] cs = clazz.getConstructors(); Constructor<?> c = null; for (Constructor<?> ctor : cs) { Class<?>[] paramClazzes = ctor.getParameterTypes(); String toParamDescriptorString = toParamDescriptorString(paramClazzes); // System.out.println(toParamDescriptorString + "<<"); if (paramDescriptor.equals(toParamDescriptorString)) { c = ctor; break; } } if (c == null) { Assert.fail("Invocation failure: could not find constructor with param descriptor " + paramDescriptor + " on type '" + clazz.getName()); } c.setAccessible(true); result = c.newInstance(params); } finally { if (capture) { System.setOut(oldo); System.setErr(olde); } } return new Result(result, oso.toString().replace("\r", ""), ose.toString().replace("\r", "")); } private String toParamDescriptorString(Class<?>[] paramClazzes) { if (paramClazzes == null) { return ""; } StringBuilder s = new StringBuilder(); for (Class<?> c : paramClazzes) { s.append(c.getName()); s.append(" "); } return s.toString().trim(); } public void runExpectNoSuchMethodException(Class<?> clazz, String methodname, Object... params) throws InstantiationException, IllegalAccessException, SecurityException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException { try { runUnguarded(clazz, methodname, params); Assert.fail("should not work, NSME should occur for " + methodname); } catch (InvocationTargetException ite) { String cause = ite.getCause().toString(); if (!cause.startsWith("java.lang.NoSuchMethodError")) { ite.printStackTrace(); Assert.fail("Should be a NoSuchMethodError, but got " + ite); } } } public static boolean printOutput = false; /** * Proposed alternate version of runOnInstance that produces a wrapper Exception object similar to the Result object, but where * the "result" is an exception. This is done so as not to lose the grabbed output when exception is raised by the test case. */ public static Result runOnInstance(Class<?> clazz, Object instance, String methodname, Object... params) throws ResultException { PrintStream oldo = System.out; PrintStream olde = System.err; Object result = null; Throwable exception = null; ByteArrayOutputStream oso = new ByteArrayOutputStream(); ByteArrayOutputStream ose = new ByteArrayOutputStream(); try { if (capture) { System.setOut(new PrintStream(oso)); System.setErr(new PrintStream(ose)); } Method m = null; Method[] ms = clazz.getMethods(); for (Method mm : ms) { if (mm.getName().equals(methodname)) { m = mm; break; } } if (m == null) { throw new IllegalStateException("No method called " + methodname + " to call on type " + (instance == null ? "null" : instance.getClass().getName())); } try { result = m.invoke(instance, params); } catch (Throwable e) { exception = e; } } finally { System.setOut(oldo); System.setErr(olde); } if (printOutput) { System.out.println("Collected output running: " + methodname); System.out.println(oso.toString()); System.out.println(ose.toString()); } if (exception != null) { throw new ResultException(exception, oso.toString().replace("\r", ""), ose.toString().replace("\r", "")); } else { return new Result(result, oso.toString().replace("\r", ""), ose.toString().replace("\r", "")); } } // attempt definition - kind of a lightweight way to see if it is OK public Class<?> loadit(String name, byte[] bytes) { try { return ((TestClassLoader) binLoader).defineTheClass(name, bytes); } catch (RuntimeException t) { ClassPrinter.print(bytes); t.printStackTrace(); throw t; } } public Class<?> loadClass(String name) { return loadit(name, loadBytesForClass(name)); } protected byte[] retrieveRename(String newName, String name) { return ClassRenamer.rename(newName, loadBytesForClass(name)); } /** * retargets are "from.this.thing:to.this.thing" * * @param newName * @param name * @param retargets of the form "this.from:this.to" * @return */ protected byte[] retrieveRename(String newName, String name, String... retargets) { return ClassRenamer.rename(newName, loadBytesForClass(name), retargets); } protected byte[] loadBytesForClass(String dottedClassName) { byte[] data = Utils.loadDottedClassAsBytes(binLoader, dottedClassName); Assert.assertNotNull(data); Assert.assertNotSame(0, data.length); return data; } protected String getStamp(String classname) { return getStamp(binLoader, classname); } public static byte[] retrieveClass(ClassLoader loader, String classname) { byte[] data = Utils.loadDottedClassAsBytes(loader, classname); Assert.assertNotNull(data); Assert.assertNotSame(0, data.length); return data; } protected void print(byte[] classdata) { ClassReader reader = new ClassReader(classdata); reader.accept(new ClassPrinter(System.out), 0); } protected String printItAndReturnIt(byte[] classdata) { return printItAndReturnIt(classdata, false); } protected String printItAndReturnIt(byte[] classdata, boolean quoted) { OutputStream os = new SimpleOutputStream(); ClassReader reader = new ClassReader(classdata); reader.accept(new ClassPrinter(new PrintStream(os)), 0); StringBuffer sb = new StringBuffer(os.toString().replace("\r", "")); if (!quoted) { return sb.toString(); } for (int i = 0; i < sb.length(); i++) { if (sb.charAt(i) == '\n') { sb.insert(i + 1, "\""); sb.insert(i, "\\n\"+"); i += 4; } } sb.delete(sb.length() - 3, sb.length()); sb.insert(0, "\""); return sb.toString(); } @SuppressWarnings("unchecked") private MethodNode getMethod(byte[] classbytes, String methodName) { ClassReader super_cr = new ClassReader(classbytes); ClassNode cn = new ClassNode(); super_cr.accept(cn, 0); List<MethodNode> methods = cn.methods; if (methods != null) { for (MethodNode mn : methods) { if (mn.name.equals(methodName)) { return mn; } } } return null; } @SuppressWarnings("unchecked") private FieldNode getField(byte[] classbytes, String fieldName) { ClassReader super_cr = new ClassReader(classbytes); ClassNode cn = new ClassNode(); super_cr.accept(cn, 0); List<FieldNode> fields = cn.fields; if (fields != null) { for (FieldNode fn : fields) { if (fn.name.equals(fieldName)) { return fn; } } } return null; } protected ClassNode getClassNode(byte[] classdata) { ClassNode cn = new ClassNode(); ClassReader cr = new ClassReader(classdata); cr.accept(cn, 0); return cn; } @SuppressWarnings("unchecked") protected List<MethodNode> getMethods(byte[] classdata) { return getClassNode(classdata).methods; } protected int countMethods(byte[] classdata) { ClassNode cn = getClassNode(classdata); return cn.methods == null ? 0 : cn.methods.size(); } protected List<MethodNode> filter(List<MethodNode> methods, String nameSubstring) { if (methods == null) { return Collections.<MethodNode>emptyList(); } List<MethodNode> subset = new ArrayList<MethodNode>(); for (MethodNode methodNode : methods) { if (methodNode.name.contains(nameSubstring)) { subset.add(methodNode); } } return subset; } protected String toStringClass(byte[] classdata) { return toStringClass(classdata, false, false); } protected String toStringClass(byte[] classdata, boolean includeBytecode) { return toStringClass(classdata, includeBytecode, false); } protected String toStringClass(byte[] classdata, boolean includeBytecode, boolean quoted) { OutputStream os = new SimpleOutputStream(); ClassPrinter.print(new PrintStream(os), classdata, includeBytecode); String s = os.toString(); StringBuffer sb = new StringBuffer(s.replaceAll("\r", "")); if (!quoted) { return sb.toString(); } for (int i = 0; i < sb.length(); i++) { if (sb.charAt(i) == '\n') { sb.insert(i + 1, "\""); sb.insert(i, "\\n\"+"); i += 4; } } sb.insert(0, "\""); sb.delete(sb.length() - 3, sb.length()); return sb.toString(); } protected String toStringMethod(byte[] classdata, String methodname, boolean quoted) { OutputStream os = new SimpleOutputStream(); // ClassReader reader = new ClassReader(classdata); MethodNode one = getMethod(classdata, methodname); one.instructions.accept(new MethodPrinter(new PrintStream(os))); String s = os.toString(); StringBuffer sb = new StringBuffer(s.replaceAll("\r", "")); if (!quoted) { return sb.toString(); } for (int i = 0; i < sb.length(); i++) { if (sb.charAt(i) == '\n') { sb.insert(i + 1, "\""); sb.insert(i, "\\n\"+"); i += 4; } } sb.insert(0, "Method is " + methodname + "\n\""); sb.delete(sb.length() - 3, sb.length()); return sb.toString(); } public static String findJar(String whereToLook, String jarPrefix) { File dir = new File(whereToLook); File[] fs = dir.listFiles(); for (File f : fs) { if (f.getName().startsWith(jarPrefix)) { return f.toString(); } } return null; } @SuppressWarnings("unchecked") protected String toStringField(byte[] classdata, String fieldname) { StringBuilder sb = new StringBuilder(); FieldNode fieldNode = getField(classdata, fieldname); if (fieldNode == null) { return null; } List<AnnotationNode> annos = fieldNode.visibleAnnotations; if (annos != null) { sb.append("vis(").append(toStringAnnotations(annos)).append(") "); } annos = fieldNode.invisibleAnnotations; if (annos != null) { sb.append("invis(").append(toStringAnnotations(annos)).append(") "); } // will need implementing at some point: // List<Attribute> attrs = fieldNode.attrs; // if (attrs = !null) { // sb.append("attrs(").append(toStringAttributes(attrs)).append(") "); // } sb.append("0x").append(Integer.toHexString(fieldNode.access)).append("(") .append(ClassPrinter.toAccessForMember(fieldNode.access)).append(") "); sb.append(fieldNode.name).append(" "); sb.append(fieldNode.desc).append(" "); if (fieldNode.signature != null) { sb.append(fieldNode.signature).append(" "); } if (fieldNode.value != null) { sb.append(fieldNode.value).append(" "); } return sb.toString().trim(); } private String toStringAnnotations(List<AnnotationNode> annos) { StringBuilder sb = new StringBuilder(); for (AnnotationNode anno : annos) { sb.append(toStringAnnotation(anno)).append(" "); } return sb.toString().trim(); } private String toStringAnnotation(AnnotationNode anno) { StringBuilder sb = new StringBuilder(); sb.append(anno.desc); if (anno.values != null) { for (int i = 0; i < anno.values.size(); i = i + 2) { if (i > 0) { sb.append(" "); } sb.append(toStringAnnotationValue((String) anno.values.get(i), anno.values.get(i + 1))); } } return sb.toString().trim(); } /** * From asm: * * The name value pairs of this annotation. Each name value pair is stored as two consecutive elements in the list. The name is * a {@link String}, and the value may be a {@link Byte}, {@link Boolean}, {@link Character}, {@link Short}, {@link Integer}, * {@link Long}, {@link Float}, {@link Double}, {@link String} or {@link org.objectweb.asm.Type}, or an two elements String * array (for enumeration values), a {@link AnnotationNode}, or a {@link List} of values of one of the preceding types. The list * may be <tt>null</tt> if there is no name value pair. */ private String toStringAnnotationValue(String name, Object value) { StringBuilder sb = new StringBuilder(); sb.append(name).append("="); if (value instanceof Byte) { sb.append(((Byte) value).byteValue()); } else if (value instanceof Boolean) { sb.append(((Boolean) value).booleanValue()); } else if (value instanceof Character) { sb.append(((Character) value).charValue()); } else if (value instanceof Short) { sb.append(((Short) value).shortValue()); } else if (value instanceof Integer) { sb.append(((Integer) value).intValue()); } else if (value instanceof Long) { sb.append(((Long) value).longValue()); } else if (value instanceof Float) { sb.append(((Float) value).floatValue()); } else if (value instanceof Double) { sb.append(((Double) value).doubleValue()); } else if (value instanceof String) { sb.append(((String) value)); } else if (value instanceof Type) { sb.append(((Type) value).getClassName()); } else if (value instanceof String[]) { String[] ss = (String[]) value; sb.append(ss[0]).append(ss[1]); } else if (value instanceof AnnotationNode) { sb.append(toStringAnnotation((AnnotationNode) value)); } else if (value instanceof List) { throw new IllegalStateException("nyi"); } return sb.toString().trim(); } private static class SimpleOutputStream extends OutputStream { StringBuilder sb = new StringBuilder(); @Override public void write(int b) throws IOException { sb.append((char) b); } @Override public String toString() { return sb.toString(); } } protected static String getStamp(ClassLoader loader, String classname) { Assert.assertFalse(classname.endsWith(".class")); Assert.assertEquals(-1, classname.indexOf('/')); URL resourceURL = loader.getResource(classname.replace('.', '/') + ".class"); System.out.println(resourceURL.getFile()); return null; } /** * Look for a <name>.print file and check the printout of the bytes matches it, unless regenerate is true in which case the * print out is recorded in that file. */ protected void checkIt(String name, byte[] bytes) { checkIt(name, bytes, shouldRegenerate()); } /** * Look for a <name>.print file and check the printout of the bytes matches it, unless regenerate is true in which case the * print out is recorded in that file. */ protected void checkIt(String name, byte[] bytes, boolean regenerate) { String filename = "src/test/java/" + name.replace('.', '/') + ".print"; try { if (regenerate) { // create the file System.out.println("creating " + filename); File f = new File(filename); FileWriter fos = new FileWriter(f); BufferedWriter dos = new BufferedWriter(fos); dos.write(printItAndReturnIt(bytes)); dos.flush(); fos.close(); } else { // compare the files List<String> expectedLines = new ArrayList<String>(); File f = new File(filename); if (!f.exists()) { Assert.fail( "Must run with renegerate on once to create the expected output for '" + name + "'"); } FileInputStream fis = new FileInputStream(f); BufferedReader dis = new BufferedReader(new FileReader(new File(filename))); String line = null; while ((line = dis.readLine()) != null) { if (line.length() != 0) { expectedLines.add(line); } } dis.close(); fis.close(); List<String> actualLines = toLines(printItAndReturnIt(bytes)); if (actualLines.size() != expectedLines.size()) { System.out.println("actual lines=" + actualLines.size()); System.out.println(" exp lines=" + expectedLines.size()); Assert.assertEquals(expectedLines, actualLines); } for (int ln = 0; ln < expectedLines.size(); ln++) { if (!expectedLines.get(ln).equals(actualLines.get(ln))) { String expLine = (ln + 1) + " " + expectedLines.get(ln); String actLine = (ln + 1) + " " + actualLines.get(ln); Assert.assertEquals(expLine, actLine); } } } } catch (Exception e) { throw new RuntimeException(e); } } protected List<String> toLines(String input) { StringTokenizer tokenizer = new StringTokenizer(input, "\n\r"); List<String> output = new ArrayList<String>(); while (tokenizer.hasMoreElements()) { output.add(tokenizer.nextToken()); } return output; } protected boolean shouldRegenerate() { return true; } protected void copyFile(File from, File to) { try { FileInputStream fis = new FileInputStream(from); FileOutputStream fos = new FileOutputStream(to); BufferedInputStream bis = new BufferedInputStream(fis); BufferedOutputStream bos = new BufferedOutputStream(fos); byte[] buffer = new byte[4096]; int len; while ((len = bis.read(buffer, 0, 4096)) != -1) { bos.write(buffer, 0, len); } bis.close(); bos.close(); } catch (IOException ioe) { throw new RuntimeException("Copy file failed", ioe); } } protected void checkMethod(byte[] bytes, String name, String expected) { String actual = toStringMethod(bytes, name, false); if (!actual.equals(expected)) { // print it out for inclusion in the testcode System.out.println(toStringMethod(bytes, name, true)); } Assert.assertEquals(expected, actual); } protected void checkType(byte[] bytes, String expected) { String actual = printItAndReturnIt(bytes, false); if (!actual.equals(expected)) { // print it out for inclusion in the testcode System.out.println(printItAndReturnIt(bytes, true)); } Assert.assertEquals(expected, actual); } // --- // private void loadNewVersion(ReloadableType rtype, String version) throws InstantiationException, // IllegalAccessException { // loadNewVersion(rtype, version, true); // } // // /** // * Loads a new version of a type, given the name of the type, the version (suffix) and the name. // */ // private void loadNewVersion(ReloadableType rtype, String version, boolean log) throws InstantiationException, // IllegalAccessException { // String name = rtype.getTypeName(); // byte[] newclassbytes = retrieveClass(name + version); // newclassbytes = ClassRenamer.rename(name.replace('.', '/'), newclassbytes); // byte[] newdispatcher = DispatcherCreator.createFor(rtype, version); // if (log) { // System.out.println("DISPATCHER:"); // print(newdispatcher); // } // Class<?> newdispatcherclass = loadit(name + "$D$" + version, newdispatcher); // byte[] newexecutorbytes = ExecutorCreator.createFor(rtype, version, newclassbytes); // if (log) { // System.out.println("EXECUTOR:"); // print(newexecutorbytes); // } // loadit(name + "$E$" + version, newexecutorbytes); // TypeRegistry.poke(name.replace('.', '/'), newdispatcherclass.newInstance()); // } // // private void checkvalue(Class<?> clazz, String methodname, Object expectedOutput) { // Object value = run(clazz, methodname); // if (!value.equals(expectedOutput)) { // Assert.fail("Expected " + expectedOutput + ", not " + value); // } // } protected void configureForTesting(TypeRegistry typeRegistry, String... includePatterns) { if (includePatterns != null) { Properties p = new Properties(); StringBuilder s = new StringBuilder(); for (int i = 0; i < includePatterns.length; i++) { if (i > 0) { s.append(','); } s.append(includePatterns[i]); } p.setProperty(TypeRegistry.Key_Inclusions, s.toString()); typeRegistry.configure(p); } } protected void checkCause(Exception e, Class<? extends Throwable> expectedCause) { Throwable t = e.getCause(); if (t == null || !t.getClass().equals(expectedCause)) { e.printStackTrace(); Assert.fail( "Expected cause of " + expectedCause + " but it was " + (t == null ? "null" : t.getClass())); } } public MethodMember grabFrom(List<MethodMember> ms, String name) { for (MethodMember m : ms) { if (m.getName().equals(name)) { return m; } } return null; } public Method grabFrom(Method[] ms, String name) { for (Method m : ms) { if (m.getName().equals(name)) { return m; } } return null; } public Field grabFrom(Field[] fs, String name) { for (Field f : fs) { if (f.getName().equals(name)) { return f; } } return null; } protected MethodMember findMethod(String toSearchFor, TypeDescriptor typeDescriptor) { for (MethodMember method : typeDescriptor.getMethods()) { if (method.toString().equals(toSearchFor)) { return method; } } return null; } /** * Create a type registry, configure it with the specified reloadable type/packages and return it. * * @return new TypeRegistry */ protected TypeRegistry getTypeRegistry(String includePatterns) { TypeRegistry.reinitialize(); TypeRegistry tr = TypeRegistry.getTypeRegistryFor(binLoader); Properties p = new Properties(); if (includePatterns != null) { p.setProperty(TypeRegistry.Key_Inclusions, includePatterns); } if (tr == null) { throw new IllegalStateException( "maybe you need to run with: -Dspringloaded=limit=false -Xmx512M -XX:MaxPermSize=256m -noverify"); } tr.configure(p); return tr; } // protected TypeRegistry getTypeRegistry(String... includePatterns) { // StringBuilder s = new StringBuilder(); // for (int i = 0; i < includePatterns.length; i++) { // if (i > 0) { // s.append(','); // } // s.append(includePatterns[i]); // } // return getTypeRegistry(s.toString()); // } protected TypeRegistry getTypeRegistry() { return getTypeRegistry(null); } /** * Make a type reload itself - this does trigger creation of the dispatcher/executor. */ protected void reload(ReloadableType reloadableType, String versionstamp) { reloadableType.loadNewVersion(versionstamp, reloadableType.bytesInitial); } @SuppressWarnings("unchecked") protected void checkLocalVariables(byte[] bytes, String methodNameAndDescriptor, String... expected) { ClassNode cn = new ClassNode(); ClassReader cr = new ClassReader(bytes); cr.accept(cn, 0); boolean checked = false; List<MethodNode> methods = cn.methods; for (MethodNode mn : methods) { if (methodNameAndDescriptor.equals(mn.name + mn.desc)) { List<LocalVariableNode> localVariables = mn.localVariables; Assert.assertEquals(expected.length, localVariables.size()); for (int i = 0; i < expected.length; i++) { StringTokenizer tokenizer = new StringTokenizer(expected[i], ":"); String expectedName = tokenizer.nextToken(); String expectedDesc = tokenizer.nextToken(); LocalVariableNode localVariable = localVariables.get(i); Assert.assertEquals(i, localVariable.index); Assert.assertEquals(expectedName, localVariable.name); Assert.assertEquals(expectedDesc, localVariable.desc); } checked = true; } } if (!checked) { for (MethodNode mn : methods) { System.out.println(mn.name + mn.desc); } Assert.fail("Unable to find method " + methodNameAndDescriptor); } } @SuppressWarnings("unchecked") protected void checkAnnotations(byte[] bytes, String methodNameAndDescriptor, String... expected) { ClassNode cn = new ClassNode(); ClassReader cr = new ClassReader(bytes); cr.accept(cn, 0); if (expected == null) { expected = new String[0]; } boolean checked = false; List<MethodNode> methods = cn.methods; for (MethodNode mn : methods) { if (methodNameAndDescriptor.equals(mn.name + mn.desc)) { List<AnnotationNode> annotations = mn.visibleAnnotations; if (annotations == null) { annotations = Collections.emptyList(); } Assert.assertEquals(expected.length, annotations.size()); for (int i = 0; i < expected.length; i++) { // StringTokenizer tokenizer = new StringTokenizer(expected[i], ":"); // String expectedName = tokenizer.nextToken(); // String expectedDesc = tokenizer.nextToken(); AnnotationNode annotation = annotations.get(i); Assert.assertEquals(expected[i], toString(annotation)); } checked = true; } } if (!checked) { for (MethodNode mn : methods) { System.out.println(mn.name + mn.desc); } Assert.fail("Unable to find method " + methodNameAndDescriptor); } } @SuppressWarnings({ "rawtypes" }) protected Object toString(AnnotationNode annotation) { StringBuilder s = new StringBuilder(); s.append("@"); String s2 = annotation.desc.substring(1, annotation.desc.length() - 1); s.append(s2.replace('/', '.')); s.append("("); List values = annotation.values; if (values != null) { int i = 0; while (i < values.size()) { String name = (String) values.get(i++); Object value = values.get(i++); s.append(name).append("=").append(value); } } s.append(")"); return s.toString(); } protected void assertStartsWith(String prefix, Object value) { String stringValue = (String) value; if (!stringValue.startsWith(prefix)) { Assert.fail("Expected 'regular' toString() but was " + result.returnValue); } } protected void checkDoesNotContain(TypeDescriptor typeDescriptor, String string) { if (typeDescriptor.toString().indexOf(string) != -1) { Assert.fail("Did not expect to find '" + string + "' in\n" + typeDescriptor); } } protected void checkDoesContain(TypeDescriptor typeDescriptor, String string) { if (typeDescriptor.toString().indexOf(string) == -1) { Assert.fail("Expected to find '" + string + "' in\n" + typeDescriptor); } } protected ReloadableType loadType(TypeRegistry typeRegistry, String dottedTypeName) { return typeRegistry.addType(dottedTypeName, loadBytesForClass(dottedTypeName)); } public Class<?> classForName(String typeName) throws ClassNotFoundException { if (typeName.endsWith("[]")) { Class<?> element = classForName(typeName.substring(0, typeName.length() - 2)); return Array.newInstance(element, 0).getClass(); } else if (typeName.equals("int")) { return int.class; } else if (typeName.equals("void")) { return void.class; } else if (typeName.equals("boolean")) { return boolean.class; } else if (typeName.equals("byte")) { return byte.class; } else if (typeName.equals("char")) { return char.class; } else if (typeName.equals("short")) { return short.class; } else if (typeName.equals("double")) { return double.class; } else if (typeName.equals("float")) { return float.class; } else if (typeName.equals("long")) { return long.class; } return Class.forName(typeName, false, binLoader); } protected Object intArrayToString(Object value) { int[] intArray = (int[]) value; StringBuilder s = new StringBuilder(); s.append("{"); if (intArray != null) { for (int j = 0; j < intArray.length; j++) { if (j > 0) { s.append(","); } s.append(intArray[j]); } } s.append("}"); return s.toString(); } protected String objectArrayToString(Object value) { Object[] array = (Object[]) value; StringBuilder s = new StringBuilder(); s.append("{"); if (array != null) { for (int j = 0; j < array.length; j++) { if (j > 0) { s.append(","); } s.append(array[j]); } } s.append("}"); return s.toString(); } protected void assertContains(String expectedToBeContained, String actual) { if (actual.indexOf(expectedToBeContained) == -1) { fail("\nCould not find expected data:\n" + expectedToBeContained + "\n in actual output:\n" + actual); } } protected void assertUniqueContains(String expectedToBeContained, String actual) { if (actual.indexOf(expectedToBeContained) == -1 || actual.indexOf(expectedToBeContained) != actual.lastIndexOf(expectedToBeContained)) { fail("Expected a unique occurrence of:\n" + expectedToBeContained + "\n in actual output:\n" + actual); } } protected void assertDoesNotContain(String expectedToBeContained, String actual) { if (actual.indexOf(expectedToBeContained) != -1) { fail("Did not expect to find data:\n" + expectedToBeContained + "\n in actual output:\n" + actual); } } protected ISMgr getFieldAccessor(Object o) { Class<?> clazz = o.getClass(); try { Field f = clazz.getDeclaredField(Constants.fInstanceFieldsName); f.setAccessible(true); return (ISMgr) f.get(o); } catch (Exception e) { e.printStackTrace(); } return null; } protected String getStaticFieldsMap(Class<?> clazz) { try { Field f = clazz.getDeclaredField(Constants.fStaticFieldsName); f.setAccessible(true); SSMgr m = (SSMgr) f.get(null); return m.toString(); } catch (Exception e) { e.printStackTrace(); } return null; } PrintStream oldo, olde; ByteArrayOutputStream oso, ose; /** * Start intercepting the System.out/System.err streams */ protected void captureOn() { oldo = System.out; olde = System.err; oso = new ByteArrayOutputStream(); ose = new ByteArrayOutputStream(); System.setOut(new PrintStream(oso)); System.setErr(new PrintStream(ose)); } protected static String toSlash(String dottedName) { return dottedName.replace('.', '/'); } protected static String toDotted(String slashedName) { return slashedName.replace('/', '.'); } /** * Stop intercepting the System.out/System.err streams and return any accumulated output since the captureOn. */ protected String captureOff() { if (oldo == null) { throw new IllegalStateException("Turning capture off without having turned it on"); } System.setOut(oldo); System.setErr(olde); oldo = null; olde = null; return new String("SYSOUT\n" + oso.toString().replace("\r", "") + "\nSYSERR\n" + ose.toString().replace("\r", "") + "\n"); } protected String captureOffReturnStdout() { if (oldo == null) { throw new IllegalStateException("Turning capture off without having turned it on"); } System.setOut(oldo); System.setErr(olde); oldo = null; olde = null; return new String(oso.toString()); } /** * Called at the end of a test to tidy up in case a test crashed and failed to stop capturing. */ protected void ensureCaptureOff() { if (oldo != null) { System.setOut(oldo); System.setErr(olde); oldo = null; } } /** * Execute a specific method, returning all output that occurred during the run to the caller. */ public String runMethodAndCollectOutput(Class<?> clazz, String methodname) throws Exception { captureOn(); Method m = clazz.getDeclaredMethod(methodname); if (!Modifier.isStatic(m.getModifiers())) { fail("Method should be static: " + m); } m.invoke(null); return captureOff(); } protected String slashed(String dotted) { return dotted.replaceAll("\\.", "/"); } protected final static void pause(int seconds) { try { Thread.sleep(seconds * 1000); } catch (Exception e) { } } protected void assertStdout(String expectedStdout, JVMOutput actualOutput) { if (!expectedStdout.equals(actualOutput.stdout)) { // assertEquals(expectedStdout, actualOutput.stdout); fail("Expected stdout '" + expectedStdout + "' not found in \n" + actualOutput.toString()); } } protected void assertStdoutContains(String expectedStdout, JVMOutput actualOutput) { if (!actualOutput.stdout.contains(expectedStdout)) { fail("Expected stdout:\n" + expectedStdout + "\nbut was:\n" + actualOutput.stdout.toString() + "\nComplete output: \n" + actualOutput.toString()); } } protected void assertStdoutContains(String expectedStdout, Result r) { // TODO Auto-generated method stub } protected void assertStderrContains(String expectedStderrContains, JVMOutput actualOutput) { if (actualOutput.stderr.indexOf(expectedStderrContains) == -1) { fail("Expected stderr to contain '" + expectedStderrContains + "'\n" + actualOutput.toString()); } } }