12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517 |
- /* *******************************************************************
- * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC),
- * 2003 Contributors.
- * All rights reserved.
- * This program and the accompanying materials are made available
- * under the terms of the Eclipse Public License v 2.0
- * which accompanies this distribution and is available at
- * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.txt
- *
- * Contributors:
- * Xerox/PARC initial implementation
- * Wes Isberg 2003 changes.
- * ******************************************************************/
-
- package org.aspectj.testing.drivers;
-
- import java.io.BufferedReader;
- import java.io.File;
- import java.io.FileReader;
- import java.io.IOException;
- import java.io.PrintStream;
- import java.io.PrintWriter;
- import java.text.DecimalFormat;
- import java.text.SimpleDateFormat;
- import java.util.ArrayList;
- import java.util.Arrays;
- import java.util.Collection;
- import java.util.Collections;
- import java.util.Date;
- import java.util.HashMap;
- import java.util.LinkedList;
- import java.util.List;
- import java.util.Map;
- import java.util.Map.Entry;
- import java.util.Properties;
- import java.util.Set;
- import java.util.StringTokenizer;
-
- import org.aspectj.bridge.IMessage;
- import org.aspectj.bridge.IMessageHolder;
- import org.aspectj.bridge.MessageHandler;
- import org.aspectj.bridge.MessageUtil;
- import org.aspectj.testing.harness.bridge.AbstractRunSpec;
- import org.aspectj.testing.harness.bridge.AjcTest;
- import org.aspectj.testing.harness.bridge.CompilerRun;
- import org.aspectj.testing.harness.bridge.FlatSuiteReader;
- import org.aspectj.testing.harness.bridge.IRunSpec;
- import org.aspectj.testing.harness.bridge.IncCompilerRun;
- import org.aspectj.testing.harness.bridge.JavaRun;
- import org.aspectj.testing.harness.bridge.RunSpecIterator;
- import org.aspectj.testing.harness.bridge.Sandbox;
- import org.aspectj.testing.harness.bridge.Validator;
- import org.aspectj.testing.run.IRun;
- import org.aspectj.testing.run.IRunIterator;
- import org.aspectj.testing.run.IRunListener;
- import org.aspectj.testing.run.IRunStatus;
- import org.aspectj.testing.run.IRunValidator;
- import org.aspectj.testing.run.RunListener;
- import org.aspectj.testing.run.RunStatus;
- import org.aspectj.testing.run.RunValidator;
- import org.aspectj.testing.run.Runner;
- import org.aspectj.testing.util.BridgeUtil;
- import org.aspectj.testing.util.RunUtils;
- import org.aspectj.testing.util.StreamsHandler;
- import org.aspectj.testing.util.StreamsHandler.Result;
- import org.aspectj.testing.xml.AjcSpecXmlReader;
- import org.aspectj.testing.xml.XMLWriter;
- import org.aspectj.util.FileUtil;
- import org.aspectj.util.LangUtil;
-
- /**
- * Test harness for running AjcTest.Suite test suites.
- * This can be easily extended by subclassing.
- * <ul>
- * <li>template algorithms for reading arguments, printing syntax,
- * reading suites, and reporting results all
- * delegate to methods that subclasses can override to support
- * additional arguments or different reporting.</li>
- * <li>implement arbitrary features as IRunListeners</li>
- * <li>support single-option aliases to any number of single-options </li>
- * </ul>
- * See {@link report(IRunStatus, int, int)} for an explanation of test result
- * categories.
- */
- public class Harness {
- /**
- * Spaces up to the width that an option should take in the syntax,
- * including the two-space leader
- */
- protected static final String SYNTAX_PAD = " ";
- protected static final String OPTION_DELIM = ";";
- private static final String JAVA_VERSION;
- private static final String ASPECTJ_VERSION;
- static {
- String version = "UNKNOWN";
- try { version = System.getProperty("java.version", "UNKNOWN"); }
- catch (Throwable t) {}
- JAVA_VERSION = version;
-
- version = "UNKNOWN";
- try {
- Class c = Class.forName("org.aspectj.bridge.Version");
- version = (String) c.getField("text").get(null);
- } catch (Throwable t) {
- // ignore
- }
- ASPECTJ_VERSION = version;
- }
-
- /** factory for the subclass currently anointed as default */
- public static Harness makeHarness() {
- return new FeatureHarness();
- }
-
- /** @param args String[] like runMain(String[]) args */
- public static void main(String[] args) throws Exception {
- if (LangUtil.isEmpty(args)) {
- File argFile = new File("HarnessArgs.txt");
- if (argFile.canRead()) {
- args = readArgs(argFile);
- } else {
- args = new String[] { "-help" };
- }
- }
- makeHarness().runMain(args, null);
- }
-
- /**
- * Get known option aliases.
- * Subclasses may add new aliases, where the key is the alias option,
- * and the value is a comma-delimited String of target options.
- * @return Properties with feature aliases or null
- */
- protected static Properties getOptionAliases() {
- if (null == optionAliases) {
- optionAliases = new Properties();
- // XXX load from **OptionAliases.properties
- }
- return optionAliases;
- }
-
- /**
- * Read argFile contents into String[],
- * delimiting at any whitespace
- */
- private static String[] readArgs(File argFile) {
- ArrayList<String> args = new ArrayList<>();
- // int lineNum = 0;
-
- try {
- BufferedReader stream =
- new BufferedReader(new FileReader(argFile));
- String line;
- while (null != (line = stream.readLine())) {
- StringTokenizer st = new StringTokenizer(line);
- while (st.hasMoreTokens()) {
- args.add(st.nextToken());
- }
- }
- } catch (IOException e) {
- e.printStackTrace(System.err);
- }
- return args.toArray(new String[0]);
- }
-
- /** aliases key="option" value="option{,option}" */
- private static Properties optionAliases;
-
- /** be extra noisy if true */
- private boolean verboseHarness;
-
- /** be extra quiet if true */
- private boolean quietHarness;
-
- /** just don't say anything! */
- protected boolean silentHarness;
-
- private Map<String,Feature> features;
-
- /** if true, do not delete temporary files. */
- private boolean keepTemp;
-
- /** if true, delete temporary files as each test completes. */
- private boolean killTemp;
-
- /** if true, then log results in report(..) when done */
- private boolean logResults;
-
- /** if true and there were failures, do System.exit({numFailures})*/
- private boolean exitOnFailure;
-
- protected Harness() {
- features = new HashMap<>();
- }
-
-
- /**
- * Entry point for a test.
- * This reads in the arguments,
- * creates the test suite(s) from the input file(s),
- * and for each suite does setup, run, report, and cleanup.
- * When arguments are read, any option ending with "-" causes
- * option variants, a set of args with and another without the
- * option. See {@link LangUtil.optionVariants(String[])} for
- * more details.
- * @param args the String[] for the test suite - use -help to get options,
- * and use "-" suffixes for variants.
- * @param resultList List for IRunStatus results - ignored if null
- */
- public void runMain(String[] args, List resultList) {
- LangUtil.throwIaxIfFalse(!LangUtil.isEmpty(args), "empty args");
- // read arguments
- final ArrayList<String> globals = new ArrayList<>();
- final List<String> files = new ArrayList<>();
- final LinkedList<String> argList = new LinkedList<>(Arrays.asList(args));
- for (int i = 0; i < argList.size(); i++) {
- String arg = argList.get(i);
- List<String> aliases = aliasOptions(arg);
- if (!LangUtil.isEmpty(aliases)) {
- argList.remove(i);
- argList.addAll(i, aliases);
- i--;
- continue;
- }
- if ("-help".equals(arg)) {
- logln("java " + Harness.class.getName() + " {option|suiteFile}..");
- printSyntax(getLogStream());
- return;
- } else if (isSuiteFile(arg)) {
- files.add(arg);
- } else if (!acceptOption(arg)) {
- globals.add(arg);
- } // else our options absorbed
- }
- if (0 == files.size()) {
- logln("## Error reading arguments: at least 1 suite file required");
- logln("java " + Harness.class.getName() + " {option|suiteFile}..");
- printSyntax(getLogStream());
- return;
- }
- String[] globalOptions = globals.toArray(new String[0]);
- String[][] globalOptionVariants = optionVariants(globalOptions);
- AbstractRunSpec.RT runtime = new AbstractRunSpec.RT();
- if (verboseHarness) {
- runtime.setVerbose(true);
- }
-
- // run suites read from each file
- AjcTest.Suite.Spec spec;
- for (String string : files) {
- File suiteFile = new File(string);
- if (!suiteFile.canRead()) {
- logln("runMain(..) cannot read file: " + suiteFile);
- continue;
- }
- if (null == (spec = readSuite(suiteFile))) {
- logln("runMain(..) cannot read suite from file: " + suiteFile);
- continue;
- }
-
- MessageHandler holder = new MessageHandler();
- for (String[] globalOptionVariant : globalOptionVariants) {
- runtime.setOptions(globalOptionVariant);
- holder.init();
- boolean skip = !spec.adoptParentValues(runtime, holder);
- // awful/brittle assumption about number of skips == number of skip messages
- final List<IMessage> skipList = MessageUtil.getMessages(holder, IMessage.INFO, false, "skip");
- if ((verboseHarness || skip || (0 < skipList.size()))) {
- final List<String> curArgs = Arrays.asList(globalOptionVariant);
- logln("runMain(" + suiteFile + ", " + curArgs + ")");
- if (verboseHarness) {
- String format = "yyyy.MM.dd G 'at' hh:mm:ss a zzz";
- SimpleDateFormat formatter = new SimpleDateFormat (format);
- String date = formatter.format(new Date());
- logln("test date: " + date);
- logln("harness features: " + listFeatureNames());
- logln("Java version: " + JAVA_VERSION);
- logln("AspectJ version: " + ASPECTJ_VERSION);
- }
- if (!(quietHarness || silentHarness) && holder.hasAnyMessage(null, true)) {
- MessageUtil.print(getLogStream(), holder, "skip - ");
- MessageUtil.printMessageCounts(getLogStream(), holder, "skip - ");
- }
- }
- if (!skip) {
- doStartSuite(suiteFile);
- long elapsed = 0;
- RunResult result = null;
- try {
- final long startTime = System.currentTimeMillis();
- result = run(spec);
- if (null != resultList) {
- resultList.add(result);
- }
- elapsed = System.currentTimeMillis() - startTime;
- report(result.status, skipList.size(), result.numIncomplete, elapsed);
- } finally {
- doEndSuite(suiteFile,elapsed);
- }
- if (exitOnFailure) {
- int numFailures = RunUtils.numFailures(result.status, true);
- if (0 < numFailures) {
- System.exit(numFailures);
- }
- Object value = result.status.getResult();
- if ((value instanceof Boolean)
- && !(Boolean) value) {
- System.exit(-1);
- }
- }
- }
- }
- }
- }
-
-
- /**
- * Tell all IRunListeners that we are about to start a test suite
- * @param suiteFile
- * @param elapsed
- */
- private void doEndSuite(File suiteFile, long elapsed) {
- Collection c = features.values();
- for (Object o : c) {
- Feature element = (Feature) o;
- if (element.listener instanceof TestCompleteListener) {
- ((TestCompleteListener) element.listener).doEndSuite(suiteFile, elapsed);
- }
- }
- }
- /**
- * Generate variants of String[] options by creating an extra set for
- * each option that ends with "-". If none end with "-", then an
- * array equal to <code>new String[][] { options }</code> is returned;
- * if one ends with "-", then two sets are returned,
- * three causes eight sets, etc.
- * @return String[][] with each option set.
- * @throws IllegalArgumentException if any option is null or empty.
- */
- public static String[][] optionVariants(String[] options) {
- if ((null == options) || (0 == options.length)) {
- return new String[][] { new String[0]};
- }
- // be nice, don't stomp input
- String[] temp = new String[options.length];
- System.arraycopy(options, 0, temp, 0, temp.length);
- options = temp;
- boolean[] dup = new boolean[options.length];
- int numDups = 0;
-
- for (int i = 0; i < options.length; i++) {
- String option = options[i];
- if (LangUtil.isEmpty(option)) {
- throw new IllegalArgumentException("empty option at " + i);
- }
- if (option.endsWith("-")) {
- options[i] = option.substring(0, option.length()-1);
- dup[i] = true;
- numDups++;
- }
- }
- final String[] NONE = new String[0];
- final int variants = exp(2, numDups);
- final String[][] result = new String[variants][];
- // variant is a bitmap wrt doing extra value when dup[k]=true
- for (int variant = 0; variant < variants; variant++) {
- ArrayList<String> next = new ArrayList<>();
- int nextOption = 0;
- for (int k = 0; k < options.length; k++) {
- if (!dup[k] || (0 != (variant & (1 << (nextOption++))))) {
- next.add(options[k]);
- }
- }
- result[variant] = next.toArray(NONE);
- }
- return result;
- }
-
- private static int exp(int base, int power) { // not in Math?
- if (0 > power) {
- throw new IllegalArgumentException("negative power: " + power);
- }
- int result = 1;
- while (0 < power--) {
- result *= base;
- }
- return result;
- }
-
- /**
- * @param suiteFile
- */
- private void doStartSuite(File suiteFile) {
- Collection<Feature> c = features.values();
- for (Feature element : c) {
- if (element.listener instanceof TestCompleteListener) {
- ((TestCompleteListener)element.listener).doStartSuite(suiteFile);
- }
- }
- }
-
- /** Run the test suite specified by the spec */
- protected RunResult run(AjcTest.Suite.Spec spec) {
- LangUtil.throwIaxIfNull(spec, "spec");
- /*
- * For each run, initialize the runner and validator,
- * create a new set of IRun{Iterator} tests,
- * and run them.
- * Delete all temp files when done.
- */
- Runner runner = new Runner();
- if (0 != features.size()) {
- for (Entry<String, Feature> entry : features.entrySet()) {
- Feature feature = entry.getValue();
- runner.registerListener(feature.clazz, feature.listener);
- }
- }
- IMessageHolder holder = new MessageHandler();
- int numIncomplete = 0;
- RunStatus status = new RunStatus(holder, runner);
- status.setIdentifier(spec);
- // validator is used for all setup in entire tree...
- Validator validator = new Validator(status);
- if (!killTemp) {
- validator.lock(this);
- }
- Sandbox sandbox = null;
- try {
- sandbox = new Sandbox(spec.getSuiteDirFile(), validator);
- IRunIterator tests = spec.makeRunIterator(sandbox, validator);
- runner.runIterator(tests, status, null);
- if (tests instanceof RunSpecIterator) {
- numIncomplete = ((RunSpecIterator) tests).getNumIncomplete();
- }
- } finally {
- if (!keepTemp) {
- if (!killTemp) {
- validator.unlock(this);
- }
- validator.deleteTempFiles(verboseHarness);
- }
- }
- return new RunResult(status, numIncomplete);
- }
-
- /**
- * Report the results of a test run after it is completed.
- * Clients should be able to identify the number of:
- * <ul>
- * <li>tests run and passed</li>
- * <li>tests failed, i.e., run and not passed (fail, error, etc.)</li>
- * <li>tests incomplete, i.e., test definition read but test run setup failed</li>
- * <li>tests skipped, i.e., test definition read and found incompatible with
- * the current configuration.</li>
- * <ul>
- *
- * @param status returned from the run
- * @param numSkipped int tests that were skipped because of
- * configuration incompatibilities
- * @param numIncomplete int tests that failed during setup,
- * usually indicating a test definition or configuration error.
- * @param msElapsed elapsed time in milliseconds
- * */
- protected void report(IRunStatus status, int numSkipped, int numIncomplete,
- long msElapsed ) {
- if (logResults) {
- RunUtils.AJCSUITE_PRINTER.printRunStatus(getLogStream(), status);
- } else if (!(quietHarness || silentHarness) && (0 < status.numMessages(null, true))) {
- if (!silentHarness) {
- MessageUtil.print(getLogStream(), status, "");
- }
- }
-
- logln(BridgeUtil.childString(status, numSkipped, numIncomplete)
- + " " + (msElapsed/1000) + " seconds");
-
- }
-
- // --------------- delegate methods
- protected void logln(String s) {
- if (!silentHarness) {
- getLogStream().println(s);
- }
- }
-
- protected PrintStream getLogStream() {
- return System.out;
- }
-
- protected boolean isSuiteFile(String arg) {
- return ((null != arg)
- && (arg.endsWith(".txt") || arg.endsWith(".xml"))
- && new File(arg).canRead());
- }
-
- /**
- * Get the options that the input option is an alias for.
- * Subclasses may add options directly to the getFeatureAliases result
- * or override this.
- * @return null if the input is not an alias for other options,
- * or a non-empty List (String) of options that this option is an alias for
- */
- protected List<String> aliasOptions(String option) {
- Properties aliases = Harness.getOptionAliases();
- if (null != aliases) {
- String args = aliases.getProperty(option);
- if (!LangUtil.isEmpty(args)) {
- return LangUtil.anySplit(args, OPTION_DELIM);
- }
- }
- return null;
- }
-
- /**
- * Read and implement any of our options.
- * Options other than this and suite files will be
- * passed down as parent options through the test spec hierarchy.
- * Subclasses override this to implement new options.
- */
- protected boolean acceptOption(String option) {
- // boolean result = false;
- if (LangUtil.isEmpty(option)) {
- return true; // skip bad input
- } else if ("-verboseHarness".equals(option)) {
- verboseHarness = true;
- } else if ("-quietHarness".equals(option)) {
- quietHarness = true;
- } else if ("-silentHarness".equals(option)) {
- silentHarness = true;
- } else if ("-keepTemp".equals(option)) {
- keepTemp = true;
- } else if ("-killTemp".equals(option)) {
- killTemp = true;
- } else if ("-logResults".equals(option)) {
- logResults = true;
- } else if ("-exitOnFailure".equals(option)) {
- exitOnFailure = true;
- } else {
- return false;
- }
- return true;
- }
-
- /**
- * Read a test suite file.
- * This implementation knows how to read .txt and .xml files
- * and logs any errors.
- * Subclasses override this to read new kinds of suites.
- * @return null if unable to read (logging errors) or AjcTest.Suite.Spec otherwise
- */
- protected AjcTest.Suite.Spec readSuite(File suiteFile) {
- if (null != suiteFile) {
- String path = suiteFile.getPath();
- try {
- if (path.endsWith(".xml")) {
- return AjcSpecXmlReader.getReader().readAjcSuite(suiteFile);
- } else if (path.endsWith(".txt")) {
- return FlatSuiteReader.ME.readSuite(suiteFile);
- } else {
- logln("unrecognized extension? " + path);
- }
- } catch (IOException e) {
- e.printStackTrace(getLogStream());
- }
- }
- return null;
- }
-
- /** Add feature to take effect during the next runMain(..) invocation.
- * @param feature the Feature to add, using feature.name as key.
- */
- protected void addFeature(Feature feature) {
- if (null != feature) {
- features.put(feature.name, feature);
- }
- }
-
- /** remove feature by name (same as feature.name) */
- protected void removeFeature(String name) {
- if (!LangUtil.isEmpty(name)) {
- features.remove(name);
- }
- }
-
- /** @return unmodifiable Set of feature names */
- protected Set listFeatureNames() {
- return Collections.unmodifiableSet(features.keySet());
- }
-
- /** print detail message for syntax of main(String[]) command-line */
- protected void printSyntax(PrintStream out) {
- out.println(" {??} unrecognized options are used as test spec globals");
- out.println(" -help print this help message");
- out.println(" -verboseHarness harness components log verbosely");
- out.println(" -quietHarness harness components suppress logging");
- out.println(" -keepTemp do not delete temporary files");
- out.println(" -logResults log results at end, verbosely if fail");
- out.println(" -exitOnFailure do System.exit({num-failures}) if suite fails");
- out.println(" {suiteFile}.xml.. specify test suite XML file");
- out.println(" {suiteFile}.txt.. specify test suite .txt file (deprecated)");
- }
-
- /** print known aliases at the end of the syntax message */
- protected void printAliases(PrintStream out) {
- LangUtil.throwIaxIfNull(out, "out");
- Map props = getOptionAliases();
- if (null == props) {
- return;
- }
- int pdLength = SYNTAX_PAD.length();
- Set<Map.Entry<Object,Object>> entries = props.entrySet();
- for (Map.Entry<Object,Object> entry : entries) {
- String alias = " " + (String) entry.getKey();
- int buf = pdLength - alias.length();
- if (0 < buf) {
- alias += SYNTAX_PAD.substring(0, buf);
- } else {
- alias += " ";
- }
- out.println(alias + entry.getValue());
- }
- }
-
- /** result struct for run(AjcTest.Spec) */
- public static class RunResult {
- public final IRunStatus status;
- public final int numIncomplete;
- public RunResult(IRunStatus status, int numIncomplete) {
- this.status = status;
- this.numIncomplete = numIncomplete;
- }
- }
- /** feature implemented as named IRunIterator/IRun association */
- public static class Feature {
- /** never null, always assignable to IRun */
- public final Class clazz;
-
- /** never null */
- public final IRunListener listener;
-
- /** never null or empty */
- public final String name;
-
- /** @throws IllegalArgumentException if any is null/empty or clazz is
- * not assignable to IRun
- */
- public Feature(String name, Class clazz, IRunListener listener) {
- LangUtil.throwIaxIfNull(clazz, "class");
- if (!IRun.class.isAssignableFrom(clazz)
- && !IRunIterator.class.isAssignableFrom(clazz)) {
- String s = clazz.getName() + "is not assignable to IRun or IRunIterator";
- LangUtil.throwIaxIfFalse(false, s);
- }
- LangUtil.throwIaxIfNull(listener, "listener");
- LangUtil.throwIaxIfNull(name, "name");
- LangUtil.throwIaxIfFalse(0 < name.length(), "empty name");
- this.clazz = clazz;
- this.listener = listener;
- this.name = name;
- }
-
- /** @return feature name */
- @Override
- public String toString() {
- return name;
- }
- }
- }
-
-
- /**
- * Harness with features for controlling output
- * (logging results and hiding streams).
- * Use -help to get a list of feature options.
- */
- class FeatureHarness extends Harness {
-
- private static final String[] ALIASES = new String[]
- { "-hideStreams",
- "-hideCompilerStreams"
- + OPTION_DELIM + "-hideRunStreams",
- "-jim",
- "-logMinFail"
- + OPTION_DELIM + "-hideStreams",
- "-loud",
- "-verboseHarness",
- "-baseline",
- "-verboseHarness"
- + OPTION_DELIM + "-traceTestsMin"
- + OPTION_DELIM + "-hideStreams",
- "-release",
- "-baseline"
- + OPTION_DELIM + "-ajctestSkipKeywords=knownLimitation,purejava",
- "-junit",
- "-silentHarness" + OPTION_DELIM + "-logJUnit" + OPTION_DELIM +
- "-hideStreams",
- "-cruisecontrol",
- "-junit" + OPTION_DELIM + "-ajctestSkipKeywords=knownLimitation,purejava"
- };
- static {
- Map optionAliases = Harness.getOptionAliases();
- if (null != optionAliases) {
- for (int i = 1; i < ALIASES.length; i += 2) {
- optionAliases.put(ALIASES[i-1], ALIASES[i]);
- }
- }
- }
-
- /** controller for suppressing and sniffing error and output streams. */
- StreamsHandler streamsHandler;
-
- /** facility of hiding-streams may be applied in many features */
- IRunListener streamHider;
-
- /** facility of capture/log may be applied in many features */
- IRunListener captureLogger;
-
- /** when making tests, do not run them */
- TestMaker testMaker;
-
- public FeatureHarness() {
- super();
- streamsHandler = new StreamsHandler(false, true);
- }
- /** override to make tests or run as usual */
- @Override
- protected RunResult run(AjcTest.Suite.Spec spec) {
- if (null != testMaker) {
- System.out.println("generating rather than running tests...");
- return testMaker.run(spec);
- } else {
- return super.run(spec);
- }
- }
-
- /**
- * Log via StreamsHandler-designated log stream.
- * @see org.aspectj.testing.drivers.Harness#log(String)
- */
- @Override
- protected void logln(String s) {
- if (!silentHarness)
- streamsHandler.lnlog(s);
- }
-
- /**
- * @see org.aspectj.testing.drivers.Harness#getLogStream()
- * @return StreamsHandler-designated log stream.
- */
- @Override
- protected PrintStream getLogStream() {
- return streamsHandler.out;
- }
-
-
- /** print detail message for syntax of main(String[]) command-line */
- @Override
- protected void printSyntax(PrintStream out) {
- super.printSyntax(out);
- out.println(" -progressDots log . or ! for each AjcTest pass or fail");
- out.println(" -logFail log each failed AjcTest");
- out.println(" -logPass log each passed AjcTest");
- out.println(" -logAll log each AjcTest");
- out.println(" -logMinFail log each AjcTest failure with minimal excess data");
- out.println(" -logMinPass log each AjcTest success with minimal excess data");
- out.println(" -logMinAll log all AjcTest with minimal excess data");
- out.println(" -logXMLFail log XML definition for each failed AjcTest");
- out.println(" -logXMLPass log XML definition for each passed AjcTest");
- out.println(" -logXMLAll log XML definition for each AjcTest");
- out.println(" -logJUnit log all tests in JUnit XML report style");
- out.println(" -hideRunStreams hide err/out streams during java runs");
- out.println(" -hideCompilerStreams hide err/out streams during compiler runs");
- out.println(" -traceTests log pass|fail, /time/memory taken after each test");
- out.println(" -traceTestsMin log pass|fail after each test");
- out.println(" -XmakeTests create source files/dirs for initial compile run of each test");
- out.println(" -XlogPublicType log test XML if \"public type\" in an error message");
- out.println(" -XlogSourceIn=Y,Z log test XML if Y or Z is in path of any sources");
- super.printAliases(out);
- }
-
- /** Accept a number of logging and output options */
- @Override
- protected boolean acceptOption(String option) {
- if (null == option) {
- return false;
- }
-
- final StreamsHandler streams = streamsHandler;
- final IRunValidator validator = RunValidator.NORMAL;
- final RunUtils.IRunStatusPrinter verbose
- = RunUtils.VERBOSE_PRINTER;
- final RunUtils.IRunStatusPrinter terse
- = RunUtils.TERSE_PRINTER;
- // final boolean LOGPASS = true;
- // final boolean LOGFAIL = true;
- // final boolean SKIPPASS = false;
- // final boolean SKIPFAIL = false;
- // final boolean LOGSTREAMS = true;
- final boolean SKIPSTREAMS = false;
-
- Feature feature = null;
- if (super.acceptOption(option)) {
- // ok, result returned below
-
- } else if ("-XmakeTests".equals(option)) {
- testMaker = TestMaker.ME;
- } else if (option.startsWith("-traceTestsMin")) {
- feature = new Feature(option, AjcTest.class,new TestTraceLogger(streams, false));
- } else if (option.startsWith("-traceTests")) {
- feature = new Feature(option, AjcTest.class,new TestTraceLogger(streams, true));
- } else if (option.startsWith("-logMin")) {
- feature = new Feature(option, AjcTest.class,
- new RunLogger(option, SKIPSTREAMS, streams, validator, terse));
- } else if (option.startsWith("-logXML")) {
- feature = new Feature(option, AjcTest.class,
- new XmlLogger(option, streams, validator));
- } else if (option.startsWith("-logJUnit")) {
- feature = new Feature(option, AjcTest.class,
- new JUnitXMLLogger(option,streams,validator));
- } else if (option.startsWith("-log")) {
- feature = new Feature(option, AjcTest.class,
- new RunLogger(option, SKIPSTREAMS, streams, validator, verbose));
- } else if ("-hideRunStreams".equals(option)) {
- feature = new Feature(option, JavaRun.class, getStreamHider());
- } else if ("-hideCompilerStreams".equals(option)) {
- addFeature(new Feature(option, IncCompilerRun.class, getStreamHider())); // hmmm
- feature = new Feature(option, CompilerRun.class, getStreamHider());
- } else if ("-progressDots".equals(option)) {
- IRunListener listener = new RunListener() {
- @Override
- public void runCompleted(IRunStatus run) {
- streamsHandler.log((validator.runPassed(run) ? "." : "!"));
- }
- };
- feature = new Feature(option, AjcTest.class, listener);
- } else if (option.startsWith("-XlogPublicType")) {
- String label = option + TestCompleteListener.PASS; // print when validator true
- feature = new Feature(option, AjcTest.class,
- new XmlLogger(label, streams, MessageRunValidator.PUBLIC_TYPE_ERROR));
- } else if (option.startsWith("-XlogSourceIn")) {
- String input = option.substring("-XlogSourceIn=".length());
- LangUtil.throwIaxIfFalse(0 < input.length(), option);
- String label = "-XlogSourceIn=" + TestCompleteListener.PASS; // print when validator true
- StringRunner sr = new SubstringRunner(input, false);
- feature = new Feature(option, AjcTest.class,
- new XmlLogger(label, streams, new SourcePathValidator(sr)));
- } else {
- return false;
- }
- addFeature(feature);
- return true;
- }
-
- /** lazy construction for shared hider */
- protected IRunListener getStreamHider() {
- if (null == streamHider) {
- streamHider = new RunListener() {
- @Override
- public void runStarting(IRunStatus run) {
- streamsHandler.hide();
- }
- @Override
- public void runCompleted(IRunStatus run) {
- streamsHandler.show();
- }
- @Override
- public String toString() { return "Harness StreamHider"; }
- };
- }
- return streamHider;
- }
- }
-
- /** Generate any needed test case files for any test. */
- class TestMaker {
-
- static TestMaker ME = new TestMaker();
-
- /** @throws Error if unable to make dir */
- static void mkdirs(File dir) {
- if (null != dir && !dir.exists()) {
- if (!dir.mkdirs()) {
- throw new Error("unable to make dir: " + dir);
- }
- }
- }
- static String getFileContents(File baseDir, File file, String label) {
- String fileName = file.getName();
- if (fileName.endsWith(".java")) {
- fileName = fileName.substring(0, fileName.length() - 5);
- }
- StringBuilder sb = new StringBuilder();
- String filePath = file.getParentFile().getAbsolutePath();
- String dirPath = baseDir.getAbsolutePath();
- String pack = null;
- if (filePath.startsWith(dirPath)) {
- pack = filePath.substring(dirPath.length()).replace('/', '.');
- }
- if (!LangUtil.isEmpty(pack)) {
- sb.append("package " + pack + ";");
- }
- final String EOL = "\n"; // XXX find discovered EOL
- sb.append( EOL
- + EOL + "import org.aspectj.testing.Tester;"
- + EOL + ""
- + EOL + "/** @testcase " + label + " */"
- + EOL + "public class " + fileName + " {"
- + EOL + "\tpublic static void main(String[] args) { "
- + EOL + "\t\tTester.check(null != args, \"null args\"); "
- + EOL + "\t}"
- + EOL + "}"
- + EOL
- );
-
- return sb.toString();
- }
-
- /** create a minimal source file for a test */
- static void createSrcFile(File baseDir, File file, String testName) {
- if (file.exists()) {
- return;
- }
- String contents = getFileContents(baseDir, file, testName);
- String error = FileUtil.writeAsString(file, contents);
- if (null != error) {
- throw new Error(error);
- }
- }
-
- /** create an empty arg file for a test */
- static void createArgFile(File baseDir, File file, String testName) {
- if (file.exists()) {
- return;
- }
- String contents = "// argfile " + file;
- String error = FileUtil.writeAsString(file, contents);
- if (null != error) {
- throw new Error(error);
- }
- }
-
- public Harness.RunResult run(AjcTest.Suite.Spec spec) {
- Iterable<IRunSpec> kids = spec.getChildren();
- for (IRunSpec iRunSpec : kids) {
- makeTest( (AjcTest.Spec) iRunSpec);
- }
- IRunStatus status = new RunStatus(new MessageHandler(), new Runner());
- status.start();
- status.finish(IRunStatus.PASS);
- return new Harness.RunResult(status, 0);
- }
-
- private void makeTest(AjcTest.Spec spec) {
- CompilerRun.Spec compileSpec = AjcTest.unwrapCompilerRunSpec(spec);
- if (null == spec) {
- throw new Error("null spec");
- }
- System.out.println(" generating test files for test: " + spec.getDescription());
- File dir = spec.getSuiteDir();
- if (null != dir) {
- TestMaker.mkdirs(dir);
- }
- String offset = spec.getTestDirOffset();
- if (!LangUtil.isEmpty(offset)) {
- if (null == dir) {
- dir = new File(offset);
- } else {
- dir = new File(dir.getAbsolutePath() + "/" + offset);
- }
- } else if (null == dir) {
- dir = new File(".");
- }
- StringBuilder testName = new StringBuilder();
- int pr = spec.getBugId();
- if (0 < pr) {
- testName.append("PR#" + pr + " ");
- }
-
- testName.append(spec.getDescription());
- final String label = testName.toString();
- final File[] srcFiles = FileUtil.getBaseDirFiles(dir, compileSpec.getPathsArray());
- if (!LangUtil.isEmpty(srcFiles)) {
- for (File srcFile : srcFiles) {
- TestMaker.createSrcFile(dir, srcFile, label);
- }
- }
- final File[] argFiles = FileUtil.getBaseDirFiles(dir, compileSpec.getArgfilesArray());
- if (!LangUtil.isEmpty(argFiles)) {
- for (File argFile : argFiles) {
- TestMaker.createArgFile(dir, argFile, label);
- }
- }
-
- }
-
- /** @return "Testmaker()" */
- @Override
- public String toString() {
- return "TestMaker()";
- }
- }
-
- interface StringRunner {
- boolean accept(String s);
- }
-
- /**
- * StringRunner than accepts input matching 0+ substrings,
- * optionally case-insensitive.
- */
- class SubstringRunner implements StringRunner {
- private static String[] extractSubstrings(
- String substrings,
- boolean caseSensitive) {
- if (null == substrings) {
- return null;
- }
- StringTokenizer st = new StringTokenizer(substrings, ",");
- String[] result = new String[st.countTokens()];
- for (int i = 0; i < result.length; i++) {
- result[i] = st.nextToken().trim();
- LangUtil.throwIaxIfFalse(0 < result[i].length(), "empty entry");
- if (!caseSensitive) {
- result[i] = result[i].toLowerCase();
- }
- }
- return result;
- }
-
- private final String[] substrings;
- private final boolean caseSensitive;
-
- /**
- * @param substrings the String containing comma-separated substrings
- * to find in input - if null, any input accepted
- * @param caseSensitive if true, do case-sensitive comparison
- * @throws IllegalArgumentException if any substrings contains empty entry ", ,"
- */
- SubstringRunner(String substrings, boolean caseSensitive) {
- this.caseSensitive = caseSensitive;
- this.substrings = extractSubstrings(substrings, caseSensitive);
- }
-
- @Override
- public boolean accept(String input) {
- if (null == substrings) {
- return true;
- }
- if (null == input) {
- return false;
- }
-
- if (!caseSensitive) {
- input = input.toLowerCase();
- }
- for (String substring : substrings) {
- if (input.contains(substring)) {
- return true;
- }
- }
- return false;
- }
- }
-
- /**
- * Signal whether run "passed" based on validating absolute source paths.
- * (Static evaluation - no run necessary)
- */
- class SourcePathValidator implements IRunValidator { // static - no run needed
- private final StringRunner validator;
- // XXX hoist common
- SourcePathValidator(StringRunner validator) {
- LangUtil.throwIaxIfNull(validator, "validator");
- this.validator = validator;
- }
- /**
- * @return true if any source files in compile spec are
- * accepted by the validator.
- * @see org.aspectj.testing.run.IRunValidator#runPassed(IRunStatus)
- */
- @Override
- public boolean runPassed(IRunStatus run) {
- AjcTest.Spec testSpec = AjcTest.unwrapSpec(run);
- if (null != testSpec) {
- CompilerRun.Spec compileSpec = AjcTest.unwrapCompilerRunSpec(testSpec);
- File basedir = new File(testSpec.getSuiteDir(), testSpec.getTestDirOffset());
- String[] paths = compileSpec.getPathsArray();
- File[] files = FileUtil.getBaseDirFiles(basedir, paths);
- for (File file : files) {
- if (validator.accept(file.getAbsolutePath())) {
- return true;
- }
- }
- }
- return false;
- }
-
- }
-
- /** Signal whether run "passed" based on message kind and content */
- class MessageRunValidator implements IRunValidator {
-
- /** signals "passed" if any error contains "public type" */
- static final IRunValidator PUBLIC_TYPE_ERROR
- = new MessageRunValidator("public type", IMessage.ERROR, false);
-
- private final IMessage.Kind kind;
- private final String sought;
- private final boolean orGreater;
-
- /**
- * @param sought the String to seek anywhere in any message of the right kind
- * if null, accept any message of the right kind.
- * @param kind the IMessage.Kind of messages to search - all if null
- */
- MessageRunValidator(String sought, IMessage.Kind kind, boolean orGreater) {
- this.sought = sought;
- this.kind = kind;
- this.orGreater = orGreater;
- }
-
- /** @return true if this run has messages of the right kind and text */
- @Override
- public boolean runPassed(IRunStatus run) {
- return gotMessage(new IRunStatus[] {run});
- }
-
- /**
- * Search these children and their children recursively
- * for messages of the right kind and content.
- * @return true at first match of message of the right kind and content
- */
- private boolean gotMessage(IRunStatus[] children) {
- if (LangUtil.isEmpty(children)) {
- return false;
- }
- for (IRunStatus run : children) {
- if (null == run) {
- continue; // hmm
- }
- IMessage[] messages = run.getMessages(kind, orGreater);
- if (!LangUtil.isEmpty(messages)) {
- if (LangUtil.isEmpty(sought)) {
- return true;
- } else {
- for (IMessage message : messages) {
- if (null == message) {
- continue; // hmm
- }
- String text = message.getMessage();
- if ((null != text) && (text.contains(sought))) {
- return true;
- }
- }
- }
- }
- if (gotMessage(run.getChildren())) {
- return true;
- }
- }
- return false;
- }
- }
-
- /**
- * Base class for listeners that run depending on pass/fail status of input.
- * Template method runCompleted handled whether to run.
- * Subclasses implement doRunCompleted(..).
- */
- abstract class TestCompleteListener extends RunListener {
- /** label suffix indicating both pass and fail */
- public static final String ALL = "All";
-
- /** label suffix indicating fail */
- public static final String FAIL = "Fail";
-
- /** label suffix indicating pass */
- public static final String PASS = "Pass";
-
-
- /** runValidator determines if a given run passed */
- protected final IRunValidator runValidator;
-
- /** label for this listener */
- final String label;
-
- /** if trun and run passed, then run doRunCompleted(..) */
- final boolean logOnPass;
-
- /** if true and run did not pass, then run doRunCompleted(..) */
- final boolean logOnNotPass;
-
- /** may be null */
- protected final StreamsHandler streamsHandler;
-
- /** true if the last run evaluation was ok */
- boolean lastRunOk;
-
- /** last run evaluated */
- IRunStatus lastRun; // XXX small memory leak - cache hashcode instead?
-
- /** @param label endsWith PASS || FAIL || ALL */
- protected TestCompleteListener(
- String label,
- IRunValidator runValidator,
- StreamsHandler streamsHandler) {
- if (null == runValidator) {
- runValidator = RunValidator.NORMAL;
- }
- this.label = (null == label? "" : label);
- this.logOnPass = label.endsWith(PASS) || label.endsWith(ALL);
- this.logOnNotPass = label.endsWith(FAIL) || label.endsWith(ALL);
- this.runValidator = runValidator;
- this.streamsHandler = streamsHandler;
- }
-
- public void runStarted(IRunStatus run) {
- if (null != streamsHandler) {
- streamsHandler.startListening();
- }
- }
-
- /** subclasses implement this to do some per-test initialization */
- protected void doRunStarted(IRunStatus run) {
- }
-
-
- /** subclasses implement this to do some per-suite initialization */
- protected void doStartSuite(File suite) {
- }
-
- /** subclasses implement this to do end-of-suite processing */
- protected void doEndSuite(File suite, long duration) {
- }
-
- @Override
- public final void runCompleted(IRunStatus run) {
- boolean doit = lastRunOk(run);
- StreamsHandler.Result result = null;
- if (null != streamsHandler) {
- streamsHandler.endListening(doit);
- }
- if (doit) {
- doRunCompleted(run, result);
- }
- }
-
- /**
- * @return true if run is ok per constructor specifications
- */
- protected boolean lastRunOk(IRunStatus run) {
- if (lastRun != run) {
- boolean passed = runValidator.runPassed(run);
- lastRunOk = (passed ? logOnPass : logOnNotPass);
- }
- return lastRunOk;
- }
-
- /** @return "{classname}({pass}{,fail})" indicating when this runs */
- @Override
- public String toString() { // XXX add label?
- return LangUtil.unqualifiedClassName(this)
- + "(" + (logOnPass ? (logOnNotPass ? "pass, fail)" : "pass)")
- : (logOnNotPass ? "fail)" : ")"));
- }
- /**
- * Subclasses implement this to do some completion action
- * @param run the IRunStatus for this completed run
- * @param result the StreamsHandler.Result (if any - may be null)
- */
- public abstract void doRunCompleted(IRunStatus run, StreamsHandler.Result result);
- }
-
- /**
- * Write XML for any test passed and/or failed.
- * Must register with Runner for RunSpecIterator.class,
- * most sensibly AjcTest.class.
- */
- class XmlLogger extends TestCompleteListener {
- /**
- * @param printer the component that prints any status - not null
- * @param runValidator if null, use RunValidator.NORMAL
- */
- public XmlLogger(
- String label,
- StreamsHandler streamsHandler,
- IRunValidator runValidator) {
- super(label, runValidator, streamsHandler);
- }
-
- @Override
- public void doRunCompleted(IRunStatus run, StreamsHandler.Result result) {
- PrintStream out = streamsHandler.getLogStream();
- out.println("");
- XMLWriter writer = new XMLWriter(new PrintWriter(out, true));
- Object id = run.getIdentifier();
- if (!(id instanceof Runner.IteratorWrapper)) {
- out.println(this + " not IteratorWrapper: "
- + id.getClass().getName() + ": " + id);
- return;
- }
- IRunIterator iter = ((Runner.IteratorWrapper) id).iterator;
- if (!(iter instanceof RunSpecIterator)) {
- out.println(this + " not RunSpecIterator: " + iter.getClass().getName()
- + ": " + iter);
- return;
- }
- ((RunSpecIterator) iter).spec.writeXml(writer);
- out.flush();
- }
-
- }
-
- /**
- * Write junit style XML output (for incorporation into html test results and
- * cruise control reports
- * format is...
- * <?xml version="1.0" encoding="UTF-8" ?>
- * <testsuite errors="x" failures="x" name="suite-name" tests="xx" time="ss.ssss">
- * <properties/>
- * <testcase name="passingTest" time="s.hh"></testcase>
- * <testcase name="failingTest" time="s.hh">
- * <failure message="failureMessage" type="ExceptionType">free text</failure>
- * </testcase>
- * </testsuite>
- */
- class JUnitXMLLogger extends TestCompleteListener {
-
- // private File suite;
- private StringBuffer junitOutput;
- private long startTimeMillis;
- private int numTests = 0;
- private int numFails = 0;
- private DecimalFormat timeFormatter = new DecimalFormat("#.##");
-
- public JUnitXMLLogger(
- String label,
- StreamsHandler streamsHandler,
- IRunValidator runValidator) {
- super(label + ALL, runValidator, streamsHandler);
- junitOutput = new StringBuffer();
- }
-
- /* (non-Javadoc)
- * @see org.aspectj.testing.drivers.TestCompleteListener#doRunCompleted(org.aspectj.testing.run.IRunStatus, org.aspectj.testing.util.StreamsHandler.Result)
- */
- @Override
- public void doRunCompleted(IRunStatus run, Result result) {
- long duration = System.currentTimeMillis() - startTimeMillis;
- numTests++;
- junitOutput.append("<testcase name=\"" + run.getIdentifier() + "\" ");
- junitOutput.append("time=\"" + timeFormatter.format((duration)/1000.0f) + "\"");
- junitOutput.append(">");
- if (!run.runResult()) {
- numFails++;
- junitOutput.append("\n");
- junitOutput.append("<failure message=\"test failed\" type=\"unknown\">\n");
- // junitOutput.println(result.junitOutput);
- // junitOutput.println(result.err);
- junitOutput.append("</failure>\n");
- }
- junitOutput.append("</testcase>\n");
- }
-
- /* (non-Javadoc)
- * @see org.aspectj.testing.drivers.TestCompleteListener#runStarted(org.aspectj.testing.run.IRunStatus)
- */
- @Override
- public void runStarting(IRunStatus run) {
- super.runStarting(run);
- startTimeMillis = System.currentTimeMillis();
- }
-
- /* (non-Javadoc)
- * @see org.aspectj.testing.drivers.TestCompleteListener#doEndSuite(java.io.File, long)
- */
- @Override
- protected void doEndSuite(File suite, long duration) {
- super.doEndSuite(suite, duration);
- String suiteName = suite.getName();
- // junit reporter doesn't like ".xml" on the end
- suiteName = suiteName.substring(0,suiteName.indexOf('.'));
- PrintStream out = streamsHandler.getLogStream();
- out.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
- String timeStr = new DecimalFormat("#.##").format(duration/1000.0);
- out.print("<testsuite errors=\"" + numFails + "\" failures=\"0\" ");
- out.print("name=\"" + suite.getName() + "\" " );
- out.println("tests=\"" + numTests + "\" time=\"" + timeStr + "\">");
- out.print(junitOutput.toString());
- out.println("</testsuite>");
- }
-
- /* (non-Javadoc)
- * @see org.aspectj.testing.drivers.TestCompleteListener#doStartSuite(java.io.File)
- */
- @Override
- protected void doStartSuite(File suite) {
- super.doStartSuite(suite);
- // this.suite = suite;
- numTests = 0;
- numFails = 0;
- junitOutput = new StringBuffer();
- }
-
- }
-
- /** log pass and/or failed runs */
- class RunLogger extends TestCompleteListener {
- final boolean logStreams;
- final RunUtils.IRunStatusPrinter printer;
-
- /**
- * @param printer the component that prints any status - not null
- * @param runValidator if null, use RunValidator.NORMAL
- */
- public RunLogger(
- String label,
- boolean logStreams,
- StreamsHandler streamsHandler,
- IRunValidator runValidator,
- RunUtils.IRunStatusPrinter printer) {
- super(label, runValidator, streamsHandler);
- LangUtil.throwIaxIfNull(streamsHandler, "streamsHandler");
- LangUtil.throwIaxIfNull(printer, "printer");
- this.logStreams = logStreams;
- this.printer = printer;
- }
-
- @Override
- public void doRunCompleted(IRunStatus run, StreamsHandler.Result result) {
- PrintStream out = streamsHandler.getLogStream();
- printer.printRunStatus(out, run);
- if (logStreams) {
- if (!LangUtil.isEmpty(result.err)) {
- out.println("--- error");
- out.println(result.err);
- }
- if (!LangUtil.isEmpty(result.out)) {
- out.println("--- ouput");
- out.println(result.out);
- }
- }
- out.println("");
- }
- }
-
- /** trace time and memory between runStaring and runCompleted */
- class TestTraceLogger extends TestCompleteListener {
- private static final Runtime runtime = Runtime.getRuntime();
- private long startTime;
- private long startMemoryFree;
- private final boolean verbose;
-
- public TestTraceLogger(StreamsHandler handler) {
- this(handler, true);
- }
- public TestTraceLogger(StreamsHandler handler, boolean verbose) {
- super("-traceTestsAll", null, handler);
- this.verbose = verbose;
- }
- @Override
- public void runStarting(IRunStatus run) {
- super.runStarting(run);
- startTime = System.currentTimeMillis();
- startMemoryFree = runtime.freeMemory();
- }
-
- @Override
- public void doRunCompleted(IRunStatus run, StreamsHandler.Result result) {
- long elapsed = System.currentTimeMillis() - startTime;
- long free = runtime.freeMemory();
- long used = startMemoryFree - free;
- String label = run.runResult() ? "PASS " : "FAIL ";
- PrintStream out = streamsHandler.getLogStream();
- if (verbose) {
- label = label
- + "elapsed: " + LangUtil.toSizedString(elapsed, 7)
- + " free: " + LangUtil.toSizedString(free, 10)
- + " used: " + LangUtil.toSizedString(used, 10)
- + " id: ";
- }
- out.println(label + renderId(run));
- }
-
- /** @return true - always trace tests */
- protected boolean isFailLabel(String label) {
- return true;
- }
-
- /** @return true - always trace tests */
- protected boolean isPassLabel(String label) {
- return true;
- }
-
- /**
- * This implementation returns run identifier toString().
- * Subclasses override this to render id as message suffix.
- */
- protected String renderId(IRunStatus run) {
- return "" + run.getIdentifier();
- }
- }
- // printing files
- // AjcTest.Spec testSpec = AjcTest.unwrapSpec(run);
- // if (null != testSpec) {
- // CompilerRun.Spec compileSpec = AjcTest.unwrapCompilerRunSpec(testSpec);
- // File dir = new File(testSpec.getSuiteDir(), testSpec.getTestDirOffset());
- // List files = compileSpec.getPathsAsFile(dir);
- // StringBuffer sb = new StringBuffer();
- // for (Iterator iter = files.iterator(); iter.hasNext();) {
- // File file = (File) iter.next();
- // sb.append(" " + file.getPath().replace('\\','/').substring(2));
- // }
- // out.println("files: " + sb);
- // }
-
|