added provisional message reader for specifying expected messages in a separate file.tags/V_1_1_b5
@@ -67,10 +67,10 @@ public class Ajctest extends Task implements PropertyChangeListener { | |||
} | |||
private static boolean dumpresults = false; | |||
private static Stats ajdocStats = new Stats(); | |||
private static Stats ajcStats = new Stats(); | |||
private static Stats runStats = new Stats(); | |||
private static Stats errorStats = new Stats(); | |||
private Stats ajdocStats = new Stats(); | |||
private Stats ajcStats = new Stats(); | |||
private Stats runStats = new Stats(); | |||
private Stats errorStats = new Stats(); | |||
private static final String NO_TESTID = "NONE"; | |||
private File workingdir = new File("ajworkingdir"); //XXX | |||
@@ -1093,7 +1093,7 @@ public class Ajctest extends Task implements PropertyChangeListener { | |||
oneLine = "\nRESULT=\"ERROR\" null ACJTEST"; | |||
} else { | |||
StringBuffer sb = new StringBuffer("\n"); | |||
int errs = current.allErrors.size(); | |||
int errs = Ajctest.allErrors.size(); | |||
int allFails = errs | |||
+ current.ajdocStats.fails | |||
+ current.ajcStats.fails | |||
@@ -1144,9 +1144,9 @@ public class Ajctest extends Task implements PropertyChangeListener { | |||
"------------------------------" + "\n"; | |||
str += "Task\tPassed\tFailed" + "\n"; | |||
Object[] os = new Object[] { | |||
"ajdoc", ajdocStats.goods+"", ajdocStats.fails+"", | |||
"ajc", ajcStats.goods +"", ajcStats.fails +"", | |||
"run", runStats.goods +"", runStats.fails +"", | |||
"ajdoc", current.ajdocStats.goods+"", current.ajdocStats.fails+"", | |||
"ajc", current.ajcStats.goods +"", current.ajcStats.fails +"", | |||
"run", current.runStats.goods +"", current.runStats.fails +"", | |||
}; | |||
for (int i = 0; i < os.length; i += 3) { | |||
str += os[i] + "\t" + os[i+1] + "\t" + os[i+2] + "\n"; | |||
@@ -1178,9 +1178,9 @@ public class Ajctest extends Task implements PropertyChangeListener { | |||
err.println(multiLine); | |||
err.println(oneLine); | |||
if (dumpresults && (allErrors.size() + | |||
ajdocStats.fails + | |||
ajcStats.fails + | |||
runStats.fails) > 0) { | |||
current.ajdocStats.fails + | |||
current.ajcStats.fails + | |||
current.runStats.fails) > 0) { | |||
String date = date(System.currentTimeMillis()); | |||
String filename = "ajc-errors"; | |||
for (StringTokenizer t = new StringTokenizer(date, ",: "); |
@@ -33,7 +33,6 @@ import java.io.*; | |||
* <code>-DMainWrapper.classname="fully.qualified.Classname"</code>. | |||
* This returns -1 if unable to load the main method, | |||
* 1 if the invoked method throws an exception, and 0 otherwise. | |||
* TODO: prelminary | |||
*/ | |||
public class MainWrapper { | |||
/** MUST set the fully-qualified name of class to invoke using |
@@ -562,7 +562,7 @@ abstract public class AbstractRunSpec implements IRunSpec { // XXX use MessageHa | |||
if (null == value) { | |||
return null; | |||
} | |||
return out.makeAttribute(name, value); | |||
return XMLWriter.makeAttribute(name, value); | |||
} | |||
/** @return null if list is null or empty or name="{flattenedList}" otherwise */ | |||
@@ -570,8 +570,8 @@ abstract public class AbstractRunSpec implements IRunSpec { // XXX use MessageHa | |||
if (LangUtil.isEmpty(list)) { | |||
return null; | |||
} | |||
String flat = out.flattenList(list); | |||
return out.makeAttribute(name, flat); | |||
String flat = XMLWriter.flattenList(list); | |||
return XMLWriter.makeAttribute(name, flat); | |||
} | |||
/** @return true if writeAttributes(..) will produce any output */ | |||
@@ -598,15 +598,16 @@ abstract public class AbstractRunSpec implements IRunSpec { // XXX use MessageHa | |||
} | |||
if (!LangUtil.isEmpty(xmlNames.keywordsName) | |||
&& !LangUtil.isEmpty(keywords)) { | |||
out.printAttribute(xmlNames.keywordsName, out.flattenList(keywords)); | |||
out.printAttribute(xmlNames.keywordsName, | |||
XMLWriter.flattenList(keywords)); | |||
} | |||
if (!LangUtil.isEmpty(xmlNames.optionsName) | |||
&& !LangUtil.isEmpty(options)) { | |||
out.printAttribute(xmlNames.optionsName, out.flattenList(options)); | |||
out.printAttribute(xmlNames.optionsName, XMLWriter.flattenList(options)); | |||
} | |||
if (!LangUtil.isEmpty(xmlNames.pathsName) | |||
&& !LangUtil.isEmpty(paths)) { | |||
out.printAttribute(xmlNames.pathsName, out.flattenList(paths)); | |||
out.printAttribute(xmlNames.pathsName, XMLWriter.flattenList(paths)); | |||
} | |||
if (!LangUtil.isEmpty(xmlNames.commentName) | |||
&& !LangUtil.isEmpty(comment)) { |
@@ -191,9 +191,9 @@ public class AjcTest extends RunSpecIterator { | |||
public void writeXml(XMLWriter out) { | |||
out.println(""); | |||
String value = (null == testDirOffset? "" : testDirOffset); | |||
String attr = out.makeAttribute("dir", value); | |||
String attr = XMLWriter.makeAttribute("dir", value); | |||
if (0 != bugId) { | |||
attr += " " + out.makeAttribute("pr", ""+bugId); | |||
attr += " " + XMLWriter.makeAttribute("pr", ""+bugId); | |||
} | |||
out.startElement(xmlElementName, attr, false); | |||
super.writeAttributes(out); |
@@ -899,7 +899,7 @@ public class CompilerRun implements IAjcRun { | |||
out.printAttribute("dir", testSrcDirOffset); | |||
} | |||
if (!LangUtil.isEmpty(argfiles)) { | |||
out.printAttribute("argfiles", out.flattenFiles(argfiles)); | |||
out.printAttribute("argfiles", XMLWriter.flattenFiles(argfiles)); | |||
} | |||
super.writeAttributes(out); | |||
out.endAttributes(); |
@@ -327,7 +327,7 @@ public class IncCompilerRun implements IAjcRun { | |||
* @see IXmlWritable#writeXml(XMLWriter) | |||
*/ | |||
public void writeXml(XMLWriter out) { | |||
String attr = out.makeAttribute("tag", tag); | |||
String attr = XMLWriter.makeAttribute("tag", tag); | |||
out.startElement(xmlElementName, attr, false); | |||
super.writeAttributes(out); | |||
out.endAttributes(); |
@@ -247,7 +247,7 @@ public class JavaRun implements IAjcRun { | |||
* @see IXmlWritable#writeXml(XMLWriter) | |||
*/ | |||
public void writeXml(XMLWriter out) { | |||
String attr = out.makeAttribute("class", className); | |||
String attr = XMLWriter.makeAttribute("class", className); | |||
out.startElement(xmlElementName, attr, false); | |||
if (skipTester) { | |||
out.printAttribute("skipTester", "true"); |
@@ -21,7 +21,6 @@ import org.aspectj.util.LangUtil; | |||
import java.io.File; | |||
import java.util.ArrayList; | |||
import java.util.Arrays; | |||
/** | |||
* A sandbox holds state shared by AjcTest sub-runs, |
@@ -28,7 +28,6 @@ import java.security.AccessController; | |||
import java.security.PrivilegedActionException; | |||
import java.security.PrivilegedExceptionAction; | |||
import java.util.ArrayList; | |||
import java.util.Arrays; | |||
import java.util.BitSet; | |||
import java.util.Collections; | |||
import java.util.Comparator; |
@@ -0,0 +1,215 @@ | |||
/* ******************************************************************* | |||
* Copyright (c) 2003 Contributors. | |||
* All rights reserved. | |||
* This program and the accompanying materials are made available | |||
* under the terms of the Common Public License v1.0 | |||
* which accompanies this distribution and is available at | |||
* http://www.eclipse.org/legal/cpl-v10.html | |||
* | |||
* Contributors: | |||
* Wes Isberg initial implementation | |||
* ******************************************************************/ | |||
package org.aspectj.testing.xml; | |||
import org.apache.commons.digester.Digester; | |||
import org.aspectj.bridge.AbortException; | |||
import org.aspectj.bridge.IMessage; | |||
import org.aspectj.bridge.ISourceLocation; | |||
import org.aspectj.bridge.MessageUtil; | |||
import org.aspectj.util.LangUtil; | |||
import org.xml.sax.SAXException; | |||
import java.io.File; | |||
import java.io.FileInputStream; | |||
import java.io.FileOutputStream; | |||
import java.io.IOException; | |||
import java.io.PrintWriter; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
/** | |||
* Read a list of messages in xml form. | |||
* Input files should comply with DOCTYPE | |||
*/ | |||
public class MessageListXmlReader { | |||
private static final String INLINE_DOCTYPE; | |||
static { | |||
final String EOL = LangUtil.EOL; | |||
final StringBuffer r = new StringBuffer(); | |||
r.append("<!DOCTYPE "); | |||
r.append(MessageList.XMLNAME); | |||
r.append(" ["); | |||
r.append(EOL + " <!ELEMENT " + MessageList.XMLNAME | |||
+ " (" + SoftMessage.XMLNAME + "+) >"); | |||
String name = SoftMessage.XMLNAME; | |||
r.append(EOL + " <!ELEMENT " + name + " (" + SoftSourceLocation.XMLNAME + ")*>"); | |||
r.append(EOL + " <!ATTLIST " + name + " kind CDATA #REQUIRED >"); | |||
r.append(EOL + " <!ATTLIST " + name + " message CDATA #IMPLIED >"); | |||
name = SoftSourceLocation.XMLNAME; | |||
r.append(EOL + " <!ELEMENT " + name + " (#PCDATA) >"); | |||
r.append(EOL + " <!ATTLIST " + name + " line CDATA #REQUIRED >"); | |||
r.append(EOL + " <!ATTLIST " + name + " endLine CDATA #IMPLIED >"); | |||
r.append(EOL + " <!ATTLIST " + name + " column CDATA #IMPLIED >"); | |||
r.append(EOL + " <!ATTLIST " + name + " sourceFile CDATA #IMPLIED >"); | |||
r.append(EOL + "] >"); | |||
INLINE_DOCTYPE = r.toString(); | |||
} | |||
private static final String[] LOG = new String[] {"info", "debug", "trace" }; | |||
private int logLevel; | |||
/** | |||
* Print IMessage[] to the output file as XML. | |||
* @param output the File to write to - overwritten | |||
* @param messages the IMessage[] to write | |||
* @return null if no warnings detected, warnings otherwise | |||
*/ | |||
public String writeMessages(File output, IMessage[] messages) throws IOException { | |||
LangUtil.throwIaxIfNull(output, "output"); | |||
LangUtil.throwIaxIfFalse(!LangUtil.isEmpty(messages), "no messages"); | |||
PrintWriter writer = new PrintWriter(new FileOutputStream(output)); | |||
XMLWriter printSink = new XMLWriter(writer); | |||
writer.println(""); | |||
writer.println(INLINE_DOCTYPE); | |||
writer.println(""); | |||
writer.println("<" + MessageList.XMLNAME + ">"); | |||
SoftMessage.writeXml(printSink, messages); | |||
writer.println("</" + MessageList.XMLNAME + ">"); | |||
writer.close(); | |||
return null; | |||
} | |||
/** @param level 0..2, info..trace */ | |||
public void setLogLevel(int level) { | |||
if (level < 0) { | |||
level = 0; | |||
} | |||
if (level > 2) { | |||
level = 2; | |||
} | |||
logLevel = level; | |||
} | |||
/** | |||
* Read the specifications for a list of IMessage from an XML file. | |||
* @param file the File must be readable, comply with DOCTYPE. | |||
* @return IMessage[] read from file | |||
* @see setLogLevel(int) | |||
*/ | |||
public IMessage[] readMessages(File file) throws IOException, AbortException { | |||
// setup loggers for digester and beanutils... | |||
System.setProperty("org.apache.commons.logging.Log", "org.apache.commons.logging.impl.SimpleLog"); // XXX | |||
System.setProperty("org.apache.commons.logging.simplelog.defaultlog", LOG[logLevel]); // trace debug XXX | |||
final Digester digester = new Digester(); | |||
setupDigester(digester); | |||
MessageListHolder holder = new MessageListHolder(); | |||
digester.push(holder); | |||
FileInputStream input = new FileInputStream(file); | |||
try { | |||
digester.parse(input); | |||
} catch (SAXException e) { | |||
MessageUtil.fail("parsing " + file, e); | |||
} finally { | |||
if (null != input) { | |||
input.close(); | |||
input = null; | |||
} | |||
} | |||
return (null == holder.list | |||
? new IMessage[0] | |||
: holder.list.getMessages()); | |||
} | |||
/** set up the mapping between the xml and Java. */ | |||
private void setupDigester(Digester digester) { | |||
// XXX supply sax parser to ignore white space? | |||
digester.setValidating(true); | |||
// element names come from the element components | |||
final String messageListX = MessageList.XMLNAME; | |||
final String messageX = messageListX + "/" + SoftMessage.XMLNAME; | |||
final String messageSrcLocX = messageX + "/" + SoftSourceLocation.XMLNAME; | |||
// ---- each sub-element needs to be created | |||
// handle messages the same at any level | |||
digester.addObjectCreate(messageListX, MessageList.class.getName()); | |||
digester.addObjectCreate(messageX, SoftMessage.class.getName()); | |||
digester.addObjectCreate(messageSrcLocX, SoftSourceLocation.class.getName()); | |||
// ---- set bean properties for sub-elements created automatically | |||
// -- some remapped - warnings | |||
// - if property exists, map will not be used | |||
digester.addSetProperties(messageListX); | |||
digester.addSetProperties(messageX); | |||
digester.addSetProperties(messageSrcLocX); | |||
digester.addSetProperties(messageX, "kind", "kindAsString"); | |||
digester.addSetProperties(messageX, "line", "lineAsString"); | |||
// ---- when subelements are created, add to parent | |||
digester.addSetNext(messageListX, "addMessage", IMessage.class.getName()); | |||
digester.addSetNext(messageX, "setSourceLocation", ISourceLocation.class.getName()); | |||
// can set parent, but prefer to have "knows-about" flow down only... | |||
} | |||
// ------------------------------------------------------------ testing code | |||
/** | |||
* This is only to do compile-time checking for the APIs impliedly | |||
* used in setupDigester(..). | |||
* The property setter checks are redundant with tests based on | |||
* expectedProperties(). | |||
*/ | |||
private static void setupDigesterCompileTimeCheck() { | |||
if (true) { throw new Error("never invoked"); } | |||
MessageListHolder holder = new MessageListHolder(); | |||
MessageList ml = new MessageList(); | |||
SoftMessage m = new SoftMessage(); | |||
SoftSourceLocation sl = new SoftSourceLocation(); | |||
holder.setMessageList(ml); | |||
ml.addMessage((IMessage) null); | |||
m.setSourceLocation(sl); | |||
m.setText((String) null); | |||
m.setKindAsString((String) null); | |||
sl.setFile((String) null); | |||
sl.setLine((String) null); | |||
sl.setColumn((String) null); | |||
sl.setEndLine((String) null); | |||
// add attribute setters to validate? | |||
} | |||
// inner classes, to make public for bean utilities | |||
/** a list of messages */ | |||
public static class MessageList { | |||
public static final String XMLNAME = "message-list"; | |||
private List messages = new ArrayList(); | |||
public void addMessage(IMessage message) { | |||
messages.add(message); | |||
} | |||
IMessage[] getMessages() { | |||
return (IMessage[]) messages.toArray(new IMessage[0]); | |||
} | |||
} | |||
/** push on digester stack to hold message list */ | |||
public static class MessageListHolder { | |||
public MessageList list; | |||
public void setMessageList(MessageList list) { | |||
this.list = list; | |||
} | |||
} | |||
} | |||
@@ -75,38 +75,31 @@ public class SoftMessage implements IMessage { // XXX mutable dup of Message | |||
} | |||
} | |||
/** print message as an element */ | |||
/** 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; | |||
String kindStr = message.getKind().toString(); | |||
String kindAttr = out.makeAttribute("kind",kindStr); | |||
String mStr = message.getMessage(); | |||
if ((null != mStr) && (0 == mStr.length())) { | |||
mStr = null; | |||
out.startElement(elementName, false); | |||
out.printAttribute("kind", message.getKind().toString()); | |||
String value = message.getMessage(); | |||
if (null != value) { | |||
out.printAttribute("message", value); | |||
} | |||
String mAttr = (null == mStr ? " " : " " + out.makeAttribute("text", mStr)); | |||
int mAttrLen = (null == mStr ? 0 : mAttr.length()); | |||
ISourceLocation sl = message.getISourceLocation(); | |||
String lineStr = (null == sl ? null : "" + sl.getLine()); | |||
String lineAttr = (null == lineStr ? " " : " " + out.makeAttribute("line", lineStr)); | |||
int lineAttrLen = (null == lineStr ? 0 : lineAttr.length()); | |||
int len = (kindAttr.length() + mAttrLen + lineAttrLen); | |||
if (len < 65) { | |||
String s = kindAttr + " " | |||
+ ((null == lineStr ? "" : lineAttr) | |||
+ (null == mStr ? "" : " " + mAttr)).trim(); | |||
out.printElement(elementName, s); | |||
} else { | |||
out.startElement(elementName, kindAttr + lineAttr, false); | |||
if (0 < mStr.length()) { | |||
out.printAttribute("text", mStr); | |||
} | |||
out.endAttributes(); | |||
out.endElement(elementName); | |||
if (null != sl) { | |||
out.endAttributes(); | |||
SoftSourceLocation.writeXml(out, sl); | |||
} | |||
out.endElement(elementName); | |||
} | |||
@@ -29,6 +29,29 @@ import java.io.File; | |||
*/ | |||
public class SoftSourceLocation implements ISourceLocation { // XXX endLine? | |||
public static final File NONE = new File("SoftSourceLocation.NONE"); | |||
public static final String XMLNAME = "source-location"; | |||
/** | |||
* Write an ISourceLocation as XML element to an XMLWriter sink. | |||
* @param out the XMLWriter sink | |||
* @param sl the ISourceLocation to write. | |||
*/ | |||
public static void writeXml(XMLWriter out, ISourceLocation sl) { | |||
if ((null == out) || (null == sl)) { | |||
return; | |||
} | |||
final String elementName = XMLNAME; | |||
out.startElement(elementName, false); | |||
out.printAttribute("line", "" + sl.getLine()); | |||
out.printAttribute("column", "" + sl.getColumn()); | |||
out.printAttribute("endLine", "" + sl.getEndLine()); | |||
File file = sl.getSourceFile(); | |||
if (null != file) { | |||
out.printAttribute("sourceFile", file.getPath()); | |||
} | |||
out.endElement(elementName); | |||
} | |||
private File sourceFile; | |||
private int line; | |||
private int column; | |||
@@ -84,6 +107,4 @@ public class SoftSourceLocation implements ISourceLocation { // XXX endLine? | |||
public String toString() { | |||
return getSourceFile().getPath() + ":" + getLine() + ":" + getColumn(); | |||
} | |||
} |
@@ -37,8 +37,20 @@ public class XMLWriter { | |||
/** default value for maxWidth, when flowing buffer */ | |||
public static final int DEFAULT_WIDTH = 80; | |||
/** currently this just strips quotes and ampersands */ | |||
/** extremely inefficient! */ | |||
public static String attributeValue(String input) { | |||
// if (-1 != input.indexOf("&")) { | |||
// String saved = input; | |||
// input = LangUtil.replace(input, "&", "ampamp;"); | |||
// if (-1 == input.indexOf("&")) { | |||
// input = saved; | |||
// } else { | |||
// input = LangUtil.replace(input, "&", "&"); | |||
// input = LangUtil.replace(input, "ampamp;", "&"); | |||
// } | |||
// } else if (-1 != input.indexOf("&")) { | |||
// input = LangUtil.replace(input, "&", "&"); | |||
// } | |||
input = input.replace('"', '~'); | |||
input = input.replace('&', '='); | |||
return input; |