/*
* This file is part of the LibreOffice project .
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License , v . 2 . 0 . If a copy of the MPL was not distributed with this
* file , You can obtain one at http : //mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice :
*
* Licensed to the Apache Software Foundation ( ASF ) under one or more
* contributor license agreements . See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership . The ASF licenses this file to you under the Apache
* License , Version 2 . 0 ( 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.apache.org/licenses/LICENSE-2.0 .
*/
package lib;
import java.io.PrintWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import share.DescEntry;
import stats.Summarizer;
import com.sun.star.uno.UnoRuntime;
/**
* The class supports method based interface tests development .
*
* < p > There are some points that should be fulfilled in a subclass to work
* correctly in the multi - method framework :
*
* 1 . each subclass should 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 _ < method name > ( ) ' , 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 necessarily 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 overridden 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
*/
@SuppressWarnings("unused" )
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 already called
*/
private final ArrayList<String> methCalled = new ArrayList<String>(10 );
/**
* 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 is called 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 entry the interface test state
* @ param tEnv the environment to test
* @ 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;
System.out.print("checking: [" + entry.longName + "]" );
// 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)
{
System.out.println();
cnfE.printStackTrace(log);
log.println("could not find a class : " + getTestedClassName());
return null ;
}
System.out.println(" is iface: [" + testedClassName + "] testcode: [" + entry.entryName + "]" );
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
try
{
setField("oObj" , oObj);
}
catch (Exception e)
{
e.printStackTrace();
setSubStates(e.toString());
return tRes;
}
// to perform some stuff before all method tests
try
{
before();
}
catch (Exception e)
{
e.printStackTrace();
setSubStates(e.toString());
return tRes;
}
// executing methods tests
for (int i = 0 ; i < entry.SubEntryCount; i++)
{
DescEntry aSubEntry = entry.SubEntries[i];
try
{
final String sEntryName = aSubEntry.entryName;
executeMethod(sEntryName);
}
catch (Exception e)
{
log.println("Exception while checking: " + aSubEntry.entryName + " : " + e.getMessage());
}
}
// to perform some stuff after all method tests
try
{
after();
}
catch (Exception e)
{
}
return tRes;
}
/**
* Is called before calling method tests , but after initialization .
* Subclasses may override to perform actions before method tests .
*/
protected void before() throws Exception
{
}
/**
* Is called after calling method tests . Subclasses may override
* to perform actions after method tests .
*/
protected void after()
{
}
/**
* @ return the name of the interface or the service tested .
*/
protected String getTestedClassName()
{
String clsName = this .getClass().getName();
int firstDot = clsName.indexOf('.' );
int lastDot = clsName.lastIndexOf('.' );
String append = "com.sun.star." ;
if (entry.longName.indexOf("::drafts::com::" ) > -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
*/
private void setStatus(String methName, Status methStatus)
{
tRes.tested(methName, methStatus);
}
/**
* sets the substates
*/
private void setSubStates(String msg)
{
for (int k = 0 ; k < entry.SubEntryCount; k++)
{
entry.SubEntries[k].hasErrorMsg = true ;
entry.SubEntries[k].ErrorMsg = msg;
if (entry.SubEntries[k].State.equals("UNKNOWN" ))
{
entry.SubEntries[k].State = msg;
}
}
}
/**
* Checks if the < code > method < / code > is optional in the service .
*/
protected boolean isOptional(String _method)
{
for (int k = 0 ; k < entry.SubEntryCount; k++)
{
final String sName = entry.SubEntries[k].entryName;
if (sName.equals(_method))
{
final boolean bIsOptional = entry.SubEntries[k].isOptional;
return bIsOptional;
}
}
return false ;
}
/**
* Checks if the < code > method < / code > test has been already called .
*/
private boolean isCalled(String method)
{
return methCalled.contains(method);
}
/**
* Calling of the method indicates that the < code > method < / code > 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.isCompleted() || mtStatus.isFailed()))
{
log.println("! Required method " + method + " failed" );
throw new StatusException(mtStatus);
}
}
/**
* Checks if the < code > method < / code > 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));
log.println();
}
}
/**
* Just calls the < code > method < / code > test .
*/
private 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 < code > method < / code > of the interface .
*
* @ return the testing method , if found , < tt > null < / tt > otherwise
*/
private 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 );
}
private void setField(String fieldName, Object value)
throws NoSuchFieldException, IllegalAccessException
{
this .getClass().getField(fieldName).set(this , value);
}
protected final void waitForEventIdle() {
util.utils.waitForEventIdle(tParam.getMSF());
}
}
Messung V0.5 in Prozent C=96 H=96 G=95
¤ Dauer der Verarbeitung: 0.12 Sekunden
(vorverarbeitet am 2026-09-29)
¤
*© Formatika GbR, Deutschland