ShowWeaveMessagesTest.java
/* *******************************************************************
* Copyright (c) 2004 Contributors.
* 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:
* Andy Clement Initial version
* Helen Hawkins Converted to new interface (bug 148190)
* ******************************************************************/
package org.aspectj.ajde.core.tests;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.aspectj.ajde.core.AjdeCoreTestCase;
import org.aspectj.ajde.core.JavaOptions;
import org.aspectj.ajde.core.TestCompilerConfiguration;
import org.aspectj.ajde.core.TestMessageHandler;
import org.aspectj.bridge.IMessage;
/**
* Weaving messages are complicated things. There are multiple places where weaving takes place and the places vary depending on
* whether we are doing a binary weave or going from source. All places that output weaving messages are tagged: // TAG:
* WeavingMessage so you can easily find them!
*
* Advice is the simplest to deal with as that is advice weaving is always done in the weaver.
*
* Next is intertype declarations. These are also always done in the weaver but in the case of a binary weave we don't know the
* originating source line for the ITD.
*
* Finally, declares. Declare Parents: extends Can only be done when going from source, if attempted by a binary weave then an error
* message (compiler limitation) is produced. Declare Parents: implements Is (currently!) done at both compile time and weave time.
* If going from source then the message is produced by the code in the compiler. if going from binary then the message is produced
* by the weaver. Declare Soft: Comes out with 'advice' as a special kind of advice: softener advice
*
*
* Q: Where are the messages turned on/off? A: It is a bit messy. See BuildArgParser.genBuildConfig(). Basically that method is the
* first time we parse the option set. Whether weaving messages are on or off is stored in the build config. As soon as we have
* parser the options and determined that weave messages are on, we grab the top level message handler and tell it not to ignore
* WeaveInfo messages.
*
*
* TODO - Other forms of declare? Do they need messages? e.g. declare precedence *
*/
public class ShowWeaveMessagesTest extends AjdeCoreTestCase {
private static boolean regenerate;
private static boolean debugTests = false;
static {
// Switch this to true for a single iteration if you want to reconstruct the
// 'expected weaving messages' files.
regenerate = false;
}
public static final String PROJECT_DIR = "WeaveInfoMessagesTest";
public static final String binDir = "bin";
public static final String expectedResultsDir = "expected";
public String[] one = new String[] { "AspectAdvice.aj", "Simple.java" };
public String[] two = new String[] { "AspectITD.aj", "Simple.java" };
public String[] three = new String[] { "AspectDeclare.aj", "Simple.java" };
public String[] four = new String[] { "AspectDeclareExtends.aj", "Simple.java" };
public String[] five = new String[] { "Simple.java", "AspectDeclareSoft.aj" };
public String[] six = new String[] { "AspectDeclareAnnotations.aj" };
public String[] seven = new String[] { "AspectDeclareAnnotations.aj" };
public String[] empty = new String[] {};
private TestMessageHandler handler;
private TestCompilerConfiguration compilerConfig;
@Override
protected void setUp() throws Exception {
super.setUp();
initialiseProject(PROJECT_DIR);
handler = (TestMessageHandler) getCompiler().getMessageHandler();
handler.dontIgnore(IMessage.WEAVEINFO);
compilerConfig = (TestCompilerConfiguration) getCompiler().getCompilerConfiguration();
compilerConfig.setNonStandardOptions("-showWeaveInfo");
}
@Override
protected void tearDown() throws Exception {
super.tearDown();
handler = null;
compilerConfig = null;
}
/**
* Weave all the possible kinds of advice and verify the messages that come out.
*/
public void testWeaveMessagesAdvice() {
if (debugTests)
System.out.println("testWeaveMessagesAdvice: Building with One.lst");
compilerConfig.setProjectSourceFiles(getSourceFileList(one));
doBuild();
assertTrue("Expected no compiler errors but found " + handler.getErrors(), handler.getErrors().isEmpty());
verifyWeavingMessages("advice", true);
}
/**
* Weave field and method ITDs and check the weave messages that come out.
*/
public void testWeaveMessagesITD() {
if (debugTests)
System.out.println("\ntestWeaveMessagesITD: Building with Two.lst");
compilerConfig.setProjectSourceFiles(getSourceFileList(two));
doBuild();
assertTrue("Expected no compiler errors but found " + handler.getErrors(), handler.getErrors().isEmpty());
verifyWeavingMessages("itd", true);
}
/**
* Weave "declare parents: implements" and check the weave messages that come out.
*/
public void testWeaveMessagesDeclare() {
if (debugTests)
System.out.println("\ntestWeaveMessagesDeclare: Building with Three.lst");
compilerConfig.setProjectSourceFiles(getSourceFileList(three));
doBuild();
assertTrue("Expected no compiler errors but found " + handler.getErrors(), handler.getErrors().isEmpty());
verifyWeavingMessages("declare1", true);
}
/**
* Weave "declare parents: extends" and check the weave messages that come out. Can't do equivalent binary test - as can't do
* extends in binary.
*/
public void testWeaveMessagesDeclareExtends() {
if (debugTests)
System.out.println("\ntestWeaveMessagesDeclareExtends: Building with Four.lst");
compilerConfig.setProjectSourceFiles(getSourceFileList(four));
doBuild();
assertTrue("Expected no compiler errors but found " + handler.getErrors(), handler.getErrors().isEmpty());
verifyWeavingMessages("declare.extends", true);
}
/**
* Weave "declare soft: type: pointcut" and check the weave messages that come out.
*/
public void testWeaveMessagesDeclareSoft() {
if (debugTests)
System.out.println("\ntestWeaveMessagesDeclareSoft: Building with Five.lst");
compilerConfig.setProjectSourceFiles(getSourceFileList(five));
doBuild();
assertTrue("Expected no compiler errors but found " + handler.getErrors(), handler.getErrors().isEmpty());
verifyWeavingMessages("declare.soft", true);
}
/**
* Weave 'declare @type, @constructor, @method and @field' and check the weave messages that come out.
*/
public void testWeaveMessagesDeclareAnnotation() {
if (debugTests)
System.out.println("\ntestWeaveMessagesDeclareAnnotation: Building with Six.lst");
compilerConfig.setProjectSourceFiles(getSourceFileList(six));
setRunIn18Mode();
compilerConfig.setNonStandardOptions("-showWeaveInfo -1.8");
doBuild();
assertTrue("Expected no compiler errors but found " + handler.getErrors(), handler.getErrors().isEmpty());
verifyWeavingMessages("declare.annotation", true);
}
/**
* Weave 'declare @type, @constructor, @method and @field' and check the weave messages don't come out without the
* -showWeaveInfo arg.
*/
public void testWeaveMessagesDeclareAnnotationWeaveInfoOff() {
if (debugTests)
System.out.println("\ntestWeaveMessagesDeclareAnnotation: Building with Seven.lst");
compilerConfig.setProjectSourceFiles(getSourceFileList(seven));
compilerConfig.setNonStandardOptions("");
setRunIn18Mode();
doBuild();
assertTrue("Expected no compiler errors but found " + handler.getErrors(), handler.getErrors().isEmpty());
verifyWeavingMessages("declare.annotationNoWeaveInfo", true);
}
// BINARY WEAVING TESTS
/**
* Binary weave variant of the advice weaving test above - to check messages are ok for binary weave. Unlike the source level
* weave, in this test we are using an aspect on the aspectpath - which means it has already had its necessary parts woven - so
* the list of weaving messages we expect is less.
*/
public void testWeaveMessagesBinaryAdvice() {
if (debugTests)
System.out.println("\ntestWeaveMessagesBinaryAdvice: Simple.jar + AspectAdvice.jar");
Set<File> inpath = new HashSet<>();
inpath.add(openFile("Simple.jar"));
compilerConfig.setInpath(inpath);
Set<File> aspectpath = new HashSet<>();
aspectpath.add(openFile("AspectAdvice.jar"));
compilerConfig.setAspectPath(aspectpath);
doBuild();
assertTrue("Expected no compiler errors but found " + handler.getErrors(), handler.getErrors().isEmpty());
verifyWeavingMessages("advice.binary", true);
}
public void testWeaveMessagesBinaryITD() {
if (debugTests)
System.out.println("\ntestWeaveMessagesBinaryITD: Simple.jar + AspectITD.jar");
Set<File> inpath = new HashSet<>();
inpath.add(openFile("Simple.jar"));
compilerConfig.setInpath(inpath);
Set<File> aspectpath = new HashSet<>();
aspectpath.add(openFile("AspectITD.jar"));
compilerConfig.setAspectPath(aspectpath);
doBuild();
assertTrue("Expected no compiler errors but found " + handler.getErrors(), handler.getErrors().isEmpty());
verifyWeavingMessages("itd", false);
}
public void testWeaveMessagesBinaryDeclare() {
if (debugTests)
System.out.println("\ntestWeaveMessagesBinaryDeclare: Simple.jar + AspectDeclare.jar");
Set<File> inpath = new HashSet<>();
inpath.add(openFile("Simple.jar"));
compilerConfig.setInpath(inpath);
Set<File> aspectpath = new HashSet<>();
aspectpath.add(openFile("AspectDeclare.jar"));
compilerConfig.setAspectPath(aspectpath);
doBuild();
assertTrue("Expected no compiler errors but found " + handler.getErrors(), handler.getErrors().isEmpty());
verifyWeavingMessages("declare1", false);
}
/**
* Weave "declare soft: type: pointcut" and check the weave messages that come out.
*/
public void testWeaveMessagesBinaryDeclareSoft() {
if (debugTests)
System.out.println("\ntestWeaveMessagesBinaryDeclareSoft: Simple.jar + AspectDeclareSoft.jar");
Set<File> inpath = new HashSet<>();
inpath.add(openFile("Simple.jar"));
compilerConfig.setInpath(inpath);
Set<File> aspectpath = new HashSet<>();
aspectpath.add(openFile("AspectDeclareSoft.jar"));
compilerConfig.setAspectPath(aspectpath);
doBuild();
assertTrue("Expected no compiler errors but found " + handler.getErrors(), handler.getErrors().isEmpty());
verifyWeavingMessages("declare.soft.binary", true);
}
public void testWeaveMessagesBinaryAdviceInPackageFromJar() {
if (debugTests)
System.out.println("\ntestWeaveMessagesBinaryAdviceInPackageFromJar: Simple.jar + AspectInPackage.jar");
Set<File> inpath = new HashSet<>();
inpath.add(openFile("Simple.jar"));
compilerConfig.setInpath(inpath);
Set<File> aspectpath = new HashSet<>();
aspectpath.add(openFile("AspectInPackage.jar"));
compilerConfig.setAspectPath(aspectpath);
doBuild();
assertTrue("Expected no compiler errors but found " + handler.getErrors(), handler.getErrors().isEmpty());
verifyWeavingMessages("advice.binary.package.jar", true);
}
public void testWeaveMessagesBinaryAdviceInPackage() {
if (debugTests)
System.out.println("\ntestWeaveMessagesBinaryAdviceInPackage: Simple.jar + AspectInPackage.jar");
Set<File> inpath = new HashSet<>();
inpath.add(openFile("Simple.jar"));
compilerConfig.setInpath(inpath);
Set<File> aspectpath = new HashSet<>();
aspectpath.add(openFile("pkg"));
compilerConfig.setAspectPath(aspectpath);
doBuild();
assertTrue("Expected no compiler errors but found " + handler.getErrors(), handler.getErrors().isEmpty());
verifyWeavingMessages("advice.binary.package", true);
}
// BINARY WEAVING WHEN WE'VE LOST THE SOURCE POINTERS
public void testWeaveMessagesBinaryAdviceNoDebugInfo() {
if (debugTests)
System.out.println("\ntestWeaveMessagesBinaryAdvice: Simple.jar + AspectAdvice.jar");
Set<File> inpath = new HashSet<>();
inpath.add(openFile("Simple_nodebug.jar"));
compilerConfig.setInpath(inpath);
Set<File> aspectpath = new HashSet<>();
aspectpath.add(openFile("AspectAdvice_nodebug.jar"));
compilerConfig.setAspectPath(aspectpath);
doBuild();
assertTrue("Expected no compiler errors but found " + handler.getErrors(), handler.getErrors().isEmpty());
verifyWeavingMessages("advice.binary.nodebug", true);
}
public void testWeaveMessagesBinaryITDNoDebugInfo() {
if (debugTests)
System.out.println("\ntestWeaveMessagesBinaryITD: Simple.jar + AspectITD.jar");
Set<File> inpath = new HashSet<>();
inpath.add(openFile("Simple_nodebug.jar"));
compilerConfig.setInpath(inpath);
Set<File> aspectpath = new HashSet<>();
aspectpath.add(openFile("AspectITD_nodebug.jar"));
compilerConfig.setAspectPath(aspectpath);
doBuild();
assertTrue("Expected no compiler errors but found " + handler.getErrors(), handler.getErrors().isEmpty());
verifyWeavingMessages("itd.nodebug", true);
}
public void testWeaveMessagesBinaryDeclareNoDebugInfo() {
if (debugTests)
System.out.println("\ntestWeaveMessagesBinaryDeclareNoDebugInfo: Simple.jar + AspectDeclare.jar");
Set<File> inpath = new HashSet<>();
inpath.add(openFile("Simple_nodebug.jar"));
compilerConfig.setInpath(inpath);
Set<File> aspectpath = new HashSet<>();
aspectpath.add(openFile("AspectDeclare_nodebug.jar"));
compilerConfig.setAspectPath(aspectpath);
doBuild();
assertTrue("Expected no compiler errors but found " + handler.getErrors(), handler.getErrors().isEmpty());
verifyWeavingMessages("declare1.nodebug", true);
}
/**
* Weave "declare soft: type: pointcut" and check the weave messages that come out.
*/
public void testWeaveMessagesBinaryDeclareSoftNoDebugInfo() {
if (debugTests)
System.out.println("\ntestWeaveMessagesBinaryDeclareSoftNoDebugInfo: Simple.jar + AspectDeclareSoft.jar");
Set<File> inpath = new HashSet<>();
inpath.add(openFile("Simple_nodebug.jar"));
compilerConfig.setInpath(inpath);
Set<File> aspectpath = new HashSet<>();
aspectpath.add(openFile("AspectDeclareSoft_nodebug.jar"));
compilerConfig.setAspectPath(aspectpath);
doBuild();
assertTrue("Expected no compiler errors but found " + handler.getErrors(), handler.getErrors().isEmpty());
verifyWeavingMessages("declare.soft.binary.nodebug", true);
}
public void verifyWeavingMessages(String testid, boolean source) {
File expectedF = openFile(expectedResultsDir + File.separator + testid + ".txt");
if (regenerate && source) {
// Create the file
saveWeaveMessages(expectedF);
} else {
// Verify the file matches what we have
compareWeaveMessages(expectedF);
}
}
/**
* Compare weaving messages with what is in the file
*/
private void compareWeaveMessages(File f) {
List<String> fileContents = new ArrayList<>();
BufferedReader fr;
try {
// Load the file in
fr = new BufferedReader(new FileReader(f));
String line = null;
while ((line = fr.readLine()) != null)
fileContents.add(line);
List<String> originalFileContents = new ArrayList<>(fileContents);
// See if the messages match
int msgCount = 0;
List<TestMessageHandler.TestMessage> l = handler.getMessages();
for (TestMessageHandler.TestMessage testMessage : l) {
IMessage msg = testMessage.getContainedMessage();
if (debugTests)
System.out.println("Looking at [" + msg + "]");
if (msg.getKind().equals(IMessage.WEAVEINFO)) {
if (!fileContents.contains(msg.getMessage())) {
fail("Could not find message '" + msg.getMessage() + "' in the expected results. Expected results are:\n"
+ stringify(originalFileContents));
} else {
fileContents.remove(msg.getMessage());
}
msgCount++;
}
}
assertTrue("Didn't get these expected messages: " + fileContents, fileContents.size() == 0);
if (debugTests)
System.out.println("Successfully verified " + msgCount + " weaving messages");
} catch (Exception e) {
fail("Unexpected exception saving weaving messages:" + e);
}
}
private String stringify(List<String> l) {
StringBuilder result = new StringBuilder();
for (String str: l) {
result.append(str);
result.append("\n");
}
return result.toString();
}
/**
* Store the weaving messages in the specified file.
*/
private void saveWeaveMessages(File f) {
System.out.println("Saving weave messages into " + f.getName());
FileWriter fw;
try {
fw = new FileWriter(f);
List<TestMessageHandler.TestMessage> l = handler.getMessages();
for (TestMessageHandler.TestMessage testMessage : l) {
IMessage msg = testMessage.getContainedMessage();
if (msg.getKind().equals(IMessage.WEAVEINFO)) {
fw.write(msg.getMessage() + "\n");
}
}
fw.close();
} catch (Exception e) {
fail("Unexpected exception saving weaving messages:" + e);
}
}
private void setRunIn18Mode() {
Map<String, String> m = new Hashtable<>();
m.put(JavaOptions.COMPLIANCE_LEVEL, JavaOptions.VERSION_18);
m.put(JavaOptions.SOURCE_COMPATIBILITY_LEVEL, JavaOptions.VERSION_18);
m.put(JavaOptions.TARGET_COMPATIBILITY_LEVEL, JavaOptions.VERSION_18);
compilerConfig.setJavaOptions(m);
}
}