001: package com.reeltwo.jumble.fast;
002:
003: import java.io.Serializable;
004: import java.lang.reflect.Constructor;
005: import java.util.Comparator;
006:
007: import java.lang.reflect.InvocationTargetException;
008:
009: import com.reeltwo.jumble.util.ClassLoaderCloneable;
010:
011: /**
012: * A class indicating the order in which tests should be run. Contains an array
013: * of test classes and associates an ordering with tests.
014: *
015: * @author Tin Pavlinic
016: * @version $Revision: 496 $
017: */
018: public class TestOrder implements Serializable, ClassLoaderCloneable {
019:
020: /** Number for serialization */
021: private static final long serialVersionUID = 4401643897371182214L;
022:
023: /** Flag to turn debugging on and off */
024: public static final boolean DEBUG = true;
025:
026: /** The test classes used to produce this ordering */
027: private String[] mTestClasses;
028:
029: /**
030: * An array containing the indices of tests to run specifying the order in
031: * which to run them.
032: */
033: private int[] mOrder;
034:
035: /**
036: * Creates a new TestOrder with the specified test classes and no
037: * particular ordering.
038: *
039: * @param testClasses
040: */
041: public TestOrder(Class[] testClasses) {
042: this (testClasses, createOrdering(testClasses.length));
043: }
044:
045: /**
046: * Creates a new TestOrder with the specified test classes and runtimes.
047: *
048: * @param testClasses
049: * @param runtimes the runtimes of the tests.
050: */
051: public TestOrder(Class[] testClasses, long[] runtimes) {
052: this (testClasses, createOrdering(runtimes));
053: }
054:
055: /**
056: * Creates a new TestOrder with the specified test classes and ordering
057: *
058: * @param testClasses
059: * @param order order permuation
060: */
061: public TestOrder(Class[] testClasses, int[] order) {
062: mTestClasses = new String[testClasses.length];
063: for (int i = 0; i < testClasses.length; i++) {
064: mTestClasses[i] = testClasses[i].getName();
065: }
066:
067: mOrder = order;
068: }
069:
070: /**
071: * Constructor used to clone the object.
072: *
073: * @param testClasses string of test classes
074: * @param order order permuation
075: */
076: public TestOrder(String[] testClasses, int[] order) {
077: mTestClasses = testClasses;
078: mOrder = order;
079: }
080:
081: /** Creates a default ordering */
082: static int[] createOrdering(int length) {
083: int[] order = new int[length];
084: for (int i = 0; i < order.length; i++) {
085: order[i] = i;
086: }
087: return order;
088: }
089:
090: /** Creates an ordering based on the runtimes */
091: static int[] createOrdering(long[] runtimes) {
092: int[] order = new int[runtimes.length];
093:
094: SortPair[] sortPairs = new SortPair[runtimes.length];
095: for (int i = 0; i < sortPairs.length; i++) {
096: sortPairs[i] = new SortPair(i, runtimes[i]);
097: }
098:
099: java.util.Arrays.sort(sortPairs, new Comparator() {
100: public int compare(Object o1, Object o2) {
101: SortPair p1 = (SortPair) o1;
102: SortPair p2 = (SortPair) o2;
103:
104: if (p1.getTime() < p2.getTime()) {
105: return -1;
106: } else if (p1.getTime() == p2.getTime()) {
107: return 0;
108: } else {
109: return 1;
110: }
111: }
112: });
113: for (int i = 0; i < order.length; i++) {
114: order[i] = sortPairs[i].getPos();
115: //System.err.println("order[" + i + "]=" + order[i]);
116: }
117: return order;
118: }
119:
120: /**
121: * Clones this object using a different class loader to achieve
122: * class isolation. In our application, the classloader will mutate
123: * the class being tested.
124: *
125: * @param loader the new class loader
126: * @return a clone of <CODE>this</CODE> in the different class loader
127: */
128: public Object clone(ClassLoader loader)
129: throws ClassNotFoundException {
130:
131: Class clazz = loader.loadClass(getClass().getName());
132:
133: try {
134: Constructor c = clazz.getConstructor(new Class[] {
135: String[].class, int[].class });
136: return c.newInstance(new Object[] { mTestClasses, mOrder });
137: } catch (InstantiationException e) {
138: e.printStackTrace();
139: throw new ClassNotFoundException(
140: "Error invoking constructor");
141: } catch (InvocationTargetException e) {
142: e.printStackTrace();
143: throw new ClassNotFoundException(
144: "Error invoking constructor");
145: } catch (IllegalAccessException e) {
146: e.printStackTrace();
147: throw new ClassNotFoundException(
148: "Error invoking constructor");
149: } catch (NoSuchMethodException e) {
150: e.printStackTrace();
151: throw new ClassNotFoundException(
152: "Error invoking constructor");
153: }
154: }
155:
156: /**
157: * Returns the total number of tests.
158: *
159: * @return the number of tests.
160: */
161: public int getTestCount() {
162: return mOrder.length;
163: }
164:
165: /**
166: * Returns the index of the test in order <CODE>order</CODE>.
167: *
168: * @param order
169: * the ordered position of the test to run
170: * @return the index of the <CODE>order</CODE> th test
171: */
172: public int getTestIndex(int order) {
173: try {
174: return mOrder[order];
175: } catch (ArrayIndexOutOfBoundsException e) {
176: e.printStackTrace();
177: return -1;
178: }
179: }
180:
181: /**
182: * Gets the names of the test classes that were timed.
183: *
184: * @return the test classes
185: */
186: public String[] getTestClasses() {
187: return mTestClasses;
188: }
189:
190: /**
191: * Just a little structure used in the sorting of runtimes.
192: */
193: private static class SortPair {
194: private int mPos;
195:
196: private long mTime;
197:
198: public SortPair(int pos, long time) {
199: mPos = pos;
200: mTime = time;
201: }
202:
203: public int getPos() {
204: return mPos;
205: }
206:
207: public long getTime() {
208: return mTime;
209: }
210: }
211: }
|