aboutsummaryrefslogtreecommitdiffstats
path: root/aspectj-attic/testing-src/org/aspectj/testing
diff options
context:
space:
mode:
authorwisberg <wisberg>2002-12-31 18:25:37 +0000
committerwisberg <wisberg>2002-12-31 18:25:37 +0000
commit63d88f163be18c14fccd02cc88b691679eb17e93 (patch)
tree3023d14aea66fec7f3b660218564f4dfec638a66 /aspectj-attic/testing-src/org/aspectj/testing
parent897e1f63b9790c079f20dd66bd0d15f4b840bcb8 (diff)
downloadaspectj-63d88f163be18c14fccd02cc88b691679eb17e93.tar.gz
aspectj-63d88f163be18c14fccd02cc88b691679eb17e93.zip
initial version of unused/attic code for later reference
Diffstat (limited to 'aspectj-attic/testing-src/org/aspectj/testing')
-rw-r--r--aspectj-attic/testing-src/org/aspectj/testing/compare/CompareFiles.java571
-rw-r--r--aspectj-attic/testing-src/org/aspectj/testing/compare/CompareUtil.java143
-rw-r--r--aspectj-attic/testing-src/org/aspectj/testing/compare/GenericTreeNode.java427
-rw-r--r--aspectj-attic/testing-src/org/aspectj/testing/compare/GenericTreeNodeListOrdererFactoryI.java30
-rw-r--r--aspectj-attic/testing-src/org/aspectj/testing/compare/GenericTreeNodeListOrdererI.java44
-rw-r--r--aspectj-attic/testing-src/org/aspectj/testing/compare/GenericTreeNodesVisitorI.java31
-rw-r--r--aspectj-attic/testing-src/org/aspectj/testing/compare/Regexp.java40
-rw-r--r--aspectj-attic/testing-src/org/aspectj/testing/compare/RegexpFactory.java64
-rw-r--r--aspectj-attic/testing-src/org/aspectj/testing/compare/RegexpFilter.java622
-rw-r--r--aspectj-attic/testing-src/org/aspectj/testing/compare/RegexpFilterReader.java291
-rw-r--r--aspectj-attic/testing-src/org/aspectj/testing/compare/TreeCompare.java217
-rw-r--r--aspectj-attic/testing-src/org/aspectj/testing/compare/adapters/GenericTreeNodeFactoryI.java33
-rw-r--r--aspectj-attic/testing-src/org/aspectj/testing/compare/adapters/JTreeNodeGenericTreeNodeFactory.java102
-rw-r--r--aspectj-attic/testing-src/org/aspectj/testing/compare/adapters/Structure.java438
-rw-r--r--aspectj-attic/testing-src/org/aspectj/testing/compare/adapters/StructureGenericTreeNodeFactory.java308
-rw-r--r--aspectj-attic/testing-src/org/aspectj/testing/compare/adapters/SubTypeComparator.java224
-rw-r--r--aspectj-attic/testing-src/org/aspectj/testing/compare/adapters/package.html50
-rw-r--r--aspectj-attic/testing-src/org/aspectj/testing/compare/package.html128
-rw-r--r--aspectj-attic/testing-src/org/aspectj/testing/taskdefs/CompareFiles.java103
19 files changed, 3866 insertions, 0 deletions
diff --git a/aspectj-attic/testing-src/org/aspectj/testing/compare/CompareFiles.java b/aspectj-attic/testing-src/org/aspectj/testing/compare/CompareFiles.java
new file mode 100644
index 000000000..2d16c9e6b
--- /dev/null
+++ b/aspectj-attic/testing-src/org/aspectj/testing/compare/CompareFiles.java
@@ -0,0 +1,571 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 2002 Palo Alto Research Center, Incorporated (PARC).
+ * 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:
+ * Xerox/PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.testing.compare;
+
+import org.aspectj.util.LangUtil;
+
+import jdiff.util.Diff;
+import jdiff.text.FileLine;
+import jdiff.util.DiffNormalOutput;
+
+import java.util.*;
+import java.util.zip.*;
+import java.io.*;
+
+/**
+ * Compare two files and emit differences.
+ * Requires the jdiff library in jdiff/jdiff.jar
+ */
+public class CompareFiles {
+ protected static String[] NO_STRINGS = new String[]{};
+ /** standard rendering of null references */
+ public static final String NULL = "null";
+ /** filter for the both files */
+ protected RegexpFilter filter;
+ /** ignore case by converting lines to upper case */
+ protected boolean ignoreCase = false;
+ /** collapse internal whitespace by converting to space character */
+ protected boolean collapseWhitespace = true;
+ /** trim leading and trailing whitespace from lines before comparison */
+ protected boolean trimWhitespace = false;
+ /** output to this File - if not set, System.out */
+ protected File output = null;
+
+ /**
+ * Compare two files by lines, emitting output to System.out as a series of edits.
+ * @param args the String[] containing two files to diff plus any number of
+ * <li>-i "ignore": ignore case</li>
+ * <li>-t "trim" : ignore leading and trailing white space</li>
+ * <li>-b "blanks": ignore differences in all white space</li>
+ * @param lhs the File on the left-hand-side of the comparison
+ * @param rhs the File on the left-hand-side of the comparison
+ * @throws IllegalArgumentException if cannot read both files
+ */
+ public static void main(String[] args) {
+ new CompareFiles().comparefiles(args);
+ }
+
+ /**
+ * Write results of a diff to some output Writer
+ * @param result the DiffResult containing the results of the diff
+ * @param output the Writer to output results to - if null,
+ * defaults to System.out, but will be closed if not null
+ * @throws IllegalArgumentException if null == result or output
+ */
+ public static void writeDiffResult(DiffResult result, File output)
+ throws IOException {
+ if (null == result) throw new IllegalArgumentException("null result");
+ Writer writer = (null != output ? new FileWriter(output)
+ : new OutputStreamWriter(System.out));
+ DiffNormalOutput out = new DiffNormalOutput(result.lhsLines, result.rhsLines);
+ out.setOut(writer);
+ out.setLineSeparator(LangUtil.EOL);
+ try {
+ out.writeScript(result.edits);
+ } finally {
+ if (null != output) {
+ try { writer.close(); }
+ catch (IOException e) {
+ e.printStackTrace(System.err);
+ }
+ }
+ }
+ } // writeDiffResult
+
+ /**
+ * descend filesystem tree, invoking FileRunnerI.accept() on files.
+ * E.g., To list files from current directory:
+ * <code><pre>descendFileTree(new File("."), new FileRunnerI() {
+ * public boolean accept(File f){
+ * System.out.println(f.getAbsolutePath());
+ * return true;
+ * }});</code></pre>
+ * @param file root/starting point. If a file, the only one visited.
+ * @param filter supplies accept(File) routine
+ */
+ public static void descendFileTree(File file, FileFilter filter) {
+ descendFileTree(file, filter, false);
+ }
+
+ /**
+ * Descend filesystem tree, invoking FileFilter.accept() on files
+ * and, if userRecursion, on dirs. If userRecursion, accept() must
+ * call descendFileTree() again to recurse down directories.
+ * This calls fileFilter.accept(File) on all files before doing any dirs.
+ * E.g., To list only files from Unix root:
+ * <code><pre>descendFileTree(new File("/"), new FileFilter() {
+ * public boolean run(File f){
+ * System.out.println(f.getAbsolutePath());
+ * return true;
+ * }}, false);</code></pre>
+ * To list files/dir from root using user recursion:
+ * <code><pre>descendFileTree(new File("/"), new FileFilter() {
+ * public boolean run(File f){
+ * System.out.println(f.getAbsolutePath());
+ * if (f.isDirectory() && (-1 == f.getName().indexOf("CVS")))
+ * return descendFileTree(f, this, true);
+ * return true;
+ * }}, true);</code></pre>
+ * @param file root/starting point. If a file, the only one visited.
+ * @param filter supplies boolean accept(File) method
+ * @param userRecursion - if true, do accept() on dirs; else, recurse
+ * @return false if any fileFilter.accept(File) did.
+ * @throws IllegalArgumentException if file or fileFilter is null
+ */
+ public static boolean descendFileTree(File file, FileFilter fileFilter,
+ boolean userRecursion) {
+ if (null == file) {throw new IllegalArgumentException("parm File"); }
+ if (null == fileFilter){throw new IllegalArgumentException("parm FileFilter");}
+
+ if (!file.isDirectory()) {
+ return fileFilter.accept(file);
+ } else if (file.canRead()) {
+ // go through files first
+ File[] files = file.listFiles(ValidFileFilter.FILE_EXISTS);
+ if (null != files) {
+ for (int i = 0; i < files.length; i++) {
+ if (!fileFilter.accept(files[i])) {
+ return false;
+ }
+ }
+ }
+ // now recurse to handle directories
+ File[] dirs = file.listFiles(ValidFileFilter.DIR_EXISTS);
+ if (null != dirs) {
+ for (int i = 0; i < dirs.length; i++) {
+ if (userRecursion) {
+ if (!fileFilter.accept(dirs[i])) {
+ return false;
+ }
+ } else {
+ if (!descendFileTree(dirs[i], fileFilter,userRecursion)) {
+ return false;
+ }
+ }
+ }
+ }
+ } // readable directory (ignore unreadable ones)
+ return true;
+ } // descendFiles
+
+ /**
+ * Render a zip/entry combination to String
+ */
+ private static String renderZipEntry(File zipfile, ZipEntry entry) {
+ String filename = (null == zipfile ? "null File" : zipfile.getName());
+ String entryname = (null == entry ? "null ZipEntry" : entry.getName());
+ //return filename + "!" + entryname;
+ return "" + entryname;
+ }
+
+ /**
+ * Initialise the filter. Users must do this before the filter is
+ * lazily constructed or must set update to true.
+ * @param args the String with any args valid for RegexpFilter.init(String, RegexpFilter)
+ * @param update if true, use existing filter settings unless
+ * overwritten by the new ones;
+ * if false, create a new filter using args.
+ * @throws IllegalArgumentException if cannot read both files
+ * @see RegexpFilter#init(String, RegexpFilter)
+ */
+ public void initFilter(String arg, boolean update) {
+ filter = RegexpFilter.init(arg, update ? filter : null);
+ }
+
+ /**
+ * Initialise the filter. Users must do this before the filter is
+ * lazily constructed or must set update to true.
+ * @param args the String[] with any args valid for RegexpFilter
+ * @param update if true, use existing filter settings unless
+ * overwritten by the new ones;
+ * if false, create a new filter using args.
+ * @throws IllegalArgumentException if cannot read both files
+ * @see RegexpFilter#init(String[], RegexpFilter)
+ */
+ public void initFilter(String[] args, boolean update) {
+ filter = RegexpFilter.init(args, update ? filter : null);
+ }
+
+ /**
+ * Compare two files by lines, emitting output to System.out as a series of edits.
+ * @param args the String[] containing two files to diff
+ * (lhs, rhs) plus any args valid for RegexpFilter
+ * @throws IllegalArgumentException if cannot read both files
+ */
+ public final void comparefiles(String[] args) {
+ if (errMessage(null == args, "null args", null)) return;
+ if (errMessage(args.length < 2, "need more args", null)) return;
+ File lhs = new File(args[0]);
+ File rhs = new File(args[1]);
+ if (errMessage(!lhs.canRead(), "!lhs.canRead()", null)) return;
+ if (errMessage(!rhs.canRead(), "!rhs.canRead()", null)) return;
+ int filterArgsLength = args.length - 2;
+ if (0 >= filterArgsLength) {
+ initFilter(NO_STRINGS, false);
+ } else {
+ String[] filterArgs = new String[filterArgsLength];
+ System.arraycopy(args, 0, filterArgs, 0, filterArgsLength);
+ initFilter(filterArgs, false);
+ }
+
+ try {
+ if (errMessage(!diff(lhs, rhs), "diff(lhs,rhs)",null)) return;
+ } catch (IOException t) {
+ if (errMessage(false, null, t)) return;
+ }
+ } // main
+
+ /**
+ * Compare two files/dirs, emitting output as a series of edits.
+ * If both files are directories, then this compares their contents
+ * (including the contents of any zip or jar files) as a series of paths
+ * (i.e., it will recognize added or removed or changed filenames, but
+ * not files whose contents have changed).
+ * Output will go to the File specifies as "output" or System.out if none specified.
+ * This is costly, creating an in-memory copy, one String per line, of both files.
+ * @param lhs the File/dir on the left-hand-side of the comparison
+ * @param rhs the File/dir on the left-hand-side of the comparison
+ * @throws IllegalArgumentException if either parm is null or not existing,
+ * or if one is a dir and the other a file
+ * @throws IOException if getFileLines or diff utilities do
+ * @return false if there was some error
+ */
+ public final boolean diff(File lhs, File rhs) throws IOException {
+ DiffResult result = null;
+ String err = null;
+ if ((null == lhs) || (null == rhs)
+ || (!lhs.exists()) || (!rhs.exists())
+ || (!lhs.canRead()) || (!rhs.canRead())
+ || (lhs.isDirectory() != rhs.isDirectory())) {
+ err = "need 2 readable files or dirs or zip files - got lhs=" + lhs + " rhs=" + rhs;
+ } else if (lhs.isDirectory()) {
+ result = diffDirUtil(lhs, rhs);
+ } else {
+ boolean lhsIsZip = isZipFile(lhs);
+ if (lhsIsZip != isZipFile(rhs)) {
+ err = "need 2 readable files or dirs or zip files - got lhs=" + lhs + " rhs=" + rhs;
+ } else if (lhsIsZip) {
+ result = diffDirUtil(lhs, rhs);
+ } else {
+ result = diffUtil(lhs, rhs);
+ }
+ }
+ if (null != err) throw new IllegalArgumentException(err);
+ if (errMessage(null == result, null, null)) return false;
+ writeDiffResult(result, output);
+ return true;
+ }
+
+ /**
+ * Compare two files, returning results for further evaluation or processing
+ * @param lhs the File on the left-hand-side of the comparison
+ * @param rhs the File on the left-hand-side of the comparison
+ * @throws IllegalArgumentException if either parm is null
+ * @throws IOException if getFileLines or diff utilities do
+ * @return false if there was some error
+ */
+ public final DiffResult diffUtil(File lhs, File rhs)
+ throws IOException {
+ if (errMessage(null == lhs, "null lhs", null)) return null;
+ if (errMessage(null == rhs, "null rhs", null)) return null;
+ FileLine[] lhsLines = getFileLines(lhs);
+ FileLine[] rhsLines = getFileLines(rhs);
+ Diff.change edits = new Diff(lhsLines, rhsLines).diff_2(false);
+ return new DiffResult(lhsLines, rhsLines, edits);
+ }
+
+ /**
+ * Read all lines of a file into a String[] (not very efficient),
+ * implementing flag policies.
+ * @param file the File to read
+ * @return a FileLine[] with elements for each line in the file
+ */
+ public FileLine[] getFileLines(File file) throws IOException {
+ if (file.isDirectory()) return getFileLinesForDir(file);
+ final Vector results = new Vector();
+
+ BufferedReader in = null;
+ try {
+ in = getReader(file);
+ String line;
+ while (null != (line = in.readLine())) {
+ results.add(toFileLine(line));
+ }
+ } finally {
+ if (null != in) { in.close(); }
+ }
+ final FileLine[] lines = new FileLine[results.size()];
+ results.copyInto(lines);
+ return lines;
+ }
+
+ /**
+ * Compare two directories or zip files by listing contents (including contents of zip/jar files)
+ * and differencing the results. This does NOT call diff on each file, but only
+ * recognizes when files or zip entries have been added or removed.
+ * @param lhsDir the File for an existing, readable directory (as left-hand-side)
+ * @param rhsDir the File for an existing, readable directory (as right-hand-side)
+ * @throws IllegalArgumentException if null == lhs or rhsDir
+ */
+ public DiffResult diffDirUtil(File lhsDir, File rhsDir) {
+ FileLine[] lhsLines = getFileLinesForDir(lhsDir);
+ FileLine[] rhsLines = getFileLinesForDir(rhsDir);
+ // now do the comparison as if they were two files
+ Diff.change edits = new Diff(lhsLines, rhsLines).diff_2(false);
+ return new DiffResult(lhsLines, rhsLines, edits);
+ }
+
+ /**
+ * Render all sub-elements of a directory as a list of FileLine[], including entries
+ * in zip and jar files. The directory prefix is not included in the FileLine.
+ * @param dir the File representing the directory to list
+ * @throws IllegalArgumentException if null == dir or !dir.isDirectory()
+ */
+ public FileLine[] getFileLinesForDir(File dir) {
+ if (null == dir) throw new IllegalArgumentException("null dir");
+ if (!dir.isDirectory() && ! isZipFile(dir)) throw new IllegalArgumentException("not a dir: " + dir);
+ Collection items = directoryToString(dir, null);
+ return toFileLine(items, dir.getPath(), true);
+ }
+
+ /** @return true if test or if null != error */
+ protected boolean errMessage(boolean test, String message, Throwable error) {
+ if (test && (null != message)) { System.err.println(message); }
+ if (null != error) { error.printStackTrace(System.err); }
+ return (test || (null != error));
+ }
+
+ /**
+ * Convert current setting into an initialization list for filter
+ */
+ protected String[] getFilterArgs() {
+ return new String[]
+ { (trimWhitespace ? "-t" : "-T")
+ , (collapseWhitespace ? "-b" : "-B")
+ , (ignoreCase ? "-i" : "-I")
+ };
+ }
+
+ /**
+ * Lazy construction of filter
+ */
+ protected RegexpFilter getFilter() {
+ if (null == filter) {
+ filter = RegexpFilter.init(getFilterArgs(), null);
+ }
+ return filter;
+ }
+
+ /**
+ * Factory for reader used by getFileLines(File).
+ * Default implementation creates a BufferedReader.
+ * Subclasses may implement pre-processing filters here.
+ */
+ protected BufferedReader getReader(File file) throws IOException {
+ return new BufferedReader(new FileReader(file));
+ }
+
+ /**
+ * Create a FileLine from the input string,
+ * applying policies for whitespace, etc.
+ * @param string the String to wrap as a FileLine
+ * @return FileLine with string as text and
+ * canonical as string modified by any canonicalizing policies.
+ */
+ protected FileLine toFileLine(String string) {
+ String canonical = getFilter().process(string);
+ return new FileLine(string, canonical);
+ }
+
+
+ protected boolean isZipFile(File f) {
+ String s = null;
+ if ((null == f) || (null == (s = f.getPath()))) {
+ return false;
+ } else {
+ return (f.exists() && !f.isDirectory() && (s.endsWith(".jar")));
+ }
+ }
+
+ /**
+ * Convert to an array of FileLine by optionally removing prefix and/or sorting
+ * @param collection the Collection of String to process
+ */
+ protected FileLine[] toFileLine(Collection collection, String ignorePrefix, boolean sort) {
+ if (null == collection) throw new IllegalArgumentException("null collection");
+ List list = new ArrayList();
+ list.addAll(collection);
+ if (null != ignorePrefix) {
+ for (int i = 0; i < list.size(); i++) {
+ String next = list.get(i).toString();
+ if (next.startsWith(ignorePrefix)) {
+ list.set(i, next.substring(ignorePrefix.length()));
+ }
+ }
+ }
+ if (sort) {
+ Collections.sort(list);
+ }
+ FileLine[] result = new FileLine[list.size()];
+ int i = 0;
+ for (Iterator it = list.iterator(); it.hasNext();) {
+ result[i++] = toFileLine(it.next().toString());
+ }
+ if (i < result.length) {
+ throw new Error("list lost elements? " + (result.length-i));
+ }
+ return result;
+ }
+
+ /**
+ * Return the names of all files below a directory.
+ * If file is a directory, then all files under the directory
+ * are returned. If file is absolute or relative, all the files are.
+ * If file is a zip or jar file, then all entries in the zip or jar
+ * are listed. Entries inside those jarfiles/zipfiles are not listed.
+ * There are no guarantees about ordering.
+ * @param dir the File to list for
+ * @param results the Collection to use for the results (may be null)
+ * @throws IllegalArgumentException if null == dir
+ * @return a Collection of String of paths, including paths inside jars
+ */
+ protected Collection directoryToString(File dir, Collection results) {
+ if (null == dir) throw new IllegalArgumentException("null dir");
+ final Collection result = (results != null? results : new Vector());
+ if (isZipFile(dir)) {
+ zipFileToString(dir, result);
+ } else if (!dir.isDirectory()) {
+ throw new IllegalArgumentException("not a dir: " + dir);
+ } else {
+ AccumulatingFileFilter acFilter = new AccumulatingFileFilter() {
+ public boolean accumulate(File file) {
+ String name = file.getPath();
+ result.add(name);
+ if (isZipFile(file)) {
+ zipFileToString(file, result);
+ }
+ return true;
+ }
+ };
+ descendFileTree(dir, acFilter, false);
+ }
+ return result;
+ } // directoryToString
+
+ /**
+ * Render as String the entries in a zip or jar file,
+ * converting each to String beforehand (as jarpath!jarentry)
+ * applying policies for whitespace, etc.
+ * @param file the File to enumerate ZipEntry for
+ * @param results the Colection to use to return the FileLine - may be null
+ * @return FileLines with string as text and
+ * canonical as string modified by any canonicalizing policies.
+ */
+ protected Collection zipFileToString(final File zipfile, Collection results) {
+ Collection result = (results != null ? results : new Vector());
+ ZipFile zip = null;
+ try {
+ //ZipFile.OPEN_READ | ZipFile.OPEN_DELETE); delete is 1.3 only
+ zip = new ZipFile(zipfile);
+ Enumeration enum = zip.entries();
+ // now emitting filename only once, so entries match even if filename does not
+ results.add("ZipFileName: " + zipfile);
+ while (enum.hasMoreElements()) {
+ results.add(renderZipEntry(zipfile, (ZipEntry) enum.nextElement()));
+ }
+ zip.close();
+ zip = null;
+ } catch (Throwable t) {
+ String err = "Error opening " + zipfile + " attempting to continue...";
+ System.err.println(err);
+ t.printStackTrace(System.err);
+ } finally {
+ if (null != zip) {
+ try { zip.close(); }
+ catch (IOException e) {
+ e.printStackTrace(System.err);
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * return structure for diffUtil
+ */
+ public final class DiffResult {
+ public final FileLine[] lhsLines;
+ public final FileLine[] rhsLines;
+ public final Diff.change edits;
+ public DiffResult (FileLine[] lhsLines,
+ FileLine[] rhsLines,
+ Diff.change edits) {
+ this.lhsLines = lhsLines;
+ this.rhsLines = rhsLines;
+ this.edits = edits;
+ }
+ }
+
+} // class CompareFiles
+
+class ValidFileFilter implements FileFilter {
+ public static final FileFilter EXIST = new ValidFileFilter();
+ public static final FileFilter FILE_EXISTS = new FilesOnlyFilter();
+ public static final FileFilter DIR_EXISTS = new DirsOnlyFilter();
+ protected ValidFileFilter(){}
+ public boolean accept(File f) {
+ return ((null != f) && (f.exists()));
+ }
+ static class FilesOnlyFilter extends ValidFileFilter {
+ public final boolean accept(File f) {
+ return (super.accept(f) && (!f.isDirectory()));
+ }
+ }
+ static class DirsOnlyFilter extends ValidFileFilter {
+ public final boolean accept(File f) {
+ return (super.accept(f) && (f.isDirectory()));
+ }
+ }
+}
+
+/**
+ * A FileFilter that accumulates the results when called if they exist.
+ * Subclasses override accumulate to determine whether it should be
+ * accumulated.
+ */
+class AccumulatingFileFilter extends ValidFileFilter {
+ Vector files = new Vector();
+ public final boolean accept(File f) {
+ if (super.accept(f) && (accumulate(f))) {
+ files.add(f);
+ }
+ return true;
+ }
+
+ /**
+ * This implementation accumulates everything.
+ * Subclasses should override to implement filter
+ * @param file a File guaranteed to exist
+ * @return true if file should be accumulated.
+ */
+ public boolean accumulate(File f) {
+ return true;
+ }
+ /**
+ * @return list of files currently accumulated
+ */
+ public File[] getFiles() {
+ return (File[]) files.toArray(new File[0]);
+ }
+}
diff --git a/aspectj-attic/testing-src/org/aspectj/testing/compare/CompareUtil.java b/aspectj-attic/testing-src/org/aspectj/testing/compare/CompareUtil.java
new file mode 100644
index 000000000..8358a177d
--- /dev/null
+++ b/aspectj-attic/testing-src/org/aspectj/testing/compare/CompareUtil.java
@@ -0,0 +1,143 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 2002 Palo Alto Research Center, Incorporated (PARC).
+ * 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:
+ * Xerox/PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.testing.compare;
+
+import java.util.Iterator;
+import java.util.Collection;
+import java.util.List;
+
+/** Minor methods for short-circuiting comparisons */
+public class CompareUtil {
+ /**
+ * Callers may abort equality checks with false
+ * if this passes its misc short-circuit semantics.
+ * A false result does not mean the arguments
+ * are equal, but a true result does mean they are not equal.
+ * <pre>if (notSame(foo,bar,true)) then return false;</pre>
+ * @param lhs the Object on the left-hand-side to compare
+ * @param rhs the Object on the right-hand-side to compare
+ * @param considerType if true, then also return true if the
+ * right-hand-side cannot be assigned to the left-hand-side
+ * @return true if lhs and rhs are not the same per considerType.
+ */
+ public static boolean notSame(Object lhs, Object rhs, boolean considerType) {
+ if (null == lhs) {
+ return (!(null == rhs));
+ } else if (null == rhs) {
+ return true;
+ } else if (lhs== rhs) {
+ return false; // known to be same
+ } else if (considerType) {
+ Class lhClass = lhs.getClass();
+ Class rhClass = rhs.getClass();
+ if (!lhClass.isAssignableFrom(rhClass)) {
+ return true;
+ }
+ }
+ return false; // unknown whether equal or not
+ }
+
+ /**
+ * Return null/equal comparison:
+ * <li>null considered to be lesser</li>
+ * <li>reference or Object.equals() considered to be 0</li>
+ * <li>return Integer.MAX_VALUE for all other cases</li>
+ * <table>
+ * <tr><td>result</td><td>input</td></tr>
+ * <tr><td>-1</td><td>null &lt; rhs</td></tr>
+ * <tr><td>1</td><td>lhs &gt; null</td></tr>
+ * <tr><td>0</td><td>null == null</td></tr>
+ * <tr><td>0</td><td>lhs == rhs</td></tr>
+ * <tr><td>0</td><td>lhs.equals(rhs)</td></tr>
+ * <tr><td>Integer.MAX_VALUE</td><td>{all other cases}</td></tr>
+ * </table>
+ * @see Comparator
+ * @return Integer.MAX_VALUE if uncertain, value otherwise
+ */
+ public static int compare(Object lhs, Object rhs) {
+ if (null == lhs) {
+ return (null == rhs ? 0 : -1);
+ } else if (null == rhs) {
+ return 1;
+ } else if (lhs == rhs) {
+ return 0; // known to be same
+ } else {
+ return Integer.MAX_VALUE;
+ }
+ }
+
+ /**
+ * Return boolean comparison where true > false.
+ * (Comparable not defined for Boolean)
+ * @see Comparator
+ */
+ public static int compare(boolean lhs, boolean rhs) {
+ return (lhs == rhs ? 0 : (lhs ? 1 : -1));
+ }
+
+ /**
+ * Return String comparison based on {@link compare(Object,Object)}
+ * and {@link String.compareTo(String)}.
+ * @see Comparator
+ */
+ public static int compare(String lhs, String rhs) {
+ int result = compare((Object) lhs, (Object) rhs);
+ if (Integer.MAX_VALUE == result) {
+ result = lhs.compareTo(rhs);
+ }
+ return result;
+ }
+
+ /**
+ * Compare two Collections by reference to a standard List.
+ * The first Collection to not contain a standard element
+ * when the other does loses. Order is ignored.
+ * The left-hand-side acts as the standard if the standard is null.
+ * @param lhs the List from the left-hand-side
+ * @param rhs the Collection from the right-hand-side
+ * @param standard the List to act as the standard (if null, use lhs)
+ * @param return -1 if lhs is null and rhs is not, 1 if reverse;
+ * 0 if both have all elements in standard,
+ * 1 if lhs has a standard element rhs does not, -1 if reverse
+ * (testing in standard order)
+ */
+ public static int compare(List lhs, Collection rhs, List standard) {
+ int result = compare(lhs, rhs);
+ if (result == Integer.MAX_VALUE) {
+ if (null == standard) {
+ result = compare(lhs, rhs, lhs); // use lhs as standard
+ } else {
+ boolean leftHasThem = lhs.containsAll(standard);
+ boolean rightHasThem = rhs.containsAll(standard);
+ if (leftHasThem != rightHasThem) {
+ result = (leftHasThem ? 1 : -1);
+ } else if (leftHasThem) {
+ result = 0; // they both have them
+ } else { // first to not have an element loses
+ Iterator standardIterator = standard.iterator();
+ while (standardIterator.hasNext()) {
+ Object standardObject = standardIterator.next();
+ boolean leftHasIt = lhs.contains(standardObject);
+ boolean rightHasIt = rhs.contains(standardObject);
+ if (leftHasIt != rightHasIt) {
+ result = (leftHasIt ? 1 : -1);
+ break;
+ }
+ }
+ }
+ }
+ }
+ return result;
+ }
+} // class Util
diff --git a/aspectj-attic/testing-src/org/aspectj/testing/compare/GenericTreeNode.java b/aspectj-attic/testing-src/org/aspectj/testing/compare/GenericTreeNode.java
new file mode 100644
index 000000000..cdb0b70da
--- /dev/null
+++ b/aspectj-attic/testing-src/org/aspectj/testing/compare/GenericTreeNode.java
@@ -0,0 +1,427 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 2002 Palo Alto Research Center, Incorporated (PARC).
+ * 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:
+ * Xerox/PARC initial implementation
+ * ******************************************************************/
+
+
+package org.aspectj.testing.compare;
+
+import java.util.*;
+
+
+/**
+ * Generic tree and pairwise traversal over it
+ * for comparison purposes.
+ * Implement a generic tree by delegation and
+ * a traversal method for comparing two trees.
+ * Guarantees after initialization:
+ * <li>nodeComparator is not null</li>
+ * <li>node is not null</li>
+ * <li>children, if any, are assignable to childClass
+ * (only as of initialization, since list is adopted)</li>
+ * <li>Obeys GenericTreeNode contract, especially regarding equals</li>
+ * <p>It will throw Error if used before initialization completes.
+ */
+public class GenericTreeNode implements Comparable {
+ /** underlying node - never null */
+ Object node;
+ /** node children - type-safe if present */
+ List children;
+ /** node parent - may be null if this is tree root */
+ GenericTreeNode parent;
+ /** used to compare underlying node */
+ Comparator nodeComparator;
+ /** Class used to verify children - may be null */
+ Class childClass;
+
+ /** Track whether we are initialized */
+ boolean ready;
+ /** cache for heavy toString() */
+ String toStringCache;
+
+ // --------------------------------------- static
+ /** Singleton visitor to match trees exactly, stopping at first failure */
+ public static final GenericTreeNodesVisitorI EXACT = new MatchExact();
+
+ /** Singleton visitor to print non-matching nodes to System.err */
+ public static final GenericTreeNodesVisitorI PRINTERR = new PrintNonMatches();
+
+ /** Singleton visitor to print all nodes to System.err */
+ public static final GenericTreeNodesVisitorI PRINTALL = new PrintAllPairs();
+
+
+ /** Singleton comparator for all of us */
+ public static final Comparator COMPARATOR = new gtnComparator();
+
+ /**
+ * Visit two generic trees in order.
+ * Visit the parents, and recursively visit the children.
+ * The children are visited in an order determined by
+ * (any) ordering factory invoked to produce an ordered pair
+ * of children lists for visiting.
+ * All children are visited, even if not paired.
+ * When one list of children is smaller, the
+ * remainder are visited with null complements.
+ * This is true for parents as well; this will visit
+ * all the children of a parent even when the
+ * other parent is null.
+ * This will return false without further visits
+ * as soon as the visitor returns false. That means
+ * the visitor can decide to stop visiting when null
+ * nodes (parent or children) are encountered).
+ * This will return true only after the tree was
+ * visited without objection from the visitor.
+ * <p>A simple example of using this to determine if
+ * two trees are strictly equal is this:
+ * @return false if the visitor returned false for any visit;
+ * true otherwise.
+ * @throws Error if any children are not GenericTreeNode
+ * @throws IllegalArgumentException if the visitor or both parents are null
+ */
+
+ public static boolean traverse(GenericTreeNode lhsParent
+ , GenericTreeNode rhsParent
+ , GenericTreeNodeListOrdererFactoryI childrenPrepFactory
+ , GenericTreeNodesVisitorI visitor) {
+ if (null == visitor) {
+ throw new IllegalArgumentException("null visitor");
+ }
+ if ((null == lhsParent) && (null == rhsParent)) {
+ throw new IllegalArgumentException("null parents");
+ }
+ if (visitor.visit(lhsParent, rhsParent)) {
+ List lhsList = (null == lhsParent ? null : lhsParent.getChildren());
+ List rhsList = (null == rhsParent ? null : rhsParent.getChildren());
+ if (null != childrenPrepFactory) {
+ GenericTreeNodeListOrdererI factory =
+ childrenPrepFactory.produce(lhsParent, rhsParent, visitor);
+ if (null != factory) {
+ List[] prepKids = factory.produceLists(lhsList, rhsList);
+ if (null != prepKids) {
+ lhsList = prepKids[0];
+ rhsList = prepKids[1];
+ }
+ }
+
+ }
+ ListIterator lhsIterator = (null == lhsList ? null : lhsList.listIterator());
+ ListIterator rhsIterator = (null == rhsList ? null : rhsList.listIterator());
+ Object lhs = null;
+ Object rhs = null;
+ while (true) {
+ lhs = null;
+ rhs = null;
+ // get the child pair
+ if ((null != lhsIterator) && (lhsIterator.hasNext())) {
+ lhs = lhsIterator.next();
+ }
+ if ((null != rhsIterator) && (rhsIterator.hasNext())) {
+ rhs = rhsIterator.next();
+ }
+ if ((null == rhs) && (null == lhs)) {
+ break;
+ }
+ if ((null != lhs) && (!(lhs instanceof GenericTreeNode))) {
+ throw new Error("GenericTreeNode expected, got lhs " + lhs);
+ }
+ if ((null != rhs) && (!(rhs instanceof GenericTreeNode))) {
+ throw new Error("GenericTreeNode expected, got rhs " + rhs);
+ }
+ // traverse the child pair
+ if (!traverse((GenericTreeNode) lhs, (GenericTreeNode) rhs,
+ childrenPrepFactory, visitor)) {
+ return false;
+ }
+ }
+ }
+ return true; // see also other return statements above
+ } // traverse
+
+ // --------------------------------------- constructors
+ public GenericTreeNode() {
+ //ready = false;
+ }
+
+ public void init(GenericTreeNode parent, Comparator nodeComparator,
+ Object node, List children, Class childClass) {
+ if (ready) ready = false; // weak sync
+ if (null == node) {
+ throw new IllegalArgumentException("null node");
+ }
+ if (null == nodeComparator) {
+ throw new IllegalArgumentException("null nodeComparator");
+ }
+ this.nodeComparator = nodeComparator;
+ this.node = node;
+ this.children = children;
+ this.parent = parent;
+ if (null != childClass) {
+ ListIterator iter = children.listIterator();
+ while (iter.hasNext()) {
+ Object kid = iter.next();
+ if (!(childClass.isAssignableFrom(kid.getClass()))) {
+ String err = "child " + kid + " is not " + childClass;
+ throw new IllegalArgumentException(err);
+ }
+ }
+ this.childClass = childClass;
+ }
+ ready = true;
+ }
+
+ //-------------------- Object interface
+ /**
+ * ambiguous: equal if
+ * <li>this is the input, or </li>
+ * <li>the input is a GenericTreeNode, and </li>
+ * <li>the underlying nodes are equal(), or</li
+ * <li>the underlying nodes have equal comparators
+ * which return 0 from compare(...)</li>
+ * @param input the Object to compare with
+ * @return true if this equals input
+ */
+ public boolean equals(Object input) {
+ if (input == this) {
+ return true;
+ } else if (!(input instanceof GenericTreeNode)) {
+ return false;
+ } else {
+ GenericTreeNode in = (GenericTreeNode) input;
+ if (node.equals(in.getNode())) { // assumes nodes are unique, not flyweights?
+ return true;
+ } else {
+ Comparator inComp = in.getNodeComparator();
+ if ((this == nodeComparator)
+ || (this == inComp)
+ || (nodeComparator == inComp)
+ || (nodeComparator.equals(inComp))) {
+ return (0 == nodeComparator.compare(this, in));
+ } else {
+ return false;
+ }
+ }
+ }
+ }
+
+ /**
+ * Delegate to the underlying node object
+ * @return the hashcode of the underlying node object
+ */
+ public int hashCode() { // todo: probably not correct to delegate to node
+ return node.hashCode();
+ }
+
+ /** toString delegates to longString() */
+ public String toString() {
+ if (null == toStringCache) {
+ toStringCache = longString();
+ }
+ return toStringCache;
+ }
+
+ /**
+ * short rendition delegates to thisString,
+ * prefixing by one tab per parent
+ */
+ public String shortString() {
+ StringBuffer sb = new StringBuffer();
+ // add a tab for each parent
+ GenericTreeNode par = parent;
+ while (null != par) {
+ sb.append("\t");
+ par = par.getParent();
+ }
+ sb.append(thisString());
+ return sb.toString();
+ }
+
+ /**
+ * long rendition delegates to parentString, thisString,
+ * and childString as follows:
+ * <pre>GenericTreeNode [parent={parentString()] [children={size}] [Node={thisString()]</pre>
+ */
+ public String longString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append("GenericTreeNode ");
+ sb.append("[parent=");
+ sb.append(parentString());
+ sb.append("] [children=");
+ if (null == children) {
+ sb.append("0");
+ } else {
+ sb.append("" + children.size());
+ }
+ sb.append("] [Node=");
+ sb.append(thisString());
+ sb.append("]");
+ return sb.toString();
+ }
+
+ /** render this as "[root] [next] ... [parent]" */
+ protected String thisString() {
+ return node.toString();
+ }
+
+ /** render parent hierarchy as "[root] [next] ... [parent]" */
+ protected String parentString() {
+ if (null == parent) {
+ return "[null]";
+ } else {
+ Vector parents = new Vector();
+ GenericTreeNode par = parent;
+ do {
+ parents.addElement(par);
+ par = par.getParent();
+ } while (null != par);
+ int size = parents.size();
+ StringBuffer sb = new StringBuffer(32*size);
+ par = (GenericTreeNode) parents.remove(--size);
+ sb.append("[");
+ do {
+ sb.append(par.toString());
+ par = (size<1?null:(GenericTreeNode) parents.remove(--size));
+ if (null != par) {
+ sb.append("] [");
+ }
+ } while (null != par);
+ sb.append("]");
+ return sb.toString();
+ }
+ } // parentString()
+
+ // -------------------------- Comparable interface
+ /**
+ * Comparable just delegates to Comparator.
+ * i.e., <code>return compare(this, rhs)</code>
+ * @param rhs the Object to compare from the right
+ * @throws ClassCastException if either is not instanceof GenericTreeNode
+ * @return 0 if equal, &gt;0 if this is greater than rhs, &lt;0 otherwise.
+ */
+ public int compareTo(Object rhs) {
+ return COMPARATOR.compare(this, rhs);
+ }
+
+
+ //-------------------- GenericTreeNode interface
+ /** @return the actual underlying node */
+ public Object getNode() { assertReady(); return node ; }
+ /** @return the actual underlying node */
+ public GenericTreeNode getParent() { assertReady(); return parent ; }
+ /** @return List of children - null if none */
+ public List getChildren() { assertReady(); return children ; }
+ /** @return Comparator used for comparing node (not children) */
+ public Comparator getNodeComparator() { assertReady(); return nodeComparator; }
+ /** @return Class which any children can be assigned to */
+ public Class getChildClass() { assertReady(); return childClass; }
+
+ //-------------------- misc
+ protected void assertReady() {
+ if (!ready) throw new Error("not ready");
+ }
+
+ //-------------------- inner classes
+ /**
+ * This relies entirely on the GenericTreeNode implementation of equals()
+ * which delegates to the underlying node equals() or the comparator
+ */
+ static class MatchExact implements GenericTreeNodesVisitorI {
+ public boolean visit(GenericTreeNode lhs,GenericTreeNode rhs) {
+ return (null == lhs ? (null == rhs) : lhs.equals(rhs));
+ }
+ }
+
+ /**
+ * This prints non-matching pairs to System.err,
+ * returning true always.
+ */
+ static class PrintNonMatches implements GenericTreeNodesVisitorI {
+ public boolean visit(GenericTreeNode lhs,GenericTreeNode rhs) {
+ if (! (null == lhs ? (null == rhs) : lhs.equals(rhs))) {
+ System.err.println("[lhs=" + lhs + "] [rhs=" + rhs + "]");
+ }
+ return true;
+ }
+ }
+
+ /**
+ * This prints all pairs to System.err, returning true always.
+ */
+ static class PrintAllPairs implements GenericTreeNodesVisitorI {
+ public boolean visit(GenericTreeNode lhs,GenericTreeNode rhs) {
+ System.err.println("[lhs=" + lhs + "] [rhs=" + rhs + "]");
+ return true;
+ }
+ }
+
+ /**
+ * have to separate to distinguish
+ * gtn.equals() from gtnComparator.equals
+ */
+ static class gtnComparator implements Comparator {
+ public boolean equals(Object o) {
+ if (null == o) return false;
+ return ( o instanceof gtnComparator );
+ }
+ public int hashCode() {
+ return gtnComparator.class.hashCode();
+ }
+ // -------------------------- Comparator interface
+ /**
+ * Shallow compare of two GenericTreeNodes.
+ * <li>any null component translates to "less than" another null component<li>
+ * <li>comparators must be equal according to
+ * <code>Comparator.equals(Comparator)</code><li>
+ * <li>underlying nodes equal according to
+ * <code>Comparator.compare(Object lhs, Object rhs)</code><li>
+ * <li>if the two comparators are not equal, then
+ * do arbitrary ordering of the node by toString().compareTo()
+ * of the underlying objects</li>
+ * <li>children are ignored. Two nodes may be equal even if
+ * they do not have the same children.</li>
+ * @param lhs the Object to compare from the left
+ * @param rhs the Object to compare from the right
+ * @throws ClassCastException if either is not instanceof GenericTreeNode
+ */
+ public int compare(Object lhs, Object rhs) {
+ int result = CompareUtil.compare(lhs, rhs);
+ if (Integer.MAX_VALUE == result) {
+ GenericTreeNode lhsNode = (GenericTreeNode) lhs;
+ GenericTreeNode rhsNode = (GenericTreeNode) rhs;
+ Object lhObject = lhsNode.getNode();
+ Object rhObject = rhsNode.getNode();
+ result = CompareUtil.compare(lhObject, rhObject); //
+ if (Integer.MAX_VALUE == result) {
+ Comparator lhComp = lhsNode.getNodeComparator();
+ Comparator rhComp = rhsNode.getNodeComparator();
+ result = CompareUtil.compare(lhComp, rhComp);
+ if ((Integer.MAX_VALUE == result)
+ || ((0 == result) && (null == lhComp))) {
+ // tricky: comparators are not equal or null, - todo
+ // so unable to determine standard of ordering.
+ // impose a consistent but arbitrary ordering
+ // on the underlying objects
+ System.err.println(" -- result: " + result + " lhComp " + lhComp);
+ result = lhObject.toString().compareTo(rhObject.toString());
+ } else if (0 == result) { // ok to use comparator
+ result = lhComp.compare(lhsNode.getNode(), rhsNode.getNode());
+ } else {
+ String err = "Program error - result: " + result
+ + " lhComp: " + lhComp + " rhComp: " + rhComp;
+ throw new Error(err);
+ }
+ }
+ }
+ return result;
+ } // compare
+ }
+
+} // class GenericTreeNode
+
diff --git a/aspectj-attic/testing-src/org/aspectj/testing/compare/GenericTreeNodeListOrdererFactoryI.java b/aspectj-attic/testing-src/org/aspectj/testing/compare/GenericTreeNodeListOrdererFactoryI.java
new file mode 100644
index 000000000..c98549829
--- /dev/null
+++ b/aspectj-attic/testing-src/org/aspectj/testing/compare/GenericTreeNodeListOrdererFactoryI.java
@@ -0,0 +1,30 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 2002 Palo Alto Research Center, Incorporated (PARC).
+ * 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:
+ * Xerox/PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.testing.compare;
+
+/**
+ * Factory to produce orderers per children list pair.
+ * Using a factory permits generation/selection of the right orderer
+ * for each set of children to be compared, potentially considering
+ * the visitor expectations. Note that while orderers may change during
+ * traversals, visitors do not.
+ */
+public interface GenericTreeNodeListOrdererFactoryI {
+ /**
+ * Produce the correct orderer for the children of the given GenericTreeNodes
+ * @return GenericTreeNodeListOrdererI for children, or null if none to be used
+ */
+ public GenericTreeNodeListOrdererI produce(GenericTreeNode lhs, GenericTreeNode rhs,
+ GenericTreeNodesVisitorI visitor);
+}
diff --git a/aspectj-attic/testing-src/org/aspectj/testing/compare/GenericTreeNodeListOrdererI.java b/aspectj-attic/testing-src/org/aspectj/testing/compare/GenericTreeNodeListOrdererI.java
new file mode 100644
index 000000000..7f5e2bd07
--- /dev/null
+++ b/aspectj-attic/testing-src/org/aspectj/testing/compare/GenericTreeNodeListOrdererI.java
@@ -0,0 +1,44 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 2002 Palo Alto Research Center, Incorporated (PARC).
+ * 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:
+ * Xerox/PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.testing.compare;
+
+import java.util.List;
+
+/**
+ * Puts two lists of GenericTreeNode children
+ * in traversal order for comparison purposes.
+ * Given two lists, produce two lists which
+ * should be the comparison order of the two.
+ * In the case of set comparison, this will
+ * impose an ordering on the produced lists
+ * such that the equal elements are pairs.
+ * In the case of list comparison, it may
+ * impose an ordering if the comparator itself
+ * does not.
+ * All Lists must contain only GenericTreeNode.
+ */
+public interface GenericTreeNodeListOrdererI {
+ /**
+ * Produce lists representing the proper transformation of
+ * the children for a given visitor.
+ * To use the existing lists, return them in a new array.
+ * You may return null for one or both Lists.
+ * @param lhs the List representing the left-hand-side
+ * which contains only GenericTreeNode
+ * @param rhs the List representing the right-hand-side
+ * which contains only GenericTreeNode
+ * @return two lists List[] (0 => lhs, 1 => rhs)
+ */
+ public List[] produceLists(List lhs, List rhs);
+}
diff --git a/aspectj-attic/testing-src/org/aspectj/testing/compare/GenericTreeNodesVisitorI.java b/aspectj-attic/testing-src/org/aspectj/testing/compare/GenericTreeNodesVisitorI.java
new file mode 100644
index 000000000..da1dcf2a5
--- /dev/null
+++ b/aspectj-attic/testing-src/org/aspectj/testing/compare/GenericTreeNodesVisitorI.java
@@ -0,0 +1,31 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 2002 Palo Alto Research Center, Incorporated (PARC).
+ * 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:
+ * Xerox/PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.testing.compare;
+/**
+ * Visit a node-pair in the trees,
+ * signalling whether to continue traversal.
+ */
+public interface GenericTreeNodesVisitorI {
+ /**
+ * Visit nodes in parallel trees.
+ * One (but not both) of the input nodes may be null.
+ * @param lhs the GenericTreeNode on the left-hand-side of a binary operation
+ * (may be null)
+ * @param lhs the GenericTreeNode on the right-hand-side of a binary operation
+ * (may be null)
+ * @return true if should continue visiting
+ */
+ public boolean visit(GenericTreeNode lhs, GenericTreeNode rhs);
+}
+
diff --git a/aspectj-attic/testing-src/org/aspectj/testing/compare/Regexp.java b/aspectj-attic/testing-src/org/aspectj/testing/compare/Regexp.java
new file mode 100644
index 000000000..c32310cd7
--- /dev/null
+++ b/aspectj-attic/testing-src/org/aspectj/testing/compare/Regexp.java
@@ -0,0 +1,40 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 2002 Palo Alto Research Center, Incorporated (PARC).
+ * 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:
+ * Xerox/PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.testing.compare;
+
+import java.util.Vector;
+
+/** Generalize regular expression interface (to avoid binding to regexp provider)*/
+public interface Regexp {
+ /** @return the substrings matched in argument by this regular expression */
+ public Vector getGroups(String argument);
+
+ /** @return true if argument is matched by this regular expression */
+ public boolean matches(String argument);
+
+ /**
+ * Set pattern used in this regular expression.
+ * May throw Exception if the pattern can be determined to be illegal
+ * during initialization.
+ * @throws Exception if pattern is illegal
+ */
+ public void setPattern(String pattern) throws Exception;
+
+ /**
+ * @return a string representaion of the pattern
+ * (may not be legal or the input)
+ */
+ public String getPattern() ;
+}
+
diff --git a/aspectj-attic/testing-src/org/aspectj/testing/compare/RegexpFactory.java b/aspectj-attic/testing-src/org/aspectj/testing/compare/RegexpFactory.java
new file mode 100644
index 000000000..0c7bccc14
--- /dev/null
+++ b/aspectj-attic/testing-src/org/aspectj/testing/compare/RegexpFactory.java
@@ -0,0 +1,64 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 2002 Palo Alto Research Center, Incorporated (PARC).
+ * 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:
+ * Xerox/PARC initial implementation
+ * ******************************************************************/
+
+// todo: non-distribution license?
+
+package org.aspectj.testing.compare;
+
+// currently in aspectj-external-lib/regexp
+import org.apache.regexp.RE;
+
+import java.util.Vector;
+
+
+/** Factory for our Regexp. */
+public class RegexpFactory {
+ public static Regexp makeRegexp() {
+ return new RegExpDelegate();
+ }
+}
+
+/** Implement Regexp by delegating to org.apache.regexp.RE */
+final class RegExpDelegate implements Regexp {
+ String pattern;
+ RE regexp;
+ public RegExpDelegate() { }
+ public Vector getGroups(String arg) {
+ String label = "getGroups(\"" + arg + "\") ";
+ D.log(label);
+ Vector result = null;
+ if ((null != arg) && (matches(arg))) {
+ int size = regexp.getParenCount();
+ D.log(label + " size " + size);
+ result = new Vector(size);
+ for (int i = 0; i < size; i++) {
+ Object item = regexp.getParen(i);
+ result.addElement(item);
+ D.log(label + i + ": " + item);
+ }
+ }
+ return result;
+ }
+ public boolean matches(String arg) {
+ return ((null != regexp) && regexp.match(arg));
+ }
+ public void setPattern(String pattern) throws Exception {
+ this.pattern = pattern;
+ regexp = new RE(this.pattern);
+ D.log("RE: " + regexp + " pattern: /" + pattern + "/");
+ }
+ public String getPattern() {
+ return pattern;
+ }
+}
+
diff --git a/aspectj-attic/testing-src/org/aspectj/testing/compare/RegexpFilter.java b/aspectj-attic/testing-src/org/aspectj/testing/compare/RegexpFilter.java
new file mode 100644
index 000000000..7ea6c7ecf
--- /dev/null
+++ b/aspectj-attic/testing-src/org/aspectj/testing/compare/RegexpFilter.java
@@ -0,0 +1,622 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 2002 Palo Alto Research Center, Incorporated (PARC).
+ * 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:
+ * Xerox/PARC initial implementation
+ * ******************************************************************/
+
+// todo: non-distribution license?
+package org.aspectj.testing.compare;
+
+import org.aspectj.testing.compare.Regexp;
+
+import java.util.*;
+import java.io.*;
+
+
+/** utility class for logging */
+class D {
+ public static boolean LOG = false;
+ public static void log(String s) { if (LOG) System.err.println("## " + s); }
+ static {
+ try {
+ LOG = (null != System.getProperty("DEBUG"));
+ } catch (Throwable t) {
+ // ignore
+ }
+ }
+}
+
+/** utility class for handling errors */
+class ErrHandler {
+ public static final ErrHandler DEFAULT = new ErrHandler();
+ public static final Action INFO = new Action("info") {
+ public void invoke(String message) { System.out.println("INFO: " + message); } };
+ public static final Action WARN = new Action("warn") {
+ public void invoke(String message) { System.err.println("WARNING: " + message); } };
+ public static final Action HALT = new Action("halt") {
+ public void invoke(String message) { throw new RuntimeException(message); } };
+ public static final Action ABORT = new Action("abort") {
+ public void invoke(String message) { throw new Error(message); } };
+ public static final Action EXIT = new Action("exit") {
+ public void invoke(String message) { System.err.println(message); System.exit(1); } };
+ abstract static class Action {
+ protected final String name;
+ private Action(String name) {
+ this.name = name.toLowerCase().trim();
+ }
+ abstract public void invoke(String message);
+ public String toString() { return name; }
+ }
+ public static final void handleErr(String message, Throwable t) {
+ DEFAULT.handle(message, t);
+ }
+ public static final void handleErr(String message) {
+ DEFAULT.handle(message);
+ }
+ public static final void handleErr(String message, Action suggestion) {
+ DEFAULT.handle(message, suggestion);
+ }
+ public void handle(String message) { handle(message, INFO); }
+ public void handle(String message, Throwable t) {
+ String eMessage = (null == t ? "" :
+ t.getClass().getName() + ": " + t.getMessage());
+ handle(message + eMessage, HALT);
+ }
+ /**
+ * The default implementation just takes the suggested action
+ * @param message the String to pass to any Action
+ * @param suggestion the Action proposed by the caller
+ */
+ public void handle(String message, Action suggestion) {
+ suggestion.invoke(message);
+ }
+}
+
+/* old comments, not correct:
+ * <li>test line against all registered select statements
+ * to get all the matching (replace) operations (unsupported)</li>
+ * The algorithm is greedy in that if the user requests a line
+ * and the default is no-output, it will read lines from the input
+ * until one is matched (or EOF).
+ */
+
+/**
+ * Process files in a minimal version of sed:
+ * <li>read line using superclass LineNumberReader.readLine()</li>
+ * <li>Preprocess with case and white space operations</li>
+ * <li>run all the replace operations on the input, in order</li>
+ * <li>return the line.</li>
+ * Using anything but the <code>readLine()</code> method will circumvent
+ * the regular expression replacement processing.
+ */
+public class RegexpFilter {
+ protected static final String[] NO_STRINGS = new String[]{};
+
+ // ---------------------------------------------- static methods
+ /**
+ * Process file (or System.in) like sed.
+ * This only calls <code>RegexpFilterReader.main(args)</code>.
+ * @param args same as for init(String[], RegexpFilter)
+ */
+ public static void main(String[] args) throws IOException {
+ RegexpFilterReader.main(args);
+ }
+
+ // todo: move String -> String[] (commas) out into utility
+ /**
+ * Initialize a RegexpFilter based on command-line style arguments
+ * in a single String. (Otherwise, same as
+ * <code>init(String[], RegexpFilter)</code>)
+ * The Strings are separated at , (unless \ escaped) and trimmed.
+ * Note that the escape characters are removed from before the ,.
+ * @param spec the String to break into String[]
+ * @param toSet the RegexpFilter to initialize - if null, construct one from
+ * the file argument or stdin if there is no file argument.
+ */
+ public static RegexpFilter init(String arg, RegexpFilter toSet) {
+ if ((null == arg) || (1 > arg.length())) {
+ return init(NO_STRINGS, toSet);
+ }
+ StringTokenizer st = new StringTokenizer(arg, ",");
+ Vector result = new Vector();
+ String last = null;
+ String next;
+ while (st.hasMoreTokens()) {
+ next = st.nextToken();
+ if (next.endsWith("\\") && (st.hasMoreTokens())) {
+ next = next.substring(0, next.length()-1);
+ last = last == null ? next : last + next;
+ continue;
+ }
+ if (null != last) {
+ next = last + next;
+ last = null;
+ }
+ result.add(next.trim());
+ }
+ String[] args = new String[result.size()];
+ result.copyInto(args);
+ return RegexpFilter.init(args, toSet);
+ }
+
+ /**
+ * Initialize a RegexpFilter based on command-line style arguments.
+ * This is the only way (currently) to set up a RegexpFilter.
+ * syntax: <code>{file | {-i|-t|-b|-s <pattern>|-s <patternFile>}..}</code>
+ * (for booleans, use lowercase to enable, uppercase to disable).
+ * @param args the String[] containing file to input plus any number of...
+ * <li>-i "ignore": ignore case</li>
+ * <li>-t "trim" : ignore leading and trailing white space</li>
+ * <li>-b "blanks": ignore differences in all white space</li>
+ * <li>-s "{s/pattern/expression/};...":
+ * replace pattern in lines with expression</li>
+ * <li>-S <file> : same as s, but read commands from file</li>
+ * @param toSet the RegexpFilter to initialize - if null, construct one from
+ * the file argument or stdin if there is no file argument.
+ */
+ public static RegexpFilter init(String[] args, RegexpFilter toSet) {
+ final String syntax = " - syntax: {file | {-i|-t|-b|-s <pattern>|-s <patternFile>}..}";
+ RegexpFilter result = (null != toSet ? toSet : new RegexpFilter());
+ if ((null != args) && (0 < args.length)) {
+ for (int i = 0; i < args.length; i++) {
+ String arg = args[i];
+ if ((null == arg) || (1 > arg.length())) continue;
+ if (arg.startsWith("-")) {
+ switch (arg.charAt(1)) {
+ case 'i' : result.ignoreCase = true; break;
+ case 'I' : result.ignoreCase = false; break;
+ case 'b' : result.collapseWhitespace = true; break;
+ case 'B' : result.collapseWhitespace = false; break;
+ case 't' : result.trimWhitespace = true; break;
+ case 'T' : result.trimWhitespace = false; break;
+ case 's' : ++i;
+ if (i < args.length) {
+ result.getOperationList().addOperation(args[i]);
+ } else {
+ String err = "need arg after -s " + syntax;
+ ErrHandler.handleErr(err, ErrHandler.WARN);
+ }
+ break;
+ case 'S' : ++i;
+ if (i < args.length) {
+ result.getOperationList().addFile(args[i]);
+ } else {
+ String err = "need arg after -s " + syntax;
+ ErrHandler.handleErr(err, ErrHandler.WARN);
+ }
+ break;
+ default:
+ String err = "unrecognized flag : " + arg + syntax;
+ ErrHandler.handleErr(err, ErrHandler.WARN);
+ break;
+ }
+ } else if (null != result) {
+ ErrHandler.handleErr("unexpected arg " + arg + syntax, ErrHandler.WARN);
+ break;
+ } else { // unflagged argument, need file - should be input file
+ File _file = new File(arg);
+ if (_file.exists() && _file.canRead()) {
+ result.setFile(_file);
+ }
+ }
+ } // reading args
+ } // have args
+ return result;
+ } // init
+
+ // ---------------------------------------------- instance fields
+ /** ignore case by converting lines to upper case */
+ protected boolean ignoreCase = false;
+ /** collapse internal whitespace by converting to space character */
+ protected boolean collapseWhitespace = true;
+ /** trim leading and trailing whitespace from lines before comparison */
+ protected boolean trimWhitespace = false;
+ /** replace input per replace operations */
+ protected boolean replace = false;
+ /** operations to process the file with */
+ protected OperationList operations;
+ /** handler for our errors*/
+ protected ErrHandler handler = ErrHandler.DEFAULT;
+ /** the File to use */
+ protected File file = null;
+
+ // ---------------------------------------------- constructors
+ /** no getter/setters yet, so construct using
+ * <code>static RegexpFilter init(String[],RegexpFilter)</code>
+ */
+ protected RegexpFilter() { }
+
+ // ---------------------------------------------- instance methods
+
+
+ /**
+ * Set a file for this RegexpFilter.
+ * This makes command-line initialization easier.
+ * @param file the File to set for this RegexpFilter
+ */
+ public void setFile(File file) { this.file = file; }
+
+ /**
+ * Return file this RegexpFilter was initialized with.
+ * @return the File this RegexpFilter was initialized with (may be null).
+ */
+ public File getFile() { return file; }
+
+ /**
+ * Lazy construction of operations list
+ */
+ protected OperationList getOperationList() {
+ if (null == operations) {
+ operations = new OperationList();
+ replace = true;
+ }
+ return operations;
+ }
+
+ /**
+ * Process line, applying case and whitespace operations
+ * before delegating to replace.
+ * @param string the String to proces
+ * @return the String as processed
+ */
+ protected String process(String string) {
+ String label = "process(\"" + string + "\")";
+ D.log(label);
+ if (null == string) return null;
+ String result = string;
+ if (ignoreCase) {
+ result = result.toUpperCase();
+ }
+ if (trimWhitespace) {
+ result = result.trim();
+ }
+ if (collapseWhitespace) {
+ final StringBuffer collapse = new StringBuffer();
+ StringTokenizer tokens = new StringTokenizer(result);
+ boolean hasMoreTokens = tokens.hasMoreTokens();
+ while (hasMoreTokens) {
+ collapse.append(tokens.nextToken());
+ hasMoreTokens = tokens.hasMoreTokens();
+ if (hasMoreTokens) {
+ collapse.append(" ");
+ }
+ }
+ result = collapse.toString();
+ }
+ if (replace) {
+ result = getOperationList().replace(result);
+ D.log(label + " result " + result);
+ }
+ return result;
+ }
+
+ /**
+ * container for ReplaceOperations constructs on add,
+ * runs operations against input.
+ */
+ class OperationList {
+ final ArrayList list;
+ public OperationList() {
+ list = new ArrayList();
+ }
+
+ /**
+ * Run input through all the operations in this list
+ * and return the result.
+ * @param input the String to process
+ * @return the String result of running input through all replace
+ * operations in order.
+ */
+ public String replace(String input) {
+ if (null == input) return null;
+ Iterator operations = operations();
+ while (operations.hasNext()) {
+ ReplaceOperation operation = (ReplaceOperation) operations.next();
+ input = operation.replace(input);
+ }
+ return input;
+ }
+
+ /**
+ * Add operations read from file, one per line,
+ * ignoring empty lines and # or // comments.
+ * ';' delimits operations within a line as it does
+ * for addOperation(String), so you must \ escape ;
+ * in the search or replace segments
+ */
+ public void addFile(String path) {
+ if (null == path) {
+ handler.handle("null path", ErrHandler.ABORT);
+ } else {
+ File file = new File(path);
+ if (!file.exists() && file.canRead()) {
+ handler.handle("invalid path: " + path, ErrHandler.ABORT);
+ } else {
+ BufferedReader reader = null;
+ int lineNumber = 0;
+ String line = null;
+ try {
+ reader = new BufferedReader(new FileReader(file));
+ while (null != (line = reader.readLine())) {
+ lineNumber++;
+ int loc = line.indexOf("#");
+ if (-1 != loc) {
+ line = line.substring(0,loc);
+ }
+ loc = line.indexOf("//");
+ if (-1 != loc) {
+ line = line.substring(0,loc);
+ }
+ line = line.trim();
+ if (1 > line.length()) continue;
+ addOperation(line);
+ }
+ } catch (IOException e) {
+ String message ="Error processing file " + path
+ + " at line " + lineNumber + ": \"" + line + "\""
+ + ": " + e.getClass().getName() + ": " + e.getMessage() ;
+ handler.handle(message, ErrHandler.ABORT);
+ } finally {
+ try {
+ if (reader != null) reader.close();
+ } catch (IOException e) {
+ // ignore
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Add operation to list, emitting warning and returning false if not created.
+ * Add multiple operations at once by separating with ';'
+ * (so any ; in search or replace must be escaped).
+ * @param operation a String acceptable to
+ * <code>ReplaceOperation.makeReplaceOperation(String, ErrHandler)</code>,
+ * of the form sX{search}X{replace}X{g};..
+ * @return false if not all added.
+ */
+ public boolean addOperation(String operation) {
+ StringTokenizer st = new StringTokenizer(operation, ";", false);
+ String last = null;
+ ReplaceOperation toAdd;
+ boolean allAdded = true;
+ while (st.hasMoreTokens()) {
+ // grab tokens, accumulating if \ escapes ; delimiter
+ String next = st.nextToken();
+ if (next.endsWith("\\") && (st.hasMoreTokens())) {
+ next = next.substring(0, next.length()-1);
+ last = (last == null ? next : last + next);
+ continue;
+ }
+ if (null != last) {
+ next = last + next;
+ last = null;
+ }
+ toAdd = ReplaceOperation.makeReplaceOperation(next, handler);
+ if (null != toAdd) {
+ list.add(toAdd);
+ } else {
+ String label = "RegexpFilter.OperationList.addOperation(\"" + operation + "\"): ";
+ handler.handle(label + " input not accepted " , ErrHandler.WARN);
+ if (allAdded) allAdded = false;
+ }
+ }
+ return allAdded;
+ }
+
+ /**
+ * @return an Iterator over the list of ReplaceOperation
+ */
+ public Iterator operations() {
+ return list.iterator();
+ }
+ } // class OperationList
+} // class RegexpFilter
+
+/**
+ * Encapsulate a search/replace operation which uses a RegExp.
+ */
+class ReplaceOperation {
+ /**
+ * This accepts a sed-like substitute command, except that
+ * the delimiter character may not be used anywhere in the
+ * search or replace strings, even if escaped. You may use
+ * any delimiter character.
+ * Note that although g (replace-globally) is supported as input,
+ * it is ignored in this implementation.
+ * @param operation a String of the form sX{search}X{replace}X{g}
+ */
+ public static ReplaceOperation makeReplaceOperation(String operation, ErrHandler handler) {
+ ReplaceOperation result = null;
+ StringBuffer err = (null == handler ? null : new StringBuffer());
+ final String syntax = "sX{search}X{replace}X{g}";
+ // todo: use Point p = isValidOperation(operation);
+ if (null == operation) {
+ if (null != err) err.append("null operation");
+ } else if (5 > operation.length()) {
+ if (null != err) err.append("empty operation");
+ } else if (!operation.startsWith("s")) {
+ if (null != err) err.append("expecting s: " + syntax);
+ } else {
+ String sep = operation.substring(1,2);
+ int mid = operation.indexOf(sep, 2);
+ if (-1 == mid) {
+ if (null != handler) err.append("expecting middle \"" + sep + "\": " + syntax);
+ } else if (mid == 2) {
+ if (null != handler) err.append("expecting search before middle \"" + sep + "\": " + syntax);
+ } else {
+ int end = operation.indexOf(sep, mid+1);
+ if (-1 == end) {
+ if (null != handler) err.append("expecting final \"" + sep + "\": " + syntax);
+ } else {
+ String search = operation.substring(2,mid);
+ if (!ReplaceOperation.isValidSearch(search)) {
+ if (null != handler) err.append("invalid search \"" + search + "\": " + syntax);
+ } else {
+ String replace = operation.substring(mid+1,end);
+ if (!ReplaceOperation.isValidReplace(replace)) {
+ if (null != handler) err.append("invalid replace \"" + replace + "\": " + syntax);
+ } else {
+ result = new ReplaceOperation(search, replace, operation.endsWith("g"), handler);
+ }
+ }
+ }
+ }
+ }
+ if ((0 < err.length()) && (null != handler)) {
+ err.append(" operation=\"" + operation + "\"");
+ handler.handle(err.toString(), ErrHandler.HALT);
+ }
+ return result;
+ }
+
+ /**
+ * Return true if the input string represents a valid search operation
+ * @param replace the String representing a search expression
+ */
+ protected static boolean isValidSearch(String search) { // todo: too weak to be useful now
+ return ((null != search) && (0 < search.length()));
+ }
+
+ /**
+ * Return Point x=mid, y=end if the input string represents a valid search operation
+ * @param search the String representing a search expression
+ protected static Point isValidOperation(String search) {
+ if (null != search) {
+ final int length = search.length();
+ if (5 < length) {
+ String sep = search.substring(2,3);
+ int mid = search.indexOf(sep, 3);
+ if (3 < mid) {
+ int end = search.indexOf(sep, mid+1);
+ if ((end == length-1)
+ || ((end == length-2)
+ && search.endsWith("g"))) {
+ return new Point(mid, end);
+ }
+ }
+ }
+ }
+ return null;
+ }
+ */
+
+ /**
+ * Return true if the input string represents a valid replace operation
+ * @param replace the String representing a replace expression
+ */
+ protected static boolean isValidReplace(String replace) { // todo: too weak to be useful now
+ boolean result = (null != replace);
+ return result;
+ } // isValidReplace
+
+ // ------------------------------------------------- instance members
+ /** If true, repeat replace as often as possible (todo: repeat not supported) */
+ protected final boolean repeat;
+ /** search pattern */
+ protected final String search;
+ /** replace pattern */
+ protected final String replace;
+ /** regexp processor */
+ protected final Regexp regexp;
+ /** replace buffer (read-only) */
+ protected final char[] replaceBuffer;
+ /** error handler */
+ protected final ErrHandler handler;
+
+ // ------------------------------------------------- constructors
+ private ReplaceOperation(String search, String replace, boolean repeat, ErrHandler handler) {
+ this.search = search;
+ this.replace = replace;
+ this.replaceBuffer = replace.toCharArray();
+ this.repeat = repeat;
+ this.handler = (null != handler ? handler : ErrHandler.DEFAULT);
+ this.regexp = RegexpFactory.makeRegexp();
+ try {
+ this.regexp.setPattern(search);
+ } catch (Exception e) {
+ this.handler.handle("setting search=" + search, e);
+ }
+ }
+
+
+ /**
+ * Return true if the input would be matched by the search string of this ReplaceOperation.
+ * @param input the String to compare
+ * @return true if the input would be matched by the search string of this ReplaceOperation
+ */
+ public boolean matches(String input) {
+ return ((null != input) && regexp.matches(input));
+ } // matches
+
+ /**
+ * Replace any search text in input with replacement text,
+ * returning input if there is no match. More specifically,
+ * <li> emit unmatched prefix, if any</li>
+ * <li> emit replacement text as-is, except that
+ * \[0-9] in the replacement text is replaced
+ * with the matching subsection of the input text</li>
+ * <li> emit unmatched suffix, if any</li>
+ * @param input the String to search and replace
+ * @throws IllegalArgumentException if null == input
+ */
+ public String replace(String input) {
+ if (null == input) throw new IllegalArgumentException("null input");
+ String label = "replace(\"" + input + "\") ";
+ D.log(label);
+ if (matches(input)) {
+ StringBuffer buffer = new StringBuffer();
+ final int length = replaceBuffer.length;
+ Vector groups = regexp.getGroups(input);
+ if ((null == groups) || (1 > groups.size())) {
+ handler.handle(label + "matched but no groups? ");
+ return input;
+ }
+ buffer.setLength(0);
+ // group 0 is whole; if not same as input, print prefix/suffix
+ String matchedPart = (String) groups.elementAt(0);
+ final int matchStart = input.indexOf(matchedPart);
+ final int matchEnd = matchStart + matchedPart.length();
+ if (0 < matchStart) {
+ buffer.append(input.substring(0, matchStart));
+ }
+ // true if \ escaping special char, esp. replace \[0-9]
+ boolean specialChar = false;
+ for (int i = 0; i < length; i++) {
+ char c = replaceBuffer[i];
+ if (specialChar) {
+ int value = Character.digit(c, 10); // only 0-9 supported
+ if ((0 <= value) && (value < groups.size())) {
+ buffer.append((String) groups.elementAt(value));
+ } else {
+ buffer.append(c);
+ }
+ specialChar = false;
+ } else if ('\\' != c) {
+ D.log("." + c);
+ buffer.append(c);
+ } else {
+ specialChar = true;
+ }
+ }
+ if (specialChar) {
+ handler.handle(label + "\\ without register: " + replace,
+ ErrHandler.ABORT);
+ }
+ if (matchEnd < input.length()) {
+ buffer.append(input.substring(matchEnd));
+ }
+ input = buffer.toString();
+ }
+ return input;
+ } // replace
+} // class ReplaceOperation
+
diff --git a/aspectj-attic/testing-src/org/aspectj/testing/compare/RegexpFilterReader.java b/aspectj-attic/testing-src/org/aspectj/testing/compare/RegexpFilterReader.java
new file mode 100644
index 000000000..5021a5efe
--- /dev/null
+++ b/aspectj-attic/testing-src/org/aspectj/testing/compare/RegexpFilterReader.java
@@ -0,0 +1,291 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 2002 Palo Alto Research Center, Incorporated (PARC).
+ * 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:
+ * Xerox/PARC initial implementation
+ * ******************************************************************/
+
+
+package org.aspectj.testing.compare;
+
+
+import org.aspectj.testing.util.StringVisitor;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.PrintStream;
+import java.io.Reader;
+import java.util.Vector;
+
+/**
+ * Adapt Writer to StringVisitor, with pre- and post-write
+ * methods for subclasses to override.
+ */
+class StringDumper implements StringVisitor {
+ /** subclasses should write errors here and be silent if null */
+ protected PrintStream errSink;
+ private final boolean appendNewlines;
+ private final BufferedWriter writer;
+ /** true only if writer non-null and close() was invoked */
+ private boolean closed;
+
+ /**
+ * @param writer the Writer to write to - ignored if null
+ * @param appendNewLines if true, append newlines after writing
+ */
+ public StringDumper(BufferedWriter writer, boolean appendNewlines) {
+ this.appendNewlines = appendNewlines;
+ this.writer = writer;
+ // closed = false;
+ errSink = System.err;
+ }
+
+ /**
+ * Set error sink - may be null to ignore IOExceptions.
+ * @param err the PrintStream to use for errors (silent if null)
+ */
+ public void setErrorSink(PrintStream err) {
+ errSink = err;
+ }
+
+ /**
+ * Invoked before the String is written.
+ * This implementation does nothing.
+ * @param string the String to be written
+ * @return false if writing should abort
+ */
+ protected boolean preWrite(String string)
+ throws IOException {
+ return true;
+ }
+
+ /**
+ * Implement StringVisitor.accept(String)
+ * by doing preWrite(String), process(String),
+ * writer.write(String...), and postWrite(String),
+ * any one of which may result in a false return value.
+ * @throws Error if invoked after <code>close()</code>
+ */
+ public final boolean accept(String string) {
+ if (closed) {
+ String m = "did close() before accept(\"" + string + "\")";
+ throw new Error(m);
+ }
+ if (null == writer) return false;
+ try {
+ if (!preWrite(string)) return false;
+ string = process(string);
+ if (null == string) return false;
+ if (null != writer) writer.write(string, 0, string.length());
+ if (!postWrite(string)) return false;
+ } catch (IOException e) {
+ PrintStream sink = errSink;
+ if (null != sink) e.printStackTrace(sink);
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Transform the input before writing.
+ * This implementation returns the input.
+ * @param string the String to transform
+ * @return the String as changed - if null,
+ * then halt and return false from the accept method.
+ */
+ protected String process(String string) {
+ return string;
+ }
+
+ /**
+ * Invoked after the String is written.
+ * This implementation handles writing of the newline.
+ * @param string the String that was written
+ * @return false if writing should abort
+ */
+ protected boolean postWrite(String string)
+ throws IOException {
+ if (appendNewlines && null != writer) {
+ writer.newLine();
+ }
+ return true;
+ }
+
+ /** convenience method to close adopted writer */
+ public void close() throws IOException {
+ if (null != writer) {
+ writer.close();
+ closed = true;
+ }
+ }
+}
+class FilteredDumper extends StringDumper {
+ protected final RegexpFilter filter;
+ public FilteredDumper(BufferedWriter writer,
+ boolean appendNewlines,
+ RegexpFilter filter) {
+ super(writer, appendNewlines);
+ this.filter = filter;
+ }
+ public String process(String arg) {
+ return filter.process(arg);
+ }
+}
+
+class FilteredAccumulator extends FilteredDumper {
+ protected final Vector results;
+ public FilteredAccumulator(RegexpFilter filter) {
+ super(null, false, filter);
+ results = new Vector();
+ }
+ public String process(String arg) {
+ arg = super.process(arg);
+ synchronized (results) {
+ results.add(arg);
+ }
+ return arg;
+ }
+ public Vector getResults() {
+ synchronized (results) {
+ return (Vector) results.clone();
+ }
+ }
+}
+
+/**
+
+/**
+ * Input file, using a RegexpFilter to preprocess each line.
+ * <li>read line using superclass LineNumberReader.readLine()</li>
+ * <li>Preprocess with case and white space operations</li>
+ * <li>run all the replace operations on the input, in order</li>
+ * <li>return the line.</li>
+ * Using anything but the <code>readLine()</code> method will circumvent
+ * the regular expression replacement processing.
+ */
+public class RegexpFilterReader extends BufferedReader {
+
+ // ---------------------------------------------- static methods
+
+ /**
+ * Pass lines from BufferedReader to visitor.
+ * Stop reading lines if visitor returns false.
+ * @param input the BufferedReader with the input
+ * - if null, use System.in
+ * @param visitor the StringVisitor to pass each line
+ * if null, just read in all lines and ignore
+ */
+ public static void visitLines(BufferedReader input,
+ StringVisitor visitor)
+ throws IOException {
+ final boolean openInput = (null == input);
+ if (openInput) input = new BufferedReader(new InputStreamReader(System.in));
+ try {
+ String line = null;
+ if (null == visitor) {
+ while (null != (line = input.readLine())) {
+ // read and ignore
+ }
+ } else {
+ while (null != (line = input.readLine())) {
+ if (!visitor.accept(line)) {
+ break;
+ }
+ }
+ }
+ } finally {
+ if (openInput && (null != input)) {
+ try { input.close(); } // todo: ok to close since System.in underlies?
+ catch (IOException e) {
+ e.printStackTrace(System.err);
+ }
+ }
+ }
+ } // visitLines
+
+ // todo move write(in,out) to a utility class
+ /**
+ * Convenience method to write one file to another by line.
+ * Neither input nor output are closed.
+ * @param input the BufferedReader with the input - if null, use System.in
+ * @param output the BufferedWriter for the output - if null, use System.out
+ */
+ public static void write(BufferedReader input,
+ BufferedWriter output)
+ throws IOException {
+ final boolean openOutput = (null == output);
+ if (openOutput) output = new BufferedWriter(new OutputStreamWriter(System.out));
+ StringDumper visitor = new StringDumper(output, true);
+ try {
+ RegexpFilterReader.visitLines(input, visitor);
+ } finally {
+ if (openOutput && (null != visitor)) {
+ try { visitor.close(); } // todo: ok to close since System.out underlies?
+ catch (IOException e) {
+ e.printStackTrace(System.err);
+ }
+ }
+ }
+ } // write
+
+ /**
+ * Process file (or System.in) like sed.
+ * @param args the String[] containing RegexpFilter arguments
+ */
+ public static void main(String[] args) throws IOException {
+ RegexpFilter filter = RegexpFilter.init(args, null);
+ if (null != filter) {
+ File file = filter.getFile();
+ Reader reader = null;
+ if (file != null) {
+ reader = new FileReader(file);
+ } else {
+ reader = new InputStreamReader(System.in);
+ }
+ RegexpFilterReader me = new RegexpFilterReader(reader);
+ me.setFilter(filter);
+ RegexpFilterReader.write(me, null);
+ }
+ }
+
+ // ---------------------------------------------- constructors
+ public RegexpFilterReader(Reader reader) {
+ super(reader);
+ }
+ public RegexpFilterReader(Reader reader, int size) {
+ super(reader, size);
+ }
+
+ // ---------------------------------------------- instance fields
+ protected RegexpFilter filter;
+ // ---------------------------------------------- instance methods
+ public void setFilter(RegexpFilter filter) {
+ this.filter = filter;
+ }
+
+ /**
+ * Process each line as it is read in by the superclass.
+ */
+ public String readLine() throws IOException {
+ RegexpFilter filter = this.filter;
+ String line = super.readLine();
+ if (null != filter) {
+ line = filter.process(line);
+ }
+ return line;
+ }
+
+} // class RegexpFilterReader
+
+
diff --git a/aspectj-attic/testing-src/org/aspectj/testing/compare/TreeCompare.java b/aspectj-attic/testing-src/org/aspectj/testing/compare/TreeCompare.java
new file mode 100644
index 000000000..cbf92daf5
--- /dev/null
+++ b/aspectj-attic/testing-src/org/aspectj/testing/compare/TreeCompare.java
@@ -0,0 +1,217 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 2002 Palo Alto Research Center, Incorporated (PARC).
+ * 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:
+ * Xerox/PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.testing.compare;
+import org.aspectj.testing.compare.adapters.StructureGenericTreeNodeFactory;
+import org.aspectj.testing.compare.adapters.JTreeNodeGenericTreeNodeFactory;
+import org.aspectj.testing.compare.adapters.GenericTreeNodeFactoryI;
+// target
+// XXX compiler import org.aspectj.asm.StructureNode;
+// testing
+import javax.swing.tree.TreeNode;
+import javax.swing.tree.DefaultMutableTreeNode;
+// utils
+import java.io.*;
+
+/**
+ * Compare two generic trees for tree-equality.
+ * Currently does not indicate where or how they failed.
+ * Input trees are serialized to disk in a format that
+ * is (or can be wrapped using) <code>GenericTreeNode</code>.
+ * requires files expected.ser and actual.ser
+ * to deserialize to type StructureNode (untested - use Structure)
+ * or Swing TreeNode.
+ */
+public class TreeCompare {
+ public static boolean DODIFF;
+ /**
+ * @param args ignored - reading expected.ser and actual.ser
+ */
+ public static void main(String[] args) {
+ TreeCompare me = new TreeCompare();
+ File expected = new File("expected.ser");
+ File actual = new File("actual.ser");
+ if ((args.length > 0)
+ || (!expected.exists() || (!actual.exists()))) {
+ DODIFF = (args.length > 1);
+ takeSnapshot(expected);
+ takeSnapshot(actual);
+ }
+ me.compareSnapshots(expected, actual);
+ }
+ private static void takeSnapshot(File file) {
+ DefaultMutableTreeNode snapshot = getRoot(file) ;
+ ObjectOutputStream p = null;
+ FileOutputStream ostream = null;
+ try {
+ ostream = new FileOutputStream(file);
+ p = new ObjectOutputStream(ostream);
+ p.writeObject(snapshot);
+ } catch (IOException e) {
+ e.printStackTrace(System.err);
+ } finally {
+ try {
+ if (null != p) p.flush();
+ if (null != ostream) ostream.close();
+ } catch (IOException o) {} // ignored
+ }
+ }
+
+ private static DefaultMutableTreeNode getRoot(File file) {
+ boolean isActual = (!DODIFF ? false : (-1 != (file.getPath().indexOf("actual"))));
+ DefaultMutableTreeNode root = new DefaultMutableTreeNode("Edna");
+ DefaultMutableTreeNode child = new DefaultMutableTreeNode("Evalyn");
+ root.add(child);
+ child.add(new DefaultMutableTreeNode("Marsha"));
+ child.add(new DefaultMutableTreeNode("Ray"));
+ if (DODIFF && isActual) { // Bill added to actual
+ child.add(new DefaultMutableTreeNode("Bill"));
+ }
+ child = new DefaultMutableTreeNode("Clifford");
+ root.add(child);
+ child.add(new DefaultMutableTreeNode("Terry"));
+ if (DODIFF && isActual) { // Peter mispelled in actual
+ child.add(new DefaultMutableTreeNode("peter"));
+ } else {
+ child.add(new DefaultMutableTreeNode("Peter"));
+ }
+ child.add(new DefaultMutableTreeNode("Mary"));
+ child = new DefaultMutableTreeNode("Anastasia");
+ root.add(child);
+ child.add(new DefaultMutableTreeNode("Victor"));
+ child.add(new DefaultMutableTreeNode("Valerie"));
+ child.add(new DefaultMutableTreeNode("Valentine"));
+ if (DODIFF && isActual) { // Vim added in actual, with a child
+ DefaultMutableTreeNode par = new DefaultMutableTreeNode("VimAdded");
+ par.add(new DefaultMutableTreeNode("Vim kid"));
+ child.add(par);
+ }
+ return root;
+ }
+
+ /**
+ * Compare two File by reading in as serialized
+ * and selecting the appropriate wrappers for the resulting
+ * Object.
+ */
+ public void compareSnapshots(File expected, File actual) {
+ try {
+ // construct the respective trees
+ FileInputStream efStream = new FileInputStream(expected);
+ ObjectInputStream eStream = new ObjectInputStream(efStream);
+ FileInputStream afStream = new FileInputStream(actual);
+ ObjectInputStream aStream = new ObjectInputStream(afStream);
+ Object expectedObject = eStream.readObject();
+ Object actualObject = aStream.readObject();
+ Class expectedObjectClass = (null == expectedObject ? null : expectedObject.getClass());
+ Class actualObjectClass = (null == actualObject ? null : actualObject.getClass());
+ // todo yuck: switch by type using known factories
+// XXX compiler
+// if (StructureNode.class.isAssignableFrom(expectedObjectClass)) {
+// if (StructureNode.class.isAssignableFrom(actualObjectClass)) {
+// compareSnapshots((StructureNode) expectedObject,(StructureNode) actualObject);
+// System.err.println("ok");
+// } else {
+// signalDifferentTypes(expectedObject, actualObject);
+// }
+// } else if (DefaultMutableTreeNode.class.isAssignableFrom(expectedObjectClass)) {
+// if (DefaultMutableTreeNode.class.isAssignableFrom(actualObjectClass)) {
+// compareSnapshots((DefaultMutableTreeNode) expectedObject,
+// (DefaultMutableTreeNode) actualObject);
+// } else {
+// signalDifferentTypes(expectedObject, actualObject);
+// }
+// } else {
+ System.err.println("Unrecognized objects - expected: "
+ + expectedObject + " actual: " + actualObject);
+// }
+ } catch (Throwable t) {
+ System.err.println("TEST FAILED: " + t.getMessage());
+ t.printStackTrace(System.err);
+ return;
+ }
+ } // compareSnapshots(File, File)
+
+ public void signalDifferentTypes(Object lhs, Object rhs) {
+ Class lhc = lhs.getClass();
+ Class rhc = rhs.getClass();
+ String err = "Different Types? lhs: " + lhc + "=" + lhs
+ + " rhs: " + rhc + "=" + rhs;
+ throw new Error(err);
+ }
+
+ /**
+ * Compare two StructureNode by wrapping in GenericTreeNode
+ */
+// XXX compiler
+// public void compareSnapshots(StructureNode expected, StructureNode actual) {
+// try {
+// GenericTreeNodeFactoryI factory =
+// StructureGenericTreeNodeFactory.SINGLETON;
+// // this is the custom part: adapter generating generic model
+// GenericTreeNode expectRoot
+// = factory.createGenericTreeNode(expected, null);
+// GenericTreeNode actualRoot
+// = factory.createGenericTreeNode(actual, null);
+// if (null == actualRoot) System.err.println("null actualRoot");
+// if (null == expectRoot) System.err.println("null expectRoot");
+// compareSnapshots(expectRoot, actualRoot);
+// } catch (Throwable t) {
+// System.err.println("TEST FAILED: " + t.getMessage());
+// t.printStackTrace(System.err);
+// return;
+// }
+// } // compareSnapshots(TreeModel, TreeModel)
+
+ /**
+ * Compare two Swing TreeModel by wrapping in GenericTreeNode
+ */
+ public void compareSnapshots(TreeNode expected, TreeNode actual) {
+ try {
+ GenericTreeNodeFactoryI factory =
+ JTreeNodeGenericTreeNodeFactory.SINGLETON;
+ // this is the custom part: adapter generating generic model
+ GenericTreeNode expectRoot
+ = factory.createGenericTreeNode(expected, null);
+ GenericTreeNode actualRoot
+ = factory.createGenericTreeNode(actual, null);
+ if (null == actualRoot) System.err.println("null actualRoot");
+ if (null == expectRoot) System.err.println("null expectRoot");
+ compareSnapshots(expectRoot, actualRoot);
+ } catch (Throwable t) {
+ System.err.println("TEST FAILED: " + t.getMessage());
+ t.printStackTrace(System.err);
+ return;
+ }
+ } // compareSnapshots(TreeModel, TreeModel)
+
+ /** Compare GenericTreeNode trees exactly, printing errors */
+ public void compareSnapshots(GenericTreeNode expected, GenericTreeNode actual) {
+ try {
+ //GenericTreeNodesVisitorI visitor = GenericTreeNode.PRINTALL;
+ GenericTreeNodesVisitorI visitor = GenericTreeNode.PRINTERR;
+ //GenericTreeNodesVisitorI visitor = GenericTreeNode.EXACT;
+
+ if (GenericTreeNode.traverse(expected, actual, null, visitor)) {
+ System.err.println("TEST PASSED");
+ } else {
+ System.err.println("TEST FAILED");
+ }
+ } catch (Throwable t) {
+ System.err.println("TEST FAILED: " + t.getMessage());
+ t.printStackTrace(System.err);
+ return;
+ }
+ } // compareSnapshots(GenericTreeNode, GenericTreeNode)
+} // TreeCompare
+
diff --git a/aspectj-attic/testing-src/org/aspectj/testing/compare/adapters/GenericTreeNodeFactoryI.java b/aspectj-attic/testing-src/org/aspectj/testing/compare/adapters/GenericTreeNodeFactoryI.java
new file mode 100644
index 000000000..adee3d3ee
--- /dev/null
+++ b/aspectj-attic/testing-src/org/aspectj/testing/compare/adapters/GenericTreeNodeFactoryI.java
@@ -0,0 +1,33 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 2002 Palo Alto Research Center, Incorporated (PARC).
+ * 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:
+ * Xerox/PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.testing.compare.adapters;
+
+import org.aspectj.testing.compare.GenericTreeNode;
+/**
+ * Encapsulate the implementation of an factory to create
+ * a GenericTreeNode tree from a given input type, to permit
+ * a general, pluggable factory to operate based on source type.
+ */
+public interface GenericTreeNodeFactoryI {
+ /** @return the expected Class of the root node supported by this factory */
+ public Class getRootClass();
+
+ /**
+ * Create a wrapped generic tree with the input root tree as delegates.
+ * @param root the {rootClass} root of the tree to convert - never null
+ * @throws IllegalArgumentException if root is null or not assignable to rootClass
+ */
+ public GenericTreeNode createGenericTreeNode(Object root, GenericTreeNode parent);
+}
+
diff --git a/aspectj-attic/testing-src/org/aspectj/testing/compare/adapters/JTreeNodeGenericTreeNodeFactory.java b/aspectj-attic/testing-src/org/aspectj/testing/compare/adapters/JTreeNodeGenericTreeNodeFactory.java
new file mode 100644
index 000000000..5f48eef40
--- /dev/null
+++ b/aspectj-attic/testing-src/org/aspectj/testing/compare/adapters/JTreeNodeGenericTreeNodeFactory.java
@@ -0,0 +1,102 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 2002 Palo Alto Research Center, Incorporated (PARC).
+ * 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:
+ * Xerox/PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.testing.compare.adapters;
+
+import org.aspectj.testing.compare.GenericTreeNode;
+import org.aspectj.testing.compare.*;
+
+import javax.swing.tree.*; // sample uses TreeModel...
+import java.util.*;
+
+/**
+ * Factory for adapting Swing TreeNode to GenericTreeNode
+ */
+public class JTreeNodeGenericTreeNodeFactory implements GenericTreeNodeFactoryI {
+ public static final GenericTreeNodeFactoryI SINGLETON
+ = new JTreeNodeGenericTreeNodeFactory();
+ private JTreeNodeGenericTreeNodeFactory() {}
+ public Class getRootClass() {
+ return TreeNode.class;
+ }
+
+ /**
+ * Adapt swing TreeModel to tree rooted at GenericTreeNode
+ * Only takes the current state of a TreeModel which does not
+ * change during the construction of the adapter. If the
+ * TreeModel changes, you can ask the adapter for a newly
+ * wrapped tree.
+ * Recursively convert entire tree from root to a wrapped tree
+ * Note this takes a snapshot of the tree such that changes to
+ * the TreeModel after the constructor returns are ignored.
+ * Changes during the constructor produce undetermined results.
+ * @param root the TreeNode taken as root of a tree to wrap
+ * @param parent the parent of the resulting GenericTreeNode
+ * @throws IllegalArgumentException if root is null
+ * or if children are not instanceof TreeNode.
+ */
+ public GenericTreeNode createGenericTreeNode(Object root, GenericTreeNode parent) {
+ if (null == root) {
+ throw new IllegalArgumentException("null root");
+ }
+ if (! (root instanceof TreeNode)) {
+ throw new IllegalArgumentException("not TreeNode: " + root);
+ }
+ TreeNode rootNode = (TreeNode) root;
+ final int numKids = rootNode.getChildCount();
+ ArrayList kids = new ArrayList(numKids);
+ Enumeration children = rootNode.children();
+ Object child;
+ GenericTreeNode result = new GenericTreeNode();
+ for (int i = 0; i < numKids; i++) {
+ if (! children.hasMoreElements()) {
+ throw new Error("(! children.hasNext())");
+ }
+ child = children.nextElement();
+ if (! (child instanceof TreeNode)) {
+ throw new Error("! (child instanceof TreeNode)): " + child );
+ }
+ kids.add(createGenericTreeNode((TreeNode) child, result));
+ }
+ //result.init(parent, GenericTreeNode.COMPARATOR, rootNode, kids, null);
+ result.init(parent, JTreeNodeComparator.SINGLETON, rootNode, kids, null);
+ return result;
+ }
+
+ /** Comparator for swing TreeNode todo convert from TreeNode to DefaultMutableTreeNode */
+ static class JTreeNodeComparator implements Comparator {
+ public static Comparator SINGLETON = new JTreeNodeComparator();
+ private JTreeNodeComparator () {}
+ public int compare(Object lhs, Object rhs) {
+ int result = CompareUtil.compare(lhs, rhs);
+ if (Integer.MAX_VALUE == result) {
+ Class lhClass = lhs.getClass() ;
+ Class rhClass = rhs.getClass() ;
+ if ((DefaultMutableTreeNode.class.isAssignableFrom(lhClass))
+ && (DefaultMutableTreeNode.class.isAssignableFrom(rhClass))) {
+ DefaultMutableTreeNode lh = (DefaultMutableTreeNode) lhs ;
+ DefaultMutableTreeNode rh = (DefaultMutableTreeNode) rhs ;
+ Object lhObject = lh.getUserObject();
+ Object rhObject = rh.getUserObject();
+ result = CompareUtil.compare(lhs, rhs);
+ if (Integer.MAX_VALUE == result) {
+ result = lhObject.toString().compareTo(rhObject.toString());
+ }
+ } else { // urk - broken unless wrapper
+ result = lhs.toString().compareTo(rhs.toString());
+ }
+ }
+ return result;
+ }
+ }
+}
diff --git a/aspectj-attic/testing-src/org/aspectj/testing/compare/adapters/Structure.java b/aspectj-attic/testing-src/org/aspectj/testing/compare/adapters/Structure.java
new file mode 100644
index 000000000..b669f7c6b
--- /dev/null
+++ b/aspectj-attic/testing-src/org/aspectj/testing/compare/adapters/Structure.java
@@ -0,0 +1,438 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 2002 Palo Alto Research Center, Incorporated (PARC).
+ * 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:
+ * Xerox/PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.testing.compare.adapters;
+
+import org.aspectj.testing.compare.GenericTreeNode;
+import org.aspectj.testing.compare.GenericTreeNodesVisitorI;
+import org.aspectj.testing.compare.GenericTreeNodeListOrdererFactoryI;
+import org.aspectj.testing.compare.GenericTreeNodeListOrdererI;
+import org.aspectj.testing.compare.adapters.StructureGenericTreeNodeFactory;
+
+// XXX compiler import org.aspectj.asm.StructureNode;
+// XXX wes move to ajde tests import org.aspectj.tools.ajde.StructureUtilities;
+
+import java.util.*;
+import java.io.*;
+
+/**
+ * Compare or print (serialized) structure tree/graph(s).
+ * Mostly thread-safe, except that (todo for now) PRINT_SINK is a mutable static
+ * variable settable by the arguments.
+ * See {@link #main(String[]) main} for usage.
+ */
+public class Structure {
+ // ---------------------------------- static fields
+ // PRINT_SINK as static permits static inner class singleton visitors to reflect output sink policy
+ /** WARNING: print sink changeable at runtime (affects all instances of class!) */
+ public static PrintStream PRINT_SINK = System.err;
+
+ /** singleton factory to sort by string */
+ protected static final GenericTreeNodeListOrdererFactoryI STRING_SORTER_FACTORY
+ = new StringSortFactory();
+ /** singleton factory to sort by string */
+ protected static final GenericTreeNodeListOrdererI STRING_SORTER
+ = new StringSort();
+ /** singleton to sort by string */
+ protected static final Comparator STRING_COMP = new StringComparator();
+ /** default visitor printer expects only one of pair and render each parent as tab */
+ protected static final GenericTreeNodesVisitorI PRINT_EACH = new PrintEach();
+ /** visitor printer prints long version of both input (todo: not redirected by toOut) */
+ protected static final GenericTreeNodesVisitorI PRINT_ALL = GenericTreeNode.PRINTALL;
+ /** visitor printer prints long version of both input if non-matching (todo: not redirected by toOut) */
+ protected static final GenericTreeNodesVisitorI PRINT_ERR = GenericTreeNode.PRINTERR;
+ /** parms: default list of files used if no files given */
+ public static final String DEFAULT_LST = "default.lst";
+ /** parms: default argument list if none given */
+ public static final String[] DEFAULT_ARGS = new String[]
+ { "-d" , "classes" , "-workingdir", "ajworkingdir", "-argfile", DEFAULT_LST};
+
+ // ---------------------------------- static methods
+ /**
+ * Print and/or compare Structure trees.
+ * One (actual) can be compiled at the same time;
+ * either (expected or actual) may be read in from a serialized tree.
+ * Supported arguments:
+ * <table>
+ * <tr><td>{ajc compiler args}</td>
+ * <td>The set of compiler arguments, to compile a new tree</td></tr>
+ * <tr><td>-expect {file}.ser</td>
+ * <td>The old Structure tree to read in and compare with new</td></tr>
+ * <tr><td>-actual {file}.ser</td>
+ * <td>The new Structure tree to read in (i.e., no compile)</td></tr>
+ * <tr><td>-save {file}.ser</td>
+ * <td>Serialize the results of the compile to {file}.ser.</td></tr>
+ * <tr><td>-printall</td>
+ * <td>Print all pairs in long format</td></tr>
+ * <tr><td>-printeach</td>
+ * <td>Print each item in short format
+ * - used when only one tree is available</td></tr>
+ * <tr><td>-printerr</td>
+ * <td>Print pairs of items that do not match
+ * - used when only both trees are available</td></tr>
+ * <tr><td>-sortString</td>
+ * <td>before comparing, do a string-sort on each child list.</td></tr>
+ * <tr><td>-toOut</td>
+ * <td>Redirect output from System.err to System.out (for all instances of this class)</td></tr>
+ * <tr><td>-notest</td>
+ * <td>Do not run test (e.g., just compile and save)</td></tr>
+ * </table>
+ * @param args the String[] of arguments for this test - defaults supplied if empty.
+ */
+ public static void main(String[] args) {
+ new Structure().runTest(args);
+ }
+
+ // ---------------------------------- static util
+ protected static final void log(String s) {
+ final PrintStream sink = PRINT_SINK;
+ if ((null != s) && (null != sink)) {
+ sink.println("Structure: " + s);
+ }
+ }
+
+ protected static void signal(String message) {
+ log(message);
+ }
+ protected static void signal(String context, String event) {
+ log(context + ": " + event);
+ }
+ protected static void signal(String context, Throwable event) {
+ if (null == event) {
+ log(context);
+ } else {
+ String msg = event.getMessage();
+ log(context + ": " + msg);
+ event.printStackTrace(PRINT_SINK);
+ }
+ }
+
+ // ---------------------------------- instance fields
+ /** args result: path to serialize actual tree to */
+ protected String actualSavePath = null;
+ /** args result: path of actual serialized tree */
+ protected String actualPath = null;
+ /** args result: path of expected serialized tree */
+ protected String expectedPath = null;
+ /** args result: false if not running comparisons */
+ protected boolean doComparison = true;
+
+ /** visitor to run - print or test (default is PRINT_ALL) */
+ protected GenericTreeNodesVisitorI visitor = PRINT_ALL;
+ /** this determines for each set of children whether/how to sort them */
+ protected GenericTreeNodeListOrdererFactoryI sorter = null;
+
+ // ---------------------------------- instance methods
+ /** no-arg (default) constructor */
+ public Structure() { }
+
+ /**
+ * Clear settings before running.
+ * Use this unless you want to inherit settings from
+ * a prior run. You can specify new arguments that
+ * overwrite the old settings.
+ * @param args the String[] used for runTest(String[])
+ * @see #clear()
+ * @see #runTest(String[])
+ */
+ public synchronized void clearAndRunTest(String[] args) {
+ actualSavePath = null;
+ actualPath = null;
+ expectedPath = null;
+ doComparison = true;
+ visitor = PRINT_ALL;
+ runTest(args);
+ }
+
+ /**
+ * Read and/or write and/or compare structure trees.
+ * Any results are delivered by the comparison visitors.
+ * The test process is as follows:
+ * <li>processArgs(..)</li>
+ * <li>saveActual(..) if saving actual to file</li>
+ * <li>doComparison(..) of actual and expected per visitor/sorter options</li>
+ * <p>If you run this consecutively, you'll inherit the values
+ * of the last run that you do not overwrite
+ * unless you invoke {@link #clear()}. The method synchronization
+ * will not prevent another thread from interrupting your
+ * @param args the String[] defined by <code>main(String[] args)</code>
+ */
+ public synchronized void runTest(String[] args) {
+ if (null == args) throw new IllegalArgumentException("null args");
+ args = processArgs(args);
+ if (null == args) throw new IllegalArgumentException("bad args");
+// XXX compiler
+//// StructureNode lhsRoot = loadStructureNode(expectedPath);
+//// StructureNode rhsRoot = loadStructureNode(actualPath);
+//// if (null == rhsRoot) { // not serialized - try compile
+//// // XXX wes move to ajde tests rhsRoot = StructureUtilities.buildStructureModel(args);
+//// }
+//// // save actual, if requested
+//// saveActual(rhsRoot);
+//// // do comparison (i.e., run test)
+//// doComparison(lhsRoot, rhsRoot);
+ }
+
+ /**
+ * Process arguments by extracting our arguments from callee arguments
+ * and initializing the class accordingly.
+ * {@link See main(String[])} for a list of valid arguments.
+ * @param args the String[] adopted, elements shifted down to remove ours
+ * @return a String[] containing args not relevant to us (i.e., for callee = compiler)
+ */
+ protected String[] processArgs(String[] args) {
+ if ((null == args) || (1 > args.length)) {
+ return processArgs(DEFAULT_ARGS);
+ }
+ int numFiles = 0;
+ int numArgFiles = 0;
+ final String SKIP = "skip";
+ String calleeArg;
+ int readIndex = 0;
+ int writeIndex = 0;
+ while (readIndex < args.length) {
+ final String arg = args[readIndex];
+ calleeArg = arg;
+ // assume valid arg for callee unless shown to be ours
+ if ((null == arg) || (0 == arg.length())) {
+ signal("processArgs", "empty arg at index "+ readIndex);
+ break;
+ } else if (arg.startsWith("@") || "-argfile".equals(arg)) {
+ numArgFiles++;
+ } else if (arg.endsWith(".java")) {
+ numFiles++;
+ } else if (arg.startsWith("-")) {
+ calleeArg = SKIP; // assume args are ours unless found otherwise
+ if ("-toOut".equals(arg)) {
+ Structure.PRINT_SINK = System.out;
+ } else if ("-notest".equals(arg)) {
+ doComparison = false;
+ } else if ("-printall".equals(arg)) {
+ visitor = PRINT_ALL;
+ } else if ("-printeach".equals(arg)) {
+ visitor = PRINT_EACH;
+ } else if ("-printerr".equals(arg)) {
+ visitor = PRINT_ERR;
+ } else if ("-sortString".equals(arg)) {
+ sorter = STRING_SORTER_FACTORY;
+ } else { // the rest of ours require a parm
+ readIndex++;
+ String next = ((readIndex < args.length)
+ ? args[readIndex] : null);
+ boolean nextIsOption
+ = ((null != next) && next.startsWith("-"));
+ if ("-expect".equals(arg)) {
+ expectedPath = next;
+ } else if ("-actual".equals(arg)) {
+ actualPath = next;
+ } else if ("-save".equals(arg)) {
+ actualSavePath = next;
+ } else {
+ readIndex--;
+ calleeArg = arg; // ok, not ours - save
+ }
+ if ((calleeArg == SKIP)
+ && ((null == next) || (nextIsOption))) {
+ signal("processArgs", arg + " requires a parameter");
+ break;
+ }
+ }
+ }
+ if (SKIP != calleeArg) {
+ args[writeIndex++] = calleeArg;
+ }
+ readIndex++;
+ } // end of reading args[]
+ if (readIndex < args.length) { // bad args[] - abort (see signals above)
+ return null;
+ }
+ // if no input specified, supply default list file
+ if ((0 == numFiles) && (0 == numArgFiles) && (null == actualPath)) {
+ if (writeIndex+3 > args.length) {
+ String[] result = new String[writeIndex+2];
+ System.arraycopy(args, 0, result, 0, writeIndex);
+ args = result;
+ }
+ args[writeIndex++] = "-argfile";
+ args[writeIndex++] = DEFAULT_LST;
+ }
+ // if some args clipped (ours), clip array to actual (callee)
+ if (writeIndex < args.length) {
+ String[] result = new String[writeIndex];
+ System.arraycopy(args, 0, result, 0, writeIndex);
+ args = result;
+ }
+ return args;
+ } // processArgs(String[])
+
+// XXX compiler
+// /**
+// * Load any StructureNode tree at path, if possible
+// * @param path the String path to a serialized StructureNode
+// */
+// protected StructureNode loadStructureNode(String path) {
+// if (null == path) return null;
+// StructureNode result = null;
+// try {
+// FileInputStream stream = new FileInputStream(path);
+// ObjectInputStream ois = new ObjectInputStream(stream);
+// Object o = ois.readObject();
+// Class oClass = (null == o ? null : o.getClass());
+// if (StructureNode.class.isAssignableFrom(oClass)) {
+// result = (StructureNode) o;
+// } else {
+// signal("loadStructureNode(\"" + path
+// + "\") - wrong type: " + oClass);
+// }
+// } catch (Throwable t) {
+// signal("loadStructureNode(\"" + path + "\")", t);
+// }
+// return result;
+// }
+//
+// /**
+// * Save any StructureNode tree to actualSavePath, if possible
+// * @param actual the StructureNode root of the actual tree to save
+// * (ignored if null)
+// */
+// protected void saveActual(StructureNode actual) {
+// if ((null != actual) && (null != actualSavePath)) {
+// ObjectOutputStream p = null;
+// FileOutputStream ostream = null;
+// try {
+// ostream = new FileOutputStream(actualSavePath);
+// p = new ObjectOutputStream(ostream);
+// p.writeObject(actual);
+// } catch (Throwable e) {
+// signal("saveActual(\"" + actual + "\") -> "
+// + actualSavePath, e);
+// } finally {
+// try {
+// if (null != p) p.flush();
+// if (null != ostream) ostream.close();
+// } catch (IOException o) {} // ignored
+// }
+// }
+// }
+
+ /**
+ * Compare two trees based on the settings for
+ * the visitor and sorter. All results should be
+ * delivered by the visitor.
+ * @param expected the StructureNode actual tree to compare
+ * @param actual the StructureNode actual tree to compare
+ */
+ // XXX compiler
+// protected void doComparison(StructureNode expected, StructureNode actual) {
+// if (doComparison) {
+// final GenericTreeNodeFactoryI fact =
+// StructureGenericTreeNodeFactory.SINGLETON;
+// GenericTreeNode lhs = null;
+// if (expected != null) {
+// lhs = fact.createGenericTreeNode(expected, null);
+// }
+// GenericTreeNode rhs = null;
+// if (actual != null) {
+// rhs = fact.createGenericTreeNode(actual, null);
+// }
+// GenericTreeNode.traverse(lhs, rhs, sorter, visitor);
+// }
+// }
+
+ /**
+ * A visitor which prints each to the sink (if any).
+ * If only one of the pair is not null,
+ * render it using GenericTreeNode.shortString()
+ */
+ static class PrintEach implements GenericTreeNodesVisitorI {
+ private PrintEach() {}
+ public boolean visit(GenericTreeNode lhs,GenericTreeNode rhs) {
+ PrintStream sink = PRINT_SINK;
+ if (null != sink) {
+ if ((lhs != null) && (rhs != null)) { // both
+ sink.println("[lhs=" + lhs + "] [rhs=" + rhs + "]");
+ } else {
+ GenericTreeNode gtn = (null == lhs ? rhs : lhs);
+ if (null != gtn) { // one
+ sink.println(gtn.shortString());
+ }
+ }
+ }
+ return true;
+ }
+ } // class PrintEach
+
+ static class StringSortFactory implements GenericTreeNodeListOrdererFactoryI {
+ /**
+ * Produce the correct orderer for the children of the given GenericTreeNodes
+ * This always produces the same StringSorter.
+ * @return GenericTreeNodeListOrdererI for children, or null if none to be used
+ */
+ public GenericTreeNodeListOrdererI produce(GenericTreeNode lhs, GenericTreeNode rhs,
+ GenericTreeNodesVisitorI visitor) {
+ return STRING_SORTER;
+ }
+ } // class StringSortFactory
+
+ /**
+ * sort input lists by Comparator <code>Structure.STRING_COMP</code>.
+ */
+ static class StringSort implements GenericTreeNodeListOrdererI {
+ /**
+ * Order input lists (not copies)
+ * using the Comparator <code>Structure.STRING_COMP</code>.
+ * @param lhs the List representing the left-hand-side
+ * which contains only GenericTreeNode
+ * @param rhs the List representing the right-hand-side
+ * which contains only GenericTreeNode
+ * @return two lists List[] (0 => lhs, 1 => rhs)
+ */
+ public List[] produceLists(List lhs, List rhs) {
+ if (null != lhs) Collections.sort(lhs, STRING_COMP);
+ if (null != rhs) Collections.sort(rhs, STRING_COMP);
+ List[] result = new List[2];
+ result[0] = lhs;
+ result[1] = rhs;
+ return result;
+ }
+ } // class CompSort
+
+ /**
+ * Comparator that imposes case-sensitive String order
+ * based on GenericTreeNode.shortString() if both are
+ * GenericTreeNode, or toString() otherwise.
+ * If both are null, considered equal.
+ * If one is null, the other is considered larger.
+ */
+ static class StringComparator implements Comparator {
+ public int compare(Object lhs, Object rhs) {
+ if (null == lhs) {
+ return (null == rhs ? 0 : -1);
+ } else if (null == rhs) {
+ return 1;
+ } else if ((lhs instanceof GenericTreeNode)
+ && (rhs instanceof GenericTreeNode)) {
+ String lhsString = ((GenericTreeNode) lhs).shortString();
+ String rhsString = ((GenericTreeNode) rhs).shortString();
+ if (null == lhsString) {
+ return (null == rhsString ? 0 : rhsString.compareTo(lhsString));
+ } else {
+ return lhsString.compareTo(rhsString);
+ }
+ } else {
+ return lhs.toString().compareTo(rhs.toString());
+ }
+ }
+ } // class StringComparator
+} // class Structure
+
diff --git a/aspectj-attic/testing-src/org/aspectj/testing/compare/adapters/StructureGenericTreeNodeFactory.java b/aspectj-attic/testing-src/org/aspectj/testing/compare/adapters/StructureGenericTreeNodeFactory.java
new file mode 100644
index 000000000..1f5883d2c
--- /dev/null
+++ b/aspectj-attic/testing-src/org/aspectj/testing/compare/adapters/StructureGenericTreeNodeFactory.java
@@ -0,0 +1,308 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 2002 Palo Alto Research Center, Incorporated (PARC).
+ * 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:
+ * Xerox/PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.testing.compare.adapters;
+//
+//import org.aspectj.asm.SourceLocation;
+import org.aspectj.testing.compare.GenericTreeNode;
+//import org.aspectj.testing.compare.*;
+//import org.aspectj.asm.StructureNode;
+//import org.aspectj.asm.LinkNode;
+//import org.aspectj.asm.RelationNode;
+//import org.aspectj.asm.Relation;
+//import org.aspectj.asm.ProgramElementNode;
+//import java.util.*;
+//
+///**
+// * Factory for adapting StructureNode trees to GenericTreeNode
+// */
+// XXX compiler
+public class StructureGenericTreeNodeFactory implements GenericTreeNodeFactoryI {
+ public GenericTreeNode createGenericTreeNode(Object root,
+ GenericTreeNode parent) {
+ return null;
+ }
+ /**
+ * @see org.aspectj.testing.compare.adapters.GenericTreeNodeFactoryI#getRootClass()
+ */
+ public Class getRootClass() {
+ return null;
+ }
+
+}
+// protected static final String[] MODIFIERS = new String[]
+// { "strictfp", "abstract", "synchronized", "native",
+// "final", "transient", "static", "volatile" };
+// protected static final List MODIFIERS_LIST = Arrays.asList(MODIFIERS);
+// protected static final String[] ACCESS = new String[]
+// { "private", "protected", "package", "public", "privileged" };
+// protected static final List ACCESS_LIST = Arrays.asList(ACCESS);
+//
+// /** represent empty list of children (todo: use immutable instead) */
+// public static final List EMPTY_LIST = new ArrayList();
+// public static final GenericTreeNodeFactoryI SINGLETON
+// = new StructureGenericTreeNodeFactory();
+// /** delegate of the factory */
+// private static final Comparator NODE_COMPARATOR;
+//
+// static {
+// SubTypeComparator init = new SubTypeComparator();
+// init.addComparator(LinkNode.class, LinkNodeComparator.SINGLETON);
+// init.addComparator(RelationNode.class, RelationNodeComparator.SINGLETON);
+// init.addComparator(ProgramElementNode.class, ProgramElementNodeComparator.SINGLETON);
+// init.addComparator(StructureNode.class, StructureNodeComparator.SINGLETON);
+// GenericTreeNodeComparator gtnc = new GenericTreeNodeComparator(init);
+// NODE_COMPARATOR = gtnc;
+// }
+//
+// private StructureGenericTreeNodeFactory() {}
+// public Class getRootClass() {
+// return StructureNode.class;
+// }
+//
+// /**
+// * Adapt Structure model to tree rooted at GenericTreeNode.
+// * Only takes the current state of a model which does not
+// * change during the construction of the adapter. If the
+// * model changes, you can ask the adapter for a newly
+// * wrapped tree.
+// * @param root the TreeNode taken as root of a tree to wrap
+// * @param parent the parent of the resulting GenericTreeNode
+// * @throws IllegalArgumentException if root is null
+// * or if children are not instanceof TreeNode.
+// */
+// public GenericTreeNode createGenericTreeNode(Object root,
+// GenericTreeNode parent) {
+// if (null == root) {
+// throw new IllegalArgumentException("null root");
+// }
+// if (! (root instanceof StructureNode)) {
+// throw new IllegalArgumentException("not StructureNode: " + root);
+// }
+// GenericTreeNode result = new GenericTreeNode();
+// StructureNode rootNode = (StructureNode) root;
+// List kidList = rootNode.getChildren();
+// List kids = EMPTY_LIST;
+// // get kids of result
+// if (null != kidList) {
+// final int numKids = kidList.size();
+// ArrayList newKids = new ArrayList(numKids);
+// ListIterator kidIter = kidList.listIterator();
+// Object child;
+// for (int i = 0; i < numKids; i++) {
+// if (! kidIter.hasNext()) { // items removed from list while iterating
+// throw new Error("(! hasNext())");
+// }
+// child = kidIter.next();
+// if (! (child instanceof StructureNode)) {
+// throw new Error("! (child instanceof StructureNode)): " + child );
+// }
+// newKids.add(createGenericTreeNode((StructureNode) child, result));
+// }
+// kids = newKids;
+// }
+// // todo: select comparator here - avoids type checking at run time
+// //result.init(parent, StructureComparator.SINGLETON, rootNode, kids, null);
+// result.init(parent, NODE_COMPARATOR, rootNode, kids, null);
+// return result;
+// }
+//
+// /** Comparator for GenericTreeNode delegates to handler for nodes... */
+// static final class GenericTreeNodeComparator implements Comparator {
+// private final Comparator delegate;
+// private GenericTreeNodeComparator (Comparator delegate) {
+// this.delegate = delegate;
+// }
+// public final int compare(Object lhs, Object rhs) {
+// return delegate.compare(((GenericTreeNode)lhs).getNode()
+// , ((GenericTreeNode)lhs).getNode());
+// }
+// }
+//
+// /**
+// * Comparator for RelationNode delegates to String & boolean comparison of public attributes.
+// */
+// static class RelationNodeComparator implements Comparator {
+// public static Comparator SINGLETON = new RelationNodeComparator();
+// private RelationNodeComparator () {}
+// /**
+// * Comparator for RelationNode uses String & boolean comparison of public attributes
+// * forwardNavigationName, backNavigationName, associationName, symmetrical, associative.
+// */
+// public int compare(Object lhs, Object rhs) {
+// int result = CompareUtil.compare(lhs, rhs);
+// if (Integer.MAX_VALUE == result) {
+// RelationNode lh = (RelationNode) lhs ;
+// RelationNode rh = (RelationNode) rhs ;
+// Relation leftRelation = lh.getRelation();
+// Relation rightRelation = rh.getRelation();
+// String left = null;
+// String right = null;
+// result = CompareUtil.compare(leftRelation, rightRelation);
+// if (0 == result) {
+// left = leftRelation.getForwardNavigationName();
+// right = rightRelation.getForwardNavigationName();
+// result = CompareUtil.compare(left, right);
+// }
+// if (0 == result) {
+// left = leftRelation.getBackNavigationName();
+// right = rightRelation.getBackNavigationName();
+// result = CompareUtil.compare(left, right);
+// }
+// if (0 == result) {
+// left = leftRelation.getAssociationName();
+// right = rightRelation.getAssociationName();
+// result = CompareUtil.compare(left, right);
+// }
+// boolean l = false;
+// boolean r = false;
+// if (0 == result) {
+// l = leftRelation.isSymmetrical();
+// r = rightRelation.isSymmetrical();
+// result = CompareUtil.compare(l, r);
+// }
+// if (0 == result) {
+// l = leftRelation.isTransitive();
+// r = rightRelation.isTransitive();
+// result = CompareUtil.compare(l, r);
+// }
+// }
+// return result;
+// }
+// }
+//
+// /** Comparator for ProgramElementNode. */
+// static class ProgramElementNodeComparator implements Comparator {
+// public static Comparator SINGLETON = new ProgramElementNodeComparator();
+// private ProgramElementNodeComparator () {}
+// public int compare(Object lhs, Object rhs) {
+// int result = CompareUtil.compare(lhs, rhs);
+// if (Integer.MAX_VALUE == result) {
+// ProgramElementNode lh = (ProgramElementNode) lhs ;
+// ProgramElementNode rh = (ProgramElementNode) rhs ;
+//
+// boolean rhStmntKind = rh.isCode();
+// boolean lhStmntKind = lh.isCode();
+// if (lhStmntKind != rhStmntKind) {
+// return (lhStmntKind ? 1 : -1);
+// }
+// String left= lh.getKind();
+// String right= rh.getKind();
+// // boilerplate
+// result = CompareUtil.compare(left, right);
+// if (Integer.MAX_VALUE == result) {
+// result = left.compareTo(right);
+// if (0 != result) return result;
+// }
+// right = rh.getSignature();
+// left = lh.getSignature();
+// result = CompareUtil.compare(left, right);
+// if (Integer.MAX_VALUE == result) {
+// result = left.compareTo(right);
+// if (0 != result) return result;
+// }
+// List rightList = rh.getModifiers();
+// List leftList = lh.getModifiers();
+// result = CompareUtil.compare(leftList, rightList, MODIFIERS_LIST);
+// if (0 != result) return result;
+//
+// result = compare(rh.getAccessibility(), lh.getAccessibility());
+// if (0 != result) return result;
+//
+// right = rh.getDeclaringType();
+// left = lh.getDeclaringType();
+// result = CompareUtil.compare(left, right);
+// if (Integer.MAX_VALUE == result) {
+// result = left.compareTo(right);
+// if (0 != result) return result;
+// }
+//
+// SourceLocation leftSourceLocation = rh.getSourceLocation();
+// SourceLocation rightSourceLocation = rh.getSourceLocation();
+// int iright= rightSourceLocation.getLineNumber();
+// int ileft= leftSourceLocation.getLineNumber();
+// if (iright != ileft) return (ileft-iright);
+// iright= rightSourceLocation.getColumnNumber();
+// ileft= leftSourceLocation.getColumnNumber();
+// if (iright != ileft) return (ileft-iright);
+//
+// right= rh.getFormalComment();
+// left= lh.getFormalComment();
+// if (Integer.MAX_VALUE == result) {
+// result = left.compareTo(right);
+// if (0 != result) return result;
+// }
+//
+// right = rh.toString(); // ignored? super
+// left = lh.toString(); // ignored? super
+// if (Integer.MAX_VALUE == result) {
+// result = left.compareTo(right);
+// if (0 != result) return result;
+// }
+// // ignore source file path - may change?
+// // lhSourceFilePath = lh.getSourceFilePath(); // ignored
+// // lh.sourceFilePath = lh.getSourceFilePath(); // ignored
+// // List rhRelations= rh.getRelations() ; // ignored
+// // List lhRelations= lh.getRelations(); // ignored
+// return 0;
+// }
+// return result;
+// }
+// }
+//
+// /** Comparator for LinkNode. */
+// static class LinkNodeComparator implements Comparator {
+// public static Comparator SINGLETON = new LinkNodeComparator();
+// private LinkNodeComparator () {}
+// public int compare(Object lhs, Object rhs) {
+// int result = CompareUtil.compare(lhs, rhs);
+// if (Integer.MAX_VALUE == result) {
+// LinkNode lh = (LinkNode) lhs ;
+// LinkNode rh = (LinkNode) rhs ;
+// // LinkNode only has child and lexical name in toString
+// result = lh.toString().compareTo(rh.toString());
+// }
+// return result;
+// }
+// } // class LinkNodeComparator
+//
+// /**
+// * Comparator for StructureNode.
+// * <li>todo: implement comparators for each StructureNode subtype</li>
+// */
+// static class StructureNodeComparator implements Comparator {
+// public static Comparator SINGLETON = new StructureNodeComparator();
+// private StructureNodeComparator () {}
+// public int compare(Object lhs, Object rhs) {
+// int result = CompareUtil.compare(lhs, rhs);
+// if (Integer.MAX_VALUE == result) {
+// Class lhClass = lhs.getClass() ;
+// Class rhClass = rhs.getClass() ;
+// if ((StructureNode.class.isAssignableFrom(lhClass))
+// && (StructureNode.class.isAssignableFrom(rhClass))) {
+// StructureNode lh = (StructureNode) lhs ;
+// StructureNode rh = (StructureNode) rhs ;
+// Object lhObject = lh.getName(); // todo: weak name-based comparison
+// Object rhObject = rh.getName();
+// result = CompareUtil.compare(lhs, rhs);
+// if (Integer.MAX_VALUE == result) {
+// result = lhObject.toString().compareTo(rhObject.toString());
+// }
+// } else { // urk - broken unless wrapper
+// result = lhs.toString().compareTo(rhs.toString());
+// }
+// }
+// return result;
+// }
+// }
+//}
diff --git a/aspectj-attic/testing-src/org/aspectj/testing/compare/adapters/SubTypeComparator.java b/aspectj-attic/testing-src/org/aspectj/testing/compare/adapters/SubTypeComparator.java
new file mode 100644
index 000000000..3094fdb64
--- /dev/null
+++ b/aspectj-attic/testing-src/org/aspectj/testing/compare/adapters/SubTypeComparator.java
@@ -0,0 +1,224 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 2002 Palo Alto Research Center, Incorporated (PARC).
+ * 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:
+ * Xerox/PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.testing.compare.adapters;
+
+import org.aspectj.testing.compare.CompareUtil;
+import java.util.Comparator;
+
+// for testing code
+import java.util.*;
+import java.text.Collator;
+
+/**
+ * This adopts pairs of [Class, Comparator]
+ * and implements compare by delegation thereto,
+ * selecting the first added where the classes of the both inputs
+ * are assignable to the pair Class.
+ * It first applies the null-semantics of CompareUtil.compare(..),
+ * which holds that null values are less-than non-null values,
+ * and that two nulls are equal.
+ * Note that this class uses Object.equals(..)'s default reference
+ * equality, so two SubTypeComparator with the same list
+ * of delegates will NOT be considered equal.
+ * <p>todo: This class is not thread-safe.
+ * <p>todo: immutable: final list copy on construction to implement equals??
+ */
+public class SubTypeComparator implements Comparator {
+ /** order-sensitive comparators collection */
+ private Vector comparators;
+ /** copy of comparators for compare method */
+ private Struct[] cache;
+
+ /** default constructor */
+ public SubTypeComparator () {
+ comparators = new Vector();
+ }
+
+ /**
+ * Return true if the Class is in the list of comparators
+ * as of the initial execution of the method.
+ * @param c the Class to look for a comparator
+ * @return true of comparator exists for c
+ */
+ private boolean contains(Class c) {
+ final int size = comparators.size();
+ for (int i = 0; i < size; i++) {
+ if (c == ((Struct) comparators.elementAt(i)).accepts) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Get copy of comparators for compare operation.
+ */
+ private Struct[] getComparators() { // todo: sync on comparators
+ if ((null == cache) || (cache.length < comparators.size())) {
+ cache = new Struct[comparators.size()];
+ comparators.copyInto(cache);
+ }
+ return cache;
+ }
+
+ /**
+ * Add a Class, Comparator pair as delegate when
+ * both input are assignable to Class.
+ * Note that additions are checked in the order they are added,
+ * so add the lowest subtypes first. (i.e., if you add
+ * a comparator for Class Object first, none of the others
+ * will ever match.)
+ * @param accepts the Class supertype of objects to accept
+ * @param comparator the Comparator to use on such objects
+ * @return false if not added, because either input is null
+ * or because the Class is represented already.
+ */
+ public final boolean addComparator(Class accepts, Comparator comparator) {
+ if ((null == accepts) || (null == comparator)
+ || (contains(accepts))) {
+ return false;
+ }
+ comparators.addElement(new Struct(accepts, comparator));
+ return true;
+ }
+
+ /**
+ * This implements compare by delegating
+ * to the first input Comparator
+ * where the class of the both input
+ * is assignable to the pair Class.
+ * It first enforces the null-semantics of CompareUtil.compare(..).
+ * @throws ClassCastException if both input are not null and
+ * they are not assignable to any registered Comparator.
+ */
+ public final int compare(Object lhs, Object rhs) {
+ int result = CompareUtil.compare(lhs, rhs);
+ if (Integer.MAX_VALUE == result) {
+ Class lhClass = lhs.getClass() ;
+ Class rhClass = rhs.getClass() ;
+ Struct[] comp = getComparators();
+ Class compClass;
+ for (int i = 0; i < comp.length; i++) {
+ compClass = comp[i].accepts;
+ if ((compClass.isAssignableFrom(lhClass))
+ && (compClass.isAssignableFrom(lhClass))) {
+ return comp[i].comparator.compare(lhs, rhs);
+ }
+ }
+ // not found - throw ClassCastException
+ String mssg = "Unable to find Comparator for "
+ + "lhs Class: " + lhClass.getName()
+ + " rhs Class: " + rhClass.getName();
+ throw new ClassCastException(mssg);
+ }
+ return result;
+ }
+
+ /**
+ * (unnecessary) Struct to hold class-comparator pair
+ * is preparation for using collections
+ */
+ static class Struct {
+ public final Class accepts;
+ public final Comparator comparator;
+ /**
+ * @param accepts the Class to accept input for - not null
+ * @param comparator the Comparator to compare input with - not null
+ */
+ public Struct(Class accepts,Comparator comparator) {
+ this.accepts = accepts;
+ this.comparator = comparator;
+ }
+ /** delegate to accept hashcode */
+ public int hashCode() { return accepts.hashCode() ; }
+ /** WARNING: fast comparison based only on accept key reference identity */
+ public boolean equals(Object o) {
+ return ((null != o) && (o instanceof Struct)
+ && (accepts == ((Struct)o).accepts));
+ }
+ } // class Struct
+
+ //----------------------------------------------- test code
+ /** test code */
+ static class Test { // todo move elsewhere
+ public void runTest(String[] args) {
+ if ((null == args) || (1 > args.length)) {
+ args = new String[] { "one", "two", "THREE", "FOUR", "fIVE", "6" };
+ }
+ SubTypeComparator me = new SubTypeComparator();
+ String[] copy = new String[args.length];
+ System.arraycopy(args, 0, copy, 0, copy.length);
+ List list = Arrays.asList(args);
+ Throwable result = test(me, list);
+ if ((null == result)
+ && (!ClassCastException.class.isAssignableFrom(result.getClass()))) {
+ System.err.println("FAIL: expected cce: " + result);
+ }
+ me.addComparator(String.class, Collator.getInstance());
+ me.addComparator(Object.class, new Comparator () {
+ public int compare (Object lhs, Object rhs) {
+ throw new Error("never used");
+ }});
+ result = test(me, list);
+ if (null != result) {
+ if (ClassCastException.class.isAssignableFrom(result.getClass())) {
+ System.err.println("FAIL: unexpected cce: " + result);
+ } else {
+ System.err.println("FAIL: unexpected Throwable: " + result);
+ }
+ }
+ // heterogeneous - pick Object
+ Object[] temp = new Object[] { "string", new Integer(1) };
+ result = test(me, Arrays.asList(temp));
+ if ((null == result)
+ && (!Error.class.isAssignableFrom(result.getClass()))) {
+ System.err.println("FAIL: expected Error: " + result);
+ }
+
+ StringBuffer toPrint = print(Arrays.asList(copy), null);
+ toPrint.append("\n");
+ print(list, toPrint);
+ System.err.println(toPrint.toString());
+ }
+
+ StringBuffer print(List list, StringBuffer sb) {
+ if (null == sb) sb = new StringBuffer();
+ sb.append("[");
+ ListIterator iter = list.listIterator();
+ while (iter.hasNext()) {
+ sb.append(iter.next().toString());
+ if (iter.hasNext()) sb.append(", ");
+ }
+ sb.append("]");
+ return sb;
+ }
+
+ /**
+ * run comparison, return true if got expected exception
+ */
+ Throwable test(Comparator c, List l) {
+ try {
+ Collections.sort(l,c);
+ return null;
+ } catch (Throwable r) {
+ return r;
+ }
+ }
+ } // class Test
+
+ /** invoke Test.runTest(args) todo remove */
+ public static void main(String[] args) {
+ new Test().runTest(args);
+ }
+} // class SubTypeComparator
diff --git a/aspectj-attic/testing-src/org/aspectj/testing/compare/adapters/package.html b/aspectj-attic/testing-src/org/aspectj/testing/compare/adapters/package.html
new file mode 100644
index 000000000..c2d839ed1
--- /dev/null
+++ b/aspectj-attic/testing-src/org/aspectj/testing/compare/adapters/package.html
@@ -0,0 +1,50 @@
+<html>
+<body>
+These adapters facilitate using the GenericTreeNode
+comparison utilities on different types of trees.
+The classes currently in this package support Swing
+<code>TreeNode</code> and AspectJ compiler <code>StructureNode</code>.
+
+<p>
+<code>Structure</code> supports a command-line interface for
+compiling <code>StructureNode</code> trees using
+<code>AspectJCompiler</code> and saving
+or loading them using serialization. Once loaded, two trees
+can be compared using the <code>GenericTreeNode.traverse(..)</code> method,
+providing it the appropriate visitors and comparators to implement
+a comparison of the expected and actual structure trees and
+report on any differences. (This is used to validate that
+changes to the structure tree are backwards compatible with
+trees from previous compiles, since the structure tree is
+effectively exported from the compiler to the IDE tools.)
+
+<p>
+If you want to support new trees,
+<code>GenericTreeNodeFactoryI</code> is the interface to implement.
+It specifies a factory to provide a <code>Comparator</code> based
+on a given pair to be compared. This means that you can
+use (or generate) comparators based on specific pairs.
+Usually you will implement only for the target type,
+so your factory may be final and always return a
+singleton <code>Comparator.</code>
+<p>
+The <code>SubTypeComparator</code> implements a <code>Comparator</code>
+container that acts as a <code>Comparator</code> by delegating to
+contained <code>Comparator</code>s registered along with the class of the input
+they accept. This permits you to write type-specific
+<code>Comparator</code>s for heterogeneous trees. It does require
+both members of the comparison be assignable to the
+target class.
+
+<p>
+<code>StructureGenericTreeNodeFactory</code> is an implementation of
+<code>GenericTreeNodeFactoryI</code> for StructureNode trees. It
+contains comparator classes for <code>RelationNode</code>, <code>LinkNode,</code>
+and <code>ProgramElementNode</code>,
+combined using a <code>SubTypeComparator.</code>
+<p>
+<code>JTreeNodeGenericTreeNodeFactory</code> is an implementation of
+<code>GenericTreeNodeFactoryI</code> for Swing <code>TreeNode</code>'s, done only
+for testing purposes.
+</body>
+</html>
diff --git a/aspectj-attic/testing-src/org/aspectj/testing/compare/package.html b/aspectj-attic/testing-src/org/aspectj/testing/compare/package.html
new file mode 100644
index 000000000..6bfec163d
--- /dev/null
+++ b/aspectj-attic/testing-src/org/aspectj/testing/compare/package.html
@@ -0,0 +1,128 @@
+<html>
+<body>
+This package implements a general tree comparison as a
+special case of visiting generic trees pairwise.
+Trees are wrapped as <code>GenericTreeNode</code>, which has a static
+method <code>boolean traverse(..)</code> which accepts
+a visitor and traverses a pair of trees, calling the
+visitor on each.
+<p>This package supports four forms of generality
+through the following classes:
+<table border="+1">
+<tr><th>Classes</th>
+ <th>Capability</th></tr>
+<tr><td valign="top">GenericTreeNode</td>
+ <td>Able to handle trees of varying types
+ by wrapping in a generic form.<td>
+ </tr>
+<tr><td valign="top">GenericTreeNodesVisitorI, GenericTreeNode.traverse(..)</td>
+ <td>Can handle any type of pairwise visitor function
+ by accepting visitor in the traverse method.</td>
+ </tr>
+<tr><td valign="top">{java.util.Comparator}, GenericTreeNode.getComparator()</td>
+ <td>The object comparison can be sensitive to the type
+ of the object on a per-object basis, established during
+ the process of wrapping the tree.</td>
+ </tr>
+<tr><td valign="top">GenericTreeListOrdererI, GenericTreeListOrdererFactoryI</td>
+ <td>The ordering of children can be appropriate to
+ the objective of the traversal. e.g., when computing
+ "set intersection" rather than "list equals", the
+ order of children might be changed to align matching
+ children for the visits.
+ <br>This ordering can be determined as appropriate for each
+ list comparison by implementing a factory which selects
+ from the appropriate orderers. Any factory product is used
+ by the traverse(..) method to order children before
+ visiting.</td>
+ <td></td>
+ </tr>
+</table>
+
+<p><u>Supported variants</u>:
+The following variants are implemented or planned using the components above:
+<table border="1">
+<tr><th>Component</th><th>Description</th></tr>
+<tr><td colspan=2>Current</th></tr>
+<tr><td>GenericTreeNode.PRINTALL</td>
+ <td>A visitor which prints out the entire tree.</td></tr>
+<tr><td>GenericTreeNode.PRINTERR</td>
+ <td>A visitor which prints the nonmatching pairs.</td></tr>
+<tr><td>GenericTreeNode.EXACT</td>
+ <td>A visitor which returns false if any pairs do not match.</td></tr>
+<tr><td>TreeCompare</td>
+ <td>A sample program to read in serialized trees and compare them.
+ (but see Structure in the compare subpackage for a better example) </td></tr>
+<tr><td>CompareUtil</td>
+ <td>Misc comparison utilities (e.g., for short-circuiting comparisons).</td></tr>
+<tr><td colspan=2>Planned</th></tr>
+<tr><td>GenericTreeNode.KIDDIFF</td>
+ <td>A visitor which calculates tree differences, using ordering children
+ (catches swaps, missed or added elements, within children)</td></tr>
+<tr><td>GenericTreeNode.TREEDIFF</td>
+ <td>A visitor which calculates tree differences, accumulating the tree
+ (catches swaps, missed or added elements, throughout tree.)</td></tr>
+</table>
+
+<p><u>Use</u>:
+ Run TreeCompare to use the comparer from the command line on a supported tree,
+ (currently only the Swing TreeNode implemented as DefaultMutableTreeNode).
+
+<p><u>Programming</u>:<br>
+To support a new tree, see the Structure example in the compare subpackage
+or use example of the Swing TreeNode:
+<li>Write an adapter that uses GenericTreeNode to wrap your tree nodes</li>
+<li>Write a factory that produces a wrapped tree</li>
+<li>Write a Comparator that compares the underlying node object
+ to include with each node object wrapped. Be sure to implement
+ the Comparator.equals(Object) method correctly, i.e., returning
+ true when it is equivalent to another comparator. It is best
+ to use a singleton for each type of node you support. </li>
+<li>Optionally write a visitor to perform whatever operations you wish.
+ Note that visitors must tolerate a single null input in order to
+ completely traverse unmatching trees.</li>
+<li>To perform operations requiring preprocessing of child List's,
+ write children orderer(s) and provide a factory to select them.</li>
+
+<p>To design new algorithms/applications, bear in mind the main tools:
+<li>The comparator that follows the node object</li>
+<li>The visitor that traverses the tree </li>
+<li>The child orderer that may preprocess the child lists </li>
+<br>In particular, when going beyond pair-wise comparisons to
+ list-wise or tree-wise comparisons, you'll have to decide
+ where to put the appropriate logic. You may have a relatively
+ lightweight visitor and a heavyweight orderer, or no
+ orderer at all. In that case, you may need to invoke a
+ special method on your visitor after the traversal completes
+ to do any final processing.
+
+<h2>Future Work</h2>:
+<p><u>Smarter group comparisons</u>:
+<br>Does calculating maps help with diagnosing problems?
+<pre>
+Given two lists,
+ A [ a, b, c, d, e, f, g, h ]
+ B [ a, e, c, d, b, g, h ]
+The result should say:
+ - B swapped order of e and b
+ - B omitted f
+Note the match-map (index of matching element, if any):
+ A->B [ 0, 4, 2, 3, 1, -, 5, 6 ]
+ B->A [ 0, 4, 2, 3, 1, 6, 7 ]
+the shift-map (difference between expected and actual order):
+ A->B [ 0, 3, 0, 0, -3, -, -1, -1 ]
+ B->A [ 0, 3, 0, 0, -3, 1, 1 ]
+
+Thus:
+- detect swaps as complementary out-of-index order pairs
+ (todo: three-way or n-ary?)
+ - fix or ignore swaps
+- detect shifts as complementary series
+ where shift-width n is +/- for both
+ - -n =>
+ - if negative element is actual, n elements omitted
+ - if negative element is expected, n elements added
+<pre>
+
+</body>
+</html>
diff --git a/aspectj-attic/testing-src/org/aspectj/testing/taskdefs/CompareFiles.java b/aspectj-attic/testing-src/org/aspectj/testing/taskdefs/CompareFiles.java
new file mode 100644
index 000000000..fe1b760ac
--- /dev/null
+++ b/aspectj-attic/testing-src/org/aspectj/testing/taskdefs/CompareFiles.java
@@ -0,0 +1,103 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 2002 Palo Alto Research Center, Incorporated (PARC).
+ * 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:
+ * Xerox/PARC initial implementation
+ * ******************************************************************/
+
+
+package org.aspectj.testing.taskdefs;
+
+import java.io.File;
+import java.io.IOException;
+import org.apache.tools.ant.*;
+
+/**
+ * Wrap file comparison utility as ant taskdef.
+ * (Whitespace semantics track the String.trim() and StringTokenizer class.)
+ * <table>
+ * <tr><td>lhsFile</td><td>path to left-hand-side file to compare (required)</td></tr>
+ * <tr><td>rhsFile</td><td>path to right-hand-side file to compare (required)</td></tr>
+ * <tr><td>output</td><td>path to output file (System.out otherwise)</td></tr>
+ * <tr><td>ignoreCase</td><td>convert to uppercase before comparison (boolean yes/no)</td></tr>
+ * <tr><td>trimWhitespace</td><td>ignore leading/trailing white space(boolean yes/no)</td></tr>
+ * <tr><td>collapseWhitespace</td><td>convert all white space runs to a single space (boolean yes/no)</td></tr>
+ * <tr><td>filterSpec</td><td>all specifications for a filter, based on the RegexpFilter class
+ * (currently, syntax: <code>{file | {-i|-t|-b|-s <pattern>|-s <patternFile>}..}</code></td></tr>
+ * </table>
+ * @see org.aspectj.testing.compare.RegexpFilter#init(String[],RegexpFilter)
+ */
+public class CompareFiles extends org.apache.tools.ant.Task {
+ /*
+ Unable to implement multiple inheritance except by delegation:
+ - Task subclass must be outer or ant throws InstantiationException
+ - if/since outer, the subclass getter/setters cannot refer to
+ protected fields in worker superclass absent inner worker
+ subclass delegate methods. yuck.
+ - getting access errors when trying to use the RuntimeConfigurable
+ to initialize the task. Looking at the Ant code, it does not
+ appear to be used for tasks?? I found none using it and the
+ initialization seems wrong...
+ */
+ final private Worker worker;
+ public CompareFiles() {
+ worker = new Worker();
+ }
+ protected File lhsFile;
+ protected File rhsFile;
+ public void setLhsFile(File file) { lhsFile = file; }
+ public void setRhsFile(File file) { rhsFile = file; }
+ public void setOutput(File file) { worker.setOutput(file); }
+ public void setFilterSpec(String str) { worker.setFilterSpec(str); }
+ public void setCollapseWhitespace(boolean ok) { worker.setCollapseWhitespace(ok); }
+ public void setTrimWhitespace(boolean ok) { worker.setTrimWhitespace(ok); }
+ public void setIgnoreCase(boolean ok) { worker.setIgnoreCase(ok); }
+ public void execute() throws BuildException {
+ if (!lhsFile.canRead()) {
+ log("FAIL taskdefs.CompareFiles: bad lhsFile: " + lhsFile);
+ } else if (!rhsFile.canRead()) {
+ log("FAIL taskdefs.CompareFiles: bad rhsFile: " + rhsFile);
+ } else if (rhsFile.isDirectory() != lhsFile.isDirectory()) {
+ log("FAIL taskdefs.CompareFiles: both must be dirs."
+ + " lhsFile=" + lhsFile
+ + " rhsFile=" + rhsFile);
+ } else {
+ worker.dodiff(lhsFile, rhsFile);
+ }
+ }
+} // class CompareFiles
+
+/** worker class exposes state and converts Exception to BuildException */
+class Worker extends org.aspectj.testing.compare.CompareFiles {
+ String spec = null;
+ public void setOutput(File file) { output = file; }
+ public void setCollapseWhitespace(boolean ok) { collapseWhitespace = ok; }
+ public void setTrimWhitespace(boolean ok) { trimWhitespace = ok; }
+ public void setIgnoreCase(boolean ok) { ignoreCase = ok; }
+ public void setFilterSpec(String str) { spec = str; }
+ public void initFilter() {
+ if (null != spec) {
+ initFilter(spec, false);
+ }
+ }
+
+ public void dodiff(File lhsFile, File rhsFile) throws BuildException {
+ initFilter();
+ try {
+ super.diff(lhsFile, rhsFile);
+ } catch (IOException t) {
+ String s = t.getClass().getName() + ": " + t.getMessage();
+ throw new BuildException(s, t);
+ } catch (Throwable e) {
+ String s = e.getClass().getName() + ": " + e.getMessage();
+ throw new BuildException("Error - " + s, e);
+ }
+ }
+} // class CompareFiles$Worker
+