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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095
  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 Eclipse Public License v1.0
  6. * which accompanies this distribution and is available at
  7. * http://www.eclipse.org/legal/epl-v10.html
  8. *
  9. * Contributors:
  10. * Adrian Colyer, Abraham Nevado (lucierna)
  11. * ******************************************************************/
  12. package org.aspectj.tools.ajc;
  13. import java.io.BufferedReader;
  14. import java.io.ByteArrayOutputStream;
  15. import java.io.File;
  16. import java.io.IOException;
  17. import java.io.InputStreamReader;
  18. import java.io.OutputStream;
  19. import java.io.PrintStream;
  20. import java.io.PrintWriter;
  21. import java.lang.reflect.Constructor;
  22. import java.lang.reflect.InvocationTargetException;
  23. import java.lang.reflect.Method;
  24. import java.net.URL;
  25. import java.net.URLClassLoader;
  26. import java.util.ArrayList;
  27. import java.util.Collections;
  28. import java.util.List;
  29. import java.util.StringTokenizer;
  30. import org.aspectj.bridge.IMessage;
  31. import org.aspectj.bridge.ISourceLocation;
  32. import org.aspectj.testing.util.TestUtil;
  33. import org.aspectj.util.LangUtil;
  34. import junit.framework.TestCase;
  35. /**
  36. * A TestCase class that acts as the superclass for all test cases wishing to drive the ajc compiler.
  37. * <p>
  38. * This class provides a number of utility methods that make programmatic testing of the compiler easy. See AjcTestCaseTest for a
  39. * couple of simple tests written using this class.
  40. * </p>
  41. * <p>
  42. * See the XMLBasedAjcTestCase subclass for TestCase class that can be used to drive compiler tests based on an ajcTests.xml format
  43. * test specification file.
  44. * </p>
  45. *
  46. * @see org.aspectj.tools.ajc.AjcTestCase.Message
  47. * @see org.aspectj.tools.ajc.AjcTestCase.MessageSpec
  48. * @see org.aspectj.tools.ajc.AjcTestCase.RunResult
  49. * @see org.aspectj.tools.ajc.AjcTestCaseTest
  50. * @see org.aspectj.testing.XMLBasedAjcTestCase
  51. */
  52. public abstract class AjcTestCase extends TestCase {
  53. private RunResult lastRunResult;
  54. /**
  55. * The Ajc (compiler) instance used for the test. Created afresh during the test setup.
  56. */
  57. protected Ajc ajc;
  58. // see Ajc and AntSpec
  59. public static final String DEFAULT_CLASSPATH_ENTRIES =
  60. Ajc.outputFolders("bridge","util","loadtime","weaver","asm","testing-client","runtime","org.aspectj.matcher")
  61. // File.pathSeparator + ".." + File.separator + "bridge" + File.separator
  62. // + "bin" + File.pathSeparator + ".." + File.separator + "util" + File.separator + "bin" + File.pathSeparator + ".."
  63. // + File.separator + "loadtime" + File.separator + "bin" + File.pathSeparator + ".." + File.separator + "weaver"
  64. // + File.separator + "bin" + File.pathSeparator + ".." + File.separator + "weaver5" + File.separator + "bin"
  65. // + File.pathSeparator + ".." + File.separator + "asm" + File.separator + "bin" + File.pathSeparator + ".."
  66. // + File.separator + "testing-client" + File.separator + "bin" + File.pathSeparator + ".." + File.separator + "runtime"
  67. // + File.separator + "bin" + File.pathSeparator + ".." + File.separator + "aspectj5rt" + File.separator + "bin"
  68. // + File.pathSeparator + ".." + File.separator + "org.aspectj.matcher" + File.separator + "bin"
  69. + File.pathSeparator
  70. + ".." + File.separator + "lib" + File.separator + "junit" + File.separator
  71. + "junit.jar"
  72. + File.pathSeparator
  73. + ".."
  74. + File.separator
  75. + "lib"
  76. + File.separator
  77. + "bcel"
  78. + File.separator
  79. + "bcel.jar"
  80. + File.pathSeparator
  81. + ".."
  82. + File.separator
  83. + "lib"
  84. + File.separator
  85. + "bcel"
  86. + File.separator
  87. + "bcel-verifier.jar"
  88. + File.pathSeparator + ".." + File.separator + "lib" + File.separator + "asm" + File.separator + "asm-8.0.1.renamed.jar"
  89. // When the build machine executes the tests, it is using code built into jars rather than code build into
  90. // bin directories. This means for the necessary types to be found we have to put these jars on the classpath:
  91. + File.pathSeparator + ".." + File.separator + "aj-build" + File.separator + "jars" + File.separator + "bridge.jar"
  92. + File.pathSeparator + ".." + File.separator + "aj-build" + File.separator + "jars" + File.separator + "util.jar"
  93. + File.pathSeparator + ".." + File.separator + "aj-build" + File.separator + "jars" + File.separator
  94. + "org.aspectj.matcher.jar" + File.pathSeparator + ".." + File.separator + "aj-build" + File.separator + "jars"
  95. + File.separator + "loadtime.jar" + File.pathSeparator + ".." + File.separator + "aj-build" + File.separator + "jars"
  96. + File.separator + "weaver.jar" + File.pathSeparator + ".." + File.separator + "aj-build" + File.separator + "jars"
  97. + File.pathSeparator + ".." + File.separator + "aj-build" + File.separator + "jars"
  98. + File.separator + "asm.jar" + File.pathSeparator + ".." + File.separator + "lib" + File.separator + "test"
  99. + File.separator + "testing-client.jar"
  100. // hmmm, this next one should perhaps point to an aj-build jar...
  101. + File.pathSeparator + ".." + File.separator + "lib" + File.separator + "test" + File.separator + "aspectjrt.jar";
  102. /*
  103. * Save reference to real stderr and stdout before starting redirection
  104. */
  105. public final static PrintStream err = System.err;
  106. public final static PrintStream out = System.out;
  107. private final static DelegatingOutputStream delegatingErr;
  108. private final static DelegatingOutputStream delegatingOut;
  109. public final static boolean DEFAULT_VERBOSE = getBoolean("aspectj.tests.verbose", true);
  110. public final static boolean DEFAULT_ERR_VERBOSE = getBoolean("org.aspectj.tools.ajc.AjcTestCase.verbose.err", DEFAULT_VERBOSE);
  111. public final static boolean DEFAULT_OUT_VERBOSE = getBoolean("org.aspectj.tools.ajc.AjcTestCase.verbose.out", DEFAULT_VERBOSE);
  112. private Process exec;
  113. /**
  114. * Helper class that represents the specification of an individual message expected to be produced during a compilation run.
  115. * <p>
  116. * Message objects are combined in a MessageSpec which can then be passed to the various assertMessage methods.
  117. * </p>
  118. *
  119. * @see org.aspectj.tools.ajc.AjcTestCase.MessageSpec
  120. */
  121. public static class Message {
  122. private int line = -1;
  123. private String text;
  124. private String sourceFileName;
  125. private ISourceLocation[] seeAlsos;
  126. public boolean careAboutOtherMessages = true;
  127. /**
  128. * Create a message that will match any compiler message on the given line.
  129. */
  130. public Message(int line) {
  131. this.line = line;
  132. }
  133. /**
  134. * Create a message that will match any compiler message on the given line, where the message text contains
  135. * <code>text</code>.
  136. */
  137. public Message(int line, String text) {
  138. this.line = line;
  139. this.text = text;
  140. if (this.text != null && text.startsWith("*")) {
  141. // Don't care what other messages are around
  142. this.careAboutOtherMessages = false;
  143. this.text = this.text.substring(1);
  144. }
  145. }
  146. /**
  147. * Create a message that will match any compiler message on the given line, where the message text contains
  148. * <code>text</code>.
  149. * <p>
  150. * If srcFile is non-null, the source file location of the message must end with <code>srcFile</code>.
  151. * </p>
  152. * <p>
  153. * If <code>seeAlso</code> is non-null, each source location in seeAlso must be matched by an extraSourceLocation in the
  154. * message.
  155. * </p>
  156. */
  157. public Message(int line, String srcFile, String text, ISourceLocation[] seeAlso) {
  158. this.line = line;
  159. StringBuffer srcFileName = new StringBuffer();
  160. if (srcFile != null) {
  161. char[] chars = srcFile.toCharArray();
  162. for (char c : chars) {
  163. if ((c == '\\') || (c == '/')) {
  164. srcFileName.append(File.separator);
  165. } else {
  166. srcFileName.append(c);
  167. }
  168. }
  169. this.sourceFileName = srcFileName.toString();
  170. }
  171. this.text = text;
  172. if (this.text != null && text.startsWith("*")) {
  173. // Don't care what other messages are around
  174. this.careAboutOtherMessages = false;
  175. this.text = this.text.substring(1);
  176. }
  177. this.seeAlsos = seeAlso;
  178. }
  179. /**
  180. * Create a message spec that will match any compiler message where the message text includes <code>text</code>.
  181. */
  182. public Message(String text) {
  183. this.text = text;
  184. if (this.text != null && text.startsWith("*")) {
  185. // Don't care what other messages are around
  186. this.careAboutOtherMessages = false;
  187. this.text = this.text.substring(1);
  188. }
  189. }
  190. /**
  191. * Return true if this message spec matches the given compiler message.
  192. */
  193. public boolean matches(IMessage message) {
  194. ISourceLocation loc = message.getSourceLocation();
  195. if ((loc == null) && ((line != -1) || (sourceFileName != null))) {
  196. return false;
  197. }
  198. if (line != -1) {
  199. if (loc.getLine() != line) {
  200. return false;
  201. }
  202. }
  203. if (sourceFileName != null) {
  204. if (!loc.getSourceFile().getPath().endsWith(sourceFileName)) {
  205. return false;
  206. }
  207. }
  208. if (text != null) {
  209. if (!message.getMessage().contains(text)) {
  210. return false;
  211. }
  212. }
  213. if (seeAlsos != null) {
  214. List<ISourceLocation> extraLocations = message.getExtraSourceLocations();
  215. if (extraLocations.size() != seeAlsos.length) {
  216. return false;
  217. }
  218. for (ISourceLocation seeAlso : seeAlsos) {
  219. if (!hasAMatch(extraLocations, seeAlso)) {
  220. return false;
  221. }
  222. }
  223. }
  224. return true;
  225. }
  226. private boolean hasAMatch(List<ISourceLocation> srcLocations, ISourceLocation sLoc) {
  227. for (ISourceLocation thisLoc: srcLocations) {
  228. if (thisLoc.getLine() == sLoc.getLine()) {
  229. if (thisLoc.getSourceFile().getPath().equals(sLoc.getSourceFile().getPath())) {
  230. return true;
  231. }
  232. }
  233. }
  234. return false;
  235. }
  236. /**
  237. * Returns a string indicating what this <code>Message</code> will match.
  238. */
  239. @Override
  240. public String toString() {
  241. StringBuffer buff = new StringBuffer();
  242. buff.append("message ");
  243. if (sourceFileName != null) {
  244. buff.append("in file ");
  245. buff.append(sourceFileName);
  246. buff.append(" ");
  247. }
  248. if (line != -1) {
  249. buff.append("on line ");
  250. buff.append(line);
  251. buff.append(" ");
  252. }
  253. if (text != null) {
  254. buff.append("containing text '");
  255. buff.append(text);
  256. buff.append("' ");
  257. }
  258. if (seeAlsos != null) {
  259. buff.append("\n\twith see alsos:");
  260. for (ISourceLocation seeAlso : seeAlsos) {
  261. buff.append("\t\t");
  262. buff.append(seeAlso.getSourceFile().getPath());
  263. buff.append(":");
  264. buff.append(seeAlso.getLine());
  265. }
  266. }
  267. return buff.toString();
  268. }
  269. }
  270. /**
  271. * Helper class that represents the specification of a set of messages expected to be produced from a compiler run.
  272. * <p>
  273. * Instances of MessageSpec are passed to the assertMessage methods to validate <code>CompilationResult</code>s.
  274. */
  275. public static class MessageSpec {
  276. /**
  277. * Convenience constant that matches a CompilationResult with any number of information messages, but no others.
  278. */
  279. public static final MessageSpec EMPTY_MESSAGE_SET = new MessageSpec(null, Collections.EMPTY_LIST, Collections.EMPTY_LIST,
  280. Collections.EMPTY_LIST, Collections.EMPTY_LIST);
  281. boolean ignoreInfos = true;
  282. public List<AjcTestCase.Message> fails;
  283. public List<AjcTestCase.Message> infos;
  284. public List<AjcTestCase.Message> warnings;
  285. public List<AjcTestCase.Message> errors;
  286. public List<AjcTestCase.Message> weaves;
  287. /**
  288. * Set to true to enable or disable comparison of information messages.
  289. */
  290. public void setInfoComparison(boolean enabled) {
  291. this.ignoreInfos = !enabled;
  292. }
  293. /**
  294. * True if information messages are not being included in matching.
  295. */
  296. public boolean isIgnoringInfoMessages() {
  297. return ignoreInfos;
  298. }
  299. /**
  300. * Create a message specification to test a CompilationResult for a given set of info, warning, error, and fail messages.
  301. *
  302. * @param infos The set of info messages to test for. Specifying a non-null value for this parameter enables info message
  303. * comparison.
  304. * @param warnings The set of warning messages to test for - can pass null to indicate empty set.
  305. * @param errors The set of error messages to test for - can pass null to indicate empty set.
  306. * @param fails The set of fail or abort messages to test for - can pass null to indicate empty set.
  307. */
  308. public MessageSpec(List<AjcTestCase.Message> infos, List<AjcTestCase.Message> warnings,
  309. List<AjcTestCase.Message> errors, List<AjcTestCase.Message> fails, List<AjcTestCase.Message> weaves) {
  310. if (infos != null) {
  311. this.infos = infos;
  312. ignoreInfos = false;
  313. } else {
  314. this.infos = Collections.emptyList();
  315. }
  316. this.warnings = ((warnings == null) ? Collections.<AjcTestCase.Message>emptyList() : warnings);
  317. this.errors = ((errors == null) ? Collections.<AjcTestCase.Message>emptyList() : errors);
  318. this.fails = ((fails == null) ? Collections.<AjcTestCase.Message>emptyList() : fails);
  319. this.weaves = ((weaves == null) ? Collections.<AjcTestCase.Message>emptyList() : weaves);
  320. }
  321. /**
  322. * Create a message specification to test a CompilationResult for a given set of info, warning, and error messages. The
  323. * presence of any fail or abort messages in a CompilationResult will be a test failure.
  324. */
  325. public MessageSpec(List<AjcTestCase.Message> infos, List<AjcTestCase.Message> warnings, List<AjcTestCase.Message> errors) {
  326. this(infos, warnings, errors, null, null);
  327. }
  328. /**
  329. * Create a message specification to test a CompilationResult for a given set of warning, and error messages. The presence
  330. * of any fail or abort messages in a CompilationResult will be a test failure. Informational messages will be ignored.
  331. */
  332. public MessageSpec(List<AjcTestCase.Message> warnings, List<AjcTestCase.Message> errors) {
  333. this(null, warnings, errors, null, null);
  334. }
  335. }
  336. public static class EmptyMessageSpec extends MessageSpec {
  337. public EmptyMessageSpec() {
  338. super(null, null);
  339. }
  340. }
  341. /**
  342. * Helper class representing the results of running a test program built by the compiler. Provides access to the standard out
  343. * and error of the program, and the actual command that was executed.
  344. */
  345. public static class RunResult {
  346. private final String command;
  347. private final String stdOut;
  348. private final String stdErr;
  349. protected RunResult(String command, String stdOut, String stdErr) {
  350. this.command = command;
  351. this.stdOut = stdOut;
  352. this.stdErr = stdErr;
  353. }
  354. /**
  355. * Return the command that was executed, e.g. "java Driver".
  356. */
  357. public String getCommand() {
  358. return command;
  359. }
  360. /**
  361. * The standard output from the run.
  362. */
  363. public String getStdOut() {
  364. return stdOut;
  365. }
  366. /**
  367. * The standard error from the run.
  368. */
  369. public String getStdErr() {
  370. return stdErr;
  371. }
  372. /**
  373. * Returns the command that was executed to produce this result.
  374. */
  375. @Override
  376. public String toString() {
  377. return command;
  378. }
  379. }
  380. /**
  381. * Assert that no (non-informational) messages where produced during a compiler run.
  382. */
  383. public void assertNoMessages(CompilationResult result) {
  384. assertNoMessages(result, "Not expecting any compiler messages to be produced");
  385. }
  386. /**
  387. * Assert that no (non-informational) messages where produced during a compiler run.
  388. */
  389. public void assertNoMessages(CompilationResult result, String message) {
  390. assertMessages(result, message, MessageSpec.EMPTY_MESSAGE_SET);
  391. }
  392. /**
  393. * Assert that messages in accordance with the <code>expected</code> message specification where produced during a compiler run.
  394. */
  395. public void assertMessages(CompilationResult result, MessageSpec expected) {
  396. assertMessages(result, "Compilation results did not meet expected messages specification", expected);
  397. }
  398. /**
  399. * Assert that messages in accordance with the <code>expected</code> message specification where produced during a compiler run.
  400. */
  401. public void assertMessages(CompilationResult result, String message, MessageSpec expected) {
  402. if (result == null)
  403. fail("Attempt to compare null compilation results against expected.");
  404. List<AjcTestCase.Message> missingFails = copyAll(expected.fails);
  405. List<AjcTestCase.Message> missingInfos = copyAll(expected.infos);
  406. List<AjcTestCase.Message> missingWarnings = copyAll(expected.warnings);
  407. List<AjcTestCase.Message> missingErrors = copyAll(expected.errors);
  408. List<AjcTestCase.Message> missingWeaves = copyAll(expected.weaves);
  409. List<IMessage> extraFails = copyAll(result.getFailMessages());
  410. List<IMessage> extraInfos = copyAll(result.getInfoMessages());
  411. List<IMessage> extraWarnings = copyAll(result.getWarningMessages());
  412. List<IMessage> extraErrors = copyAll(result.getErrorMessages());
  413. List<IMessage> extraWeaves = copyAll(result.getWeaveMessages());
  414. compare(expected.fails, result.getFailMessages(), missingFails, extraFails);
  415. compare(expected.warnings, result.getWarningMessages(), missingWarnings, extraWarnings);
  416. compare(expected.errors, result.getErrorMessages(), missingErrors, extraErrors);
  417. if (!expected.isIgnoringInfoMessages()) {
  418. compare(expected.infos, result.getInfoMessages(), missingInfos, extraInfos);
  419. }
  420. compare(expected.weaves, result.getWeaveMessages(), missingWeaves, extraWeaves);
  421. boolean infosEmpty = expected.isIgnoringInfoMessages() ? true : (missingInfos.isEmpty() && extraInfos.isEmpty());
  422. if (!(missingFails.isEmpty() && missingWarnings.isEmpty() && missingErrors.isEmpty() && missingWeaves.isEmpty()
  423. && extraFails.isEmpty() && extraWarnings.isEmpty() && extraErrors.isEmpty() && extraWeaves.isEmpty() && infosEmpty)) {
  424. StringBuffer failureReport = new StringBuffer(message);
  425. failureReport.append("\n");
  426. if (!expected.isIgnoringInfoMessages()) {
  427. addMissing(failureReport, "info", missingInfos);
  428. }
  429. addMissing(failureReport, "warning", missingWarnings);
  430. addMissing(failureReport, "error", missingErrors);
  431. addMissing(failureReport, "fail", missingFails);
  432. addMissing(failureReport, "weaveInfo", missingWeaves);
  433. if (!expected.isIgnoringInfoMessages()) {
  434. addExtra(failureReport, "info", extraInfos);
  435. }
  436. addExtra(failureReport, "warning", extraWarnings);
  437. addExtra(failureReport, "error", extraErrors);
  438. addExtra(failureReport, "fail", extraFails);
  439. addExtra(failureReport, "weaveInfo", extraWeaves);
  440. failureReport.append("\ncommand was: 'ajc");
  441. String[] args = result.getArgs();
  442. for (String arg : args) {
  443. failureReport.append(" ");
  444. failureReport.append(arg);
  445. }
  446. String report = failureReport.toString();
  447. System.err.println(failureReport);
  448. fail(message + "'\n" + report);
  449. }
  450. }
  451. /**
  452. * Helper method to build a new message list for passing to a MessageSpec.
  453. */
  454. protected List<Message> newMessageList(Message m1) {
  455. List<Message> ret = new ArrayList<>();
  456. ret.add(m1);
  457. return ret;
  458. }
  459. /**
  460. * Helper method to build a new message list for passing to a MessageSpec.
  461. */
  462. protected List<Message> newMessageList(Message m1, Message m2) {
  463. List<Message> ret = new ArrayList<>();
  464. ret.add(m1);
  465. ret.add(m2);
  466. return ret;
  467. }
  468. /**
  469. * Helper method to build a new message list for passing to a MessageSpec.
  470. */
  471. protected List<Message> newMessageList(Message m1, Message m2, Message m3) {
  472. List<Message> ret = new ArrayList<>();
  473. ret.add(m1);
  474. ret.add(m2);
  475. ret.add(m3);
  476. return ret;
  477. }
  478. /**
  479. * Helper method to build a new message list for passing to a MessageSpec.
  480. */
  481. protected List newMessageList(Message[] messages) {
  482. List ret = new ArrayList();
  483. Collections.addAll(ret, messages);
  484. return ret;
  485. }
  486. /**
  487. * Perform a compilation and return the result.
  488. *
  489. * @param baseDir the base directory relative to which all relative paths and directories in the arguments will be interpreted.
  490. * @param args the compiler arguments, as you would specify on the command-line. See the Ajc class for a description of the
  491. * argument processing done in order to run the compilation in a sandbox.
  492. * @see org.aspectj.tools.ajc.Ajc
  493. */
  494. public CompilationResult ajc(File baseDir, String[] args) {
  495. try {
  496. ajc.setBaseDir(baseDir);
  497. args = fixupArgs(args);
  498. return ajc.compile(args);
  499. } catch (IOException ioEx) {
  500. fail("IOException thrown during compilation: " + ioEx);
  501. }
  502. return null;
  503. }
  504. public File getSandboxDirectory() {
  505. return ajc.getSandboxDirectory();
  506. }
  507. /**
  508. * Indicate whether or not the sandbox should be emptied before the next compile.
  509. *
  510. * @see org.aspectj.tools.ajc.Ajc#setShouldEmptySandbox(boolean)
  511. */
  512. public void setShouldEmptySandbox(boolean empty) {
  513. ajc.setShouldEmptySandbox(empty);
  514. }
  515. public RunResult getLastRunResult() {
  516. return lastRunResult;
  517. }
  518. /**
  519. * Run the given class (main method), and return the result in a RunResult. The program runs with a classpath containing the
  520. * sandbox directory, runtime, testing-client, bridge, and util projects (all used by the Tester class), and any jars in the
  521. * sandbox.
  522. */
  523. public RunResult run(String className) {
  524. return run(className, new String[0], null);
  525. }
  526. public RunResult run(String className, String[] args, String classpath) {
  527. return run(className, null, args, "", "", null, false,false);
  528. }
  529. /**
  530. * Run the given class, and return the result in a RunResult. The program runs with a classpath containing the sandbox
  531. * directory, runtime, testing-client, bridge, and util projects (all used by the Tester class), and any jars in the sandbox.
  532. *
  533. * @param args the arguments to pass to the program.
  534. * @param classpath the execution classpath, the sandbox directory, runtime, testing-client, bridge, and util projects will all
  535. * be appended to the classpath, as will any jars in the sandbox.
  536. * @param runSpec
  537. */
  538. public RunResult run(String className, String moduleName, String[] args, String vmargs, final String classpath, String modulepath, boolean useLTW, boolean useFullLTW) {
  539. if (args != null) {
  540. for (int i = 0; i < args.length; i++) {
  541. args[i] = substituteSandbox(args[i]);
  542. }
  543. }
  544. lastRunResult = null;
  545. StringBuffer cp = new StringBuffer();
  546. if (classpath != null) {
  547. // allow replacing this special variable, rather than copying all files to allow tests of jars that don't end in .jar
  548. cp.append(substituteSandbox(classpath));
  549. cp.append(File.pathSeparator);
  550. }
  551. if (moduleName == null) {
  552. // When running modules, we want more control so don't try to be helpful by adding all jars
  553. cp.append(ajc.getSandboxDirectory().getAbsolutePath());
  554. getAnyJars(ajc.getSandboxDirectory(), cp);
  555. }
  556. StringBuffer mp = new StringBuffer();
  557. if (modulepath != null) {
  558. mp.append(substituteSandbox(modulepath));
  559. mp.append(File.pathSeparator);
  560. }
  561. URLClassLoader sandboxLoader;
  562. ClassLoader parentLoader = getClass().getClassLoader().getParent();
  563. /* Sandbox -> AspectJ -> Extension -> Bootstrap */
  564. if ( !useFullLTW && useLTW) {
  565. // URLClassLoader testLoader = (URLClassLoader) getClass().getClassLoader();
  566. /*
  567. * Create a new AspectJ class loader using the existing test CLASSPATH and any missing Java 5 projects
  568. */
  569. URL[] testUrls = new URL[0];//testLoader.getURLs();
  570. // What are the URLs on java 8?
  571. URL[] java5Urls = getURLs(DEFAULT_CLASSPATH_ENTRIES);
  572. URL[] urls = new URL[testUrls.length + java5Urls.length];
  573. System.arraycopy(testUrls, 0, urls, 0, testUrls.length);
  574. System.arraycopy(java5Urls, 0, urls, testUrls.length, java5Urls.length);
  575. // ClassLoader aspectjLoader = new URLClassLoader(getURLs(DEFAULT_CLASSPATH_ENTRIES),parent);
  576. ClassLoader aspectjLoader = new URLClassLoader(urls, parentLoader);
  577. URL[] sandboxUrls = getURLs(cp.toString());
  578. sandboxLoader = createWeavingClassLoader(sandboxUrls, aspectjLoader);
  579. // sandboxLoader = createWeavingClassLoader(sandboxUrls,testLoader);
  580. } else if(useFullLTW && useLTW) {
  581. if(vmargs == null){
  582. vmargs ="";
  583. }
  584. File directory = new File (".");
  585. String absPath = directory.getAbsolutePath();
  586. String javaagent= absPath+File.separator+".."+File.separator+"aj-build"+File.separator+"dist"+File.separator+"tools"+File.separator+"lib"+File.separator+"aspectjweaver.jar";
  587. try {
  588. String command ="java " +vmargs+ " -classpath " + cp +" -javaagent:"+javaagent + " " + className ;
  589. // Command is executed using ProcessBuilder to allow setting CWD for ajc sandbox compliance
  590. ProcessBuilder pb = new ProcessBuilder(tokenizeCommand(command));
  591. pb.directory( new File(ajc.getSandboxDirectory().getAbsolutePath()));
  592. exec = pb.start();
  593. BufferedReader stdInput = new BufferedReader(new InputStreamReader(exec.getInputStream()));
  594. BufferedReader stdError = new BufferedReader(new InputStreamReader(exec.getErrorStream()));
  595. exec.waitFor();
  596. lastRunResult = createResultFromBufferReaders(command,stdInput, stdError);
  597. } catch (Exception e) {
  598. System.out.println("Error executing full LTW test: " + e);
  599. e.printStackTrace();
  600. }
  601. return lastRunResult;
  602. } else if (moduleName != null) {
  603. // CODE FOR RUNNING MODULES
  604. if(vmargs == null){
  605. vmargs ="";
  606. }
  607. try {
  608. if (mp.indexOf("$runtimemodule") != -1) {
  609. mp = mp.replace(mp.indexOf("$runtimemodule"),"$runtimemodule".length(),TestUtil.aspectjrtPath(true).toString());
  610. }
  611. if (mp.indexOf("$runtime") != -1) {
  612. mp = mp.replace(mp.indexOf("$runtime"),"$runtime".length(),TestUtil.aspectjrtPath().toString());
  613. }
  614. if (cp.indexOf("aspectjrt")==-1) {
  615. cp.append(TestUtil.aspectjrtPath().getPath()).append(File.pathSeparator);
  616. }
  617. String command = LangUtil.getJavaExecutable().getAbsolutePath() + " " +vmargs+ (cp.length()==0?"":" -classpath " + cp) + " -p "+mp+" --module "+moduleName ;
  618. if (Ajc.verbose) {
  619. System.out.println("Command is "+command);
  620. }
  621. // Command is executed using ProcessBuilder to allow setting CWD for ajc sandbox compliance
  622. ProcessBuilder pb = new ProcessBuilder(tokenizeCommand(command));
  623. pb.directory( new File(ajc.getSandboxDirectory().getAbsolutePath()));
  624. exec = pb.start();
  625. BufferedReader stdInput = new BufferedReader(new InputStreamReader(exec.getInputStream()));
  626. BufferedReader stdError = new BufferedReader(new InputStreamReader(exec.getErrorStream()));
  627. exec.waitFor();
  628. lastRunResult = createResultFromBufferReaders(command,stdInput, stdError);
  629. } catch (Exception e) {
  630. System.out.println("Error executing module test: " + e);
  631. e.printStackTrace();
  632. }
  633. return lastRunResult;
  634. } else if (vmargs!=null && (vmargs.contains("--enable-preview") || vmargs.contains("--add-modules") || vmargs.contains("--limit-modules") || vmargs.contains("--add-reads"))) {
  635. // If --add-modules supplied, need to fork the test
  636. try {
  637. // if (mp.indexOf("$runtime") != -1) {
  638. // mp = mp.replace(mp.indexOf("$runtime"),"$runtime".length(),TestUtil.aspectjrtPath().toString());
  639. // }
  640. if (cp.indexOf("aspectjrt")==-1) {
  641. cp.append(File.pathSeparator).append(TestUtil.aspectjrtPath().getPath());
  642. }
  643. String command = LangUtil.getJavaExecutable().getAbsolutePath() + " " +vmargs+ (cp.length()==0?"":" -classpath " + cp) + " " + className ;
  644. if (Ajc.verbose) {
  645. System.out.println("\nCommand is "+command);
  646. }
  647. // Command is executed using ProcessBuilder to allow setting CWD for ajc sandbox compliance
  648. ProcessBuilder pb = new ProcessBuilder(tokenizeCommand(command));
  649. pb.directory( new File(ajc.getSandboxDirectory().getAbsolutePath()));
  650. exec = pb.start();
  651. BufferedReader stdInput = new BufferedReader(new InputStreamReader(exec.getInputStream()));
  652. BufferedReader stdError = new BufferedReader(new InputStreamReader(exec.getErrorStream()));
  653. exec.waitFor();
  654. lastRunResult = createResultFromBufferReaders(command,stdInput, stdError);
  655. } catch (Exception e) {
  656. System.out.println("Error executing module test: " + e);
  657. e.printStackTrace();
  658. }
  659. return lastRunResult;
  660. } else {
  661. cp.append(DEFAULT_CLASSPATH_ENTRIES);
  662. URL[] urls = getURLs(cp.toString());
  663. sandboxLoader = new URLClassLoader(urls, parentLoader);
  664. }
  665. ByteArrayOutputStream baosOut = new ByteArrayOutputStream();
  666. ByteArrayOutputStream baosErr = new ByteArrayOutputStream();
  667. StringBuffer command = new StringBuffer();
  668. command.append("java -classpath ");
  669. command.append(cp.toString());
  670. command.append(" ");
  671. command.append(className);
  672. for (String arg : args) {
  673. command.append(" ");
  674. command.append(arg);
  675. }
  676. // try {
  677. // // Enable the security manager
  678. // Policy.setPolicy(new MyPolicy());
  679. // SecurityManager sm = new SecurityManager();
  680. // System.setSecurityManager(sm);
  681. // } catch (SecurityException se) {
  682. // // SecurityManager already set
  683. // }
  684. ClassLoader contexClassLoader = Thread.currentThread().getContextClassLoader();
  685. try {
  686. try {
  687. Class<?> testerClass = sandboxLoader.loadClass("org.aspectj.testing.Tester");
  688. Method setBaseDir = testerClass.getDeclaredMethod("setBASEDIR", new Class[] { File.class });
  689. setBaseDir.invoke(null, new Object[] { ajc.getSandboxDirectory() });
  690. } catch (InvocationTargetException itEx) {
  691. fail("Unable to prepare org.aspectj.testing.Tester for test run: " + itEx.getTargetException());
  692. } catch (Exception ex) {
  693. fail("Unable to prepare org.aspectj.testing.Tester for test run: " + ex);
  694. }
  695. startCapture(baosErr, baosOut);
  696. /* Frameworks like XML use context class loader for dynamic loading */
  697. Thread.currentThread().setContextClassLoader(sandboxLoader);
  698. Class<?> toRun = sandboxLoader.loadClass(className);
  699. Method mainMethod = toRun.getMethod("main", new Class[] { String[].class });
  700. mainMethod.invoke(null, new Object[] { args });
  701. } catch (ClassNotFoundException cnf) {
  702. fail("Can't find class: " + className);
  703. } catch (NoSuchMethodException nsm) {
  704. fail(className + " does not have a main method");
  705. } catch (IllegalAccessException illEx) {
  706. fail("main method in class " + className + " is not public");
  707. } catch (InvocationTargetException invTgt) {
  708. // the main method threw an exception...
  709. fail("Exception thrown by " + className + ".main(String[]) :" + invTgt.getTargetException());
  710. } finally {
  711. // try {
  712. // // Enable the security manager
  713. // SecurityManager sm = new SecurityManager();
  714. // System.setSecurityManager(null);
  715. // } catch (SecurityException se) {
  716. // se.printStackTrace();
  717. // // SecurityManager already set
  718. // }
  719. Thread.currentThread().setContextClassLoader(contexClassLoader);
  720. stopCapture(baosErr, baosOut);
  721. lastRunResult = new RunResult(command.toString(), new String(baosOut.toByteArray()), new String(baosErr.toByteArray()));
  722. }
  723. return lastRunResult;
  724. }
  725. private List<String >tokenizeCommand(String command) {
  726. StringTokenizer st = new StringTokenizer(command," ", false);
  727. List<String> arguments = new ArrayList<>();
  728. while(st.hasMoreElements()){
  729. String nextToken =st.nextToken();
  730. arguments.add(nextToken);
  731. }
  732. return arguments;
  733. }
  734. private RunResult createResultFromBufferReaders(String command,
  735. BufferedReader stdInput, BufferedReader stdError) throws IOException {
  736. String line = "";
  737. ByteArrayOutputStream baosOut = new ByteArrayOutputStream();
  738. ByteArrayOutputStream baosErr = new ByteArrayOutputStream();
  739. PrintWriter stdOutWriter = new PrintWriter(baosOut);
  740. PrintWriter stdErrWriter = new PrintWriter(baosErr);
  741. if (Ajc.verbose) {
  742. System.out.println();
  743. }
  744. while ((line = stdInput.readLine()) != null) {
  745. stdOutWriter.println(line);
  746. if (Ajc.verbose) {
  747. System.out.println(line);
  748. }
  749. }
  750. stdOutWriter.flush();
  751. while ((line = stdError.readLine()) != null) {
  752. stdErrWriter.println(line);
  753. if (Ajc.verbose) {
  754. System.err.println(line);
  755. }
  756. }
  757. stdErrWriter.flush();
  758. baosOut.close();
  759. baosErr.close();
  760. return new RunResult(command.toString(), new String(baosOut.toByteArray()), new String(baosErr.toByteArray()));
  761. }
  762. // static class MyPolicy extends Policy {
  763. //
  764. // @Override
  765. // public boolean implies(ProtectionDomain domain, Permission permission) {
  766. // // if (permission != SecurityConstants.GET_POLICY_PERMISSION) {
  767. // // // System.out.println(domain + " " + permission.getName());
  768. // // System.out.println(permission.getName());
  769. // // }
  770. // // if (true) {
  771. // // return true;
  772. // // }
  773. // if (permission instanceof PropertyPermission) {
  774. // return true;
  775. // }
  776. // if (permission instanceof RuntimePermission) {
  777. // return true;
  778. // }
  779. // if (permission instanceof FilePermission) {
  780. // // System.out.println(permission);
  781. // return true;
  782. // }
  783. // if (permission instanceof ReflectPermission) {
  784. // return true;
  785. // }
  786. // // System.out.println(permission);
  787. // return super.implies(domain, permission);
  788. // // return true;
  789. // }
  790. // }
  791. /*
  792. * Must create weaving class loader reflectively using new parent so we don't have a reference to a World loaded from CLASSPATH
  793. * which won't be able to resolve Java 5 specific extensions and may cause ClassCastExceptions
  794. */
  795. private URLClassLoader createWeavingClassLoader(URL[] urls, ClassLoader parent) {
  796. URLClassLoader loader = null;
  797. try {
  798. Class loaderClazz = Class.forName("org.aspectj.weaver.loadtime.WeavingURLClassLoader", false, parent);
  799. Class[] parameterTypes = new Class[] { urls.getClass(), ClassLoader.class };
  800. Object[] parameters = new Object[] { urls, parent };
  801. Constructor constructor = loaderClazz.getConstructor(parameterTypes);
  802. loader = (URLClassLoader) constructor.newInstance(parameters);
  803. } catch (InvocationTargetException ex) {
  804. ex.printStackTrace();
  805. fail("Cannot create weaving class loader: " + ex.getTargetException());
  806. } catch (Exception ex) {
  807. ex.printStackTrace();
  808. fail("Cannot create weaving class loader: " + ex.toString());
  809. }
  810. return loader;
  811. }
  812. private URL[] getURLs(String classpath) {
  813. StringTokenizer strTok = new StringTokenizer(classpath, File.pathSeparator);
  814. URL[] urls = new URL[strTok.countTokens()];
  815. try {
  816. for (int i = 0; i < urls.length; i++) {
  817. urls[i] = new File(strTok.nextToken()).getCanonicalFile().toURL();
  818. }
  819. } catch (Exception malEx) {
  820. fail("Bad classpath specification: " + classpath);
  821. }
  822. return urls;
  823. }
  824. private String substituteSandbox(String path) {
  825. // the longhand form of the non 1.3 API: path.replace("$sandbox", ajc.getSandboxDirectory().getAbsolutePath());
  826. while (path.contains("$sandbox")) {
  827. int pos = path.indexOf("$sandbox");
  828. String firstbit = path.substring(0, pos);
  829. String endbit = path.substring(pos + 8);
  830. path = firstbit + ajc.getSandboxDirectory().getAbsolutePath() + endbit;
  831. }
  832. return path;
  833. }
  834. /**
  835. * Any central pre-processing of args. This supplies aspectjrt.jar if available and classpath not set.
  836. *
  837. * @param args the String[] args to fix up
  838. * @return the String[] args to use
  839. */
  840. protected String[] fixupArgs(String[] args) {
  841. if (null == args) {
  842. return null;
  843. }
  844. int cpIndex = -1;
  845. boolean hasruntime = false;
  846. for (int i = 0; i < args.length - 1; i++) {
  847. args[i] = adaptToPlatform(args[i]);
  848. if ("-classpath".equals(args[i])) {
  849. cpIndex = i;
  850. args[i + 1] = substituteSandbox(args[i + 1]);
  851. String next = args[i + 1];
  852. hasruntime = ((null != next) && (next.contains("aspectjrt.jar")));
  853. } else if ("-p".equals(args[i]) || "--module-path".equals(args[i])) {
  854. args[i + 1] = substituteSandbox(args[i + 1]);
  855. }
  856. }
  857. if (-1 == cpIndex) {
  858. String[] newargs = new String[args.length + 2];
  859. newargs[0] = "-classpath";
  860. newargs[1] = TestUtil.aspectjrtPath(false).getPath();
  861. System.arraycopy(args, 0, newargs, 2, args.length);
  862. args = newargs;
  863. cpIndex = 1;
  864. } else {
  865. if (!hasruntime) {
  866. cpIndex++;
  867. String[] newargs = new String[args.length];
  868. System.arraycopy(args, 0, newargs, 0, args.length);
  869. newargs[cpIndex] = args[cpIndex] + File.pathSeparator + TestUtil.aspectjrtPath().getPath();
  870. args = newargs;
  871. }
  872. }
  873. boolean needsJRTFS = LangUtil.is9VMOrGreater();
  874. if (needsJRTFS) {
  875. if (!args[cpIndex].contains(LangUtil.JRT_FS)) {
  876. String jrtfsPath = LangUtil.getJrtFsFilePath();
  877. args[cpIndex] = jrtfsPath + File.pathSeparator + args[cpIndex];
  878. }
  879. }
  880. return args;
  881. }
  882. private String adaptToPlatform(String s) {
  883. String ret = s.replace(';', File.pathSeparatorChar);
  884. // ret = ret.replace(':',File.pathSeparatorChar);
  885. return ret;
  886. }
  887. private <T> List<T> copyAll(List<T> in) {
  888. if (in == Collections.EMPTY_LIST)
  889. return in;
  890. List<T> out = new ArrayList<>();
  891. for (T t : in) {
  892. out.add(t);
  893. }
  894. return out;
  895. }
  896. /**
  897. * Compare the set of expected messages against the set of actual messages, leaving in missingElements the set of messages that
  898. * were expected but did not occur, and in extraElements the set of messages that occured but were not excpected
  899. *
  900. * @param expected the expected messages
  901. * @param actual the actual messages
  902. * @param missingElements the missing messages, when passed in must contain all of the expected messages
  903. * @param extraElements the additional messages, when passed in must contain all of the actual messages
  904. */
  905. private void compare(List<AjcTestCase.Message> expected, List<IMessage> actual, List<AjcTestCase.Message> missingElements, List<IMessage> extraElements) {
  906. for (Message expectedMessage: expected) {
  907. for (IMessage actualMessage: actual) {
  908. if (expectedMessage.matches(actualMessage)) {
  909. if (expectedMessage.careAboutOtherMessages) {
  910. missingElements.remove(expectedMessage);
  911. extraElements.remove(actualMessage);
  912. }
  913. else {
  914. missingElements.clear();
  915. extraElements.clear();
  916. }
  917. }
  918. }
  919. }
  920. }
  921. private void addMissing(StringBuffer buff, String type, List<AjcTestCase.Message> messages) {
  922. if (!messages.isEmpty()) {
  923. buff.append("Missing expected ");
  924. buff.append(type);
  925. buff.append(" messages:\n");
  926. for (Message message : messages) {
  927. buff.append("\t");
  928. buff.append(message.toString());
  929. buff.append("\n");
  930. }
  931. }
  932. }
  933. private void addExtra(StringBuffer buff, String type, List messages) {
  934. if (!messages.isEmpty()) {
  935. buff.append("Unexpected ");
  936. buff.append(type);
  937. buff.append(" messages:\n");
  938. for (Object message : messages) {
  939. buff.append("\t");
  940. buff.append(message.toString());
  941. buff.append("\n");
  942. }
  943. }
  944. }
  945. // add any jars in the directory to the classpath
  946. private void getAnyJars(File dir, StringBuffer buff) {
  947. File[] files = dir.listFiles();
  948. for (File file : files) {
  949. if (file.getName().endsWith(".jar")) {
  950. buff.append(File.pathSeparator);
  951. buff.append(file.getAbsolutePath());
  952. } else if (file.isDirectory()) {
  953. getAnyJars(file, buff);
  954. }
  955. }
  956. }
  957. private static void startCapture(OutputStream errOS, OutputStream outOS) {
  958. delegatingErr.add(errOS);
  959. delegatingOut.add(outOS);
  960. delegatingErr.setVerbose(DEFAULT_ERR_VERBOSE);
  961. delegatingOut.setVerbose(DEFAULT_OUT_VERBOSE);
  962. }
  963. private static void stopCapture(OutputStream errOS, OutputStream outOS) {
  964. delegatingErr.setVerbose(true);
  965. delegatingOut.setVerbose(true);
  966. delegatingErr.remove(errOS);
  967. delegatingOut.remove(outOS);
  968. }
  969. private static boolean getBoolean(String name, boolean def) {
  970. String defaultValue = String.valueOf(def);
  971. String value = System.getProperty(name, defaultValue);
  972. return Boolean.valueOf(value);
  973. }
  974. /*
  975. * (non-Javadoc)
  976. *
  977. * @see junit.framework.TestCase#setUp()
  978. */
  979. @Override
  980. protected void setUp() throws Exception {
  981. super.setUp();
  982. ajc = new Ajc();
  983. }
  984. /*
  985. * (non-Javadoc)
  986. *
  987. * @see junit.framework.TestCase#tearDown()
  988. */
  989. @Override
  990. protected void tearDown() throws Exception {
  991. super.tearDown();
  992. // ajc = null;
  993. }
  994. static {
  995. // new RuntimeException("*** AjcTestCase.<clinit>()").printStackTrace();
  996. delegatingErr = new DelegatingOutputStream(err);
  997. System.setErr(new PrintStream(delegatingErr));
  998. delegatingOut = new DelegatingOutputStream(out);
  999. System.setOut(new PrintStream(delegatingOut));
  1000. }
  1001. }