/************************************************************************* * * $RCSfile: MultiMethodTest.java,v $ * * $Revision: 1.2 $ * * last change: $Author: pjunck $ $Date: 2004-11-02 11:36:44 $ * * The Contents of this file are made available subject to the terms of * either of the following licenses * * - GNU Lesser General Public License Version 2.1 * - Sun Industry Standards Source License Version 1.1 * * Sun Microsystems Inc., October, 2000 * * GNU Lesser General Public License Version 2.1 * ============================================= * Copyright 2000 by Sun Microsystems, Inc. * 901 San Antonio Road, Palo Alto, CA 94303, USA * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * * * Sun Industry Standards Source License Version 1.1 * ================================================= * The contents of this file are subject to the Sun Industry Standards * Source License Version 1.1 (the "License"); You may not use this file * except in compliance with the License. You may obtain a copy of the * License at http://www.openoffice.org/license.html. * * Software provided under this License is provided on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. * See the License for the specific provisions governing your rights and * obligations concerning the Software. * * The Initial Developer of the Original Code is: Sun Microsystems, Inc. * * Copyright: 2000 by Sun Microsystems, Inc. * * All Rights Reserved. * * Contributor(s): _______________________________________ * * ************************************************************************/ package lib; import java.io.PrintWriter; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Hashtable; import java.util.StringTokenizer; import java.util.Vector; import com.sun.star.uno.UnoRuntime; import com.sun.star.uno.XInterface; import share.DescEntry; import lib.TestParameters; import stats.Summarizer; /** * The class supports method based interface tests development. * *

There are some points that should be fulfilled in a subclass to work * correctly in the multi-method framework: * * 1. each subclass schould define a public field named oObj of type tested * by the subclass, e.g. 'public XText oObj;'. That field will be initialized * by the MultiMethodTest code with the instance of the interface to test. * In a case of service testing the field type should be XPropertySet. * * 2. for the test of each method of the tested interface(or a property in the * case of service testing) should be method with the following signature * provided: 'public void _()', e.g. 'public void _getText()'. * The methods will be called by MultiMethodText code using reflection API * for each method in the interface description. * * 3. to set status for a call 'tRes.tested(String method, * boolean result)' should be used. For example 'tRes.tested("getText()", * true)'. Also 'tRes.assert(String assertion, boolean result)' call can * be used. Note, that one can call the methods not neccesarily from the * test for the tested method, but from other method tests too (in the * MultiMethodTest subclass). See also TestResult and MultiMethodTest.tRes * documentation. * * 4. the before() and after() methods can be overriden to perform some * actions, accordingly, before and after calling the test methods. * * 5. besides tRes, there are some fields initialized in the MultiMethodTest, * that can be used for implementing tests: * * - tEnv contains the environment tested * - tParam contains parameters of the test * - log a writer to log information about the test * * @see TestResult */ public class MultiMethodTest { /** * Contains the TestEnvironment being tested, to allow for tests to access * it. */ protected TestEnvironment tEnv; /** * Contains the TestParameters for the tests, to allow for tests to access * it. */ protected TestParameters tParam; /** * Contains the Description for the test * it. */ protected DescEntry entry; /** * Contains a writer to log an information about the interface testing, to * allows for tests to access it. */ protected PrintWriter log; /** * Contains the TestResult instance for the interface test to collect * information about methods test. */ protected TestResult tRes; /** * Contains names of the methods have been alreadycalled */ private Vector methCalled = new Vector(10); /** * Disposes the test environment, which was corrupted by the test. * * @param tEnv the environment to dispose */ public void disposeEnvironment( TestEnvironment tEnv ) { disposeEnvironment(); } /** * Disposes the current test environment, which was corrupted by the test. * * @see #disposeEnvironment(TestEnvironment) */ public void disposeEnvironment() { tEnv.dispose(); TestCase tCase = tEnv.getTestCase(); tCase.disposeTestEnvironment( tEnv, tParam ); } /** * Runs the interface test: its method tests. First, it initializes some * of MultiMethodTest fields, like tRes, log, tEnv, etc. Then, it queries * the tested interface and initializes 'oObj' field (defined in a * subclass). Before calling method tests, before() method calles to allow * initialization of s stuff before testing. Then, the method tests are * called. After them, after() method is called, to allow cleaning up the * stuff initialized in before() and test methods. * * @param tEnv the environment to test * @param ifcState the interface test state * @param tParam the parameters of the test * * @see #before * @see #after */ public TestResult run( DescEntry entry, TestEnvironment tEnv, TestParameters tParam ) { log = (PrintWriter) entry.Logger; this.tEnv = tEnv; this.tParam = tParam; this.log = log; this.entry = entry; this.tRes = new TestResult(); Class testedClass; String ifcName = getInterfaceName(); System.out.println("checking : "+ifcName); // defining a name of the class corresponding to the tested interface // or service String testedClassName; testedClassName = getTestedClassName(); if (entry.EntryType.equals("service")) { testedClassName = "com.sun.star.beans.XPropertySet"; } try { testedClass = Class.forName(testedClassName); } catch (ClassNotFoundException cnfE) { cnfE.printStackTrace(log); log.println("could not find a class : " + getTestedClassName()); return null; } // quering the tested interface from the tested object XInterface tCase = tEnv.getTestObject(); Object oObj = UnoRuntime.queryInterface( testedClass, tEnv.getTestObject()); if (oObj == null) { if (entry.isOptional) { Summarizer.summarizeDown( entry,"Not supported but optional.OK"); } else { Summarizer.summarizeDown( entry,"queryInterface returned null.FAILED"); entry.ErrorMsg="queryInterface returned null"; entry.hasErrorMsg=true; } return null; } //setting the field oObj setField("oObj",oObj); // to perform some stuff before all method tests try { before(); } catch (Exception e){ setSubStates(e.toString()); return tRes; } // executing methods tests for (int i=0;i-1) { append = "drafts.com.sun.star."; } return append + clsName.substring(firstDot + 1, lastDot + 1) + clsName.substring(lastDot + 2); } /** * Sets a method status. * * @param methName the method name to set status * @param methStatus the status to set to the method */ protected void setStatus( String methName, Status methStatus ) { tRes.tested( methName, methStatus ); } /** * sets the substates */ protected void setSubStates(String msg) { for (int k=0;kmethod is optional in the service. */ protected boolean isOptional(String method) { for (int k=0;kmethod test has been already called. */ protected boolean isCalled( String method ) { return methCalled.contains( method ); } /** * Calling of the method indicates that the method test should * be called. The method checks this and if it is not called, calls it. * If the method is failed or skipped, it throws StatusException. */ protected void requiredMethod(String method) { log.println("starting required method: " + method); executeMethod( method ); Status mtStatus = tRes.getStatusFor( method ); if ( mtStatus != null && (!mtStatus.isPassed() || mtStatus.isFailed()) ) { log.println( "! Required method " + method + " failed" ); throw new StatusException( mtStatus ); } } /** * Checks if the method was called, and if not, call it. * On contrary to requiredMethod(), he method doesn't check its status. */ protected void executeMethod( String method ) { if ( ! isCalled( method ) ) { log.println("Execute: "+ method); callMethod( method ); log.println(method + ": " + tRes.getStatusFor(method)); } } /** * Just calls the method test. */ protected void callMethod(String method) { methCalled.add(method); invokeTestMethod(getMethodFor(method), method); } /** * Invokes a test method of the subclass using reflection API. Handles * the method results and sets its status. * * @param meth the subclass' method to invoke * @param methName the name of the method */ protected void invokeTestMethod(Method meth, String methName) { if (meth == null) { setStatus( methName, Status.skipped( false ) ); } else { Status stat; try { meth.invoke(this, new Object[0]); return; } catch (InvocationTargetException itE) { Throwable t = itE.getTargetException(); if ( t instanceof StatusException ) { stat = ((StatusException)t).getStatus(); } else { t.printStackTrace(log); stat = Status.exception(t); } } catch (IllegalAccessException iaE) { iaE.printStackTrace(log); stat = Status.exception(iaE); } catch (IllegalArgumentException iaE) { iaE.printStackTrace(log); stat = Status.exception(iaE); } catch (ClassCastException ccE) { ccE.printStackTrace(log); stat = Status.exception(ccE); } setStatus(methName, stat); } } /** * Finds a testing method for the method of the interface. * * @return the testing method, if found, null otherwise */ protected Method getMethodFor(String method) { String mName = "_" + method; if (mName.endsWith("()")) { mName = mName.substring(0, mName.length() - 2); } final Class[] paramTypes = new Class[0]; try { return this.getClass().getDeclaredMethod(mName, paramTypes); } catch (NoSuchMethodException nsmE) { return null; } } /** * @return the name of the interface tested */ public String getInterfaceName() { String clName = this.getClass().getName(); return clName.substring( clName.lastIndexOf('.') + 1 ); } /** * Initializes fieldName of the subclass with * value. * * @return Status describing the result of the operation. */ protected Status setField( String fieldName, Object value) { Field objField; try { objField = this.getClass().getField( fieldName ); } catch( NoSuchFieldException nsfE ){ return Status.exception( nsfE ); } try { objField.set( this, value ); return Status.passed(true); } catch( IllegalArgumentException iaE ){ return Status.exception( iaE ); } catch( IllegalAccessException iaE ){ return Status.exception( iaE ); } } }