diff options
Diffstat (limited to 'aspectj-attic/testing-src/org/aspectj/testing/compare/adapters')
6 files changed, 1155 insertions, 0 deletions
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> |