1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
29 import com
.sun
.star
.beans
.Property
;
30 import com
.sun
.star
.beans
.PropertyAttribute
;
31 import com
.sun
.star
.beans
.PropertyVetoException
;
32 import com
.sun
.star
.beans
.XPropertySet
;
33 import com
.sun
.star
.beans
.XPropertySetInfo
;
34 import com
.sun
.star
.beans
.UnknownPropertyException
;
35 import com
.sun
.star
.lang
.XServiceInfo
;
36 import com
.sun
.star
.lang
.IllegalArgumentException
;
37 import com
.sun
.star
.lang
.WrappedTargetException
;
38 import com
.sun
.star
.uno
.UnoRuntime
;
40 import java
.lang
.reflect
.Method
;
42 import util
.ValueChanger
;
43 import util
.ValueComparer
;
46 import com
.sun
.star
.uno
.Any
;
47 import com
.sun
.star
.uno
.AnyConverter
;
48 import com
.sun
.star
.uno
.Type
;
51 * MultiPropertyTest extends the functionality of MultiMethodTest to support
52 * services testing. Since, in most cases, service tests has one method testing
53 * most of its properties, the MultiPropertyTest provides unified version of
54 * the method: testProperty().
56 * <p>The testProperty() is called, when the MultiMethodTest's testing method
57 * is not found in the subclass. So, by defining such methods for properties
58 * the standard testing behavioutr can be changed.
60 * <p>The testing behaviour also can be changed by overriding compare(),
61 * getNewVAlue() or toString(Object) methods, or by extending PropertyTester
64 * @see MultiMethodTest
65 * @see #testProperty(String)
66 * @see #testProperty(String, Propertytester)
69 * @see #toString(Object)
71 public class MultiPropertyTest
extends MultiMethodTest
75 * Contains a XPropertySet interface of the tested object. Is initialized
76 * in MultiMethodTest code.
78 public XPropertySet oObj
;
79 protected boolean optionalService
= false;
82 * Overrides super.before() to check the service is supported by the object.
84 protected void before()
86 XServiceInfo xInfo
= (XServiceInfo
) UnoRuntime
.queryInterface(
87 XServiceInfo
.class, oObj
);
89 optionalService
= entry
.isOptional
;
91 String theService
= getTestedClassName();
92 if (xInfo
!= null && !xInfo
.supportsService(theService
))
94 log
.println("Service " + theService
+ " not available");
97 log
.println("This is OK since it is optional");
101 Status
.failed(theService
+ " is not supported");
107 * Overrides MultiMethodTest.invokeTestMethod(). If the test for the
108 * <code>meth</code> is not available (<code>meth</code> == <tt>null</tt>)
109 * calls testProperty method for the method. Otherwise calls
110 * super.invokeTestMethod().
112 * @see #MultiMethodTest.invokeTestMethod()
114 protected void invokeTestMethod(Method meth
, String methName
)
118 super.invokeTestMethod(meth
, methName
);
122 testProperty(methName
);
127 * PropertyTester class defines how to test a property and defined
128 * to allow subclasses of MultiPropertyTest to change the testing
129 * behaviour more flexible, since the behaviour can be customized for
130 * each property separately, by providing subclass of PropertyTester
131 * and passing it to testProperty(String, PropertyTester method).
133 public class PropertyTester
137 * The method defines the whole process of testing propName
140 * <p>First, it checks if the property exists(it maybe optional).
141 * Then, a value to set the property with is calculated with
142 * getNewValue method. Normally, the new value is calculated
143 * based on old value, but subclasses can override the behaviour
144 * (for example, if old value is null) and specify their own value.
145 * Then the property is set with that new value and the result(
146 * it maybe an exception too, for example a PropertyVetoException)
147 * is checked with checkResult method.
149 * @param propName - the property to test.
150 * @result - adds the result of testing propName property to
151 * MultiMethodTest.tRes.
153 protected void testProperty(String propName
)
155 XPropertySetInfo info
= oObj
.getPropertySetInfo();
159 final boolean bHasProperty
= info
.hasPropertyByName(propName
);
162 if (isOptional(propName
) || optionalService
)
164 // skipping optional property test
165 log
.println("Property '" + propName
+ "' is optional and not supported");
166 tRes
.tested(propName
, true);
171 // cannot test the property
172 log
.println("Tested XPropertySet does not contain'" + propName
+ "' property");
173 tRes
.tested(propName
, false);
181 Object oldValue
= oObj
.getPropertyValue(propName
);
183 if( (oldValue
==null) || utils
.isVoid(oldValue
) )
185 // #i111560# method getNewValue() does not work with an empty oldValue
186 Property prop
= info
.getPropertyByName(propName
);
187 if( (prop
.Attributes
& PropertyAttribute
.MAYBEVOID
) != 0 )
189 // todo: implement a new test independent from method getNewValue()
190 log
.println("changing initially empty MAYBEVOID properties is not supported by the test framework so far - skip test of property: " + propName
);
191 tRes
.tested(propName
, true);
196 log
.println( "property '"+propName
+"' is not set but is not MAYBEVOID");
197 tRes
.tested(propName
, false);
204 // trying to create new value
207 newValue
= getNewValue(propName
, oldValue
);
209 catch (java
.lang
.IllegalArgumentException e
)
211 // skipping test since new value is not available
212 Status
.failed("Cannot create new value for '" + propName
+ " : " + e
.getMessage());
216 // for an exception thrown during setting new value
217 // to pass it to checkResult method
218 Exception exception
= null;
222 log
.println("try to set:");
223 log
.println("old = " + toString(oldValue
));
224 log
.println("new = " + toString(newValue
));
225 oObj
.setPropertyValue(propName
, newValue
);
227 catch (IllegalArgumentException e
)
231 catch (PropertyVetoException e
)
235 catch (WrappedTargetException e
)
239 catch (UnknownPropertyException e
)
243 catch (RuntimeException e
)
248 // getting result value
249 Object resValue
= oObj
.getPropertyValue(propName
);
252 checkResult(propName
, oldValue
, newValue
, resValue
, exception
);
256 log
.println("Exception occured while testing property '" + propName
+ "'");
257 e
.printStackTrace(log
);
258 tRes
.tested(propName
, false);
263 * The method checks result of setting a new value to the
264 * property based o the following arguments:
265 * @propName - the property to test
266 * @oldValue - the old value of the property, before changing it.
267 * @newValue - the new value the property has been set with
268 * @resValue - the value of the property after having changed it
269 * @exception - if not null - the exception thrown by
270 * XPropertySet.setPropertyValue, else indicates
271 * normal method completion.
273 * <p>If the property is READ_ONLY, than either PropertyVetoException
274 * should be thrown or the value of property should not have changed
275 * (resValue is compared with oldValue with compare method).
277 * <p>If the property is not READ_ONLY, checks that the new value has
278 * been successfully set(resValue is compared with newValue with
281 * <p>If the exception is not null then(except the case of read-only
282 * property and PropertyVetoException above) it is rethrown to allow
283 * further catching it if needed.
285 * <p>Subclasses can override to change this behaviour.
287 protected void checkResult(String propName
, Object oldValue
,
288 Object newValue
, Object resValue
, Exception exception
)
291 XPropertySetInfo info
= oObj
.getPropertySetInfo();
294 log
.println("Can't get XPropertySetInfo for property " + propName
);
295 tRes
.tested(propName
, false);
298 Property prop
= info
.getPropertyByName(propName
);
300 short attr
= prop
.Attributes
;
301 boolean readOnly
= (prop
.Attributes
& PropertyAttribute
.READONLY
) != 0;
302 boolean maybeVoid
= (prop
.Attributes
& PropertyAttribute
.MAYBEVOID
) != 0;
303 //check get-set methods
306 log
.println("Property " + propName
+ " is void");
310 log
.println("Property " + propName
+ " is readOnly");
312 if (util
.utils
.isVoid(oldValue
) && !maybeVoid
)
314 log
.println(propName
+ " is void, but it's not MAYBEVOID");
315 tRes
.tested(propName
, false);
317 else if (oldValue
== null)
319 log
.println(propName
+ " has null value, and therefore can't be changed");
320 tRes
.tested(propName
, true);
324 // check if exception was thrown
325 if (exception
!= null)
327 if (exception
instanceof PropertyVetoException
)
329 // the change of read only prohibited - OK
330 log
.println("Property is ReadOnly and wasn't changed");
331 log
.println("Property '" + propName
+ "' OK");
332 tRes
.tested(propName
, true);
334 else if (exception
instanceof IllegalArgumentException
)
336 // the change of read only prohibited - OK
337 log
.println("Property is ReadOnly and wasn't changed");
338 log
.println("Property '" + propName
+ "' OK");
339 tRes
.tested(propName
, true);
341 else if (exception
instanceof UnknownPropertyException
)
343 // the change of read only prohibited - OK
344 log
.println("Property is ReadOnly and wasn't changed");
345 log
.println("Property '" + propName
+ "' OK");
346 tRes
.tested(propName
, true);
348 else if (exception
instanceof RuntimeException
)
350 // the change of read only prohibited - OK
351 log
.println("Property is ReadOnly and wasn't changed");
352 log
.println("Property '" + propName
+ "' OK");
353 tRes
.tested(propName
, true);
362 // if no exception - check that value
364 if (!compare(resValue
, oldValue
))
366 log
.println("Read only property '" + propName
+ "' has changed");
369 if (!util
.utils
.isVoid(oldValue
) && oldValue
instanceof Any
)
371 oldValue
= AnyConverter
.toObject(new Type(((Any
) oldValue
).getClass()), oldValue
);
373 // log.println("old = " + toString(oldValue));
374 // log.println("new = " + toString(newValue));
375 log
.println("result = " + toString(resValue
));
377 catch (com
.sun
.star
.lang
.IllegalArgumentException iae
)
379 log
.println("NOTIFY: this property needs further investigations.");
380 log
.println("\t The type seems to be an Any with value of NULL.");
381 log
.println("\t Maybe the property should get it's own test method.");
384 tRes
.tested(propName
, false);
388 log
.println("Read only property '" + propName
+ "' hasn't changed");
389 log
.println("Property '" + propName
+ "' OK");
390 tRes
.tested(propName
, true);
396 if (exception
== null)
398 // if no exception thrown
399 // check that the new value is set
400 if ((!compare(resValue
, newValue
)) || (compare(resValue
, oldValue
)))
402 log
.println("Value for '" + propName
+ "' hasn't changed as expected");
405 if (!util
.utils
.isVoid(oldValue
) && oldValue
instanceof Any
)
407 oldValue
= AnyConverter
.toObject(new Type(((Any
) oldValue
).getClass()), oldValue
);
409 // log.println("old = " + toString(oldValue));
410 // log.println("new = " + toString(newValue));
411 log
.println("result = " + toString(resValue
));
413 catch (com
.sun
.star
.lang
.IllegalArgumentException iae
)
415 log
.println("NOTIFY: this property needs further investigations.");
416 log
.println("\t The type seems to be an Any with value of NULL.");
417 log
.println("\t Maybe the property should get it's own test method.");
419 if (resValue
!= null)
421 if ((!compare(resValue
, oldValue
)) || (!resValue
.equals(oldValue
)))
423 log
.println("But it has changed.");
424 tRes
.tested(propName
, true);
428 tRes
.tested(propName
, false);
433 tRes
.tested(propName
, false);
435 //tRes.tested(propName, false);
439 log
.println("Property '" + propName
+ "' OK");
442 if (!util
.utils
.isVoid(oldValue
) && oldValue
instanceof Any
)
444 oldValue
= AnyConverter
.toObject(new Type(((Any
) oldValue
).getClass()), oldValue
);
446 // log.println("old = " + toString(oldValue));
447 // log.println("new = " + toString(newValue));
448 log
.println("result = " + toString(resValue
));
450 catch (com
.sun
.star
.lang
.IllegalArgumentException iae
)
453 tRes
.tested(propName
, true);
464 * The method produces new value of the property from the oldValue.
465 * It returns the result of ValueChanger.changePValue method.
466 * Subclasses can override the method to return their own value,
467 * when the changePValue beahviour is not enough, for example,
468 * when oldValue is null.
470 protected Object
getNewValue(String propName
, Object oldValue
)
471 throws java
.lang
.IllegalArgumentException
473 return ValueChanger
.changePValue(oldValue
);
477 * The method compares obj1 and obj2. It calls
478 * MultiPropertyTest.compare, but subclasses can override to change
479 * the behaviour, since normally compare calls Object.equals method
480 * which is not apropriate in some cases(e.g., structs with equals
483 protected boolean compare(Object obj1
, Object obj2
)
485 return callCompare(obj1
, obj2
);
489 * The method returns a String representation of the obj. It calls
490 * MultipropertyTest.toString(Object), but subclasses can override
491 * to change the behaviour.
493 protected String
toString(Object obj
)
495 return callToString(obj
);
500 * Extension for <code>PropertyTester</code> which switches two
501 * different values. <code>getNewValue()</code> method of this
502 * class returns one of these two values depending on the
503 * old value, so new value is not equal to old value.
505 public class PropertyValueSwitcher
extends PropertyTester
512 * Constructs a property tester with two different values
513 * specified as parameters.
515 * @param val1 Not <code>null</code> value for the property
517 * @param val1 Not <code>null</code> value for the property
518 * tested which differs from the first value.
520 public PropertyValueSwitcher(Object val1
, Object val2
)
527 * Overriden method of <code>PropertyTester</code> which
528 * retruns new value from two values specified.
530 * @return The second value if old value is equal to the first
531 * one, the first value otherwise.
533 protected Object
getNewValue(String propName
, Object old
)
535 if (ValueComparer
.equalValue(val1
, old
))
547 * The method performs testing of propName property using propTester.
549 protected void testProperty(String propName
, PropertyTester propTester
)
551 propTester
.testProperty(propName
);
555 * The method performs testing of propName property. It uses PropertyTester
556 * instance for testing.
558 protected void testProperty(String propName
)
560 testProperty(propName
, new PropertyTester());
564 * Tests the property using <code>PropertyValueSwitcher</code>
565 * tester and two values for this property.
567 * @see #PropertyValueSwitcher
569 protected void testProperty(String propName
, Object val1
, Object val2
)
571 testProperty(propName
, new PropertyValueSwitcher(val1
, val2
));
575 * The method just calls compare. This is a workaround to CodeWarrior's
578 private boolean callCompare(Object obj1
, Object obj2
)
580 return compare(obj1
, obj2
);
584 * Compares two object. In the implementation calls obj1.equals(obj2).
586 protected boolean compare(Object obj1
, Object obj2
)
588 return ValueComparer
.equalValue(obj1
, obj2
);
592 * The method just calls toString. This is a workaround to
593 * CodeWarrior's compiler bug.
595 private String
callToString(Object obj
)
597 return toString(obj
);
601 * Gets string representation of the obj. In the implementation
602 * returns obj.toString().
604 protected String
toString(Object obj
)
606 return obj
== null ?
"null" : obj
.toString();