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

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