summaryrefslogtreecommitdiffstats
path: root/org.aspectj.ajdt.core
diff options
context:
space:
mode:
authoracolyer <acolyer>2004-08-04 11:59:41 +0000
committeracolyer <acolyer>2004-08-04 11:59:41 +0000
commit9bf0a7543072b66835b2417ce932fc34da4e45ee (patch)
tree51170bd1254596a34b1b32b5ad6352ab24820ad6 /org.aspectj.ajdt.core
parentef7885fd1269261aec9cb1265f0e15472fdb03bb (diff)
downloadaspectj-9bf0a7543072b66835b2417ce932fc34da4e45ee.tar.gz
aspectj-9bf0a7543072b66835b2417ce932fc34da4e45ee.zip
Added support to ease programmatic testing of compiler (AjcTestCase
class and accompanying support).
Diffstat (limited to 'org.aspectj.ajdt.core')
-rw-r--r--org.aspectj.ajdt.core/.classpath27
-rw-r--r--org.aspectj.ajdt.core/src/org/aspectj/tools/ajc/Main.java9
-rw-r--r--org.aspectj.ajdt.core/testsrc/org/aspectj/tools/ajc/Ajc.java396
-rw-r--r--org.aspectj.ajdt.core/testsrc/org/aspectj/tools/ajc/AjcTestCase.java646
-rw-r--r--org.aspectj.ajdt.core/testsrc/org/aspectj/tools/ajc/AjcTestCaseTest.java51
-rw-r--r--org.aspectj.ajdt.core/testsrc/org/aspectj/tools/ajc/CompilationResult.java202
-rw-r--r--org.aspectj.ajdt.core/testsrc/org/aspectj/tools/ajc/MainTest.java13
7 files changed, 1326 insertions, 18 deletions
diff --git a/org.aspectj.ajdt.core/.classpath b/org.aspectj.ajdt.core/.classpath
index 0f9073da2..32c74b39c 100644
--- a/org.aspectj.ajdt.core/.classpath
+++ b/org.aspectj.ajdt.core/.classpath
@@ -1,16 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
- <classpathentry kind="src" path="src"/>
- <classpathentry kind="var" path="JRE_LIB" sourcepath="JRE_SRC"/>
- <classpathentry kind="src" path="/org.eclipse.jdt.core"/>
- <classpathentry kind="src" path="/bridge"/>
- <classpathentry kind="src" path="/weaver"/>
- <classpathentry kind="src" path="/asm"/>
- <classpathentry kind="src" path="/util"/>
- <classpathentry kind="src" path="/runtime"/>
- <classpathentry kind="src" path="testsrc"/>
- <classpathentry kind="lib" path="/lib/bcel/bcel.jar" sourcepath="/lib/bcel/bcel-src.zip"/>
- <classpathentry kind="lib" path="/lib/junit/junit.jar" sourcepath="/lib/junit/junit-src.jar"/>
- <classpathentry kind="src" path="/testing-util"/>
- <classpathentry kind="output" path="bin"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry sourcepath="JRE_SRC" kind="var" path="JRE_LIB"/>
+ <classpathentry kind="src" path="/org.eclipse.jdt.core"/>
+ <classpathentry kind="src" path="/bridge"/>
+ <classpathentry kind="src" path="/weaver"/>
+ <classpathentry kind="src" path="/asm"/>
+ <classpathentry kind="src" path="/util"/>
+ <classpathentry kind="src" path="/runtime"/>
+ <classpathentry kind="src" path="testsrc"/>
+ <classpathentry sourcepath="/lib/bcel/bcel-src.zip" kind="lib" path="/lib/bcel/bcel.jar"/>
+ <classpathentry sourcepath="/lib/junit/junit-src.jar" kind="lib" path="/lib/junit/junit.jar"/>
+ <classpathentry kind="src" path="/testing-util"/>
+ <classpathentry kind="src" path="/testing-client"/>
+ <classpathentry kind="output" path="bin"/>
</classpath>
diff --git a/org.aspectj.ajdt.core/src/org/aspectj/tools/ajc/Main.java b/org.aspectj.ajdt.core/src/org/aspectj/tools/ajc/Main.java
index 1ec80de03..fa790ae7c 100644
--- a/org.aspectj.ajdt.core/src/org/aspectj/tools/ajc/Main.java
+++ b/org.aspectj.ajdt.core/src/org/aspectj/tools/ajc/Main.java
@@ -192,6 +192,11 @@ public class Main {
return ourHandler;
}
+ // for unit testing...
+ void setController(CommandController controller) {
+ this.controller = controller;
+ }
+
/**
* Run without throwing exceptions but optionally using System.exit(..).
* This sets up a message handler which emits messages immediately,
@@ -284,7 +289,7 @@ public class Main {
boolean passed = command.runCommand(args, holder);
if (report(passed, holder) && controller.incremental()) {
// final boolean onCommandLine = controller.commandLineIncremental();
- while (controller.doRepeatCommand()) {
+ while (controller.doRepeatCommand(command)) {
holder.clearMessages();
if (controller.buildFresh()) {
continue outer;
@@ -646,7 +651,7 @@ public class Main {
}
/** @return false if we should quit, true to do another command */
- boolean doRepeatCommand() {
+ boolean doRepeatCommand(ICommand command) {
if (!running) {
return false;
}
diff --git a/org.aspectj.ajdt.core/testsrc/org/aspectj/tools/ajc/Ajc.java b/org.aspectj.ajdt.core/testsrc/org/aspectj/tools/ajc/Ajc.java
new file mode 100644
index 000000000..5df4feae5
--- /dev/null
+++ b/org.aspectj.ajdt.core/testsrc/org/aspectj/tools/ajc/Ajc.java
@@ -0,0 +1,396 @@
+/* *******************************************************************
+ * Copyright (c) 2004 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Common Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * Adrian Colyer,
+ * ******************************************************************/
+package org.aspectj.tools.ajc;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringTokenizer;
+
+import junit.framework.AssertionFailedError;
+
+import org.aspectj.bridge.ICommand;
+import org.aspectj.bridge.IMessage;
+import org.aspectj.bridge.IMessageHandler;
+import org.aspectj.bridge.MessageHandler;
+import org.aspectj.util.FileUtil;
+
+/**
+ * The Ajc class is intended for use as part of a unit-test suite, it drives
+ * the AspectJ compiler and lets you check the compilation results. Compilations
+ * run in a sandbox that is created in C:\temp\ajcSandbox or /tmp/ajcSandbox
+ * depending on your platform.
+ * <p>
+ * The expected usage of Ajc is through the TestCase superclass,
+ * AjcTestCase, which provides helper methods that conveniently
+ * drive the base functions exposed by this class.
+ * </p>
+ * @see org.aspectj.tools.ajc.AjcTestCase
+ */
+public class Ajc {
+
+ private static final String SANDBOX_NAME = "ajcSandbox";
+ private static final String TESTER_PATH =
+ "../testing-client/bin" + File.pathSeparator + "../runtime/bin";
+ private CompilationResult result;
+ private File sandbox;
+ private File baseDir;
+ private Main main;
+ private String[] ajcArgs;
+ private int incrementalStage = 10;
+ private boolean shouldEmptySandbox = true;
+ private AjcCommandController controller;
+
+ /**
+ * Constructs a new Ajc instance, with a new AspectJ compiler
+ * inside.
+ */
+ public Ajc() {
+ main = new Main();
+ controller = new AjcCommandController();
+ main.setController(controller);
+ }
+
+ /**
+ * By default, each call to <code>compile</code> creates a new
+ * sandbox (C:\temp\ajcSandbox\ajtTestxxx.tmp, or /tmp/ajcSandbox/ajcTestxxx.tmp
+ * depending on your platform). To write a test that performs multiple
+ * (non-incremental) compiles, building on the results of previous
+ * compilations, set 'should empty sandbox' to false after the first
+ * compile, which will cause subsequent compiles in the test to use the
+ * same directory and contents.
+ */
+ public void setShouldEmptySandbox(boolean empty) {
+ this.shouldEmptySandbox = empty;
+ }
+
+ /**
+ * Call the compiler with the given arguments (args are exactly the same
+ * as you would pass to ajc on the command-line). The results of the
+ * compile are returned in a <code>CompilationResult</code>, which
+ * provides for easy testing of results.
+ * <p>The compilation happens in a sandbox (C:\temp\ajcSandbox\ajTestxxx.tmp or
+ * /tmp/ajcSandbox/ajcTestxxx.tmp depending on platform). Compiler arguments are
+ * adapted to the sandbox as follows.</p>
+ * <p>For every file or directory listed in an argument (source file, or component
+ * of inpath, aspectpath, sourceroots, classpath,...), if the file is specified
+ * using an absolute path then it is left unchanged, but if the file is specified
+ * using a relative path, and a base directory (see setBaseDir) has been provided,
+ * then files/directories are copied from the base directory to the sandbox, and the
+ * compiler arguments adjusted to reflect their new location.
+ * </p>
+ * <p>For example, given a baseDir of "tests/pr12345" and a compile command:
+ * "ajc src/A.java src/B.java", the files in
+ * <pre>
+ * tests/pr12345/
+ * src/
+ * A.java
+ * B.java
+ * </pre>
+ * are copied to:
+ * <pre>
+ * ajcSandbox/ajcTestxxx.tmp/
+ * src/
+ * A.java
+ * B.java
+ * </pre>
+ * <p>
+ * If no classpath is specified (no -classpath in the arguments) the classpath will
+ * be set to include the sandbox directory, testing-client/bin (for the Tester class),
+ * and runtime/bin (for the AspectJ runtime). If a classpath <i>is</i> specified,
+ * then any relative directories in it will be made relative to the sandbox, and
+ * the testing-client and runtime bin directories are also added.
+ * </p>
+ * <p>
+ * If no output directory is specified (no -d in the arguments), the output directory
+ * is set to the sandbox. If a directory is specified, and the path is relative, it
+ * will be made relative to the sandbox.
+ * </p>
+ * <ul>
+ * </ul>
+ * </p>
+ * @param args The compiler arguments.
+ * @return a CompilationResult object with all the messages produced by
+ * the compiler, a description of the ajc command that was issued,
+ * and the standard output and error of the compile (excluding messages
+ * which are provided separately)
+ * @throws IOException
+ * @see org.aspectj.tools.ajc.CompilationResult
+ */
+ public CompilationResult compile(String[] args) throws IOException {
+ incrementalStage = 10;
+ return compile(args,false);
+ }
+
+ private CompilationResult compile(String[] args,boolean isIncremental) throws IOException {
+ result = null;
+ ajcArgs = args;
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ PrintStream pout = new PrintStream(out);
+ ByteArrayOutputStream err = new ByteArrayOutputStream();
+ PrintStream perr = new PrintStream(err);
+ PrintStream systemOut = System.out;
+ PrintStream systemErr = System.err;
+ System.setOut(pout);
+ System.setErr(perr);
+
+ List fails = new ArrayList();
+ List errors = new ArrayList();
+ List warnings = new ArrayList();
+ List infos = new ArrayList();
+
+ try {
+ if (!isIncremental && shouldEmptySandbox) {
+ createEmptySandbox();
+ }
+ args = adjustToSandbox(args,!isIncremental);
+ MessageHandler holder = new MessageHandler();
+ main.setHolder(holder);
+ if (isIncremental) {
+ controller.doIncremental(holder);
+ } else {
+ main.runMain(args,false);
+ }
+ addMessagesTo(infos,holder.getMessages(IMessage.INFO,false));
+ addMessagesTo(warnings,holder.getWarnings());
+ addMessagesTo(errors,holder.getErrors());
+ addMessagesTo(fails,holder.getMessages(IMessage.FAIL,true));
+ String stdOut = new String(out.toByteArray());
+ String stdErr = new String(err.toByteArray());
+ result = new CompilationResult(args,stdOut,stdErr,infos,errors,warnings,fails);
+ } finally {
+ System.setOut(systemOut);
+ System.setErr(systemErr);
+ }
+ return result;
+ }
+
+ /**
+ * After compiling for the first time with compile(), if the -incremental option was specified
+ * you can do as many subsequent incremental compiles as you like by calling this method.
+ * <p>
+ * Throws an IllegalStateException if you try and call this method without first doing a compile
+ * that specified the -incremental option.
+ * </p>
+ * @return A CompilationResult giving the results of the most recent increment.
+ * @throws IOException
+ */
+ public CompilationResult doIncrementalCompile() throws IOException {
+ if ((ajcArgs == null) || !isIncremental(ajcArgs)) {
+ throw new IllegalStateException("Can't do incremental compile unless -incremental specified and first compile has taken place");
+ }
+ incrementalStage += 10;
+ return compile(ajcArgs,true);
+ }
+
+ /**
+ * Return the result of the last compile or incremental compile. This is the same as the
+ * return value from the compile() or doIncrementalCompile() methods.
+ */
+ public CompilationResult getLastCompilationResult() {
+ return result;
+ }
+
+ /**
+ * Get the sandbox directory used for the compilation.
+ */
+ public File getSandboxDirectory() {
+ if (sandbox == null) {createEmptySandbox();}
+ return sandbox;
+ }
+
+ /**
+ * Set the base directory relative to which all relative paths specified in the arguments to a compile will be
+ * interpreted.
+ */
+ public void setBaseDir(File dir) {
+ if ((dir != null) && !dir.isDirectory()) throw new IllegalArgumentException(dir.getPath() + " is not a directory");
+ baseDir = dir;
+ }
+
+ private void addMessagesTo(List aList, IMessage[] messages) {
+ for (int i = 0; i < messages.length; i++) {
+ aList.add(messages[i]);
+ }
+ }
+
+ private boolean isIncremental(String[] args) {
+ for (int i = 0; i < args.length; i++) {
+ if (args[i].trim().equals("-incremental")) return true;
+ }
+ return false;
+ }
+
+ private void createEmptySandbox() {
+ String os = System.getProperty("os.name");
+ File tempDir = null;
+ // AMC - I did this rather than use the JDK default as I hate having to go look
+ // in c:\documents and settings\......... for the results of a failed test.
+ if (os.startsWith("Windows")) {
+ tempDir = new File("C:\\temp");
+ } else {
+ tempDir = new File("/tmp");
+ }
+ File sandboxRoot = new File(tempDir,SANDBOX_NAME);
+ if (!sandboxRoot.exists()) {
+ sandboxRoot.mkdir();
+ }
+
+ FileUtil.deleteContents(sandboxRoot);
+
+ try {
+ sandbox = File.createTempFile("ajcTest",".tmp",sandboxRoot);
+ sandbox.delete();
+ sandbox.mkdir();
+ } catch (IOException ioEx) {
+ throw new AssertionFailedError("Unable to create sandbox directory for test");
+ }
+ }
+
+ /**
+ * Make every relative file name and dir be absolute under sandbox
+ * Add TESTER_PATH to classpath
+ */
+ private String[] adjustToSandbox(String[] args,boolean doCopy) throws IOException {
+ String[] newArgs = new String[args.length];
+ boolean hasClasspath = false;
+ boolean hasOutdir = false;
+ for (int i = 0; i < args.length; i++) {
+ newArgs[i] = args[i];
+ if (FileUtil.hasSourceSuffix(args[i])) {
+ File f = new File(args[i]);
+ //newArgs[i] = new File(baseDir,args[i]).getAbsolutePath(); // might be quicker?
+ newArgs[i] = adjustFileOrDir(f,doCopy).getAbsolutePath();
+ } else {
+ if ((args[i].equals("-aspectpath") ||
+ args[i].equals("-inpath") ||
+ args[i].equals("-injars") ||
+ args[i].equals("-classpath") ||
+ args[i].equals("-sourceroots") ||
+ args[i].equals("-Xlintfile") ||
+ args[i].equals("-extdirs") ||
+ args[i].equals("-d")) &&
+ args.length > (i+1)) {
+ newArgs[i] = args[i];
+ StringBuffer buff = new StringBuffer();
+ boolean copyThisTime = doCopy;
+ if (args[i].equals("-d")) {
+ copyThisTime = false;
+ hasOutdir = true;
+ }
+ StringTokenizer strTok = new StringTokenizer(args[++i],File.pathSeparator);
+ while (strTok.hasMoreTokens()) {
+ File f = new File(strTok.nextToken());
+ buff.append(adjustFileOrDir(f,copyThisTime).getAbsolutePath());
+ if (strTok.hasMoreTokens()) buff.append(File.pathSeparator);
+ }
+ newArgs[i] = buff.toString();
+ if (args[i-1].equals("-classpath")) {
+ hasClasspath = true;
+ newArgs[i] = newArgs[i] + File.pathSeparator + TESTER_PATH;
+ }
+ } else {
+ // could be resource file
+ File f = new File(args[i]);
+ if (f.exists()) {
+ newArgs[i] = adjustFileOrDir(f,doCopy).getAbsolutePath();
+ }
+ }
+ }
+ }
+ if (!hasClasspath) {
+ String[] oldArgs = newArgs;
+ newArgs = new String[oldArgs.length + 2];
+ System.arraycopy(oldArgs,0,newArgs,0,oldArgs.length);
+ newArgs[oldArgs.length] = "-classpath";
+ newArgs[oldArgs.length + 1] = TESTER_PATH + File.pathSeparator + getSandboxDirectory().getAbsolutePath();
+ }
+ if (!hasOutdir) {
+ String[] oldArgs = newArgs;
+ newArgs = new String[oldArgs.length + 2];
+ System.arraycopy(oldArgs,0,newArgs,0,oldArgs.length);
+ newArgs[oldArgs.length] = "-d";
+ newArgs[oldArgs.length + 1] = getSandboxDirectory().getPath();
+ }
+ return newArgs;
+ }
+
+ private File adjustFileOrDir(File from,boolean doCopy) throws IOException {
+ File to = from;
+ File ret = from;
+ if (!from.isAbsolute()) {
+ ret = new File(sandbox,from.getPath());
+ File fromParent = from.getParentFile();
+ String relativeToPath = (fromParent != null) ? (fromParent.getPath() + File.separator) : "";
+ if (baseDir != null) {
+ from = new File(baseDir,from.getPath());
+ }
+ if (!from.exists()) return ret;
+ if (doCopy) {
+ // harness requires that any files with the same name, and a different extension,
+ // get copied too (e.g. .out, .err, .event files)
+ if (from.isFile()) {
+ final String prefix = from.getName().substring(0,from.getName().lastIndexOf('.'));
+ String[] toCopy = from.getParentFile().list(new FilenameFilter() {
+ public boolean accept(File dir, String name) {
+ if (name.indexOf('.') == -1) return false;
+ String toMatch = name.substring(0,name.lastIndexOf('.'));
+ return (toMatch.equals(prefix));
+ }
+ });
+ for (int i = 0; i < toCopy.length; i++) {
+ String toPath = relativeToPath + toCopy[i];
+ to = new File(sandbox,toPath);
+ FileUtil.copyFile(new File(from.getParentFile(),toCopy[i]),
+ to);
+ }
+ } else {
+ FileUtil.copyFile(from,ret);
+ }
+ }
+ }
+ return ret;
+ }
+}
+
+/*
+ * So that we can drive incremental compilation easily from a unit
+ * test.
+ */
+class AjcCommandController extends Main.CommandController {
+
+ private ICommand command;
+
+ /* (non-Javadoc)
+ * @see org.aspectj.tools.ajc.Main.CommandController#doRepeatCommand()
+ */
+ boolean doRepeatCommand(ICommand command) {
+ this.command = command;
+ return false; // ensure that control returns to caller
+ }
+
+ /* (non-Javadoc)
+ * @see org.aspectj.tools.ajc.Main.CommandController#running()
+ */
+ public boolean running() {
+ return false; // so that we can come back for more...
+ }
+
+ public void doIncremental(IMessageHandler handler) {
+ if (command == null) throw new IllegalArgumentException("Can't repeat command until it has executed at least once!");
+ command.repeatCommand(handler);
+ }
+}
diff --git a/org.aspectj.ajdt.core/testsrc/org/aspectj/tools/ajc/AjcTestCase.java b/org.aspectj.ajdt.core/testsrc/org/aspectj/tools/ajc/AjcTestCase.java
new file mode 100644
index 000000000..acfc9ac0f
--- /dev/null
+++ b/org.aspectj.ajdt.core/testsrc/org/aspectj/tools/ajc/AjcTestCase.java
@@ -0,0 +1,646 @@
+/* *******************************************************************
+ * Copyright (c) 2004 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Common Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * Adrian Colyer,
+ * ******************************************************************/
+package org.aspectj.tools.ajc;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintStream;
+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 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 {
+
+ /**
+ * The Ajc (compiler) instance used for thet test. Created afresh
+ * during the test setup.
+ */
+ protected Ajc ajc;
+
+ private static final String DEFAULT_CLASSPATH_ENTRIES =
+ File.pathSeparator +
+ ".." + File.separator + "runtime" + File.separator + "bin" +
+ File.pathSeparator +
+ ".." + File.separator + "testing-client" + File.separator + "bin" +
+ File.pathSeparator +
+ ".." + File.separator + "bridge" + File.separator + "bin" +
+ File.pathSeparator +
+ ".." + File.separator + "util" + File.separator + "bin";
+
+ /**
+ * 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;
+
+ /**
+ * 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;
+ }
+
+ /**
+ * 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;
+ 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;
+ }
+
+ /**
+ * 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 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 srcLocations,ISourceLocation sLoc) {
+ for (Iterator iter = srcLocations.iterator(); iter.hasNext();) {
+ ISourceLocation thisLoc = (ISourceLocation) iter.next();
+ 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.
+ */
+ 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);
+
+ boolean ignoreInfos = true;
+ public List fails;
+ public List infos;
+ public List warnings;
+ public List errors;
+
+ /**
+ * 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 infos, List warnings, List errors, List fails) {
+ if (infos != null) {
+ this.infos = infos;
+ ignoreInfos = false;
+ } else {
+ this.infos = Collections.EMPTY_LIST;
+ }
+ this.warnings = ((warnings == null) ? Collections.EMPTY_LIST : warnings);
+ this.errors = ((errors == null) ? Collections.EMPTY_LIST : errors);
+ this.fails = ((fails == null) ? Collections.EMPTY_LIST : fails);
+ }
+
+ /**
+ * 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 infos, List warnings, List errors) {
+ this(infos,warnings,errors,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 warnings, List errors) {
+ this(null,warnings,errors,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 String command;
+ private String stdOut;
+ private 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.
+ */
+ 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 missingFails = copyAll(expected.fails);
+ List missingInfos = copyAll(expected.infos);
+ List missingWarnings = copyAll(expected.warnings);
+ List missingErrors = copyAll(expected.errors);
+ List extraFails = copyAll(result.getFailMessages());
+ List extraInfos = copyAll(result.getInfoMessages());
+ List extraWarnings = copyAll(result.getWarningMessages());
+ List extraErrors = copyAll(result.getErrorMessages());
+ 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);
+ }
+
+ boolean infosEmpty = expected.isIgnoringInfoMessages() ? true: (missingInfos.isEmpty() && extraInfos.isEmpty());
+ if ( !(missingFails.isEmpty() && missingWarnings.isEmpty() && missingErrors.isEmpty() &&
+ extraFails.isEmpty() && extraWarnings.isEmpty() && extraErrors.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);
+ if (!expected.isIgnoringInfoMessages()) {
+ addExtra(failureReport,"info",extraInfos);
+ }
+ addExtra(failureReport,"warning",extraWarnings);
+ addExtra(failureReport,"error",extraErrors);
+ addExtra(failureReport,"fail",extraFails);
+ 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();
+ fail(message + "\n" + report);
+ }
+ }
+
+ /**
+ * Helper method to build a new message list for passing to a MessageSpec.
+ */
+ protected List newMessageList(Message m1) {
+ List ret = new ArrayList();
+ ret.add(m1);
+ return ret;
+ }
+
+ /**
+ * Helper method to build a new message list for passing to a MessageSpec.
+ */
+ protected List newMessageList(Message m1, Message m2) {
+ List ret = new ArrayList();
+ ret.add(m1);
+ ret.add(m2);
+ return ret;
+ }
+
+ /**
+ * Helper method to build a new message list for passing to a MessageSpec.
+ */
+ protected List newMessageList(Message m1, Message m2, Message m3) {
+ List ret = new ArrayList();
+ 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);
+ return ajc.compile(args);
+ } catch(IOException ioEx ) {
+ fail("IOException thrown during compilation: " + ioEx);
+ }
+ return null;
+ }
+
+ /**
+ * 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);
+ }
+
+ /**
+ * 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);
+ }
+
+ /**
+ * 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.
+ */
+ public RunResult run(String className, String[] args, String classpath) {
+ RunResult result = null;
+ StringBuffer cp = new StringBuffer();
+ if (classpath != null) {
+ cp.append(classpath);
+ cp.append(File.pathSeparator);
+ }
+ cp.append(ajc.getSandboxDirectory().getAbsolutePath());
+ cp.append(DEFAULT_CLASSPATH_ENTRIES);
+ getAnyJars(ajc.getSandboxDirectory(),cp);
+ classpath = cp.toString();
+ StringBuffer command = new StringBuffer("java -classpath ");
+ command.append(classpath);
+ command.append(" ");
+ command.append(className);
+ for (int i = 0; i < args.length; i++) {
+ command.append(" ");
+ command.append(args[i]);
+ }
+ PrintStream systemOut = System.out;
+ PrintStream systemErr = System.err;
+ ByteArrayOutputStream baosOut = new ByteArrayOutputStream();
+ ByteArrayOutputStream baosErr = new ByteArrayOutputStream();
+ 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);
+ }
+ URLClassLoader cLoader = new URLClassLoader(urls,null);
+ //System.out.println(cLoader.getParent());
+ try {
+ try {
+ Class testerClass = cLoader.loadClass("org.aspectj.testing.Tester");
+ Method setBaseDir = testerClass.getDeclaredMethod("setBASEDIR",new Class[] {File.class});
+ setBaseDir.invoke(null,new Object[] {ajc.getSandboxDirectory()});
+ } catch (Exception ex) {
+ fail ("Unable to prepare org.aspectj.testing.Tester for test run: " + ex);
+ }
+ Class toRun = cLoader.loadClass(className);
+ Method mainMethod = toRun.getMethod("main",new Class[] {String[].class});
+ System.setOut(new PrintStream(baosOut));
+ System.setErr(new PrintStream(baosErr));
+ mainMethod.invoke(null,new Object[] {args});
+ result = new RunResult(command.toString(),new String(baosOut.toByteArray()),new String(baosErr.toByteArray()));
+ } 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 {
+ System.setOut(systemOut);
+ System.setErr(systemErr);
+ }
+ return result;
+ }
+
+ private List copyAll(List in) {
+ if (in == Collections.EMPTY_LIST) return in;
+
+ List out = new ArrayList();
+ for (Iterator 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 expected, List actual, List missingElements, List extraElements) {
+ for (Iterator expectedIter = expected.iterator(); expectedIter.hasNext();) {
+ Message expectedMessage = (Message) expectedIter.next();
+ for (Iterator actualIter = actual.iterator(); actualIter.hasNext();) {
+ IMessage actualMessage = (IMessage) actualIter.next();
+ if (expectedMessage.matches(actualMessage)) {
+ missingElements.remove(expectedMessage);
+ extraElements.remove(actualMessage);
+ }
+ }
+ }
+ }
+
+ private void addMissing(StringBuffer buff,String type, List messages) {
+ if (!messages.isEmpty()) {
+ buff.append("Missing expected ");
+ 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");
+ }
+ }
+ }
+
+ 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);
+ }
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see junit.framework.TestCase#setUp()
+ */
+ protected void setUp() throws Exception {
+ super.setUp();
+ ajc = new Ajc();
+ }
+ /* (non-Javadoc)
+ * @see junit.framework.TestCase#tearDown()
+ */
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+}
diff --git a/org.aspectj.ajdt.core/testsrc/org/aspectj/tools/ajc/AjcTestCaseTest.java b/org.aspectj.ajdt.core/testsrc/org/aspectj/tools/ajc/AjcTestCaseTest.java
new file mode 100644
index 000000000..79a06dfce
--- /dev/null
+++ b/org.aspectj.ajdt.core/testsrc/org/aspectj/tools/ajc/AjcTestCaseTest.java
@@ -0,0 +1,51 @@
+/* *******************************************************************
+ * Copyright (c) 2004 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Common Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * Adrian Colyer,
+ * ******************************************************************/
+package org.aspectj.tools.ajc;
+
+import java.io.File;
+
+import org.aspectj.util.FileUtil;
+
+/**
+ * @author colyer
+ * Exercise the features of the AjcTestCase class and check they do as
+ * expected
+ */
+public class AjcTestCaseTest extends AjcTestCase {
+
+ public void testCompile() {
+ File baseDir = new File("../tests/base/test106");
+ String[] args = new String[] {"Driver.java","pkg/Obj.java"};
+ CompilationResult result = ajc(baseDir,args);
+ assertNoMessages(result);
+ RunResult rresult = run("Driver",new String[0],null);
+ System.out.println(rresult.getStdOut());
+ }
+
+ public void testIncrementalCompile() throws Exception {
+ File baseDir = new File("../tests/incrementalju/initialTests/classAdded");
+ String[] args = new String[] {"-sourceroots","src","-d",".","-incremental"};
+ CompilationResult result = ajc(baseDir,args);
+ assertNoMessages(result);
+ RunResult rr = run("main.Main",new String[0],null);
+ // prepare for increment
+ FileUtil.copyFile(new File(baseDir,"src.20/main/Main.java"),
+ new File(ajc.getSandboxDirectory(),"src/main/Main.java"));
+ assertFalse("main.Target does not exist",new File(ajc.getSandboxDirectory(),"main/Target.class").exists());
+ result = ajc.doIncrementalCompile();
+ assertNoMessages(result);
+ assertTrue("main.Target created",new File(ajc.getSandboxDirectory(),"main/Target.class").exists());
+ rr = run("main.Main",new String[0],null);
+ System.out.println(rr.getStdOut());
+ }
+
+}
diff --git a/org.aspectj.ajdt.core/testsrc/org/aspectj/tools/ajc/CompilationResult.java b/org.aspectj.ajdt.core/testsrc/org/aspectj/tools/ajc/CompilationResult.java
new file mode 100644
index 000000000..31e2afdfc
--- /dev/null
+++ b/org.aspectj.ajdt.core/testsrc/org/aspectj/tools/ajc/CompilationResult.java
@@ -0,0 +1,202 @@
+/* *******************************************************************
+ * Copyright (c) 2004 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Common Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * Adrian Colyer,
+ * ******************************************************************/
+package org.aspectj.tools.ajc;
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Utility class that makes the results of a compiler run available.
+ * <p>
+ * Instances of this class are returned by the Ajc.compile() and
+ * doIncrementalCompile() methods (and the AjcTestCase.ajc() wrapper).
+ * </p>
+ * <p>
+ * This class provides a useful toString() method that is very helpful when
+ * debugging or creating messages for assert statements.
+ * </p>
+ * <p>Note that the stdOut and stdErr captured from the compiler run do
+ * not contain any rendered messages - these are in the messages lists
+ * instead. Therefore for many compiler runs, they will be empty.
+ * </p>
+ */
+public class CompilationResult {
+
+ private String[] args;
+ private String stdOut;
+ private String stdErr;
+ private List /*IMessage*/ infoMessages;
+ private List /*IMessage*/ errorMessages;
+ private List /*IMessage*/ warningMessages;
+ private List /*IMessage*/ failMessages;
+
+ /**
+ * Build a compilation result - called by the Ajc.compile and
+ * Ajc.doIncrementalCompile methods. Should be no need for you
+ * to construct an instance yourself.
+ */
+ protected CompilationResult(
+ String[] args,
+ String stdOut,
+ String stdErr,
+ List infoMessages,
+ List errorMessages,
+ List warningMessages,
+ List failMessages) {
+ this.args = args;
+ this.stdOut = stdOut;
+ this.stdErr = stdErr;
+ this.infoMessages = (infoMessages == null) ? Collections.EMPTY_LIST : infoMessages;
+ this.errorMessages = (errorMessages == null) ? Collections.EMPTY_LIST : errorMessages;
+ this.warningMessages = (warningMessages == null) ? Collections.EMPTY_LIST : warningMessages;
+ this.failMessages = (failMessages == null) ? Collections.EMPTY_LIST : failMessages;
+ }
+
+ /**
+ * The arguments that were passed to the compiler.
+ */
+ public String[] getArgs() { return args; }
+ /**
+ * The standard output written by the compiler, excluding any messages.
+ */
+ public String getStandardOutput() { return stdOut; }
+ /**
+ * The standard error written by the compiler, excluding any messages.
+ */
+ public String getStandardError() { return stdErr; }
+
+ /**
+ * True if the compiler issued any messages of any kind.
+ */
+ public boolean hasMessages() { return (hasInfoMessages() || hasErrorMessages() || hasWarningMessages() || hasFailMessages()); }
+ /**
+ * True if the compiler issued one or more informational messages.
+ */
+ public boolean hasInfoMessages() { return !infoMessages.isEmpty(); }
+ /**
+ * True if the compiler issued one or more error messages.
+ */
+ public boolean hasErrorMessages() { return !errorMessages.isEmpty(); }
+ /**
+ * True if the compiler issued one or more warning messages.
+ */
+ public boolean hasWarningMessages() { return !warningMessages.isEmpty(); }
+ /**
+ * True if the compiler issued one or more fail or abort messages.
+ */
+ public boolean hasFailMessages() { return !failMessages.isEmpty(); }
+
+ /**
+ * The informational messages produced by the compiler. The list
+ * entries are the <code>IMessage</code> objects created during the
+ * compile - so that you can programmatically test source locations
+ * etc. etc.. It may often be easier to use the <code>assertMessages</code>
+ * helper methods defined in the AjcTestCase class to test for messages
+ * though.
+ * @see org.aspectj.tools.ajc.AjcTestCase
+ */
+ public List /*IMessage*/ getInfoMessages() { return infoMessages; }
+ /**
+ * The error messages produced by the compiler. The list
+ * entries are the <code>IMessage</code> objects created during the
+ * compile - so that you can programmatically test source locations
+ * etc. etc.. It may often be easier to use the <code>assertMessages</code>
+ * helper methods defined in the AjcTestCase class to test for messages
+ * though.
+ * @see org.aspectj.tools.ajc.AjcTestCase
+ */
+ public List /*IMessage*/ getErrorMessages() { return errorMessages; }
+ /**
+ * The warning messages produced by the compiler. The list
+ * entries are the <code>IMessage</code> objects created during the
+ * compile - so that you can programmatically test source locations
+ * etc. etc.. It may often be easier to use the <code>assertMessages</code>
+ * helper methods defined in the AjcTestCase class to test for messages
+ * though.
+ * @see org.aspectj.tools.ajc.AjcTestCase
+ */
+ public List /*IMessage*/ getWarningMessages() { return warningMessages; }
+ /**
+ * The fail or abort messages produced by the compiler. The list
+ * entries are the <code>IMessage</code> objects created during the
+ * compile - so that you can programmatically test source locations
+ * etc. etc.. It may often be easier to use the <code>assertMessages</code>
+ * helper methods defined in the AjcTestCase class to test for messages
+ * though.
+ * @see org.aspectj.tools.ajc.AjcTestCase
+ */
+ public List /*IMessage*/ getFailMessages() { return failMessages; }
+
+ /**
+ * Returns string containing message count summary, list of messages
+ * by type, and the actual ajc compilation command that was issued.
+ */
+ public String toString() {
+ StringBuffer buff = new StringBuffer();
+ buff.append("AspectJ Compilation Result:\n");
+ int totalMessages = infoMessages.size() + warningMessages.size() + errorMessages.size() + failMessages.size();
+ buff.append(totalMessages);
+ buff.append(" messages");
+ if (totalMessages > 0) {
+ buff.append(" (");
+ buff.append(infoMessages.size());
+ buff.append(" info, ");
+ buff.append(warningMessages.size());
+ buff.append(" warning, ");
+ buff.append(errorMessages.size());
+ buff.append(" error, ");
+ buff.append(failMessages.size());
+ buff.append(" fail)");
+ }
+ buff.append("\n");
+ int msgNo = 1;
+ for (Iterator iter = failMessages.iterator(); iter.hasNext();) {
+ buff.append("[fail ");
+ buff.append(msgNo++);
+ buff.append("] ");
+ buff.append(iter.next().toString());
+ buff.append("\n");
+ }
+ msgNo = 1;
+ for (Iterator iter = errorMessages.iterator(); iter.hasNext();) {
+ buff.append("[error ");
+ buff.append(msgNo++);
+ buff.append("] ");
+ buff.append(iter.next().toString());
+ buff.append("\n");
+ }
+ msgNo = 1;
+ for (Iterator iter = warningMessages.iterator(); iter.hasNext();) {
+ buff.append("[warning ");
+ buff.append(msgNo++);
+ buff.append("] ");
+ buff.append(iter.next().toString());
+ buff.append("\n");
+ }
+ msgNo = 1;
+ for (Iterator iter = infoMessages.iterator(); iter.hasNext();) {
+ buff.append("[info ");
+ buff.append(msgNo++);
+ buff.append("] ");
+ buff.append(iter.next().toString());
+ buff.append("\n");
+ }
+ buff.append("\ncommand was: 'ajc");
+ for (int i = 0; i < args.length; i++) {
+ buff.append(' ');
+ buff.append(args[i]);
+ }
+ buff.append("'\n");
+ return buff.toString();
+ }
+}
diff --git a/org.aspectj.ajdt.core/testsrc/org/aspectj/tools/ajc/MainTest.java b/org.aspectj.ajdt.core/testsrc/org/aspectj/tools/ajc/MainTest.java
index 13d7216dd..aa2110c03 100644
--- a/org.aspectj.ajdt.core/testsrc/org/aspectj/tools/ajc/MainTest.java
+++ b/org.aspectj.ajdt.core/testsrc/org/aspectj/tools/ajc/MainTest.java
@@ -13,13 +13,12 @@
package org.aspectj.tools.ajc;
import java.util.ArrayList;
-
-import junit.framework.TestCase;
+import java.util.ResourceBundle;
/**
*
*/
-public class MainTest extends TestCase {
+public class MainTest extends AjcTestCase {
public void testMainbare() {
ArrayList list = new ArrayList();
@@ -32,4 +31,12 @@ public class MainTest extends TestCase {
// assertTrue(-1 != ((String)o).indexOf("-aspectpath"));
// assertTrue(-1 != ((String)o).indexOf("-incremental"));
}
+
+ public void testDashX() {
+ String xoptionText = ResourceBundle.getBundle("org.aspectj.ajdt.ajc.messages").getString("xoption.usage");
+ xoptionText = xoptionText.substring("{compiler.name}".length());
+ CompilationResult result = ajc(null,new String[] {"-X"});
+ assertMessages(result,"Expecting xoptions usage message",
+ new MessageSpec(null,null,null,newMessageList(new Message(xoptionText))));
+ }
}