123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343 |
- /* *******************************************************************
- * Copyright (c) 1999-2001 Xerox Corporation,
- * 2002 Palo Alto Research Center, Incorporated (PARC).
- * All rights reserved.
- * This program and the accompanying materials are made available
- * under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Xerox/PARC initial implementation
- * ******************************************************************/
-
- package org.aspectj.testing.harness.bridge;
-
- import java.util.ArrayList;
- import java.util.Arrays;
- import java.util.Collections;
- import java.util.Comparator;
- import java.util.Iterator;
- import java.util.List;
-
- import org.aspectj.bridge.IMessage;
- import org.aspectj.bridge.IMessageHandler;
- import org.aspectj.bridge.IMessageHolder;
- import org.aspectj.bridge.MessageHandler;
- import org.aspectj.bridge.MessageUtil;
- //import org.aspectj.bridge.IMessage.Kind;
- import org.aspectj.testing.util.BridgeUtil;
- import org.aspectj.testing.util.Diffs;
- import org.aspectj.util.LangUtil;
-
- /**
- * Handle messages during test and calculate differences
- * between expected and actual messages.
- */
- public class AjcMessageHandler extends MessageHandler {
-
- /** Comparator for enclosed IMessage diffs */
- public static final Comparator COMP_IMessage =
- BridgeUtil.Comparators.MEDIUM_IMessage;
-
- /** Comparator for enclosed File diffs */
- public static final Comparator COMP_File = BridgeUtil.Comparators.WEAK_File;
-
- /** unmodifiable list of IMessage messages of any type */
- private final List expectedMessagesAsList;
-
- /** IMessageHolder variant of expectedMessagesAsList */
- private final IMessageHolder expectedMessages;
-
- /** number of messages FAIL or worse */
- private final int numExpectedFailed;
-
- /** true if there were no error or worse messages expected */
- private final boolean expectingCommandTrue;
-
- /** unmodifiable list of File expected to be recompiled */
- private final List expectedRecompiled;
- // Unused now, but reinstate when supported
-
- /** if true, ignore warnings when calculating diffs and passed() */
- private final boolean ignoreWarnings;
-
- /** list of File actually recompiled */
- private List actualRecompiled;
-
- /** cache expected/actual diffs, nullify if any new message */
- private transient CompilerDiffs diffs;
-
- AjcMessageHandler(IMessageHolder expectedMessages) {
- this(expectedMessages, false);
- }
- /**
- * @param messages the (constant) IMessageHolder with expected messages
- */
- AjcMessageHandler(
- IMessageHolder expectedMessages,
- boolean ignoreWarnings) {
- LangUtil.throwIaxIfNull(messages, "messages");
- this.expectedMessages = expectedMessages;
- expectedMessagesAsList = expectedMessages.getUnmodifiableListView();
- expectedRecompiled = Collections.EMPTY_LIST;
- this.ignoreWarnings = ignoreWarnings;
- int fails = 0;
- int errors = 0;
- for (Iterator iter = expectedMessagesAsList.iterator();
- iter.hasNext();
- ) {
- IMessage m = (IMessage) iter.next();
- IMessage.Kind kind = m.getKind();
- if (IMessage.FAIL.isSameOrLessThan(kind)) {
- fails++;
- } else if (m.isError()) {
- errors++;
- }
- }
- expectingCommandTrue = (0 == (errors + fails));
- numExpectedFailed = fails;
- }
-
- /** clear out any actual values to be re-run */
- public void init() {
- super.init();
- actualRecompiled = null;
- diffs = null;
- }
-
- /**
- * Return true if we have this kind of
- * message for the same line and store all messages.
- * @see bridge.tools.impl.ErrorHandlerAdapter#doShowMessage(IMessage)
- * @return true if message handled (processing should abort)
- */
- public boolean handleMessage(IMessage message) {
- if (null == message) {
- throw new IllegalArgumentException("null message");
- }
- super.handleMessage(message);
- return expecting(message);
- }
-
- /**
- * Set the actual files recompiled.
- * @param List of File recompiled - may be null; adopted but not modified
- * @throws IllegalStateException if they have been set already.
- */
- public void setRecompiled(List list) {
- if (null != actualRecompiled) {
- throw new IllegalStateException("actual recompiled already set");
- }
- this.actualRecompiled = LangUtil.safeList(list);
- }
-
- /** Generate differences between expected and actual errors and warnings */
- public CompilerDiffs getCompilerDiffs() {
- if (null == diffs) {
- final List<IMessage> expected;
- final List<IMessage> actual;
- if (!ignoreWarnings) {
- expected = expectedMessages.getUnmodifiableListView();
- actual = this.getUnmodifiableListView();
- } else {
- expected =
- Arrays.asList(
- expectedMessages.getMessages(IMessage.ERROR, true));
- actual = Arrays.asList(this.getMessages(IMessage.ERROR, true));
- }
- // we ignore unexpected info messages,
- // but we do test for expected ones
- final Diffs messages;
- boolean usingNew = true; // XXX extract old API's after shake-out period
- if (usingNew) {
- final IMessage.Kind[] NOSKIPS = new IMessage.Kind[0];
- IMessage.Kind[] skipActual = new IMessage.Kind[] { IMessage.INFO };
- int expectedInfo
- = MessageUtil.numMessages(expected, IMessage.INFO, false);
- if (0 < expectedInfo) {
- // fyi, when expecting any info messages, have to expect all
- skipActual = NOSKIPS;
- }
- messages = Diffs.makeDiffs(
- "message",
- (IMessage[]) expected.toArray(new IMessage[0]),
- (IMessage[]) actual.toArray(new IMessage[0]),
- NOSKIPS,
- skipActual);
- } else {
- messages = Diffs.makeDiffs(
- "message",
- expected,
- actual,
- COMP_IMessage,
- Diffs.ACCEPT_ALL,
- CompilerDiffs.SKIP_UNEXPECTED_INFO);
- }
- Diffs recompiled =
- Diffs.makeDiffs(
- "recompiled",
- expectedRecompiled,
- actualRecompiled,
- COMP_File);
- diffs = new CompilerDiffs(messages, recompiled);
- }
- return diffs;
- }
-
- /**
- * Get the (current) result of this run,
- * ignoring differences in warnings on request.
- * Note it may return passed (true) when there are expected error messages.
- * @return false
- * if there are any fail or abort messages,
- * or if the expected errors, warnings, or recompiled do not match actual.
- */
- public boolean passed() {
- return !getCompilerDiffs().different;
- }
-
- /** @return true if we are expecting the command to fail - i.e., any expected errors */
- public boolean expectingCommandTrue() {
- return expectingCommandTrue;
- }
-
- /**
- * Report results to a handler,
- * adding all messages
- * and creating fail messages for each diff.
- */
- public void report(IMessageHandler handler) {
- if (null == handler) {
- MessageUtil.debug(this, "report got null handler");
- }
- // Report all messages except expected fail+ messages,
- // which will cause the reported-to handler client to gack.
- // XXX need some verbose way to report even expected fail+
- final boolean fastFail = false; // do all messages
- if (0 == numExpectedFailed) {
- MessageUtil.handleAll(handler, this, fastFail);
- } else {
- IMessage[] ra = getMessagesWithoutExpectedFails();
- MessageUtil.handleAll(handler, ra, fastFail);
- }
-
- CompilerDiffs diffs = getCompilerDiffs();
- if (diffs.different) {
- diffs.messages.report(handler, IMessage.FAIL);
- diffs.recompiled.report(handler, IMessage.FAIL);
- }
- }
-
- /** @return String consisting of differences and any other messages */
- public String toString() {
- CompilerDiffs diffs = getCompilerDiffs();
- StringBuffer sb = new StringBuffer(super.toString());
- final String EOL = "\n";
- sb.append(EOL);
- render(sb, " unexpected message ", EOL, diffs.messages.unexpected);
- render(sb, " missing message ", EOL, diffs.messages.missing);
- render(sb, " fail ", EOL, getList(IMessage.FAIL));
- render(sb, " abort ", EOL, getList(IMessage.ABORT));
- render(sb, " info ", EOL, getList(IMessage.INFO));
- return sb.toString(); // XXX cache toString
- }
-
- /**
- * Check if the message was expected, and clear diffs if not.
- * @return true if we expect a message of this kind with this line number
- */
- private boolean expecting(IMessage message) {
- boolean match = false;
- if (null != message) {
- for (Iterator iter = expectedMessagesAsList.iterator();
- iter.hasNext();
- ) {
- // amc - we have to compare against all messages to consume multiple
- // text matches on same line. Return true if any matches.
- if (0 == COMP_IMessage.compare(message, iter.next())) {
- match = true;
- }
- }
- }
- if (!match) {
- diffs = null;
- }
- return match;
- }
-
- private IMessage[] getMessagesWithoutExpectedFails() {
- IMessage[] result = super.getMessages(null, true);
- // remove all expected fail+ (COSTLY)
- ArrayList<IMessage> list = new ArrayList<>();
- int leftToFilter = numExpectedFailed;
- for (int i = 0; i < result.length; i++) {
- if ((0 == leftToFilter)
- || !IMessage.FAIL.isSameOrLessThan(result[i].getKind())) {
- list.add(result[i]);
- } else {
- // see if this failure was expected
- if (expectedMessagesHasMatchFor(result[i])) {
- leftToFilter--; // ok, don't add
- } else {
- list.add(result[i]);
- }
- }
- }
- result = (IMessage[]) list.toArray(new IMessage[0]);
- return result;
- }
-
- /**
- * @param actual the actual IMessage to seek a match for in expected messages
- * @return true if actual message is matched in the expected messages
- */
- private boolean expectedMessagesHasMatchFor(IMessage actual) {
- for (Iterator iter = expectedMessagesAsList.iterator();
- iter.hasNext();
- ) {
- IMessage expected = (IMessage) iter.next();
- if (0 == COMP_IMessage.compare(expected, actual)) {
- return true;
- }
- }
- return false;
- }
-
- /** @return immutable list of a given kind - use null for all kinds */
- private List getList(IMessage.Kind kind) {
- if ((null == kind) || (0 == numMessages(kind, IMessageHolder.EQUAL))) {
- return Collections.EMPTY_LIST;
- }
- return Arrays.asList(getMessages(kind, IMessageHolder.EQUAL));
- }
-
- /** @return "" if no items or {prefix}{item}{suffix}... otherwise */
- private void render(// LangUtil instead?
- StringBuffer result, String prefix, String suffix, List items) {
- if ((null != items)) {
- for (Iterator iter = items.iterator(); iter.hasNext();) {
- result.append(prefix + iter.next() + suffix);
- }
- }
- }
-
- /** compiler results for errors, warnings, and recompiled files */
- public static class CompilerDiffs {
- /** Skip info messages when reporting unexpected messages */
- static final Diffs.Filter SKIP_UNEXPECTED_INFO = new Diffs.Filter() {
- public boolean accept(Object o) {
- return ((o instanceof IMessage) && !((IMessage) o).isInfo());
- }
- };
- public final Diffs messages;
- public final Diffs recompiled;
- public final boolean different;
-
- public CompilerDiffs(Diffs messages, Diffs recompiled) {
- this.recompiled = recompiled;
- this.messages = messages;
- different = (messages.different || recompiled.different);
- }
- }
- }
|