You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

AjcTestCase.java 25KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750
  1. /* *******************************************************************
  2. * Copyright (c) 2004 IBM Corporation
  3. * All rights reserved.
  4. * This program and the accompanying materials are made available
  5. * under the terms of the Common Public License v1.0
  6. * which accompanies this distribution and is available at
  7. * http://www.eclipse.org/legal/cpl-v10.html
  8. *
  9. * Contributors:
  10. * Adrian Colyer,
  11. * ******************************************************************/
  12. package org.aspectj.tools.ajc;
  13. import java.io.ByteArrayOutputStream;
  14. import java.io.File;
  15. import java.io.IOException;
  16. import java.io.PrintStream;
  17. import java.lang.reflect.InvocationTargetException;
  18. import java.lang.reflect.Method;
  19. import java.net.URL;
  20. import java.net.URLClassLoader;
  21. import java.util.ArrayList;
  22. import java.util.Collections;
  23. import java.util.Iterator;
  24. import java.util.List;
  25. import java.util.StringTokenizer;
  26. import org.aspectj.bridge.IMessage;
  27. import org.aspectj.bridge.ISourceLocation;
  28. import org.aspectj.testing.util.TestUtil;
  29. import org.aspectj.weaver.loadtime.WeavingURLClassLoader;
  30. import junit.framework.TestCase;
  31. /**
  32. * A TestCase class that acts as the superclass for all test cases wishing
  33. * to drive the ajc compiler.
  34. * <p>
  35. * This class provides a number of utility methods that make programmatic
  36. * testing of the compiler easy. See AjcTestCaseTest for a couple of simple
  37. * tests written using this class.
  38. * </p>
  39. * <p>
  40. * See the XMLBasedAjcTestCase subclass for TestCase class that can be
  41. * used to drive compiler tests based on an ajcTests.xml format test
  42. * specification file.</p>
  43. * @see org.aspectj.tools.ajc.AjcTestCase.Message
  44. * @see org.aspectj.tools.ajc.AjcTestCase.MessageSpec
  45. * @see org.aspectj.tools.ajc.AjcTestCase.RunResult
  46. * @see org.aspectj.tools.ajc.AjcTestCaseTest
  47. * @see org.aspectj.testing.XMLBasedAjcTestCase
  48. */
  49. public class AjcTestCase extends TestCase {
  50. private RunResult lastRunResult;
  51. /**
  52. * The Ajc (compiler) instance used for thet test. Created afresh
  53. * during the test setup.
  54. */
  55. protected Ajc ajc;
  56. public static final String DEFAULT_CLASSPATH_ENTRIES =
  57. File.pathSeparator + ".." + File.separator + "runtime" + File.separator + "bin" +
  58. File.pathSeparator + ".." + File.separator + "testing-client" + File.separator + "bin" +
  59. File.pathSeparator + ".." + File.separator + "bridge" + File.separator + "bin" +
  60. File.pathSeparator + ".." + File.separator + "util" + File.separator + "bin" +
  61. File.pathSeparator + ".." + File.separator + "aspectj5rt" + File.separator + "bin" +
  62. File.pathSeparator+ ".."+File.separator+"lib"+File.separator+"junit"+File.separator+"junit.jar"
  63. + File.pathSeparator+ ".."+File.separator+"loadtime"+File.separator+"bin"
  64. + File.pathSeparator+ ".."+File.separator+"weaver"+File.separator+"bin"
  65. + File.pathSeparator+ ".."+File.separator+"weaver5"+File.separator+"bin"
  66. // When the build machine executes the tests, it is using code built into jars rather than code build into
  67. // bin directories. This means for the necessary types to be found we have to put these jars on the classpath:
  68. + File.pathSeparator+".."+File.separator+"aj-build"+File.separator+"jars"+File.separator+"bridge.jar"
  69. + File.pathSeparator+".."+File.separator+"aj-build"+File.separator+"jars"+File.separator+"util.jar"
  70. + File.pathSeparator+".."+File.separator+"aj-build"+File.separator+"jars"+File.separator+"loadtime.jar"
  71. + File.pathSeparator+".."+File.separator+"aj-build"+File.separator+"jars"+File.separator+"weaver.jar"
  72. + File.pathSeparator+".."+File.separator+"aj-build"+File.separator+"jars"+File.separator+"weaver5.jar"
  73. + File.pathSeparator+".."+File.separator+"aj-build"+File.separator+"jars"+File.separator+"asm.jar"
  74. + File.pathSeparator+".."+File.separator+"lib" +File.separator+"test"+File.separator+"testing-client.jar"
  75. // hmmm, this next one should perhaps point to an aj-build jar...
  76. + File.pathSeparator+".."+File.separator+"lib" +File.separator+"test"+File.separator+"aspectjrt.jar"
  77. ;
  78. /**
  79. * Helper class that represents the specification of an individual
  80. * message expected to be produced during a compilation run.
  81. * <p>
  82. * Message objects are combined in a MessageSpec which can then be
  83. * passed to the various assertMessage methods.</p>
  84. * @see org.aspectj.tools.ajc.AjcTestCase.MessageSpec
  85. */
  86. public static class Message {
  87. private int line = -1;
  88. private String text;
  89. private String sourceFileName;
  90. private ISourceLocation[] seeAlsos;
  91. /**
  92. * Create a message that will match any compiler message on
  93. * the given line.
  94. */
  95. public Message(int line) {
  96. this.line = line;
  97. }
  98. /**
  99. * Create a message that will match any compiler message on
  100. * the given line, where the message text contains <code>text</code>.
  101. */
  102. public Message(int line, String text) {
  103. this.line = line;
  104. this.text = text;
  105. }
  106. /**
  107. * Create a message that will match any compiler message on
  108. * the given line, where the message text contains <code>text</code>.
  109. * <p>
  110. * If srcFile is non-null, the source file location of the message must
  111. * end with <code>srcFile</code>.
  112. * </p>
  113. * <p>
  114. * If <code>seeAlso</code> is non-null, each source location in seeAlso
  115. * must be matched by an extraSourceLocation in the message.
  116. * </p>
  117. */
  118. public Message(int line, String srcFile, String text, ISourceLocation[] seeAlso) {
  119. this.line = line;
  120. StringBuffer srcFileName = new StringBuffer();
  121. if (srcFile != null) {
  122. char[] chars = srcFile.toCharArray();
  123. for (int i = 0; i < chars.length; i++) {
  124. if ((chars[i] == '\\') || (chars[i] == '/')) {
  125. srcFileName.append(File.separator);
  126. } else {
  127. srcFileName.append(chars[i]);
  128. }
  129. }
  130. this.sourceFileName = srcFileName.toString();
  131. }
  132. this.text = text;
  133. this.seeAlsos = seeAlso;
  134. }
  135. /**
  136. * Create a message spec that will match any compiler message where
  137. * the message text includes <code>text</code>.
  138. */
  139. public Message(String text) {
  140. this.text = text;
  141. }
  142. /**
  143. * Return true if this message spec matches the given compiler message.
  144. */
  145. public boolean matches(IMessage message) {
  146. ISourceLocation loc = message.getSourceLocation();
  147. if ((loc == null) && ((line != -1) || (sourceFileName != null))) {
  148. return false;
  149. }
  150. if (line != -1) {
  151. if (loc.getLine() != line) {
  152. return false;
  153. }
  154. }
  155. if (sourceFileName != null) {
  156. if (!loc.getSourceFile().getPath().endsWith(sourceFileName)) {
  157. return false;
  158. }
  159. }
  160. if (text != null) {
  161. if (message.getMessage().indexOf(text) == -1) {
  162. return false;
  163. }
  164. }
  165. if (seeAlsos != null) {
  166. List extraLocations = message.getExtraSourceLocations();
  167. if (extraLocations.size() != seeAlsos.length) {
  168. return false;
  169. }
  170. for (int i = 0; i < seeAlsos.length; i++) {
  171. if (!hasAMatch(extraLocations,seeAlsos[i])) {
  172. return false;
  173. }
  174. }
  175. }
  176. return true;
  177. }
  178. private boolean hasAMatch(List srcLocations,ISourceLocation sLoc) {
  179. for (Iterator iter = srcLocations.iterator(); iter.hasNext();) {
  180. ISourceLocation thisLoc = (ISourceLocation) iter.next();
  181. if (thisLoc.getLine() == sLoc.getLine()) {
  182. if (thisLoc.getSourceFile().getPath().equals(sLoc.getSourceFile().getPath())) {
  183. return true;
  184. }
  185. }
  186. }
  187. return false;
  188. }
  189. /**
  190. * Returns a string indicating what this <code>Message</code> will match.
  191. */
  192. public String toString() {
  193. StringBuffer buff = new StringBuffer();
  194. buff.append("message ");
  195. if (sourceFileName != null) {
  196. buff.append("in file ");
  197. buff.append(sourceFileName);
  198. buff.append(" ");
  199. }
  200. if (line != -1) {
  201. buff.append("on line ");
  202. buff.append(line);
  203. buff.append(" ");
  204. }
  205. if (text != null) {
  206. buff.append("containing text '");
  207. buff.append(text);
  208. buff.append("' ");
  209. }
  210. if (seeAlsos != null) {
  211. buff.append("\n\twith see alsos:");
  212. for (int i = 0; i < seeAlsos.length; i++) {
  213. buff.append("\t\t");
  214. buff.append(seeAlsos[i].getSourceFile().getPath());
  215. buff.append(":");
  216. buff.append(seeAlsos[i].getLine());
  217. }
  218. }
  219. return buff.toString();
  220. }
  221. }
  222. /**
  223. * Helper class that represents the specification of a set of
  224. * messages expected to be produced from a compiler run.
  225. * <p>
  226. * Instances of MessageSpec are passed to the assertMessage methods
  227. * to validate <code>CompilationResult</code>s.
  228. */
  229. public static class MessageSpec {
  230. /**
  231. * Convenience constant that matches a CompilationResult with
  232. * any number of information messages, but no others.
  233. */
  234. public static final MessageSpec EMPTY_MESSAGE_SET =
  235. new MessageSpec(
  236. null,
  237. Collections.EMPTY_LIST,
  238. Collections.EMPTY_LIST,
  239. Collections.EMPTY_LIST,
  240. Collections.EMPTY_LIST);
  241. boolean ignoreInfos = true;
  242. public List fails;
  243. public List infos;
  244. public List warnings;
  245. public List errors;
  246. public List weaves;
  247. /**
  248. * Set to true to enable or disable comparison of information messages.
  249. */
  250. public void setInfoComparison(boolean enabled) {
  251. this.ignoreInfos = !enabled;
  252. }
  253. /**
  254. * True if information messages are not being included in matching.
  255. */
  256. public boolean isIgnoringInfoMessages() {
  257. return ignoreInfos;
  258. }
  259. /**
  260. * Create a message specification to test a CompilationResult for a
  261. * given set of info, warning, error, and fail messages.
  262. * @param infos The set of info messages to test for. Specifying a non-null value
  263. * for this parameter enables info message comparison.
  264. * @param warnings The set of warning messages to test for - can pass null to indicate
  265. * empty set.
  266. * @param errors The set of error messages to test for - can pass null to indicate
  267. * empty set.
  268. * @param fails The set of fail or abort messages to test for - can pass null to indicate
  269. * empty set.
  270. */
  271. public MessageSpec(List infos, List warnings, List errors, List fails, List weaves) {
  272. if (infos != null) {
  273. this.infos = infos;
  274. ignoreInfos = false;
  275. } else {
  276. this.infos = Collections.EMPTY_LIST;
  277. }
  278. this.warnings = ((warnings == null) ? Collections.EMPTY_LIST : warnings);
  279. this.errors = ((errors == null) ? Collections.EMPTY_LIST : errors);
  280. this.fails = ((fails == null) ? Collections.EMPTY_LIST : fails);
  281. this.weaves = ((weaves == null) ? Collections.EMPTY_LIST : weaves);
  282. }
  283. /**
  284. * Create a message specification to test a CompilationResult for a given
  285. * set of info, warning, and error messages. The presence of any fail or
  286. * abort messages in a CompilationResult will be a test failure.
  287. */
  288. public MessageSpec(List infos, List warnings, List errors) {
  289. this(infos,warnings,errors,null,null);
  290. }
  291. /**
  292. * Create a message specification to test a CompilationResult for a given
  293. * set of warning, and error messages. The presence of any fail or
  294. * abort messages in a CompilationResult will be a test failure. Informational
  295. * messages will be ignored.
  296. */
  297. public MessageSpec(List warnings, List errors) {
  298. this(null,warnings,errors,null,null);
  299. }
  300. }
  301. public static class EmptyMessageSpec extends MessageSpec {
  302. public EmptyMessageSpec() {
  303. super(null,null);
  304. }
  305. }
  306. /**
  307. * Helper class representing the results of running a test program built
  308. * by the compiler. Provides access to the standard out and error of the
  309. * program, and the actual command that was executed.
  310. */
  311. public static class RunResult {
  312. private String command;
  313. private String stdOut;
  314. private String stdErr;
  315. protected RunResult(String command, String stdOut, String stdErr) {
  316. this.command = command;
  317. this.stdOut = stdOut;
  318. this.stdErr = stdErr;
  319. }
  320. /**
  321. * Return the command that was executed, e.g. "java Driver".
  322. */
  323. public String getCommand() { return command; }
  324. /**
  325. * The standard output from the run.
  326. */
  327. public String getStdOut() {return stdOut;}
  328. /**
  329. * The standard error from the run.
  330. */
  331. public String getStdErr() {return stdErr;}
  332. /**
  333. * Returns the command that was executed to produce this result.
  334. */
  335. public String toString() { return command; }
  336. }
  337. /**
  338. * Assert that no (non-informational) messages where produced during a compiler run.
  339. */
  340. public void assertNoMessages(CompilationResult result) {
  341. assertNoMessages(result,"Not expecting any compiler messages to be produced");
  342. }
  343. /**
  344. * Assert that no (non-informational) messages where produced during a compiler run.
  345. */
  346. public void assertNoMessages(CompilationResult result, String message) {
  347. assertMessages(result, message,MessageSpec.EMPTY_MESSAGE_SET);
  348. }
  349. /**
  350. * Assert that messages in accordance with the <code>expected</code> message specification
  351. * where produced during a compiler run.
  352. */
  353. public void assertMessages(CompilationResult result, MessageSpec expected) {
  354. assertMessages(result, "Compilation results did not meet expected messages specification",expected);
  355. }
  356. /**
  357. * Assert that messages in accordance with the <code>expected</code> message specification
  358. * where produced during a compiler run.
  359. */
  360. public void assertMessages(CompilationResult result, String message, MessageSpec expected) {
  361. if (result == null) fail("Attempt to compare null compilation results against expected.");
  362. List missingFails = copyAll(expected.fails);
  363. List missingInfos = copyAll(expected.infos);
  364. List missingWarnings = copyAll(expected.warnings);
  365. List missingErrors = copyAll(expected.errors);
  366. List missingWeaves = copyAll(expected.weaves);
  367. List extraFails = copyAll(result.getFailMessages());
  368. List extraInfos = copyAll(result.getInfoMessages());
  369. List extraWarnings = copyAll(result.getWarningMessages());
  370. List extraErrors = copyAll(result.getErrorMessages());
  371. List extraWeaves = copyAll(result.getWeaveMessages());
  372. compare(expected.fails,result.getFailMessages(),missingFails,extraFails);
  373. compare(expected.warnings,result.getWarningMessages(),missingWarnings,extraWarnings);
  374. compare(expected.errors,result.getErrorMessages(),missingErrors,extraErrors);
  375. if (!expected.isIgnoringInfoMessages()) {
  376. compare(expected.infos,result.getInfoMessages(),missingInfos,extraInfos);
  377. }
  378. compare(expected.weaves,result.getWeaveMessages(),missingWeaves,extraWeaves);
  379. boolean infosEmpty = expected.isIgnoringInfoMessages() ? true: (missingInfos.isEmpty() && extraInfos.isEmpty());
  380. if ( !(missingFails.isEmpty() && missingWarnings.isEmpty() && missingErrors.isEmpty() && missingWeaves.isEmpty() &&
  381. extraFails.isEmpty() && extraWarnings.isEmpty() && extraErrors.isEmpty() && extraWeaves.isEmpty() && infosEmpty)) {
  382. StringBuffer failureReport = new StringBuffer(message);
  383. failureReport.append("\n");
  384. if (!expected.isIgnoringInfoMessages()) {
  385. addMissing(failureReport,"info",missingInfos);
  386. }
  387. addMissing(failureReport,"warning",missingWarnings);
  388. addMissing(failureReport,"error",missingErrors);
  389. addMissing(failureReport,"fail",missingFails);
  390. addMissing(failureReport,"weaveInfo",missingWeaves);
  391. if (!expected.isIgnoringInfoMessages()) {
  392. addExtra(failureReport,"info",extraInfos);
  393. }
  394. addExtra(failureReport,"warning",extraWarnings);
  395. addExtra(failureReport,"error",extraErrors);
  396. addExtra(failureReport,"fail",extraFails);
  397. addExtra(failureReport,"weaveInfo",extraWeaves);
  398. failureReport.append("\ncommand was: ajc");
  399. String[] args = result.getArgs();
  400. for (int i = 0; i < args.length; i++) {
  401. failureReport.append(" ");
  402. failureReport.append(args[i]);
  403. }
  404. String report = failureReport.toString();
  405. System.err.println(failureReport);
  406. fail(message + "\n" + report);
  407. }
  408. }
  409. /**
  410. * Helper method to build a new message list for passing to a MessageSpec.
  411. */
  412. protected List newMessageList(Message m1) {
  413. List ret = new ArrayList();
  414. ret.add(m1);
  415. return ret;
  416. }
  417. /**
  418. * Helper method to build a new message list for passing to a MessageSpec.
  419. */
  420. protected List newMessageList(Message m1, Message m2) {
  421. List ret = new ArrayList();
  422. ret.add(m1);
  423. ret.add(m2);
  424. return ret;
  425. }
  426. /**
  427. * Helper method to build a new message list for passing to a MessageSpec.
  428. */
  429. protected List newMessageList(Message m1, Message m2, Message m3) {
  430. List ret = new ArrayList();
  431. ret.add(m1);
  432. ret.add(m2);
  433. ret.add(m3);
  434. return ret;
  435. }
  436. /**
  437. * Helper method to build a new message list for passing to a MessageSpec.
  438. */
  439. protected List newMessageList(Message[] messages) {
  440. List ret = new ArrayList();
  441. for (int i = 0; i < messages.length; i++) {
  442. ret.add(messages[i]);
  443. }
  444. return ret;
  445. }
  446. /**
  447. * Perform a compilation and return the result.
  448. * @param baseDir the base directory relative to which all relative paths and
  449. * directories in the arguments will be interpreted.
  450. * @param args the compiler arguments, as you would specify on the command-line.
  451. * See the Ajc class for a description of the argument processing done in
  452. * order to run the compilation in a sandbox.
  453. * @see org.aspectj.tools.ajc.Ajc
  454. */
  455. public CompilationResult ajc(File baseDir, String[] args) {
  456. try {
  457. ajc.setBaseDir(baseDir);
  458. args = fixupArgs(args);
  459. return ajc.compile(args);
  460. } catch(IOException ioEx ) {
  461. fail("IOException thrown during compilation: " + ioEx);
  462. }
  463. return null;
  464. }
  465. public File getSandboxDirectory() {
  466. return ajc.getSandboxDirectory();
  467. }
  468. /**
  469. * Indicate whether or not the sandbox should be emptied before the next compile.
  470. * @see org.aspectj.tools.ajc.Ajc#setShouldEmptySandbox(boolean)
  471. */
  472. public void setShouldEmptySandbox(boolean empty) {
  473. ajc.setShouldEmptySandbox(empty);
  474. }
  475. public RunResult getLastRunResult() {
  476. return lastRunResult;
  477. }
  478. public void testNothingForAntJUnit() {}
  479. /**
  480. * Run the given class (main method), and return the result in a RunResult. The program runs with
  481. * a classpath containing the sandbox directory, runtime, testing-client, bridge, and
  482. * util projects (all used by the Tester class), and any jars in the sandbox.
  483. */
  484. public RunResult run(String className){
  485. return run(className,new String[0],null);
  486. }
  487. public RunResult run(String className, String[] args, String classpath) {
  488. return run(className,args,null,false);
  489. }
  490. /**
  491. * Run the given class, and return the result in a RunResult. The program runs with
  492. * a classpath containing the sandbox directory, runtime, testing-client, bridge, and
  493. * util projects (all used by the Tester class), and any jars in the sandbox.
  494. * @param args the arguments to pass to the program.
  495. * @param classpath the execution classpath, the sandbox directory, runtime, testing-client,
  496. * bridge, and util projects will all be appended to the classpath, as will any jars in
  497. * the sandbox.
  498. */
  499. public RunResult run(String className, String[] args, String classpath, boolean useLTW) {
  500. lastRunResult = null;
  501. StringBuffer cp = new StringBuffer();
  502. if (classpath != null) {
  503. cp.append(classpath);
  504. cp.append(File.pathSeparator);
  505. }
  506. cp.append(ajc.getSandboxDirectory().getAbsolutePath());
  507. cp.append(DEFAULT_CLASSPATH_ENTRIES);
  508. getAnyJars(ajc.getSandboxDirectory(),cp);
  509. classpath = cp.toString();
  510. StringBuffer command = new StringBuffer("java -classpath ");
  511. command.append(classpath);
  512. command.append(" ");
  513. command.append(className);
  514. for (int i = 0; i < args.length; i++) {
  515. command.append(" ");
  516. command.append(args[i]);
  517. }
  518. PrintStream systemOut = System.out;
  519. PrintStream systemErr = System.err;
  520. ByteArrayOutputStream baosOut = new ByteArrayOutputStream();
  521. ByteArrayOutputStream baosErr = new ByteArrayOutputStream();
  522. StringTokenizer strTok = new StringTokenizer(classpath,File.pathSeparator);
  523. URL[] urls = new URL[strTok.countTokens()];
  524. try {
  525. for (int i = 0; i < urls.length; i++) {
  526. urls[i] = new File(strTok.nextToken()).getCanonicalFile().toURL();
  527. }
  528. } catch (Exception malEx) {
  529. fail("Bad classpath specification: " + classpath);
  530. }
  531. URLClassLoader cLoader;
  532. if (useLTW) {
  533. ClassLoader parent = getClass().getClassLoader();
  534. cLoader = new WeavingURLClassLoader(urls,parent);
  535. }
  536. else {
  537. cLoader = new URLClassLoader(urls,null);
  538. }
  539. try {
  540. try {
  541. Class testerClass = cLoader.loadClass("org.aspectj.testing.Tester");
  542. Method setBaseDir = testerClass.getDeclaredMethod("setBASEDIR",new Class[] {File.class});
  543. setBaseDir.invoke(null,new Object[] {ajc.getSandboxDirectory()});
  544. } catch (Exception ex) {
  545. fail ("Unable to prepare org.aspectj.testing.Tester for test run: " + ex);
  546. }
  547. System.setOut(new PrintStream(baosOut));
  548. System.setErr(new PrintStream(baosErr));
  549. Class toRun = cLoader.loadClass(className);
  550. Method mainMethod = toRun.getMethod("main",new Class[] {String[].class});
  551. mainMethod.invoke(null,new Object[] {args});
  552. lastRunResult = new RunResult(command.toString(),new String(baosOut.toByteArray()),new String(baosErr.toByteArray()));
  553. } catch(ClassNotFoundException cnf) {
  554. fail("Can't find class: " + className);
  555. } catch(NoSuchMethodException nsm) {
  556. fail(className + " does not have a main method");
  557. } catch (IllegalAccessException illEx) {
  558. fail("main method in class " + className + " is not public");
  559. } catch (InvocationTargetException invTgt) {
  560. // the main method threw an exception...
  561. fail("Exception thrown by " + className + ".main(String[]) :" + invTgt.getTargetException());
  562. } finally {
  563. System.setOut(systemOut);
  564. System.setErr(systemErr);
  565. }
  566. return lastRunResult;
  567. }
  568. /**
  569. * Any central pre-processing of args.
  570. * This supplies aspectjrt.jar if available and classpath not set.
  571. * @param args the String[] args to fix up
  572. * @return the String[] args to use
  573. */
  574. protected String[] fixupArgs(String[] args) {
  575. if (null == args) {
  576. return null;
  577. }
  578. int cpIndex = -1;
  579. boolean hasruntime = false;
  580. for (int i = 0; i < args.length-1; i++) {
  581. args[i] = adaptToPlatform(args[i]);
  582. if ("-classpath".equals(args[i])) {
  583. cpIndex = i;
  584. String next = args[i+1];
  585. hasruntime = ((null != next)
  586. && (-1 != next.indexOf("aspectjrt.jar")));
  587. }
  588. }
  589. if (-1 == cpIndex) {
  590. String[] newargs = new String[args.length + 2];
  591. newargs[0] = "-classpath";
  592. newargs[1] = TestUtil.aspectjrtPath().getPath();
  593. System.arraycopy(args, 0, newargs, 2, args.length);
  594. args = newargs;
  595. } else {
  596. if (!hasruntime) {
  597. cpIndex++;
  598. String[] newargs = new String[args.length];
  599. System.arraycopy(args, 0, newargs, 0, args.length);
  600. newargs[cpIndex] = args[cpIndex] + File.pathSeparator
  601. + TestUtil.aspectjrtPath().getPath();
  602. args = newargs;
  603. }
  604. }
  605. return args;
  606. }
  607. private String adaptToPlatform(String s) {
  608. String ret = s.replace(';',File.pathSeparatorChar);
  609. //ret = ret.replace(':',File.pathSeparatorChar);
  610. return ret;
  611. }
  612. private List copyAll(List in) {
  613. if (in == Collections.EMPTY_LIST) return in;
  614. List out = new ArrayList();
  615. for (Iterator iter = in.iterator(); iter.hasNext();) {
  616. out.add(iter.next());
  617. }
  618. return out;
  619. }
  620. /**
  621. * Compare the set of expected messages against the set of actual messages,
  622. * leaving in missingElements the set of messages that were expected but did not
  623. * occur, and in extraElements the set of messages that occured but were not
  624. * excpected
  625. * @param expected the expected messages
  626. * @param actual the actual messages
  627. * @param missingElements the missing messages, when passed in must contain all of the expected messages
  628. * @param extraElements the additional messages, when passed in must contain all of the actual messages
  629. */
  630. private void compare(List expected, List actual, List missingElements, List extraElements) {
  631. for (Iterator expectedIter = expected.iterator(); expectedIter.hasNext();) {
  632. Message expectedMessage = (Message) expectedIter.next();
  633. for (Iterator actualIter = actual.iterator(); actualIter.hasNext();) {
  634. IMessage actualMessage = (IMessage) actualIter.next();
  635. if (expectedMessage.matches(actualMessage)) {
  636. missingElements.remove(expectedMessage);
  637. extraElements.remove(actualMessage);
  638. }
  639. }
  640. }
  641. }
  642. private void addMissing(StringBuffer buff,String type, List messages) {
  643. if (!messages.isEmpty()) {
  644. buff.append("Missing expected ");
  645. buff.append(type);
  646. buff.append(" messages:\n");
  647. for (Iterator iter = messages.iterator(); iter.hasNext();) {
  648. buff.append("\t");
  649. buff.append(iter.next().toString());
  650. buff.append("\n");
  651. }
  652. }
  653. }
  654. private void addExtra(StringBuffer buff, String type, List messages) {
  655. if (!messages.isEmpty()) {
  656. buff.append("Unexpected ");
  657. buff.append(type);
  658. buff.append(" messages:\n");
  659. for (Iterator iter = messages.iterator(); iter.hasNext();) {
  660. buff.append("\t");
  661. buff.append(iter.next().toString());
  662. buff.append("\n");
  663. }
  664. }
  665. }
  666. // add any jars in the directory to the classpath
  667. private void getAnyJars(File dir,StringBuffer buff) {
  668. File[] files = dir.listFiles();
  669. for (int i = 0; i < files.length; i++) {
  670. if (files[i].getName().endsWith(".jar")) {
  671. buff.append(File.pathSeparator);
  672. buff.append(files[i].getAbsolutePath());
  673. } else if (files[i].isDirectory()) {
  674. getAnyJars(files[i],buff);
  675. }
  676. }
  677. }
  678. /* (non-Javadoc)
  679. * @see junit.framework.TestCase#setUp()
  680. */
  681. protected void setUp() throws Exception {
  682. super.setUp();
  683. ajc = new Ajc();
  684. }
  685. /* (non-Javadoc)
  686. * @see junit.framework.TestCase#tearDown()
  687. */
  688. protected void tearDown() throws Exception {
  689. super.tearDown();
  690. //ajc = null;
  691. }
  692. }