001: /*
002: *
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
004: *
005: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
006: *
007: * The contents of this file are subject to the terms of either the GNU
008: * General Public License Version 2 only ("GPL") or the Common
009: * Development and Distribution License("CDDL") (collectively, the
010: * "License"). You may not use this file except in compliance with the
011: * License. You can obtain a copy of the License at
012: * http://www.netbeans.org/cddl-gplv2.html
013: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
014: * specific language governing permissions and limitations under the
015: * License. When distributing the software, include this License Header
016: * Notice in each file and include the License file at
017: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
018: * particular file as subject to the "Classpath" exception as provided
019: * by Sun in the GPL Version 2 section of the License file that
020: * accompanied this code. If applicable, add the following below the
021: * License Header, with the fields enclosed by brackets [] replaced by
022: * your own identifying information:
023: * "Portions Copyrighted [year] [name of copyright owner]"
024: *
025: * Contributor(s):
026: *
027: * The Original Software is NetBeans. The Initial Developer of the Original
028: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
029: * Microsystems, Inc. All Rights Reserved.
030: *
031: * If you wish your version of this file to be governed by only the CDDL
032: * or only the GPL Version 2, indicate your decision by adding
033: * "[Contributor] elects to include this software in this distribution
034: * under the [CDDL or GPL Version 2] license." If you do not indicate a
035: * single choice of license, a recipient has the option to distribute
036: * your version of this file under either the CDDL, the GPL Version 2 or
037: * to extend the choice of license to its licensees as provided above.
038: * However, if you add GPL Version 2 code and therefore, elected the GPL
039: * Version 2 license, then the option applies only if the new code is
040: * made subject to such option by the copyright holder.
041: */
042:
043: package org.netbeans.xtest.testrunner;
044:
045: import java.io.*;
046: import java.util.*;
047: import org.netbeans.junit.Filter;
048:
049: /**
050: *
051: * @author breh
052: */
053: public class JUnitTestRunnerProperties {
054:
055: // junit runner understood properties
056: // suites and their filters - in real property file
057: // suites are present as:
058: // xtest.junit-test-runner.testsuite/1=my.test.MySuite
059: // xtest.junit-test-runner.testsuite.filter.exclude/1/1=my.test.MySuite.myExclFilteredMethod
060: // xtest.junit-test-runner.testsuite.filter.include/1/2=my.test.MySuite.myInclFilteredMethod
061: static final String TEST_TO_EXECUTE = "xtest.junit-test-runner.test/";
062: static final String TEST_FILTER_INCLUDE = "xtest.junit-test-runner.test-filter.include/";
063: static final String TEST_FILTER_EXCLUDE = "xtest.junit-test-runner.test-filter.exclude/";
064: static final String TEST_FILTER_EXPECTED_FAIL = "xtest.junit-test-runner.test-filter.expected-fail/";
065: static final String TESTBAG_SETUP_CLASS = "xtest.testbag.setup.class";
066: static final String TESTBAG_TEARDOWN_CLASS = "xtest.testbag.teardown.class";
067: static final String TESTBAG_SETUP_METHOD = "xtest.testbag.setup.method";
068: static final String TESTBAG_TEARDOWN_METHOD = "xtest.testbag.teardown.method";
069:
070: // testrun type stuff
071: static final String TESTRUN_TYPE = "xtest.junit-test-runner.testrun-type";
072:
073: // dir property where xml results should be places
074: public static final String RESULTS_DIRECTORY = "xtest.junit-test-runner.result-dir";
075:
076: private static final String HEADER = "JUnitTestRunner properties";
077:
078: // index of added test names
079: private int testIndex;
080:
081: // indicates whether properties need to be parsed
082: private boolean needToParse;
083:
084: /** Creates a new instance of JUnitTestRunnerProperties */
085: public JUnitTestRunnerProperties() {
086: runnerProperties = new Properties();
087: needToParse = true;
088: testIndex = 0;
089: }
090:
091: public static JUnitTestRunnerProperties load(String filename)
092: throws IOException {
093: return load(new File(filename));
094: }
095:
096: public static JUnitTestRunnerProperties load(File file)
097: throws IOException {
098: JUnitTestRunnerProperties jutrProperties = new JUnitTestRunnerProperties();
099: jutrProperties.runnerProperties = new Properties();
100: InputStream is = new FileInputStream(file);
101: jutrProperties.runnerProperties.load(is);
102: // parse the properties
103: jutrProperties.parseRunnerProperties();
104: is.close();
105: return jutrProperties;
106: }
107:
108: public void save(File propFile, boolean overwrite)
109: throws IOException {
110:
111: if (propFile.exists()) {
112: if (!overwrite) {
113: throw new IOException("File " + propFile
114: + " already exists");
115: }
116: }
117: OutputStream os = new FileOutputStream(propFile);
118: runnerProperties.store(os, HEADER);
119: os.close();
120: }
121:
122: public void save(File propFile) throws IOException {
123: save(propFile, true);
124: }
125:
126: public void save(String filename, boolean overwrite)
127: throws IOException {
128: File propFile = new File(filename);
129: save(propFile, overwrite);
130: }
131:
132: public void save(String filename) throws IOException {
133: save(filename, true);
134: }
135:
136: // API
137: public void addTestName(String testName) {
138: addTestNameWithFilter(testName, null, null);
139: }
140:
141: public void addTestNameWithFilter(String testName,
142: Filter.IncludeExclude[] includes,
143: Filter.IncludeExclude[] excludes) {
144: runnerProperties.setProperty(getTestPropertyName(testIndex),
145: testName);
146: if (includes != null) {
147: for (int i = 0; i < includes.length; i++) {
148: if (includes[i].getName() != null)
149: runnerProperties.setProperty(
150: getIncludeFilterPropertyName(testIndex, i),
151: includes[i].getName());
152: if (includes[i].getExpectedFail() != null)
153: runnerProperties.setProperty(
154: getExpectedFailFilterPropertyName(
155: testIndex, i), includes[i]
156: .getExpectedFail());
157: }
158: }
159: if (excludes != null) {
160: for (int i = 0; i < excludes.length; i++) {
161: runnerProperties.setProperty(
162: getExcludeFilterPropertyName(testIndex, i),
163: excludes[i].getName());
164: }
165: }
166: testIndex++;
167: needToParse = true;
168: }
169:
170: public String[] getTestNames() {
171: parseRunnerProperties();
172: return testNames;
173: }
174:
175: public Filter.IncludeExclude[] getTestFilterIncludes(int testIndex) {
176: parseRunnerProperties();
177: if ((testIndex >= 0) & (testIndex < testFilterIncludes.length)) {
178: return testFilterIncludes[testIndex];
179: } else {
180: return null;
181: }
182: }
183:
184: public Filter.IncludeExclude[] getTestFilterExcludes(int testIndex) {
185: parseRunnerProperties();
186: if ((testIndex >= 0) & (testIndex < testFilterExcludes.length)) {
187: /*
188: for (int i=0; i < testFilterExcludes[testIndex].length; i++) {
189: System.out.println("**** Returning exclude:"+testFilterExcludes[testIndex][i]);
190: }
191: */
192: return testFilterExcludes[testIndex];
193: } else {
194: return null;
195: }
196: }
197:
198: public String getTestRunType() {
199: return runnerProperties.getProperty(TESTRUN_TYPE);
200: }
201:
202: public void setTestRunType(String value) {
203: if (value != null) {
204: runnerProperties.setProperty(TESTRUN_TYPE, value);
205: }
206: }
207:
208: public String getTestbagSetupClassName() {
209: return setupClassName;
210: }
211:
212: public String getTestbagSetupMethodName() {
213: return setupMethodName;
214: }
215:
216: public String getTestbagTeardownClassName() {
217: return teardownClassName;
218: }
219:
220: public String getTestbagTeardownMethodName() {
221: return teardownMethodName;
222: }
223:
224: public void setTestbagSetup(String className, String methodName) {
225: if ((className == null) || (methodName == null)) {
226: throw new NullPointerException(
227: "className or methodName cannot be null");
228: }
229: setupClassName = className;
230: setupMethodName = methodName;
231: runnerProperties.setProperty(TESTBAG_SETUP_CLASS, className);
232: runnerProperties.setProperty(TESTBAG_SETUP_METHOD, methodName);
233: }
234:
235: public void setTestbagTeardown(String className, String methodName) {
236: if ((className == null) || (methodName == null)) {
237: throw new NullPointerException(
238: "className or methodName cannot be null");
239: }
240: teardownClassName = className;
241: teardownMethodName = methodName;
242: runnerProperties.setProperty(TESTBAG_TEARDOWN_CLASS, className);
243: runnerProperties.setProperty(TESTBAG_TEARDOWN_METHOD,
244: methodName);
245: }
246:
247: public String getResultsDirName() {
248: return runnerProperties.getProperty(RESULTS_DIRECTORY);
249: }
250:
251: public void setResultsDirName(String value) {
252: if (value != null) {
253: runnerProperties.setProperty(RESULTS_DIRECTORY, value);
254: }
255: }
256:
257: public JUnitTestRunnerProperties[] divideByTests() {
258: Vector properties = new Vector();
259: parseRunnerProperties();
260: // testbag setup
261: if (getTestbagSetupClassName() != null) {
262: JUnitTestRunnerProperties prop = new JUnitTestRunnerProperties();
263: prop.setTestbagSetup(getTestbagSetupClassName(),
264: getTestbagSetupMethodName());
265: prop.setResultsDirName(getResultsDirName());
266: properties.add(prop);
267: }
268: // testbag tests
269: for (int i = 0; i < testNames.length; i++) {
270: JUnitTestRunnerProperties prop = new JUnitTestRunnerProperties();
271: prop.setResultsDirName(getResultsDirName());
272: prop.setTestRunType(getTestRunType());
273: prop.addTestNameWithFilter(testNames[i],
274: testFilterIncludes[i], testFilterExcludes[i]);
275: // is parsing really necessary ????
276: prop.parseRunnerProperties();
277: properties.add(prop);
278: }
279: // testbag teardown
280: if (getTestbagTeardownClassName() != null) {
281: JUnitTestRunnerProperties prop = new JUnitTestRunnerProperties();
282: prop.setTestbagTeardown(getTestbagTeardownClassName(),
283: getTestbagTeardownMethodName());
284: prop.setResultsDirName(getResultsDirName());
285: properties.add(prop);
286: }
287:
288: return (JUnitTestRunnerProperties[]) properties
289: .toArray(new JUnitTestRunnerProperties[0]);
290: }
291:
292: public void list(PrintStream out) {
293: runnerProperties.list(out);
294: }
295:
296: //public String
297:
298: // private stuff
299:
300: // properties - they have it all :-)
301: private Properties runnerProperties;
302: // test names
303: private String[] testNames;
304: // includes
305: private Filter.IncludeExclude[][] testFilterIncludes;
306: // excludes
307: private Filter.IncludeExclude[][] testFilterExcludes;
308:
309: // setup/teardown classes and methods
310: private String setupClassName;
311: private String setupMethodName;
312: private String teardownClassName;
313: private String teardownMethodName;
314:
315: // get the first number from tests/filterr in format "TEST_/testID{/filterID)"
316: static Integer getTestID(String propertyName) {
317: if (propertyName == null)
318: throw new NullPointerException(
319: "propertyName cannot be null");
320: Integer testID = null;
321: String testIDString = null;
322: if (propertyName.startsWith(TEST_TO_EXECUTE)) {
323: testIDString = propertyName.substring(TEST_TO_EXECUTE
324: .length());
325: // we should have suite number string - convert it to suiteNumber
326:
327: } else if (propertyName.startsWith(TEST_FILTER_INCLUDE)) {
328: // filter is a bit more complicated
329: String filterSuffix = propertyName
330: .substring(TEST_FILTER_INCLUDE.length());
331: testIDString = filterSuffix.substring(0, filterSuffix
332: .lastIndexOf('/'));
333: } else if (propertyName.startsWith(TEST_FILTER_EXCLUDE)) {
334: // filter is a bit more complicated
335: String filterSuffix = propertyName
336: .substring(TEST_FILTER_EXCLUDE.length());
337: testIDString = filterSuffix.substring(0, filterSuffix
338: .lastIndexOf('/'));
339: } else if (propertyName.startsWith(TEST_FILTER_EXPECTED_FAIL)) {
340: // filter is a bit more complicated
341: String filterSuffix = propertyName
342: .substring(TEST_FILTER_EXPECTED_FAIL.length());
343: testIDString = filterSuffix.substring(0, filterSuffix
344: .lastIndexOf('/'));
345: }
346: try {
347: if (testIDString != null) {
348: testID = new Integer(testIDString);
349: }
350: } catch (NumberFormatException nfe) {
351: // id cannot be converted
352: // just swallow the exception and return null;
353: }
354: return testID;
355: }
356:
357: // get the second number from filter in format "TEST_FILTER/testID/filterID"
358: static Integer getFilterID(String propertyName) {
359: if (propertyName == null)
360: throw new NullPointerException(
361: "propertyName cannot be null");
362: Integer filterID = null;
363: String filterIDString = null;
364: if (propertyName
365: .startsWith(JUnitTestRunnerProperties.TEST_FILTER_INCLUDE)) {
366: filterIDString = propertyName.substring(propertyName
367: .lastIndexOf('/') + 1);
368: } else if (propertyName
369: .startsWith(JUnitTestRunnerProperties.TEST_FILTER_EXCLUDE)) {
370: filterIDString = propertyName.substring(propertyName
371: .lastIndexOf('/') + 1);
372: } else if (propertyName
373: .startsWith(JUnitTestRunnerProperties.TEST_FILTER_EXPECTED_FAIL)) {
374: filterIDString = propertyName.substring(propertyName
375: .lastIndexOf('/') + 1);
376: }
377: try {
378: if (filterIDString != null) {
379: filterID = new Integer(filterIDString);
380: }
381: } catch (NumberFormatException nfe) {
382: // id cannot be converted
383: // just swallow the exception and return null;
384: }
385: return filterID;
386: }
387:
388: // private method, which parses the property object and fills arrays test, filters ...
389: void parseRunnerProperties() {
390: if (needToParse) {
391: HashMap testNames = new HashMap();
392: HashMap filterIncludes = new HashMap();
393: HashMap filterExcludes = new HashMap();
394: Enumeration keys = runnerProperties.keys();
395: while (keys.hasMoreElements()) {
396: String key = (String) keys.nextElement();
397: if (key.startsWith(TEST_TO_EXECUTE)) {
398: // get the suite number
399: Integer testID = getTestID(key);
400: String testName = runnerProperties.getProperty(key);
401: if (testName != null) {
402: testNames.put(testID, testName);
403: } else {
404: // test name is null - this suite is ignored
405: // there is also no reason to notify user
406: // only for debugging purposes
407: System.err
408: .println("Cannot find test class for key "
409: + key);
410: }
411: } else if (key.startsWith(TESTBAG_SETUP_CLASS)) {
412: setupClassName = runnerProperties.getProperty(key);
413: } else if (key.startsWith(TESTBAG_SETUP_METHOD)) {
414: setupMethodName = runnerProperties.getProperty(key);
415: } else if (key.startsWith(TESTBAG_TEARDOWN_CLASS)) {
416: teardownClassName = runnerProperties
417: .getProperty(key);
418: } else if (key.startsWith(TESTBAG_TEARDOWN_METHOD)) {
419: teardownMethodName = runnerProperties
420: .getProperty(key);
421:
422: } else if (key.startsWith(TEST_FILTER_INCLUDE)
423: | key.startsWith(TEST_FILTER_EXCLUDE)
424: | key.startsWith(TEST_FILTER_EXPECTED_FAIL)) {
425: String value = runnerProperties.getProperty(key);
426: if (value != null) {
427: Integer testID = getTestID(key);
428: if (key.startsWith(TEST_FILTER_INCLUDE)) {
429: // install include filter if not yet installed
430: TreeMap includeFilters = (TreeMap) filterIncludes
431: .get(testID);
432: if (includeFilters == null) {
433: includeFilters = new TreeMap();
434: filterIncludes.put(testID,
435: includeFilters);
436: }
437: Integer filterID = getFilterID(key);
438: Filter.IncludeExclude valueObject = (Filter.IncludeExclude) includeFilters
439: .get(filterID);
440: if (valueObject == null) {
441: valueObject = new Filter.IncludeExclude();
442: includeFilters.put(filterID,
443: valueObject);
444: }
445: valueObject.setName(value);
446: } else if (key.startsWith(TEST_FILTER_EXCLUDE)) {
447: // install exclude filter
448: TreeMap excludeFilters = (TreeMap) filterExcludes
449: .get(testID);
450: if (excludeFilters == null) {
451: excludeFilters = new TreeMap();
452: filterExcludes.put(testID,
453: excludeFilters);
454: }
455: excludeFilters.put(getFilterID(key),
456: new Filter.IncludeExclude(value,
457: null));
458: } else if (key
459: .startsWith(TEST_FILTER_EXPECTED_FAIL)) {
460: // install expected fails
461: TreeMap includeFilters = (TreeMap) filterIncludes
462: .get(testID);
463: if (includeFilters == null) {
464: includeFilters = new TreeMap();
465: filterIncludes.put(testID,
466: includeFilters);
467: }
468: Integer filterID = getFilterID(key);
469: Filter.IncludeExclude valueObject = (Filter.IncludeExclude) includeFilters
470: .get(filterID);
471: if (valueObject == null) {
472: valueObject = new Filter.IncludeExclude();
473: includeFilters.put(filterID,
474: valueObject);
475: }
476: valueObject.setExpectedFail(value);
477: }
478: }
479: }
480: }
481:
482: // now create arrays from test names and filter includes/excludes
483: this .testNames = new String[testNames.size()];
484: // incldues/excludes arrays
485: this .testFilterIncludes = new Filter.IncludeExclude[testNames
486: .size()][];
487: this .testFilterExcludes = new Filter.IncludeExclude[testNames
488: .size()][];
489: int i = 0;
490: // sort the keys in ascending order
491: List keyList = new ArrayList();
492: keyList.addAll(testNames.keySet());
493: Collections.sort(keyList);
494: Iterator keyListIterator = keyList.iterator();
495: while (keyListIterator.hasNext()) {
496: Integer key = (Integer) keyListIterator.next();
497: String testName = (String) testNames.get(key);
498: this .testNames[i] = testName;
499: // now includes/excludes
500: if (filterIncludes.containsKey(key)) {
501: TreeMap includes = (TreeMap) filterIncludes
502: .get(key);
503: // convert the includes into String array which then assign to testFilterIncludes;
504: this .testFilterIncludes[i] = (Filter.IncludeExclude[]) (includes
505: .values()
506: .toArray(new Filter.IncludeExclude[0]));
507: }
508: if (filterExcludes.containsKey(key)) {
509: TreeMap excludes = (TreeMap) filterExcludes
510: .get(key);
511: // convert the excludes into String array which then assign to testFilterExcludes;
512: this .testFilterExcludes[i] = (Filter.IncludeExclude[]) (excludes
513: .values()
514: .toArray(new Filter.IncludeExclude[0]));
515: }
516: i++;
517: }
518: testIndex = i;
519: needToParse = false;
520: }
521: }
522:
523: //
524: private static String getTestPropertyName(int testIndex) {
525: return TEST_TO_EXECUTE + testIndex;
526: }
527:
528: private static String getIncludeFilterPropertyName(int testIndex,
529: int filterIndex) {
530: return TEST_FILTER_INCLUDE + testIndex + '/' + filterIndex;
531: }
532:
533: private static String getExcludeFilterPropertyName(int testIndex,
534: int filterIndex) {
535: return TEST_FILTER_EXCLUDE + testIndex + '/' + filterIndex;
536: }
537:
538: private static String getExpectedFailFilterPropertyName(
539: int testIndex, int filterIndex) {
540: return TEST_FILTER_EXPECTED_FAIL + testIndex + '/'
541: + filterIndex;
542: }
543:
544: }
|