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

11 years ago
11 years ago
11 years ago
11 years ago
15 years ago
11 years ago
12 years ago
12 years ago
12 years ago
12 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
5 years ago
5 years ago
11 years ago
11 years ago
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-7.0-beta.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 (int i = 0; i < chars.length; i++) {
  164. if ((chars[i] == '\\') || (chars[i] == '/')) {
  165. srcFileName.append(File.separator);
  166. } else {
  167. srcFileName.append(chars[i]);
  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().indexOf(text) == -1) {
  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 (int i = 0; i < seeAlsos.length; i++) {
  220. if (!hasAMatch(extraLocations, seeAlsos[i])) {
  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 (int i = 0; i < seeAlsos.length; i++) {
  262. buff.append("\t\t");
  263. buff.append(seeAlsos[i].getSourceFile().getPath());
  264. buff.append(":");
  265. buff.append(seeAlsos[i].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 (int i = 0; i < args.length; i++) {
  444. failureReport.append(" ");
  445. failureReport.append(args[i]);
  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 (int i = 0; i < messages.length; i++) {
  485. ret.add(messages[i]);
  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 (int i = 0; i < args.length; i++) {
  672. command.append(" ");
  673. command.append(args[i]);
  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.indexOf("$sandbox") != -1) {
  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) && (-1 != next.indexOf("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].indexOf(LangUtil.JRT_FS) == -1) {
  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 (Iterator<T> iter = in.iterator(); iter.hasNext();) {
  884. out.add(iter.next());
  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 (Iterator<AjcTestCase.Message> iter = messages.iterator(); iter.hasNext();) {
  919. buff.append("\t");
  920. buff.append(iter.next().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 (Iterator iter = messages.iterator(); iter.hasNext();) {
  931. buff.append("\t");
  932. buff.append(iter.next().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 (int i = 0; i < files.length; i++) {
  941. if (files[i].getName().endsWith(".jar")) {
  942. buff.append(File.pathSeparator);
  943. buff.append(files[i].getAbsolutePath());
  944. } else if (files[i].isDirectory()) {
  945. getAnyJars(files[i], 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. }