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.

IncrementalCase.java 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484
  1. /* *******************************************************************
  2. * Copyright (c) 1999-2001 Xerox Corporation,
  3. * 2002 Palo Alto Research Center, Incorporated (PARC).
  4. * All rights reserved.
  5. * This program and the accompanying materials are made available
  6. * under the terms of the Eclipse Public License v 2.0
  7. * which accompanies this distribution and is available at
  8. * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.txt
  9. *
  10. * Contributors:
  11. * PARC initial implementation
  12. * ******************************************************************/
  13. package org.aspectj.ajdt.internal.compiler.batch;
  14. import java.io.File;
  15. import java.io.FileFilter;
  16. import java.io.FileInputStream;
  17. import java.io.IOException;
  18. import java.util.ArrayList;
  19. import java.util.Arrays;
  20. import java.util.BitSet;
  21. import java.util.Collections;
  22. import java.util.List;
  23. import java.util.Properties;
  24. import org.aspectj.bridge.ICommand;
  25. import org.aspectj.bridge.IMessage;
  26. import org.aspectj.bridge.IMessageHandler;
  27. import org.aspectj.bridge.IMessageHolder;
  28. import org.aspectj.bridge.ISourceLocation;
  29. import org.aspectj.bridge.Message;
  30. import org.aspectj.bridge.MessageHandler;
  31. import org.aspectj.bridge.ReflectionFactory;
  32. import org.aspectj.util.FileUtil;
  33. import org.aspectj.util.LangUtil;
  34. /**
  35. * Mostly stateless incremental test case.
  36. * Subclass to use from junit.
  37. */
  38. public class IncrementalCase { // XXX NOT bound to junit - bridge tests?
  39. public static final String[] RA_String = new String[0]; // XXX
  40. boolean verbose = true;
  41. boolean ignoreWarnings = false;
  42. public static void main(String[] args) throws IOException {
  43. IncrementalCase me = new IncrementalCase();
  44. MessageHandler h = new MessageHandler();
  45. // boolean result;
  46. StringBuilder sb = new StringBuilder();
  47. for (String arg : args) {
  48. sb.append("\n###### results for " + arg);
  49. sb.append("\n" + me.run(new File(arg), h) + ": " + h);
  50. }
  51. System.err.flush();
  52. System.out.flush();
  53. System.err.println(sb.toString());
  54. }
  55. /**
  56. * Run an incremental compile case.
  57. * For each i=1..9, copy files srcDir/*{i=1..9}0.java
  58. * to the sandbox and compile.
  59. * This only expects the changed files to be recompiled, but
  60. * it also calls verifyCompile(..);
  61. * @param handler all non-functional feedback here.
  62. * Exceptions are logged as ABORT messages
  63. */
  64. public boolean run(File srcBase, IMessageHandler handler)
  65. throws IOException {
  66. final String cname = ReflectionFactory.ECLIPSE;
  67. File targetBase =
  68. makeDir(getSandboxDir(), "IncrementalCaseSandbox", handler);
  69. if (null == targetBase) {
  70. return false;
  71. }
  72. File targetSrc = makeDir(targetBase, "src", handler);
  73. if (null == targetSrc) {
  74. return false;
  75. }
  76. File targetClasses = makeDir(targetBase, "classes", handler);
  77. if (null == targetClasses) {
  78. return false;
  79. }
  80. final List<File> files = new ArrayList<>();
  81. final FileFilter collector = new FileFilter() {
  82. @Override
  83. public boolean accept(File file) {
  84. return files.add(file);
  85. }
  86. };
  87. final ICommand compiler =
  88. ReflectionFactory.makeCommand(cname, handler);
  89. List recompiled = null;
  90. boolean result = true;
  91. final String toSuffix = ".java";
  92. // final String canonicalFrom = srcBase.getCanonicalPath();
  93. final Definition[] defs = getDefinitions(srcBase);
  94. if ((null == defs) || (defs.length < 9)) {
  95. throw new Error("did not get definitions");
  96. }
  97. MessageHandler compilerMessages = new MessageHandler();
  98. StringBuffer commandLine = new StringBuffer();
  99. for (int i = 1; result && (i < 10); i++) {
  100. String fromSuffix = "." + i + "0.java";
  101. // copy files, collecting as we go...
  102. files.clear();
  103. FileUtil.copyDir(
  104. srcBase,
  105. targetSrc,
  106. fromSuffix,
  107. toSuffix,
  108. collector);
  109. if (0 == files.size()) { // XXX detect incomplete?
  110. break;
  111. }
  112. List safeFiles = Collections.unmodifiableList(files);
  113. log("Compiling ", safeFiles, handler);
  114. if (1 == i) {
  115. ArrayList<String> argList = new ArrayList<>(getBaseArgs(targetSrc, targetClasses));
  116. File[] fra = (File[]) safeFiles.toArray(new File[0]);
  117. // sigh
  118. argList.addAll(
  119. Arrays.asList(FileUtil.getAbsolutePaths(fra)));
  120. String[] args = argList.toArray(new String[0]);
  121. commandLine.append(""+argList);
  122. result = compiler.runCommand(args, compilerMessages);
  123. } else {
  124. if (null == recompiled) {
  125. recompiled = new ArrayList();
  126. } else {
  127. recompiled.clear();
  128. }
  129. compilerMessages.init();
  130. commandLine.append("["+i+": " + recompiled + "] ");
  131. result =
  132. compiler.repeatCommand(compilerMessages);
  133. }
  134. result =
  135. verifyCompile(
  136. i,
  137. result,
  138. srcBase,
  139. targetSrc,
  140. targetClasses,
  141. defs[i - 1],
  142. compilerMessages,
  143. commandLine,
  144. handler);
  145. }
  146. return result;
  147. }
  148. // -------------------------------------- test case verification
  149. /**
  150. * Verify that this incremental compile step worked.
  151. * @param recompiled the List of Files the compiler recompiled - null the first pass
  152. * @param files the (unmodifiable) List of File passed as sources to the compiler
  153. * @param recompiled the List sink for the Files actually recompiled
  154. */
  155. // XXX argh no parent/child relationship in this world...
  156. protected boolean verifyCompile(
  157. int iteration,
  158. boolean result,
  159. File srcDir,
  160. File sandboxSrcDir,
  161. File sandboxClassesDir,
  162. Definition def,
  163. IMessageHolder compilerMessages,
  164. StringBuffer commandLine,
  165. IMessageHandler handler) {
  166. log("verifyCompile - iteration ", iteration, handler);
  167. log("verifyCompile - def ", def, handler);
  168. log("verifyCompile - command ", commandLine.toString(), handler);
  169. log("verifyCompile - messages ", compilerMessages, handler);
  170. StringBuilder failures = new StringBuilder();
  171. if (def.expectFail == result) {
  172. failures.append("iteration " + iteration +
  173. " expected to " + (def.expectFail ? "fail\n" : "pass"));
  174. }
  175. if (0 < failures.length()) {
  176. fail(handler,
  177. "\nFailures in iteration " + iteration
  178. + "\n Command: " + commandLine
  179. + "\nMessages: " + compilerMessages
  180. + "\n Def: " + def
  181. + "\nFailures: " + failures);
  182. return false;
  183. }
  184. IMessage[] messages = compilerMessages.getMessages(IMessage.ERROR, IMessageHolder.EQUAL);
  185. String[] expected =
  186. (null != def.errors ? def.errors : def.eclipseErrors);
  187. if (haveAll("errors", expected, messages, handler)) {
  188. if (!ignoreWarnings) {
  189. messages = compilerMessages.getMessages(IMessage.WARNING, IMessageHolder.EQUAL);
  190. expected =
  191. (null != def.warnings
  192. ? def.warnings
  193. : def.eclipseWarnings);
  194. if (!haveAll("warnings", expected, messages, handler)) {
  195. return false;
  196. }
  197. }
  198. }
  199. return true;
  200. }
  201. // -------------------------------------- test case setup
  202. /**
  203. * Get the sandbox (parent) directory.
  204. * This implementation uses the temporary directory
  205. */
  206. protected File getSandboxDir() throws IOException { // XXX util
  207. File tempFile = File.createTempFile("IncrementalCase", ".txt");
  208. File tempDir = tempFile.getParentFile();
  209. tempFile.delete();
  210. return tempDir;
  211. }
  212. //XXX hack
  213. public File outputDir;
  214. /** @param srcDir ignored for now */
  215. protected List<String> getBaseArgs(File srcDir, File classesDir) {
  216. outputDir = classesDir;
  217. String[] input =
  218. new String[] {
  219. "-verbose",
  220. // "-classpath",
  221. // System.getProperty("sun.boot.class.path"),
  222. "-d",
  223. classesDir.getAbsolutePath()};
  224. return Collections.unmodifiableList(
  225. new ArrayList<>(Arrays.asList(input)));
  226. }
  227. protected File makeDir(
  228. File parent,
  229. String name,
  230. IMessageHandler handler) { // XXX util
  231. File result = new File(parent, name);
  232. if (!result.exists()) {
  233. result.mkdirs();
  234. if (!result.exists()) {
  235. fail(handler, "unable to create " + result);
  236. return null;
  237. }
  238. }
  239. return result;
  240. }
  241. // -------------------------------------- test case verification
  242. List<String> normalizeFilenames(String[] ra) { // XXX util
  243. List<String> result = new ArrayList<>();
  244. if (null != ra) {
  245. for (String s : ra) {
  246. result.add(normalizeFilename(s));
  247. }
  248. if (1 < ra.length) {
  249. Collections.sort(result);
  250. }
  251. }
  252. return result;
  253. }
  254. /** @param list the List of File */
  255. List<String> normalizeFilenames(List<File> list) { // XXX util
  256. List<String> result = new ArrayList<>();
  257. for (File file: list) {
  258. // for (Iterator<?> iter = list.iterator(); iter.hasNext();) {
  259. result.add(normalizeFilename(file.getPath()));
  260. }
  261. Collections.sort(result);
  262. return result;
  263. }
  264. String normalizeFilename(String s) { // XXX error-prone
  265. final String suffix = ".java";
  266. int loc = s.lastIndexOf(suffix);
  267. if (-1 == loc) {
  268. return s; // punt
  269. }
  270. s = s.substring(0, loc + suffix.length()).replace('\\', '/');
  271. loc = s.lastIndexOf("/");
  272. return (-1 == loc ? s : s.substring(loc+1));
  273. }
  274. /** XXX duplicate message checking */
  275. boolean haveAll(
  276. String label,
  277. String[] expected,
  278. IMessage[] messages,
  279. IMessageHandler handler) {
  280. if (null == expected) {
  281. expected = new String[0];
  282. }
  283. boolean result = true;
  284. final int[] exp = new int[expected.length];
  285. StringBuilder sb = new StringBuilder();
  286. sb.append("[");
  287. for (int i = 0; i < exp.length; i++) {
  288. String s = expected[i];
  289. int loc = s.lastIndexOf(":");
  290. if (-1 != loc)
  291. s = s.substring(loc + 1);
  292. try {
  293. exp[i] = Integer.valueOf(s);
  294. sb.append(exp[i] + ((i < (exp.length - 1)) ? ", " : ""));
  295. } catch (NumberFormatException e) {
  296. info(handler, "bad " + label + ":" + expected[i]);
  297. // XXX worse than info...
  298. sb.append("bad" + ((i < (exp.length - 1)) ? ", " : "]"));
  299. }
  300. }
  301. sb.append("]");
  302. final String context =
  303. label
  304. + "\n in context haveAll expected="
  305. + Arrays.asList(expected)
  306. + " exp="
  307. + sb
  308. + " actual="
  309. + Arrays.asList(messages);
  310. info(handler, context);
  311. BitSet foundSet = new BitSet(10);
  312. for (final int expLine : exp) {
  313. boolean found = false;
  314. for (int j = 0; !found && (j < messages.length); j++) {
  315. ISourceLocation sl = messages[j].getSourceLocation();
  316. found = ((null != sl) && (expLine == sl.getLine()));
  317. if (found) {
  318. info(handler, "found " + label + " for: " + expLine);
  319. if (foundSet.get(j)) {
  320. info(
  321. handler,
  322. "duplicate " + label + " expected: " + expLine);
  323. }
  324. foundSet.set(j);
  325. }
  326. }
  327. if (!found) {
  328. String s =
  329. "expected "
  330. + label
  331. + " not found: "
  332. + expLine
  333. + context;
  334. fail(handler, s); // bad short-circuit
  335. if (!result) {
  336. result = false;
  337. }
  338. }
  339. }
  340. sb.setLength(0);
  341. for (int i = 0; i < messages.length; i++) {
  342. if (!foundSet.get(i)) {
  343. sb.append(
  344. "\n unexpected " + label + " found: " + messages[i]);
  345. }
  346. }
  347. if (0 == sb.length()) {
  348. return true;
  349. } else {
  350. fail(handler, sb.toString() + context);
  351. return false;
  352. }
  353. }
  354. // -------------------------------------- messages
  355. protected void log(String label, Object o, IMessageHandler handler) {
  356. if (verbose) {
  357. if (null != handler) {
  358. message(IMessage.INFO, label + ": " + o, handler);
  359. } else {
  360. System.err.println("\nlog: " + label + ": " + o);
  361. }
  362. }
  363. }
  364. protected void info(IMessageHandler handler, String mssg) {
  365. message(IMessage.INFO, mssg, handler);
  366. }
  367. protected void fail(IMessageHandler handler, String mssg) {
  368. message(IMessage.FAIL, mssg, handler);
  369. }
  370. /** this is the only client of the message handler - remplement to do other notification*/
  371. protected void message(
  372. IMessage.Kind kind,
  373. String mssg,
  374. IMessageHandler handler) {
  375. if (null != handler) {
  376. handler.handleMessage(
  377. new Message("\n### " + mssg, kind, null, null));
  378. }
  379. }
  380. /** @return Definition[9] read from srceBase/Definition.PATH */
  381. Definition[] getDefinitions(File srcBase) {
  382. File file = new File(srcBase, Definition.PATH);
  383. Properties props = new Properties();
  384. FileInputStream in = null;
  385. try {
  386. in = new FileInputStream(file);
  387. props.load(in);
  388. } catch (IOException e) {
  389. e.printStackTrace(System.err);
  390. } finally {
  391. if (null != in)
  392. try {
  393. in.close();
  394. } catch (IOException e) {
  395. }
  396. }
  397. Definition[] result = new Definition[9];
  398. for (int i = 0; i < 9; i++) { // XXX matches run
  399. result[i] = new Definition((1+i) + "0", props);
  400. }
  401. return result;
  402. }
  403. static class Definition {
  404. static final String PATH = "expected.txt";
  405. boolean expectFail;
  406. String prefix;
  407. String[] files;
  408. String[] recompiled;
  409. String[] errors;
  410. String[] warnings;
  411. String[] eclipseErrors;
  412. String[] eclipseWarnings;
  413. Definition(String prefix, Properties props) {
  414. // Enumeration keys = props.keys();
  415. this.prefix = prefix;
  416. files = get(props, prefix + ".files");
  417. recompiled = get(props, prefix + ".recompiled");
  418. errors = get(props, prefix + ".errors");
  419. warnings = get(props, prefix + ".warnings");
  420. eclipseErrors = get(props, prefix + ".eclipse.errors");
  421. eclipseWarnings = get(props, prefix + ".eclipse.warnings");
  422. expectFail =
  423. (((null != errors) && (0 < errors.length))
  424. || ((null != eclipseErrors)
  425. && (0 < eclipseErrors.length)));
  426. }
  427. String[] get(Properties props, String key) {
  428. String s = props.getProperty(key);
  429. if (null != s) {
  430. return LangUtil.split(s);
  431. }
  432. return null;
  433. }
  434. @Override
  435. public String toString() {
  436. return "Definition "
  437. + " expectFail="
  438. + expectFail
  439. + " prefix="
  440. + prefix
  441. + " files="
  442. + safe(files)
  443. + " recompiled="
  444. + safe(recompiled)
  445. + " errors="
  446. + safe(errors)
  447. + " warnings="
  448. + safe(warnings)
  449. + " eclipseErrors="
  450. + safe(eclipseErrors)
  451. + " eclipseWarnings="
  452. + safe(eclipseWarnings);
  453. }
  454. String safe(String[] in) {
  455. return (null == in ? "" : "" + Arrays.asList(in));
  456. }
  457. }
  458. }