tdf#160371: sc_subsequent_filters_test2: Add unittest
[LibreOffice.git] / qadevOOo / runner / lib / MultiPropertyTest.java
blob54e7122c4baa8807d98d481e2dd70d9e1354faef
1 /*
2 * This file is part of the LibreOffice project.
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 * This file incorporates work covered by the following license notice:
10 * Licensed to the Apache Software Foundation (ASF) under one or more
11 * contributor license agreements. See the NOTICE file distributed
12 * with this work for additional information regarding copyright
13 * ownership. The ASF licenses this file to you under the Apache
14 * License, Version 2.0 (the "License"); you may not use this file
15 * except in compliance with the License. You may obtain a copy of
16 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 package lib;
20 import com.sun.star.beans.Property;
21 import com.sun.star.beans.PropertyAttribute;
22 import com.sun.star.beans.PropertyVetoException;
23 import com.sun.star.beans.XPropertySet;
24 import com.sun.star.beans.XPropertySetInfo;
25 import com.sun.star.beans.UnknownPropertyException;
26 import com.sun.star.lang.IllegalArgumentException;
27 import com.sun.star.lang.WrappedTargetException;
28 import java.lang.reflect.Array;
29 import java.lang.reflect.Field;
30 import java.lang.reflect.Method;
31 import java.lang.reflect.Modifier;
33 import util.ValueChanger;
34 import util.ValueComparer;
35 import util.utils;
37 /**
38 * MultiPropertyTest extends the functionality of MultiMethodTest to support
39 * services testing. Since, in most cases, service tests has one method testing
40 * most of its properties, the MultiPropertyTest provides unified version of
41 * the method: testProperty().
43 * <p>The testProperty() is called, when the MultiMethodTest's testing method
44 * is not found in the subclass. So, by defining such methods for properties
45 * the standard testing behaviour can be changed.
47 * <p>The testing behaviour also can be changed by overriding compare(),
48 * getNewVAlue() or toString(Object) methods, or by extending PropertyTester
49 * class.
51 * @see MultiMethodTest
52 * @see #testProperty(String)
53 * @see #testProperty(String, PropertyTester)
54 * @see #compare
55 * @see #toString(Object)
57 public class MultiPropertyTest extends MultiMethodTest
60 /**
61 * Contains a XPropertySet interface of the tested object. Is initialized
62 * in MultiMethodTest code.
64 public XPropertySet oObj;
66 /**
67 * Overrides MultiMethodTest.invokeTestMethod(). If the test for the
68 * <code>meth</code> is not available (<code>meth</code> == <tt>null</tt>)
69 * calls testProperty method for the method. Otherwise calls
70 * super.invokeTestMethod().
72 * @see MultiMethodTest#invokeTestMethod
74 @Override
75 protected void invokeTestMethod(Method meth, String methName)
77 if (meth != null)
79 super.invokeTestMethod(meth, methName);
81 else
83 testProperty(methName);
87 /**
88 * PropertyTester class defines how to test a property and defined
89 * to allow subclasses of MultiPropertyTest to change the testing
90 * behaviour more flexible, since the behaviour can be customized for
91 * each property separately, by providing subclass of PropertyTester
92 * and passing it to testProperty(String, PropertyTester method).
94 public class PropertyTester
97 /**
98 * The method defines the whole process of testing propName
99 * property.
101 * <p>First, it checks if the property exists(it maybe optional).
102 * Then, a value to set the property with is calculated with
103 * getNewValue method. Normally, the new value is calculated
104 * based on old value, but subclasses can override the behaviour
105 * (for example, if old value is null) and specify their own value.
106 * Then the property is set with that new value and the result(
107 * it maybe an exception too, for example a PropertyVetoException)
108 * is checked with checkResult method.
110 * @param propName - the property to test.
111 * @result - adds the result of testing propName property to
112 * MultiMethodTest.tRes.
114 protected void testProperty(String propName)
116 XPropertySetInfo info = oObj.getPropertySetInfo();
118 if (info != null)
120 final boolean bHasProperty = info.hasPropertyByName(propName);
121 if (!bHasProperty)
123 if (isOptional(propName) || entry.isOptional)
125 // skipping optional property test
126 log.println("Property '" + propName + "' is optional and not supported");
127 tRes.tested(propName, true);
128 return;
130 else
132 // cannot test the property
133 log.println("Tested XPropertySet does not contain'" + propName + "' property");
134 tRes.tested(propName, false);
135 return;
142 Object oldValue = oObj.getPropertyValue(propName);
144 if( (oldValue==null) || utils.isVoid(oldValue) )
146 // #i111560# method getNewValue() does not work with an empty oldValue
147 Property prop = info.getPropertyByName(propName);
148 if( (prop.Attributes & PropertyAttribute.MAYBEVOID) != 0 )
150 // todo: implement a new test independent from method getNewValue()
151 log.println("changing initially empty MAYBEVOID properties is not supported by the test framework so far - skip test of property: " + propName);
152 tRes.tested(propName, true);
153 return;
155 else
157 log.println( "property '"+propName+"' is not set but is not MAYBEVOID");
158 tRes.tested(propName, false);
159 return;
163 Object newValue;
165 // trying to create new value
168 newValue = getNewValue(propName, oldValue);
170 catch (java.lang.IllegalArgumentException e)
172 // skipping test since new value is not available
173 log.println("Cannot create new value for '" + propName + " : " + e.getMessage());
174 return;
177 // for an exception thrown during setting new value
178 // to pass it to checkResult method
179 Exception exception = null;
183 log.println("try to set:");
184 log.println("old = " + toString(oldValue));
185 log.println("new = " + toString(newValue));
186 oObj.setPropertyValue(propName, newValue);
188 catch (IllegalArgumentException e)
190 exception = e;
192 catch (PropertyVetoException e)
194 exception = e;
196 catch (WrappedTargetException e)
198 exception = e;
200 catch (UnknownPropertyException e)
202 exception = e;
204 catch (RuntimeException e)
206 exception = e;
209 // getting result value
210 Object resValue = oObj.getPropertyValue(propName);
212 // checking results
213 checkResult(propName, oldValue, newValue, resValue, exception);
215 catch (Exception e)
217 log.println("Exception occurred while testing property '" + propName + "'");
218 e.printStackTrace(log);
219 tRes.tested(propName, false);
224 * The method checks result of setting a new value to the
225 * property based o the following arguments:
226 * @param propName - the property to test
227 * @param oldValue - the old value of the property, before changing it.
228 * @param newValue - the new value the property has been set with
229 * @param resValue - the value of the property after having changed it
230 * @param exception - if not null - the exception thrown by
231 * XPropertySet.setPropertyValue, else indicates
232 * normal method completion.
234 * <p>If the property is READ_ONLY, then either PropertyVetoException
235 * should be thrown or the value of property should not have changed
236 * (resValue is compared with oldValue with compare method).
238 * <p>If the property is not READ_ONLY, checks that the new value has
239 * been successfully set(resValue is compared with newValue with
240 * compare method).
242 * <p>If the exception is not null then(except the case of read-only
243 * property and PropertyVetoException above) it is rethrown to allow
244 * further catching it if needed.
246 * <p>Subclasses can override to change this behaviour.
248 protected void checkResult(String propName, Object oldValue,
249 Object newValue, Object resValue, Exception exception)
250 throws Exception
252 XPropertySetInfo info = oObj.getPropertySetInfo();
253 if (info == null)
255 log.println("Can't get XPropertySetInfo for property " + propName);
256 tRes.tested(propName, false);
257 return;
259 Property prop = info.getPropertyByName(propName);
261 boolean readOnly = (prop.Attributes & PropertyAttribute.READONLY) != 0;
262 boolean maybeVoid = (prop.Attributes & PropertyAttribute.MAYBEVOID) != 0;
263 //check get-set methods
264 if (maybeVoid)
266 log.println("Property " + propName + " is void");
268 if (readOnly)
270 log.println("Property " + propName + " is readOnly");
272 if (util.utils.isVoid(oldValue) && !maybeVoid)
274 log.println(propName + " is void, but it's not MAYBEVOID");
275 tRes.tested(propName, false);
277 else if (oldValue == null)
279 log.println(propName + " has null value, and therefore can't be changed");
280 tRes.tested(propName, true);
282 else if (readOnly)
284 // check if exception was thrown
285 if (exception != null)
287 if (exception instanceof PropertyVetoException)
289 // the change of read only prohibited - OK
290 log.println("Property is ReadOnly and wasn't changed");
291 log.println("Property '" + propName + "' OK");
292 tRes.tested(propName, true);
294 else if (exception instanceof IllegalArgumentException)
296 // the change of read only prohibited - OK
297 log.println("Property is ReadOnly and wasn't changed");
298 log.println("Property '" + propName + "' OK");
299 tRes.tested(propName, true);
301 else if (exception instanceof UnknownPropertyException)
303 // the change of read only prohibited - OK
304 log.println("Property is ReadOnly and wasn't changed");
305 log.println("Property '" + propName + "' OK");
306 tRes.tested(propName, true);
308 else if (exception instanceof RuntimeException)
310 // the change of read only prohibited - OK
311 log.println("Property is ReadOnly and wasn't changed");
312 log.println("Property '" + propName + "' OK");
313 tRes.tested(propName, true);
315 else
317 throw exception;
320 else
322 // if no exception - check that value
323 // has not changed
324 if (!compare(resValue, oldValue))
326 log.println("Read only property '" + propName + "' has changed");
327 log.println("result = " + toString(resValue));
328 tRes.tested(propName, false);
330 else
332 log.println("Read only property '" + propName + "' hasn't changed");
333 log.println("Property '" + propName + "' OK");
334 tRes.tested(propName, true);
338 else
340 if (exception == null)
342 // if no exception thrown
343 // check that the new value is set
344 if (!compare(resValue, newValue))
346 log.println("Value for '" + propName + "' hasn't changed as expected");
347 log.println("result = " + toString(resValue));
348 if (!compare(resValue, oldValue))
350 log.println("But it has changed.");
351 tRes.tested(propName, true);
353 else
355 tRes.tested(propName, false);
358 else
360 log.println("Property '" + propName + "' OK");
361 log.println("result = " + toString(resValue));
362 tRes.tested(propName, true);
365 else
367 throw exception;
373 * The method produces new value of the property from the oldValue.
374 * It returns the result of ValueChanger.changePValue method.
375 * Subclasses can override the method to return their own value,
376 * when the changePValue behavior is not enough, for example,
377 * when oldValue is null.
379 protected Object getNewValue(String propName, Object oldValue)
380 throws java.lang.IllegalArgumentException
382 return ValueChanger.changePValue(oldValue, propName);
386 * The method compares obj1 and obj2. It calls
387 * MultiPropertyTest.compare, but subclasses can override to change
388 * the behavior, since normally compare calls Object.equals method
389 * which is not appropriate in some cases(e.g., structs with equals
390 * not overridden).
392 protected boolean compare(Object obj1, Object obj2)
394 return MultiPropertyTest.this.compare(obj1, obj2);
398 * The method returns a String representation of the obj. It calls
399 * MultipropertyTest.toString(Object), but subclasses can override
400 * to change the behavior.
402 protected String toString(Object obj)
404 return MultiPropertyTest.this.toString(obj);
409 * Extension for <code>PropertyTester</code> which switches two
410 * different values. <code>getNewValue()</code> method of this
411 * class returns one of these two values depending on the
412 * old value, so new value is not equal to old value.
414 public class PropertyValueSwitcher extends PropertyTester
417 Object val1 = null;
418 Object val2 = null;
421 * Constructs a property tester with two different values
422 * specified as parameters.
424 * @param val1 Not <code>null</code> value for the property
425 * tested.
426 * @param val2 Not <code>null</code> value for the property
427 * tested which differs from the first value.
429 public PropertyValueSwitcher(Object val1, Object val2)
431 this.val1 = val1;
432 this.val2 = val2;
436 * Overridden method of <code>PropertyTester</code> which
437 * returns new value from two values specified.
439 * @return The second value if old value is equal to the first
440 * one, the first value otherwise.
442 @Override
443 protected Object getNewValue(String propName, Object old)
445 if (ValueComparer.equalValue(val1, old))
447 return val2;
449 else
451 return val1;
457 * The method performs testing of propName property using propTester.
459 protected void testProperty(String propName, PropertyTester propTester)
461 propTester.testProperty(propName);
465 * The method performs testing of propName property. It uses PropertyTester
466 * instance for testing.
468 protected void testProperty(String propName)
470 testProperty(propName, new PropertyTester());
474 * Tests the property using <code>PropertyValueSwitcher</code>
475 * tester and two values for this property.
477 * @see PropertyValueSwitcher
479 protected void testProperty(String propName, Object val1, Object val2)
481 testProperty(propName, new PropertyValueSwitcher(val1, val2));
485 * Compares two object. In the implementation calls obj1.equals(obj2).
487 protected boolean compare(Object obj1, Object obj2)
489 return ValueComparer.equalValue(obj1, obj2);
493 * Gets string representation of the obj. In the implementation
494 * returns obj.toString().
496 protected String toString(Object obj)
498 if (obj == null) {
499 return "null";
501 StringBuilder s = new StringBuilder(obj.toString());
502 if (obj.getClass().isArray()) {
503 int n = Array.getLength(obj);
504 s.append('[').append(n).append("]{");
505 for (int i = 0; i != n; ++i) {
506 if (i != 0) {
507 s.append(", ");
509 s.append(toString(Array.get(obj, i)));
511 s.append('}');
512 } else if (ValueChanger.isStructure(obj)) {
513 s.append('{');
514 Field[] fields = obj.getClass().getFields();
515 boolean first = true;
516 for (int i = 0; i != fields.length; ++i) {
517 if ((fields[i].getModifiers() & Modifier.STATIC) == 0) {
518 if (!first) {
519 s.append(", ");
521 first = false;
522 try {
523 s.append(toString(fields[i].get(obj)));
524 } catch (IllegalAccessException e) {
525 throw new RuntimeException("unexpected " + e, e);
529 s.append('}');
531 return s.toString();