您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

AjcTestCase.java 38KB

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