blob: 39259a8c9733509ae130d572c8d719b788bc8261 [file] [log] [blame]
/*
* The Apache Software License, Version 1.1
*
*
* Copyright (c) 2003 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Apache" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache
* XMLBeans", nor may "Apache" appear in their name, without prior
* written permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation and was
* originally based on software copyright (c) 2003 BEA Systems
* Inc., <http://www.bea.com/>. For more information on the Apache Software
* Foundation, please see <http://www.apache.org/>.
*/
package org.apache.xmlbeans.test.jam;
import junit.framework.TestCase;
import org.apache.xmlbeans.impl.jam.*;
import org.apache.xmlbeans.impl.jam.internal.elements.ClassImpl;
import org.apache.xmlbeans.impl.jam.xml.JamXmlUtils;
import org.w3c.dom.Document;
import javax.xml.stream.XMLStreamException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.FileReader;
import java.io.StringReader;
import java.io.InputStream;
import java.io.Writer;
import java.io.FileInputStream;
import java.util.*;
import com.sun.org.apache.xml.internal.serialize.XMLSerializer;
import com.sun.org.apache.xml.internal.serialize.OutputFormat;
import org.apache.xmlbeans.test.jam.dummyclasses.jsr175.RFEAnnotation;
import org.apache.xmlbeans.test.jam.dummyclasses.jsr175.EmployeeAnnotation;
import org.apache.xmlbeans.test.jam.dummyclasses.jsr175.EmployeeGroupAnnotation;
import org.apache.xmlbeans.test.jam.dummyclasses.jsr175.AddressAnnotation;
/**
* <p>Abstract base class for basic jam test cases. These test cases work
* against an abstract JamService - they don't care how the java types
* were loaded. Extending classes are responsible for implementing the
* getService() method which should create the service from sources, or
* classes, or whatever is appropriate.</p>
*
* @author Patrick Calahan &lt;email: pcal-at-bea-dot-com&gt;
*/
public abstract class JamTestBase extends TestCase {
// ========================================================================
// Constants
private static final boolean CONTINUE_ON_COMPARE_FAIL = false;
private static final boolean WRITE_RESULT_ON_FAIL = false;
private static final String WRITE_RESULT_PREFIX = "result-";
protected static final String
DUMMY = "org.apache.xmlbeans.test.jam.dummyclasses";
protected static final String DUMMY_EJB = DUMMY+".ejb";
//this array must contain the names of all of the test classes under
//dummyclasses
private static final String[] ALL_CLASSES = {
"DefaultPackageClass",
"org.TopLevelPackageClass",
DUMMY+".ejb.IEnv",
DUMMY+".ejb.MyEjbException",
DUMMY+".ejb.TraderEJB",
DUMMY+".ejb.TradeResult",
DUMMY+".jsr175.AnnotatedClass",
DUMMY+".jsr175.NestedAnnotatedClass",
DUMMY+".jsr175.AddressAnnotation",
DUMMY+".jsr175.EmployeeAnnotation",
DUMMY+".jsr175.Constants",
DUMMY+".jsr175.RFEAnnotation",
DUMMY+".jsr175.RFEAnnotationImpl",
DUMMY+".Base",
DUMMY+".Baz",
DUMMY+".Foo",
DUMMY+".FooImpl",
DUMMY+".HeavilyCommented",
DUMMY+".ImportsGalore",
DUMMY+".MyException",
DUMMY+".MultilineTags",
DUMMY+".ManyTags",
DUMMY+".ValuesById"
};
// this needs to correspond to the methods on the FooImpl dummyclass
private static final String[][] FOOIMPL_METHODS = {
{"public", "int", "getId", null, null},
{"public", "void", "setId", "int id",null},
{"private final static", "void", "setId2", "double id",null},
{"protected synchronized ", "void", "setId3", "double id, double id2",null},
{"protected abstract", "void", "setId4", "double id, double id2, double id3",null},
{"", "java.lang.String[][]", "methodDealingWithArrays", "int[] foo, java.lang.Object[] bar",null},
{"protected abstract", "void", "iThrowExceptions", "int p1, java.lang.String p2",
"java.lang.IllegalArgumentException," +
"java.lang.NoSuchMethodError," +
DUMMY+".MyException,"+
DUMMY+".ejb.MyEjbException,"+
"java.net.MalformedURLException,"+
"java.lang.OutOfMemoryError,"+
"java.lang.NullPointerException"
}
};
// this needs to correspond to the methods on the FooImpl dummyclass
private static final String[] HEAVILY_COMMENTS = {
"A simple comment.",
"A comment which\n spans\n\n several\n\n\n lines."
};
/**
* A comment which
* spans
*
* several
*
*
* lines.
*/
private static final boolean VERBOSE = false;
// ========================================================================
// Variables
private JamService mResult = null;
private JamClassLoader mLoader = null;
// ========================================================================
// Constructors
public JamTestBase() {
super("JamTestBase");
System.out.println("constructed JamTestBase");
}
public JamTestBase(String casename) {
super(casename);
System.out.println("constructed JamTestBase "+casename);
}
// ========================================================================
// Abstract methods
/**
* Called during setup() to get the JamService object to test against.
*/
protected abstract JamService getResultToTest() throws Exception;
//kind of a quick hack for now, should remove this and make sure that
//even the classes case make the annotations available using a special
//JStore
protected abstract boolean isAnnotationsAvailable();
//kind of a quick hack for now, should remove this and make sure that
//even the classes case make the annotations available using a special
//JStore
protected abstract boolean is175AnnotationInstanceAvailable();
//kind of a quick hack for now, should remove this and make sure that
//even the classes case make the annotations available using a special
//JStore
protected abstract boolean isParameterNamesKnown();
protected abstract boolean isCommentsAvailable();
protected abstract boolean isImportsAvailable();
protected abstract File getMasterDir();
// ========================================================================
// Utility methods
/**
* Returns the directory in which the sources for the dummyclasses live.
*/
protected File[] getDummyclassesSourcepath() {
return new File[] {new File("dummyclasses")};
}
/**
* Returns the directory into which the dummyclasses have been compiled.
*/
protected File[] getDummyclassesClassPath() {
return new File[] {new File("../../build/jam/test/dummyclasses")};
}
// ========================================================================
// TestCase implementation
public void setUp() throws Exception {
mResult = getResultToTest();
mLoader = mResult.getClassLoader();
}
// ========================================================================
// Test methods
public void testAllClassesAvailable() {
if (true) return; //FIXME skipping this until we get inner classes
// (Constants.Bool) sorted out between reflect and javadoc
JClass[] classes = mResult.getAllClasses();
List classNames = new ArrayList(classes.length);
for(int i=0; i<classes.length; i++) {
resolved(classes[i]);
classNames.add(classes[i].getQualifiedName());
//System.out.println("-- "+classes[i].getQualifiedName());
}
List expected = Arrays.asList(ALL_CLASSES);
assertTrue("result does not contain all expected classes",
classNames.containsAll(expected));
assertTrue("result contains more than expected classes",
expected.containsAll(classNames));
}
public void testAnnotationUrlValues() {
if (!isAnnotationsAvailable()) return;
JClass clazz = resolved(mLoader.loadClass(DUMMY+".ValuesById"));
{
final String ANN = "xsdgen:type@target_namespace";
final String VAL = "http://www.yahoo.com";
JAnnotationValue tns = clazz.getAnnotationValue(ANN);
assertTrue("no "+ANN, tns != null);
assertTrue(ANN+" does not equal "+VAL+", instead is '"+tns.asString(),
tns.asString().equals(VAL));
}
{
final String ANN = "xsdgen:type@quoted_tns";
final String VAL = "http://homestarrunner.com/sbemail58.html";
JAnnotationValue tns = clazz.getAnnotationValue(ANN);
assertTrue("no "+ANN, tns != null);
assertTrue(ANN+" does not equal "+VAL+", instead is '"+tns.asString(),
tns.asString().equals(VAL));
}
{
final String ANN = "someurl";
final String VAL = "http://www.apache.org/foo";
JAnnotationValue tns = clazz.getAnnotationValue(ANN);
assertTrue("no "+ANN, tns != null);
assertTrue(ANN+" does not equal "+VAL+", instead is '"+tns.asString(),
tns.asString().equals(VAL));
}
}
public void testAnnotationValuesById() {
if (!isAnnotationsAvailable()) return;
JClass clazz = resolved(mLoader.loadClass(DUMMY+".ValuesById"));
assertTrue("value id foo has unexpected single-member value",
clazz.getAnnotationValue("foo") == null);
{
final String ANN = "bar@x";
final String VAL = "hello";
JAnnotationValue barx = clazz.getAnnotationValue(ANN);
assertTrue("no "+ANN, barx != null);
assertTrue(ANN+" does not equal "+VAL+", instead is '"+barx.asString(),
barx.asString().equals(VAL));
}
{
final String ANN = "bar@y";
final String VAL = "goodbye";
JAnnotationValue bary = clazz.getAnnotationValue(ANN);
assertTrue("no "+ANN, bary != null);
assertTrue(ANN+" does not equal "+VAL+", instead is '"+bary.asString(),
bary.asString().equals(VAL));
}
{
final String ANN = "baz";
final String VAL = "I have no pairs.";
JAnnotationValue val = clazz.getAnnotationValue(ANN);
assertTrue("no "+ANN, val != null);
assertTrue(ANN+" does not equal "+VAL+", instead is '"+val.asString(),
val.asString().equals(VAL));
}
{
JAnnotationValue widget = clazz.getAnnotationValue("bar@widegetgen:name");
assertTrue("no bar@widegentgen:name", widget != null);
assertTrue("bar@widegetgen:name does not equal aloha",widget.asString().equals("aloha"));
}
assertTrue(clazz.getAnnotationValue("nothinghere") == null);
}
public void testXmlWriter() throws XMLStreamException, IOException
{
final String MASTER = "testXmlWriter.xml";
JClass[] classes = mResult.getAllClasses();
StringWriter xml = new StringWriter();
JamXmlUtils.getInstance().toXml(classes,xml);
//
compare(xml.toString(), MASTER);
}
public void testXmlRoundtrip() throws XMLStreamException, IOException
{
final String MASTER = "testXmlRoundtrip.xml";
final String SOURCE = "testXmlWriter.xml";
JamXmlUtils jxu = JamXmlUtils.getInstance();
//JClass[] classes = mResult.getAllClasses();
File source = new File(getMasterDir(),SOURCE);
JClass[] classes = jxu.createService(new FileInputStream(source)).
getAllClasses();
StringWriter xml = new StringWriter();
JamXmlUtils.getInstance().toXml(classes,xml);
compare(xml.toString(), MASTER);
}
public void testPackageNames()
{
JClass clazz = resolved(mLoader.loadClass(DUMMY_EJB+".TraderEJB"));
JPackage pkg = clazz.getContainingPackage();
assertTrue("Expected '"+DUMMY_EJB+"', got '"+pkg.getQualifiedName()+"'",
pkg.getQualifiedName().equals(DUMMY_EJB));
//
clazz = resolved(mLoader.loadClass("DefaultPackageClass"));
pkg = clazz.getContainingPackage();
assertTrue("Expected '', got '"+pkg.getQualifiedName()+"'",
pkg.getQualifiedName().equals(""));
//
clazz = resolved(mLoader.loadClass("org.TopLevelPackageClass"));
pkg = clazz.getContainingPackage();
assertTrue("Expected 'org', got '"+pkg.getQualifiedName()+"'",
pkg.getQualifiedName().equals("org"));
}
public void test175Annotations() throws IOException, XMLStreamException {
JClass clazz = resolved(mLoader.loadClass(DUMMY+".jsr175.AnnotatedClass"));
JAnnotation ann = clazz.getAnnotation(RFEAnnotation.class);
assertTrue("no "+RFEAnnotation.class+ " on "+clazz.getQualifiedName(),
ann != null);
if (!is175AnnotationInstanceAvailable()) return; //FIXME test untyped access
RFEAnnotation rfe = (RFEAnnotation)ann.getAnnotationInstance();
assertTrue("id = "+rfe.id(), rfe.id() == 4561414);
assertTrue("synopsis = '"+rfe.synopsis()+"'",
rfe.synopsis().equals("Balance the federal budget"));
}
public void testNested175AnnotationsUntyped() throws IOException, XMLStreamException {
JClass clazz = resolved(mLoader.loadClass(DUMMY+".jsr175.NestedAnnotatedClass"));
JAnnotation employeeGroup = clazz.getAnnotation(EmployeeGroupAnnotation.class);
assertTrue("employeeGroup is null", employeeGroup != null);
JAnnotationValue employeeListValue = employeeGroup.getValue("employees");
JClass listType = employeeListValue.getType();
assertTrue("listType is null", listType != null);
assertTrue("listType is "+listType.getFieldDescriptor()+", expecting"+
EmployeeAnnotation[].class.getName(),
EmployeeAnnotation[].class.getName().equals(listType.getFieldDescriptor()));
assertTrue("employees list is null", employeeListValue != null);
JAnnotation[] employeeList = employeeListValue.asAnnotationArray();
assertTrue("employees list is null", employeeList != null);
assertTrue("employees list length is "+employeeList.length+", expecting 2",
employeeList.length == 2);
JAnnotation boog = employeeList[0];
assertTrue("boog annotation is null",boog != null);
//FIXME shouldnt be isCommentsAvailable
if (isCommentsAvailable()) assertTrue(boog.getSourcePosition() != null);
{
JAnnotationValue firstName = boog.getValue("firstName");
assertTrue("firstName is null",firstName != null);
assertTrue("firstName is "+firstName.asString(),
firstName.asString().equals("Boog"));
JClass type = firstName.getType();
assertTrue("firstName type is null",type != null);
assertTrue("firstName type is "+type.getQualifiedName(),
"java.lang.String".equals(type.getQualifiedName()));
}
{
JAnnotationValue aka = boog.getValue("aka");
assertTrue("aka is null",aka != null);
JClass type = aka.getType();
assertTrue("aka type is null",type != null);
assertTrue("aka type is "+type.getFieldDescriptor(),
String[].class.getName().equals(type.getFieldDescriptor()));
String[] akas = aka.asStringArray();
assertTrue("akas is null",akas != null);
assertTrue("akas length is "+akas.length, akas.length == 3);
for(int i=0; i<akas.length; i++) {
assertTrue("akas "+i+" is empty '"+akas[i]+"'",
(akas[i] != null && akas[i].trim().length() > 0));
}
}
{
JAnnotationValue active = boog.getValue("active");
assertTrue("active is null",active != null);
assertTrue("active = "+active.asString(),
active.asString().equals("TRUE"));
JClass type = active.getType();
assertTrue("active type is null",type != null);
//FIXME another place where we need to get our story straight with
//inner classes. need to always separate inner and outer with a '$' -
//javadoc doesn't like to do this
//assertTrue("active type is "+type.getQualifiedName(),
// type.getQualifiedName().equals
// ("org.apache.xmlbeans.test.jam.dummyclasses.jsr175.Constants$Bool"));
//FIXME javadoc seems to have a bug in it, not telling is it's an enum
//assertTrue("active type is not an enum", ((ClassImpl)type).isEnumType());
}
{
JAnnotationValue lastName = boog.getValue("lastName");
assertTrue("lastName is null",lastName != null);
assertTrue("lastName is "+lastName.asString(),
lastName.asString().equals("Powell"));
JClass lastNameType = lastName.getType();
assertTrue("street type is null",lastNameType != null);
assertTrue("lastNameType "+lastNameType.getQualifiedName(),
"java.lang.String".equals(lastNameType.getQualifiedName()));
}
{
JAnnotationValue specialDigits = boog.getValue("specialDigits");
assertTrue("specialDigits is null",specialDigits != null);
int[] expect = { 8, 6, 7, 5, 3, 0, 9 };
assertTrue("specialDigits does not contain expected digits",
Arrays.equals(expect,specialDigits.asIntArray()));
JClass specialDigitsType = specialDigits.getType();
assertTrue("specialDigits type is null",specialDigitsType != null);
assertTrue("specialDigits type is "+specialDigitsType.getFieldDescriptor()+
", expecting "+int[].class.getName(),
specialDigitsType.getFieldDescriptor().equals(int[].class.getName()));
}
{
JAnnotationValue addressValue = boog.getValue("address");
assertTrue("address is null",addressValue != null);
JAnnotation address = addressValue.asAnnotation();
assertTrue("address is null",address != null);
//FIXME shouldnt be isCommentsAvailable
if (isCommentsAvailable()) assertTrue(boog.getSourcePosition() != null);
{
JAnnotationValue street = address.getValue("street");
assertTrue("street is null",street != null);
assertTrue("street is "+street.asString(),
street.asString().equals("123 shady lane"));
JClass streetType = street.getType();
assertTrue("street type is null",streetType != null);
assertTrue("streetType "+streetType.getQualifiedName(),
streetType.getQualifiedName().equals("java.lang.String"));
}
{
JAnnotationValue city = address.getValue("city");
assertTrue("city is null",city != null);
assertTrue("city is "+city.asString(),
city.asString().equals("Cooperstown"));
JClass cityType = city.getType();
assertTrue("street type is null",cityType != null);
assertTrue("cityType "+cityType.getQualifiedName(),
cityType.getQualifiedName().equals("java.lang.String"));
}
{
JAnnotationValue zip = address.getValue("zip");
assertTrue("zip is null",zip != null);
assertTrue("zip is "+zip.asInt(),
zip.asInt() == 123456);
JClass zipType = zip.getType();
assertTrue("street type is null",zipType != null);
assertTrue("zipType "+zipType.getQualifiedName(),
zipType.getQualifiedName().equals("int"));
assertTrue("zipType not primitive", zipType.isPrimitiveType());
}
}
}
public void testRecursiveResolve() {
resolveCheckRecursively(mResult.getAllClasses(),new HashSet());
}
/**
* Test comment parsing on the HeavilyCommented dummy class.
*/
public void testComments() {
if (!isCommentsAvailable()) return;
JClass hcImpl = mLoader.loadClass(DUMMY+".HeavilyCommented");
JMethod[] methods = hcImpl.getDeclaredMethods();
for(int i=0; i<methods.length; i++) {
JComment comment = methods[i].getComment();
assertTrue("'"+comment.getText()+"'\ndoes not match expected\n'" +
HEAVILY_COMMENTS[i]+"'",
HEAVILY_COMMENTS[i].equals(comment.getText()));
}
}
/**
* Verify that FooImpl has the correct methods with the correct
* number of parameters and correct return types.
*/
public void testFooImplMethods() {
JClass fooImpl = resolved(mLoader.loadClass(DUMMY+".FooImpl"));
GoldenInvokable[] methods = GoldenInvokable.createArray(FOOIMPL_METHODS);
GoldenInvokable.doComparison(fooImpl.getDeclaredMethods(),
methods,isParameterNamesKnown(),this);
}
public void testImports()
{
if (!isImportsAvailable()) return;
JClass clazz = resolved(mLoader.loadClass(DUMMY+".ImportsGalore"));
JClass[] imports = clazz.getImportedClasses();
assertTrue("class has "+imports.length+" imports",
imports.length == 3);
}
public void testInterfaceIsAssignableFrom()
{
JClass fooImpl = resolved(mLoader.loadClass(DUMMY+".FooImpl"));
JClass foo = resolved(mLoader.loadClass(DUMMY+".Foo"));
assertTrue("Foo should be assignableFrom FooImpl",
foo.isAssignableFrom(fooImpl));
assertTrue("FooImpl should not be assignableFrom Foo",
!fooImpl.isAssignableFrom(foo));
}
public void testClassIsAssignableFrom()
{
JClass fooImpl = resolved(mLoader.loadClass(DUMMY+".FooImpl"));
JClass base = resolved(mLoader.loadClass(DUMMY+".Base"));
assertTrue("Base should be assignableFrom FooImpl",
base.isAssignableFrom(fooImpl));
assertTrue("FooImpl should not be assignableFrom Base",
!fooImpl.isAssignableFrom(base));
}
public void testClassIsAssignableFromDifferentClassLoaders()
{
JClass baz = resolved(mLoader.loadClass(DUMMY+".Baz"));
JClass runnable = resolved(mLoader.loadClass("java.lang.Runnable"));
assertTrue("Runnable should be assignableFrom Baz",
runnable.isAssignableFrom(baz));
assertTrue("Baz should not be assignableFrom Runnable",
!baz.isAssignableFrom(runnable));
}
public void testAnnotationPresent()
{
if (!isAnnotationsAvailable()) return;
String ANN = "ejbgen:remote-method";
JClass ejb = resolved(mLoader.loadClass(DUMMY+".ejb.TraderEJB"));
JMethod method = ejb.getMethods()[0];
assertTrue(method.getQualifiedName()+" does not have expected "+ANN+
" annotation",
method.getAnnotation(ANN) != null);
}
public void testAnnotationValue()
{
if (!isAnnotationsAvailable()) return;
JClass ejb = resolved(mLoader.loadClass(DUMMY+".ejb.TraderEJB"));
JMethod ejbBuy = ejb.getMethods()[0];
String CLASS_ANN = "ejbgen:remote-method@isolation-level";
String CLASS_ANN_VALUE = "Serializable";
verifyAnnotationValue(ejbBuy,CLASS_ANN,CLASS_ANN_VALUE);
}
public void testAnnotationsAndInheritance()
{
JClass ejb = resolved(mLoader.loadClass(DUMMY+".ejb.TraderEJB"));
JClass ienv = resolved(ejb.getInterfaces()[0]);
JMethod ejbBuy = ejb.getMethods()[0];
JMethod ienvBuy = ienv.getMethods()[0];
String INTER_ANN = "ejbgen:remote-method@transaction-attribute";
String INTER_ANN_VALUE = "NotSupported";
String CLASS_ANN = "ejbgen:remote-method@isolation-level";
String CLASS_ANN_VALUE = "Serializable";
verifyAnnotationAbsent(ejbBuy,INTER_ANN);
verifyAnnotationAbsent(ienvBuy,CLASS_ANN);
if (isAnnotationsAvailable()) {
verifyAnnotationValue(ienvBuy,INTER_ANN,INTER_ANN_VALUE);
verifyAnnotationValue(ejbBuy,CLASS_ANN,CLASS_ANN_VALUE);
} else {
verifyAnnotationAbsent(ienvBuy,INTER_ANN);
verifyAnnotationAbsent(ejbBuy,CLASS_ANN);
}
}
public void testMultilineTags() {
if (!isAnnotationsAvailable()) return;
JClass mt = resolved(mLoader.loadClass(DUMMY+".MultilineTags"));
JAnnotation ann = mt.getAllJavadocTags()[5];
compare(resolved(mt), "testMultilineTags.xml");
}
public void testMultipleTags() {
if (!isAnnotationsAvailable()) return;
JClass mt = resolved(mLoader.loadClass(DUMMY+".ManyTags"));
JMethod method = mt.getMethods()[0];
assertTrue(method.getAllJavadocTags().length == 6);
compare(mt,"testManyTags.xml");
}
// ========================================================================
// Private methods
private void compare(String result, String masterFileName) {
try {
File masterFile = new File(getMasterDir().getAbsolutePath(),masterFileName);
StringWriter diff = new StringWriter();
if (masterFile.exists()) {
FileReader inA = new FileReader(masterFile);
StringReader inB = new StringReader(result);
boolean same = Differ.getInstance().diff(inA,inB,diff);
if (same) return;
} else {
System.out.println("WARNING: Missing master file: "+masterFile);
}
if (WRITE_RESULT_ON_FAIL) {
File resultFile = new File(getMasterDir(),WRITE_RESULT_PREFIX+masterFileName);
FileWriter rout = new FileWriter(resultFile);
rout.write(result);
rout.close();
System.out.println("WARNING: Comparison failed, ignoring, wrote \n"+
resultFile);
}
if (CONTINUE_ON_COMPARE_FAIL) return;
fail("Result did not match master at "+masterFile+":\n"+
diff.toString());
} catch(IOException ioe) {
ioe.printStackTrace();
fail(ioe.getMessage());
}
}
private void compare(JClass clazz, String masterName) {
try {
String result = null;
{
StringWriter resultWriter = new StringWriter();
PrintWriter out = new PrintWriter(resultWriter,true);
JamXmlUtils.getInstance().toXml(new JClass[] {clazz}, out);
out.flush();
result = resultWriter.toString();
/*
try {
System.out.println("--------------- "+resultWriter.toString());
result = prettyPrint(resultWriter.toString());
} catch(Exception e) {
e.printStackTrace();
System.err.flush();
System.out.println("Problem with result:");
System.out.println(resultWriter.toString());
System.out.flush();
fail("failed to parse result");
return;
}
*/
}
compare(result,masterName);
} catch(XMLStreamException xse) {
xse.printStackTrace();
fail(xse.getMessage());
} catch(IOException ioe) {
ioe.printStackTrace();
fail(ioe.getMessage());
}
}
private String prettyPrint(String xml) throws Exception {
return xml;//FIXME
//FIXME StringBufferInputStream is bad
//return prettyPrint(new StringBufferInputStream(xml));
}
//all this work just because the 173 RI won't pretty print
private String prettyPrint(InputStream in) throws Exception {
StringWriter s = new StringWriter();
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(in);
OutputFormat format = new OutputFormat(doc);
//format.setIndenting(true);
//format.setIndent(2);
XMLSerializer serializer = new FixedXMLSerializer(s, format);
serializer.serialize(doc);
return s.toString();
}
private void resolveCheckRecursively(JClass[] clazzes, Set resolved) {
for(int i=0; i<clazzes.length; i++) {
resolveCheckRecursively(clazzes[i],resolved);
}
}
private void resolveCheckRecursively(JClass clazz, Set set) {
if (clazz == null || set.contains(clazz)) return;
assertTrue("'"+clazz.getQualifiedName()+"' is not resolved",
!clazz.isUnresolvedType());
if (VERBOSE) System.out.println("checking "+clazz.getQualifiedName());
set.add(clazz);
resolveCheckRecursively(clazz.getSuperclass(),set);
resolveCheckRecursively(clazz.getInterfaces(),set);
{
//check methods
JMethod[] methods = clazz.getDeclaredMethods();
for(int i=0; i<methods.length; i++) {
resolveCheckRecursively(methods[i].getReturnType(),set);
JParameter[] params = methods[i].getParameters();
for(int j=0; j<params.length; j++) {
resolveCheckRecursively(params[j].getType(),set);
}
}
}
{
//check constructors
JConstructor[] ctors = clazz.getConstructors();
for(int i=0; i<ctors.length; i++) {
JParameter[] params = ctors[i].getParameters();
for(int j=0; j<params.length; j++) {
resolveCheckRecursively(params[j].getType(),set);
}
}
}
{
//check fields
JField[] fields = clazz.getFields();
for(int i=0; i<fields.length; i++) {
resolveCheckRecursively(fields[i].getType(),set);
}
}
}
private JClass resolved(JClass c) {
assertTrue("class "+c.getQualifiedName()+" is not resolved",
!c.isUnresolvedType());
return c;
}
private void verifyAnnotationValue(JAnnotatedElement j, String valueId, String val) {
JAnnotationValue v = j.getAnnotationValue(valueId);
assertTrue(/*j.getParent().getQualifiedName()+" '"+*/
j.getQualifiedName()+"' is missing expected annotation value '"+valueId+"'",
v != null);
assertTrue(j.getQualifiedName()+" annotation '"+valueId+"' does not equal "+
val,val.equals(v.asString().trim()));
}
private void verifyAnnotationAbsent(JAnnotatedElement j, String ann) {
JAnnotation a = j.getAnnotation(ann);
assertTrue("'"+j.getQualifiedName()+"' expected to NOT have annotation '"+ann+"'",
a == null);
}
private void dump(JElement j, PrintWriter out) throws XMLStreamException {
}
//THIS IS A HACK to fix Sun's stupid bug for them
private class FixedXMLSerializer extends XMLSerializer {
public FixedXMLSerializer( Writer writer, OutputFormat format ) {
super(writer,format);
}
protected boolean getFeature(String feature){
if (fFeatures == null) return false;
Boolean b = (Boolean)fFeatures.get(feature);
if (b == null) return false;
return b.booleanValue();
}
}
}