aboutsummaryrefslogtreecommitdiffstats
path: root/testing
diff options
context:
space:
mode:
authorwisberg <wisberg>2003-10-29 08:56:38 +0000
committerwisberg <wisberg>2003-10-29 08:56:38 +0000
commited96631f11efc4895a90a68f86f0e75eef8e9e2d (patch)
tree89a9d5fb905a2e87b41b4480d45651c84c9e5602 /testing
parent7a01c23476bda528f577b9fe4861f40ad1086381 (diff)
downloadaspectj-ed96631f11efc4895a90a68f86f0e75eef8e9e2d.tar.gz
aspectj-ed96631f11efc4895a90a68f86f0e75eef8e9e2d.zip
revamped option handling: n-element options, collision/conflict detection/resolution via forcing as an attribute, option families. More compiler options actually handled, and error messages for unhandled options.
Diffstat (limited to 'testing')
-rw-r--r--testing/src/org/aspectj/testing/harness/bridge/AbstractRunSpec.java63
-rw-r--r--testing/src/org/aspectj/testing/harness/bridge/CompilerRun.java1510
-rw-r--r--testing/src/org/aspectj/testing/harness/bridge/Globals.java114
-rw-r--r--testing/src/org/aspectj/testing/util/options/Option.java707
-rw-r--r--testing/src/org/aspectj/testing/util/options/Options.java152
-rw-r--r--testing/src/org/aspectj/testing/util/options/Values.java714
-rw-r--r--testing/testsrc/TestingModuleTests.java1
-rw-r--r--testing/testsrc/org/aspectj/testing/harness/bridge/CompilerRunSpecTest.java496
-rw-r--r--testing/testsrc/org/aspectj/testing/util/options/OptionChecker.java195
-rw-r--r--testing/testsrc/org/aspectj/testing/util/options/OptionsTest.java486
-rw-r--r--testing/testsrc/org/aspectj/testing/util/options/OptionsTests.java30
-rw-r--r--testing/testsrc/org/aspectj/testing/util/options/ValuesTest.java69
12 files changed, 3928 insertions, 609 deletions
diff --git a/testing/src/org/aspectj/testing/harness/bridge/AbstractRunSpec.java b/testing/src/org/aspectj/testing/harness/bridge/AbstractRunSpec.java
index 8339a25ad..b1e3051e1 100644
--- a/testing/src/org/aspectj/testing/harness/bridge/AbstractRunSpec.java
+++ b/testing/src/org/aspectj/testing/harness/bridge/AbstractRunSpec.java
@@ -30,7 +30,10 @@ import org.aspectj.bridge.ISourceLocation;
import org.aspectj.bridge.MessageHandler;
import org.aspectj.bridge.MessageUtil;
import org.aspectj.testing.run.IRunIterator;
+import org.aspectj.testing.util.*;
import org.aspectj.testing.util.BridgeUtil;
+import org.aspectj.testing.util.options.*;
+import org.aspectj.testing.util.options.Option.InvalidInputException;
import org.aspectj.testing.xml.IXmlWritable;
import org.aspectj.testing.xml.SoftMessage;
import org.aspectj.testing.xml.XMLWriter;
@@ -956,6 +959,66 @@ abstract public class AbstractRunSpec implements IRunSpec { // XXX use MessageHa
}
/**
+ * Return any parent option accepted by validOptions,
+ * optionally removing the parent option.
+ * @param validOptions String[] of options to extract
+ * @param remove if true, then remove any parent option matched
+ * @return String[] containing any validOptions[i] in parentOptions
+ *
+ */
+ public Values extractOptions(
+ Options validOptions,
+ boolean remove,
+ StringBuffer errors) {
+ Values result = Values.EMPTY;
+ if (null == errors) {
+ errors = new StringBuffer();
+ }
+ if (null == validOptions) {
+ errors.append("null options");
+ return result;
+ }
+ if (LangUtil.isEmpty(parentOptions)) {
+ return result;
+ }
+ boolean haveOption = false;
+ String[] parents = (String[]) parentOptions.toArray(new String[0]);
+ try {
+ result = validOptions.acceptInput(parents);
+ } catch (InvalidInputException e) {
+ errors.append(e.getFullMessage());
+ return result;
+ }
+ if (remove) {
+ Option.Value[] values = result.asArray();
+ for (int i = 0; i < values.length; i++) {
+ Option.Value value = values[i];
+ if (null == value) {
+ continue;
+ }
+ final int max = i + value.option.numArguments();
+ if (max > i) {
+ if (max >= parents.length) {
+ errors.append("expecting more args for "
+ + value.option
+ + " at ["
+ + i
+ + "]: "
+ + Arrays.asList(parents));
+ return result;
+ }
+ // XXX verify
+ for (int j = i; j < max ; j++) {
+ parentOptions.remove(parents[j]);
+ }
+ i = max-1;
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
* Return any parent option which has one of validOptions as a prefix,
* optionally absorbing (removing) the parent option.
* @param validOptions String[] of options to extract
diff --git a/testing/src/org/aspectj/testing/harness/bridge/CompilerRun.java b/testing/src/org/aspectj/testing/harness/bridge/CompilerRun.java
index 172f0de74..0f0385ac2 100644
--- a/testing/src/org/aspectj/testing/harness/bridge/CompilerRun.java
+++ b/testing/src/org/aspectj/testing/harness/bridge/CompilerRun.java
@@ -1,5 +1,6 @@
/* *******************************************************************
- * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
+ * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC),
+ * 2003 Contributors.
* All rights reserved.
* This program and the accompanying materials are made available
* under the terms of the Common Public License v1.0
@@ -8,34 +9,22 @@
*
* Contributors:
* Xerox/PARC initial implementation
+ * Wes Isberg 2003 updates
* ******************************************************************/
package org.aspectj.testing.harness.bridge;
-import org.aspectj.bridge.ICommand;
-import org.aspectj.bridge.IMessage;
-import org.aspectj.bridge.IMessageHandler;
-import org.aspectj.bridge.MessageUtil;
-import org.aspectj.bridge.ReflectionFactory;
+import java.io.*;
+import java.util.*;
+
+import org.aspectj.bridge.*;
import org.aspectj.testing.ajde.CompileCommand;
-import org.aspectj.testing.run.IRunIterator;
-import org.aspectj.testing.run.IRunStatus;
-import org.aspectj.testing.run.WrappedRunIterator;
+import org.aspectj.testing.run.*;
import org.aspectj.testing.taskdefs.AjcTaskCompileCommand;
-import org.aspectj.testing.xml.SoftMessage;
-import org.aspectj.testing.xml.XMLWriter;
-import org.aspectj.util.FileUtil;
-import org.aspectj.util.LangUtil;
-
-import java.io.File;
-import java.io.FileFilter;
-import java.io.IOException;
-import java.io.PrintStream;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Iterator;
-import java.util.List;
-import java.util.ListIterator;
+import org.aspectj.testing.util.options.*;
+import org.aspectj.testing.util.options.Option.*;
+import org.aspectj.testing.xml.*;
+import org.aspectj.util.*;
/**
* Run the compiler once.
@@ -62,40 +51,37 @@ import java.util.ListIterator;
* </ul>
*/
public class CompilerRun implements IAjcRun {
- static final String BUILDER_COMPILER =
- "org.aspectj.ajdt.internal.core.builder.Builder.Command";
- static final String AJDE_COMPILER = CompileCommand.class.getName();
- static final String AJCTASK_COMPILER
- = AjcTaskCompileCommand.class.getName();
-// static final String JAVAC_COMPILER
-// = JavacCompileCommand.class.getName();
-
- static final String[] RA_String = new String[0];
-
+ // static final String JAVAC_COMPILER
+ // = JavacCompileCommand.class.getName();
+
+ static final String[] RA_String = new String[0];
+
static final String[] JAR_SUFFIXES = new String[] { ".jar", ".zip" };
- static final String[] SOURCE_SUFFIXES
- = (String[]) FileUtil.SOURCE_SUFFIXES.toArray(new String[0]);
-
+ static final String[] SOURCE_SUFFIXES =
+ (String[]) FileUtil.SOURCE_SUFFIXES.toArray(new String[0]);
+
/** specifications, set on construction */
Spec spec;
//------------ calculated during setup
- /** get shared stuff during setup */
+ /** get shared stuff during setup */
Sandbox sandbox;
-
+
/**
* During run, these String are passed as the source and arg files to compile.
* The list is set up in setupAjcRun(..), when arg files are prefixed with "@".
*/
- final List /*String*/ arguments;
-
+ final List /*String*/
+ arguments;
+
/**
* During run, these String are collapsed and passed as the injar option.
* The list is set up in setupAjcRun(..).
*/
- final List /*String*/ injars;
-
+ final List /*String*/
+ injars;
+
private CompilerRun(Spec spec) {
if (null == spec) {
throw new IllegalArgumentException("null spec");
@@ -103,8 +89,8 @@ public class CompilerRun implements IAjcRun {
this.spec = spec;
arguments = new ArrayList();
injars = new ArrayList();
- }
-
+ }
+
/**
* This checks that the spec is reasonable and does setup:
* <ul>
@@ -124,72 +110,98 @@ public class CompilerRun implements IAjcRun {
* for incremental tests. Note that (as of this writing) the
* compiler only handles source roots for incremental tests.
* @param classesDir the File
- * @see org.aspectj.testing.harness.bridge.AjcTest.IAjcRun#setup(File, File)
+ * @see org.aspectj.testing.harness.bridge.AjcTest.IAjcRun#setup(File, File)
* @throws AbortException containing IOException or IllegalArgumentException
* if the staging operations fail
- */
- public boolean setupAjcRun(Sandbox sandbox, Validator validator) {
+ */
+ public boolean setupAjcRun(Sandbox sandbox, Validator validator) {
if (!validator.nullcheck(spec.getOptionsArray(), "localOptions")
|| !validator.nullcheck(sandbox, "sandbox")
|| !validator.nullcheck(spec.compiler, "compilerName")
|| !validator.canRead(Globals.F_aspectjrt_jar, "aspectjrt.jar")
- || !validator.canRead(Globals.F_testingclient_jar, "testing-client.jar")
- ) {
+ || !validator.canRead(
+ Globals.F_testingclient_jar,
+ "testing-client.jar")) {
return false;
}
-
+
this.sandbox = sandbox;
-
+
String rdir = spec.testSrcDirOffset;
File testBaseSrcDir;
if ((null == rdir) || (0 == rdir.length())) {
testBaseSrcDir = sandbox.testBaseDir;
} else {
- testBaseSrcDir = new File(sandbox.testBaseDir, rdir); // XXX what if rdir is two levels deep?
- if (!validator.canReadDir(testBaseSrcDir, "sandbox.testBaseSrcDir")) {
+ testBaseSrcDir = new File(sandbox.testBaseDir, rdir);
+ // XXX what if rdir is two levels deep?
+ if (!validator
+ .canReadDir(testBaseSrcDir, "sandbox.testBaseSrcDir")) {
return false;
}
}
sandbox.setTestBaseSrcDir(testBaseSrcDir, this);
-
-
+
// Sources come as relative paths - check read, copy if staging.
// This renders paths absolute before run(RunStatusI) is called.
// For a compile run to support relative paths + source base,
// change so the run calculates the paths (differently when staging)
- final String[] injarPaths;
+ final String[] injarPaths;
final String[] srcPaths;
- {
+ {
final String[] paths = spec.getPathsArray();
- srcPaths = LangUtil.endsWith(paths, CompilerRun.SOURCE_SUFFIXES, true);
- injarPaths = LangUtil.endsWith(paths, CompilerRun.JAR_SUFFIXES, true);
- }
+ srcPaths =
+ LangUtil.endsWith(
+ paths,
+ CompilerRun.SOURCE_SUFFIXES,
+ true);
+ injarPaths =
+ LangUtil.endsWith(paths, CompilerRun.JAR_SUFFIXES, true);
+ }
// validate readable for sources
if (!spec.badInput) {
if (!validator.canRead(testBaseSrcDir, srcPaths, "sources")
|| !validator.canRead(testBaseSrcDir, injarPaths, "injars")
- || !validator.canRead(testBaseSrcDir, spec.argfiles, "argfiles")
- || !validator.canRead(testBaseSrcDir, spec.classpath, "classpath")
- || !validator.canRead(testBaseSrcDir, spec.aspectpath, "aspectpath")
- || !validator.canRead(testBaseSrcDir, spec.sourceroots, "sourceroots")
- ) {
+ || !validator.canRead(
+ testBaseSrcDir,
+ spec.argfiles,
+ "argfiles")
+ || !validator.canRead(
+ testBaseSrcDir,
+ spec.classpath,
+ "classpath")
+ || !validator.canRead(
+ testBaseSrcDir,
+ spec.aspectpath,
+ "aspectpath")
+ || !validator.canRead(
+ testBaseSrcDir,
+ spec.sourceroots,
+ "sourceroots")) {
return false;
}
}
-
- int numSources = srcPaths.length + injarPaths.length
- + spec.argfiles.length + spec.sourceroots.length;
+
+ int numSources =
+ srcPaths.length
+ + injarPaths.length
+ + spec.argfiles.length
+ + spec.sourceroots.length;
if (!spec.badInput && (numSources < 1)) {
- validator.fail("no input jars, arg files, or source files or roots");
- return false;
- }
-
- final File[] argFiles = FileUtil.getBaseDirFiles(testBaseSrcDir, spec.argfiles);
- final File[] injarFiles = FileUtil.getBaseDirFiles(testBaseSrcDir, injarPaths);
- final File[] aspectFiles = FileUtil.getBaseDirFiles(testBaseSrcDir, spec.aspectpath);
- final File[] classFiles = FileUtil.getBaseDirFiles(testBaseSrcDir, spec.classpath);
+ validator.fail(
+ "no input jars, arg files, or source files or roots");
+ return false;
+ }
+
+ final File[] argFiles =
+ FileUtil.getBaseDirFiles(testBaseSrcDir, spec.argfiles);
+ final File[] injarFiles =
+ FileUtil.getBaseDirFiles(testBaseSrcDir, injarPaths);
+ final File[] aspectFiles =
+ FileUtil.getBaseDirFiles(testBaseSrcDir, spec.aspectpath);
+ final File[] classFiles =
+ FileUtil.getBaseDirFiles(testBaseSrcDir, spec.classpath);
// hmm - duplicates validation above, verifying getBaseDirFiles?
if (!spec.badInput) {
if (!validator.canRead(argFiles, "argFiles")
@@ -203,34 +215,53 @@ public class CompilerRun implements IAjcRun {
final File[] srcFiles;
File[] sourcerootFiles = new File[0];
// source text files are copied when staging incremental tests
- if (!spec.isStaging()) { // XXX why this? was always? || (testBaseSrcDir != sandbox.stagingDir))) {
- srcFiles = FileUtil.getBaseDirFiles(testBaseSrcDir, srcPaths, CompilerRun.SOURCE_SUFFIXES);
+ if (!spec.isStaging()) {
+ // XXX why this? was always? || (testBaseSrcDir != sandbox.stagingDir))) {
+ srcFiles =
+ FileUtil.getBaseDirFiles(
+ testBaseSrcDir,
+ srcPaths,
+ CompilerRun.SOURCE_SUFFIXES);
if (!LangUtil.isEmpty(spec.sourceroots)) {
- sourcerootFiles = FileUtil.getBaseDirFiles(testBaseSrcDir, spec.sourceroots, null);
+ sourcerootFiles =
+ FileUtil.getBaseDirFiles(
+ testBaseSrcDir,
+ spec.sourceroots,
+ null);
}
} else { // staging - copy files
if (spec.badInput) {
- validator.info("badInput ignored - files checked when staging");
+ validator.info(
+ "badInput ignored - files checked when staging");
}
try {
// copy all files, then remove tagged ones
// XXX make copyFiles support a filter?
- srcFiles = FileUtil.copyFiles(testBaseSrcDir, srcPaths, sandbox.stagingDir);
+ srcFiles =
+ FileUtil.copyFiles(
+ testBaseSrcDir,
+ srcPaths,
+ sandbox.stagingDir);
if (!LangUtil.isEmpty(spec.sourceroots)) {
- sourcerootFiles = FileUtil.copyFiles(testBaseSrcDir, spec.sourceroots, sandbox.stagingDir);
+ sourcerootFiles =
+ FileUtil.copyFiles(
+ testBaseSrcDir,
+ spec.sourceroots,
+ sandbox.stagingDir);
// delete incremental files in sourceroot after copying // XXX inefficient
FileFilter pickIncFiles = new FileFilter() {
- // an incremental file has an extra "." in name
- // most .java files don't, because they are named after
- // the principle type they contain, and simple type names
- // have no dots.
- public boolean accept(File file) {
- if (file.isDirectory()) { // continue recursion
+ // an incremental file has an extra "." in name
+ // most .java files don't, because they are named after
+ // the principle type they contain, and simple type names
+ // have no dots.
+ public boolean accept(File file) {
+ if (file.isDirectory()) {
+ // continue recursion
return true;
}
String path = file.getPath();
// only source files are relevant to staging
- if (!FileUtil.hasSourceSuffix(path)) {
+ if (!FileUtil.hasSourceSuffix(path)) {
return false;
}
int first = path.indexOf(".");
@@ -239,13 +270,18 @@ public class CompilerRun implements IAjcRun {
}
};
for (int i = 0; i < sourcerootFiles.length; i++) {
- FileUtil.deleteContents(sourcerootFiles[i], pickIncFiles, false);
+ FileUtil.deleteContents(
+ sourcerootFiles[i],
+ pickIncFiles,
+ false);
}
if (0 < sourcerootFiles.length) {
- FileUtil.sleepPastFinalModifiedTime(sourcerootFiles);
+ FileUtil.sleepPastFinalModifiedTime(
+ sourcerootFiles);
}
}
- File[] files = FileUtil.getBaseDirFiles(sandbox.stagingDir, srcPaths);
+ File[] files =
+ FileUtil.getBaseDirFiles(sandbox.stagingDir, srcPaths);
if (0 < files.length) {
FileUtil.sleepPastFinalModifiedTime(files);
}
@@ -257,7 +293,8 @@ public class CompilerRun implements IAjcRun {
return false;
}
}
- if (!spec.badInput && !validator.canRead(srcFiles, "copied paths")) {
+ if (!spec.badInput
+ && !validator.canRead(srcFiles, "copied paths")) {
return false;
}
arguments.clear();
@@ -279,12 +316,13 @@ public class CompilerRun implements IAjcRun {
arguments.add("@" + ra[j]);
}
if (!spec.badInput && spec.isStaging) {
- validator.fail("warning: files listed in argfiles not staged");
- }
+ validator.fail(
+ "warning: files listed in argfiles not staged");
+ }
}
// save classpath and aspectpath in sandbox for this and other clients
- final boolean checkReadable = !spec.badInput;
+ final boolean checkReadable = !spec.badInput;
int size = spec.includeClassesDir ? 3 : 2;
File[] cp = new File[size + classFiles.length];
System.arraycopy(classFiles, 0, cp, 0, classFiles.length);
@@ -299,7 +337,7 @@ public class CompilerRun implements IAjcRun {
if (0 < aspectFiles.length) {
sandbox.setAspectpath(aspectFiles, checkReadable, this);
}
-
+
// set bootclasspath if set for forking
AbstractRunSpec.Fork fork = spec.getFork();
String bootclasspath = fork.getJavaBootclasspath();
@@ -308,7 +346,7 @@ public class CompilerRun implements IAjcRun {
}
return true;
}
-
+
/**
* Setup result evaluation and command line, run, and evaluate result.
* <li>setup an AjcMessageHandler using the expected messages from
@@ -325,20 +363,23 @@ public class CompilerRun implements IAjcRun {
* <li>After running, report AjcMessageHandler results to the status parameter.
* If the AjcMessageHandler reports a failure, then send info messages
* for the Spec, TestSetup, and command line.<li>
- * @see org.aspectj.testing.run.IRun#run(IRunStatus)
- */
- public boolean run(IRunStatus status) {
+ * @see org.aspectj.testing.run.IRun#run(IRunStatus)
+ */
+ public boolean run(IRunStatus status) {
if (null == spec.testSetup) {
- MessageUtil.abort(status, "no test setup - adoptParentValues not called");
+ MessageUtil.abort(
+ status,
+ "no test setup - adoptParentValues not called");
return false;
} else if (!spec.testSetup.result) {
MessageUtil.abort(status, spec.testSetup.failureReason);
return false;
}
- boolean ignoreWarnings = (spec.testSetup.ignoreWarningsSet
+ boolean ignoreWarnings =
+ (spec.testSetup.ignoreWarningsSet
&& spec.testSetup.ignoreWarnings);
- AjcMessageHandler handler
- = new AjcMessageHandler(spec.getMessages());
+ AjcMessageHandler handler =
+ new AjcMessageHandler(spec.getMessages());
handler.init();
boolean handlerResult = false;
boolean result = false;
@@ -349,9 +390,12 @@ public class CompilerRun implements IAjcRun {
argList.add("-d");
String outputDirPath = sandbox.classesDir.getAbsolutePath();
try { // worth it to try for canonical?
- outputDirPath = sandbox.classesDir.getCanonicalPath();
+ outputDirPath = sandbox.classesDir.getCanonicalPath();
} catch (IOException e) {
- MessageUtil.abort(status, "canonical " + sandbox.classesDir, e);
+ MessageUtil.abort(
+ status,
+ "canonical " + sandbox.classesDir,
+ e);
}
argList.add(outputDirPath);
@@ -365,7 +409,7 @@ public class CompilerRun implements IAjcRun {
argList.add("-bootclasspath");
argList.add(path);
}
-
+
path = sandbox.aspectpathToString(this);
if (!LangUtil.isEmpty(path)) {
argList.add("-aspectpath");
@@ -374,54 +418,81 @@ public class CompilerRun implements IAjcRun {
if (0 < injars.size()) {
argList.add("-injars");
- argList.add(FileUtil.flatten((String[]) injars.toArray(new String[0]), null));
+ argList.add(
+ FileUtil.flatten(
+ (String[]) injars.toArray(new String[0]),
+ null));
}
-
+
// put specified arguments last, for better badInput tests
argList.addAll(setupResult.commandOptions);
// add both java/aspectj and argfiles
argList.addAll(arguments);
-
+
// XXX hack - seek on request as a side effect. reimplement as listener
if (null != setupResult.seek) {
String slopPrefix = Spec.SEEK_MESSAGE_PREFIX + " slop - ";
- PrintStream slop = MessageUtil.handlerPrintStream(
- status,
- IMessage.INFO,
- System.err,
- slopPrefix);
- List found = FileUtil.lineSeek(setupResult.seek, arguments, false, slop);
+ PrintStream slop =
+ MessageUtil.handlerPrintStream(
+ status,
+ IMessage.INFO,
+ System.err,
+ slopPrefix);
+ List found =
+ FileUtil.lineSeek(
+ setupResult.seek,
+ arguments,
+ false,
+ slop);
if (!LangUtil.isEmpty(found)) {
- for (Iterator iter = found.iterator(); iter.hasNext();) {
- MessageUtil.info(status, Spec.SEEK_MESSAGE_PREFIX + iter.next());
- }
+ for (Iterator iter = found.iterator();
+ iter.hasNext();
+ ) {
+ MessageUtil.info(
+ status,
+ Spec.SEEK_MESSAGE_PREFIX + iter.next());
+ }
}
}
- ICommand compiler = spec.reuseCompiler
- ? sandbox.getCommand(this) // throws IllegalStateException if null
- : ReflectionFactory.makeCommand(setupResult.compilerName, status);
+ ICommand compiler = spec.reuseCompiler
+ // throws IllegalStateException if null
+ ? sandbox.getCommand(this)
+ : ReflectionFactory.makeCommand(setupResult.compilerName, status);
DirChanges dirChanges = null;
if (null == compiler) {
- MessageUtil.fail(status, "unable to make compiler " + setupResult.compilerName);
+ MessageUtil.fail(
+ status,
+ "unable to make compiler " + setupResult.compilerName);
return false;
} else {
if (setupResult.compilerName != Spec.DEFAULT_COMPILER) {
- MessageUtil.info(status, "compiler: " + setupResult.compilerName);
+ MessageUtil.info(
+ status,
+ "compiler: " + setupResult.compilerName);
}
if (status.aborted()) {
- MessageUtil.debug(status, "aborted, but compiler valid?: " + compiler);
+ MessageUtil.debug(
+ status,
+ "aborted, but compiler valid?: " + compiler);
} else {
// same DirChanges handling for JavaRun, CompilerRun, IncCompilerRun
// XXX around advice or template method/class
if (!LangUtil.isEmpty(spec.dirChanges)) {
- LangUtil.throwIaxIfFalse(1 == spec.dirChanges.size(), "expecting 0..1 dirChanges");
- dirChanges = new DirChanges((DirChanges.Spec) spec.dirChanges.get(0));
- if (!dirChanges.start(status, sandbox.classesDir)) {
+ LangUtil.throwIaxIfFalse(
+ 1 == spec.dirChanges.size(),
+ "expecting 0..1 dirChanges");
+ dirChanges =
+ new DirChanges(
+ (DirChanges.Spec) spec.dirChanges.get(0));
+ if (!dirChanges
+ .start(status, sandbox.classesDir)) {
return false; // setup failed
}
}
- MessageUtil.info(status, compiler + "(" + argList + ")");
+ MessageUtil.info(
+ status,
+ compiler + "(" + argList + ")");
sandbox.setCommand(compiler, this);
String[] args = (String[]) argList.toArray(RA_String);
commandResult = compiler.runCommand(args, handler);
@@ -431,11 +502,12 @@ public class CompilerRun implements IAjcRun {
if (!handlerResult) {
return false;
} else {
- result = (commandResult == handler.expectingCommandTrue());
- if (! result) {
- String m = commandResult
- ? "compile did not fail as expected"
- : "compile failed unexpectedly";
+ result = (commandResult == handler.expectingCommandTrue());
+ if (!result) {
+ String m =
+ commandResult
+ ? "compile did not fail as expected"
+ : "compile failed unexpectedly";
MessageUtil.fail(status, m);
} else if (null != dirChanges) {
result = dirChanges.end(status, sandbox.testBaseDir);
@@ -450,111 +522,163 @@ public class CompilerRun implements IAjcRun {
MessageUtil.info(handler, "" + setupResult);
}
}
- handler.report(status); // XXX weak - actual messages not reported in real-time, no fast-fail
- }
+ handler.report(status);
+ // XXX weak - actual messages not reported in real-time, no fast-fail
+ }
}
-
public String toString() {
return "CompilerRun(" + spec + ")";
}
-
+
/**
* Initializer/factory for CompilerRun
* any path or file is relative to this test base dir
*/
public static class Spec extends AbstractRunSpec {
public static final String XMLNAME = "compile";
+ public static final String DEFAULT_COMPILER =
+ ReflectionFactory.ECLIPSE;
static final String SEEK_PREFIX = "-seek:";
static final String SEEK_MESSAGE_PREFIX = "found: ";
-
- /** can't specify these as options */
- private static final String[] INVALID_OPTIONS = new String[]
- { "-workingdir", "-argfile", "-sourceroots", "-outjar"};
- // when updating these, update tests/harness/selectionTest.xml
-
-
- /** no support in the javac for these otherwise-valid options */
- private static final String[] INVALID_JAVAC_OPTIONS = new String[]
- { "-lenient", "-strict", "-usejavac", "-preprocess",
- "-XOcodeSize", "-XSerializable", "-XaddSafePrefix",
- "-XtargetNearSource",
- "-incremental", "-Xlint", "-aspectpath",
- "workingdir", "-argfile", "-sourceroots", "-outjar",
- };
-
- /** no support in the eclipse-based compiler for these otherwise-valid options */
- private static final String[] INVALID_ECLIPSE_OPTIONS = new String[]
- { "-lenient", "-strict", "-usejavac", "-preprocess",
- "-XOcodeSize", "-XSerializable", "-XaddSafePrefix",
- "-XtargetNearSource" };
-
- /** options supported by the harness */
- private static final String[] VALID_OPTIONS = new String[]
- {
- SEEK_PREFIX,
- // eajc does not support -usejavac, -preprocess
- // testFlag() handles -ajc, -eclipse, -javac, -ajdeCompiler, -ignoreWarnings
- "-usejavac", "-preprocess",
- "-Xlint", "-lenient", "-strict",
- "-source14", "-verbose", "-emacssym",
- "-ajc", "-eclipse", "-ajdeCompiler", "-ajctaskCompiler", "-javac",
- "-ignoreWarnings", "-1.3", "-1.4", "-1.5",
- // XXX consider adding [!^]ajdeCompiler
- "!usejavac", "!preprocess",
- "!Xlint", "!lenient", "!strict",
- "!source14", "!verbose", "!emacssym",
- "!ajc", "!eclipse",
-
- "^usejavac", "^preprocess",
- "^Xlint", "^lenient", "^strict",
- "^source14", "^verbose", "^emacssym",
- "^ajc", "^eclipse"
- };
- public static final String DEFAULT_COMPILER
- = ReflectionFactory.ECLIPSE;
+
+ private static final CRSOptions CRSOPTIONS = new CRSOptions();
+ /**
+ * Retitle description to title, paths to files, do comment,
+ * staging, badInput,
+ * do dirChanges, and print no chidren.
+ */
+ private static final AbstractRunSpec.XMLNames NAMES =
+ new AbstractRunSpec.XMLNames(
+ AbstractRunSpec.XMLNames.DEFAULT,
+ "title",
+ null,
+ null,
+ null,
+ "files",
+ null,
+ null,
+ null,
+ false,
+ false,
+ true);
/**
- * Retitle description to title, paths to files, do comment,
- * staging, badInput,
- * do dirChanges, and print no chidren.
+ * If the source version warrants, add a -bootclasspath
+ * entry to the list of arguments to add.
+ * This will fail and return an error String if the
+ * required library is not found.
+ * @param sourceVersion the String (if any) describing the -source option
+ * (expecting one of [null, "1.3", "1.4", "1.5"].
+ * @param compilerName the String name of the target compiler
+ * @param toAdd the ArrayList to add -bootclasspath to
+ * @return the String describing any errors, or null if no errors
*/
- private static final XMLNames NAMES = new XMLNames(XMLNames.DEFAULT,
- "title", null, null, null, "files", null, null, null, false, false, true);
-
+ private static String updateBootclasspathForSourceVersion(
+ String sourceVersion,
+ String compilerName,
+ ArrayList toAdd) {
+ if (null == sourceVersion) {
+ return null;
+ }
+ if (3 != sourceVersion.length()) {
+ throw new IllegalArgumentException(
+ "bad version: " + sourceVersion);
+ }
+ if (null == toAdd) {
+ throw new IllegalArgumentException("null toAdd");
+ }
+ int version = sourceVersion.charAt(2) - '0';
+ switch (version) {
+ case (3) :
+ if (LangUtil.supportsJava("1.4")) {
+ if (!FileUtil.canReadFile(Globals.J2SE13_RTJAR)) {
+ return "no 1.3 libraries to handle -source 1.3";
+ }
+ toAdd.add("-bootclasspath");
+ toAdd.add(Globals.J2SE13_RTJAR.getAbsolutePath());
+ }
+ break;
+ case (4) :
+ if (!LangUtil.supportsJava("1.4")) {
+ if (ReflectionFactory
+ .ECLIPSE
+ .equals(compilerName)) {
+ return "run eclipse under 1.4 to handle -source 1.4";
+ }
+ if (!FileUtil.canReadFile(Globals.J2SE14_RTJAR)) {
+ return "no 1.4 libraries to handle -source 1.4";
+ }
+ toAdd.add("-bootclasspath");
+ toAdd.add(Globals.J2SE14_RTJAR.getAbsolutePath());
+ }
+ break;
+ case (5) :
+ return "1.5 not supported in CompilerRun";
+ case (0) :
+ // ignore - no version specified
+ break;
+ default :
+ throw new Error("unexpected version: " + version);
+ }
+ return null;
+ }
+
+ static CRSOptions testAccessToCRSOptions() {
+ return CRSOPTIONS;
+ }
+
+ static Options testAccessToOptions() {
+ return CRSOPTIONS.getOptions();
+ }
+
+ private static String[] copy(String[] input) {
+ if (null == input) {
+ return null;
+ }
+ String[] result = new String[input.length];
+ System.arraycopy(input, 0, result, 0, input.length);
+ return result;
+ }
+
+ /** @return true if javac is available on the classpath */
+ private static boolean haveJavac() { // XXX copy/paste from JavaCWrapper.java
+ Class compilerClass = null;
+ try {
+ compilerClass = Class.forName("com.sun.tools.javac.Main");
+ } catch (ClassNotFoundException ce1) {
+ try {
+ compilerClass = Class.forName("sun.tools.javac.Main");
+ } catch (ClassNotFoundException ce2) {
+ }
+ }
+ return (null != compilerClass);
+ }
+
protected String compiler;
-
+
// use same command - see also IncCompiler.Spec.fresh
protected boolean reuseCompiler;
protected boolean includeClassesDir;
-
+
protected TestSetup testSetup;
-
+
protected String[] argfiles = new String[0];
protected String[] aspectpath = new String[0];
protected String[] classpath = new String[0]; // XXX unused
protected String[] sourceroots = new String[0];
-
+
/** src path = {suiteParentDir}/{testBaseDirOffset}/{testSrcDirOffset}/{path} */
protected String testSrcDirOffset;
-
+
public Spec() {
super(XMLNAME);
setXMLNames(NAMES);
compiler = DEFAULT_COMPILER;
}
-
- private static String[] copy(String[] input) {
- if (null == input) {
- return null;
- }
- String[] result = new String[input.length];
- System.arraycopy(input, 0, result, 0, input.length);
- return result;
- }
- protected void initClone(Spec spec)
- throws CloneNotSupportedException {
+ protected void initClone(Spec spec)
+ throws CloneNotSupportedException {
super.initClone(spec);
spec.argfiles = copy(argfiles);
spec.aspectpath = copy(aspectpath);
@@ -569,11 +693,11 @@ public class CompilerRun implements IAjcRun {
}
spec.testSrcDirOffset = testSrcDirOffset;
}
-
+
public Object clone() throws CloneNotSupportedException {
Spec result = new Spec();
initClone(result);
- return result;
+ return result;
}
public void setIncludeClassesDir(boolean include) {
@@ -582,17 +706,17 @@ public class CompilerRun implements IAjcRun {
public void setReuseCompiler(boolean reuse) {
this.reuseCompiler = reuse;
}
-
+
public void setCompiler(String compilerName) {
this.compiler = compilerName;
- }
+ }
public void setTestSrcDirOffset(String s) {
if (null != s) {
testSrcDirOffset = s;
}
}
-
+
/** override to set dirToken to Sandbox.CLASSES and default suffix to ".class" */
public void addDirChanges(DirChanges.Spec spec) {
if (null == spec) {
@@ -602,7 +726,7 @@ public class CompilerRun implements IAjcRun {
spec.setDefaultSuffix(".class");
super.addDirChanges(spec);
}
-
+
public String toLongString() {
return getPrintName() + "(" + super.containedSummary() + ")";
}
@@ -611,11 +735,11 @@ public class CompilerRun implements IAjcRun {
return getPrintName() + "(" + super.containedSummary() + ")";
}
- /** bean mapping for writers */
+ /** bean mapping for writers */
public void setFiles(String paths) {
addPaths(paths);
}
-
+
/**
* Add to default classpath
* (which includes aspectjrt.jar and testing-client.jar).
@@ -632,7 +756,7 @@ public class CompilerRun implements IAjcRun {
* Set source roots, deleting any old ones
* @param files comma-delimited list of directories
* - ignored if null or empty
- */
+ */
public void setSourceroots(String dirs) {
if (!LangUtil.isEmpty(dirs)) {
sourceroots = XMLWriter.unflattenList(dirs);
@@ -643,7 +767,7 @@ public class CompilerRun implements IAjcRun {
* Set aspectpath, deleting any old ones
* @param files comma-delimited list of aspect jars - ignored if null or
* empty
- */
+ */
public void setAspectpath(String files) {
if (!LangUtil.isEmpty(files)) {
aspectpath = XMLWriter.unflattenList(files);
@@ -653,7 +777,7 @@ public class CompilerRun implements IAjcRun {
/**
* Set argfiles, deleting any old ones
* @param files comma-delimited list of argfiles - ignored if null or empty
- */
+ */
public void setArgfiles(String files) {
if (!LangUtil.isEmpty(files)) {
argfiles = XMLWriter.unflattenList(files);
@@ -668,20 +792,22 @@ public class CompilerRun implements IAjcRun {
}
return (String[]) LangUtil.copy(argfiles);
}
-
+
/**
* This implementation skips if:
* <ul>
* <li>incremental test, but using ajc (not eclipse)</li>
* <li>usejavac, but javac is not available on the classpath</li>
* <li>eclipse, but -usejavac or -preprocess test</li>
- * <li>-source14, but running under 1.2 (XXX design)</li>
+ * <li>-source 1.4, but running under 1.2 (XXX design)</li>
* <li>local/global option conflicts (-lenient/-strict)</li>
* <li>semantic conflicts (e.g., -lenient/-strict)</li>
* </ul>
* @return false if this wants to be skipped, true otherwise
*/
- protected boolean doAdoptParentValues(RT parentRuntime, IMessageHandler handler) {
+ protected boolean doAdoptParentValues(
+ RT parentRuntime,
+ IMessageHandler handler) {
if (!super.doAdoptParentValues(parentRuntime, handler)) {
return false;
}
@@ -690,33 +816,35 @@ public class CompilerRun implements IAjcRun {
skipMessage(handler, testSetup.failureReason);
}
return testSetup.result;
- }
-
+ }
- private String getShortCompilerName() {
- String cname = compiler;
+ private String getShortCompilerName() {
+ String compilerClassName = compiler;
if (null != testSetup) {
- cname = testSetup.compilerName;
- }
- if (null != cname) {
- int loc = cname.lastIndexOf(".");
- if (-1 != loc) {
- cname = cname.substring(loc+1);
- }
- }
- return cname;
- }
-
+ compilerClassName = testSetup.compilerName;
+ }
+ if (null != compilerClassName) {
+ int loc = compilerClassName.lastIndexOf(".");
+ if (-1 != loc) {
+ compilerClassName =
+ compilerClassName.substring(loc + 1);
+ }
+ }
+ return compilerClassName;
+ }
+
/** @return a CompilerRun with this as spec if setup completes successfully. */
- public IRunIterator makeRunIterator(Sandbox sandbox, Validator validator) {
- CompilerRun run = new CompilerRun(this);
+ public IRunIterator makeRunIterator(
+ Sandbox sandbox,
+ Validator validator) {
+ CompilerRun run = new CompilerRun(this);
if (run.setupAjcRun(sandbox, validator)) {
// XXX need name for compilerRun
return new WrappedRunIterator(this, run);
}
return null;
- }
-
+ }
+
protected String getPrintName() {
return "CompilerRun.Spec " + getShortCompilerName();
}
@@ -750,9 +878,6 @@ public class CompilerRun implements IAjcRun {
* <li>lenient, strict</li>
* </ul>
* <p>
- * The -source 1.4 flag should always be specified as -source14,
- * as this will otherwise fail to process it correctly.
- * This converts it back to -source 1.4.
* <p>
* This also interprets any relevant System properties,
* e.g., from <code>JavaRun.BOOTCLASSPATH_KEY</code>.
@@ -773,298 +898,346 @@ public class CompilerRun implements IAjcRun {
* and commandOptions is not null, and any test flags (ignore warning,
* compiler) are reflected in the TestSetup.
* If this fails, then TestSetup.result is false,
- * and a TestSetup.failreason is set.
+ * and a TestSetup.failreason is set.
+ * This means the test is skipped.
* @return TestSetup with results
* (TestSetup result=false if the run should not continue)
*/
protected TestSetup setupArgs(IMessageHandler handler) {
// warning: HarnessSelectionTest checks for specific error wording
- ArrayList argList = new ArrayList();
- argList.addAll(getOptionsList());
final Spec spec = this;
- TestSetup result = new TestSetup();
- if (argList.contains("-source")) {
- result.failureReason = "use -source14 for -source 1.4: " + argList;
- return result;
- }
+ final TestSetup result = new TestSetup();
result.compilerName = spec.compiler;
- String[] globalOptions = spec.runtime.extractOptions(Spec.VALID_OPTIONS, true);
- if ((null != globalOptions) && (globalOptions.length > 0)) {
- // --- fold in globals, removing conflicts, etc.
- for (int i = 0; i < globalOptions.length; i++) {
- String globalArg = globalOptions[i];
- if ((null == globalArg) || (2 > globalArg.length())) {
- continue;
- } else if (globalArg.startsWith(SEEK_PREFIX)) {
- result.seek = globalArg.substring(SEEK_PREFIX.length());
- continue;
- } else if ("-source".equals(globalArg)) {
- result.failureReason = "use -source14 for -source 1.4 [" + i + "]";
- return result;
- }
- char first = globalArg.charAt(0);
- globalArg = globalArg.substring(1);
- boolean globalForceOn = (first == '!');
- boolean globalForceOff = (first == '^');
- boolean globalSet = (first == '-');
- if (!globalSet && !globalForceOn && !globalForceOff) {
- MessageUtil.info(handler, "ignoring bad global: " + globalOptions[i]);
- continue;
- }
- int argIndex = indexOf(globalArg, argList);
- if (-1 == argIndex) { // no apparent conflict - look for eclipse/ajc conflicts XXX unresolved
- boolean ajcGlobal = true;
- if ("ajc".equals(globalArg)) {
- argIndex = indexOf("eclipse", argList);
- } else if ("eclipse".equals(globalArg)) {
- argIndex = indexOf("ajc", argList);
- ajcGlobal = false;
- }
- if (-1 != argIndex) { // resolve eclipse/ajc conflict
- String arg = ((String) argList.get(argIndex));
- char argFirst = arg.charAt(0);
- argList.remove(arg); // replace with resolved variant...
- char ajcFirst;
- char eclipseFirst;
- if (ajcGlobal) {
- ajcFirst = first;
- eclipseFirst = argFirst;
- } else {
- ajcFirst = argFirst;
- eclipseFirst = first;
- }
- if ('!' == eclipseFirst) {
- if ('!' == ajcFirst) {
- result.failureReason = "conflict between !eclipse and !ajc";
- return result;
- } else {
- argList.add("-eclipse");
- }
- } else if (('!' == ajcFirst) || ('^' == eclipseFirst)) {
- argList.add("-ajc");
- } else if ('^' == ajcFirst) {
- argList.add("-eclipse");
- } else if (('-' != ajcFirst) || ('-' != eclipseFirst)) {
- result.failureReason = "harness logic error resolving "
- + arg + " and global " + globalArg;
- return result;
- } else if (ajcGlobal) {
- argList.add("-ajc");
- } else {
- argList.add("-eclipse");
- }
- continue; // resolved
- }
- }
-
- if (-1 == argIndex) { // no dup, so no conflict
- if (!globalForceOff) {
- argList.add("-" + globalArg);
- }
- } else { // have conflict - resolve
- String arg = (String) argList.get(argIndex);
- first = arg.charAt(0);
- boolean localForceOn = (first == '!');
- boolean localForceOff = (first == '^');
- boolean localSet = (first == '-');
- if (!localSet && !localForceOn && !localForceOff) {
- result.failureReason = "only handling [-^!]{arg}: " + arg;
- return result;
- }
- if ((localForceOn && globalForceOff)
- || (localForceOff && globalForceOn)) {
- result.failureReason = "force conflict between arg="
- + arg + " and global=" + globalOptions[i];
- return result;
- }
- if (globalForceOn) {
- if (localForceOn) { // localSet is already correct, localForceOff was conflict
- argList.remove(arg); // no !funkiness
- argList.add("-" + globalArg);
- }
- } else if (globalSet) {
- if (localSet) {
- // do nothing - already correct
- } else if (localForceOn) {
- argList.remove(arg); // no !funkiness
- argList.add("-" + globalArg);
- }
- } else if (globalForceOff) {
- argList.remove(arg);
- } else {
- throw new Error("illegal arg state?? : " + arg);
- //MessageUtil.info(handler, "illegal arg state??: " + arg);
- }
- }
- }
+ // urk - s.b. null, but expected
+ Values values = gatherValues(result);
+
+ if ((null == values) || (null != result.failureReason)) {
+ return checkResult(result);
}
+
// send info messages about
// forced staging when -incremental
// or staging but no -incremental flag
- int incLoc = argList.indexOf("-incremental");
+ Option.Family getFamily =
+ CRSOPTIONS.crsIncrementalOption.getFamily();
+ final boolean haveIncrementalFlag =
+ (null != values.firstInFamily(getFamily));
+
if (spec.isStaging()) {
- if (-1 == incLoc) { // staging and no flag
- MessageUtil.info(handler, "staging but no -incremental flag");
+ if (!haveIncrementalFlag) {
+ MessageUtil.info(
+ handler,
+ "staging but no -incremental flag");
}
- } else if (-1 != incLoc) { // flagged but not staging - stage
+ } else if (haveIncrementalFlag) {
spec.setStaging(true);
MessageUtil.info(handler, "-incremental forcing staging");
}
- // remove funky prefixes from remainder, fixup two-part flags
- // and interpret special flags
- boolean source14 = false;
- ArrayList toAdd = new ArrayList();
- for (ListIterator iter = argList.listIterator(); iter.hasNext();) {
- String arg = (String) iter.next();
- if (testFlag(arg, result)) {
- iter.remove();
- continue;
- }
- char c = arg.charAt(0);
- String rest = arg.substring(1);
- if (c == '^') {
- iter.remove();
- continue;
- }
- if (c == '!') {
- iter.remove();
- if (!("source14".equals(rest))) {
- toAdd.add("-" + rest);
- } else {
- source14 = true;
- }
- rest = null;
- } else if ("source14".equals(rest)) {
- iter.remove();
- source14 = true;
- }
+
+ if (hasInvalidOptions(values, result)) {
+ return checkResult(result);
}
- if (source14) {
- // must run under 1.4 VM or (if ajc) set up bootclasspath
- if (!LangUtil.supportsJava("1.4")) {
- if (ReflectionFactory.ECLIPSE.equals(result.compilerName)) {
- result.failureReason
- = "eclipse must run under 1.4 to implement -source 1.4";
- return result;
- }
-
- if (!FileUtil.canReadFile(Globals.J2SE14_RTJAR)) {
- result.failureReason
- = "unable to get 1.4 libraries to implement -source 1.4";
- return result;
- }
- toAdd.add("-bootclasspath");
- toAdd.add(Globals.J2SE14_RTJAR.getAbsolutePath());
- }
- toAdd.add("-source");
- toAdd.add("1.4");
- }
- argList.addAll(toAdd);
-
- // finally, check for semantic conflicts
- String[] badOptions = LangUtil.selectOptions(argList, Spec.INVALID_OPTIONS);
- if (!LangUtil.isEmpty(badOptions)) {
- result.failureReason = "no support for (normally-valid) options "
- + Arrays.asList(badOptions);
- } else if (argList.contains("-lenient") && argList.contains("-strict")) {
- result.failureReason = "semantic conflict -lenient | -strict";
- } else if (ReflectionFactory.OLD_AJC.equals(result.compilerName)) {
- if (spec.isStaging) {
- result.failureReason = "OLD_AJC does not do incremental compiles";
- } else if (argList.contains("-usejavac") && !haveJavac()) {
- result.failureReason = "-usejavac but no javac on classpath";
- } else {
- result.result = true;
- }
- } else if (ReflectionFactory.ECLIPSE.equals(result.compilerName)
- || AJDE_COMPILER.equals(result.compilerName)
- || AJCTASK_COMPILER.equals(result.compilerName)
- || BUILDER_COMPILER.equals(result.compilerName)) {
- badOptions = LangUtil.selectOptions(argList, Spec.INVALID_ECLIPSE_OPTIONS);
- if (!LangUtil.isEmpty(badOptions)) {
- result.failureReason = "no support in eclipse-based compiler"
- + " for (normally-valid) options "+ Arrays.asList(badOptions);
- } else {
- result.result = true;
+
+ // set compiler in result
+ getFamily = CRSOPTIONS.ajccompilerOption.getFamily();
+ Option.Value compiler = values.firstInFamily(getFamily);
+ if (null != compiler) {
+ result.compilerName
+ = CRSOPTIONS.compilerClassName(compiler.option);
+ if (null == result.compilerName) {
+ result.failureReason =
+ "unable to get class name for " + compiler;
+ return checkResult(result);
}
-// } else if (JAVAC_COMPILER.equals(result.compilerName)) {
-// // XXX vet
-// badOptions = LangUtil.selectOptions(argList, Spec.INVALID_JAVAC_OPTIONS);
-// if (!LangUtil.isEmpty(badOptions)) {
-// result.failureReason = "no support in javac"
-// + " for (normally-valid) options " + Arrays.asList(badOptions);
-// } else {
-// result.result = true;
-// }
- } else {
- result.failureReason = "unrecognized compiler: " + result.compilerName;
}
- if (result.result) {
- result.commandOptions = argList;
+ String compilerName =
+ (null == result.compilerName
+ ? spec.compiler
+ : result.compilerName);
+ // check compiler semantics
+ if (hasCompilerSpecErrors(compilerName, values, result)) {
+ return checkResult(result);
+ }
+ // add toadd and finish result
+ ArrayList args = new ArrayList();
+ String[] rendered = values.render();
+ if (!LangUtil.isEmpty(rendered)) {
+ args.addAll(Arrays.asList(rendered));
}
- return result;
+ // update bootclasspath
+ getFamily = CRSOPTIONS.crsSourceOption.getFamily();
+ Option.Value source = values.firstInFamily(getFamily);
+ if (null != source) {
+ String sourceVersion = source.unflatten()[1];
+ ArrayList toAdd = new ArrayList();
+ String err =
+ updateBootclasspathForSourceVersion(
+ sourceVersion,
+ spec.compiler,
+ toAdd);
+ args.addAll(toAdd);
+ }
+ result.commandOptions = args;
+ result.result = true;
+ return checkResult(result);
}
- /** @return true if javac is available on the classpath */
- private boolean haveJavac() { // XXX copy/paste from JavaCWrapper.java
- Class compilerClass = null;
- try {
- compilerClass = Class.forName("com.sun.tools.javac.Main");
- } catch (ClassNotFoundException ce1) {
- try {
- compilerClass = Class.forName("sun.tools.javac.Main");
- } catch (ClassNotFoundException ce2) {
+ /**
+ * Ensure exit invariant:
+ * <code>result.result == (null == result.failureReason)
+ * == (null != result.commandOptions)</code>
+ * @param result the TestSetup to verify
+ * @return result
+ * @throws Error if invariant is not true
+ */
+ TestSetup checkResult(TestSetup result) {
+ String err = null;
+ if (null == result) {
+ err = "null result";
+ } else if (result.result != (null == result.failureReason)) {
+ err =
+ result.result
+ ? "expected no failure: " + result.failureReason
+ : "fail for no reason";
+ } else if (result.result != (null != result.commandOptions)) {
+ err =
+ result.result
+ ? "expected command options"
+ : "unexpected command options";
+ }
+ if (null != err) {
+ throw new Error(err);
+ }
+ return result;
+ }
+
+ boolean hasInvalidOptions(Values values, TestSetup result) {
+ // not supporting 1.0 options any more
+ for (Iterator iter = CRSOPTIONS.invalidOptions.iterator();
+ iter.hasNext();
+ ) {
+ Option option = (Option) iter.next();
+ if (null != values.firstOption(option)) {
+ result.failureReason =
+ "invalid option in harness: " + option;
+ return true;
}
}
- return (null != compilerClass);
- }
+ return false;
+ }
-
- /**
- * Handle flags that are interpreted by the test rather than the
- * underlying command. These flags are to be removed from the
- * arg list.
- * @return true if this is a flag to remove from the arg list
- */
- protected boolean testFlag(String arg, TestSetup result) {
- if ("-ajdeCompiler".equals(arg)) {
- result.compilerName = AJDE_COMPILER;
- return true;
- } else if ("-builderCompiler".equals(arg)) {
- result.compilerName = BUILDER_COMPILER;
- return true;
- } else if ("-ajctaskCompiler".equals(arg)) {
- result.compilerName = AJCTASK_COMPILER;
- return true;
-// } else if ("-javac".equals(arg)) {
-// result.compilerName = JAVAC_COMPILER;
-// return true;
- } else if ("-eclipse".equals(arg) || "!eclipse".equals(arg) || "^ajc".equals(arg)) {
- result.compilerName = ReflectionFactory.ECLIPSE;
- return true;
- } else if ("-ajc".equals(arg) || "!ajc".equals(arg) || "^eclipse".equals(arg)) {
- result.compilerName = ReflectionFactory.OLD_AJC;
+ boolean hasCompilerSpecErrors(
+ String compilerName,
+ Values values,
+ TestSetup result) {
+ /*
+ * Describe any semantic conflicts between options.
+ * This skips:
+ * - old 1.0 options, including lenient v. strict
+ * - old ajc options, include !incremental and usejavac w/o javac
+ * - invalid eclipse options (mostly ajc)
+ * @param compilerName the String name of the target compiler
+ * @return a String describing any conflicts, or null if none
+ */
+ if (!(ReflectionFactory.ECLIPSE.equals(compilerName)
+ || ReflectionFactory.OLD_AJC.equals(compilerName)
+ || CRSOPTIONS.AJDE_COMPILER.equals(compilerName)
+ || CRSOPTIONS.AJCTASK_COMPILER.equals(compilerName)
+ )) {
+ //|| BUILDER_COMPILER.equals(compilerName))
+ result.failureReason =
+ "unrecognized compiler: " + compilerName;
return true;
- } else if ("-ignoreWarnings".equals(arg)) {
- result.ignoreWarnings = true;
- result.ignoreWarningsSet = true;
+ }
+ // not supporting ajc right now
+ if (null
+ != values.firstOption(CRSOPTIONS.ajccompilerOption)) {
+ result.failureReason = "ajc not supported";
return true;
}
+ // not supporting 1.0 options any more
+ for (Iterator iter = CRSOPTIONS.ajc10Options.iterator();
+ iter.hasNext();
+ ) {
+ Option option = (Option) iter.next();
+ if (null != values.firstOption(option)) {
+ result.failureReason = "old ajc 1.0 option: " + option;
+ return true;
+ }
+ }
+
return false;
}
-
+
+ protected Values gatherValues(TestSetup result) {
+ final Spec spec = this;
+ // ---- local option values
+ final Values localValues;
+ final Options options = CRSOPTIONS.getOptions();
+ try {
+ String[] input = getOptionsArray();
+ // this handles reading options,
+ // flattening two-String options, etc.
+ localValues = options.acceptInput(input);
+ // all local values should be picked up
+ String err = Options.missedMatchError(input, localValues);
+ if (!LangUtil.isEmpty(err)) {
+ result.failureReason = err;
+ return null;
+ }
+ } catch (InvalidInputException e) {
+ result.failureReason = e.getFullMessage();
+ return null;
+ }
+
+ // ---- global option values
+ StringBuffer errs = new StringBuffer();
+ final Values globalValues =
+ spec.runtime.extractOptions(options, true, errs);
+ if (errs.length() > 0) {
+ result.failureReason = errs.toString();
+ return null;
+ }
+ final Values combined =
+ Values.wrapValues(
+ new Values[] { localValues, globalValues });
+
+ String err = combined.resolve();
+ if (null != err) {
+ result.failureReason = err;
+ return null;
+ }
+
+ return handleTestArgs(combined, result);
+ }
+
+ // final int len = globalValues.length() + localValues.length();
+ // final Option.Value[] combinedValues = new Option.Value[len];
+ // System.arraycopy(
+ // globalValues,
+ // 0,
+ // combinedValues,
+ // 0,
+ // globalValues.length());
+ // System.arraycopy(
+ // localValues,
+ // 0,
+ // combinedValues,
+ // globalValues.length(),
+ // localValues.length());
+ //
+ // result.compilerName = spec.compiler;
+ // if (0 < combinedValues.length) {
+ // // this handles option forcing, etc.
+ // String err = Options.resolve(combinedValues);
+ // if (null != err) {
+ // result.failureReason = err;
+ // return null;
+ // }
+ // if (!handleTestArgs(combinedValues, result)) {
+ // return null;
+ // }
+ // }
+ // return Values.wrapValues(combinedValues);
+ // }
+ /**
+ * This interprets and nullifies values for the test.
+ * @param values the Option.Value[] being processed
+ * @param result the TestSetup to modify
+ * @return false if error (caller should return), true otherwise
+ */
+ Values handleTestArgs(Values values, final TestSetup result) {
+ final Option.Family compilerFamily =
+ CRSOPTIONS.ajccompilerOption.getFamily();
+ Values.Selector selector = new Values.Selector() {
+ protected boolean accept(Option.Value value) {
+ if (null == value) {
+ return false;
+ }
+ Option option = value.option;
+ if (compilerFamily.sameFamily(option.getFamily())) {
+ if (value.prefix.isSet()) {
+ String compilerClass
+ = CRSOPTIONS.compilerClassName(option);
+ if (null == compilerClass) {
+ result.failureReason =
+ "unrecognized compiler: " + value;
+ throw Values.Selector.STOP;
+ }
+ if (!CRSOPTIONS.compilerIsLoadable(option)) {
+ result.failureReason =
+ "unable to load compiler: " + option;
+ throw Values.Selector.STOP;
+ }
+ result.compilerName = compilerClass;
+ }
+ return true;
+ } else if (
+ CRSOPTIONS.crsIgnoreWarnings.sameOptionIdentifier(
+ option)) {
+ result.ignoreWarnings = value.prefix.isSet();
+ result.ignoreWarningsSet = true;
+ return true;
+ }
+ return false;
+ }
+ };
+ return values.nullify(selector);
+ }
+
+ // /**
+ // * This interprets and nullifies values for the test.
+ // * @param values the Option.Value[] being processed
+ // * @param result the TestSetup to modify
+ // * @return false if error (caller should return), true otherwise
+ // */
+ // boolean handleTestArgs(Option.Value[] values, TestSetup result) {
+ // if (!LangUtil.isEmpty(values)) {
+ // for (int i = 0; i < values.length; i++) {
+ // Option.Value value = values[i];
+ // if (null == value) {
+ // continue;
+ // }
+ // Option option = value.option;
+ // if (option.sameOptionFamily(ECLIPSE_OPTION)) {
+ // if (!value.prefix.isSet()) {
+ // values[i] = null;
+ // continue;
+ // }
+ // String compilerClass =
+ // (String) COMPILER_OPTION_TO_CLASSNAME.get(
+ // option);
+ // if (null == compilerClass) {
+ // result.failureReason =
+ // "unrecognized compiler: " + value;
+ // return false;
+ // }
+ // result.compilerName = compilerClass;
+ // values[i] = null;
+ // } else if (
+ // option.sameOptionFamily(crsIgnoreWarnings)) {
+ // result.ignoreWarnings = value.prefix.isSet();
+ // result.ignoreWarningsSet = true;
+ // values[i] = null;
+ // }
+ // }
+ // }
+ // return true;
+ // }
+
// XXX need keys, cache...
/** @return index of global in argList, ignoring first char */
protected int indexOf(String global, ArrayList argList) {
int max = argList.size();
for (int i = 0; i < max; i++) {
- if (global.equals(((String) argList.get(i)).substring(1))) {
+ if (global
+ .equals(((String) argList.get(i)).substring(1))) {
return i;
- }
+ }
}
return -1;
}
-
+
/**
* Write this out as a compile element as defined in
* AjcSpecXmlReader.DOCTYPE.
@@ -1087,13 +1260,19 @@ public class CompilerRun implements IAjcRun {
out.printAttribute("includeClassesDir", "true");
}
if (!LangUtil.isEmpty(argfiles)) {
- out.printAttribute("argfiles", XMLWriter.flattenFiles(argfiles));
+ out.printAttribute(
+ "argfiles",
+ XMLWriter.flattenFiles(argfiles));
}
if (!LangUtil.isEmpty(aspectpath)) {
- out.printAttribute("aspectpath", XMLWriter.flattenFiles(argfiles));
+ out.printAttribute(
+ "aspectpath",
+ XMLWriter.flattenFiles(argfiles));
}
if (!LangUtil.isEmpty(sourceroots)) {
- out.printAttribute("sourceroots", XMLWriter.flattenFiles(argfiles));
+ out.printAttribute(
+ "sourceroots",
+ XMLWriter.flattenFiles(argfiles));
}
out.endAttributes();
if (!LangUtil.isEmpty(dirChanges)) {
@@ -1102,7 +1281,7 @@ public class CompilerRun implements IAjcRun {
SoftMessage.writeXml(out, getMessages());
out.endElement(xmlElementName);
}
-
+
/**
* Encapsulate the directives that can be set using
* global arguments supplied in {@link Spec.getOptions()}.
@@ -1116,22 +1295,22 @@ public class CompilerRun implements IAjcRun {
* to ignore warnings in its result evaluation
*/
boolean ignoreWarningsSet;
-
+
/** if telling AjcMessageHandler, what we tell it */
boolean ignoreWarnings;
-
+
/** false if setup failed */
boolean result;
-
+
/** if setup failed, this has the reason why */
String failureReason;
-
+
/** beyond running test, also seek text in sources */
String seek;
-
+
/** if setup completed, this has the combined global/local options */
ArrayList commandOptions;
-
+
public Object clone() {
TestSetup testSetup = new TestSetup();
testSetup.compilerName = compilerName;
@@ -1149,13 +1328,326 @@ public class CompilerRun implements IAjcRun {
public String toString() {
return "TestSetup("
+ (null == compilerName ? "" : compilerName + " ")
- + (!ignoreWarningsSet ? ""
+ + (!ignoreWarningsSet
+ ? ""
: (ignoreWarnings ? "" : "do not ")
+ "ignore warnings ")
+ (result ? "" : "setup failed")
+ ")";
}
}
+
+ /**
+ * Options-related stuff in the spec.
+ */
+ static class CRSOptions {
+ // static final String BUILDER_COMPILER =
+ // "org.aspectj.ajdt.internal.core.builder.Builder.Command";
+ static final String AJDE_COMPILER =
+ CompileCommand.class.getName();
+
+ static final String AJCTASK_COMPILER =
+ AjcTaskCompileCommand.class.getName();
+
+ private final Map compilerOptionToLoadable = new TreeMap();
+ /*
+ * The options field in a compiler test permits some arbitrary
+ * command-line options to be set. It does not permit things
+ * like classpath, aspectpath, files, etc. which are set
+ * using other fields in the test specification, so the options
+ * permitted are a subset of those permitted on the command-line.
+ *
+ * Global options specified on the harness command-line are
+ * adopted for the compiler command-line if they are permitted
+ * in the options field. That means we have to detect each
+ * permitted option, rather than just letting all through
+ * for the compiler.
+ *
+ * Conversely, some options are targeted not at the compiler,
+ * but at the test itself (e.g., to ignore warnings, or to
+ * select a compiler.
+ *
+ * The harness can run many compilers, and they differ in
+ * which options are permitted. You can specify a compiler
+ * as an option (e.g., -eclipse). So the set of constraints
+ * on the list of permitted options can differ from test to test.
+ *
+ * The following code sets up the lists of permitted options
+ * and breaks out subsets for different compiler-variant checks.
+ * Most options are created but not named, but some options
+ * are named to detect corresponding values for further
+ * processing. e.g., the compiler options are saved so
+ * we can do per-compiler option verification.
+ *
+ */
+ private final Options crsOptions;
+ private final Family compilerFamily;
+ private final Option crsIncrementalOption;
+ private final Option crsSourceOption;
+ // these are options handled/absorbed by CompilerRun
+ private final Option crsIgnoreWarnings;
+ private final Option eclipseOption;
+ private final Option buildercompilerOption;
+ private final Option ajdecompilerOption;
+ private final Option javacOption;
+ private final Option ajctaskcompilerOption;
+ private final Option ajccompilerOption;
+ private final Map compilerOptionToClassname;
+ private final Set compilerOptions;
+ // compiler verification - permit but flag ajc 1.0 options
+ private final List ajc10Options;
+ private final List invalidOptions;
+
+ private CRSOptions() {
+ crsOptions = new Options(true);
+ Option.Factory factory = new Option.Factory("CompilerRun");
+ // compiler options go in map
+ eclipseOption =
+ factory.create(
+ "eclipse",
+ "compiler",
+ Option.FORCE_PREFIXES,
+ false);
+ compilerFamily = eclipseOption.getFamily();
+ buildercompilerOption =
+ factory.create(
+ "builderCompiler",
+ "compiler",
+ Option.FORCE_PREFIXES,
+ false);
+ ajctaskcompilerOption =
+ factory.create(
+ "ajctaskCompiler",
+ "compiler",
+ Option.FORCE_PREFIXES,
+ false);
+ ajdecompilerOption =
+ factory.create(
+ "ajdeCompiler",
+ "compiler",
+ Option.FORCE_PREFIXES,
+ false);
+ ajccompilerOption =
+ factory.create(
+ "ajc",
+ "compiler",
+ Option.FORCE_PREFIXES,
+ false);
+ javacOption =
+ factory.create(
+ "javac",
+ "compiler",
+ Option.FORCE_PREFIXES,
+ false);
+
+ Map map = new TreeMap();
+ map.put(eclipseOption, ReflectionFactory.ECLIPSE);
+ //map.put(BUILDERCOMPILER_OPTION, BUILDER_COMPILER);
+ map.put(
+ ajctaskcompilerOption,
+ AJCTASK_COMPILER);
+ map.put(ajdecompilerOption, AJDE_COMPILER);
+ map.put(ajccompilerOption, ReflectionFactory.OLD_AJC);
+ //map.put(JAVAC_OPTION, "XXX javac option not supported");
+ compilerOptionToClassname =
+ Collections.unmodifiableMap(map);
+
+ compilerOptions =
+ Collections.unmodifiableSet(
+ compilerOptionToClassname.keySet());
+ // options not permitted in the harness
+ List list = new ArrayList();
+ list.add(factory.create("workingdir"));
+ list.add(factory.create("argfile"));
+ list.add(factory.create("sourceroots"));
+ list.add(factory.create("outjar"));
+ invalidOptions = Collections.unmodifiableList(list);
+
+ // other options added directly
+ crsIncrementalOption = factory.create("incremental");
+
+ crsIgnoreWarnings = factory.create("ignoreWarnings");
+
+ crsSourceOption =
+ factory
+ .create(
+ "source",
+ "source",
+ Option.FORCE_PREFIXES,
+ false,
+ new String[][] { new String[] { "1.3", "1.4" }
+ });
+
+ // ajc 1.0 options
+ // workingdir above in invalid options
+ list = new ArrayList();
+ list.add(factory.create("usejavac"));
+ list.add(factory.create("preprocess"));
+ list.add(factory.create("nocomment"));
+ list.add(factory.create("porting"));
+ list.add(factory.create("XOcodeSize"));
+ list.add(factory.create("XTargetNearSource"));
+ list.add(factory.create("XaddSafePrefix"));
+ list.add(
+ factory.create(
+ "lenient",
+ "lenient",
+ Option.FORCE_PREFIXES,
+ false));
+ list.add(
+ factory.create(
+ "strict",
+ "lenient",
+ Option.FORCE_PREFIXES,
+ false));
+ ajc10Options = Collections.unmodifiableList(list);
+
+ // -warn:.. and -g/-g:.. are not exclusive
+ if (!(factory.setupFamily("debug", true)
+ && factory.setupFamily("warning", true))) {
+ System.err.println("CompilerRun debug/warning fail!");
+ }
+ Option[] options =
+ new Option[] {
+ crsIncrementalOption,
+ crsIgnoreWarnings,
+ crsSourceOption,
+ factory.create(
+ "Xlint",
+ "XLint",
+ Option.FORCE_PREFIXES,
+ true),
+ factory.create("verbose"),
+ factory.create("emacssym"),
+ factory.create("referenceInfo"),
+ factory.create("nowarn"),
+ factory.create("deprecation"),
+ factory.create("noImportError"),
+ factory.create("proceedOnError"),
+ factory.create("preserveAllLocals"),
+ factory.create(
+ "warn",
+ "warning",
+ Option.STANDARD_PREFIXES,
+ true),
+ factory.create(
+ "g",
+ "debug",
+ Option.STANDARD_PREFIXES,
+ false),
+ factory.create(
+ "g:",
+ "debug",
+ Option.STANDARD_PREFIXES,
+ true),
+ factory.create(
+ "1.3",
+ "compliance",
+ Option.FORCE_PREFIXES,
+ false),
+ factory.create(
+ "1.4",
+ "compliance",
+ Option.FORCE_PREFIXES,
+ false),
+ factory
+ .create(
+ "target",
+ "target",
+ Option.FORCE_PREFIXES,
+ false,
+ new String[][] { new String[] {
+ "1.1",
+ "1.2" }}),
+ factory.create("XnoInline"),
+ factory.create("XnoWeave"),
+ factory.create("XserializableAspects")
+ };
+ for (int i = 0; i < options.length; i++) {
+ crsOptions.addOption(options[i]);
+ }
+ for (Iterator iter = compilerOptions.iterator();
+ iter.hasNext();
+ ) {
+ crsOptions.addOption((Option) iter.next());
+ }
+ // these are recognized but records with them are skipped
+ for (Iterator iter = ajc10Options.iterator();
+ iter.hasNext();
+ ) {
+ crsOptions.addOption((Option) iter.next());
+ }
+ crsOptions.freeze();
+ }
+
+ Options getOptions() {
+ return crsOptions;
+ }
+
+ /**
+ * @return unmodifiable Set of options sharing the
+ * family "compiler".
+ */
+ Set compilerOptions() {
+ return compilerOptions;
+ }
+
+ /**
+ * @param option the compiler Option to get name for
+ * @return null if option is null or not a compiler option,
+ * or the fully-qualified classname of the ICommand
+ * implementing the compiler.
+ */
+ String compilerClassName(Option option) {
+ if ((null == option)
+ || (!compilerFamily.sameFamily(option.getFamily()))) {
+ return null;
+ }
+ return (String) compilerOptionToClassname.get(option);
+ }
+
+ /**
+ * Check that the compiler class associated with a compiler
+ * option can be loaded. This check only happens once;
+ * the result is cached (by compilerOption key) for later calls.
+ * @param compilerOption the Option (family compiler) to check
+ * @return true if compiler class for this option can be loaded
+ */
+ boolean compilerIsLoadable(Option compilerOption) {
+ LangUtil.throwIaxIfNull(compilerOption, "compilerName");
+ synchronized (compilerOptionToLoadable) {
+ Boolean result =
+ (Boolean) compilerOptionToLoadable.get(
+ compilerOption);
+ if (null == result) {
+ MessageHandler sink = new MessageHandler();
+ String compilerClassname =
+ (String) compilerOptionToClassname.get(
+ compilerOption);
+ if (null == compilerClassname) {
+ result = Boolean.FALSE;
+ } else {
+ ICommand c =
+ ReflectionFactory.makeCommand(
+ compilerClassname,
+ sink);
+
+ if ((null == c)
+ || sink.hasAnyMessage(
+ IMessage.ERROR,
+ true)) {
+ result = Boolean.FALSE;
+ } else {
+ result = Boolean.TRUE;
+ }
+ }
+ compilerOptionToLoadable.put(
+ compilerOption,
+ result);
+ }
+ return result.booleanValue();
+ }
+ }
+ } // CompilerRun.Spec.CRSOptions
} // CompilerRun.Spec
-} // CompilerRun
- \ No newline at end of file
+} // CompilerRun \ No newline at end of file
diff --git a/testing/src/org/aspectj/testing/harness/bridge/Globals.java b/testing/src/org/aspectj/testing/harness/bridge/Globals.java
index 9b0b7736c..e4060d50a 100644
--- a/testing/src/org/aspectj/testing/harness/bridge/Globals.java
+++ b/testing/src/org/aspectj/testing/harness/bridge/Globals.java
@@ -12,7 +12,7 @@
* Xerox/PARC initial implementation
* Wes Isberg removed unused globals.
* ******************************************************************/
-
+
package org.aspectj.testing.harness.bridge;
import java.io.File;
@@ -23,71 +23,105 @@ import org.aspectj.util.LangUtil;
/**
*/
public class Globals {
- public static final String FORK_NAME = "harness.fork"; // XXX in testing-drivers/../package.htm
+ public static final String FORK_NAME = "harness.fork";
+ // XXX in testing-drivers/../package.htm
/** name/key of the System property to set to define library dir */
public static final String LIBDIR_NAME = "harness.libdir";
/** name/key of the System property to set to define J2SE_HOME dir */
public static final String J2SE14_RTJAR_NAME = "j2se14.rtjar";
+ public static final String J2SE13_RTJAR_NAME = "j2se13.rtjar";
/** assumed relative location of a library with required jars */
- public static final String LIBDIR = getSystemProperty(LIBDIR_NAME, "../lib/test");
+ public static final String LIBDIR =
+ getSystemProperty(LIBDIR_NAME, "../lib/test");
/** Path to J2SE_HOME */
- public static final File J2SE14_RTJAR; // XXX used only by 1.0 compiler tests - deprecate?
+ public static final File J2SE14_RTJAR;
+ // XXX used only by 1.0 compiler tests - deprecate?
+ public static final File J2SE13_RTJAR;
/** array of parameter types for main(String[]) */
- public static final Class[] MAIN_PARM_TYPES = new Class[] {String[].class};
- public static final String S_testingclient_jar = LIBDIR + "/testing-client.jar";
- public static final String S_aspectjrt_jar = LIBDIR + "/aspectjrt.jar";
- public static final File F_testingclient_jar = new File(S_testingclient_jar);
- public static final File F_aspectjrt_jar = new File(S_aspectjrt_jar);
+ public static final Class[] MAIN_PARM_TYPES =
+ new Class[] { String[].class };
+ public static final String S_testingclient_jar =
+ LIBDIR + "/testing-client.jar";
+ public static final String S_aspectjrt_jar = LIBDIR + "/aspectjrt.jar";
+ public static final File F_testingclient_jar =
+ new File(S_testingclient_jar);
+ public static final File F_aspectjrt_jar = new File(S_aspectjrt_jar);
public static final boolean globalsValid;
-
+
static {
+ J2SE13_RTJAR =
+ getRtJarFor(J2SE13_RTJAR_NAME, "c:/home/apps/jdk13");
+ J2SE14_RTJAR =
+ getRtJarFor(J2SE14_RTJAR_NAME, "c:/home/apps/jdk14");
+
+ String forkSpec = getSystemProperty(FORK_NAME, null);
+ globalsValid =
+ (FileUtil.canReadFile(F_testingclient_jar)
+ && FileUtil.canReadFile(F_aspectjrt_jar)
+ && FileUtil.canReadFile(J2SE13_RTJAR)
+ && FileUtil.canReadFile(J2SE14_RTJAR));
+ }
+
+ private static File getRtJarFor(
+ String propertyName,
+ String defaultLocation) {
File j2seJar = null;
- String path = getSystemProperty(J2SE14_RTJAR_NAME, "c:/home/apps/jdk14");
- File j2seHome = new File(path);
- if (j2seHome.exists() && j2seHome.isDirectory()) {
- File rtjar = new File(j2seHome.getAbsolutePath() + "/jre/lib/rt.jar");
- if (rtjar.canRead() && rtjar.isFile()) {
- j2seJar = rtjar;
+ try {
+ String path = getSystemProperty(propertyName, defaultLocation);
+ File file = new File(path);
+ if (file.exists()) {
+ File rtjar = null;
+ if (path.endsWith("rt.jar")) {
+ rtjar = file;
+ } else if (file.isDirectory()) {
+ path = file.getAbsolutePath() + "/jre/lib/rt.jar";
+ rtjar = new File(path);
+ }
+ if (rtjar.canRead() && rtjar.isFile()) {
+ j2seJar = rtjar;
+ }
+ }
+ } catch (Throwable t) { // avoid at all costs during static init
+ try {
+ t.printStackTrace(System.err);
+ } catch (Throwable x) {
+ // unable to log, better to just fail...
}
}
- J2SE14_RTJAR = j2seJar;
- globalsValid =
- (FileUtil.canReadFile(F_testingclient_jar)
- && FileUtil.canReadFile(F_aspectjrt_jar)
- && FileUtil.canReadFile(J2SE14_RTJAR)
- );
+ return j2seJar;
}
- /**
- *
- * @return null if not found, or
+ /**
+ *
+ * @return null if not found, or
* String with class path for compiler to load J2SE 1.4 classes from.
- */
- public static String get14Bootclasspath() {
+ */
+ public static String get14Bootclasspath() {
return null;
- }
+ }
- /**
- * Get System property completely safely.
- * @param propertyName the String name of the property to get
- * @param defaultValue the String default value to return value is null or empty
- * @return String value or defaultValue if not available.
- */
- static String getSystemProperty(
- String propertyName,
- String defaultValue) {
+ /**
+ * Get System property completely safely.
+ * @param propertyName the String name of the property to get
+ * @param defaultValue the String default value to return value is null or empty
+ * @return String value or defaultValue if not available.
+ */
+ static String getSystemProperty(
+ String propertyName,
+ String defaultValue) {
String result = defaultValue;
try {
String value = System.getProperty(propertyName);
if (!LangUtil.isEmpty(value)) {
result = value;
}
- } catch (Throwable t) {}
- return result;
- }
+ } catch (Throwable t) {
+ }
+ return result;
+ }
}
diff --git a/testing/src/org/aspectj/testing/util/options/Option.java b/testing/src/org/aspectj/testing/util/options/Option.java
new file mode 100644
index 000000000..85917922e
--- /dev/null
+++ b/testing/src/org/aspectj/testing/util/options/Option.java
@@ -0,0 +1,707 @@
+/* *******************************************************************
+ * Copyright (c) 2003 Contributors.
+ * 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:
+ * Wes Isberg initial implementation
+ * ******************************************************************/
+
+package org.aspectj.testing.util.options;
+
+import java.util.*;
+
+import org.aspectj.util.LangUtil;
+
+/**
+ * Immutable schema for an input (command-line) option.
+ * The schema contains the expected name/label,
+ * the family (for comparison purposes),
+ * and permitted prefixes.
+ * This has operations to accept input values and compare options.
+ * Options cannot be created directly; for that, use an
+ * <code>Option.Factory</code>, since it enforces uniqueness
+ * within the families and options created by the factory.
+ * <p>
+ * Option is used with related nested classes to implement relations:
+ * <ul>
+ * <li>Option.Factory produces Option</li>
+ * <li>An Option has a set of Option.Prefixes,
+ * which are variants of Option.Prefix
+ * valid for the option (e.g., on/set, force-off, and force-on)</li>
+ * <li>Option evaluates input, produces Option.Value</li>
+ * <li>Related instances of Option share an Option.Family,
+ * which enforce option exclusion, etc.</li>
+ * </ul>
+ * The classes are nested as "friends" in order to hide private
+ * members (esp. constructors) that can be used within relations.
+ * Most of these classes are immutable.
+ */
+public class Option implements Comparable {
+ public static final Prefix ON = new Prefix("-", "on", true, false);
+ public static final Prefix NONE = new Prefix("", "none", true, false);
+ public static final Prefix FORCE_ON =
+ new Prefix("!", "force-on", true, true);
+
+ public static final Prefix FORCE_OFF =
+ new Prefix("^", "force-off", false, true);
+ public static final Prefixes LITERAL_PREFIXES =
+ new Prefixes(new Prefix[] { NONE });
+ public static final Prefixes STANDARD_PREFIXES =
+ new Prefixes(new Prefix[] { ON });
+ public static final Prefixes FORCE_PREFIXES =
+ new Prefixes(new Prefix[] { ON, FORCE_ON, FORCE_OFF });
+
+ /** family is the key for comparing two options */
+ private final Family family;
+
+ /** label expected for the option */
+ private final String name;
+
+ /** unique identifier for option */
+ private final String optionIdentifier;
+
+ /** prefixes permitted for the option in input */
+ private final Prefixes permittedPrefixes;
+
+ /** if true, then match on input that has extra suffix beyond prefix and name */
+ private final boolean acceptSuffixedInput;
+
+ /**
+ * If true, no collision if there are multiple values
+ * that share the same family but not the same literal value
+ */
+ private final boolean permitMultipleValues;
+
+ /** int number of arguments expected after the option itself */
+ private final int numArguments;
+
+ /**
+ * If numArguments > 0, each element has a list of arguments
+ * permitted at that index from the initial matching value.
+ * Elements are not null.
+ */
+ private final String[][] permittedArguments;
+
+ private final int nameLength;
+
+ /*
+ * Create a standard named boolean option,
+ * permitting force-on and force-off.
+ * @param name the String name of the option, e.g., "1.3" for "-1.3"
+ * @param family
+ * @param permittedPrefixes
+ * @param acceptSuffixedInput
+ * @param permittedArguments
+ */
+ public Option(
+ String name,
+ Family family,
+ Prefixes permittedPrefixes,
+ boolean acceptSuffixedInput,
+ String[][] permittedArguments) {
+ LangUtil.throwIaxIfNull(name, "name");
+ LangUtil.throwIaxIfNull(family, "family");
+ LangUtil.throwIaxIfNull(permittedPrefixes, "permittedPrefixes");
+ this.name = name;
+ this.nameLength = name.length();
+ this.family = family;
+ this.permittedPrefixes = permittedPrefixes;
+ this.acceptSuffixedInput = acceptSuffixedInput;
+ this.permitMultipleValues = false;
+ if (LangUtil.isEmpty(permittedArguments)) {
+ permittedArguments = new String[][] { };
+ // nominal, unused
+ } else {
+ String[][] temp = new String[permittedArguments.length][];
+ for (int i = 0; i < temp.length; i++) {
+ String[] toCopy = permittedArguments[i];
+ LangUtil.throwIaxIfNull(toCopy, "no permitted args");
+ final int len = toCopy.length;
+ String[] variants = new String[len];
+ System.arraycopy(toCopy, 0, variants, 0, len);
+ temp[i] = variants;
+ }
+ permittedArguments = temp;
+ }
+ this.permittedArguments = permittedArguments;
+ numArguments = permittedArguments.length;
+ optionIdentifier = family.familyName + "." + name;
+ }
+
+ public int compareTo(Object other) {
+ Option option = (Option) other;
+ int diff = family.compareTo(option.family);
+ if (0 == diff) {
+ diff = name.compareTo(option.name);
+ }
+ return diff;
+ }
+
+ public Family getFamily() {
+ return family;
+ }
+
+ public boolean permitMultipleValues() {
+ return permitMultipleValues;
+ }
+
+ /**
+ * @return int number of elements in this option,
+ * e.g., 0 for -g or 1 for -source 1.4
+ */
+ public int numArguments() {
+ return numArguments;
+ }
+
+ /**
+ * If this value String represents a valid input for this option,
+ * then create and return the associated Value.
+ *
+ * @param value the Value created, or null if invalid
+ * @return Value if this value is permitted by this option
+ */
+ public Value acceptValue(String value) {
+ Prefix prefix = hasPrefix(value);
+ if (null != prefix) {
+ if (value.startsWith(name, prefix.length())) {
+ value = value.substring(prefix.length());
+ if (value.length() == nameLength) {
+ return new Value(value, prefix, this);
+ } else if (acceptSuffixedInput) {
+ return new Value(value, prefix, this);
+ } else {
+ return rejectingSuffixedInput(value);
+ }
+ }
+ }
+ return null;
+ }
+
+ /** @return true if we have same option family */
+ public boolean sameOptionFamily(Option other) {
+ return ((null != other) && other.family.equals(family));
+ }
+
+ /** @return true if we have same option family and name */
+ public boolean sameOptionIdentifier(Option other) {
+ return (sameOptionFamily(other) && name.equals(other.name));
+ }
+
+ public String toString() {
+ return name;
+ }
+
+ /**
+ * Called when ignoreSuffix is off but we got value with suffix.
+ */
+ protected Value rejectingSuffixedInput(String value) {
+ return null;
+ }
+
+ /**
+ * Verify that the input is permitted at this position.
+ * @param input the String input to check for validity
+ * @param position the int proposed position (0-based)
+ * for the input (position 0 is for first argument)
+ * @return null if this input is valid at this position,
+ * or a String error message otherwise.
+ */
+ String validArgument(String input, int position) {
+ if (null == input) {
+ return "null input";
+ }
+ // assert numArguments == permittedInput.length
+ if ((position < 0) || (position >= numArguments)) {
+ return "no input permitted at " + position;
+ }
+ String[] permitted = permittedArguments[position];
+ for (int i = 0; i < permitted.length; i++) {
+ if (input.equals(permitted[i])) {
+ return null;
+ }
+ }
+ return input + " not permitted, expecting one of "
+ + Arrays.asList(permitted);
+ }
+
+ String getName() {
+ return name;
+ }
+ Object getKey() {
+ return family;
+ }
+
+ private String optionIdentifier() {
+ return optionIdentifier;
+ }
+
+ private Prefix hasPrefix(String value) {
+ for (Iterator iter = permittedPrefixes.iterator();
+ iter.hasNext();
+ ) {
+ Prefix prefix = (Prefix) iter.next();
+ if (-1 != prefix.prefixLength(value)) {
+ return prefix;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * An option family identifies a set of related options that
+ * might share no literal specification.
+ * E.g., the compiler family of options might include
+ * -ajc and -eclipse, and the debugInfo family of options
+ * might include -g and -g:vars.
+ * Option families may permit or avoid option collisions.
+ * <p>
+ * For subclasses to permit some collisions and not others,
+ * they should set permitMultipleFamilyValues to false
+ * and implement <code>doCollision(Option, Option)</code>.
+ * <p>
+ * This relies on Factory to ensure that familyName is
+ * a unique identifier for the factory.
+ */
+ public static class Family implements Comparable {
+
+ /** unique String identifier for this family */
+ private final String familyName;
+
+ /** if true, then report no collisions */
+ private final boolean permitMultipleFamilyValues;
+
+ protected Family(
+ String familyName,
+ boolean permitMultipleFamilyValues) {
+ this.familyName = familyName;
+ this.permitMultipleFamilyValues = permitMultipleFamilyValues;
+ }
+
+ public int compareTo(Object arg0) {
+ Family family = (Family) arg0;
+ return familyName.compareTo(family.familyName);
+ }
+
+ public boolean sameFamily(Family family) {
+ return (
+ (null != family) && familyName.equals(family.familyName));
+ }
+
+ boolean permitMultipleFamilyValues() {
+ return permitMultipleFamilyValues;
+ }
+
+ /**
+ * Options collide if they share the same family
+ * but are not the same,
+ * and multiple values are not permitted by the family.
+ * @param lhs the Option to compare with rhs
+ * @param rhs the Option to compare with lhs
+ * @return true if the two options collide, false otherwise
+ * @throws IllegalArgumentException if the input differ
+ * and share the same family, but this isn't it.
+ */
+ public final boolean collision(Option lhs, Option rhs) {
+ if ((lhs == rhs) || (null == lhs) || (null == rhs)) {
+ return false;
+ }
+ Family lhsFamily = lhs.getFamily();
+ Family rhsFamily = rhs.getFamily();
+ if (!(lhsFamily.sameFamily(rhsFamily))) {
+ return false;
+ }
+ if (lhs.sameOptionIdentifier(rhs)) {
+ return false;
+ }
+ if (this != lhsFamily) {
+ String s =
+ "expected family " + this +" got family " + lhsFamily;
+ throw new IllegalArgumentException(s);
+ }
+ return doCollision(lhs, rhs);
+ }
+
+ /**
+ * Subclasses implement this to resolve collisions on
+ * a case-by-case basis. Input are guaranteed to be
+ * non-null, different, and to share this family.
+ * This implementation returns
+ * <code>!permitMultipleFamilyValues</code>.
+ *
+ * @param lhs the Option to compare
+ * @param rhs the other Option to compare
+ * @return true if there is a collision.
+ */
+ protected boolean doCollision(Option lhs, Option rhs) {
+ return !permitMultipleFamilyValues;
+ }
+ }
+
+ /**
+ * A factory enforces a namespace on options.
+ * All options produced from a given factory are unique,
+ * as are all families.
+ * Once an option or family is created, it cannot be changed.
+ * To have a family permit multiple values
+ * (i.e., ignore collisions), set up the family before any
+ * associated options are created using
+ * <code>setupFamily(String, boolean)</code>.
+ */
+ public static class Factory {
+ private final String factoryName;
+
+ /** enforce uniqueness of family */
+ private final Map familyNameToFamily = new TreeMap();
+
+ /** enforce uniqueness of options */
+ private final ArrayList names = new ArrayList();
+
+ public Factory(String factoryName) {
+ this.factoryName = factoryName;
+ }
+
+ /**
+ * Ensure that the family with this name has the
+ * specified permission. If the family does not exist,
+ * it is created. If it does, the permission is checked.
+ * If this returns false, there is no way to change the
+ * family permission.
+ * @param name the String identifier for the family
+ * @param permitMultipleValues the boolean permission whether to
+ * allow multiple values in this family
+ * @return true if family exists with this name and permission
+ */
+ public boolean setupFamily(
+ String name,
+ boolean permitMultipleValues) {
+ LangUtil.throwIaxIfNull(name, "name");
+ Family family;
+ synchronized (familyNameToFamily) {
+ family = (Family) familyNameToFamily.get(name);
+ if (null == family) {
+ family = new Family(name, permitMultipleValues);
+ familyNameToFamily.put(name, family);
+ } else if (
+ permitMultipleValues
+ != family.permitMultipleFamilyValues) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Register a family with this factory.
+ * @return null if the family was successfully registered,
+ * or a String error otherwise
+ */
+ public String registerFamily(Family family) {
+ if (null == family) {
+ return "null family";
+ }
+ synchronized (familyNameToFamily) {
+ Family knownFamily =
+ (Family) familyNameToFamily.get(family.familyName);
+ if (null == knownFamily) {
+ familyNameToFamily.put(family.familyName, family);
+ } else if (!knownFamily.equals(family)) {
+ return "different family registered, have "
+ + knownFamily
+ + " registering "
+ + family;
+ }
+ }
+
+ return null;
+ }
+
+ public Option create(String name) {
+ return create(name, name, FORCE_PREFIXES, false);
+ }
+
+ public Option create(
+ String name,
+ String family,
+ Prefixes permittedPrefixes,
+ boolean acceptSuffixedInput) {
+ return create(
+ name,
+ family,
+ permittedPrefixes,
+ acceptSuffixedInput,
+ (String[][]) null);
+ }
+
+ public Option create(
+ String name,
+ String family,
+ Prefixes permittedPrefixes,
+ boolean acceptSuffixedInput,
+ String[][] permittedArguments) {
+ LangUtil.throwIaxIfNull(name, "name");
+ LangUtil.throwIaxIfNull(family, "family");
+ LangUtil.throwIaxIfNull(
+ permittedPrefixes,
+ "permittedPrefixes");
+ Family resolvedFamily;
+ synchronized (familyNameToFamily) {
+ resolvedFamily = (Family) familyNameToFamily.get(family);
+ if (null == resolvedFamily) {
+ resolvedFamily = new Family(family, false);
+ familyNameToFamily.put(family, resolvedFamily);
+ }
+ }
+ Option result =
+ new Option(
+ name,
+ resolvedFamily,
+ permittedPrefixes,
+ acceptSuffixedInput,
+ permittedArguments);
+ synchronized (names) {
+ String optionIdentifier = result.optionIdentifier();
+ if (names.contains(optionIdentifier)) {
+ String s = "not unique: " + result;
+ throw new IllegalArgumentException(s);
+ } else {
+ names.add(optionIdentifier);
+ }
+ }
+ return result;
+ }
+
+ public String toString() {
+ return Factory.class.getName() + ": " + factoryName;
+ }
+
+ private void checkUnique(Option result) {
+ String name = result.family + "." + result.name;
+ }
+ }
+
+ /**
+ * The actual input value for an option.
+ * When an option takes arguments, all the arguments
+ * are absorbed/flattened into its value.
+ */
+ public static class Value {
+ private static final String FLATTEN_DELIM = "_";
+
+ private static final int NOTARGUMENT = -1;
+
+ private static String flatten(String prefix, String suffix) {
+ return prefix + FLATTEN_DELIM + suffix;
+ }
+
+ private static String[] unflatten(Value value) {
+ if (value.argIndex == Value.NOTARGUMENT) {
+ return new String[] { value.value };
+ }
+ StringTokenizer st =
+ new StringTokenizer(value.value, FLATTEN_DELIM);
+ String[] result = new String[st.countTokens()];
+ // assert result.length == 1+inputIndex
+ for (int i = 0; i < result.length; i++) {
+ result[i] = st.nextToken();
+ }
+ return result;
+
+ }
+
+ public final String value;
+ public final Prefix prefix;
+ public final Option option;
+ private final int argIndex;
+
+ private Value(
+ String value,
+ Prefix prefix,
+ Option option) {
+ this(value, prefix, option, NOTARGUMENT);
+ }
+ private Value(
+ String value,
+ Prefix prefix,
+ Option option,
+ int argIndex) {
+ this.value = value;
+ this.prefix = prefix;
+ this.option = option;
+ this.argIndex = argIndex;
+ // asserts deferred - local clients only
+ // assert null != value
+ // assert null != prefix
+ // assert null != option
+ // assert 0 <= inputIndex
+ // assert inputIndex <= option.numArguments()
+ // assert {number of DELIM} == argIndex
+ }
+
+ public String[] unflatten() {
+ return unflatten(this);
+ }
+
+ /**
+ * Create new value same as this, but with new prefix.
+ * If the prefix is the same, return this.
+ * @param prefix the Prefix to convert to
+ * @return Value with new prefix - never null
+ */
+ public Value convert(Prefix prefix) {
+ LangUtil.throwIaxIfNull(prefix, "prefix");
+ if (this.prefix.equals(prefix)) {
+ return this;
+ }
+ return new Value(
+ this.value,
+ prefix,
+ this.option,
+ this.argIndex);
+ }
+
+ /**
+ *
+ * @param other
+ * @return true if other == this for purposes of collisions
+ */
+ public boolean sameValueIdentifier(Value other) {
+ return (
+ (null != other)
+ && sameValueIdentifier(option, other.value));
+ }
+
+ public boolean sameValueIdentifier(Option option, String value) {
+ return (
+ (null != option)
+ && this.option.sameOptionIdentifier(option)
+ && this.value.equals(value));
+ }
+
+ public boolean conflictsWith(Value other) {
+ return (
+ (null != other)
+ && option.equals(other.option)
+ && (prefix.force == other.prefix.force)
+ && ((prefix.set != other.prefix.set)
+ || !value.equals(other.value)));
+ }
+
+ public String toString() {
+ return option + "=" + prefix + value;
+ }
+
+ final Value nextInput(String input) throws InvalidInputException {
+ final int index = argIndex + 1;
+ String err = option.validArgument(input, index);
+ if (null != err) {
+ throw new InvalidInputException(err, input, option);
+ }
+ return new Value(flatten(value, input), prefix, option, index);
+ }
+ }
+
+ /**
+ * A bunch of prefixes.
+ */
+ public static class Prefixes {
+ final List list;
+ private Prefixes(Prefix[] prefixes) {
+ if (LangUtil.isEmpty(prefixes)) {
+ list = Collections.EMPTY_LIST;
+ } else {
+ list =
+ Collections.unmodifiableList(
+ Arrays.asList(
+ LangUtil.safeCopy(prefixes, new Prefix[0])));
+ }
+ }
+ public Iterator iterator() {
+ return list.iterator();
+ }
+ }
+
+ /**
+ * A permitted prefix for an option, mainly so that options
+ * "-verbose", "^verbose", and "!verbose" can be treated
+ * as variants (set, force-off, and force-on) of the
+ * same "verbose" option.
+ */
+ public static class Prefix {
+ private final String prefix;
+ private final int prefixLength;
+ private final String name;
+ private final boolean set;
+ private final boolean force;
+ private Prefix(
+ String prefix,
+ String name,
+ boolean set,
+ boolean force) {
+ this.prefix = prefix;
+ this.name = name;
+ this.set = set;
+ this.force = force;
+ this.prefixLength = prefix.length();
+ }
+
+ /**
+ * Render a value for input if this is set.
+ * @param value the String to render as an input value
+ * @return null if value is null or option is not set,
+ * "-" + value otherwise
+ */
+ public String render(String value) {
+ return ((!set || (null == value)) ? null : "-" + value);
+ }
+
+ boolean forceOff() {
+ return force && !set;
+ }
+ boolean forceOn() {
+ return force && set;
+ }
+ public boolean isSet() {
+ return set;
+ }
+ private int length() {
+ return prefixLength;
+ }
+ private int prefixLength(String input) {
+ if ((null != input) && input.startsWith(prefix)) {
+ return length();
+ }
+ return -1;
+ }
+ public String toString() {
+ return prefix;
+ }
+ }
+
+ /**
+ * Thrown when an Option specifies required arguments,
+ * but the arguments are not available.
+ */
+ public static class InvalidInputException extends Exception {
+ public final String err;
+ public final String input;
+ public final Option option;
+ InvalidInputException(String err, String input, Option option) {
+ super(err);
+ this.err = err;
+ this.input = input;
+ this.option = option;
+ }
+ public String getFullMessage() {
+ return "illegal input \""
+ + input
+ + "\" for option "
+ + option
+ + ": "
+ + err;
+ }
+ }
+}
diff --git a/testing/src/org/aspectj/testing/util/options/Options.java b/testing/src/org/aspectj/testing/util/options/Options.java
new file mode 100644
index 000000000..642ea0ca7
--- /dev/null
+++ b/testing/src/org/aspectj/testing/util/options/Options.java
@@ -0,0 +1,152 @@
+/* *******************************************************************
+ * Copyright (c) 2003 Contributors.
+ * 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:
+ * Wes Isberg initial implementation
+ * ******************************************************************/
+
+package org.aspectj.testing.util.options;
+
+import java.util.*;
+
+import org.aspectj.util.LangUtil;
+
+/**
+ * A bunch of options that handle search boilerplate.
+ * This enforces an initialization phase by permitting
+ * options to be added only until frozen, and
+ * permitting matching only after frozen.
+ */
+public class Options {
+
+ /** if true, then perform extra checks to debug problems */
+ private static final boolean verifying = false;
+ private static final boolean FROZEN = true;
+
+ /**
+ * List input unmatched by options, if any.
+ * @param input the String[] used to generate the values
+ * @param values the Option.Value[] found from the input
+ * @return null if no values are null, String list of missed otherwise
+ */
+ public static String missedMatchError(
+ String[] input,
+ Values values) {
+ int[] missed = values.indexMissedMatches();
+ LangUtil.throwIaxIfNull(input, "input");
+ LangUtil.throwIaxIfNull(values, "values");
+ LangUtil.throwIaxIfFalse(
+ input.length == values.length(),
+ "input is not matched by values");
+ if (0 == missed.length) {
+ return null;
+ }
+ StringBuffer sb = new StringBuffer();
+ sb.append("missed values: [");
+ for (int i = 0; i < missed.length; i++) {
+ if (i > 0) {
+ sb.append(", ");
+ }
+ sb.append(missed[i] + ": " + input[missed[i]]);
+ }
+ sb.append("]");
+ return sb.toString();
+ }
+
+ private final ArrayList options = new ArrayList();
+ private final boolean stopAtFirstMatch;
+ private boolean frozen = !FROZEN;
+
+ public Options(boolean stopAtFirstMatch) {
+ this.stopAtFirstMatch = stopAtFirstMatch;
+ }
+
+ public void freeze() {
+ if (frozen != FROZEN) {
+ frozen = FROZEN;
+ }
+ }
+
+ public boolean isFrozen() {
+ return (frozen == FROZEN);
+ }
+
+ public void addOption(Option option) {
+ checkFrozen("adding option", !FROZEN);
+ LangUtil.throwIaxIfNull(option, "option");
+ options.add(option);
+ }
+
+ /**
+ * Associate options matched, if any, with input by index.
+ * If an input element is not matched, the corresponding
+ * result element will be null.
+ * If there are multi-argument options matched, then
+ * only the initial element will be non-null, but it
+ * will contain the accumulated value of the arguments.
+ * @param input the String[] of input
+ * @return Option.Value[] corresponding to input
+ * @throws Option.InvalidInputException when encountering
+ * invalid arguments to a matched multi-argument option.
+ */
+ public Values acceptInput(String[] input)
+ throws Option.InvalidInputException {
+ checkFrozen("matching options", FROZEN);
+ if ((null == input) || (0 == input.length)) {
+ return Values.EMPTY;
+ }
+ Option.Value[] results = new Option.Value[input.length];
+ for (int i = 0; i < input.length; i++) {
+ Option.Value result = firstMatch(input[i]);
+ final int index = i;
+ if (null != result) {
+ for (int len = result.option.numArguments();
+ len > 0;
+ len--) {
+ i++;
+ if (i >= input.length) {
+ throw new Option.InvalidInputException(
+ "not enough arguments",
+ null,
+ result.option);
+ }
+ result = result.nextInput(input[i]);
+ }
+ }
+ results[index] = result;
+ }
+ return Values.wrapValues(results);
+ }
+
+ private void checkFrozen(String actionLabel, boolean expectFrozen) {
+ if (expectFrozen != isFrozen()) {
+ if (null == actionLabel) {
+ actionLabel = "use";
+ }
+ if (expectFrozen) {
+ actionLabel = "must freeze before " + actionLabel;
+ } else {
+ actionLabel = "frozen before " + actionLabel;
+ }
+ throw new IllegalStateException(actionLabel);
+ }
+ }
+
+ private Option.Value firstMatch(String value) {
+ LangUtil.throwIaxIfNull(value, "value");
+ ArrayList list = new ArrayList();
+ for (Iterator iter = options.iterator(); iter.hasNext();) {
+ Option option = (Option) iter.next();
+ Option.Value result = option.acceptValue(value);
+ if (null != result) {
+ return result;
+ }
+ }
+ return null;
+ }
+}
diff --git a/testing/src/org/aspectj/testing/util/options/Values.java b/testing/src/org/aspectj/testing/util/options/Values.java
new file mode 100644
index 000000000..21cd3b52f
--- /dev/null
+++ b/testing/src/org/aspectj/testing/util/options/Values.java
@@ -0,0 +1,714 @@
+/* *******************************************************************
+ * Copyright (c) 2003 Contributors.
+ * 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:
+ * Wes Isberg initial implementation
+ * ******************************************************************/
+
+package org.aspectj.testing.util.options;
+
+import java.util.*;
+
+import org.aspectj.testing.util.options.Option.Value;
+import org.aspectj.util.LangUtil;
+
+/**
+ * Wrapper for Value[] that handles search boilerplate.
+ */
+public class Values {
+ public static final Values EMPTY;
+ /** used by methods taking Selector to halt processing early */
+ private static final boolean VERIFYING = true;
+ private static final boolean FIND_ALL = true;
+
+ private static final String NO_ERROR = "no error";
+
+ static {
+ EMPTY = new Values(new Value[0]);
+ }
+
+ public static Values wrapValues(Value[] values) {
+ if ((null == values) || (0 == values.length)) {
+ return EMPTY;
+ }
+ return new Values(values);
+ }
+
+ public static Values wrapValues(Values[] values) {
+ if ((null == values) || (0 == values.length)) {
+ return EMPTY;
+ }
+ Value[] input = null;
+ if (values.length == 1) {
+ input = values[0].asArray();
+ LangUtil.throwIaxIfNull(input, "values");
+ } else {
+ int length = 0;
+ for (int i = 0; i < values.length; i++) {
+ if (values[i] == null) {
+ LangUtil.throwIaxIfNull(null, "null value[" + i + "]");
+ }
+ length += values[i].length();
+ }
+ input = new Value[length];
+ length = 0;
+ Value[] temp;
+ for (int i = 0; i < values.length; i++) {
+ temp = values[i].asArray();
+ System.arraycopy(temp, 0, input, length, temp.length);
+ length += temp.length;
+ }
+ }
+ return new Values(input);
+ }
+
+ static int[] invert(int[] missed, int length) {
+ final int MAX = length;
+ final int len = MAX - missed.length;
+ final int[] result = new int[len];
+ int missedIndex = 0;
+ int resultIndex = 0;
+ for (int counter = 0; counter < MAX; counter++) {
+ // catch result up to missed
+ while (((missedIndex >= missed.length)
+ || (missed[missedIndex] > counter))
+ && (counter < MAX)) {
+ result[resultIndex++] = counter++;
+ }
+ // absorb missed up to counter
+ while ((missedIndex < missed.length)
+ && (missed[missedIndex] <= counter)
+ && (counter < MAX)) {
+ missedIndex++;
+ }
+ }
+ return result;
+ }
+
+ private static Option.Value[] toArray(ArrayList list) {
+ return (Option.Value[]) list.toArray(new Option.Value[0]);
+ }
+
+ /**
+ * Resolve input to remove any values matching the same options,
+ * where option conflicts are handled by option forcing.
+ * First, for any force-off value, all matching set-on and
+ * the force-off itself are removed. At this time, if there
+ * is a matching force-on, then this will return an error.
+ * Next, for any force-on value, it is converted to set-on,
+ * and any other matching set-on value is removed.
+ * Finally, this signals a collision if two values share
+ * the same option family and the family reports that this is
+ * a collision.
+ * In all cases, only the first error detected is reported.
+ * @param input the Option.Value[] matched from the input,
+ * (forced/duplicate options will be set to null)
+ * @return String error during resolution, or null if no error
+ */
+ private static String resolve(Option.Value[] input) {
+ String err = null;
+ if (LangUtil.isEmpty(input)) {
+ return null;
+ }
+
+ Map familyToMatches = new TreeMap();
+ for (int i = 0;(null == err) && (i < input.length); i++) {
+ if (null != input[i]) {
+ Option.Family family = input[i].option.getFamily();
+ int[] matches = (int[]) familyToMatches.get(family);
+ if (null == matches) {
+ matches = match(input, i);
+ familyToMatches.put(family, matches);
+ }
+ }
+ }
+
+ familyToMatches = Collections.unmodifiableMap(familyToMatches);
+ for (Iterator iter = familyToMatches.entrySet().iterator();
+ (null == err) && iter.hasNext();
+ ) {
+ Map.Entry entry = (Map.Entry) iter.next();
+ int[] matches = (int[]) entry.getValue();
+ err = resolve(input, matches);
+ }
+ return err;
+ }
+
+ /**
+ * Resolve all related options into one
+ * by nullifying or modifying the values.
+ *
+ * First, for any force-off value,
+ * remove all identical set-on
+ * and the force-off itself,
+ * and alert on any identical force-on.
+ *
+ * Next, for any force-on value,
+ * convert to set-on,
+ * throw Error on any same-family force-off value,
+ * remove any identical force-on or set-on value,
+ * alert on any other non-identical same-family force-on value,
+ * remove any same-family set-on value,
+ * and alert on any same-family set-off value.
+ *
+ * Finally, alert if any two remaining values share
+ * the same option family, unless the option is marked
+ * as permitting multiple values.
+ *
+ * @param input the Option.Value[] matching the input
+ * @param matches the int[] list of indexes into input for
+ * values for related by option
+ * (all such values must have option matched by family)
+ * @return String error, if any, or null if no error
+ * @see #match(Option.Value[], int)
+ */
+ private static String resolve(Option.Value[] input, int[] matches) {
+ String err = null;
+ // seek force-off
+ Option.Value forceOff = null;
+ Option option = null;
+ // find and remove any force-off
+ for (int i = 0;(null == err) && (i < matches.length); i++) {
+ Option.Value value = input[matches[i]];
+ if (null != value) {
+ // verify that matches are in the same family
+ if (VERIFYING) {
+ if (null == option) {
+ option = value.option;
+ } else if (!(option.sameOptionFamily(value.option))) {
+ String s =
+ value.option
+ + " has different family from "
+ + option;
+ throw new IllegalArgumentException(s);
+ }
+ }
+ if (value.prefix.forceOff()) {
+ err = removeForceOff(input, value, matches);
+ }
+ }
+ }
+ // find and set any force-on, removing others
+ for (int i = 0;(null == err) && (i < matches.length); i++) {
+ Option.Value value = input[matches[i]];
+ if (null != value) {
+ if (value.prefix.forceOn()) {
+ err = convertForceOn(input, i, matches);
+ }
+ }
+ }
+ // remove any exact duplicates
+ for (int i = 0;(null == err) && (i < matches.length); i++) {
+ Option.Value value = input[matches[i]];
+ if (null != value) {
+ for (int j = i + 1; j < matches.length; j++) {
+ if (value.sameValueIdentifier(input[matches[j]])) {
+ input[matches[j]] = null;
+ }
+ }
+ }
+ }
+ // signal error if two left unless permitMultipleFamilyValues
+ Option.Value first = null;
+ for (int i = 0;(null == err) && (i < matches.length); i++) {
+ Option.Value value = input[matches[i]];
+ if (null != value) {
+ if (null == first) {
+ first = value;
+ if (first
+ .option
+ .getFamily()
+ .permitMultipleFamilyValues()) {
+ break;
+ }
+ } else {
+ err = "collision between " + first + " and " + value;
+ }
+ }
+ }
+
+ return err;
+ }
+
+ /**
+ * For any force-off value,
+ * remove all set-on or force-off with same value
+ * (including the force-off itself),
+ * and alert on any identical force-on.
+ * @param input the Option.Value[] matching the input
+ * @param value the force-off Option.Value to remove
+ * @param matches the int[] list of indexes into input for
+ * values for related by option
+ * (all such values must have matching option)
+ * @return String error if any
+ */
+ private static String removeForceOff(
+ Option.Value[] input,
+ Option.Value value,
+ int[] matches) {
+ if (!value.prefix.forceOff()) {
+ throw new IllegalArgumentException(
+ "expecting force-off: " + value);
+ }
+ for (int i = 0; i < matches.length; i++) {
+ Option.Value match = input[matches[i]];
+ if ((null != match) && value.sameValueIdentifier(match)) {
+ if (match.prefix.forceOn()) {
+ return "force conflict between "
+ + value
+ + " and "
+ + match;
+ } else {
+ input[matches[i]] = null; // unset matches[i]?
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * For this force-on value, convert to set-on,
+ * throw Error on any same-family force-off value,
+ * remove any identical force-on or set-on value,
+ * alert on any other non-identical same-family force-on value,
+ * remove any same-family set-on value,
+ * and alert on any same-family set-off value.
+ * This must be called after <code>removeForceOff(..)</code>.
+ * @param input the Option.Value[] to modify
+ * @param valueIndex the int index in matches to find the force-on
+ * and to start after
+ * @param matches the int[] map into input entries with matching options
+ * @return
+ * @throw Error if any matching force-off found
+ */
+ private static String convertForceOn(
+ Option.Value[] input,
+ int valueIndex,
+ int[] matches) {
+ Option.Value value = input[matches[valueIndex]];
+ if (!value.prefix.forceOn()) {
+ throw new IllegalArgumentException(
+ "expecting force-on: " + value);
+ }
+ input[matches[valueIndex]] = value.convert(Option.ON);
+ for (int i = 0; i < matches.length; i++) {
+ if (i == valueIndex) {
+ continue;
+ }
+ Option.Value match = input[matches[i]];
+ if (null != match) {
+ // assert match.sameOptionFamily(value);
+ if (match.prefix.forceOff()) {
+ throw new Error(
+ "unexpected force-off:"
+ + match
+ + " when processing "
+ + value);
+ }
+ if (value.option.sameOptionIdentifier(match.option)) {
+ input[matches[i]] = null;
+ // remove any identical force-on or set
+ } else if (match.prefix.forceOn()) {
+ return "conflict between " + match + " and " + value;
+ } else if (match.prefix.isSet()) {
+ input[matches[i]] = null;
+ // remove any same-value set-on value
+ } else { // same family, force-off
+ return "collision between " + match + " and " + value;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Get a list of input matching the option in the initial value,
+ * rendered as indexes into the input array.
+ * @param input the Option.Value[] to seek in
+ * @param start the int index of the starting position
+ * @return int[] of indexes into input with the same option
+ * as index[start] - never null, but can be empty
+ */
+ private static int[] match(Option.Value[] input, int start) {
+ IntList result = new IntList();
+ Option.Family key = null;
+ Option.Family nextKey = null;
+ for (int i = start; i < input.length; i++) {
+ if (null != input[i]) {
+ nextKey = input[i].option.getFamily();
+ if (null == key) {
+ key = nextKey;
+ result.add(i);
+ } else if (key.equals(nextKey)) {
+ result.add(i);
+ }
+ }
+ }
+ return result.getList();
+ }
+
+ static int nullify(Option.Value[] values, Selector selector) {
+ LangUtil.throwIaxIfNull(selector, "selector");
+ int changed = 0;
+ for (int i = 0; i < values.length; i++) {
+ final boolean accepted;
+ try {
+ accepted = selector.accept(values[i]);
+ } catch (Error e) {
+ if (e != Selector.STOP) {
+ throw e;
+ }
+ break;
+ }
+ if (accepted) {
+ if (null != values[i]) {
+ values[i] = null;
+ changed++;
+ }
+ }
+ }
+ return changed;
+ }
+
+ /**
+ * Render set values as String using associated prefix.
+ * @param values the Value[] to render
+ * @return String[] of values rendered for output
+ * (never null or longer than values, but might be shorter)
+ */
+ private static String[] render(Value[] values) {
+ ArrayList list = new ArrayList();
+ for (int i = 0; i < values.length; i++) {
+ if (null != values[i]) {
+ String[] output = values[i].unflatten();
+ if (LangUtil.isEmpty(output)) {
+ throw new Error("no output for " + values[i]);
+ }
+
+ String s = values[i].prefix.render(output[0]);
+ if (null != s) { // this means the prefix is set
+ list.add(s);
+ for (int j = 1; j < output.length; j++) {
+ list.add(output[j]);
+ }
+ }
+ }
+ }
+ return (String[]) list.toArray(new String[list.size()]);
+ }
+
+ private final Option.Value[] values;
+ private Option.Value[] valuesNotNull;
+ private String resolveError;
+
+ private Values(Value[] values) {
+ this.values = new Value[values.length];
+ System.arraycopy(values, 0, this.values, 0, values.length);
+ }
+
+ public int length() {
+ return values.length;
+ }
+
+ public Option.Value[] asArray() {
+ Option.Value[] result = new Option.Value[values.length];
+ System.arraycopy(values, 0, result, 0, result.length);
+ return result;
+ }
+
+ /**
+ * Emit as String[] the non-null values.
+ * @return String[] of matched entries (never null, elements not null)
+ */
+ public String[] render() {
+ return Values.render(valuesNotNull());
+ }
+
+ public String toString() {
+ return Arrays.asList(values).toString();
+ }
+
+ /**
+ * Create index into values of those that were matched,
+ * including the options and their arguments.
+ * @return int[] of elements in values that are not null (options)
+ * or that represent option arguments
+ */
+ public int[] indexMatches() {
+ // must be in order, low to high
+ final int[] missed = indexMissedMatches();
+ return invert(missed, length());
+ }
+
+ /**
+ * Create index into values of missed input,
+ * taking into account that matched arguments are
+ * represented as null.
+ * @return int[] of elements in values that are null
+ * or optionally represent option arguments
+ */
+ public int[] indexMissedMatches() {
+ MissedSelector selector = new MissedSelector();
+ find(selector, FIND_ALL);
+ String errors = selector.getErrors();
+ if (null != errors) {
+ throw new Error(errors);
+ }
+ return selector.getResult();
+ }
+
+ public Value firstInFamily(Option.Family family) {
+ return findFirst(new ValueSelector(family));
+ }
+
+ public Value[] allInFamily(Option.Family family) {
+ return find(new ValueSelector(family), FIND_ALL);
+ }
+
+ public Value firstOption(Option option) {
+ return findFirst(new ValueSelector(option));
+ }
+
+ public Value[] allOption(Option option) {
+ return find(new ValueSelector(option), FIND_ALL);
+ }
+
+ public Value firstValue(Option option, String value) {
+ LangUtil.throwIaxIfNull(value, "value");
+ return findFirst(new ValueSelector(option, value));
+ }
+
+ public Value[] allValues(Option option, String value) {
+ LangUtil.throwIaxIfNull(value, "value");
+ return find(new ValueSelector(option, value), FIND_ALL);
+ }
+
+ public boolean isResolved() {
+ return ((this != EMPTY) && (null != resolveError));
+ }
+
+ /**
+ *
+ * @param selector the Selector to pick out entries to nullify
+ * (should throw STOP to halt processing)
+ * @return Values resulting from nullifying entries,
+ * or this if none were changed
+ */
+ public Values nullify(Selector selector) {
+ if (null == selector) {
+ return this;
+ }
+ Value[] temp = asArray();
+ int changed = nullify(temp, selector);
+ if (0 == changed) {
+ return this;
+ }
+ return new Values(temp);
+ }
+
+ /**
+ * Resolve options, removing duplicates by force if necessary.
+ * If any error is returned, then the values are left unchanged.
+ * @return String error, if any
+ * @throws IllegalStateException if <code>isResolved()</code>
+ */
+ public String resolve() {
+ if (isResolved()) {
+ throw new IllegalStateException("already resolved");
+ }
+ Option.Value[] temp = asArray();
+ resolveError = resolve(temp);
+ if (null == resolveError) {
+ System.arraycopy(temp, 0, values, 0, temp.length);
+ valuesNotNull = null;
+ resolveError = NO_ERROR;
+ return null;
+ }
+ return resolveError;
+ }
+
+ protected Option.Value findFirst(Selector filter) {
+ Option.Value[] result = find(filter, !FIND_ALL);
+ return (0 == result.length ? null : result[0]);
+ }
+
+ protected Option.Value[] find(Selector filter, boolean findAll) {
+ LangUtil.throwIaxIfNull(filter, "filter");
+ ArrayList result = new ArrayList();
+ for (int i = 0; i < values.length; i++) {
+ final boolean accepted;
+ try {
+ accepted = filter.accept(values[i]);
+ } catch (Error e) {
+ if (Selector.STOP != e) {
+ throw e;
+ }
+ break;
+ }
+ if (accepted) {
+ result.add(values[i]);
+ if (findAll != FIND_ALL) {
+ break;
+ }
+ }
+ }
+ return toArray(result);
+ }
+
+ private Option.Value[] valuesNotNull() {
+ if (null == valuesNotNull) {
+ ArrayList list = new ArrayList();
+ for (int i = 0; i < this.values.length; i++) {
+ if (null != this.values[i]) {
+ list.add(this.values[i]);
+ }
+ }
+ valuesNotNull = toArray(list);
+ }
+ return valuesNotNull;
+ }
+
+ public static class Selector {
+ public static final Error STOP = new Error("stop invoking Selector");
+ protected Selector() {
+ }
+ protected boolean accept(Value value) {
+ return false;
+ }
+ }
+ protected static class ValueSelector extends Selector {
+
+ private final Option option;
+ private final Option.Family family;
+ private final String value;
+ ValueSelector(Option.Family family) {
+ LangUtil.throwIaxIfNull(family, "family");
+ this.family = family;
+ option = null;
+ value = null;
+ }
+ ValueSelector(Option option) {
+ this(option, (String) null);
+ }
+ ValueSelector(Option option, String value) {
+ LangUtil.throwIaxIfNull(option, "option");
+ this.option = option;
+ family = null;
+ this.value = value;
+ }
+ protected boolean accept(Value value) {
+ if (null == value) {
+ return false;
+ }
+ if (null != family) {
+ return family.sameFamily(value.option.getFamily());
+ } else if (!option.sameOptionIdentifier(value.option)) {
+ return false;
+ } else {
+ return ((null == this.value)
+ || (this.value.equals(value.value)));
+ }
+ }
+ }
+
+ /** pick all null entries (except for args), return as int[] */
+ protected static class MissedSelector extends Selector {
+ public static final String DELIM = "; ";
+ final IntList result = new IntList();
+ int index;
+ final StringBuffer errors = new StringBuffer();
+ int argsExpected;
+ Option argsExpectedFor;
+ MissedSelector() {
+ }
+
+ int[] getResult() {
+ return result.getList();
+ }
+
+ /**
+ * add index if value is null
+ * unless skipArguments
+ */
+ protected boolean accept(Value value) {
+ index++;
+ if (null != value) {
+ if (0 < argsExpected) { // expected more (null) args
+ missedArgsFor(argsExpectedFor, argsExpected);
+ }
+ argsExpected = value.option.numArguments();
+ argsExpectedFor = value.option;
+ } else if (0 < argsExpected) { // ignore null in arg position
+ argsExpected--;
+ if (0 == argsExpected) {
+ argsExpectedFor = null;
+ }
+ } else { // null, not expecting arg, so missing
+ result.add(index - 1);
+ return true;
+ }
+ return false;
+ }
+
+ private void missedArgsFor(Option option, int numArgs) {
+ errors.append("missed ");
+ errors.append(numArgs + " args for ");
+ errors.append(option + DELIM);
+ }
+
+ String getErrors() {
+ if (0 < argsExpected) {
+ }
+ if (0 == errors.length()) {
+ return null;
+ }
+ return errors.toString();
+ }
+ }
+
+ static class IntList {
+ // not synchronized - used only in one thread
+ static String render(int[] input) {
+ if (null == input) {
+ return "null";
+ }
+ StringBuffer sb = new StringBuffer();
+ sb.append("[");
+ for (int i = 0; i < input.length; i++) {
+ if (i > 0) {
+ sb.append(", " + input[i]);
+ } else {
+ sb.append("" + input[i]);
+ }
+ }
+ sb.append("]");
+ return sb.toString();
+ }
+
+ private int[] input = new int[256];
+ private int insert;
+ private void add(int i) {
+ if (insert >= input.length) {
+ int[] temp = new int[insert + 256];
+ for (int j = 0; j < input.length; j++) {
+ temp[j] = input[j];
+ }
+ input = temp;
+ }
+ input[insert++] = i;
+ }
+
+ private int[] getList() {
+ int[] result = new int[insert];
+ for (int i = 0; i < result.length; i++) {
+ result[i] = input[i];
+ }
+ return result;
+ }
+ }
+}
diff --git a/testing/testsrc/TestingModuleTests.java b/testing/testsrc/TestingModuleTests.java
index 452d2e0b1..4c904ac90 100644
--- a/testing/testsrc/TestingModuleTests.java
+++ b/testing/testsrc/TestingModuleTests.java
@@ -25,6 +25,7 @@ public class TestingModuleTests extends TestCase {
suite.addTest(org.aspectj.testing.harness.bridge.TestingBridgeTests.suite());
suite.addTest(org.aspectj.testing.taskdefs.TaskdefTests.suite());
suite.addTest(org.aspectj.testing.util.UtilTests.suite());
+ suite.addTest(org.aspectj.testing.util.options.OptionsTests.suite());
suite.addTest(org.aspectj.testing.xml.TestingXmlTests.suite());
return suite;
}
diff --git a/testing/testsrc/org/aspectj/testing/harness/bridge/CompilerRunSpecTest.java b/testing/testsrc/org/aspectj/testing/harness/bridge/CompilerRunSpecTest.java
index a876db105..8d05160b4 100644
--- a/testing/testsrc/org/aspectj/testing/harness/bridge/CompilerRunSpecTest.java
+++ b/testing/testsrc/org/aspectj/testing/harness/bridge/CompilerRunSpecTest.java
@@ -1,6 +1,6 @@
/* *******************************************************************
- * Copyright (c) 1999-2001 Xerox Corporation,
- * 2002 Palo Alto Research Center, Incorporated (PARC).
+ * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC),
+ * 2003 Contributors.
* All rights reserved.
* This program and the accompanying materials are made available
* under the terms of the Common Public License v1.0
@@ -9,14 +9,22 @@
*
* Contributors:
* Xerox/PARC initial implementation
+ * Wes Isberg 2003 modifications
* ******************************************************************/
package org.aspectj.testing.harness.bridge;
+import java.util.*;
+import java.util.Arrays;
+
import junit.framework.TestCase;
import org.aspectj.bridge.MessageHandler;
import org.aspectj.bridge.MessageUtil;
+import org.aspectj.testing.harness.bridge.CompilerRun.Spec.CRSOptions;
+import org.aspectj.testing.util.options.*;
+import org.aspectj.testing.util.options.Options;
+import org.aspectj.util.LangUtil;
/**
*
@@ -24,147 +32,515 @@ import org.aspectj.bridge.MessageUtil;
public class CompilerRunSpecTest extends TestCase {
private static boolean PRINTING = true;
-
- /**
- * Constructor for CompilerRunSpecTest.
- * @param name
- */
- public CompilerRunSpecTest(String name) {
- super(name);
- }
+ private static final boolean SETUP_JAVA13 =
+ haveProperty(Globals.J2SE13_RTJAR_NAME);
+ private static final boolean SETUP_JAVA14 =
+ haveProperty(Globals.J2SE14_RTJAR_NAME);
+ static {
+ if (!SETUP_JAVA14) {
+ System.err.println(
+ "warning: set -D"
+ + Globals.J2SE14_RTJAR_NAME
+ + "=... in order to run all tests");
+ }
+ if (!SETUP_JAVA13) {
+ System.err.println(
+ "warning: set -D"
+ + Globals.J2SE13_RTJAR_NAME
+ + "=... in order to run all tests");
+ }
+ }
+ private static boolean haveProperty(String key) {
+ try {
+ return (null != System.getProperty(key));
+ } catch (Throwable t) {
+ // ignore
+ }
+ return false;
+ }
+
+ /**
+ * Constructor for CompilerRunSpecTest.
+ * @param name
+ */
+ public CompilerRunSpecTest(String name) {
+ super(name);
+ }
public void testSetupArgs() {
- checkSetupArgs("verbose", false);
- // XXX skipping since eclipse is default
- // checkSetupArgs("lenient", false);
- // checkSetupArgs("strict", false);
- // checkSetupArgs("ajc", true); // XXX need to predict/test compiler selection
- // eclipse-only
checkSetupArgs("eclipse", true);
+ checkSetupArgs("verbose", false);
+ }
+
+ public void testCompliance() {
+ // 1.3 should work
+ String specOptions = "-1.3";
+ String[] globalOptions = new String[0];
+ boolean expectAdopted = true;
+ String resultContains = "1.3";
+ String messagesContain = null;
+ MessageHandler handler =
+ runTest(
+ specOptions,
+ globalOptions,
+ expectAdopted,
+ resultContains,
+ messagesContain);
+ checkMessages(handler, null);
+
+ // 1.3 should work with collision?
+ globalOptions = new String[] { "-1.3" };
+ resultContains = "1.3";
+ handler =
+ runTest(
+ specOptions,
+ globalOptions,
+ expectAdopted,
+ resultContains,
+ messagesContain);
+ checkMessages(handler, null);
+
+ // 1.4 should work
+ globalOptions = new String[0];
+ specOptions = "-1.4";
+ resultContains = "1.4";
+ handler =
+ runTest(
+ specOptions,
+ globalOptions,
+ expectAdopted,
+ resultContains,
+ messagesContain);
+ checkMessages(handler, null);
+
+ // compliance not checked for valid numbers, so -1.2 would pass
+ }
+
+ private void checkMessages(MessageHandler handler, String contains) {
+ if (null == contains) {
+ if (0 != handler.numMessages(null, true)) {
+ assertTrue("" + handler, false);
+ }
+ } else {
+ String messages = "" + handler;
+ if (-1 == messages.indexOf(contains)) {
+ assertTrue(messages, false);
+ }
+ }
+ }
+
+ /** @testcase check -target converts for 1.1 and 1.2, not others */
+ public void testTarget() {
+ final boolean PASS = true;
+ final boolean FAIL = false;
+ checkSourceTargetVersionConversion("target", 1, PASS, null);
+ checkSourceTargetVersionConversion("target", 2, PASS, null);
+ checkSourceTargetVersionConversion(
+ "target",
+ 3,
+ FAIL,
+ "illegal input");
+ }
+
+ /** @testcase check -source converts for 1.3 and 1.4, not others */
+ public void testSource() {
+ final boolean PASS = true;
+ final boolean FAIL = false;
+ if (SETUP_JAVA13) {
+ checkSourceTargetVersionConversion("source", 3, PASS, null);
+ }
+ if (SETUP_JAVA14) {
+ checkSourceTargetVersionConversion("source", 4, PASS, null);
+ }
+
+ checkSourceTargetVersionConversion(
+ "source",
+ 2,
+ FAIL,
+ "not permitted");
+ checkSourceTargetVersionConversion(
+ "source",
+ 6,
+ FAIL,
+ "not permitted");
+ }
+
+ public void testSourceOverride() {
+ if (SETUP_JAVA13 && SETUP_JAVA14) {
+ checkSourceTargetOverride("source", 3, 4);
+ checkSourceTargetOverride("source", 4, 3);
+ checkSourceTargetOverride("source", 3, 3);
+ checkSourceTargetOverride("source", 4, 4);
+ }
+ }
+
+ public void testTargetOverride() {
+ checkSourceTargetOverride("target", 1, 2);
+ checkSourceTargetOverride("target", 2, 1);
+ checkSourceTargetOverride("target", 1, 1);
+ checkSourceTargetOverride("target", 2, 2);
}
- void checkSetupArgs(String arg, boolean isTestArg) {
+ public void testCompilerOptions() {
+ checkCompilerOption(null, CompilerRun.Spec.DEFAULT_COMPILER);
+ CRSOptions crsOptions = CompilerRun.Spec.testAccessToCRSOptions();
+ Set options = crsOptions.compilerOptions();
+ assertTrue(null != options);
+ StringBuffer notLoaded = new StringBuffer();
+ for (Iterator iter = options.iterator(); iter.hasNext();) {
+ Option compilerOption = (Option) iter.next();
+ if (!(crsOptions.compilerIsLoadable(compilerOption))) {
+ notLoaded.append(" " + compilerOption);
+ } else {
+ String className = crsOptions.compilerClassName(compilerOption);
+ String argValue = compilerOption.toString(); // XXX snoop
+ String arg = Option.ON.render(argValue);
+ checkCompilerOption(arg, className);
+ }
+ }
+ if (0 < notLoaded.length()) {
+ System.err.println(
+ getClass().getName()
+ + ".testCompilerOptions()"
+ + " warning: compiler options not tested because not loadable: "
+ + notLoaded);
+ }
+ }
+
+ void checkCompilerOption(String arg, String className) {
+ MessageHandler handler = new MessageHandler();
+ try {
+ CompilerRun.Spec spec = null;
+ try {
+ spec = new CompilerRun.Spec();
+ } catch (Throwable t) {
+ t.printStackTrace(System.err);
+ }
+ assertTrue(spec != null);
+ AbstractRunSpec.RT parentRuntime = new AbstractRunSpec.RT();
+ String result;
+ String expResult;
+
+ if (null != arg) {
+ parentRuntime.setOptions(new String[] { arg });
+ }
+ if (!spec.adoptParentValues(parentRuntime, handler)) {
+ if (0 != handler.numMessages(null, true)) {
+ assertTrue(handler.toString(), false);
+ } else {
+ assertTrue("adopt failed, but no messages", false);
+ }
+ }
+ result = "" + spec.testSetup.commandOptions;
+ assertEquals("[]", result);
+ assertEquals(className, spec.testSetup.compilerName);
+ } finally {
+ }
+ }
+
+ public void testSpecOptions() {
+ Options options = CompilerRun.Spec.testAccessToOptions();
+ OptionChecker optionChecker = new OptionChecker(options);
+ // known failures: extdirs, aspectpath, Xlintfile <file>
+ // progress, time, noExit, repeat <n>,
+ // help,
+ String[][] input =
+ new String[][] {
+ new String[] { "-verbose" },
+ new String[] { "-incremental" },
+ new String[] { "-emacssym" },
+ new String[] { "-Xlint" },
+ new String[] { "-Xlint:error" },
+ new String[] { "-1.3" },
+ new String[] { "-1.4" },
+ new String[] { "-source", "1.3" },
+ new String[] { "-source", "1.4" },
+ new String[] { "-target", "1.1" },
+ new String[] { "-target", "1.2" },
+ new String[] { "-preserveAllLocals" },
+ new String[] { "-referenceInfo" },
+ new String[] { "-deprecation" },
+ new String[] { "-noImportError" },
+ new String[] { "-proceedOnError" }
+ };
+ String[][] literalInput =
+ new String[][] {
+ new String[] { "-nowarn" },
+ new String[] { "-warn:deprecated" },
+ new String[] { "-warn:deprecated,unverified" },
+ new String[] { "-warn:deprecated", "-warn:unusedLocals" },
+ new String[] { "-g" },
+ new String[] { "-g", "-g:none" },
+ new String[] { "-g:vars,source" },
+ new String[] { "-verbose", "-g:vars,source" },
+ };
+ // normal
+ for (int i = 0; i < input.length; i++) {
+ optionChecker.checkOptions(input[i], input[i]);
+ }
+ for (int i = 0; i < literalInput.length; i++) {
+ optionChecker.checkOptions(literalInput[i], literalInput[i]);
+ }
+ // force-on
+ String[][] forceInput = duplicate(input, "!");
+ for (int i = 0; i < input.length; i++) {
+ optionChecker.checkOptions(forceInput[i], input[i]);
+ }
+ // force-off
+ forceInput = duplicate(input, "^");
+ String[] none = new String[0];
+ for (int i = 0; i < input.length; i++) {
+ optionChecker.checkOptions(forceInput[i], none);
+ }
+ }
+
+ String[][] duplicate(String[][] input, String prefix) {
+ String[][] output = new String[input.length][];
+ final int prefixLength = (null == prefix ? 0 : prefix.length());
+ for (int i = 0; i < output.length; i++) {
+ int length = input[i].length;
+ output[i] = new String[length];
+ if ((length > 0) && (prefixLength > 0)) {
+ System.arraycopy(input[i], 0, output[i], 0, length);
+ output[i][0] =
+ prefix + output[i][0].substring(prefixLength);
+ }
+ }
+ return output;
+ }
+
+ public void checkSourceTargetOverride(String name, int from, int to) {
+ final String specOptions = "-" + name + ", 1." + from;
+ String[] globalOptions = new String[] { "!" + name, "1." + to };
+ boolean expectAdopted = true;
+ String resultContains = "[-" + name + ", 1." + to;
+ String messagesContain = null;
+ MessageHandler handler =
+ runTest(
+ specOptions,
+ globalOptions,
+ expectAdopted,
+ resultContains,
+ messagesContain);
+ checkMessages(handler, null);
+ }
+
+ void checkSourceTargetVersionConversion(
+ String name,
+ int i,
+ boolean expectPass,
+ String expectedErr) {
+ final String specOptions = "-" + name + ", 1." + i;
+ String[] globalOptions = new String[0];
+ boolean expectAdopted = expectPass;
+ String resultContains =
+ !expectPass ? null : "[-" + name + ", 1." + i;
+ String messagesContain = expectedErr;
+ MessageHandler handler =
+ runTest(
+ specOptions,
+ globalOptions,
+ expectAdopted,
+ resultContains,
+ messagesContain);
+ }
+
+ MessageHandler runTest(
+ String specOptions,
+ String[] globalOptions,
+ boolean expectAdopted,
+ String resultContains,
+ String messagesContain) {
MessageHandler handler = new MessageHandler();
try {
CompilerRun.Spec spec = new CompilerRun.Spec();
AbstractRunSpec.RT parentRuntime = new AbstractRunSpec.RT();
+
+ if (!LangUtil.isEmpty(specOptions)) {
+ spec.setOptions(specOptions);
+ }
+ if (!LangUtil.isEmpty(globalOptions)) {
+ parentRuntime.setOptions(globalOptions);
+ }
+ boolean adopted =
+ spec.adoptParentValues(parentRuntime, handler);
+ if (adopted != expectAdopted) {
+ String s =
+ (expectAdopted ? "not " : "")
+ + "adopted spec="
+ + specOptions
+ + " globals="
+ + (LangUtil.isEmpty(globalOptions)
+ ? "[]"
+ : Arrays.asList(globalOptions).toString())
+ + " -- "
+ + handler;
+ assertTrue(s, false);
+ }
+ if (null != resultContains) {
+ String result = "" + spec.testSetup.commandOptions;
+ if (-1 == result.indexOf(resultContains)) {
+ assertTrue(
+ "expected " + resultContains + " got " + result,
+ false);
+ }
+ }
+ if (null != messagesContain) {
+ boolean haveMessages =
+ (0 != handler.numMessages(null, true));
+ if (!haveMessages) {
+ assertTrue("expected " + messagesContain, false);
+ } else {
+ String messages = handler.toString();
+ if (-1 == messages.indexOf(messagesContain)) {
+ assertTrue(
+ "expected "
+ + messagesContain
+ + " got "
+ + messages,
+ false);
+ }
+ }
+ }
+ return handler;
+ } finally {
+ }
+ }
+
+ void checkSetupArgs(String arg, final boolean isTestArg) {
+ MessageHandler handler = new MessageHandler();
+ try {
+ CompilerRun.Spec spec = null;
+ try {
+ spec = new CompilerRun.Spec();
+ } catch (Throwable t) {
+ t.printStackTrace(System.err);
+ }
+ assertTrue(spec != null);
+ AbstractRunSpec.RT parentRuntime = new AbstractRunSpec.RT();
String result;
String expResult;
-
+
// -------- local set
+ // global - (set) does not change local-set
+ parentRuntime.setOptions(new String[] { "-" + arg });
+ assertTrue(spec.adoptParentValues(parentRuntime, handler));
+ if (0 != handler.numMessages(null, true)) {
+ assertTrue(handler.toString(), false);
+ }
+ result = "" + spec.testSetup.commandOptions;
+ expResult = (isTestArg ? "[]" : "[-" + arg + "]");
+ assertTrue(result, expResult.equals(result));
+
// global ^ (force-off) to disable
spec.setOptions("-" + arg);
- parentRuntime.setOptions(new String[] {"^" + arg});
+ parentRuntime.setOptions(new String[] { "^" + arg });
assertTrue(spec.adoptParentValues(parentRuntime, handler));
if (0 != handler.numMessages(null, true)) {
assertTrue(handler.toString(), false);
}
- result = ""+spec.testSetup.commandOptions;
+ result = "" + spec.testSetup.commandOptions;
assertTrue(result, "[]".equals(result));
-
+
// global ! (force-on) does not change local-set
- parentRuntime.setOptions(new String[] {"!" + arg});
+ parentRuntime.setOptions(new String[] { "!" + arg });
assertTrue(spec.adoptParentValues(parentRuntime, handler));
if (0 != handler.numMessages(null, true)) {
assertTrue(handler.toString(), false);
}
- result = ""+spec.testSetup.commandOptions;
+ result = "" + spec.testSetup.commandOptions;
expResult = (isTestArg ? "[]" : "[-" + arg + "]");
- assertTrue(result, expResult.equals(result));
-
- // global - (set) does not change local-set
- parentRuntime.setOptions(new String[] {"-" + arg});
- assertTrue(spec.adoptParentValues(parentRuntime, handler));
- if (0 != handler.numMessages(null, true)) {
- assertTrue(handler.toString(), false);
+ if (!expResult.equals(result)) {
+ assertTrue(
+ "expected " + expResult + " got " + result,
+ false);
}
- result = ""+spec.testSetup.commandOptions;
- expResult = (isTestArg ? "[]" : "[-" + arg + "]");
- assertTrue(result, expResult.equals(result));
-
+
// global (unset) does not change local-set
- parentRuntime.setOptions(new String[] {""});
+ parentRuntime.setOptions(new String[] { "" });
assertTrue(spec.adoptParentValues(parentRuntime, handler));
if (0 != handler.numMessages(null, true)) {
assertTrue(handler.toString(), false);
}
- result = ""+spec.testSetup.commandOptions;
+ result = "" + spec.testSetup.commandOptions;
expResult = (isTestArg ? "[]" : "[-" + arg + "]");
assertTrue(result, expResult.equals(result));
-
+
// -------- local force-on
// global ^ (force-off) conflicts with local force-on
spec.setOptions("!" + arg);
- parentRuntime.setOptions(new String[] {"^" + arg});
+ parentRuntime.setOptions(new String[] { "^" + arg });
assertTrue(!spec.adoptParentValues(parentRuntime, handler));
assertTrue(0 != handler.numMessages(null, true));
handler.init();
-
+
// global ! (force-on) does not change local force-on
- parentRuntime.setOptions(new String[] {"!" + arg});
+ parentRuntime.setOptions(new String[] { "!" + arg });
assertTrue(spec.adoptParentValues(parentRuntime, handler));
if (0 != handler.numMessages(null, true)) {
assertTrue(handler.toString(), false);
}
- result = ""+spec.testSetup.commandOptions;
+ result = "" + spec.testSetup.commandOptions;
expResult = (isTestArg ? "[]" : "[-" + arg + "]");
assertTrue(result, expResult.equals(result));
-
+
// global - (set) does not change local force-on
- parentRuntime.setOptions(new String[] {"-" + arg});
+ parentRuntime.setOptions(new String[] { "-" + arg });
assertTrue(spec.adoptParentValues(parentRuntime, handler));
if (0 != handler.numMessages(null, true)) {
assertTrue(handler.toString(), false);
}
- result = ""+spec.testSetup.commandOptions;
+ result = "" + spec.testSetup.commandOptions;
expResult = (isTestArg ? "[]" : "[-" + arg + "]");
assertTrue(result, expResult.equals(result));
-
+
// global (unset) does not change local force-on
- parentRuntime.setOptions(new String[] {""});
+ parentRuntime.setOptions(new String[] { "" });
assertTrue(spec.adoptParentValues(parentRuntime, handler));
if (0 != handler.numMessages(null, true)) {
assertTrue(handler.toString(), false);
}
- result = ""+spec.testSetup.commandOptions;
+ result = "" + spec.testSetup.commandOptions;
expResult = (isTestArg ? "[]" : "[-" + arg + "]");
assertTrue(result, expResult.equals(result));
-
-
+
// -------- local force-off
// global ^ (force-off) does not change local force-off
spec.setOptions("^" + arg);
- parentRuntime.setOptions(new String[] {"^" + arg});
+ parentRuntime.setOptions(new String[] { "^" + arg });
assertTrue(spec.adoptParentValues(parentRuntime, handler));
if (0 != handler.numMessages(null, true)) {
assertTrue(handler.toString(), false);
}
- result = ""+spec.testSetup.commandOptions;
+ result = "" + spec.testSetup.commandOptions;
assertTrue(result, ("[]").equals(result));
-
+
// global ! (force-on) conflicts with local force-off
- parentRuntime.setOptions(new String[] {"!" + arg});
+ parentRuntime.setOptions(new String[] { "!" + arg });
assertTrue(!spec.adoptParentValues(parentRuntime, handler));
assertTrue(0 != handler.numMessages(null, true));
handler.init();
-
- // global - (set) overridden by local force-off // XXX??
- parentRuntime.setOptions(new String[] {"-" + arg});
+
+ // global - (set) overridden by local force-off
+ parentRuntime.setOptions(new String[] { "-" + arg });
assertTrue(spec.adoptParentValues(parentRuntime, handler));
if (0 != handler.numMessages(null, true)) {
assertTrue(handler.toString(), false);
}
- result = ""+spec.testSetup.commandOptions;
+ result = "" + spec.testSetup.commandOptions;
assertTrue(result, ("[]").equals(result));
-
+
// global (unset) does not change local force-off
- parentRuntime.setOptions(new String[] {""});
+ parentRuntime.setOptions(new String[] { "" });
assertTrue(spec.adoptParentValues(parentRuntime, handler));
if (0 != handler.numMessages(null, true)) {
assertTrue(handler.toString(), false);
}
- result = ""+spec.testSetup.commandOptions;
+ result = "" + spec.testSetup.commandOptions;
assertTrue(result, ("[]").equals(result));
+
+ // undefined whether global set overrides local set
+ // for different sibling options
} finally {
if (PRINTING && (0 < handler.numMessages(null, true))) {
MessageUtil.print(System.err, handler, "checkSetupArgs: ");
diff --git a/testing/testsrc/org/aspectj/testing/util/options/OptionChecker.java b/testing/testsrc/org/aspectj/testing/util/options/OptionChecker.java
new file mode 100644
index 000000000..f2ae8acad
--- /dev/null
+++ b/testing/testsrc/org/aspectj/testing/util/options/OptionChecker.java
@@ -0,0 +1,195 @@
+/* *******************************************************************
+ * Copyright (c) 2003 Contributors.
+ * 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:
+ * Wes Isberg initial implementation
+ * ******************************************************************/
+
+package org.aspectj.testing.util.options;
+
+import java.util.Arrays;
+
+import junit.framework.Assert;
+
+import org.aspectj.testing.util.LangUtil;
+
+/**
+ * Checks that throw AssertionFailedError on failure.
+ * Subclasses reimplement <code>assertionFailed(String)</code>
+ * to handle failures differently.
+ */
+public class OptionChecker {
+ private final Options options;
+
+ public OptionChecker(Options options) {
+ this.options = options;
+ LangUtil.throwIaxIfNull(options, "options");
+ }
+
+ /**
+ * Subclasses override this to throw different exceptions
+ * on assertion failures.
+ * This implementation delegates to
+ * <code>Assert.assertTrue(label, false)</code>.
+ * @param label the String message for the assertion
+ *
+ */
+ public void assertionFailed(String label) {
+ Assert.assertTrue(label, false);
+ }
+
+ public void checkAssertion(String label, boolean test) {
+ if (!test) {
+ assertionFailed(label);
+ }
+ }
+
+ public void checkOptions(String[] input, String[] expected) {
+ checkOptions(input, expected, true);
+ }
+
+ public void checkOptions(
+ String[] input,
+ String[] expected,
+ boolean resolve) {
+ Values values = getValues(input);
+ if (resolve) {
+ String err = values.resolve();
+ checkAssertion("error: \"" + err + "\"", null == err);
+ }
+ String[] actual = values.render(); // Value.render(values);
+ checkEqual(expected, actual);
+ }
+
+ public void checkOptionsNegative(
+ String[] input,
+ String expectedMissedMatchErr,
+ String expectedResolveErr) {
+ checkOptionsNegative(
+ input,
+ null,
+ expectedMissedMatchErr,
+ expectedResolveErr);
+ }
+
+ public void checkOptionsNegative(
+ String[] input,
+ String expectedInValuesException,
+ String expectedMissedMatchErr,
+ String expectedResolveErr) {
+ Values values =
+ getValuesNegative(input, expectedInValuesException);
+ if (null == expectedInValuesException) {
+ String err = Options.missedMatchError(input, values);
+ checkContains(expectedMissedMatchErr, err);
+ err = values.resolve();
+ checkContains(expectedResolveErr, err);
+ }
+ }
+
+ private Values getValuesNegative(
+ String[] input,
+ String expectedInExceptionMessage,
+ Options options) {
+ try {
+ return options.acceptInput(input);
+ } catch (Option.InvalidInputException e) {
+ String m = e.getFullMessage();
+ boolean ok =
+ (null != expectedInExceptionMessage)
+ && (-1 != m.indexOf(expectedInExceptionMessage));
+ if (!ok) {
+ e.printStackTrace(System.err);
+ if (null != expectedInExceptionMessage) {
+ m =
+ "expected \""
+ + expectedInExceptionMessage
+ + "\" in "
+ + m;
+ }
+ assertionFailed(m);
+ }
+ return null; // actually never executed
+ }
+ }
+
+ private Values getValuesNegative(
+ String[] input,
+ String expectedInExceptionMessage) {
+ return getValuesNegative(
+ input,
+ expectedInExceptionMessage,
+ options);
+ }
+
+ private Values getValues(String[] input, Options options) {
+ return getValuesNegative(input, null, options);
+ }
+
+ private Values getValues(String[] input) {
+ return getValuesNegative(input, null);
+ }
+
+ private void checkContains(String expected, String expectedIn) {
+ if (null == expected) {
+ if (null != expectedIn) {
+ assertionFailed("did not expect \"" + expectedIn + "\"");
+ }
+ } else {
+ if ((null == expectedIn)
+ || (-1 == expectedIn.indexOf(expected))) {
+ assertionFailed(
+ "expected \""
+ + expected
+ + "\" in \""
+ + expectedIn
+ + "\"");
+ }
+ }
+ }
+
+ private String safeString(String[] ra) {
+ return (null == ra ? "null" : Arrays.asList(ra).toString());
+ }
+
+ private void checkEqual(String[] expected, String[] actual) {
+ if (!isEqual(expected, actual)) {
+ assertionFailed(
+ "expected \""
+ + safeString(expected)
+ + "\" got \""
+ + safeString(actual)
+ + "\"");
+ }
+ }
+
+ private boolean isEqual(String[] expected, String[] actual) {
+ if (null == expected) {
+ return (null == actual ? true : false);
+ } else if (null == actual) {
+ return false;
+ } else if (expected.length != actual.length) {
+ return false;
+ }
+ for (int i = 0; i < actual.length; i++) {
+ String e = expected[i];
+ String a = actual[i];
+ if (null == e) {
+ if (null != a) {
+ return false;
+ }
+ } else if (null == a) {
+ return false;
+ } else if (!(e.equals(a))) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+}
diff --git a/testing/testsrc/org/aspectj/testing/util/options/OptionsTest.java b/testing/testsrc/org/aspectj/testing/util/options/OptionsTest.java
new file mode 100644
index 000000000..29048aa07
--- /dev/null
+++ b/testing/testsrc/org/aspectj/testing/util/options/OptionsTest.java
@@ -0,0 +1,486 @@
+/* *******************************************************************
+ * Copyright (c) 2003 Contributors.
+ * 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:
+ * Wes Isberg initial implementation
+ * ******************************************************************/
+
+package org.aspectj.testing.util.options;
+
+import junit.framework.*;
+
+import org.aspectj.testing.util.options.Option.InvalidInputException;
+
+/**
+ */
+public class OptionsTest extends TestCase {
+
+ private static Options OPTIONS;
+
+ private static Options getOptions() {
+ if (null == OPTIONS) {
+ OPTIONS = new Options(true);
+ Option.Factory factory = new Option.Factory("OptionsTest");
+ OPTIONS.addOption(factory.create("verbose"));
+ OPTIONS.addOption(factory.create("quiet"));
+ OPTIONS.addOption(factory.create("debug"));
+ OPTIONS.addOption(
+ factory.create("ajc", "compiler", Option.FORCE_PREFIXES, false));
+ OPTIONS.addOption(
+ factory.create(
+ "eclipse",
+ "compiler",
+ Option.FORCE_PREFIXES,
+ false));
+ OPTIONS.addOption(
+ factory.create(
+ "ajdeCompiler",
+ "compiler",
+ Option.FORCE_PREFIXES,
+ false));
+ OPTIONS.addOption(
+ factory.create("1.3", "compliance", Option.FORCE_PREFIXES, false));
+ OPTIONS.addOption(
+ factory.create("1.4", "compliance", Option.FORCE_PREFIXES, false));
+
+ // treating multi-arg as single - extrinsic flatten/unflatten
+ OPTIONS.addOption(
+ factory.create("target11", "target", Option.FORCE_PREFIXES, false));
+ OPTIONS.addOption(
+ factory.create("target12", "target", Option.FORCE_PREFIXES, false));
+ OPTIONS.addOption(
+ factory.create("source13", "source", Option.FORCE_PREFIXES, false));
+ OPTIONS.addOption(
+ factory.create("source14", "source", Option.FORCE_PREFIXES, false));
+
+ // suffix options (a) -warn:... (b) -g, -g:...
+ Assert.assertTrue(factory.setupFamily("warning", true));
+ OPTIONS.addOption(
+ factory.create("warn", "warning", Option.STANDARD_PREFIXES, true));
+
+ Assert.assertTrue(factory.setupFamily("debugSymbols", true));
+ OPTIONS.addOption(
+ factory.create(
+ "g",
+ "debugSymbols",
+ Option.STANDARD_PREFIXES,
+ false));
+ OPTIONS.addOption(
+ factory.create(
+ "g:",
+ "debugSymbols",
+ Option.STANDARD_PREFIXES,
+ true));
+
+ // treating multi-arg as single - intrinsic flatten/unflatten
+ OPTIONS
+ .addOption(
+ factory
+ .create(
+ "target",
+ "target",
+ Option.FORCE_PREFIXES,
+ false,
+ new String[][] {
+ new String[] { "1.1", "1.2" }
+ }));
+ OPTIONS
+ .addOption(
+ factory
+ .create(
+ "source",
+ "source",
+ Option.FORCE_PREFIXES,
+ false,
+ new String[][] {
+ new String[] { "1.3", "1.4" }
+ }));
+ OPTIONS.freeze();
+ }
+ return OPTIONS;
+ }
+
+ private boolean verbose;
+ private OptionChecker localOptionChecker;
+
+ public void testDebugCase() {
+ OptionChecker optionChecker = getOptionChecker();
+ String[] input = new String[] {
+ };
+ String[] expected = new String[0];
+ optionChecker.checkOptions(input, expected);
+
+ input = new String[] { "-target", "1.1", "^target", "1.2" };
+ expected = new String[] { "-target", "1.1" };
+
+ optionChecker.checkOptions(input, expected);
+ }
+ public void testNegDebugCase() {
+ OptionChecker optionChecker = getOptionChecker();
+ String[] input = new String[] { "-target" };
+ String expectedInValuesException = "not enough arguments";
+ String expectedMissedMatchErr = null;
+ String expectedResolveErr = null;
+
+ optionChecker.checkOptionsNegative(
+ input,
+ expectedInValuesException,
+ expectedMissedMatchErr,
+ expectedResolveErr);
+ }
+
+ public void testOptionsPositive() {
+ OptionChecker optionChecker = getOptionChecker();
+ String[] input = new String[] {
+ };
+ String[] expected = new String[0];
+ optionChecker.checkOptions(input, expected);
+
+ input = new String[] { "-verbose" };
+ expected = new String[] { "-verbose" };
+ optionChecker.checkOptions(input, expected);
+
+ input = new String[] { "!verbose" };
+ expected = new String[] { "-verbose" };
+ optionChecker.checkOptions(input, expected);
+
+ input = new String[] { "!verbose", "-verbose" };
+ optionChecker.checkOptions(input, expected);
+
+ input = new String[] { "-verbose", "!verbose" };
+ optionChecker.checkOptions(input, expected);
+
+ input = new String[] { "^verbose" };
+ expected = new String[] {
+ };
+ optionChecker.checkOptions(input, expected);
+
+ input = new String[] { "^verbose", "-verbose" };
+ optionChecker.checkOptions(input, expected);
+
+ input = new String[] { "-verbose", "^verbose" };
+ optionChecker.checkOptions(input, expected);
+
+ input = new String[] { "-verbose", "-debug" };
+ expected = new String[] { "-verbose", "-debug" };
+ optionChecker.checkOptions(input, expected);
+
+ input = new String[] { "!verbose", "!debug" };
+ expected = new String[] { "-verbose", "-debug" };
+ optionChecker.checkOptions(input, expected);
+
+ input = new String[] { "-verbose", "^verbose", "!debug" };
+ expected = new String[] { "-debug" };
+ optionChecker.checkOptions(input, expected);
+
+ input = new String[] { "^verbose", "-verbose", "!debug" };
+ optionChecker.checkOptions(input, expected);
+
+ input = new String[] { "!debug", "^verbose", "-verbose" };
+ optionChecker.checkOptions(input, expected);
+
+ input = new String[] { "-ajc" };
+ expected = new String[] { "-ajc" };
+ optionChecker.checkOptions(input, expected);
+
+ input = new String[] { "-eclipse" };
+ expected = new String[] { "-eclipse" };
+ optionChecker.checkOptions(input, expected);
+
+ input = new String[] { "-eclipse", "-ajc", "!ajc" };
+ expected = new String[] { "-ajc" };
+ optionChecker.checkOptions(input, expected);
+
+ input = new String[] { "-eclipse", "!ajc" };
+ optionChecker.checkOptions(input, expected);
+
+ input = new String[] { "-ajdeCompiler", "^ajc" };
+ expected = new String[] { "-ajdeCompiler" };
+ optionChecker.checkOptions(input, expected);
+
+ input = new String[] { "!ajdeCompiler", "^ajc" };
+ optionChecker.checkOptions(input, expected);
+
+ input =
+ new String[] {
+ "-verbose",
+ "^verbose",
+ "!quiet",
+ "-quiet",
+ "-debug",
+ "^debug" };
+ expected = new String[] { "-quiet" };
+ optionChecker.checkOptions(input, expected);
+
+ input =
+ new String[] {
+ "-verbose",
+ "^debug",
+ "!quiet",
+ "!quiet",
+ "-debug",
+ "^verbose" };
+ expected = new String[] { "-quiet" };
+ optionChecker.checkOptions(input, expected);
+ }
+
+ public void testOptionsNegative() {
+ OptionChecker optionChecker = getOptionChecker();
+ String[] input = new String[] { "-unknown" };
+ String expectedMissedMatchErr = "-unknown";
+ String expectedResolveErr = null;
+ optionChecker.checkOptionsNegative(
+ input,
+ expectedMissedMatchErr,
+ expectedResolveErr);
+
+ input = new String[] { "!verbose", "^verbose" };
+ expectedMissedMatchErr = null;
+ expectedResolveErr = "conflict";
+ optionChecker.checkOptionsNegative(
+ input,
+ expectedMissedMatchErr,
+ expectedResolveErr);
+
+ input = new String[] { "!ajc", "!eclipse" };
+ optionChecker.checkOptionsNegative(
+ input,
+ expectedMissedMatchErr,
+ expectedResolveErr);
+
+ input = new String[] { "-ajc", "-eclipse" };
+ expectedResolveErr = "collision";
+ optionChecker.checkOptionsNegative(
+ input,
+ expectedMissedMatchErr,
+ expectedResolveErr);
+
+ input = new String[] { "-verbose", "-verbose" };
+ expectedResolveErr = null; // duplicates redundant, not colliding
+ optionChecker.checkOptionsNegative(
+ input,
+ expectedMissedMatchErr,
+ expectedResolveErr);
+ }
+
+ public void testMissedMatches() throws InvalidInputException {
+ checkMissedMatches(new int[0], Values.EMPTY);
+ checkMissedMatches(new int[] { 0 },
+ Values.wrapValues(new Option.Value[1])); // null in [0]
+ checkMissedMatches(
+ new int[] { 0, 1, 2 },
+ Values.wrapValues(new Option.Value[] { null, null, null }));
+
+ Option.Factory factory = new Option.Factory("testMissedMatches");
+ Option single = factory.create("verbose");
+ Option multiple =
+ factory
+ .create(
+ "source",
+ "source",
+ Option.STANDARD_PREFIXES,
+ false,
+ new String[][] { new String[] { "1.3", "1.4" }
+ });
+
+ Options options = new Options(false);
+ options.addOption(single);
+ options.addOption(multiple);
+ options.freeze();
+ int[] expectNone = new int[0];
+ String[] input = new String[] { "-verbose" };
+ Values result = options.acceptInput(input);
+ checkMissedMatches(expectNone, result);
+
+ input = new String[] { "-verbose", "-verbose" };
+ result = options.acceptInput(input);
+ checkMissedMatches(expectNone, result);
+
+ input = new String[] { "-source", "1.3" };
+ result = options.acceptInput(input);
+ checkMissedMatches(expectNone, result);
+
+ input = new String[] { "-source", "1.4" };
+ result = options.acceptInput(input);
+ checkMissedMatches(expectNone, result);
+
+ input = new String[] { "-verbose", "-missed" };
+ result = options.acceptInput(input);
+ checkMissedMatches(new int[] { 1 }, result);
+
+ input = new String[] { "-source", "1.4", "-missed" };
+ result = options.acceptInput(input);
+ checkMissedMatches(new int[] { 2 }, result);
+
+ input = new String[] { "-source", "1.4", "-missed", "-verbose" };
+ result = options.acceptInput(input);
+ checkMissedMatches(new int[] { 2 }, result);
+
+ }
+
+ void checkMissedMatches(int[] expected, Values actual) {
+ int[] result = actual.indexMissedMatches();
+ boolean failed = (result.length != expected.length);
+
+ for (int i = 0; !failed && (i < result.length); i++) {
+ failed = (result[i] != expected[i]);
+ }
+ if (failed) {
+ assertTrue(
+ "expected "
+ + Values.IntList.render(expected)
+ + " got "
+ + Values.IntList.render(result)
+ + " for "
+ + actual,
+ false);
+ }
+ }
+
+ public void testComplexOptionsPositive() {
+ OptionChecker optionChecker = getOptionChecker();
+ String[] input = new String[] {
+ };
+ String[] expected = new String[0];
+ optionChecker.checkOptions(input, expected);
+
+ input = new String[] { "-target11" };
+ expected = new String[] { "-target11" };
+ optionChecker.checkOptions(input, expected);
+
+ input = new String[] { "!target12" };
+ expected = new String[] { "-target12" };
+ optionChecker.checkOptions(input, expected);
+
+ input = new String[] { "!target12", "-target11" };
+ optionChecker.checkOptions(input, expected);
+
+ input = new String[] { "!target12", "^target11" };
+ optionChecker.checkOptions(input, expected);
+
+ input = new String[] { "^target12", "^target11" };
+ expected = new String[] {
+ };
+ optionChecker.checkOptions(input, expected);
+
+ input = new String[] { "!1.3" };
+ expected = new String[] { "-1.3" };
+ optionChecker.checkOptions(input, expected);
+
+ input = new String[] { "!1.3", "-1.4" };
+ optionChecker.checkOptions(input, expected);
+
+ input = new String[] { "!1.3", "^1.4" };
+ optionChecker.checkOptions(input, expected);
+
+ input = new String[] { "^1.3", "^1.4" };
+ expected = new String[] {
+ };
+ optionChecker.checkOptions(input, expected);
+
+ }
+
+ public void testMultiArgOptionsPositive() {
+ OptionChecker optionChecker = getOptionChecker();
+ String[] input = new String[] {
+ };
+ String[] expected = new String[0];
+ optionChecker.checkOptions(input, expected);
+
+ input = new String[] { "-target", "1.1" };
+ expected = new String[] { "-target", "1.1" };
+ optionChecker.checkOptions(input, expected);
+
+ input = new String[] { "!target", "1.1" };
+ optionChecker.checkOptions(input, expected);
+
+ input = new String[] { "!target", "1.1", "-target", "1.2" };
+ optionChecker.checkOptions(input, expected);
+
+ input = new String[] { "-target", "1.1", "^target", "1.2" };
+ optionChecker.checkOptions(input, expected);
+
+ input = new String[] { "-source", "1.3" };
+ expected = new String[] { "-source", "1.3" };
+ optionChecker.checkOptions(input, expected);
+
+ input = new String[] { "!source", "1.3", "-source", "1.4" };
+ optionChecker.checkOptions(input, expected);
+
+ input = new String[] { "-source", "1.3", "^source", "1.4" };
+ input =
+ new String[] {
+ "-source",
+ "1.3",
+ "^source",
+ "1.4",
+ "!source",
+ "1.3",
+ "-source",
+ "1.4" };
+ optionChecker.checkOptions(input, expected);
+ }
+
+ public void testMultiArgOptionsNegative() {
+ OptionChecker optionChecker = getOptionChecker();
+ String[] input = new String[] { "-target" };
+ String expectedException = "not enough arguments";
+
+ optionChecker.checkOptionsNegative(
+ input,
+ expectedException,
+ null,
+ null);
+
+ input = new String[] { "-source" };
+ optionChecker.checkOptionsNegative(
+ input,
+ expectedException,
+ null,
+ null);
+
+ input = new String[] { "-source", "1.1" };
+ expectedException = "not permitted";
+ optionChecker.checkOptionsNegative(
+ input,
+ expectedException,
+ null,
+ null);
+
+ input = new String[] { "-target", "1.3" };
+ optionChecker.checkOptionsNegative(
+ input,
+ expectedException,
+ null,
+ null);
+ }
+
+ public void testMultipleInput() {
+ OptionChecker optionChecker = getOptionChecker();
+ String[][] input =
+ new String[][] {
+ new String[] { "-warn:deprecated" },
+ new String[] { "-warn:deprecated,unverified" },
+ new String[] { "-warn:deprecated", "-warn:unusedLocals" },
+ new String[] { "-g" },
+ new String[] { "-g", "-g:none" },
+ new String[] { "-g:vars,source" },
+ new String[] { "-verbose", "-g:vars,source" },
+ };
+ for (int i = 0; i < input.length; i++) {
+ optionChecker.checkOptions(input[i], input[i]);
+ }
+ }
+
+ private OptionChecker getOptionChecker() {
+ if (null == localOptionChecker) {
+ localOptionChecker = new OptionChecker(getOptions());
+ }
+ return localOptionChecker;
+ }
+}
diff --git a/testing/testsrc/org/aspectj/testing/util/options/OptionsTests.java b/testing/testsrc/org/aspectj/testing/util/options/OptionsTests.java
new file mode 100644
index 000000000..2cc937935
--- /dev/null
+++ b/testing/testsrc/org/aspectj/testing/util/options/OptionsTests.java
@@ -0,0 +1,30 @@
+/* *******************************************************************
+ * Copyright (c) 2003 Contributors.
+ * 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:
+ * Wes Isberg initial implementation
+ * ******************************************************************/
+
+
+package org.aspectj.testing.util.options;
+
+import junit.framework.*;
+
+public class OptionsTests extends TestCase {
+
+ public static Test suite() {
+ TestSuite suite = new TestSuite(OptionsTests.class.getName());
+ //$JUnit-BEGIN$
+ suite.addTestSuite(OptionsTest.class);
+ //$JUnit-END$
+ return suite;
+ }
+
+ public OptionsTests(String name) { super(name); }
+
+}
diff --git a/testing/testsrc/org/aspectj/testing/util/options/ValuesTest.java b/testing/testsrc/org/aspectj/testing/util/options/ValuesTest.java
new file mode 100644
index 000000000..cc6623ffc
--- /dev/null
+++ b/testing/testsrc/org/aspectj/testing/util/options/ValuesTest.java
@@ -0,0 +1,69 @@
+/* *******************************************************************
+ * Copyright (c) 2003 Contributors.
+ * 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:
+ * Wes Isberg initial implementation
+ * ******************************************************************/
+
+package org.aspectj.testing.util.options;
+
+import junit.framework.TestCase;
+
+/**
+ */
+public class ValuesTest extends TestCase {
+
+ public ValuesTest(String s) {
+ super(s);
+ }
+ public void testInvert() {
+ checkInvert(new int[0], 0, new int[0]); // no input or missed => none found
+ checkInvert(new int[0], 1, new int[] {0}); // no missed, input 1 => 1 found
+ checkInvert(new int[] {0}, 1, new int[] {}); // 1 (all) missed, input 1 => none found
+ checkInvert(new int[] {}, 1, new int[] {0}); // 0 (none) missed, input 1 => 1 found
+ checkInvert(new int[] {1,2}, 3, new int[] {0}); // 2 missed, input 3 => 1 (first) found
+ checkInvert(new int[] {0,2}, 3, new int[] {1}); // 2 missed, input 3 => 1 (middle) found
+ checkInvert(new int[] {0,1}, 3, new int[] {2}); // 2 missed, input 3 => 1 (last) found
+ checkInvert(new int[] {1,3}, 4, new int[] {0,2}); // 2 missed, input 4 => 2 found
+ checkInvert(new int[] {5,6,7}, 8, new int[] {0,1,2,3,4}); // starting run
+ checkInvert(new int[] {0,1,2,3,4}, 8, new int[] {5,6,7}); // ending run
+ checkInvert(new int[] {0,5,6,7}, 8, new int[] {1,2,3,4}); // middle run
+ checkInvert(new int[] {0,5,6,9},10, new int[] {1,2,3,4,7,8}); // two middle run
+ checkInvert(new int[] {1,2,5,6,9},10, new int[] {0,3,4,7,8}); // start, 2 middle run
+ checkInvert(new int[] {0,1,2,5,6},10, new int[] {3,4,7,8,9}); // middle, end run
+ }
+
+ void checkInvert(int[] missed, int length, int[] expected) {
+ int[] actual = Values.invert(missed, length);
+ assertTrue(null != actual);
+ assertTrue(actual.length == expected.length);
+ for (int i = 0; i < actual.length; i++) {
+ if (expected[i] != actual[i]) {
+ assertTrue("failed at " + i + render(expected, actual), false);
+ }
+ }
+ }
+ static String render(int[] expected, int[] actual) {
+ StringBuffer sb = new StringBuffer();
+ sb.append(" expected ");
+ render(expected, sb);
+ sb.append(" actual ");
+ render(actual, sb);
+ return sb.toString();
+ }
+ static void render(int[] ra, StringBuffer sb) {
+ sb.append("[");
+ for (int i = 0; i < ra.length; i++) {
+ if (i > 0) {
+ sb.append(", ");
+ }
+ sb.append("" + ra[i]);
+ }
+ sb.append("]");
+ }
+}