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

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