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.

AjcMessageHandler.java 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  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 v1.0
  7. * which accompanies this distribution and is available at
  8. * http://www.eclipse.org/legal/epl-v10.html
  9. *
  10. * Contributors:
  11. * Xerox/PARC initial implementation
  12. * ******************************************************************/
  13. package org.aspectj.testing.harness.bridge;
  14. import java.util.ArrayList;
  15. import java.util.Arrays;
  16. import java.util.Collections;
  17. import java.util.Comparator;
  18. import java.util.Iterator;
  19. import java.util.List;
  20. import org.aspectj.bridge.IMessage;
  21. import org.aspectj.bridge.IMessageHandler;
  22. import org.aspectj.bridge.IMessageHolder;
  23. import org.aspectj.bridge.MessageHandler;
  24. import org.aspectj.bridge.MessageUtil;
  25. //import org.aspectj.bridge.IMessage.Kind;
  26. import org.aspectj.testing.util.BridgeUtil;
  27. import org.aspectj.testing.util.Diffs;
  28. import org.aspectj.util.LangUtil;
  29. /**
  30. * Handle messages during test and calculate differences
  31. * between expected and actual messages.
  32. */
  33. public class AjcMessageHandler extends MessageHandler {
  34. /** Comparator for enclosed IMessage diffs */
  35. public static final Comparator COMP_IMessage =
  36. BridgeUtil.Comparators.MEDIUM_IMessage;
  37. /** Comparator for enclosed File diffs */
  38. public static final Comparator COMP_File = BridgeUtil.Comparators.WEAK_File;
  39. /** unmodifiable list of IMessage messages of any type */
  40. private final List expectedMessagesAsList;
  41. /** IMessageHolder variant of expectedMessagesAsList */
  42. private final IMessageHolder expectedMessages;
  43. /** number of messages FAIL or worse */
  44. private final int numExpectedFailed;
  45. /** true if there were no error or worse messages expected */
  46. private final boolean expectingCommandTrue;
  47. /** unmodifiable list of File expected to be recompiled */
  48. private final List expectedRecompiled;
  49. // Unused now, but reinstate when supported
  50. /** if true, ignore warnings when calculating diffs and passed() */
  51. private final boolean ignoreWarnings;
  52. /** list of File actually recompiled */
  53. private List actualRecompiled;
  54. /** cache expected/actual diffs, nullify if any new message */
  55. private transient CompilerDiffs diffs;
  56. AjcMessageHandler(IMessageHolder expectedMessages) {
  57. this(expectedMessages, false);
  58. }
  59. /**
  60. * @param messages the (constant) IMessageHolder with expected messages
  61. */
  62. AjcMessageHandler(
  63. IMessageHolder expectedMessages,
  64. boolean ignoreWarnings) {
  65. LangUtil.throwIaxIfNull(messages, "messages");
  66. this.expectedMessages = expectedMessages;
  67. expectedMessagesAsList = expectedMessages.getUnmodifiableListView();
  68. expectedRecompiled = Collections.EMPTY_LIST;
  69. this.ignoreWarnings = ignoreWarnings;
  70. int fails = 0;
  71. int errors = 0;
  72. for (Iterator iter = expectedMessagesAsList.iterator();
  73. iter.hasNext();
  74. ) {
  75. IMessage m = (IMessage) iter.next();
  76. IMessage.Kind kind = m.getKind();
  77. if (IMessage.FAIL.isSameOrLessThan(kind)) {
  78. fails++;
  79. } else if (m.isError()) {
  80. errors++;
  81. }
  82. }
  83. expectingCommandTrue = (0 == (errors + fails));
  84. numExpectedFailed = fails;
  85. }
  86. /** clear out any actual values to be re-run */
  87. public void init() {
  88. super.init();
  89. actualRecompiled = null;
  90. diffs = null;
  91. }
  92. /**
  93. * Return true if we have this kind of
  94. * message for the same line and store all messages.
  95. * @see bridge.tools.impl.ErrorHandlerAdapter#doShowMessage(IMessage)
  96. * @return true if message handled (processing should abort)
  97. */
  98. public boolean handleMessage(IMessage message) {
  99. if (null == message) {
  100. throw new IllegalArgumentException("null message");
  101. }
  102. super.handleMessage(message);
  103. return expecting(message);
  104. }
  105. /**
  106. * Set the actual files recompiled.
  107. * @param List of File recompiled - may be null; adopted but not modified
  108. * @throws IllegalStateException if they have been set already.
  109. */
  110. public void setRecompiled(List list) {
  111. if (null != actualRecompiled) {
  112. throw new IllegalStateException("actual recompiled already set");
  113. }
  114. this.actualRecompiled = LangUtil.safeList(list);
  115. }
  116. /** Generate differences between expected and actual errors and warnings */
  117. public CompilerDiffs getCompilerDiffs() {
  118. if (null == diffs) {
  119. final List<IMessage> expected;
  120. final List<IMessage> actual;
  121. if (!ignoreWarnings) {
  122. expected = expectedMessages.getUnmodifiableListView();
  123. actual = this.getUnmodifiableListView();
  124. } else {
  125. expected =
  126. Arrays.asList(
  127. expectedMessages.getMessages(IMessage.ERROR, true));
  128. actual = Arrays.asList(this.getMessages(IMessage.ERROR, true));
  129. }
  130. // we ignore unexpected info messages,
  131. // but we do test for expected ones
  132. final Diffs messages;
  133. boolean usingNew = true; // XXX extract old API's after shake-out period
  134. if (usingNew) {
  135. final IMessage.Kind[] NOSKIPS = new IMessage.Kind[0];
  136. IMessage.Kind[] skipActual = new IMessage.Kind[] { IMessage.INFO };
  137. int expectedInfo
  138. = MessageUtil.numMessages(expected, IMessage.INFO, false);
  139. if (0 < expectedInfo) {
  140. // fyi, when expecting any info messages, have to expect all
  141. skipActual = NOSKIPS;
  142. }
  143. messages = Diffs.makeDiffs(
  144. "message",
  145. (IMessage[]) expected.toArray(new IMessage[0]),
  146. (IMessage[]) actual.toArray(new IMessage[0]),
  147. NOSKIPS,
  148. skipActual);
  149. } else {
  150. messages = Diffs.makeDiffs(
  151. "message",
  152. expected,
  153. actual,
  154. COMP_IMessage,
  155. Diffs.ACCEPT_ALL,
  156. CompilerDiffs.SKIP_UNEXPECTED_INFO);
  157. }
  158. Diffs recompiled =
  159. Diffs.makeDiffs(
  160. "recompiled",
  161. expectedRecompiled,
  162. actualRecompiled,
  163. COMP_File);
  164. diffs = new CompilerDiffs(messages, recompiled);
  165. }
  166. return diffs;
  167. }
  168. /**
  169. * Get the (current) result of this run,
  170. * ignoring differences in warnings on request.
  171. * Note it may return passed (true) when there are expected error messages.
  172. * @return false
  173. * if there are any fail or abort messages,
  174. * or if the expected errors, warnings, or recompiled do not match actual.
  175. */
  176. public boolean passed() {
  177. return !getCompilerDiffs().different;
  178. }
  179. /** @return true if we are expecting the command to fail - i.e., any expected errors */
  180. public boolean expectingCommandTrue() {
  181. return expectingCommandTrue;
  182. }
  183. /**
  184. * Report results to a handler,
  185. * adding all messages
  186. * and creating fail messages for each diff.
  187. */
  188. public void report(IMessageHandler handler) {
  189. if (null == handler) {
  190. MessageUtil.debug(this, "report got null handler");
  191. }
  192. // Report all messages except expected fail+ messages,
  193. // which will cause the reported-to handler client to gack.
  194. // XXX need some verbose way to report even expected fail+
  195. final boolean fastFail = false; // do all messages
  196. if (0 == numExpectedFailed) {
  197. MessageUtil.handleAll(handler, this, fastFail);
  198. } else {
  199. IMessage[] ra = getMessagesWithoutExpectedFails();
  200. MessageUtil.handleAll(handler, ra, fastFail);
  201. }
  202. CompilerDiffs diffs = getCompilerDiffs();
  203. if (diffs.different) {
  204. diffs.messages.report(handler, IMessage.FAIL);
  205. diffs.recompiled.report(handler, IMessage.FAIL);
  206. }
  207. }
  208. /** @return String consisting of differences and any other messages */
  209. public String toString() {
  210. CompilerDiffs diffs = getCompilerDiffs();
  211. StringBuffer sb = new StringBuffer(super.toString());
  212. final String EOL = "\n";
  213. sb.append(EOL);
  214. render(sb, " unexpected message ", EOL, diffs.messages.unexpected);
  215. render(sb, " missing message ", EOL, diffs.messages.missing);
  216. render(sb, " fail ", EOL, getList(IMessage.FAIL));
  217. render(sb, " abort ", EOL, getList(IMessage.ABORT));
  218. render(sb, " info ", EOL, getList(IMessage.INFO));
  219. return sb.toString(); // XXX cache toString
  220. }
  221. /**
  222. * Check if the message was expected, and clear diffs if not.
  223. * @return true if we expect a message of this kind with this line number
  224. */
  225. private boolean expecting(IMessage message) {
  226. boolean match = false;
  227. if (null != message) {
  228. for (Iterator iter = expectedMessagesAsList.iterator();
  229. iter.hasNext();
  230. ) {
  231. // amc - we have to compare against all messages to consume multiple
  232. // text matches on same line. Return true if any matches.
  233. if (0 == COMP_IMessage.compare(message, iter.next())) {
  234. match = true;
  235. }
  236. }
  237. }
  238. if (!match) {
  239. diffs = null;
  240. }
  241. return match;
  242. }
  243. private IMessage[] getMessagesWithoutExpectedFails() {
  244. IMessage[] result = super.getMessages(null, true);
  245. // remove all expected fail+ (COSTLY)
  246. ArrayList<IMessage> list = new ArrayList<>();
  247. int leftToFilter = numExpectedFailed;
  248. for (int i = 0; i < result.length; i++) {
  249. if ((0 == leftToFilter)
  250. || !IMessage.FAIL.isSameOrLessThan(result[i].getKind())) {
  251. list.add(result[i]);
  252. } else {
  253. // see if this failure was expected
  254. if (expectedMessagesHasMatchFor(result[i])) {
  255. leftToFilter--; // ok, don't add
  256. } else {
  257. list.add(result[i]);
  258. }
  259. }
  260. }
  261. result = (IMessage[]) list.toArray(new IMessage[0]);
  262. return result;
  263. }
  264. /**
  265. * @param actual the actual IMessage to seek a match for in expected messages
  266. * @return true if actual message is matched in the expected messages
  267. */
  268. private boolean expectedMessagesHasMatchFor(IMessage actual) {
  269. for (Iterator iter = expectedMessagesAsList.iterator();
  270. iter.hasNext();
  271. ) {
  272. IMessage expected = (IMessage) iter.next();
  273. if (0 == COMP_IMessage.compare(expected, actual)) {
  274. return true;
  275. }
  276. }
  277. return false;
  278. }
  279. /** @return immutable list of a given kind - use null for all kinds */
  280. private List getList(IMessage.Kind kind) {
  281. if ((null == kind) || (0 == numMessages(kind, IMessageHolder.EQUAL))) {
  282. return Collections.EMPTY_LIST;
  283. }
  284. return Arrays.asList(getMessages(kind, IMessageHolder.EQUAL));
  285. }
  286. /** @return "" if no items or {prefix}{item}{suffix}... otherwise */
  287. private void render(// LangUtil instead?
  288. StringBuffer result, String prefix, String suffix, List items) {
  289. if ((null != items)) {
  290. for (Iterator iter = items.iterator(); iter.hasNext();) {
  291. result.append(prefix + iter.next() + suffix);
  292. }
  293. }
  294. }
  295. /** compiler results for errors, warnings, and recompiled files */
  296. public static class CompilerDiffs {
  297. /** Skip info messages when reporting unexpected messages */
  298. static final Diffs.Filter SKIP_UNEXPECTED_INFO = new Diffs.Filter() {
  299. public boolean accept(Object o) {
  300. return ((o instanceof IMessage) && !((IMessage) o).isInfo());
  301. }
  302. };
  303. public final Diffs messages;
  304. public final Diffs recompiled;
  305. public final boolean different;
  306. public CompilerDiffs(Diffs messages, Diffs recompiled) {
  307. this.recompiled = recompiled;
  308. this.messages = messages;
  309. different = (messages.different || recompiled.different);
  310. }
  311. }
  312. }