You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@ant.apache.org by rigel <ze...@gmail.com> on 2008/02/10 00:51:59 UTC

How to retrieve any params from build.xml internally to the ant source code environment?

Hello Everyone,

I'd like to print out additional test cases descriptive info into any final
Junit report, for this I started patching "XMLJUnitResultFormatter" to
accept a custom annotation associated to tested method

So now to parameterize well the annotation introspection, I need some
information on  how retrieving build.xml params values strictly following
and according to ant-junit library design, but unfortunately I don't know
where to start to find a clear example of. Basically I need something to get
current params of the running target.


In "XMLJUnitResultFormatter" I implemented the generation of a nested child
tag set into  tag of the JUnit xml raw data report. But these tags are
brutally wired by an "user space" annotation class. The following shows
wired tag into testcase tag:




  
    
    
    
      
    
    
  

[...]




This tag set is added only if testcase contains a specific annotation which
contains the following attributes:


	public String title() default "Default test title";

	public String desc() default "Default test description";

	public String[] input() default {};



Now I would like to pass both name and attributes of the annotation directly
from the JUnit target or a nested one, but I don't know how to do it.

A more readable code sample usage of all classes that I implemented are
available 
http://www.nabble.com/Regarding-%22Annotated-descriptions%22-of-new-improvements-in-version-4.4-td15348555.html
here  and presents a wired solution.



However here I put (my painful written code, sorry for my awful style %-| )
what I modified to accomplish this. All text formatting follows my
unconventional style, and I hope it will be readable even if Nabble  try to
explode in one line:wistle: ):

Here I attached my actual code with all modified/patched Ant sources:

http://www.nabble.com/file/p15391637/XMLConstants.java XMLConstants.java 

http://www.nabble.com/file/p15391637/XMLJUnitResultFormatter.java
XMLJUnitResultFormatter.java 

http://www.nabble.com/file/p15391637/JUnitVersionHelper.java
JUnitVersionHelper.java 

http://www.nabble.com/file/p15391637/junit-frames.xsl A customized
stylesheet used by ANT JUnit to produce the final testcase report
("testcase.test.header" & "testcase" template lightly modified with appended
additions) 

http://www.nabble.com/file/p15391637/TestInfo.java Custom descriptive
annotation 

http://www.nabble.com/file/p15391637/EnumTestType.java An optional Enum used
by custom annotation just to complicat more :p :-D 

http://www.nabble.com/file/p15391637/SampleTest.java Testcase sample using
custom annotation 

http://www.nabble.com/file/t906682/6_TestBigRationalFraction.html JUnit
descriptive report sample 




// ===org.apache.tools.ant.taskdefs.optional.junit.XMLConstants===
//
// Some consts referring to additional tag set
//
+++
[...]


    /**
     * info element for testcase element
     * @author rigel alias zetatau 
     * TODO:
     */
    String TESTINFO = "info";
    
    /**
     * title element for info element
     * @author rigel alias zetatau 
     * TODO:
     */
    String TESTINFO_TITLE = "title";

    /**
     * desc element for info element
     * @author rigel alias zetatau 
     * TODO:
     */
    String TESTINFO_DESC = "desc";
    
    /**
     * input element for testcase element
     * @author rigel alias zetatau 
     * TODO:
     */
    String TESTINPUT = "input";

    /**
     * item element for input element
     * @author rigel alias zetatau 
     * TODO:
     */
    String TESTINPUT_ITEM = "input-item";
    
    /**
     * id attribute for testcase item
     * @author rigel alias zetatau 
     * TODO:
     */
    String ATTR_TESTINPUT_ITEM_ID = "id";
    
    /**
     * type attribute for testcase item
     * @author rigel alias zetatau 
     * TODO:
     */
    String ATTR_TESTINPUT_ITEM_TYPE = "type";



[...]
+++



// ===org.apache.tools.ant.taskdefs.optional.junit.JUnitVersionHelper===
//
// Reflection routines used to get testcase annotation info (mantaining
JDK1.2 compiler compliance only, not granted correct execution@runtime)
//
+++
[...]


    /** constant for unnnamed testsuites/cases */
    private static final String UNKNOWN = "unknown";
    private static final String JUNIT_TESTFACADE =
"junit.framework.JUnit4TestCaseFacade";
    final static int DATA=0,TYPE=1;
    
	public static String getTestCaseStringAtt(Test test, String
annotationMatch, String annotationParameter) {
        if (test != null) {
        	if (test.getClass().getName().equals(JUNIT_TESTFACADE)) {
        		String sOut =
String.valueOf(helperMethodInvoke(test,annotationMatch,annotationParameter,UNKNOWN)[DATA][0]);
        		if (!sOut.equals(UNKNOWN))
        			return sOut;
        	} else
    			return "";
        }
		return UNKNOWN;
	}
	
	public static Object[][] getTestCaseStringArrayAtt(Test test, String
annotationMatch, String annotationParameter) {
        if (test != null) {
        	if (test.getClass().getName().equals(JUNIT_TESTFACADE)) {
        		Object[][] rt =
helperMethodInvoke(test,annotationMatch,annotationParameter,UNKNOWN);
        		if (rt.length==0)
        			return new Object[0][0];
        		if (rt.length==0)
        			return new Object[][]{rt[DATA],{}};
        		rt = new Object[][]{rt[DATA],new Object[rt[DATA].length]};
        		for (int i=0; i

	private static Iterator helperDescriptorCollection(Test facade) {
		final String 
			junitDescription="org.junit.runner.Description",
			methodOnFacade="getDescription",
			methodOnItem="getAnnotations";
				
		ArrayList empty = new ArrayList();
		if (!facade.getClass().getName().equals(JUNIT_TESTFACADE))
			return empty.iterator();
		try {
			Class.forName(junitDescription,false,ClassLoader.getSystemClassLoader());
				// otherwise throw an exception
			Method m = facade.getClass().getMethod(methodOnFacade, new Class[0]);
			Object itemInstance = m.invoke(facade, new Object[0]);
			if
(itemInstance!=null&&junitDescription.equals(itemInstance.getClass().getName())){
				Method m1 = itemInstance.getClass().getMethod(methodOnItem, new
Class[0]);
				Object rtObj = m1.invoke(itemInstance, new Object[0]);
				if (rtObj instanceof Collection)
					return ((Collection)rtObj).iterator();
				return empty.iterator();
			} else return empty.iterator();
		} catch (ClassNotFoundException e) {
		} catch (SecurityException e) {
		} catch (IllegalArgumentException e) {
		} catch (NoSuchMethodException e) {
		} catch (IllegalAccessException e) {
		} catch (InvocationTargetException e) {
		}
		return empty.iterator();
	}
	
	private static Object helperAnnotation(Test façade, String annotationMatch)
{
		final String methodOnAnnotation="annotationType";
		Object item=null;
		Iterator it = helperDescriptorCollection(façade);
		while (it.hasNext()) {
			Object a = (Object)it.next();
			String match = "";
			try {
				Method m = a.getClass().getMethod(methodOnAnnotation, new Class[0]);
				Class out = (Class)m.invoke(a, new Object[0]);
				match=String.valueOf(out.getName());
			} catch (SecurityException e) {
			} catch (NoSuchMethodException e) {
			} catch (IllegalArgumentException e) {
			} catch (IllegalAccessException e) {
			} catch (InvocationTargetException e) {
			}
			if (annotationMatch.equals(match)) {
				item=a;
				break;
			}
		}
		return item;
	}
	
	private static Object[][] helperMethodInvoke(Test instance, String
annotationMatch, String methodName, String defaultValue) {
		try {
/*
 * ANNOTATIONS WORKS DOES NOT WORK UNDER JDK 1.5
			Iterator it = 
(junit.framework.JUnit4TestCaseFacade)instance).getDescription().getAnnotations().iterator();
			java.lang.annotation.Annotation item=null;
    		while (it.hasNext()) {
    			java.lang.annotation.Annotation a =
(java.lang.annotation.Annotation)it.next();
    			if (annotationMatch.equals(a.annotationType().getName())) {
    				item=a;
    				break;
    			}
    		}*/
			Object item = helperAnnotation(instance, annotationMatch);
    			/* No appropriate annotation was found so returns defaultValue */
			if (item==null)
				return new Object[][]{new String[]{defaultValue},{}};
    		
			Method m = item.getClass().getMethod(methodName, new Class[0]);
			Object oOut = m.invoke(item, new Object[0]);
			if (oOut instanceof String) {
				String sOut = String.valueOf(oOut);
				if ("".equals(sOut)||sOut==null)
					return new Object[][]{new String[]{defaultValue},{}};
				else
					return new Object[][]{new String[]{sOut},{}};
			} else if (oOut instanceof String[]) {
				return new Object[][]{(String[])oOut,{}};
			} else if (oOut instanceof Enum) {
				return new Object[][]{new String[]{String.valueOf(oOut)},{}};
			} else {
				return new Object[][]{new String[]{defaultValue},{}};
			}
		} catch (SecurityException e) {
		} catch (IllegalArgumentException e) {
		} catch (NoSuchMethodException e) {
		} catch (IllegalAccessException e) {
		} catch (InvocationTargetException e) {
		}
		return new Object[][]{new String[]{defaultValue}};
	}

	
	public static String predictDataType(Object obj) {
		String sPlain = String.valueOf(obj);
		String sPlainType = obj.getClass().getName();
		Number nTest=null;
		try {
			nTest = new BigDecimal(sPlain);
			if (nTest.toString().equals(sPlain))
				sPlainType=nTest.getClass().getName();
		} catch (NumberFormatException e) {}
		try {
			nTest = new BigInteger(sPlain);
			if (nTest.toString().equals(sPlain))
				sPlainType=nTest.getClass().getName();
		} catch (NumberFormatException e) {}
		try {
			nTest = new Double(sPlain);
			if (nTest.toString().equals(sPlain))
				sPlainType=nTest.getClass().getName();
		} catch (NumberFormatException e) {}
		try {
			nTest = new Long(sPlain);
			if (nTest.toString().equals(sPlain))
				sPlainType=nTest.getClass().getName();
		} catch (NumberFormatException e) {}
		try {
			nTest = new Float(sPlain);
			if (nTest.toString().equals(sPlain))
				sPlainType=nTest.getClass().getName();
		} catch (NumberFormatException e) {}
		try {
			nTest = new Integer(sPlain);
			if (nTest.toString().equals(sPlain))
				sPlainType=nTest.getClass().getName();
		} catch (NumberFormatException e) {}
		try {
			nTest = new Byte(sPlain);
			if (nTest.toString().equals(sPlain))
				sPlainType=nTest.getClass().getName();
		} catch (NumberFormatException e) {}
		try {
			nTest = new Short(sPlain);
			if (nTest.toString().equals(sPlain))
				sPlainType=nTest.getClass().getName();
		} catch (NumberFormatException e) {}
		
		return sPlainType;
	}


[...]
+++



//
===org.apache.tools.ant.taskdefs.optional.junit.XMLJUnitResultFormatter===
// 
// Additional tag set inserted into testcase and composed by information
retrieved by custom annotation
//
+++
public void endTest(Test test) {
[...]


/* 
 * This adds additional info to the generated XML test case data,
unfortunately I don't
 * know what ant helper class can give me some params from XML build
 */

String sType =
JUnitVersionHelper.getTestCaseStringAtt(test,"test.TestInfo",ATTR_TESTTYPE);
if (!UNKNOWN.equals(sType)) {
	 currentTest.setAttribute(ATTR_TESTTYPE,sType);
}
String sTypeId =
JUnitVersionHelper.getTestCaseStringAtt(test,"test.TestInfo",ATTR_TESTTYPEID);
if (!UNKNOWN.equals(sTypeId)) {
	 currentTest.setAttribute(ATTR_TESTTYPEID,sTypeId);
}        


Element currentTestInfo = doc.createElement(TESTINFO);

String sTitle =
JUnitVersionHelper.getTestCaseStringAtt(test,"test.TestInfo",TESTINFO_TITLE);
if (!UNKNOWN.equals(sTitle)) {
    CDATASection titleNode = doc.createCDATASection(sTitle);
    Element currentTestInfoTitle = doc.createElement(TESTINFO_TITLE);
    currentTestInfoTitle.appendChild(titleNode);
    currentTestInfo.appendChild(currentTestInfoTitle);
}
String sDesc =
JUnitVersionHelper.getTestCaseStringAtt(test,"test.TestInfo",TESTINFO_DESC);
if (!UNKNOWN.equals(sDesc)) {
    CDATASection descNode = doc.createCDATASection(sDesc);
    Element currentTestInfoDesc = doc.createElement(TESTINFO_DESC);
    currentTestInfoDesc.appendChild(descNode);
    currentTestInfo.appendChild(currentTestInfoDesc);
}		

final int DATA=0, TYPE=1;
Object[][] aInput =
JUnitVersionHelper.getTestCaseStringArrayAtt(test,"test.TestInfo",TESTINPUT);
if (aInput.length>0) {
	Element currentTestInput = doc.createElement(TESTINPUT);
	if (aInput[DATA].length>=1) {
		if (!String.valueOf(aInput[DATA][0]).equals(UNKNOWN)) {
			for (int i=0; i

				Element currentTestInputItem = doc.createElement(TESTINPUT_ITEM);
			
currentTestInputItem.setAttribute(ATTR_TESTINPUT_ITEM_ID,String.valueOf(i));
				if (aInput[TYPE].length>0)
				
currentTestInputItem.setAttribute(ATTR_TESTINPUT_ITEM_TYPE,String.valueOf(aInput[TYPE][i]));
				else
				
currentTestInputItem.setAttribute(ATTR_TESTINPUT_ITEM_TYPE,String.class.getName());
				CDATASection inputNode =
doc.createCDATASection(String.valueOf(aInput[DATA][i]));
				currentTestInputItem.appendChild(inputNode);
				currentTestInput.appendChild(currentTestInputItem);
			}					
		}
	}
	currentTestInfo.appendChild(currentTestInput);
}
currentTest.appendChild(currentTestInfo);


[...]
}
+++



Thank You 
-- 
View this message in context: http://www.nabble.com/How-to-retrieve-any-params-from-build.xml-internally-to-the-ant-source-code-environment--tp15391637p15391637.html
Sent from the Ant - Dev mailing list archive at Nabble.com.