WeaveTestCase.java
/* *******************************************************************
* Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
* All rights reserved.
* This program and the accompanying materials are made available
* under the terms of the Eclipse Public License v 2.0
* which accompanies this distribution and is available at
* https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.txt
*
* Contributors:
* PARC initial implementation
* ******************************************************************/
package org.aspectj.weaver.bcel;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.aspectj.apache.bcel.Constants;
import org.aspectj.apache.bcel.generic.InstructionFactory;
import org.aspectj.apache.bcel.generic.InstructionList;
import org.aspectj.apache.bcel.generic.InvokeInstruction;
import org.aspectj.apache.bcel.generic.Type;
import org.aspectj.testing.util.TestUtil;
import org.aspectj.util.FileUtil;
import org.aspectj.util.LangUtil;
import org.aspectj.weaver.Advice;
import org.aspectj.weaver.ShadowMunger;
import org.aspectj.weaver.WeaverTestCase;
import org.aspectj.weaver.patterns.FormalBinding;
import org.aspectj.weaver.patterns.PerClause;
import org.aspectj.weaver.patterns.Pointcut;
import org.aspectj.weaver.patterns.SimpleScope;
import junit.framework.TestCase;
public abstract class WeaveTestCase extends TestCase {
public boolean regenerate = false;
public boolean runTests = true;
public boolean behave15 = false;
File outDir;
String outDirPath;
public BcelWorld world = new BcelWorld();
{
world.addPath(classDir);
// Some of the tests in here rely on comparing output from dumping the delegates - if
// we are using ASM delegates we don't know the names of parameters (they are irrelevant...)
// and are missing from the dumping of asm delegates. This switch ensures we
// continue to use BCEL for these tests.
// world.setFastDelegateSupport(false);
}
public WeaveTestCase(String name) {
super(name);
}
@Override
public void setUp() throws Exception {
outDir = WeaverTestCase.getOutdir();
outDirPath = outDir.getAbsolutePath();
}
@Override
public void tearDown() throws Exception {
super.tearDown();
WeaverTestCase.removeOutDir();
outDir = null;
outDirPath = null;
}
public static InstructionList getAdviceTag(BcelShadow shadow, String where) {
String methodName = "ajc_" + where + "_" + shadow.getKind().toLegalJavaIdentifier();
InstructionFactory fact = shadow.getFactory();
InvokeInstruction il = fact.createInvoke("Aspect", methodName, Type.VOID, new Type[] {}, Constants.INVOKESTATIC);
return new InstructionList(il);
}
public void weaveTest(String name, String outName, ShadowMunger planner) throws IOException {
List<ShadowMunger> l = new ArrayList<>(1);
l.add(planner);
weaveTest(name, outName, l);
}
// static String classDir = "../weaver/bin";
static String classDir = WeaverTestCase.TESTDATA_PATH + File.separator + "bin";
public void weaveTest(String name, String outName, List<ShadowMunger> planners) throws IOException {
BcelWeaver weaver = new BcelWeaver(world);
try {
if (behave15)
world.setBehaveInJava5Way(true);
UnwovenClassFile classFile = makeUnwovenClassFile(classDir, name, outDirPath);
weaver.addClassFile(classFile, false);
weaver.setShadowMungers(planners);
weaveTestInner(weaver, classFile, name, outName);
} finally {
if (behave15)
world.setBehaveInJava5Way(false);
}
}
protected void weaveTestInner(BcelWeaver weaver, UnwovenClassFile classFile, String name, String outName) throws IOException {
// int preErrors = currentResult.errorCount();
BcelObjectType classType = BcelWorld.getBcelObjectType(world.resolve(classFile.getClassName()));
LazyClassGen gen = weaver.weave(classFile, classType);
if (gen == null) {
// we didn't do any weaving, but let's make a gen anyway
gen = classType.getLazyClassGen(); // new LazyClassGen(classType);
}
try {
String filenameToUse = findMostRelevantFile(outName);
checkClass(gen, outDirPath, filenameToUse);
if (runTests) {
System.out.println("*******RUNNING: " + outName + " " + name + " *******");
TestUtil.runMain(makeClassPath(outDirPath), name);
}
} catch (Error e) {
System.err.println("Comparing to " + outName + ".txt");
gen.print(System.err);
throw e;
} catch (RuntimeException e) {
gen.print(System.err);
throw e;
}
}
public String findMostRelevantFile(String name) {
double version = LangUtil.getVmVersion();
while (version > 0) {
String possibleFileName = name+"."+Double.toString(version)+".txt";
if (new File(TESTDATA_DIR, possibleFileName).exists()) {
return possibleFileName;
}
version--;
}
// Use the standard file
return name+".txt";
}
public String makeClassPath(String outDir) {
return outDir + File.pathSeparator + getTraceJar() + File.pathSeparator + classDir + File.pathSeparator
+ System.getProperty("java.class.path");
}
/**
* '/' in the name indicates the location of the class
*/
public static UnwovenClassFile makeUnwovenClassFile(String classDir, String name, String outDir) throws IOException {
File outFile = new File(outDir, name + ".class");
if (classDir.endsWith(".jar")) {
String fname = name + ".class";
UnwovenClassFile ret = new UnwovenClassFile(outFile.getAbsolutePath(), FileUtil.readAsByteArray(FileUtil
.getStreamFromZip(classDir, fname)));
return ret;
} else {
File inFile = new File(classDir, name + ".class");
return new UnwovenClassFile(outFile.getAbsolutePath(), FileUtil.readAsByteArray(inFile));
}
}
public void checkClass(LazyClassGen gen, String outDir, String expectedFile) throws IOException {
if (regenerate)
genClass(gen, outDir, expectedFile);
else
realCheckClass(gen, outDir, expectedFile);
}
static final File TESTDATA_DIR = new File(WeaverTestCase.TESTDATA_PATH);
void genClass(LazyClassGen gen, String outDir, String expectedFile) throws IOException {
// ClassGen b = getJavaClass(outDir, className);
FileOutputStream out = new FileOutputStream(new File(TESTDATA_DIR, expectedFile));
PrintStream ps = new PrintStream(out);
gen.print(ps);
ps.flush();
}
void realCheckClass(LazyClassGen gen, String outDir, String expectedFile) throws IOException {
TestUtil.assertMultiLineStringEquals(expectedFile/* "classes" */,
FileUtil.readAsString(new File(TESTDATA_DIR, expectedFile)), gen.toLongString());
}
// ----
public ShadowMunger makeConcreteAdvice(String mungerString) {
return makeConcreteAdvice(mungerString, 0, null);
}
public ShadowMunger makeConcreteAdvice(String mungerString, int extraArgFlag) {
return makeConcreteAdvice(mungerString, extraArgFlag, null);
}
protected ShadowMunger makeConcreteAdvice(String mungerString, int extraArgFlag, PerClause perClause) {
Advice myMunger = BcelTestUtils.shadowMunger(world, mungerString, extraArgFlag);
// PerSingleton s = new PerSingleton();
// s.concretize(world.resolve("Aspect"));
// System.err.println(((KindedPointcut)myMunger.getPointcut().getPointcut()).getKind());
Advice cm = (Advice) myMunger.concretize(myMunger.getDeclaringAspect().resolve(world), world, perClause);
return cm;
}
public ShadowMunger makeAdviceField(String kind, String extraArgType) {
return makeConcreteAdvice(kind + "(): get(* *.*) -> static void Aspect.ajc_" + kind + "_field_get(" + extraArgType + ")", 1);
}
public List<ShadowMunger> makeAdviceAll(String kind, boolean matchOnlyPrintln) {
List<ShadowMunger> ret = new ArrayList<>();
if (matchOnlyPrintln) {
ret.add(makeConcreteAdvice(kind + "(): call(* *.println(..)) -> static void Aspect.ajc_" + kind + "_method_execution()"));
} else {
ret.add(makeConcreteAdvice(kind + "(): call(* *.*(..)) -> static void Aspect.ajc_" + kind + "_method_call()"));
ret.add(makeConcreteAdvice(kind + "(): call(*.new(..)) -> static void Aspect.ajc_" + kind + "_constructor_call()"));
ret.add(makeConcreteAdvice(kind + "(): execution(* *.*(..)) -> static void Aspect.ajc_" + kind + "_method_execution()"));
ret.add(makeConcreteAdvice(kind + "(): execution(*.new(..)) -> static void Aspect.ajc_" + kind
+ "_constructor_execution()"));
// ret.add(
// makeConcreteMunger(
// kind
// + "(): staticinitialization(*) -> static void Aspect.ajc_"
// + kind
// + "_staticinitialization()"));
ret.add(makeConcreteAdvice(kind + "(): get(* *.*) -> static void Aspect.ajc_" + kind + "_field_get()"));
// ret.add(
// makeConcreteMunger(
// kind + "(): set(* *.*) -> static void Aspect.ajc_" + kind + "_field_set()"));
// XXX no test for advice execution, staticInitialization or (god help us) preInitialization
}
return ret;
}
public List<ShadowMunger> makeAdviceAll(final String kind) {
return makeAdviceAll(kind, false);
}
public Pointcut makePointcutAll() {
return makeConcretePointcut("get(* *.*) || call(* *.*(..)) || execution(* *.*(..)) || call(*.new(..)) || execution(*.new(..))");
}
public Pointcut makePointcutNoZeroArg() {
return makeConcretePointcut("call(* *.*(*, ..)) || execution(* *.*(*, ..)) || call(*.new(*, ..)) || execution(*.new(*, ..))");
}
public Pointcut makePointcutPrintln() {
return makeConcretePointcut("call(* *.println(..))");
}
public Pointcut makeConcretePointcut(String s) {
return makeResolvedPointcut(s).concretize(null, null, 0);
}
public Pointcut makeResolvedPointcut(String s) {
Pointcut pointcut0 = Pointcut.fromString(s);
return pointcut0.resolve(new SimpleScope(world, FormalBinding.NONE));
}
// ----
public String[] getStandardTargets() {
return new String[] { "HelloWorld", "FancyHelloWorld" };
}
public String getTraceJar() {
return WeaverTestCase.TESTDATA_PATH + "/tracing.jar";
}
// ----
protected void weaveTest(String[] inClassNames, String outKind, ShadowMunger patternMunger) throws IOException {
for (String inFileName : inClassNames) {
weaveTest(inFileName, outKind + inFileName, patternMunger);
}
}
protected void weaveTest(String[] inClassNames, String outKind, List<ShadowMunger> patternMungers) throws IOException {
for (String inFileName : inClassNames) {
weaveTest(inFileName, outKind + inFileName, patternMungers);
}
}
protected List<ShadowMunger> addLexicalOrder(List<ShadowMunger> l) {
int i = 10;
for (ShadowMunger element: l) {
((Advice)element).setLexicalPosition(i += 10);
}
return l;
}
// XXX cut-and-paster from IdWeaveTestCase
public void checkShadowSet(List l, String[] ss) {
outer:
for (String s : ss) {
// inner:
for (Iterator j = l.iterator(); j.hasNext(); ) {
BcelShadow shadow = (BcelShadow) j.next();
String shadowString = shadow.toString();
if (shadowString.equals(s)) {
j.remove();
continue outer;
}
}
assertTrue("didn't find " + s + " in " + l, false);
}
assertTrue("too many things in " + l, l.size() == 0);
}
}