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 27KB

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