bump product version to 5.0.4.1
[LibreOffice.git] / qadevOOo / runner / lib / MultiMethodTest.java
blobe7bf886c3223adbd85a0629d7e6336091571da42
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 java.io.PrintWriter;
21 import java.lang.reflect.InvocationTargetException;
22 import java.lang.reflect.Method;
23 import java.util.ArrayList;
25 import share.DescEntry;
26 import stats.Summarizer;
28 import com.sun.star.uno.UnoRuntime;
30 /**
31 * The class supports method based interface tests development.
33 * <p>There are some points that should be fulfilled in a subclass to work
34 * correctly in the multi-method framework:
36 * 1. each subclass schould define a public field named oObj of type tested
37 * by the subclass, e.g. 'public XText oObj;'. That field will be initialized
38 * by the MultiMethodTest code with the instance of the interface to test.
39 * In a case of service testing the field type should be XPropertySet.
41 * 2. for the test of each method of the tested interface(or a property in the
42 * case of service testing) should be method with the following signature
43 * provided: 'public void _<method name>()', e.g. 'public void _getText()'.
44 * The methods will be called by MultiMethodText code using reflection API
45 * for each method in the interface description.
47 * 3. to set status for a call 'tRes.tested(String method,
48 * boolean result)' should be used. For example 'tRes.tested("getText()",
49 * true)'. Also 'tRes.assert(String assertion, boolean result)' call can
50 * be used. Note, that one can call the methods not necessarily from the
51 * test for the tested method, but from other method tests too (in the
52 * MultiMethodTest subclass). See also TestResult and MultiMethodTest.tRes
53 * documentation.
55 * 4. the before() and after() methods can be overridden to perform some
56 * actions, accordingly, before and after calling the test methods.
58 * 5. besides tRes, there are some fields initialized in the MultiMethodTest,
59 * that can be used for implementing tests:
61 * - tEnv contains the environment tested
62 * - tParam contains parameters of the test
63 * - log a writer to log information about the test
65 * @see TestResult
67 public class MultiMethodTest
70 /**
71 * Contains the TestEnvironment being tested, to allow for tests to access
72 * it.
74 protected TestEnvironment tEnv;
75 /**
76 * Contains the TestParameters for the tests, to allow for tests to access
77 * it.
79 protected TestParameters tParam;
80 /**
81 * Contains the Description for the test
82 * it.
84 protected DescEntry entry;
85 /**
86 * Contains a writer to log an information about the interface testing, to
87 * allows for tests to access it.
89 protected PrintWriter log;
90 /**
91 * Contains the TestResult instance for the interface test to collect
92 * information about methods test.
94 protected TestResult tRes;
95 /**
96 * Contains names of the methods have been already called
98 private final ArrayList<String> methCalled = new ArrayList<String>(10);
101 * Disposes the current test environment, which was corrupted by the test.
103 * @see #disposeEnvironment(TestEnvironment)
105 public void disposeEnvironment()
107 tEnv.dispose();
108 TestCase tCase = tEnv.getTestCase();
109 tCase.disposeTestEnvironment(tEnv, tParam);
113 * Runs the interface test: its method tests. First, it initializes some
114 * of MultiMethodTest fields, like tRes, log, tEnv, etc. Then, it queries
115 * the tested interface and initializes 'oObj' field (defined in a
116 * subclass). Before calling method tests, before() method calles to allow
117 * initialization of s stuff before testing. Then, the method tests are
118 * called. After them, after() method is called, to allow cleaning up the
119 * stuff initialized in before() and test methods.
121 * @param entry the interface test state
122 * @param tEnv the environment to test
123 * @param tParam the parameters of the test
125 * @see #before
126 * @see #after
128 public TestResult run(DescEntry entry, TestEnvironment tEnv, TestParameters tParam)
131 log = (PrintWriter) entry.Logger;
133 this.tEnv = tEnv;
134 this.tParam = tParam;
135 // this.log = log;
136 this.entry = entry;
137 this.tRes = new TestResult();
138 Class<?> testedClass;
140 // Some fake code for a self test.
141 // For normal test we must not be a "ifc.qadevooo._SelfTest"
142 if (! ("ifc.qadevooo._SelfTest").equals(entry.entryName))
144 getInterfaceName();
145 System.out.print("checking: [" + entry.longName + "]");
147 // defining a name of the class corresponding to the tested interface
148 // or service
149 String testedClassName;
151 testedClassName = getTestedClassName();
153 if (entry.EntryType.equals("service"))
155 testedClassName = "com.sun.star.beans.XPropertySet";
160 testedClass = Class.forName(testedClassName);
162 catch (ClassNotFoundException cnfE)
164 System.out.println();
165 cnfE.printStackTrace(log);
166 log.println("could not find a class : " + getTestedClassName());
167 return null;
169 System.out.println(" is iface: [" + testedClassName + "] testcode: [" + entry.entryName + "]");
171 Object oObj = UnoRuntime.queryInterface(testedClass, tEnv.getTestObject());
173 if (oObj == null)
175 if (entry.isOptional)
177 Summarizer.summarizeDown(entry, "Not supported but optional.OK");
179 else
181 Summarizer.summarizeDown(entry, "queryInterface returned null.FAILED");
182 entry.ErrorMsg = "queryInterface returned null";
183 entry.hasErrorMsg = true;
186 return null;
189 //setting the field oObj
192 setField("oObj", oObj);
194 catch (Exception e)
196 e.printStackTrace();
197 setSubStates(e.toString());
198 return tRes;
202 // to perform some stuff before all method tests
205 before();
207 catch (Exception e)
209 e.printStackTrace();
210 setSubStates(e.toString());
211 return tRes;
214 // executing methods tests
215 for (int i = 0; i < entry.SubEntryCount; i++)
217 DescEntry aSubEntry = entry.SubEntries[i];
220 final String sEntryName = aSubEntry.entryName;
221 executeMethod(sEntryName);
223 catch (Exception e)
225 log.println("Exception while checking: " + aSubEntry.entryName + " : " + e.getMessage());
229 // to perform some stuff after all method tests
232 after();
234 catch (Exception e)
238 return tRes;
242 * Is called before calling method tests, but after initialization.
243 * Subclasses may override to perform actions before method tests.
245 protected void before()
250 * Is called after calling method tests. Subclasses may override
251 * to perform actions after method tests.
253 protected void after()
258 * @return the name of the interface or the service tested.
260 protected String getTestedClassName()
262 String clsName = this.getClass().getName();
264 int firstDot = clsName.indexOf('.');
265 int lastDot = clsName.lastIndexOf('.');
267 String append = "com.sun.star.";
269 if (entry.longName.indexOf("::drafts::com::") > -1)
271 append = "drafts.com.sun.star.";
274 return append + clsName.substring(firstDot + 1, lastDot + 1) + clsName.substring(lastDot + 2);
278 * Sets a method status.
280 * @param methName the method name to set status
281 * @param methStatus the status to set to the method
283 private void setStatus(String methName, Status methStatus)
285 tRes.tested(methName, methStatus);
289 * sets the substates
291 private void setSubStates(String msg)
293 for (int k = 0; k < entry.SubEntryCount; k++)
295 entry.SubEntries[k].hasErrorMsg = true;
296 entry.SubEntries[k].ErrorMsg = msg;
297 if (entry.SubEntries[k].State.equals("UNKNOWN"))
299 entry.SubEntries[k].State = msg;
306 * Checks if the <code>method</code> is optional in the service.
308 protected boolean isOptional(String _method)
310 for (int k = 0; k < entry.SubEntryCount; k++)
312 final String sName = entry.SubEntries[k].entryName;
313 if (sName.equals(_method))
315 final boolean bIsOptional = entry.SubEntries[k].isOptional;
316 return bIsOptional;
319 return false;
323 * Checks if the <code>method</code> test has been already called.
325 private boolean isCalled(String method)
327 return methCalled.contains(method);
331 * Calling of the method indicates that the <code>method</code> test should
332 * be called. The method checks this and if it is not called, calls it.
333 * If the method is failed or skipped, it throws StatusException.
335 protected void requiredMethod(String method)
337 log.println("starting required method: " + method);
338 executeMethod(method);
339 Status mtStatus = tRes.getStatusFor(method);
341 if (mtStatus != null && (!mtStatus.isPassed() || mtStatus.isFailed()))
343 log.println("! Required method " + method + " failed");
344 throw new StatusException(mtStatus);
349 * Checks if the <code>method</code> was called, and if not, call it.
350 * On contrary to requiredMethod(), he method doesn't check its status.
352 protected void executeMethod(String method)
354 if (!isCalled(method))
356 log.println("Execute: " + method);
357 callMethod(method);
358 log.println(method + ": " + tRes.getStatusFor(method));
359 log.println();
364 * Just calls the <code>method</code> test.
366 private void callMethod(String method)
368 methCalled.add(method);
369 invokeTestMethod(getMethodFor(method), method);
373 * Invokes a test method of the subclass using reflection API. Handles
374 * the method results and sets its status.
376 * @param meth the subclass' method to invoke
377 * @param methName the name of the method
379 protected void invokeTestMethod(Method meth, String methName)
381 if (meth == null)
383 setStatus(methName, Status.skipped(false));
385 else
387 Status stat;
391 meth.invoke(this, new Object[0]);
392 return;
394 catch (InvocationTargetException itE)
396 Throwable t = itE.getTargetException();
398 if (t instanceof StatusException)
400 stat = ((StatusException) t).getStatus();
402 else
404 t.printStackTrace(log);
405 stat = Status.exception(t);
408 catch (IllegalAccessException iaE)
410 iaE.printStackTrace(log);
411 stat = Status.exception(iaE);
413 catch (IllegalArgumentException iaE)
415 iaE.printStackTrace(log);
416 stat = Status.exception(iaE);
418 catch (ClassCastException ccE)
420 ccE.printStackTrace(log);
421 stat = Status.exception(ccE);
424 setStatus(methName, stat);
429 * Finds a testing method for the <code>method</code> of the interface.
431 * @return the testing method, if found, <tt>null</tt> otherwise
433 private Method getMethodFor(String method)
435 String mName = "_" + method;
437 if (mName.endsWith("()"))
439 mName = mName.substring(0, mName.length() - 2);
442 final Class<?>[] paramTypes = new Class[0];
446 return this.getClass().getDeclaredMethod(mName, paramTypes);
448 catch (NoSuchMethodException nsmE)
450 return null;
455 * @return the name of the interface tested
457 public String getInterfaceName()
459 String clName = this.getClass().getName();
460 return clName.substring(clName.lastIndexOf('.') + 1);
463 private void setField(String fieldName, Object value)
464 throws NoSuchFieldException, IllegalAccessException
466 this.getClass().getField(fieldName).set(this, value);