/*
* 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 com.sun.star.beans.Property;
import com.sun.star.beans.PropertyAttribute;
import com.sun.star.beans.PropertyVetoException;
import com.sun.star.beans.XPropertySet;
import com.sun.star.beans.XPropertySetInfo;
import com.sun.star.beans.UnknownPropertyException;
import com.sun.star.lang.IllegalArgumentException;
import com.sun.star.lang.WrappedTargetException;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import util.ValueChanger;
import util.ValueComparer;
import util.utils;
/**
* MultiPropertyTest extends the functionality of MultiMethodTest to support
* services testing . Since , in most cases , service tests has one method testing
* most of its properties , the MultiPropertyTest provides unified version of
* the method : testProperty ( ) .
*
* < p > The testProperty ( ) is called , when the MultiMethodTest ' s testing method
* is not found in the subclass . So , by defining such methods for properties
* the standard testing behaviour can be changed .
*
* < p > The testing behaviour also can be changed by overriding compare ( ) ,
* getNewVAlue ( ) or toString ( Object ) methods , or by extending PropertyTester
* class .
*
* @ see MultiMethodTest
* @ see # testProperty ( String )
* @ see # testProperty ( String , PropertyTester )
* @ see # compare
* @ see # toString ( Object )
*/
public class MultiPropertyTest extends MultiMethodTest
{
/**
* Contains a XPropertySet interface of the tested object . Is initialized
* in MultiMethodTest code .
*/
public XPropertySet oObj;
/**
* Overrides MultiMethodTest . invokeTestMethod ( ) . If the test for the
* < code > meth < / code > is not available ( < code > meth < / code > = = < tt > null < / tt > )
* calls testProperty method for the method . Otherwise calls
* super . invokeTestMethod ( ) .
*
* @ see MultiMethodTest # invokeTestMethod
*/
@Override
protected void invokeTestMethod(Method meth, String methName)
{
if (meth != null )
{
super .invokeTestMethod(meth, methName);
}
else
{
testProperty(methName);
}
}
/**
* PropertyTester class defines how to test a property and defined
* to allow subclasses of MultiPropertyTest to change the testing
* behaviour more flexible , since the behaviour can be customized for
* each property separately , by providing subclass of PropertyTester
* and passing it to testProperty ( String , PropertyTester method ) .
*/
public class PropertyTester
{
/**
* The method defines the whole process of testing propName
* property .
*
* < p > First , it checks if the property exists ( it maybe optional ) .
* Then , a value to set the property with is calculated with
* getNewValue method . Normally , the new value is calculated
* based on old value , but subclasses can override the behaviour
* ( for example , if old value is null ) and specify their own value .
* Then the property is set with that new value and the result (
* it maybe an exception too , for example a PropertyVetoException )
* is checked with checkResult method .
*
* @ param propName - the property to test .
* @ result - adds the result of testing propName property to
* MultiMethodTest . tRes .
*/
protected void testProperty(String propName)
{
XPropertySetInfo info = oObj.getPropertySetInfo();
if (info != null )
{
final boolean bHasProperty = info.hasPropertyByName(propName);
if (!bHasProperty)
{
if (isOptional(propName) || entry.isOptional)
{
// skipping optional property test
log.println("Property '" + propName + "' is optional and not supported" );
tRes.tested(propName, true );
return ;
}
else
{
// cannot test the property
log.println("Tested XPropertySet does not contain'" + propName + "' property" );
tRes.tested(propName, false );
return ;
}
}
}
try
{
Object oldValue = oObj.getPropertyValue(propName);
if ( (oldValue==null ) || utils.isVoid(oldValue) )
{
// #i111560# method getNewValue() does not work with an empty oldValue
Property prop = info.getPropertyByName(propName);
if ( (prop.Attributes & PropertyAttribute.MAYBEVOID) != 0 )
{
// todo: implement a new test independent from method getNewValue()
log.println("changing initially empty MAYBEVOID properties is not supported by the test framework so far - skip test of property: " + propName);
tRes.tested(propName, true );
return ;
}
else
{
log.println( "property '" +propName+"' is not set but is not MAYBEVOID" );
tRes.tested(propName, false );
return ;
}
}
Object newValue;
// trying to create new value
try
{
newValue = getNewValue(propName, oldValue);
}
catch (java.lang.IllegalArgumentException e)
{
// skipping test since new value is not available
log.println("Cannot create new value for '" + propName + " : " + e.getMessage());
return ;
}
// for an exception thrown during setting new value
// to pass it to checkResult method
Exception exception = null ;
try
{
log.println("try to set:" );
log.println("old = " + toString(oldValue));
log.println("new = " + toString(newValue));
oObj.setPropertyValue(propName, newValue);
}
catch (IllegalArgumentException e)
{
exception = e;
}
catch (PropertyVetoException e)
{
exception = e;
}
catch (WrappedTargetException e)
{
exception = e;
}
catch (UnknownPropertyException e)
{
exception = e;
}
catch (RuntimeException e)
{
exception = e;
}
// getting result value
Object resValue = oObj.getPropertyValue(propName);
// checking results
checkResult(propName, oldValue, newValue, resValue, exception);
}
catch (Exception e)
{
log.println("Exception occurred while testing property '" + propName + "'" );
e.printStackTrace(log);
tRes.tested(propName, false );
}
}
/**
* The method checks result of setting a new value to the
* property based o the following arguments :
* @ param propName - the property to test
* @ param oldValue - the old value of the property , before changing it .
* @ param newValue - the new value the property has been set with
* @ param resValue - the value of the property after having changed it
* @ param exception - if not null - the exception thrown by
* XPropertySet . setPropertyValue , else indicates
* normal method completion .
*
* < p > If the property is READ_ONLY , then either PropertyVetoException
* should be thrown or the value of property should not have changed
* ( resValue is compared with oldValue with compare method ) .
*
* < p > If the property is not READ_ONLY , checks that the new value has
* been successfully set ( resValue is compared with newValue with
* compare method ) .
*
* < p > If the exception is not null then ( except the case of read - only
* property and PropertyVetoException above ) it is rethrown to allow
* further catching it if needed .
*
* < p > Subclasses can override to change this behaviour .
*/
protected void checkResult(String propName, Object oldValue,
Object newValue, Object resValue, Exception exception)
throws Exception
{
XPropertySetInfo info = oObj.getPropertySetInfo();
if (info == null )
{
log.println("Can't get XPropertySetInfo for property " + propName);
tRes.tested(propName, false );
return ;
}
Property prop = info.getPropertyByName(propName);
boolean readOnly = (prop.Attributes & PropertyAttribute.READONLY) != 0 ;
boolean maybeVoid = (prop.Attributes & PropertyAttribute.MAYBEVOID) != 0 ;
//check get-set methods
if (maybeVoid)
{
log.println("Property " + propName + " is void" );
}
if (readOnly)
{
log.println("Property " + propName + " is readOnly" );
}
if (util.utils.isVoid(oldValue) && !maybeVoid)
{
log.println(propName + " is void, but it's not MAYBEVOID" );
tRes.tested(propName, false );
}
else if (oldValue == null )
{
log.println(propName + " has null value, and therefore can't be changed" );
tRes.tested(propName, true );
}
else if (readOnly)
{
// check if exception was thrown
if (exception != null )
{
if (exception instanceof PropertyVetoException)
{
// the change of read only prohibited - OK
log.println("Property is ReadOnly and wasn't changed" );
log.println("Property '" + propName + "' OK" );
tRes.tested(propName, true );
}
else if (exception instanceof IllegalArgumentException)
{
// the change of read only prohibited - OK
log.println("Property is ReadOnly and wasn't changed" );
log.println("Property '" + propName + "' OK" );
tRes.tested(propName, true );
}
else if (exception instanceof UnknownPropertyException)
{
// the change of read only prohibited - OK
log.println("Property is ReadOnly and wasn't changed" );
log.println("Property '" + propName + "' OK" );
tRes.tested(propName, true );
}
else if (exception instanceof RuntimeException)
{
// the change of read only prohibited - OK
log.println("Property is ReadOnly and wasn't changed" );
log.println("Property '" + propName + "' OK" );
tRes.tested(propName, true );
}
else
{
throw exception;
}
}
else
{
// if no exception - check that value
// has not changed
if (!compare(resValue, oldValue))
{
log.println("Read only property '" + propName + "' has changed" );
log.println("result = " + toString(resValue));
tRes.tested(propName, false );
}
else
{
log.println("Read only property '" + propName + "' hasn't changed" );
log.println("Property '" + propName + "' OK" );
tRes.tested(propName, true );
}
}
}
else
{
if (exception == null )
{
// if no exception thrown
// check that the new value is set
if (!compare(resValue, newValue))
{
log.println("Value for '" + propName + "' hasn't changed as expected" );
log.println("result = " + toString(resValue));
if (!compare(resValue, oldValue))
{
log.println("But it has changed." );
tRes.tested(propName, true );
}
else
{
tRes.tested(propName, false );
}
}
else
{
log.println("Property '" + propName + "' OK" );
log.println("result = " + toString(resValue));
tRes.tested(propName, true );
}
}
else
{
throw exception;
}
}
}
/**
* The method produces new value of the property from the oldValue .
* It returns the result of ValueChanger . changePValue method .
* Subclasses can override the method to return their own value ,
* when the changePValue behavior is not enough , for example ,
* when oldValue is null .
*/
protected Object getNewValue(String propName, Object oldValue)
throws java.lang.IllegalArgumentException
{
return ValueChanger.changePValue(oldValue, propName);
}
/**
* The method compares obj1 and obj2 . It calls
* MultiPropertyTest . compare , but subclasses can override to change
* the behavior , since normally compare calls Object . equals method
* which is not appropriate in some cases ( e . g . , structs with equals
* not overridden ) .
*/
protected boolean compare(Object obj1, Object obj2)
{
return MultiPropertyTest.this .compare(obj1, obj2);
}
/**
* The method returns a String representation of the obj . It calls
* MultipropertyTest . toString ( Object ) , but subclasses can override
* to change the behavior .
*/
protected String toString(Object obj)
{
return MultiPropertyTest.this .toString(obj);
}
}
/**
* Extension for < code > PropertyTester < / code > which switches two
* different values . < code > getNewValue ( ) < / code > method of this
* class returns one of these two values depending on the
* old value , so new value is not equal to old value .
*/
public class PropertyValueSwitcher extends PropertyTester
{
Object val1 = null ;
Object val2 = null ;
/**
* Constructs a property tester with two different values
* specified as parameters .
*
* @ param val1 Not < code > null < / code > value for the property
* tested .
* @ param val2 Not < code > null < / code > value for the property
* tested which differs from the first value .
*/
public PropertyValueSwitcher(Object val1, Object val2)
{
this .val1 = val1;
this .val2 = val2;
}
/**
* Overridden method of < code > PropertyTester < / code > which
* returns new value from two values specified .
*
* @ return The second value if old value is equal to the first
* one , the first value otherwise .
*/
@Override
protected Object getNewValue(String propName, Object old)
{
if (ValueComparer.equalValue(val1, old))
{
return val2;
}
else
{
return val1;
}
}
}
/**
* The method performs testing of propName property using propTester .
*/
protected void testProperty(String propName, PropertyTester propTester)
{
propTester.testProperty(propName);
}
/**
* The method performs testing of propName property . It uses PropertyTester
* instance for testing .
*/
protected void testProperty(String propName)
{
testProperty(propName, new PropertyTester());
}
/**
* Tests the property using < code > PropertyValueSwitcher < / code >
* tester and two values for this property .
*
* @ see PropertyValueSwitcher
*/
protected void testProperty(String propName, Object val1, Object val2)
{
testProperty(propName, new PropertyValueSwitcher(val1, val2));
}
/**
* Compares two object . In the implementation calls obj1 . equals ( obj2 ) .
*/
protected boolean compare(Object obj1, Object obj2)
{
return ValueComparer.equalValue(obj1, obj2);
}
/**
* Gets string representation of the obj . In the implementation
* returns obj . toString ( ) .
*/
protected String toString(Object obj)
{
if (obj == null ) {
return "null" ;
}
StringBuilder s = new StringBuilder(obj.toString());
if (obj.getClass().isArray()) {
int n = Array.getLength(obj);
s.append('[' ).append(n).append("]{" );
for (int i = 0 ; i != n; ++i) {
if (i != 0 ) {
s.append(", " );
}
s.append(toString(Array.get(obj, i)));
}
s.append('}' );
} else if (ValueChanger.isStructure(obj)) {
s.append('{' );
Field[] fields = obj.getClass().getFields();
boolean first = true ;
for (int i = 0 ; i != fields.length; ++i) {
if ((fields[i].getModifiers() & Modifier.STATIC ) == 0 ) {
if (!first) {
s.append(", " );
}
first = false ;
try {
s.append(toString(fields[i].get(obj)));
} catch (IllegalAccessException e) {
throw new RuntimeException("unexpected " + e, e);
}
}
}
s.append('}' );
}
return s.toString();
}
}
Messung V0.5 in Prozent C=94 H=92 G=92
¤ Dauer der Verarbeitung: 0.17 Sekunden
(vorverarbeitet am 2026-09-29)
¤
*© Formatika GbR, Deutschland