12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091 |
- /* *******************************************************************
- * Copyright (c) 2004 IBM Corporation
- * All rights reserved.
- * This program and the accompanying materials are made available
- * under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Adrian Colyer, Abraham Nevado (lucierna)
- * ******************************************************************/
- package org.aspectj.tools.ajc;
-
- import java.io.BufferedReader;
- import java.io.ByteArrayOutputStream;
- import java.io.File;
- import java.io.IOException;
- import java.io.InputStreamReader;
- import java.io.OutputStream;
- import java.io.PrintStream;
- import java.io.PrintWriter;
- import java.lang.reflect.Constructor;
- import java.lang.reflect.InvocationTargetException;
- import java.lang.reflect.Method;
- import java.net.URL;
- import java.net.URLClassLoader;
- import java.util.ArrayList;
- import java.util.Collections;
- import java.util.Iterator;
- import java.util.List;
- import java.util.StringTokenizer;
-
- import org.aspectj.bridge.IMessage;
- import org.aspectj.bridge.ISourceLocation;
- import org.aspectj.testing.util.TestUtil;
- import org.aspectj.util.LangUtil;
-
- import junit.framework.TestCase;
-
- /**
- * A TestCase class that acts as the superclass for all test cases wishing to drive the ajc compiler.
- * <p>
- * This class provides a number of utility methods that make programmatic testing of the compiler easy. See AjcTestCaseTest for a
- * couple of simple tests written using this class.
- * </p>
- * <p>
- * See the XMLBasedAjcTestCase subclass for TestCase class that can be used to drive compiler tests based on an ajcTests.xml format
- * test specification file.
- * </p>
- *
- * @see org.aspectj.tools.ajc.AjcTestCase.Message
- * @see org.aspectj.tools.ajc.AjcTestCase.MessageSpec
- * @see org.aspectj.tools.ajc.AjcTestCase.RunResult
- * @see org.aspectj.tools.ajc.AjcTestCaseTest
- * @see org.aspectj.testing.XMLBasedAjcTestCase
- */
- public class AjcTestCase extends TestCase {
-
- private RunResult lastRunResult;
-
- /**
- * The Ajc (compiler) instance used for the test. Created afresh during the test setup.
- */
- protected Ajc ajc;
-
- // see Ajc and AntSpec
- public static final String DEFAULT_CLASSPATH_ENTRIES = File.pathSeparator + ".." + File.separator + "bridge" + File.separator
- + "bin" + File.pathSeparator + ".." + File.separator + "util" + File.separator + "bin" + File.pathSeparator + ".."
- + File.separator + "loadtime" + File.separator + "bin" + File.pathSeparator + ".." + File.separator + "weaver"
- + File.separator + "bin" + File.pathSeparator + ".." + File.separator + "weaver5" + File.separator + "bin"
- + File.pathSeparator + ".." + File.separator + "asm" + File.separator + "bin" + File.pathSeparator + ".."
- + File.separator + "testing-client" + File.separator + "bin" + File.pathSeparator + ".." + File.separator + "runtime"
- + File.separator + "bin" + File.pathSeparator + ".." + File.separator + "aspectj5rt" + File.separator + "bin"
- + File.pathSeparator + ".." + File.separator + "org.aspectj.matcher" + File.separator + "bin" + File.pathSeparator
- + ".." + File.separator + "lib" + File.separator + "junit" + File.separator
- + "junit.jar"
- + File.pathSeparator
- + ".."
- + File.separator
- + "lib"
- + File.separator
- + "bcel"
- + File.separator
- + "bcel.jar"
- + File.pathSeparator
- + ".."
- + File.separator
- + "lib"
- + File.separator
- + "bcel"
- + File.separator
- + "bcel-verifier.jar"
-
- + File.pathSeparator + ".." + File.separator + "lib" + File.separator + "asm" + File.separator + "asm-7.0-beta.renamed.jar"
-
- // When the build machine executes the tests, it is using code built into jars rather than code build into
- // bin directories. This means for the necessary types to be found we have to put these jars on the classpath:
- + File.pathSeparator + ".." + File.separator + "aj-build" + File.separator + "jars" + File.separator + "bridge.jar"
- + File.pathSeparator + ".." + File.separator + "aj-build" + File.separator + "jars" + File.separator + "util.jar"
- + File.pathSeparator + ".." + File.separator + "aj-build" + File.separator + "jars" + File.separator
- + "org.aspectj.matcher.jar" + File.pathSeparator + ".." + File.separator + "aj-build" + File.separator + "jars"
- + File.separator + "loadtime.jar" + File.pathSeparator + ".." + File.separator + "aj-build" + File.separator + "jars"
- + File.separator + "weaver.jar" + File.pathSeparator + ".." + File.separator + "aj-build" + File.separator + "jars"
- + File.separator + "weaver5.jar" + File.pathSeparator + ".." + File.separator + "aj-build" + File.separator + "jars"
- + File.separator + "asm.jar" + File.pathSeparator + ".." + File.separator + "lib" + File.separator + "test"
- + File.separator + "testing-client.jar"
- // hmmm, this next one should perhaps point to an aj-build jar...
- + File.pathSeparator + ".." + File.separator + "lib" + File.separator + "test" + File.separator + "aspectjrt.jar";
-
- public static final String JAVA5_CLASSPATH_ENTRIES = File.pathSeparator + ".." + File.separator + "aspectj5rt" + File.separator
- + "bin" + File.pathSeparator + ".." + File.separator + "loadtime5" + File.separator + "bin" + File.pathSeparator + ".."
- + File.separator + "weaver5" + File.separator + "bin"
- + File.pathSeparator + ".." + File.separator + "aj-build" + File.separator + "jars" + File.separator + "aspectj5rt.jar"
- + File.pathSeparator + ".." + File.separator + "aj-build" + File.separator + "jars" + File.separator + "loadtime5.jar"
- + File.pathSeparator + ".." + File.separator + "aj-build" + File.separator + "jars" + File.separator + "weaver5.jar";
-
- /*
- * Save reference to real stderr and stdout before starting redirection
- */
- public final static PrintStream err = System.err;
- public final static PrintStream out = System.out;
- private final static DelegatingOutputStream delegatingErr;
- private final static DelegatingOutputStream delegatingOut;
- public final static boolean DEFAULT_VERBOSE = getBoolean("org.aspectj.tools.ajc.AjcTestCase.verbose", true);
- public final static boolean DEFAULT_ERR_VERBOSE = getBoolean("org.aspectj.tools.ajc.AjcTestCase.verbose.err", DEFAULT_VERBOSE);
- public final static boolean DEFAULT_OUT_VERBOSE = getBoolean("org.aspectj.tools.ajc.AjcTestCase.verbose.out", DEFAULT_VERBOSE);
-
- private Process exec;
-
- /**
- * Helper class that represents the specification of an individual message expected to be produced during a compilation run.
- * <p>
- * Message objects are combined in a MessageSpec which can then be passed to the various assertMessage methods.
- * </p>
- *
- * @see org.aspectj.tools.ajc.AjcTestCase.MessageSpec
- */
- public static class Message {
- private int line = -1;
- private String text;
- private String sourceFileName;
- private ISourceLocation[] seeAlsos;
- public boolean careAboutOtherMessages = true;
-
- /**
- * Create a message that will match any compiler message on the given line.
- */
- public Message(int line) {
- this.line = line;
- }
-
- /**
- * Create a message that will match any compiler message on the given line, where the message text contains
- * <code>text</code>.
- */
- public Message(int line, String text) {
- this.line = line;
- this.text = text;
- if (this.text != null && text.startsWith("*")) {
- // Don't care what other messages are around
- this.careAboutOtherMessages = false;
- this.text = this.text.substring(1);
- }
- }
-
- /**
- * Create a message that will match any compiler message on the given line, where the message text contains
- * <code>text</code>.
- * <p>
- * If srcFile is non-null, the source file location of the message must end with <code>srcFile</code>.
- * </p>
- * <p>
- * If <code>seeAlso</code> is non-null, each source location in seeAlso must be matched by an extraSourceLocation in the
- * message.
- * </p>
- */
- public Message(int line, String srcFile, String text, ISourceLocation[] seeAlso) {
- this.line = line;
- StringBuffer srcFileName = new StringBuffer();
- if (srcFile != null) {
- char[] chars = srcFile.toCharArray();
- for (int i = 0; i < chars.length; i++) {
- if ((chars[i] == '\\') || (chars[i] == '/')) {
- srcFileName.append(File.separator);
- } else {
- srcFileName.append(chars[i]);
- }
- }
- this.sourceFileName = srcFileName.toString();
- }
- this.text = text;
- if (this.text != null && text.startsWith("*")) {
- // Don't care what other messages are around
- this.careAboutOtherMessages = false;
- this.text = this.text.substring(1);
- }
- this.seeAlsos = seeAlso;
- }
-
- /**
- * Create a message spec that will match any compiler message where the message text includes <code>text</code>.
- */
- public Message(String text) {
- this.text = text;
- if (this.text != null && text.startsWith("*")) {
- // Don't care what other messages are around
- this.careAboutOtherMessages = false;
- this.text = this.text.substring(1);
- }
- }
-
- /**
- * Return true if this message spec matches the given compiler message.
- */
- public boolean matches(IMessage message) {
- ISourceLocation loc = message.getSourceLocation();
- if ((loc == null) && ((line != -1) || (sourceFileName != null))) {
- return false;
- }
- if (line != -1) {
- if (loc.getLine() != line) {
- return false;
- }
- }
- if (sourceFileName != null) {
- if (!loc.getSourceFile().getPath().endsWith(sourceFileName)) {
- return false;
- }
- }
- if (text != null) {
- if (message.getMessage().indexOf(text) == -1) {
- return false;
- }
- }
- if (seeAlsos != null) {
- List<ISourceLocation> extraLocations = message.getExtraSourceLocations();
- if (extraLocations.size() != seeAlsos.length) {
- return false;
- }
- for (int i = 0; i < seeAlsos.length; i++) {
- if (!hasAMatch(extraLocations, seeAlsos[i])) {
- return false;
- }
- }
- }
- return true;
- }
-
- private boolean hasAMatch(List<ISourceLocation> srcLocations, ISourceLocation sLoc) {
- for (ISourceLocation thisLoc: srcLocations) {
- if (thisLoc.getLine() == sLoc.getLine()) {
- if (thisLoc.getSourceFile().getPath().equals(sLoc.getSourceFile().getPath())) {
- return true;
- }
- }
- }
- return false;
- }
-
- /**
- * Returns a string indicating what this <code>Message</code> will match.
- */
- @Override
- public String toString() {
- StringBuffer buff = new StringBuffer();
- buff.append("message ");
- if (sourceFileName != null) {
- buff.append("in file ");
- buff.append(sourceFileName);
- buff.append(" ");
- }
- if (line != -1) {
- buff.append("on line ");
- buff.append(line);
- buff.append(" ");
- }
- if (text != null) {
- buff.append("containing text '");
- buff.append(text);
- buff.append("' ");
- }
- if (seeAlsos != null) {
- buff.append("\n\twith see alsos:");
- for (int i = 0; i < seeAlsos.length; i++) {
- buff.append("\t\t");
- buff.append(seeAlsos[i].getSourceFile().getPath());
- buff.append(":");
- buff.append(seeAlsos[i].getLine());
- }
- }
- return buff.toString();
- }
- }
-
- /**
- * Helper class that represents the specification of a set of messages expected to be produced from a compiler run.
- * <p>
- * Instances of MessageSpec are passed to the assertMessage methods to validate <code>CompilationResult</code>s.
- */
- public static class MessageSpec {
-
- /**
- * Convenience constant that matches a CompilationResult with any number of information messages, but no others.
- */
- public static final MessageSpec EMPTY_MESSAGE_SET = new MessageSpec(null, Collections.EMPTY_LIST, Collections.EMPTY_LIST,
- Collections.EMPTY_LIST, Collections.EMPTY_LIST);
-
- boolean ignoreInfos = true;
- public List<AjcTestCase.Message> fails;
- public List<AjcTestCase.Message> infos;
- public List<AjcTestCase.Message> warnings;
- public List<AjcTestCase.Message> errors;
- public List<AjcTestCase.Message> weaves;
-
- /**
- * Set to true to enable or disable comparison of information messages.
- */
- public void setInfoComparison(boolean enabled) {
- this.ignoreInfos = !enabled;
- }
-
- /**
- * True if information messages are not being included in matching.
- */
- public boolean isIgnoringInfoMessages() {
- return ignoreInfos;
- }
-
- /**
- * Create a message specification to test a CompilationResult for a given set of info, warning, error, and fail messages.
- *
- * @param infos The set of info messages to test for. Specifying a non-null value for this parameter enables info message
- * comparison.
- * @param warnings The set of warning messages to test for - can pass null to indicate empty set.
- * @param errors The set of error messages to test for - can pass null to indicate empty set.
- * @param fails The set of fail or abort messages to test for - can pass null to indicate empty set.
- */
- public MessageSpec(List<AjcTestCase.Message> infos, List<AjcTestCase.Message> warnings,
- List<AjcTestCase.Message> errors, List<AjcTestCase.Message> fails, List<AjcTestCase.Message> weaves) {
- if (infos != null) {
- this.infos = infos;
- ignoreInfos = false;
- } else {
- this.infos = Collections.emptyList();
- }
- this.warnings = ((warnings == null) ? Collections.<AjcTestCase.Message>emptyList() : warnings);
- this.errors = ((errors == null) ? Collections.<AjcTestCase.Message>emptyList() : errors);
- this.fails = ((fails == null) ? Collections.<AjcTestCase.Message>emptyList() : fails);
- this.weaves = ((weaves == null) ? Collections.<AjcTestCase.Message>emptyList() : weaves);
- }
-
- /**
- * Create a message specification to test a CompilationResult for a given set of info, warning, and error messages. The
- * presence of any fail or abort messages in a CompilationResult will be a test failure.
- */
- public MessageSpec(List<AjcTestCase.Message> infos, List<AjcTestCase.Message> warnings, List<AjcTestCase.Message> errors) {
- this(infos, warnings, errors, null, null);
- }
-
- /**
- * Create a message specification to test a CompilationResult for a given set of warning, and error messages. The presence
- * of any fail or abort messages in a CompilationResult will be a test failure. Informational messages will be ignored.
- */
- public MessageSpec(List<AjcTestCase.Message> warnings, List<AjcTestCase.Message> errors) {
- this(null, warnings, errors, null, null);
- }
- }
-
- public static class EmptyMessageSpec extends MessageSpec {
- public EmptyMessageSpec() {
- super(null, null);
- }
- }
-
- /**
- * Helper class representing the results of running a test program built by the compiler. Provides access to the standard out
- * and error of the program, and the actual command that was executed.
- */
- public static class RunResult {
- private final String command;
- private final String stdOut;
- private final String stdErr;
-
- protected RunResult(String command, String stdOut, String stdErr) {
- this.command = command;
- this.stdOut = stdOut;
- this.stdErr = stdErr;
- }
-
- /**
- * Return the command that was executed, e.g. "java Driver".
- */
- public String getCommand() {
- return command;
- }
-
- /**
- * The standard output from the run.
- */
- public String getStdOut() {
- return stdOut;
- }
-
- /**
- * The standard error from the run.
- */
- public String getStdErr() {
- return stdErr;
- }
-
- /**
- * Returns the command that was executed to produce this result.
- */
- @Override
- public String toString() {
- return command;
- }
- }
-
- /**
- * Assert that no (non-informational) messages where produced during a compiler run.
- */
- public void assertNoMessages(CompilationResult result) {
- assertNoMessages(result, "Not expecting any compiler messages to be produced");
- }
-
- /**
- * Assert that no (non-informational) messages where produced during a compiler run.
- */
- public void assertNoMessages(CompilationResult result, String message) {
- assertMessages(result, message, MessageSpec.EMPTY_MESSAGE_SET);
- }
-
- /**
- * Assert that messages in accordance with the <code>expected</code> message specification where produced during a compiler run.
- */
- public void assertMessages(CompilationResult result, MessageSpec expected) {
- assertMessages(result, "Compilation results did not meet expected messages specification", expected);
- }
-
- /**
- * Assert that messages in accordance with the <code>expected</code> message specification where produced during a compiler run.
- */
- public void assertMessages(CompilationResult result, String message, MessageSpec expected) {
- if (result == null)
- fail("Attempt to compare null compilation results against expected.");
- List<AjcTestCase.Message> missingFails = copyAll(expected.fails);
- List<AjcTestCase.Message> missingInfos = copyAll(expected.infos);
- List<AjcTestCase.Message> missingWarnings = copyAll(expected.warnings);
- List<AjcTestCase.Message> missingErrors = copyAll(expected.errors);
- List<AjcTestCase.Message> missingWeaves = copyAll(expected.weaves);
- List<IMessage> extraFails = copyAll(result.getFailMessages());
- List<IMessage> extraInfos = copyAll(result.getInfoMessages());
- List<IMessage> extraWarnings = copyAll(result.getWarningMessages());
- List<IMessage> extraErrors = copyAll(result.getErrorMessages());
- List<IMessage> extraWeaves = copyAll(result.getWeaveMessages());
- compare(expected.fails, result.getFailMessages(), missingFails, extraFails);
- compare(expected.warnings, result.getWarningMessages(), missingWarnings, extraWarnings);
- compare(expected.errors, result.getErrorMessages(), missingErrors, extraErrors);
- if (!expected.isIgnoringInfoMessages()) {
- compare(expected.infos, result.getInfoMessages(), missingInfos, extraInfos);
- }
- compare(expected.weaves, result.getWeaveMessages(), missingWeaves, extraWeaves);
-
- boolean infosEmpty = expected.isIgnoringInfoMessages() ? true : (missingInfos.isEmpty() && extraInfos.isEmpty());
- if (!(missingFails.isEmpty() && missingWarnings.isEmpty() && missingErrors.isEmpty() && missingWeaves.isEmpty()
- && extraFails.isEmpty() && extraWarnings.isEmpty() && extraErrors.isEmpty() && extraWeaves.isEmpty() && infosEmpty)) {
- StringBuffer failureReport = new StringBuffer(message);
- failureReport.append("\n");
- if (!expected.isIgnoringInfoMessages()) {
- addMissing(failureReport, "info", missingInfos);
- }
- addMissing(failureReport, "warning", missingWarnings);
- addMissing(failureReport, "error", missingErrors);
- addMissing(failureReport, "fail", missingFails);
- addMissing(failureReport, "weaveInfo", missingWeaves);
- if (!expected.isIgnoringInfoMessages()) {
- addExtra(failureReport, "info", extraInfos);
- }
- addExtra(failureReport, "warning", extraWarnings);
- addExtra(failureReport, "error", extraErrors);
- addExtra(failureReport, "fail", extraFails);
- addExtra(failureReport, "weaveInfo", extraWeaves);
- failureReport.append("\ncommand was: ajc");
- String[] args = result.getArgs();
- for (int i = 0; i < args.length; i++) {
- failureReport.append(" ");
- failureReport.append(args[i]);
- }
- String report = failureReport.toString();
- System.err.println(failureReport);
- fail(message + "\n" + report);
- }
- }
-
- /**
- * Helper method to build a new message list for passing to a MessageSpec.
- */
- protected List<Message> newMessageList(Message m1) {
- List<Message> ret = new ArrayList<Message>();
- ret.add(m1);
- return ret;
- }
-
- /**
- * Helper method to build a new message list for passing to a MessageSpec.
- */
- protected List<Message> newMessageList(Message m1, Message m2) {
- List<Message> ret = new ArrayList<Message>();
- ret.add(m1);
- ret.add(m2);
- return ret;
- }
-
- /**
- * Helper method to build a new message list for passing to a MessageSpec.
- */
- protected List<Message> newMessageList(Message m1, Message m2, Message m3) {
- List<Message> ret = new ArrayList<Message>();
- ret.add(m1);
- ret.add(m2);
- ret.add(m3);
- return ret;
- }
-
- /**
- * Helper method to build a new message list for passing to a MessageSpec.
- */
- protected List newMessageList(Message[] messages) {
- List ret = new ArrayList();
- for (int i = 0; i < messages.length; i++) {
- ret.add(messages[i]);
- }
- return ret;
- }
-
- /**
- * Perform a compilation and return the result.
- *
- * @param baseDir the base directory relative to which all relative paths and directories in the arguments will be interpreted.
- * @param args the compiler arguments, as you would specify on the command-line. See the Ajc class for a description of the
- * argument processing done in order to run the compilation in a sandbox.
- * @see org.aspectj.tools.ajc.Ajc
- */
- public CompilationResult ajc(File baseDir, String[] args) {
- try {
- ajc.setBaseDir(baseDir);
- args = fixupArgs(args);
- return ajc.compile(args);
- } catch (IOException ioEx) {
- fail("IOException thrown during compilation: " + ioEx);
- }
- return null;
- }
-
- public File getSandboxDirectory() {
- return ajc.getSandboxDirectory();
- }
-
- /**
- * Indicate whether or not the sandbox should be emptied before the next compile.
- *
- * @see org.aspectj.tools.ajc.Ajc#setShouldEmptySandbox(boolean)
- */
- public void setShouldEmptySandbox(boolean empty) {
- ajc.setShouldEmptySandbox(empty);
- }
-
- public RunResult getLastRunResult() {
- return lastRunResult;
- }
-
- public void testNothingForAntJUnit() {
- }
-
- /**
- * Run the given class (main method), and return the result in a RunResult. The program runs with a classpath containing the
- * sandbox directory, runtime, testing-client, bridge, and util projects (all used by the Tester class), and any jars in the
- * sandbox.
- */
- public RunResult run(String className) {
- return run(className, new String[0], null);
- }
-
- public RunResult run(String className, String[] args, String classpath) {
- return run(className, null, args, "", "", null, false,false);
- }
-
- /**
- * Run the given class, and return the result in a RunResult. The program runs with a classpath containing the sandbox
- * directory, runtime, testing-client, bridge, and util projects (all used by the Tester class), and any jars in the sandbox.
- *
- * @param args the arguments to pass to the program.
- * @param classpath the execution classpath, the sandbox directory, runtime, testing-client, bridge, and util projects will all
- * be appended to the classpath, as will any jars in the sandbox.
- * @param runSpec
- */
- public RunResult run(String className, String moduleName, String[] args, String vmargs, final String classpath, String modulepath, boolean useLTW, boolean useFullLTW) {
-
- if (args != null) {
- for (int i = 0; i < args.length; i++) {
- args[i] = substituteSandbox(args[i]);
- }
- }
- lastRunResult = null;
- StringBuffer cp = new StringBuffer();
- if (classpath != null) {
- // allow replacing this special variable, rather than copying all files to allow tests of jars that don't end in .jar
- cp.append(substituteSandbox(classpath));
- cp.append(File.pathSeparator);
- }
- if (moduleName == null) {
- // When running modules, we want more control so don't try to be helpful by adding all jars
- cp.append(ajc.getSandboxDirectory().getAbsolutePath());
- getAnyJars(ajc.getSandboxDirectory(), cp);
- }
- StringBuffer mp = new StringBuffer();
- if (modulepath != null) {
- mp.append(substituteSandbox(modulepath));
- mp.append(File.pathSeparator);
- }
-
- URLClassLoader sandboxLoader;
- ClassLoader parentLoader = getClass().getClassLoader().getParent();
-
- /* Sandbox -> AspectJ -> Extension -> Bootstrap */
- if ( !useFullLTW && useLTW) {
- // URLClassLoader testLoader = (URLClassLoader) getClass().getClassLoader();
- /*
- * Create a new AspectJ class loader using the existing test CLASSPATH and any missing Java 5 projects
- */
- URL[] testUrls = new URL[0];//testLoader.getURLs();
- // What are the URLs on java 8?
- URL[] java5Urls = getURLs(DEFAULT_CLASSPATH_ENTRIES);//getURLs(JAVA5_CLASSPATH_ENTRIES);
- URL[] urls = new URL[testUrls.length + java5Urls.length];
- System.arraycopy(testUrls, 0, urls, 0, testUrls.length);
- System.arraycopy(java5Urls, 0, urls, testUrls.length, java5Urls.length);
- // ClassLoader aspectjLoader = new URLClassLoader(getURLs(DEFAULT_CLASSPATH_ENTRIES),parent);
- ClassLoader aspectjLoader = new URLClassLoader(urls, parentLoader);
- URL[] sandboxUrls = getURLs(cp.toString());
- sandboxLoader = createWeavingClassLoader(sandboxUrls, aspectjLoader);
- // sandboxLoader = createWeavingClassLoader(sandboxUrls,testLoader);
- } else if(useFullLTW && useLTW) {
- if(vmargs == null){
- vmargs ="";
- }
-
- File directory = new File (".");
- String absPath = directory.getAbsolutePath();
- String javaagent= absPath+File.separator+".."+File.separator+"aj-build"+File.separator+"dist"+File.separator+"tools"+File.separator+"lib"+File.separator+"aspectjweaver.jar";
- try {
- String command ="java " +vmargs+ " -classpath " + cp +" -javaagent:"+javaagent + " " + className ;
-
- // Command is executed using ProcessBuilder to allow setting CWD for ajc sandbox compliance
- ProcessBuilder pb = new ProcessBuilder(tokenizeCommand(command));
- pb.directory( new File(ajc.getSandboxDirectory().getAbsolutePath()));
- exec = pb.start();
- BufferedReader stdInput = new BufferedReader(new InputStreamReader(exec.getInputStream()));
- BufferedReader stdError = new BufferedReader(new InputStreamReader(exec.getErrorStream()));
- exec.waitFor();
- lastRunResult = createResultFromBufferReaders(command,stdInput, stdError);
- } catch (Exception e) {
- System.out.println("Error executing full LTW test: " + e);
- e.printStackTrace();
- }
- return lastRunResult;
- } else if (moduleName != null) {
- // CODE FOR RUNNING MODULES
- if(vmargs == null){
- vmargs ="";
- }
- try {
- if (mp.indexOf("$runtime") != -1) {
- mp = mp.replace(mp.indexOf("$runtime"),"$runtime".length(),TestUtil.aspectjrtPath().toString());
- }
- if (cp.indexOf("aspectjrt")==-1) {
- cp.append(TestUtil.aspectjrtPath().getPath()).append(File.pathSeparator);
- }
- String command = LangUtil.getJavaExecutable().getAbsolutePath() + " " +vmargs+ (cp.length()==0?"":" -classpath " + cp) + " -p "+mp+" --module "+moduleName ;
- System.out.println("Command is "+command);
- // Command is executed using ProcessBuilder to allow setting CWD for ajc sandbox compliance
- ProcessBuilder pb = new ProcessBuilder(tokenizeCommand(command));
- pb.directory( new File(ajc.getSandboxDirectory().getAbsolutePath()));
- exec = pb.start();
- BufferedReader stdInput = new BufferedReader(new InputStreamReader(exec.getInputStream()));
- BufferedReader stdError = new BufferedReader(new InputStreamReader(exec.getErrorStream()));
- exec.waitFor();
- lastRunResult = createResultFromBufferReaders(command,stdInput, stdError);
- } catch (Exception e) {
- System.out.println("Error executing module test: " + e);
- e.printStackTrace();
- }
- return lastRunResult;
- } else if (vmargs!=null && (vmargs.contains("--add-modules") || vmargs.contains("--limit-modules") || vmargs.contains("--add-reads"))) {
- // If --add-modules supplied, need to fork the test
- try {
- // if (mp.indexOf("$runtime") != -1) {
- // mp = mp.replace(mp.indexOf("$runtime"),"$runtime".length(),TestUtil.aspectjrtPath().toString());
- // }
- if (cp.indexOf("aspectjrt")==-1) {
- cp.append(File.pathSeparator).append(TestUtil.aspectjrtPath().getPath());
- }
- String command = LangUtil.getJavaExecutable().getAbsolutePath() + " " +vmargs+ (cp.length()==0?"":" -classpath " + cp) + " " + className ;
- System.out.println("Command is "+command);
- // Command is executed using ProcessBuilder to allow setting CWD for ajc sandbox compliance
- ProcessBuilder pb = new ProcessBuilder(tokenizeCommand(command));
- pb.directory( new File(ajc.getSandboxDirectory().getAbsolutePath()));
- exec = pb.start();
- BufferedReader stdInput = new BufferedReader(new InputStreamReader(exec.getInputStream()));
- BufferedReader stdError = new BufferedReader(new InputStreamReader(exec.getErrorStream()));
- exec.waitFor();
- lastRunResult = createResultFromBufferReaders(command,stdInput, stdError);
- } catch (Exception e) {
- System.out.println("Error executing module test: " + e);
- e.printStackTrace();
- }
- return lastRunResult;
- } else {
- cp.append(DEFAULT_CLASSPATH_ENTRIES);
- URL[] urls = getURLs(cp.toString());
- sandboxLoader = new URLClassLoader(urls, parentLoader);
- }
- ByteArrayOutputStream baosOut = new ByteArrayOutputStream();
- ByteArrayOutputStream baosErr = new ByteArrayOutputStream();
-
-
- StringBuffer command = new StringBuffer();
- command.append("java -classpath ");
- command.append(cp.toString());
- command.append(" ");
- command.append(className);
- for (int i = 0; i < args.length; i++) {
- command.append(" ");
- command.append(args[i]);
- }
- // try {
- // // Enable the security manager
- // Policy.setPolicy(new MyPolicy());
- // SecurityManager sm = new SecurityManager();
- // System.setSecurityManager(sm);
- // } catch (SecurityException se) {
- // // SecurityManager already set
- // }
-
- ClassLoader contexClassLoader = Thread.currentThread().getContextClassLoader();
- try {
- try {
- Class<?> testerClass = sandboxLoader.loadClass("org.aspectj.testing.Tester");
- Method setBaseDir = testerClass.getDeclaredMethod("setBASEDIR", new Class[] { File.class });
- setBaseDir.invoke(null, new Object[] { ajc.getSandboxDirectory() });
- } catch (InvocationTargetException itEx) {
- fail("Unable to prepare org.aspectj.testing.Tester for test run: " + itEx.getTargetException());
- } catch (Exception ex) {
- fail("Unable to prepare org.aspectj.testing.Tester for test run: " + ex);
- }
- startCapture(baosErr, baosOut);
-
- /* Frameworks like XML use context class loader for dynamic loading */
- Thread.currentThread().setContextClassLoader(sandboxLoader);
-
- Class<?> toRun = sandboxLoader.loadClass(className);
- Method mainMethod = toRun.getMethod("main", new Class[] { String[].class });
- mainMethod.invoke(null, new Object[] { args });
- } catch (ClassNotFoundException cnf) {
- fail("Can't find class: " + className);
- } catch (NoSuchMethodException nsm) {
- fail(className + " does not have a main method");
- } catch (IllegalAccessException illEx) {
- fail("main method in class " + className + " is not public");
- } catch (InvocationTargetException invTgt) {
- // the main method threw an exception...
- fail("Exception thrown by " + className + ".main(String[]) :" + invTgt.getTargetException());
- } finally {
-
- // try {
- // // Enable the security manager
- // SecurityManager sm = new SecurityManager();
- // System.setSecurityManager(null);
- // } catch (SecurityException se) {
- // se.printStackTrace();
- // // SecurityManager already set
- // }
- Thread.currentThread().setContextClassLoader(contexClassLoader);
- stopCapture(baosErr, baosOut);
- lastRunResult = new RunResult(command.toString(), new String(baosOut.toByteArray()), new String(baosErr.toByteArray()));
- }
- return lastRunResult;
- }
-
- private List<String >tokenizeCommand(String command) {
- StringTokenizer st = new StringTokenizer(command," ", false);
- ArrayList<String> arguments = new ArrayList<String>();
- while(st.hasMoreElements()){
- String nextToken =st.nextToken();
- arguments.add(nextToken);
- }
-
- return arguments;
- }
-
- private RunResult createResultFromBufferReaders(String command,
- BufferedReader stdInput, BufferedReader stdError) throws IOException {
- String line = "";
- ByteArrayOutputStream baosOut = new ByteArrayOutputStream();
- ByteArrayOutputStream baosErr = new ByteArrayOutputStream();
-
- PrintWriter stdOutWriter = new PrintWriter(baosOut);
- PrintWriter stdErrWriter = new PrintWriter(baosErr);
-
- while ((line = stdInput.readLine()) != null) {
- stdOutWriter.println(line);
- System.out.println(line);
- }
- stdOutWriter.flush();
- while ((line = stdError.readLine()) != null) {
- stdErrWriter.println(line);
- System.err.println(line);
-
- }
- stdErrWriter.flush();
-
- baosOut.close();
- baosErr.close();
-
- return new RunResult(command.toString(), new String(baosOut.toByteArray()), new String(baosErr.toByteArray()));
- }
-
- // static class MyPolicy extends Policy {
- //
- // @Override
- // public boolean implies(ProtectionDomain domain, Permission permission) {
- // // if (permission != SecurityConstants.GET_POLICY_PERMISSION) {
- // // // System.out.println(domain + " " + permission.getName());
- // // System.out.println(permission.getName());
- // // }
- // // if (true) {
- // // return true;
- // // }
- // if (permission instanceof PropertyPermission) {
- // return true;
- // }
- // if (permission instanceof RuntimePermission) {
- // return true;
- // }
- // if (permission instanceof FilePermission) {
- // // System.out.println(permission);
- // return true;
- // }
- // if (permission instanceof ReflectPermission) {
- // return true;
- // }
- // // System.out.println(permission);
- // return super.implies(domain, permission);
- // // return true;
- // }
- // }
-
- /*
- * Must create weaving class loader reflectively using new parent so we don't have a reference to a World loaded from CLASSPATH
- * which won't be able to resolve Java 5 specific extensions and may cause ClassCastExceptions
- */
- private URLClassLoader createWeavingClassLoader(URL[] urls, ClassLoader parent) {
- URLClassLoader loader = null;
-
- try {
- Class loaderClazz = Class.forName("org.aspectj.weaver.loadtime.WeavingURLClassLoader", false, parent);
- Class[] parameterTypes = new Class[] { urls.getClass(), ClassLoader.class };
- Object[] parameters = new Object[] { urls, parent };
- Constructor constructor = loaderClazz.getConstructor(parameterTypes);
- loader = (URLClassLoader) constructor.newInstance(parameters);
- } catch (InvocationTargetException ex) {
- ex.printStackTrace();
- fail("Cannot create weaving class loader: " + ex.getTargetException());
- } catch (Exception ex) {
- ex.printStackTrace();
- fail("Cannot create weaving class loader: " + ex.toString());
- }
-
- return loader;
- }
-
- private URL[] getURLs(String classpath) {
- StringTokenizer strTok = new StringTokenizer(classpath, File.pathSeparator);
- URL[] urls = new URL[strTok.countTokens()];
- try {
- for (int i = 0; i < urls.length; i++) {
- urls[i] = new File(strTok.nextToken()).getCanonicalFile().toURL();
- }
- } catch (Exception malEx) {
- fail("Bad classpath specification: " + classpath);
- }
-
- return urls;
- }
-
- private String substituteSandbox(String path) {
- // the longhand form of the non 1.3 API: path.replace("$sandbox", ajc.getSandboxDirectory().getAbsolutePath());
- while (path.indexOf("$sandbox") != -1) {
- int pos = path.indexOf("$sandbox");
- String firstbit = path.substring(0, pos);
- String endbit = path.substring(pos + 8);
- path = firstbit + ajc.getSandboxDirectory().getAbsolutePath() + endbit;
- }
- return path;
- }
-
- /**
- * Any central pre-processing of args. This supplies aspectjrt.jar if available and classpath not set.
- *
- * @param args the String[] args to fix up
- * @return the String[] args to use
- */
- protected String[] fixupArgs(String[] args) {
- if (null == args) {
- return null;
- }
- int cpIndex = -1;
- boolean hasruntime = false;
- for (int i = 0; i < args.length - 1; i++) {
- args[i] = adaptToPlatform(args[i]);
- if ("-classpath".equals(args[i])) {
- cpIndex = i;
- args[i + 1] = substituteSandbox(args[i + 1]);
- String next = args[i + 1];
- hasruntime = ((null != next) && (-1 != next.indexOf("aspectjrt.jar")));
- } else if ("-p".equals(args[i]) || "--module-path".equals(args[i])) {
- args[i + 1] = substituteSandbox(args[i + 1]);
- }
- }
- if (-1 == cpIndex) {
- String[] newargs = new String[args.length + 2];
- newargs[0] = "-classpath";
- newargs[1] = TestUtil.aspectjrtPath().getPath();
- System.arraycopy(args, 0, newargs, 2, args.length);
- args = newargs;
- cpIndex = 1;
- } else {
- if (!hasruntime) {
- cpIndex++;
- String[] newargs = new String[args.length];
- System.arraycopy(args, 0, newargs, 0, args.length);
- newargs[cpIndex] = args[cpIndex] + File.pathSeparator + TestUtil.aspectjrtPath().getPath();
- args = newargs;
- }
- }
- boolean needsJRTFS = LangUtil.is19VMOrGreater();
- if (needsJRTFS) {
- if (args[cpIndex].indexOf(LangUtil.JRT_FS) == -1) {
- String jrtfsPath = LangUtil.getJrtFsFilePath();
- args[cpIndex] = jrtfsPath + File.pathSeparator + args[cpIndex];
- }
- }
- return args;
- }
-
- private String adaptToPlatform(String s) {
- String ret = s.replace(';', File.pathSeparatorChar);
- // ret = ret.replace(':',File.pathSeparatorChar);
- return ret;
- }
-
- private <T> List<T> copyAll(List<T> in) {
- if (in == Collections.EMPTY_LIST)
- return in;
-
- List<T> out = new ArrayList<T>();
- for (Iterator<T> iter = in.iterator(); iter.hasNext();) {
- out.add(iter.next());
- }
- return out;
- }
-
- /**
- * Compare the set of expected messages against the set of actual messages, leaving in missingElements the set of messages that
- * were expected but did not occur, and in extraElements the set of messages that occured but were not excpected
- *
- * @param expected the expected messages
- * @param actual the actual messages
- * @param missingElements the missing messages, when passed in must contain all of the expected messages
- * @param extraElements the additional messages, when passed in must contain all of the actual messages
- */
- private void compare(List<AjcTestCase.Message> expected, List<IMessage> actual, List<AjcTestCase.Message> missingElements, List<IMessage> extraElements) {
- for (Message expectedMessage: expected) {
- for (IMessage actualMessage: actual) {
- if (expectedMessage.matches(actualMessage)) {
- if (expectedMessage.careAboutOtherMessages) {
- missingElements.remove(expectedMessage);
- extraElements.remove(actualMessage);
- }
- else {
- missingElements.clear();
- extraElements.clear();
- }
- }
- }
- }
- }
-
- private void addMissing(StringBuffer buff, String type, List<AjcTestCase.Message> messages) {
- if (!messages.isEmpty()) {
- buff.append("Missing expected ");
- buff.append(type);
- buff.append(" messages:\n");
- for (Iterator<AjcTestCase.Message> iter = messages.iterator(); iter.hasNext();) {
- buff.append("\t");
- buff.append(iter.next().toString());
- buff.append("\n");
- }
- }
- }
-
- private void addExtra(StringBuffer buff, String type, List messages) {
- if (!messages.isEmpty()) {
- buff.append("Unexpected ");
- buff.append(type);
- buff.append(" messages:\n");
- for (Iterator iter = messages.iterator(); iter.hasNext();) {
- buff.append("\t");
- buff.append(iter.next().toString());
- buff.append("\n");
- }
- }
- }
-
- // add any jars in the directory to the classpath
- private void getAnyJars(File dir, StringBuffer buff) {
- File[] files = dir.listFiles();
- for (int i = 0; i < files.length; i++) {
- if (files[i].getName().endsWith(".jar")) {
- buff.append(File.pathSeparator);
- buff.append(files[i].getAbsolutePath());
- } else if (files[i].isDirectory()) {
- getAnyJars(files[i], buff);
- }
- }
- }
-
- private static void startCapture(OutputStream errOS, OutputStream outOS) {
- delegatingErr.add(errOS);
- delegatingOut.add(outOS);
-
- delegatingErr.setVerbose(DEFAULT_ERR_VERBOSE);
- delegatingOut.setVerbose(DEFAULT_OUT_VERBOSE);
- }
-
- private static void stopCapture(OutputStream errOS, OutputStream outOS) {
- delegatingErr.setVerbose(true);
- delegatingOut.setVerbose(true);
-
- delegatingErr.remove(errOS);
- delegatingOut.remove(outOS);
- }
-
- private static boolean getBoolean(String name, boolean def) {
- String defaultValue = String.valueOf(def);
- String value = System.getProperty(name, defaultValue);
- return Boolean.valueOf(value).booleanValue();
- }
-
- /*
- * (non-Javadoc)
- *
- * @see junit.framework.TestCase#setUp()
- */
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- ajc = new Ajc();
- }
-
- /*
- * (non-Javadoc)
- *
- * @see junit.framework.TestCase#tearDown()
- */
- @Override
- protected void tearDown() throws Exception {
- super.tearDown();
- // ajc = null;
- }
-
- static {
- // new RuntimeException("*** AjcTestCase.<clinit>()").printStackTrace();
- delegatingErr = new DelegatingOutputStream(err);
- System.setErr(new PrintStream(delegatingErr));
- delegatingOut = new DelegatingOutputStream(out);
- System.setOut(new PrintStream(delegatingOut));
- }
-
-
- }
|