summaryrefslogtreecommitdiffstats
path: root/testing
diff options
context:
space:
mode:
Diffstat (limited to 'testing')
-rw-r--r--testing/src/org/aspectj/testing/harness/bridge/AjcMessageHandler.java574
-rw-r--r--testing/src/org/aspectj/testing/harness/bridge/FlatSuiteReader.java3
-rw-r--r--testing/src/org/aspectj/testing/util/Diffs.java612
-rw-r--r--testing/src/org/aspectj/testing/util/FileUtil.java2
-rw-r--r--testing/src/org/aspectj/testing/util/LangUtil.java3
-rw-r--r--testing/src/org/aspectj/testing/util/TestDiffs.java4
-rw-r--r--testing/src/org/aspectj/testing/xml/AjcSpecXmlReader.java100
-rw-r--r--testing/src/org/aspectj/testing/xml/SoftMessage.java536
-rw-r--r--testing/src/org/aspectj/testing/xml/SoftSourceLocation.java39
9 files changed, 1136 insertions, 737 deletions
diff --git a/testing/src/org/aspectj/testing/harness/bridge/AjcMessageHandler.java b/testing/src/org/aspectj/testing/harness/bridge/AjcMessageHandler.java
index d01f26ddc..dc19ea2b9 100644
--- a/testing/src/org/aspectj/testing/harness/bridge/AjcMessageHandler.java
+++ b/testing/src/org/aspectj/testing/harness/bridge/AjcMessageHandler.java
@@ -30,298 +30,314 @@ 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 {
+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;
+ /** Comparator for enclosed IMessage diffs */
+ public static final Comparator COMP_IMessage =
+ BridgeUtil.Comparators.MEDIUM_IMessage;
- /** 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;
+ /** Comparator for enclosed File diffs */
+ public static final Comparator COMP_File = BridgeUtil.Comparators.WEAK_File;
- /** true if there were no error or worse messages expected */
- private final boolean expectingCommandTrue;
+ /** unmodifiable list of IMessage messages of any type */
+ private final List expectedMessagesAsList;
- /** 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;
- }
+ /** IMessageHolder variant of expectedMessagesAsList */
+ private final IMessageHolder expectedMessages;
- /**
- * 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 expected;
- final List 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
- Diffs messages = new Diffs(
- "message",
- expected,
- actual,
- COMP_IMessage,
- Diffs.ACCEPT_ALL,
- CompilerDiffs.SKIP_UNEXPECTED_INFO);
- Diffs recompiled = new Diffs(
- "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);
- }
+ /** number of messages FAIL or worse */
+ private final int numExpectedFailed;
- 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
- }
+ /** true if there were no error or worse messages expected */
+ private final boolean expectingCommandTrue;
- /**
- * 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;
- }
+ /** unmodifiable list of File expected to be recompiled */
+ private final List expectedRecompiled;
+ // Unused now, but reinstate when supported
- private IMessage[] getMessagesWithoutExpectedFails() {
- IMessage[] result = super.getMessages(null, true);
- // remove all expected fail+ (COSTLY)
- ArrayList 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]);
+ /** 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 expected;
+ final List 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);
}
- }
- result = (IMessage[]) list.toArray(new IMessage[0]);
- return result;
- }
+ Diffs recompiled =
+ Diffs.makeDiffs(
+ "recompiled",
+ expectedRecompiled,
+ actualRecompiled,
+ COMP_File);
+ diffs = new CompilerDiffs(messages, recompiled);
+ }
+ return diffs;
+ }
-
- /**
- * @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);
- }
- }
+ /**
+ * 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 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);
+ }
+ }
}
diff --git a/testing/src/org/aspectj/testing/harness/bridge/FlatSuiteReader.java b/testing/src/org/aspectj/testing/harness/bridge/FlatSuiteReader.java
index 96e15bdc9..cdfe4d542 100644
--- a/testing/src/org/aspectj/testing/harness/bridge/FlatSuiteReader.java
+++ b/testing/src/org/aspectj/testing/harness/bridge/FlatSuiteReader.java
@@ -24,6 +24,7 @@ import org.aspectj.bridge.AbortException;
import org.aspectj.bridge.IMessage;
import org.aspectj.bridge.ISourceLocation;
import org.aspectj.bridge.Message;
+import org.aspectj.bridge.MessageUtil;
import org.aspectj.bridge.SourceLocation;
import org.aspectj.bridge.IMessage.Kind;
import org.aspectj.testing.util.BridgeUtil;
@@ -368,7 +369,7 @@ public class FlatSuiteReader implements SFileReader.Maker {
abortOnError,
System.err);
} catch (IOException e) {
- IMessage m = Message.fail("reading " + suiteFile, e);
+ IMessage m = MessageUtil.fail("reading " + suiteFile, e);
throw new AbortException(m);
}
diff --git a/testing/src/org/aspectj/testing/util/Diffs.java b/testing/src/org/aspectj/testing/util/Diffs.java
index 4e493534f..4c2ff3d39 100644
--- a/testing/src/org/aspectj/testing/util/Diffs.java
+++ b/testing/src/org/aspectj/testing/util/Diffs.java
@@ -13,6 +13,7 @@
package org.aspectj.testing.util;
+import java.io.File;
import java.util.*;
import java.util.ArrayList;
import java.util.Collections;
@@ -22,120 +23,525 @@ import java.util.List;
import org.aspectj.bridge.IMessage;
import org.aspectj.bridge.IMessageHandler;
+import org.aspectj.bridge.ISourceLocation;
import org.aspectj.bridge.MessageUtil;
+import org.aspectj.util.FileUtil;
+import org.aspectj.util.LangUtil;
-/** result struct for expected/actual diffs for Collection */
+/**
+ * Result struct for expected/actual diffs for Collection
+ */
public class Diffs {
- public static final Filter ACCEPT_ALL = new Filter() {
- public boolean accept(Object o) {
- return true;
- }
- };
- // XXX List -> Collection b/c comparator orders
- public static final Diffs NONE
- = new Diffs("NONE", Collections.EMPTY_LIST, Collections.EMPTY_LIST);
-
- /** name of the thing being diffed - used only for reporting */
- public final String label;
-
- /** immutable List */
- public final List missing;
+ /**
+ * Compare IMessage.Kind based on kind priority.
+ */
+ public static final Comparator KIND_PRIORITY = new Comparator() {
+ /**
+ * Compare IMessage.Kind based on kind priority.
+ * @throws NullPointerException if anything is null
+ */
+ public int compare(Object lhs, Object rhs) {
+ return ((IMessage.Kind) lhs).compareTo((IMessage.Kind) rhs);
+ }
+ };
+ /**
+ * Sort ISourceLocation based on line, file path.
+ */
+ public static final Comparator SORT_SOURCELOC = new Comparator() {
+ /**
+ * Compare ISourceLocation based on line, file path.
+ * @throws NullPointerException if anything is null
+ */
+ public int compare(Object lhs, Object rhs) {
+ ISourceLocation l = (ISourceLocation) lhs;
+ ISourceLocation r = (ISourceLocation) rhs;
+ int result = getLine(l) - getLine(r);
+ if (0 != result) {
+ return result;
+ }
+ String lp = getSourceFile(l).getPath();
+ String rp = getSourceFile(r).getPath();
+ return lp.compareTo(rp);
+ }
+ };
- /** immutable List */
- public final List unexpected;
+ /**
+ * Compare IMessages based on kind and source location line (only).
+ */
+ public static final Comparator MESSAGE_LINEKIND = new Comparator() {
+ /**
+ * Compare IMessages based on kind and source location line (only).
+ * @throws NullPointerException if anything is null
+ */
+ public int compare(Object lhs, Object rhs) {
+ IMessage lm = (IMessage) lhs;
+ IMessage rm = (IMessage) rhs;
+ ISourceLocation ls = (lm == null ? null : lm.getSourceLocation());
+ ISourceLocation rs = (rm == null ? null : rm.getSourceLocation());
+ int left = (ls == null ? -1 : ls.getLine());
+ int right = (rs == null ? -1 : rs.getLine());
+ int result = left - right;
+ if (0 == result) {
+ result = lm.getKind().compareTo(rm.getKind());
+ }
+ return result;
+ }
+ };
+ public static final Filter ACCEPT_ALL = new Filter() {
+ public boolean accept(Object o) {
+ return true;
+ }
+ };
+ // // XXX List -> Collection b/c comparator orders
+ // public static final Diffs NONE
+ // = new Diffs("NONE", Collections.EMPTY_LIST, Collections.EMPTY_LIST);
- /** true if there are any missing or unexpected */
- public final boolean different;
-
- private Diffs(String label, List missing, List unexpected) {
- this.label = label;
- this.missing = missing;
- this.unexpected = unexpected;
- different = ((0 != this.missing.size())
- || (0 != this.unexpected.size()));
- }
+ public static Diffs makeDiffs(
+ String label,
+ List expected,
+ List actual,
+ Comparator comparator) {
+ return makeDiffs(
+ label,
+ expected,
+ actual,
+ comparator,
+ ACCEPT_ALL,
+ ACCEPT_ALL);
+ }
- public Diffs(
- String label,
- List expected,
- List actual,
- Comparator comparator) {
- this(label, expected, actual, comparator, ACCEPT_ALL, ACCEPT_ALL);
- }
+ public static Diffs makeDiffs(
+ String label,
+ IMessage[] expected,
+ IMessage[] actual) {
+ return makeDiffs(label, expected, actual, null, null);
+ }
- public Diffs(
- String label,
- List expected,
- List actual,
- Comparator comparator,
- Filter missingFilter,
- Filter unexpectedFilter) {
- label = label.trim();
- if (null == label) {
- label = ": ";
- } else if (!label.endsWith(":")) {
- label += ": ";
- }
- this.label = " " + label;
- ArrayList miss = new ArrayList();
- ArrayList unexpect = new ArrayList();
-
- org.aspectj.testing.util.LangUtil.makeSoftDiffs(expected, actual, miss, unexpect, comparator);
- if (null != missingFilter) {
- for (ListIterator iter = miss.listIterator(); iter.hasNext();) {
- if (!missingFilter.accept(iter.next())) {
- iter.remove();
- }
- }
- }
- missing = Collections.unmodifiableList(miss);
- if (null != unexpectedFilter) {
- for (ListIterator iter = unexpect.listIterator(); iter.hasNext();) {
- if (!unexpectedFilter.accept(iter.next())) {
- iter.remove();
- }
- }
+ private static int getLine(ISourceLocation loc) {
+ int result = -1;
+ if (null != loc) {
+ result = loc.getLine();
}
- unexpected = Collections.unmodifiableList(unexpect);
- different = ((0 != this.missing.size())
- || (0 != this.unexpected.size()));
+ return result;
}
-
- /**
- * Report missing and extra items to handler.
- * For each item in missing or unexpected, this creates a {kind} IMessage with
- * the text "{missing|unexpected} {label}: {message}"
- * where {message} is the result of
- * <code>MessageUtil.renderMessage(IMessage)</code>.
- * @param handler where the messages go - not null
- * @param kind the kind of message to construct - not null
- * @param label the prefix for the message text - if null, "" used
- * @see MessageUtil#renderMessage(IMessage)
- */
- public void report(IMessageHandler handler, IMessage.Kind kind) {
- LangUtil.throwIaxIfNull(handler, "handler");
- LangUtil.throwIaxIfNull(kind, "kind");
- if (different) {
- for (Iterator iter = missing.iterator(); iter.hasNext();) {
- String s = MessageUtil.renderMessage((IMessage) iter.next());
- MessageUtil.fail(handler, "missing " + label + s);
- }
- for (Iterator iter = unexpected.iterator(); iter.hasNext();) {
- String s = MessageUtil.renderMessage((IMessage) iter.next());
- MessageUtil.fail(handler, "unexpected " + label + s);
- }
+ private static int getLine(IMessage message) {
+ int result = -1;
+ if ((null != message)) {
+ result = getLine(message.getSourceLocation());
}
+ return result;
}
-
- /** @return "{label}: (unexpected={#}, missing={#})" */
- public String toString() {
- return label + "(unexpected=" + unexpected.size()
- + ", missing=" + missing.size() + ")";
- }
- public static interface Filter {
- /** @return true to keep input in list of messages */
- boolean accept(Object input);
+
+ private static File getSourceFile(ISourceLocation loc) {
+ File result = ISourceLocation.NO_FILE;
+ if (null != loc) {
+ result = loc.getSourceFile();
+ }
+ return result;
}
-}
+ public static Diffs makeDiffs(
+ String label,
+ IMessage[] expected,
+ IMessage[] actual,
+ IMessage.Kind[] ignoreExpectedKinds,
+ IMessage.Kind[] ignoreActualKinds) {
+ ArrayList exp = getExcept(expected, ignoreExpectedKinds);
+ ArrayList act = getExcept(actual, ignoreActualKinds);
+
+ ArrayList missing = new ArrayList();
+ List unexpected = new ArrayList();
+
+ if (LangUtil.isEmpty(expected)) {
+ unexpected.addAll(act);
+ } else if (LangUtil.isEmpty(actual)) {
+ missing.addAll(exp);
+ } else {
+ ListIterator expectedIterator = exp.listIterator();
+ int lastLine = Integer.MIN_VALUE + 1;
+ ArrayList expectedFound = new ArrayList();
+ ArrayList expectedForLine = new ArrayList();
+ for (ListIterator iter = act.listIterator(); iter.hasNext();) {
+ IMessage actualMessage = (IMessage) iter.next();
+ int actualLine = getLine(actualMessage);
+ if (actualLine != lastLine) {
+ // new line - get all messages expected for it
+ if (lastLine > actualLine) {
+ throw new Error("sort error");
+ }
+ lastLine = actualLine;
+ expectedForLine.clear();
+ while (expectedIterator.hasNext()) {
+ IMessage curExpected =
+ (IMessage) expectedIterator.next();
+ int curExpectedLine = getLine(curExpected);
+ if (actualLine == curExpectedLine) {
+ expectedForLine.add(curExpected);
+ } else {
+ expectedIterator.previous();
+ break;
+ }
+ }
+ }
+ // now check actual against all expected on that line
+ boolean found = false;
+ IMessage expectedMessage = null;
+ for (Iterator iterator = expectedForLine.iterator();
+ !found && iterator.hasNext();
+ ) {
+ expectedMessage = (IMessage) iterator.next();
+ found = expectingMessage(expectedMessage, actualMessage);
+ }
+ if (found) {
+ iter.remove();
+ if (expectedFound.contains(expectedMessage)) {
+ // XXX warn: expected message matched two actual
+ } else {
+ expectedFound.add(expectedMessage);
+ }
+ } else {
+ // unexpected: any actual result not found
+ unexpected.add(actualMessage);
+ }
+ }
+ // missing: all expected results not found
+ exp.removeAll(expectedFound);
+ missing.addAll(exp);
+ }
+ return new Diffs(label, missing, unexpected);
+ }
+
+ public static Diffs makeDiffs(
+ String label,
+ List expected,
+ List actual,
+ Comparator comparator,
+ Filter missingFilter,
+ Filter unexpectedFilter) {
+ label = label.trim();
+ if (null == label) {
+ label = ": ";
+ } else if (!label.endsWith(":")) {
+ label += ": ";
+ }
+ final String thisLabel = " " + label;
+ ArrayList miss = new ArrayList();
+ ArrayList unexpect = new ArrayList();
+
+ org.aspectj.testing.util.LangUtil.makeSoftDiffs(
+ expected,
+ actual,
+ miss,
+ unexpect,
+ comparator);
+ if (null != missingFilter) {
+ for (ListIterator iter = miss.listIterator(); iter.hasNext();) {
+ if (!missingFilter.accept(iter.next())) {
+ iter.remove();
+ }
+ }
+ }
+ if (null != unexpectedFilter) {
+ for (ListIterator iter = unexpect.listIterator();
+ iter.hasNext();
+ ) {
+ if (!unexpectedFilter.accept(iter.next())) {
+ iter.remove();
+ }
+ }
+ }
+ return new Diffs(thisLabel, miss, unexpect);
+ }
+
+ // /**
+ // * Shift over elements in sink if they are of one of the specified kinds.
+ // * @param sink the IMessage[] to shift elements from
+ // * @param kinds
+ // * @return length of sink after shifting
+ // * (same as input length if nothing shifted)
+ // */
+ // public static int removeKinds(IMessage[] sink, IMessage.Kind[] kinds) {
+ // if (LangUtil.isEmpty(kinds)) {
+ // return sink.length;
+ // } else if (LangUtil.isEmpty(sink)) {
+ // return 0;
+ // }
+ // int from = -1;
+ // int to = -1;
+ // for (int j = 0; j < sink.length; j++) {
+ // from++;
+ // if (null == sink[j]) {
+ // continue;
+ // }
+ // boolean remove = false;
+ // for (int i = 0; !remove && (i < kinds.length); i++) {
+ // IMessage.Kind kind = kinds[i];
+ // if (null == kind) {
+ // continue;
+ // }
+ // if (0 == kind.compareTo(sink[j].getKind())) {
+ // remove = true;
+ // }
+ // }
+ // if (!remove) {
+ // to++;
+ // if (to != from) {
+ // sink[to] = sink[from];
+ // }
+ // }
+ // }
+ // return to+1;
+ // }
+
+ /**
+ * @param expected the File from the expected source location
+ * @param actual the File from the actual source location
+ * @return true if exp is ISourceLocation.NO_FILE
+ * or exp path is a suffix of the actual path
+ * (after using FileUtil.weakNormalize(..) on both)
+ */
+ static boolean expectingFile(File expected, File actual) {
+ if (null == expected) {
+ return (null == actual);
+ } else if (null == actual) {
+ return false;
+ }
+ if (expected != ISourceLocation.NO_FILE) {
+ String expPath = FileUtil.weakNormalize(expected.getPath());
+ String actPath = FileUtil.weakNormalize(actual.getPath());
+ if (!actPath.endsWith(expPath)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Soft comparison for expected message will not check a corresponding
+ * element in the actual message unless defined in the expected message.
+ * <pre>
+ * message
+ * kind must match (constant/priority)
+ * message only requires substring
+ * thrown ignored
+ * column ignored
+ * endline ignored
+ * details only requires substring
+ * sourceLocation
+ * line must match, unless expected < 0
+ * file ignored if ISourceLocation.NOFILE
+ * matches if expected is a suffix of actual
+ * after changing any \ to /
+ * extraSourceLocation[]
+ * if any are defined in expected, then there
+ * must be exactly the actual elements as are
+ * defined in expected (so it is an error to
+ * not define all if you define any)
+ * <pre>
+ * @param expected
+ * @param actual
+ * @return true if we are expecting the line, kind, file, message,
+ * details, and any extra source locations.
+ * (ignores column/endline, thrown) XXX
+ */
+ static boolean expectingMessage(IMessage expected, IMessage actual) {
+ if (null == expected) {
+ return (null == actual);
+ } else if (null == actual) {
+ return false;
+ }
+ if (0 != expected.getKind().compareTo(actual.getKind())) {
+ return false;
+ }
+ if (!expectingSourceLocation(expected.getSourceLocation(),
+ actual.getSourceLocation())) {
+ return false;
+ }
+ if (!expectingText(expected.getMessage(), actual.getMessage())) {
+ return false;
+ }
+ if (!expectingText(expected.getDetails(), actual.getDetails())) {
+ return false;
+ }
+ ISourceLocation[] esl =
+ (ISourceLocation[]) expected.getExtraSourceLocations().toArray(
+ new ISourceLocation[0]);
+ ISourceLocation[] asl =
+ (ISourceLocation[]) actual.getExtraSourceLocations().toArray(
+ new ISourceLocation[0]);
+
+ Arrays.sort(esl, SORT_SOURCELOC);
+ Arrays.sort(asl, SORT_SOURCELOC);
+ if (!expectingSourceLocations(esl, asl)) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * This returns true if no ISourceLocation are specified
+ * (i.e., it ignored any extra source locations if no expectations stated).
+ * XXX need const like NO_FILE.
+ * @param expected the sorted ISourceLocation[] expected
+ * @param expected the actual sorted ISourceLocation[]
+ * @return true if any expected element is expected by the corresponding actual element.
+ */
+ static boolean expectingSourceLocations(
+ ISourceLocation[] expected,
+ ISourceLocation[] actual) {
+ if (LangUtil.isEmpty(expected)) {
+ return true;
+ } else if (LangUtil.isEmpty(actual)) {
+ return false;
+ } else if (actual.length != expected.length) {
+ return false;
+ }
+ for (int i = 0; i < actual.length; i++) {
+ if (!expectingSourceLocation(expected[i], actual[i])) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * @param expected
+ * @param actual
+ * @return true if any expected line/file matches the actual line/file,
+ * accepting a substring as a file match
+ */
+ static boolean expectingSourceLocation(
+ ISourceLocation expected,
+ ISourceLocation actual) {
+ int eline = getLine(expected);
+ int aline = getLine(actual);
+ if ((-1 < eline) && (eline != aline)) {
+ return false;
+ }
+ if (!expectingFile(getSourceFile(expected), getSourceFile(actual))) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * @param expected the String in the expected message
+ * @param actual the String in the actual message
+ * @return true if both are null or actual contains expected
+ */
+ static boolean expectingText(String expected, String actual) {
+ if (null == expected) {
+ return true; // no expectations
+ } else if (null == actual) {
+ return false; // expected something
+ } else {
+ return (-1 != actual.indexOf(expected));
+ }
+ }
+
+ private static ArrayList getExcept(
+ IMessage[] source,
+ IMessage.Kind[] skip) {
+ ArrayList sink = new ArrayList();
+ if (LangUtil.isEmpty(source)) {
+ return sink;
+ }
+
+ if (LangUtil.isEmpty(skip)) {
+ sink.addAll(Arrays.asList(source));
+ Collections.sort(sink, MESSAGE_LINEKIND);
+ return sink;
+ }
+ for (int i = 0; i < source.length; i++) {
+ IMessage message = source[i];
+ IMessage.Kind mkind = message.getKind();
+ boolean skipping = false;
+ for (int j = 0; !skipping && (j < skip.length); j++) {
+ if (0 == mkind.compareTo(skip[j])) {
+ skipping = true;
+ }
+ }
+ if (!skipping) {
+ sink.add(message);
+ }
+ }
+ Collections.sort(sink, MESSAGE_LINEKIND);
+ return sink;
+ }
+
+ private static List harden(List list) {
+ return (
+ LangUtil.isEmpty(list)
+ ? Collections.EMPTY_LIST
+ : Collections.unmodifiableList(list));
+ }
+
+ /** name of the thing being diffed - used only for reporting */
+ public final String label;
+
+ /** immutable List */
+ public final List missing;
+
+ /** immutable List */
+ public final List unexpected;
+
+ /** true if there are any missing or unexpected */
+ public final boolean different;
+
+ /**
+ * Struct-constructor stores these values,
+ * wrapping the lists as unmodifiable.
+ * @param label the String label for these diffs
+ * @param missing the List of missing elements
+ * @param unexpected the List of unexpected elements
+ */
+ public Diffs(String label, List missing, List unexpected) {
+ this.label = label;
+ this.missing = harden(missing);
+ this.unexpected = harden(unexpected);
+ different =
+ ((0 != this.missing.size()) || (0 != this.unexpected.size()));
+ }
+
+ /**
+ * Report missing and extra items to handler.
+ * For each item in missing or unexpected, this creates a {kind} IMessage with
+ * the text "{missing|unexpected} {label}: {message}"
+ * where {message} is the result of
+ * <code>MessageUtil.renderMessage(IMessage)</code>.
+ * @param handler where the messages go - not null
+ * @param kind the kind of message to construct - not null
+ * @param label the prefix for the message text - if null, "" used
+ * @see MessageUtil#renderMessage(IMessage)
+ */
+ public void report(IMessageHandler handler, IMessage.Kind kind) {
+ LangUtil.throwIaxIfNull(handler, "handler");
+ LangUtil.throwIaxIfNull(kind, "kind");
+ if (different) {
+ for (Iterator iter = missing.iterator(); iter.hasNext();) {
+ String s = MessageUtil.renderMessage((IMessage) iter.next());
+ MessageUtil.fail(handler, "missing " + label + ": " + s);
+ }
+ for (Iterator iter = unexpected.iterator(); iter.hasNext();) {
+ String s = MessageUtil.renderMessage((IMessage) iter.next());
+ MessageUtil.fail(handler, "unexpected " + label + ": " + s);
+ }
+ }
+ }
+
+ /** @return "{label}: (unexpected={#}, missing={#})" */
+ public String toString() {
+ return label
+ + "(unexpected="
+ + unexpected.size()
+ + ", missing="
+ + missing.size()
+ + ")";
+ }
+ public static interface Filter {
+ /** @return true to keep input in list of messages */
+ boolean accept(Object input);
+ }
+}
diff --git a/testing/src/org/aspectj/testing/util/FileUtil.java b/testing/src/org/aspectj/testing/util/FileUtil.java
index e3ca612d1..b68d7f8b2 100644
--- a/testing/src/org/aspectj/testing/util/FileUtil.java
+++ b/testing/src/org/aspectj/testing/util/FileUtil.java
@@ -193,7 +193,7 @@ public class FileUtil {
unexp.addAll(Arrays.asList(dir.listFiles(touchedCollector)));
// report any unexpected changes
- return new Diffs(label, expected, unexp, String.CASE_INSENSITIVE_ORDER);
+ return Diffs.makeDiffs(label, expected, unexp, String.CASE_INSENSITIVE_ORDER);
}
diff --git a/testing/src/org/aspectj/testing/util/LangUtil.java b/testing/src/org/aspectj/testing/util/LangUtil.java
index d05fd2edc..c6b4b9ae1 100644
--- a/testing/src/org/aspectj/testing/util/LangUtil.java
+++ b/testing/src/org/aspectj/testing/util/LangUtil.java
@@ -270,8 +270,7 @@ public class LangUtil {
return ((null == s) || (0 == s.length()));
}
-
-
+
/**
* Throw IllegalArgumentException if any component in input array
* is null or (if superType is not null) not assignable to superType.
diff --git a/testing/src/org/aspectj/testing/util/TestDiffs.java b/testing/src/org/aspectj/testing/util/TestDiffs.java
index f07ed9664..2a69b1634 100644
--- a/testing/src/org/aspectj/testing/util/TestDiffs.java
+++ b/testing/src/org/aspectj/testing/util/TestDiffs.java
@@ -80,13 +80,13 @@ public class TestDiffs { // XXX pretty dumb implementation
reading = actual;
act = TestDiffs.readTestResults(actual, actual.getPath());
- Diffs tests = new Diffs("tests", exp, act, TestResult.BY_NAME);
+ Diffs tests = Diffs.makeDiffs("tests", exp, act, TestResult.BY_NAME);
// remove missing/unexpected (removed, added) tests from results
// otherwise, unexpected-[pass|fail] look like [fixes|broken]
ArrayList expResults = trimByName(exp, tests.missing);
ArrayList actResults = trimByName(act, tests.unexpected);
- Diffs results = new Diffs("results", expResults, actResults, TestResult.BY_PASSNAME);
+ Diffs results = Diffs.makeDiffs("results", expResults, actResults, TestResult.BY_PASSNAME);
// broken tests show up in results as unexpected-fail or missing-pass
// fixed tests show up in results as unexpected-pass or missing-fail
diff --git a/testing/src/org/aspectj/testing/xml/AjcSpecXmlReader.java b/testing/src/org/aspectj/testing/xml/AjcSpecXmlReader.java
index 849c59096..60be24296 100644
--- a/testing/src/org/aspectj/testing/xml/AjcSpecXmlReader.java
+++ b/testing/src/org/aspectj/testing/xml/AjcSpecXmlReader.java
@@ -52,6 +52,13 @@ public class AjcSpecXmlReader {
* - update any client writers referring to the DOCTYPE, as necessary.
* - the parent IXmlWriter should delegate to the child component
* as IXmlWriter (or write the subelement itself)
+ *
+ * Debugging
+ * - use logLevel = 2 for tracing
+ * - common mistakes
+ * - dtd has to match input
+ * - no rule defined (or misdefined) so element ignored
+ * - property read-only (?)
*/
private static final String EOL = "\n";
@@ -63,82 +70,6 @@ public class AjcSpecXmlReader {
public static final String DOCTYPE = "<!DOCTYPE "
+ AjcTest.Suite.Spec.XMLNAME + " SYSTEM \"" + DTD_PATH + "\">";
- /** xml leader */
- public static final String FILE_LEADER
- = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>";
-
- /**
- * @deprecated
- * @return a String suitable as an inlined DOCTYPE statement
- */
- public static String inlineDocType() {
- return "<!DOCTYPE "
- + AjcTest.Suite.Spec.XMLNAME
- + " ["
- + AjcSpecXmlReader.getDocType()
- + EOL + " ]>";
- }
-
- /**
- * @deprecated
- * @return the elements of a document type as a String,
- * using EOL as a line delimiter
- */
- public static String getDocType() {
- if (true) {
- throw new Error("XXX using ajcTestSuite.dtd");
- }
- StringBuffer r = new StringBuffer();
- final String suiteX = AjcTest.Suite.Spec.XMLNAME;
- final String ajctestX = AjcTest.Spec.XMLNAME;
- final String compileX = CompilerRun.Spec.XMLNAME;
- final String inccompileX = IncCompilerRun.Spec.XMLNAME;
- final String runX = JavaRun.Spec.XMLNAME;
- final String dirchangesX = DirChanges.Spec.XMLNAME;
- final String messageX = SoftMessage.XMLNAME;
-
- r.append(EOL + " <!ELEMENT " + suiteX + " (" + ajctestX + "+)>");
- r.append(EOL + " <!ATTLIST " + suiteX + " suiteDir CDATA #IMPLIED >");
- r.append(EOL + "");
- r.append(EOL + " <!ELEMENT " + ajctestX + " (" + compileX + ", (" + compileX + " | " + inccompileX + " | " + runX + ")*)>");
- r.append(EOL + " <!ATTLIST " + ajctestX + " title CDATA #REQUIRED >");
- r.append(EOL + " <!ATTLIST " + ajctestX + " dir CDATA #REQUIRED >");
- r.append(EOL + " <!ATTLIST " + ajctestX + " pr CDATA #IMPLIED >");
- r.append(EOL + " <!ATTLIST " + ajctestX + " keywords CDATA #IMPLIED >");
- r.append(EOL + "");
- r.append(EOL + " <!ELEMENT " + compileX + " (" + dirchangesX + "*,file*," + messageX + "*)>"); // deprecate file?
- r.append(EOL + " <!ATTLIST " + compileX + " staging CDATA #IMPLIED >"); // if precursor to incremental
- r.append(EOL + " <!ATTLIST " + compileX + " files CDATA #IMPLIED >");
- r.append(EOL + " <!ATTLIST " + compileX + " options CDATA #IMPLIED >");
- r.append(EOL + "");
- r.append(EOL + " <!ELEMENT " + inccompileX + " (" + dirchangesX + "*," + messageX + "*)>"); // add file* if not deprecated
- r.append(EOL + " <!ATTLIST " + inccompileX + " tag CDATA #REQUIRED >");
- r.append(EOL + "");
- r.append(EOL + " <!ELEMENT " + runX + " (" + dirchangesX + "*," + messageX + "*)>");
- r.append(EOL + " <!ATTLIST " + runX + " class CDATA #REQUIRED >");
- r.append(EOL + " <!ATTLIST " + runX + " skipTester CDATA #IMPLIED >");
- r.append(EOL + " <!ATTLIST " + runX + " options CDATA #IMPLIED >");
- r.append(EOL + "");
- r.append(EOL + " <!ELEMENT file (#PCDATA)>"); // deprecate?
- r.append(EOL + " <!ATTLIST file path CDATA #IMPLIED >");
- r.append(EOL + "");
- r.append(EOL + " <!ELEMENT " + messageX + " (#PCDATA)>");
- r.append(EOL + " <!ATTLIST " + messageX + " kind (error | warning | info | Xlint) #REQUIRED >");
- r.append(EOL + " <!ATTLIST " + messageX + " line CDATA #REQUIRED >");
- r.append(EOL + " <!ATTLIST " + messageX + " text CDATA #IMPLIED >"); // but Message requires non-null...
- r.append(EOL + " <!ATTLIST " + messageX + " file CDATA #IMPLIED >");
- r.append(EOL + "");
- r.append(EOL + " <!ELEMENT " + dirchangesX + " (#PCDATA)>");
- r.append(EOL + " <!ATTLIST " + dirchangesX + " dirToken (classes | run) #IMPLIED >");
- r.append(EOL + " <!ATTLIST " + dirchangesX + " defaultSuffix (.class) #IMPLIED >");
- r.append(EOL + " <!ATTLIST " + dirchangesX + " added CDATA #IMPLIED >");
- r.append(EOL + " <!ATTLIST " + dirchangesX + " removed CDATA #IMPLIED >");
- r.append(EOL + " <!ATTLIST " + dirchangesX + " updated CDATA #IMPLIED >");
- r.append(EOL + " <!ATTLIST " + dirchangesX + " unchanged CDATA #IMPLIED >");
- r.append(EOL + "");
- return r.toString();
- }
-
private static final AjcSpecXmlReader ME
= new AjcSpecXmlReader();
@@ -162,7 +93,7 @@ public class AjcSpecXmlReader {
try {
out.println("<!-- document type for ajc test suite - see "
+ AjcSpecXmlReader.class.getName() + " -->");
- out.println(getDocType());
+ //out.println(getDocType());
} finally {
out.close();
}
@@ -170,7 +101,8 @@ public class AjcSpecXmlReader {
private static final String[] LOG = new String[] {"info", "debug", "trace" };
- private int logLevel;
+ // XXX logLevel n>0 causes JUnit tests to fail!
+ private int logLevel = 0; // use 2 for tracing
private AjcSpecXmlReader() {}
@@ -292,7 +224,7 @@ public class AjcSpecXmlReader {
final String runX = ajctestX + "/" + JavaRun.Spec.XMLNAME;
final String dirchangesX = "*/" + DirChanges.Spec.XMLNAME;
final String messageX = "*/" + SoftMessage.XMLNAME;
- final String messageSrcLocX = messageX + "/source-location";
+ final String messageSrcLocX = messageX + "/" +SoftSourceLocation.XMLNAME;
// ---- each sub-element needs to be created
// handle messages the same at any level
@@ -323,9 +255,10 @@ public class AjcSpecXmlReader {
new String[] { "className", "javaVersion", "skipTester"});
digester.addSetProperties(dirchangesX);
digester.addSetProperties(messageX);
- digester.addSetProperties(messageSrcLocX);
+ digester.addSetProperties(messageSrcLocX, "line", "lineAsString");
digester.addSetProperties(messageX, "kind", "kindAsString");
digester.addSetProperties(messageX, "line", "lineAsString");
+ //digester.addSetProperties(messageX, "details", "details");
// only file subelement of compile uses text as path... XXX vestigial
digester.addCallMethod(compileX + "/file", "setFile", 0);
@@ -340,7 +273,9 @@ public class AjcSpecXmlReader {
digester.addSetNext(runX, "addChild", JavaRun.Spec.class.getName());
digester.addSetNext(compileX + "/file", "addWrapFile", AbstractRunSpec.WrapFile.class.getName());
digester.addSetNext(messageX, "addMessage", IMessage.class.getName());
- digester.addSetNext(messageSrcLocX, "setSourceLocation", ISourceLocation.class.getName());
+ // setSourceLocation is for the inline variant
+ // addSourceLocation is for the extra
+ digester.addSetNext(messageSrcLocX, "addSourceLocation", ISourceLocation.class.getName());
digester.addSetNext(dirchangesX, "addDirChanges", DirChanges.Spec.class.getName());
// can set parent, but prefer to have "knows-about" flow down only...
@@ -372,7 +307,7 @@ public class AjcSpecXmlReader {
new BProps(AbstractRunSpec.WrapFile.class,
new String[] { "path"}),
new BProps(SoftMessage.class,
- new String[] { "kindAsString", "lineAsString", "text", "file"})
+ new String[] { "kindAsString", "lineAsString", "text", "details", "file"})
// mapped from { "kind", "line", ...}
};
}
@@ -430,6 +365,7 @@ public class AjcSpecXmlReader {
m.setSourceLocation((ISourceLocation) null);
m.setText((String) null);
m.setKindAsString((String) null);
+ m.setDetails((String) null);
SoftSourceLocation sl = new SoftSourceLocation();
sl.setFile((String) null);
diff --git a/testing/src/org/aspectj/testing/xml/SoftMessage.java b/testing/src/org/aspectj/testing/xml/SoftMessage.java
index f11e55966..208b155b7 100644
--- a/testing/src/org/aspectj/testing/xml/SoftMessage.java
+++ b/testing/src/org/aspectj/testing/xml/SoftMessage.java
@@ -11,10 +11,10 @@
* Xerox/PARC initial implementation
* ******************************************************************/
-
package org.aspectj.testing.xml;
import java.io.File;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
@@ -26,261 +26,294 @@ import org.aspectj.bridge.MessageUtil;
import org.aspectj.bridge.SourceLocation;
import org.aspectj.util.LangUtil;
-
/**
* Implement messages.
- * This implementation is immutable if ISourceLocation is immutable.
+ * This implementation is immutable if ISourceLocation is immutable,
+ * except for adding source locations.
*/
-public class SoftMessage implements IMessage { // XXX mutable dup of Message
- public static String XMLNAME = "message";
- public static final File NO_FILE = ISourceLocation.NO_FILE;
- private String message;
- private IMessage.Kind kind;
- private Throwable thrown;
- private ISourceLocation sourceLocation;
- private String details;
+public class SoftMessage implements IMessage {
+ public static String XMLNAME = "message";
+ public static final File NO_FILE = ISourceLocation.NO_FILE;
+ private String message;
+ private IMessage.Kind kind;
+ private Throwable thrown;
+ private ISourceLocation sourceLocation;
+ private String details;
+ private final ArrayList extraSourceLocations = new ArrayList();
//private ISourceLocation pseudoSourceLocation; // set directly
- // collapse enclosed source location for shorter, property-based xml
- private String file;
- private int line = Integer.MAX_VALUE;
-
- /** convenience for constructing failure messages */
- public static SoftMessage fail(String message, Throwable thrown) {
- return new SoftMessage(message, IMessage.FAIL, thrown, null);
- }
-
- /**
- * Print messages.
- * @param messages List of IMessage
- */
- public static void writeXml(XMLWriter out, IMessageHolder messages) {
- if ((null == out) || (null == messages)
- || (0 == messages.numMessages(null, true))) {
- return;
- }
- List list = messages.getUnmodifiableListView();
- for (Iterator iter = list.iterator(); iter.hasNext();) {
- writeXml(out, (IMessage) iter.next());
- }
- }
-
- /**
- * Print messages.
- * @param messages IMessage[]
- */
- public static void writeXml(XMLWriter out, IMessage[] messages) {
- if ((null == out) || (null == messages)) {
- return;
- }
- for (int i = 0; i < messages.length; i++) {
- writeXml(out, messages[i]);
- }
- }
-
- /** print message as an element
- * @throws IllegalArgumentException if message.getThrown() is not null
- */
- public static void writeXml(XMLWriter out, IMessage message) { // XXX short form only, no files
- if ((null == out) || (null == message)) {
- return;
- }
- Throwable thrown = message.getThrown();
- if (null != thrown) {
- String m = "unable to write " + message + " thrown not permitted";
- throw new IllegalArgumentException(m);
- }
- final String elementName = XMLNAME;
- out.startElement(elementName, false);
- out.printAttribute("kind", message.getKind().toString());
- String value = message.getMessage();
- if (null != value) {
- out.printAttribute("message", value);
- }
- ISourceLocation sl = message.getSourceLocation();
- if (null != sl) {
- out.endAttributes();
- SoftSourceLocation.writeXml(out, sl);
- }
- out.endElement(elementName);
- }
-
-
-
- public SoftMessage() {} // XXX programmatic only
-
- /**
- * Create a (compiler) error or warning message
- * @param message the String used as the underlying message
- * @param sourceLocation the ISourceLocation, if any, associated with this message
- * @param isError if true, use IMessage.ERROR; else use IMessage.WARNING
- */
- public SoftMessage(String message, ISourceLocation location, boolean isError) {
- this(message, (isError ? IMessage.ERROR : IMessage.WARNING), null,
- location);
- }
-
- /**
- * Create a message, handling null values for message and kind
- * if thrown is not null.
- * @param message the String used as the underlying message
- * @param kind the IMessage.Kind of message - not null
- * @param thrown the Throwable, if any, associated with this message
- * @param sourceLocation the ISourceLocation, if any, associated with this message
- * @throws IllegalArgumentException if message is null and
- * thrown is null or has a null message, or if kind is null
- * and thrown is null.
- */
- public SoftMessage(String message, IMessage.Kind kind, Throwable thrown,
- ISourceLocation sourceLocation) {
- this.message = message;
- this.kind = kind;
- this.thrown = thrown;
- this.sourceLocation = sourceLocation;
- if (null == message) {
- if (null != thrown) {
- message = thrown.getMessage();
- }
- if (null == message) {
- throw new IllegalArgumentException("null message");
+ // collapse enclosed source location for shorter, property-based xml
+ private String file;
+ private int line = Integer.MAX_VALUE;
+
+ /** convenience for constructing failure messages */
+ public static SoftMessage fail(String message, Throwable thrown) {
+ return new SoftMessage(message, IMessage.FAIL, thrown, null);
+ }
+
+ /**
+ * Print messages.
+ * @param messages List of IMessage
+ */
+ public static void writeXml(XMLWriter out, IMessageHolder messages) {
+ if ((null == out)
+ || (null == messages)
+ || (0 == messages.numMessages(null, true))) {
+ return;
+ }
+ List list = messages.getUnmodifiableListView();
+ for (Iterator iter = list.iterator(); iter.hasNext();) {
+ writeXml(out, (IMessage) iter.next());
+ }
+ }
+
+ /**
+ * Print messages.
+ * @param messages IMessage[]
+ */
+ public static void writeXml(XMLWriter out, IMessage[] messages) {
+ if ((null == out) || (null == messages)) {
+ return;
+ }
+ for (int i = 0; i < messages.length; i++) {
+ writeXml(out, messages[i]);
+ }
+ }
+
+ /** print message as an element
+ * XXX has to sync with ajcTests.dtd
+ * @throws IllegalArgumentException if message.getThrown() is not null
+ */
+ public static void writeXml(
+ XMLWriter out,
+ IMessage message) { // XXX short form only, no files
+ if ((null == out) || (null == message)) {
+ return;
+ }
+ Throwable thrown = message.getThrown();
+ if (null != thrown) {
+ String m = "unable to write " + message + " thrown not permitted";
+ throw new IllegalArgumentException(m);
+ }
+ final String elementName = XMLNAME;
+ out.startElement(elementName, false);
+ out.printAttribute("kind", message.getKind().toString());
+ String value = message.getMessage();
+ if (null != value) {
+ value = XMLWriter.attributeValue(value);
+ out.printAttribute("message", value);
+ }
+ value = message.getDetails();
+ if (null != value) {
+ value = XMLWriter.attributeValue(value);
+ out.printAttribute("details", value);
+ }
+ ISourceLocation sl = message.getSourceLocation();
+ if (null != sl) {
+ int line = sl.getLine();
+ if (-1 < line) {
+ out.printAttribute("line", "" + line);
}
+ File file = sl.getSourceFile();
+ if ((null != file) && !ISourceLocation.NO_FILE.equals(file)) {
+ value = XMLWriter.attributeValue(file.getPath());
+ out.printAttribute("file", value);
+ }
+ }
+ List extras = message.getExtraSourceLocations();
+ if (!LangUtil.isEmpty(extras)) {
+ out.endAttributes();
+ for (Iterator iter = extras.iterator(); iter.hasNext();) {
+ ISourceLocation element = (ISourceLocation) iter.next();
+ SoftSourceLocation.writeXml(out, sl);
+ }
}
- if (null == kind) {
- throw new IllegalArgumentException("null kind");
- }
- }
-
- /** @return the kind of this message */
- public IMessage.Kind getKind() {
- return kind;
- }
-
- /** @return true if kind == IMessage.ERROR */
- public boolean isError() {
- return kind == IMessage.ERROR;
- }
-
- /** @return true if kind == IMessage.WARNING */
- public boolean isWarning() {
- return kind == IMessage.WARNING;
- }
-
- /** @return true if kind == IMessage.DEBUG */
- public boolean isDebug() {
- return kind == IMessage.DEBUG;
- }
-
- /**
- * @return true if kind == IMessage.INFO
- */
- public boolean isInfo() {
- return kind == IMessage.INFO;
- }
-
- /** @return true if kind == IMessage.ABORT */
- public boolean isAbort() {
- return kind == IMessage.ABORT;
- }
-
- /**
- * @return true if kind == IMessage.FAIL
- */
- public boolean isFailed() {
- return kind == IMessage.FAIL;
- }
-
- /** @return non-null String with simple message */
- final public String getMessage() {
- return message;
- }
-
- /** @return Throwable associated with this message, or null if none */
- final public Throwable getThrown() {
- return thrown;
- }
-
- /**
- * This returns any ISourceLocation set or a mock-up
- * if file and/or line were set.
- * @return ISourceLocation associated with this message,
- * a mock-up if file or line is available, or null if none
- */
- final public ISourceLocation getSourceLocation() {
- if ((null == sourceLocation)
- && ((null != file) || (line != Integer.MAX_VALUE))) {
- File f = (null == file ? NO_FILE : new File(file));
- int line = (this.line == Integer.MAX_VALUE ? 0 : this.line);
- sourceLocation = new SourceLocation(f, line);
- }
- return sourceLocation;
- }
-
- /** set the kind of this message */
- public void setMessageKind(IMessage.Kind kind) {
- this.kind = (null == kind ? IMessage.ERROR : kind);
- }
-
-
- /** set the file for the underlying source location of this message
- * @throws IllegalStateException if source location was set directly
- * or indirectly by calling getSourceLocation after setting
- * file or line.
- */
- public void setFile(String path) {
- LangUtil.throwIaxIfFalse(!LangUtil.isEmpty(path), "empty path");
- if (null != sourceLocation) {
- throw new IllegalStateException("cannot set line after creating source location");
- }
- this.file = path;
- }
-
- /** set the kind of this message */
- public void setKindAsString(String kind) {
- setMessageKind(MessageUtil.getKind(kind));
- }
-
- public void setSourceLocation(ISourceLocation sourceLocation) {
- this.sourceLocation = sourceLocation;
- }
-
- /**
- * Set the line for the underlying source location.
- * @throws IllegalStateException if source location was set directly
- * or indirectly by calling getSourceLocation after setting
- * file or line.
- */
- public void setLineAsString(String line) {
- if (null != sourceLocation) {
- throw new IllegalStateException("cannot set line after creating source location");
- }
- this.line = Integer.valueOf(line).intValue();
- SourceLocation.validLine(this.line);
- }
-
- public void setText(String text) {
- this.message = (null == text ? "" : text);
- }
-
- public String toString() {
- StringBuffer result = new StringBuffer();
-
- result.append(getKind().toString());
-
- String messageString = getMessage();
- if (!LangUtil.isEmpty(messageString)) {
- result.append(messageString);
- }
+ out.endElement(elementName);
+ }
+
+ public SoftMessage() {
+ } // XXX programmatic only
+
+ /**
+ * Create a (compiler) error or warning message
+ * @param message the String used as the underlying message
+ * @param sourceLocation the ISourceLocation, if any, associated with this message
+ * @param isError if true, use IMessage.ERROR; else use IMessage.WARNING
+ */
+ public SoftMessage(
+ String message,
+ ISourceLocation location,
+ boolean isError) {
+ this(
+ message,
+ (isError ? IMessage.ERROR : IMessage.WARNING),
+ null,
+ location);
+ }
+
+ /**
+ * Create a message, handling null values for message and kind
+ * if thrown is not null.
+ * @param message the String used as the underlying message
+ * @param kind the IMessage.Kind of message - not null
+ * @param thrown the Throwable, if any, associated with this message
+ * @param sourceLocation the ISourceLocation, if any, associated with this message
+ * @throws IllegalArgumentException if message is null and
+ * thrown is null or has a null message, or if kind is null
+ * and thrown is null.
+ */
+ public SoftMessage(
+ String message,
+ IMessage.Kind kind,
+ Throwable thrown,
+ ISourceLocation sourceLocation) {
+ this.message = message;
+ this.kind = kind;
+ this.thrown = thrown;
+ this.sourceLocation = sourceLocation;
+ if (null == message) {
+ if (null != thrown) {
+ message = thrown.getMessage();
+ }
+ if (null == message) {
+ throw new IllegalArgumentException("null message");
+ }
+ }
+ if (null == kind) {
+ throw new IllegalArgumentException("null kind");
+ }
+ }
+
+ /** @return the kind of this message */
+ public IMessage.Kind getKind() {
+ return kind;
+ }
+
+ /** @return true if kind == IMessage.ERROR */
+ public boolean isError() {
+ return kind == IMessage.ERROR;
+ }
+
+ /** @return true if kind == IMessage.WARNING */
+ public boolean isWarning() {
+ return kind == IMessage.WARNING;
+ }
+
+ /** @return true if kind == IMessage.DEBUG */
+ public boolean isDebug() {
+ return kind == IMessage.DEBUG;
+ }
+
+ /**
+ * @return true if kind == IMessage.INFO
+ */
+ public boolean isInfo() {
+ return kind == IMessage.INFO;
+ }
+
+ /** @return true if kind == IMessage.ABORT */
+ public boolean isAbort() {
+ return kind == IMessage.ABORT;
+ }
+
+ /**
+ * @return true if kind == IMessage.FAIL
+ */
+ public boolean isFailed() {
+ return kind == IMessage.FAIL;
+ }
+
+ /** @return non-null String with simple message */
+ final public String getMessage() {
+ return message;
+ }
+
+ /** @return Throwable associated with this message, or null if none */
+ final public Throwable getThrown() {
+ return thrown;
+ }
+
+ /**
+ * This returns any ISourceLocation set or a mock-up
+ * if file and/or line were set.
+ * @return ISourceLocation associated with this message,
+ * a mock-up if file or line is available, or null if none
+ */
+ final public ISourceLocation getSourceLocation() {
+ if ((null == sourceLocation)
+ && ((null != file) || (line != Integer.MAX_VALUE))) {
+ File f = (null == file ? NO_FILE : new File(file));
+ int line = (this.line == Integer.MAX_VALUE ? 0 : this.line);
+ sourceLocation = new SourceLocation(f, line);
+ }
+ return sourceLocation;
+ }
+
+ /** set the kind of this message */
+ public void setMessageKind(IMessage.Kind kind) {
+ this.kind = (null == kind ? IMessage.ERROR : kind);
+ }
+
+ /** set the file for the underlying source location of this message
+ * @throws IllegalStateException if source location was set directly
+ * or indirectly by calling getSourceLocation after setting
+ * file or line.
+ */
+ public void setFile(String path) {
+ LangUtil.throwIaxIfFalse(!LangUtil.isEmpty(path), "empty path");
+ if (null != sourceLocation) {
+ throw new IllegalStateException("cannot set line after creating source location");
+ }
+ this.file = path;
+ }
+
+ /** set the kind of this message */
+ public void setKindAsString(String kind) {
+ setMessageKind(MessageUtil.getKind(kind));
+ }
+
+ public void setSourceLocation(ISourceLocation sourceLocation) {
+ this.sourceLocation = sourceLocation;
+ }
+
+ /**
+ * Set the line for the underlying source location.
+ * @throws IllegalStateException if source location was set directly
+ * or indirectly by calling getSourceLocation after setting
+ * file or line.
+ */
+ public void setLineAsString(String line) {
+ if (null != sourceLocation) {
+ throw new IllegalStateException("cannot set line after creating source location");
+ }
+ this.line = Integer.valueOf(line).intValue();
+ SourceLocation.validLine(this.line);
+ }
+
+ public void setText(String text) {
+ this.message = (null == text ? "" : text);
+ }
+
+ public String toString() {
+ StringBuffer result = new StringBuffer();
+
+ result.append(null == getKind() ? "<null kind>" : getKind().toString());
+
+ String messageString = getMessage();
+ if (!LangUtil.isEmpty(messageString)) {
+ result.append(messageString);
+ }
+
+ ISourceLocation loc = getSourceLocation();
+ if ((null != loc) && (loc != ISourceLocation.NO_FILE)) {
+ result.append(" at " + loc);
+ }
+ if (null != thrown) {
+ result.append(" -- " + LangUtil.renderExceptionShort(thrown));
+ }
+ return result.toString();
+ }
- ISourceLocation loc = getSourceLocation();
- if ((null != loc) && (loc != ISourceLocation.NO_FILE)) {
- result.append(" at " + loc);
- }
- if (null != thrown) {
- result.append(" -- " + LangUtil.renderExceptionShort(thrown));
- }
- return result.toString();
- }
-
public String getDetails() {
return details;
}
@@ -293,6 +326,11 @@ public class SoftMessage implements IMessage { // XXX mutable dup of Message
* @see org.aspectj.bridge.IMessage#getExtraSourceLocations()
*/
public List getExtraSourceLocations() {
- return Collections.EMPTY_LIST;
+ return extraSourceLocations;
+ }
+ public void addSourceLocation(ISourceLocation location) {
+ if (null != location) {
+ extraSourceLocations.add(location);
+ }
}
}
diff --git a/testing/src/org/aspectj/testing/xml/SoftSourceLocation.java b/testing/src/org/aspectj/testing/xml/SoftSourceLocation.java
index 48d88db69..7df8436a0 100644
--- a/testing/src/org/aspectj/testing/xml/SoftSourceLocation.java
+++ b/testing/src/org/aspectj/testing/xml/SoftSourceLocation.java
@@ -1,6 +1,7 @@
/* *******************************************************************
* Copyright (c) 1999-2001 Xerox Corporation,
- * 2002 Palo Alto Research Center, Incorporated (PARC).
+ * 2002 Palo Alto Research Center, Incorporated (PARC),
+ * 2004 Contributors.
* All rights reserved.
* This program and the accompanying materials are made available
* under the terms of the Common Public License v1.0
@@ -9,6 +10,7 @@
*
* Contributors:
* Xerox/PARC initial implementation
+ * Wes Isberg 2004 updates
* ******************************************************************/
package org.aspectj.testing.xml;
@@ -20,17 +22,13 @@ import org.aspectj.bridge.ISourceLocation;
import org.aspectj.util.LangUtil;
/**
- * Immutable source location.
- * This guarantees that the source file is not null
- * and that the numeric values are positive and line <= endLine.
- * @see org.aspectj.lang.reflect.SourceLocation
- * @see org.aspectj.compiler.base.parser.SourceInfo
- * @see org.aspectj.tools.ide.SourceLine
- * @see org.aspectj.testing.harness.ErrorLine
+ * A mutable ISourceLocation for XML initialization of tests.
+ * This does not support reading/writing of the attributes
+ * column, context, or endline.
*/
-public class SoftSourceLocation implements ISourceLocation { // XXX endLine?
- public static final File NONE = new File("SoftSourceLocation.NONE");
- public static final String XMLNAME = "source-location";
+public class SoftSourceLocation implements ISourceLocation {
+ public static final File NONE = ISourceLocation.NO_FILE;
+ public static final String XMLNAME = "source";
/**
* Write an ISourceLocation as XML element to an XMLWriter sink.
@@ -44,17 +42,16 @@ public class SoftSourceLocation implements ISourceLocation { // XXX endLine?
final String elementName = XMLNAME;
out.startElement(elementName, false);
out.printAttribute("line", "" + sl.getLine());
- out.printAttribute("column", "" + sl.getColumn());
- out.printAttribute("endLine", "" + sl.getEndLine());
+ // other attributes not supported
File file = sl.getSourceFile();
if (null != file) {
- out.printAttribute("sourceFile", file.getPath());
+ out.printAttribute("file", file.getPath());
}
out.endElement(elementName);
}
private File sourceFile;
- private int line;
+ private int line = -1; // required for no-line comparisons to work
private int column;
private int endLine;
private String context;
@@ -83,13 +80,20 @@ public class SoftSourceLocation implements ISourceLocation { // XXX endLine?
public void setFile(String sourceFile) {
this.sourceFile = new File(sourceFile);
}
+
+ public void setLine(String line) {
+ setLineAsString(line);
+ }
- public void setLine(String line) {
+ public void setLineAsString(String line) {
this.line = convert(line);
if (0 == endLine) {
endLine = this.line;
}
}
+ public String getLineAsString() {
+ return ""+line;
+ }
public void setColumn(String column) {
this.column = convert(column);
@@ -115,7 +119,6 @@ public class SoftSourceLocation implements ISourceLocation { // XXX endLine?
public String toString() {
return (null == context ? "" : context + LangUtil.EOL)
+ getSourceFile().getPath()
- + ":" + getLine()
- + ":" + getColumn();
+ + ":" + getLine() ;
}
}