0001: /*
0002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003: *
0004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005: *
0006: * The contents of this file are subject to the terms of either the GNU
0007: * General Public License Version 2 only ("GPL") or the Common
0008: * Development and Distribution License("CDDL") (collectively, the
0009: * "License"). You may not use this file except in compliance with the
0010: * License. You can obtain a copy of the License at
0011: * http://www.netbeans.org/cddl-gplv2.html
0012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
0013: * specific language governing permissions and limitations under the
0014: * License. When distributing the software, include this License Header
0015: * Notice in each file and include the License file at
0016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
0017: * particular file as subject to the "Classpath" exception as provided
0018: * by Sun in the GPL Version 2 section of the License file that
0019: * accompanied this code. If applicable, add the following below the
0020: * License Header, with the fields enclosed by brackets [] replaced by
0021: * your own identifying information:
0022: * "Portions Copyrighted [year] [name of copyright owner]"
0023: *
0024: * Contributor(s):
0025: *
0026: * The Original Software is NetBeans. The Initial Developer of the Original
0027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
0028: * Microsystems, Inc. All Rights Reserved.
0029: *
0030: * If you wish your version of this file to be governed by only the CDDL
0031: * or only the GPL Version 2, indicate your decision by adding
0032: * "[Contributor] elects to include this software in this distribution
0033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
0034: * single choice of license, a recipient has the option to distribute
0035: * your version of this file under either the CDDL, the GPL Version 2 or
0036: * to extend the choice of license to its licensees as provided above.
0037: * However, if you add GPL Version 2 code and therefore, elected the GPL
0038: * Version 2 license, then the option applies only if the new code is
0039: * made subject to such option by the copyright holder.
0040: */
0041:
0042: package org.netbeans.modules.junit;
0043:
0044: import java.awt.BorderLayout;
0045: import java.awt.EventQueue;
0046: import java.awt.GridLayout;
0047: import java.awt.event.ActionListener;
0048: import java.io.IOException;
0049: import java.net.URL;
0050: import java.util.ArrayList;
0051: import java.util.Collection;
0052: import java.util.Collections;
0053: import java.util.HashMap;
0054: import java.util.HashSet;
0055: import java.util.LinkedList;
0056: import java.util.List;
0057: import java.util.Map;
0058: import java.util.Set;
0059: import java.util.logging.Logger;
0060: import java.util.regex.Matcher;
0061: import java.util.regex.Pattern;
0062: import javax.lang.model.element.TypeElement;
0063: import javax.swing.BorderFactory;
0064: import javax.swing.ButtonGroup;
0065: import javax.swing.JButton;
0066: import javax.swing.JComponent;
0067: import javax.swing.JPanel;
0068: import javax.swing.JRadioButton;
0069: import org.netbeans.api.java.classpath.ClassPath;
0070: import org.netbeans.api.java.project.classpath.ProjectClassPathModifier;
0071: import org.netbeans.api.java.queries.UnitTestForSourceQuery;
0072: import org.netbeans.api.java.source.ElementHandle;
0073: import org.netbeans.api.java.source.JavaSource;
0074: import org.netbeans.api.project.FileOwnerQuery;
0075: import org.netbeans.api.project.Project;
0076: import org.netbeans.api.project.ProjectManager;
0077: import org.netbeans.api.project.ProjectUtils;
0078: import org.netbeans.api.project.SourceGroup;
0079: import org.netbeans.api.project.Sources;
0080: import org.netbeans.api.project.libraries.Library;
0081: import org.netbeans.api.project.libraries.LibraryManager;
0082: import org.netbeans.modules.junit.TestabilityResult.SkippedClass;
0083: import org.netbeans.modules.junit.plugin.JUnitPlugin;
0084: import org.netbeans.modules.junit.plugin.JUnitPlugin.CreateTestParam;
0085: import org.netbeans.modules.junit.plugin.JUnitPlugin.Location;
0086: import org.netbeans.modules.junit.wizards.Utils;
0087: import org.netbeans.spi.java.classpath.ClassPathProvider;
0088: import org.netbeans.spi.java.classpath.support.ClassPathSupport;
0089: import org.openide.DialogDescriptor;
0090: import org.openide.DialogDisplayer;
0091: import org.openide.ErrorManager;
0092: import org.openide.NotifyDescriptor;
0093: import org.openide.awt.Mnemonics;
0094: import org.openide.cookies.SaveCookie;
0095: import org.openide.filesystems.FileObject;
0096: import org.openide.filesystems.FileUtil;
0097: import org.openide.filesystems.Repository;
0098: import org.openide.loaders.DataFolder;
0099: import org.openide.loaders.DataObject;
0100: import org.openide.loaders.DataObjectNotFoundException;
0101: import org.openide.util.HelpCtx;
0102: import org.openide.util.Mutex;
0103: import org.openide.util.NbBundle;
0104: import static java.util.logging.Level.FINER;
0105: import static java.util.logging.Level.FINEST;
0106: import static javax.lang.model.util.ElementFilter.methodsIn;
0107: import static javax.lang.model.util.ElementFilter.typesIn;
0108: import static org.netbeans.api.java.classpath.ClassPath.SOURCE;
0109: import static org.netbeans.api.java.classpath.ClassPath.COMPILE;
0110: import static org.netbeans.api.java.classpath.ClassPath.BOOT;
0111: import static org.netbeans.api.java.project.JavaProjectConstants.SOURCES_TYPE_JAVA;
0112: import static org.netbeans.modules.junit.JUnitSettings.JUNIT_GENERATOR_ASK_USER;
0113: import static org.openide.ErrorManager.ERROR;
0114: import static org.openide.ErrorManager.WARNING;
0115: import static org.openide.NotifyDescriptor.CANCEL_OPTION;
0116: import static org.openide.NotifyDescriptor.OK_CANCEL_OPTION;
0117: import static org.openide.NotifyDescriptor.QUESTION_MESSAGE;
0118: import static org.openide.NotifyDescriptor.WARNING_MESSAGE;
0119:
0120: /**
0121: * Default JUnit plugin.
0122: *
0123: * @author Marian Petras
0124: */
0125: public final class DefaultPlugin extends JUnitPlugin {
0126:
0127: /** logger for logging management of JUnit libraries */
0128: private static final Logger LOG_JUNIT_VER = Logger
0129: .getLogger(DefaultPlugin.class.getName()
0130: + "_JUnit_version_handling"); //NOI18N
0131:
0132: /** full name of a file specific for the JUnit 3.8.x library */
0133: private static final String JUNIT3_SPECIFIC = "junit/awtui/TestRunner.class"; //NOI18N
0134: /** full name of a file specific for the JUnit 4.x library */
0135: private static final String JUNIT4_SPECIFIC = "org/junit/Test.class"; //NOI18N
0136:
0137: /** */
0138: private JUnitVersion junitVer;
0139:
0140: /** name of FreeMarker template property - generate {@code @BeforeClass} method? */
0141: private static final String templatePropBeforeClass = "classSetUp"; //NOI18N
0142: /** name of FreeMarker template property - generate {@code @AfterClass} method? */
0143: private static final String templatePropAfterClass = "classTearDown";//NOI18N
0144: /** name of FreeMarker template property - generate {@code @Before} method? */
0145: private static final String templatePropBefore = "methodSetUp"; //NOI18N
0146: /** name of FreeMarker template property - generate {@code @After} method? */
0147: private static final String templatePropAfter = "methodTearDown"; //NOI18N
0148: /** name of FreeMarker template property - generate in-method source code hints? */
0149: private static final String templatePropCodeHints = "sourceCodeHint"; //NOI18N
0150: /** name of FreeMarker template property - generate hints - method placeholders? */
0151: private static final String templatePropMethodPH = "testMethodsPlaceholder"; //NOI18N
0152: /** name of FreeMarker template property - use Java annotations? */
0153: private static final String templatePropUseAnnotations = "useAnnotations"; //NOI18N
0154: /** name of FreeMarker template property - list of class names */
0155: private static final String templatePropClassNames = "classNames"; //NOI18N
0156: /**
0157: * name of FreeMarker template property - list of class names,
0158: * each with a suffix <code>".class"</code>
0159: */
0160: private static final String templatePropClasses = "classes"; //NOI18N
0161:
0162: /** */
0163: private static java.util.ResourceBundle bundle = org.openide.util.NbBundle
0164: .getBundle(DefaultPlugin.class);
0165:
0166: /**
0167: *
0168: */
0169: @Override
0170: protected boolean canCreateTests(FileObject... fileObjects) {
0171: if (fileObjects.length == 0) {
0172: return false;
0173: }
0174:
0175: final FileObject firstFile = fileObjects[0];
0176: final SourceGroup sourceGroup = findSourceGroup(firstFile);
0177: if (sourceGroup == null) {
0178: return false;
0179: }
0180: final FileObject rootFolder = sourceGroup.getRootFolder();
0181: if (UnitTestForSourceQuery.findUnitTests(rootFolder).length == 0) {
0182: return false;
0183: }
0184:
0185: /*
0186: * Now we know that source folder of the first file has a corresponding
0187: * test folder (possible non-existent).
0188: */
0189: if (fileObjects.length == 1) {
0190: /* ... if there is just one file selected, it is all we need: */
0191: return true;
0192: }
0193:
0194: /*
0195: * ...for multiple files, we just check that all the selected files
0196: * have the same root folder:
0197: */
0198: for (int i = 1; i < fileObjects.length; i++) {
0199: FileObject fileObj = fileObjects[i];
0200: if (!FileUtil.isParentOf(rootFolder, fileObj)
0201: || !sourceGroup.contains(fileObj)) {
0202: return false;
0203: }
0204: }
0205: return true;
0206: }
0207:
0208: /**
0209: * Finds a Java source group the given file belongs to.
0210: *
0211: * @param file {@code FileObject} to find a {@code SourceGroup} for
0212: * @return the found {@code SourceGroup}, or {@code null} if the given
0213: * file does not belong to any Java source group
0214: */
0215: private static SourceGroup findSourceGroup(FileObject file) {
0216: final Project project = FileOwnerQuery.getOwner(file);
0217: if (project == null) {
0218: return null;
0219: }
0220:
0221: Sources src = ProjectUtils.getSources(project);
0222: SourceGroup[] srcGrps = src.getSourceGroups(SOURCES_TYPE_JAVA);
0223: for (SourceGroup srcGrp : srcGrps) {
0224: FileObject rootFolder = srcGrp.getRootFolder();
0225: if (((file == rootFolder) || FileUtil.isParentOf(
0226: rootFolder, file))
0227: && srcGrp.contains(file)) {
0228: return srcGrp;
0229: }
0230: }
0231: return null;
0232: }
0233:
0234: /**
0235: *
0236: */
0237: protected Location getTestLocation(Location sourceLocation) {
0238: FileObject fileObj = sourceLocation.getFileObject();
0239: ClassPath srcCp;
0240:
0241: if ((srcCp = ClassPath.getClassPath(fileObj, SOURCE)) == null) {
0242: return null;
0243: }
0244:
0245: String baseResName = srcCp.getResourceName(fileObj, '/', false);
0246: String testResName = !fileObj.isFolder() ? getTestResName(
0247: baseResName, fileObj.getExt())
0248: : getSuiteResName(baseResName);
0249: assert testResName != null;
0250:
0251: return getOppositeLocation(sourceLocation, srcCp, testResName,
0252: true);
0253: }
0254:
0255: /**
0256: *
0257: */
0258: protected Location getTestedLocation(Location testLocation) {
0259: FileObject fileObj = testLocation.getFileObject();
0260: ClassPath srcCp;
0261:
0262: if (fileObj.isFolder()
0263: || ((srcCp = ClassPath.getClassPath(fileObj, SOURCE)) == null)) {
0264: return null;
0265: }
0266:
0267: String baseResName = srcCp.getResourceName(fileObj, '/', false);
0268: String srcResName = getSrcResName(baseResName, fileObj.getExt());
0269: if (srcResName == null) {
0270: return null; //if the selectedFO is not a test class (by name)
0271: }
0272:
0273: return getOppositeLocation(testLocation, srcCp, srcResName,
0274: false);
0275: }
0276:
0277: /**
0278: *
0279: */
0280: private static Location getOppositeLocation(
0281: final Location sourceLocation, final ClassPath fileObjCp,
0282: final String oppoResourceName, final boolean sourceToTest) {
0283: FileObject fileObj = sourceLocation.getFileObject();
0284: FileObject fileObjRoot;
0285:
0286: if ((fileObjRoot = fileObjCp.findOwnerRoot(fileObj)) == null) {
0287: return null;
0288: }
0289:
0290: URL[] oppoRootsURLs = sourceToTest ? UnitTestForSourceQuery
0291: .findUnitTests(fileObjRoot) : UnitTestForSourceQuery
0292: .findSources(fileObjRoot);
0293: //if (sourceToTest && (oppoRootsURLs.length == 0)) {
0294: // PENDING - offer creation of new unit tests root
0295: //}
0296: if ((oppoRootsURLs == null) || (oppoRootsURLs.length == 0)) {
0297: return null;
0298: }
0299:
0300: ClassPath oppoRootsClassPath = ClassPathSupport
0301: .createClassPath(oppoRootsURLs);
0302: final List<FileObject> oppoFiles = oppoRootsClassPath
0303: .findAllResources(oppoResourceName);
0304: if (oppoFiles.isEmpty()) {
0305: //if (sourceToTest) {
0306: // PENDING - offer creation of new test class
0307: //}
0308: return null;
0309: }
0310:
0311: // final ElementHandle elementHandle = sourceLocation.getElementHandle();
0312: // if (elementHandle == null) {
0313: return new Location(oppoFiles.get(0)/*, null*/);
0314: // }
0315:
0316: // /* Build SOURCE classpath: */
0317: // ClassPath[] srcCpDelegates = new ClassPath[2];
0318: // if (sourceToTest) {
0319: // srcCpDelegates[0] = fileObjCp;
0320: // srcCpDelegates[1] = oppoRootsClassPath;
0321: // } else {
0322: // srcCpDelegates[0] = oppoRootsClassPath;
0323: // srcCpDelegates[1] = fileObjCp;
0324: // }
0325: // ClassPath srcClassPath
0326: // = ClassPathSupport.createProxyClassPath(srcCpDelegates);
0327: //
0328: // /* Build COMPILE classpath: */
0329: // FileObject[] oppoRoots = oppoRootsClassPath.getRoots();
0330: // ClassPath[] compCpDelegates = new ClassPath[oppoRoots.length + 1];
0331: // int delegateIndex = 0;
0332: // if (sourceToTest) {
0333: // compCpDelegates[delegateIndex++]
0334: // = ClassPath.getClassPath(fileObjRoot, COMPILE);
0335: // }
0336: // for (FileObject oppoRoot : oppoRoots) {
0337: // compCpDelegates[delegateIndex++]
0338: // = ClassPath.getClassPath(oppoRoot, COMPILE);
0339: // }
0340: // if (!sourceToTest) {
0341: // compCpDelegates[delegateIndex++]
0342: // = ClassPath.getClassPath(fileObjRoot, COMPILE);
0343: // }
0344: // ClassPath compClassPath
0345: // = ClassPathSupport.createProxyClassPath(compCpDelegates);
0346: //
0347: // /* Obtain the BOOT classpath: */
0348: // ClassPath bootClassPath = ClassPath.getClassPath(fileObj, BOOT);
0349: //
0350: // ClasspathInfo cpInfo = ClasspathInfo.create(bootClassPath,
0351: // compClassPath,
0352: // srcClassPath);
0353: // List<FileObject> files = new ArrayList<FileObject>(oppoFiles.size() + 1);
0354: // files.add(fileObj);
0355: // files.addAll(oppoFiles);
0356: // JavaSource javaSource = JavaSource.create(cpInfo, files);
0357: //
0358: // try {
0359: // MatchFinder matchFinder = new MatchFinder(sourceLocation,
0360: // oppoFiles,
0361: // sourceToTest);
0362: // javaSource.runUserActionTask(matchFinder, true);
0363: // return matchFinder.getResult();
0364: // } catch (IOException ex) {
0365: // Logger.getLogger("global").log(Level.SEVERE, null, ex); //NOI18N
0366: // return null;
0367: // }
0368: }
0369:
0370: // /**
0371: // *
0372: // */
0373: // private static final class MatchFinder
0374: // implements CancellableTask<CompilationController> {
0375: // private final FileObject currFile;
0376: // private final ElementHandle currElemHandle;
0377: // private final List<FileObject> oppoFiles;
0378: // private final boolean sourceToTest;
0379: //
0380: // private String currFilePkgPrefix;
0381: // private Element currElement;
0382: //
0383: // private volatile boolean cancelled;
0384: //
0385: // private String[] oppoClassNames;
0386: // private String oppoMethodName;
0387: // private int bestCandidateClassNamesCount;
0388: // private FileObject bestCandidateFile;
0389: // private Element bestCandidateElement;
0390: //
0391: // /** */
0392: // private FileObject oppoFile = null;
0393: // /** storage for the result */
0394: // private Element oppoElement = null;
0395: //
0396: // /**
0397: // *
0398: // */
0399: // private MatchFinder(Location currLocation,
0400: // List<FileObject> oppoFiles,
0401: // boolean sourceToTest) {
0402: // this.currFile = currLocation.getFileObject();
0403: // this.currElemHandle = currLocation.getElementHandle();
0404: // this.oppoFiles = oppoFiles;
0405: // this.sourceToTest = sourceToTest;
0406: // }
0407: //
0408: // /**
0409: // * This method is run once for the file referred by
0410: // * {@link #currLocation} and then once for each file contained
0411: // * in {@link #oppoFiles}.
0412: // *
0413: // * @param controller controller for the current run of this method
0414: // */
0415: // public void run(CompilationController controller) throws IOException {
0416: // if (oppoFile != null) {
0417: // /* We already have the result. */
0418: //
0419: // /*
0420: // * This should be only possible if there are multiple oppoFiles.
0421: // */
0422: // assert oppoFiles.size() > 1;
0423: // return;
0424: // }
0425: //
0426: // final FileObject runFile = controller.getFileObject();
0427: // if (runFile == currFile) {
0428: // resolveCurrentElement(controller); //--> currElement
0429: // return;
0430: // }
0431: //
0432: // if (currElement == null) {
0433: // /*
0434: // * The element for 'currLocation' was not resolved during
0435: // * the first run of this method on this instance.
0436: // */
0437: // return;
0438: // }
0439: // if ((oppoClassNames == null) || (oppoClassNames.length == 0)) {
0440: // return;
0441: // }
0442: //
0443: // controller.toPhase(Phase.PARSED);
0444: //
0445: // final Elements elements = controller.getElements();
0446: // TypeElement topClass = elements.getTypeElement(getCanonicalClassName(oppoClassNames[0]));
0447: // if ((topClass != null)
0448: // && !CLASS_LIKE_ELEM_TYPES.contains(topClass.getKind())) {
0449: // topClass = null;
0450: // }
0451: // if (cancelled || (topClass == null)) {
0452: // return;
0453: // }
0454: //
0455: // int classNamesCount = 0;
0456: // TypeElement bestClass = null;
0457: // TypeElement theSubClass = topClass;
0458: // while ((theSubClass != null) && (++classNamesCount < oppoClassNames.length)) {
0459: // bestClass = theSubClass;
0460: //
0461: // String oppoClassName = oppoClassNames[classNamesCount];
0462: // if (oppoClassName == null) {
0463: // break;
0464: // }
0465: //
0466: // theSubClass = null;
0467: // for (TypeElement subClass : typesIn(bestClass.getEnclosedElements())) {
0468: // if (cancelled) {
0469: // return;
0470: // }
0471: //
0472: // if (CLASS_LIKE_ELEM_TYPES.contains(subClass.getKind())
0473: // && subClass.getSimpleName().toString().equals(oppoClassName)) {
0474: // theSubClass = subClass;
0475: // break;
0476: // }
0477: // }
0478: // }
0479: // if (cancelled) {
0480: // return;
0481: // }
0482: // if (classNamesCount == oppoClassNames.length) {
0483: // bestClass = theSubClass; //this does not get called in the above while (...) cycle
0484: //
0485: // if (oppoMethodName == null) {
0486: // oppoFile = runFile;
0487: // oppoElement = bestClass;
0488: // } else {
0489: // ExecutableElement testMethod = findOppoMethod(bestClass);
0490: // if (testMethod != null) {
0491: // /* We found the test method! */
0492: // oppoFile = runFile;
0493: // oppoElement = testMethod;
0494: // }
0495: // }
0496: // if (oppoFile != null) {
0497: // return;
0498: // }
0499: // }
0500: //
0501: // if (classNamesCount > bestCandidateClassNamesCount) {
0502: // bestCandidateFile = runFile;
0503: // bestCandidateElement = bestClass;
0504: // bestCandidateClassNamesCount = classNamesCount;
0505: // }
0506: // }
0507: //
0508: // /**
0509: // */
0510: // private ExecutableElement findOppoMethod(TypeElement classElem) {
0511: // for (ExecutableElement elem : methodsIn(classElem.getEnclosedElements())) {
0512: // if (elem.getSimpleName().toString().equals(oppoMethodName)) {
0513: // if (!sourceToTest) {
0514: // return elem;
0515: // }
0516: // if (elem.getParameters().isEmpty()) {
0517: // Set<Modifier> modifiers = elem.getModifiers();
0518: // if (modifiers.contains(Modifier.PUBLIC)
0519: // && !modifiers.contains(Modifier.STATIC)) {
0520: // return elem;
0521: // }
0522: // }
0523: // break;
0524: // }
0525: // }
0526: // return null;
0527: // }
0528: //
0529: // public void cancel() {
0530: // cancelled = true;
0531: // }
0532: //
0533: // /**
0534: // */
0535: // private Location getResult() {
0536: // assert (oppoFile == null) == (oppoElement == null);
0537: //
0538: // return (oppoFile != null)
0539: // ? new Location(oppoFile, oppoElement)
0540: // : new Location(bestCandidateFile, bestCandidateElement);
0541: // }
0542: //
0543: // /**
0544: // * Resolves 'currElementHandle' and stores the result to 'currElement'.
0545: // */
0546: // private void resolveCurrentElement(CompilationController controller)
0547: // throws IOException {
0548: // String canonicalFileName
0549: // = controller.getClasspathInfo().getClassPath(PathKind.SOURCE)
0550: // .getResourceName(currFile, '.', false);
0551: // int lastDotIndex = canonicalFileName.lastIndexOf('.');
0552: // currFilePkgPrefix = (lastDotIndex != -1)
0553: // ? canonicalFileName.substring(0, lastDotIndex + 1)
0554: // : null;
0555: //
0556: // controller.toPhase(Phase.PARSED);
0557: // if (cancelled) {
0558: // return;
0559: // }
0560: // currElement = currElemHandle.resolve(controller);
0561: // if (currElement == null) {
0562: // Logger.getLogger(getClass().getName()).log(
0563: // Level.INFO,
0564: // "Could not resolve element " + currElemHandle); //NOI18N
0565: // return;
0566: // }
0567: //
0568: // if (cancelled) {
0569: // return;
0570: // }
0571: //
0572: // Element clsElement;
0573: // ElementKind currElemKind = currElement.getKind();
0574: // if (CLASS_LIKE_ELEM_TYPES.contains(currElement.getKind())) {
0575: // clsElement = currElement;
0576: // oppoMethodName = null;
0577: // } else {
0578: // clsElement = currElement.getEnclosingElement();
0579: // oppoMethodName = (currElemKind == ElementKind.METHOD)
0580: // ? getOppoMethodName(currElement.getSimpleName().toString())
0581: // : null; //no rule for finding tests for initializers
0582: // }
0583: // assert CLASS_LIKE_ELEM_TYPES.contains(clsElement.getKind());
0584: //
0585: // if (cancelled) {
0586: // return;
0587: // }
0588: //
0589: // oppoClassNames = buildOppoClassNames(clsElement);
0590: // if (oppoClassNames == null) {
0591: // oppoMethodName = null;
0592: // } else {
0593: // for (int i = 0; i < oppoClassNames.length; i++) {
0594: // if (oppoClassNames[i] == null) {
0595: // if (i == 0) {
0596: // oppoClassNames = null;
0597: // } else {
0598: // String[] newArray = new String[i];
0599: // System.arraycopy(oppoClassNames, 0, newArray, 0, i);
0600: // oppoClassNames = newArray;
0601: // }
0602: // oppoMethodName = null;
0603: // break;
0604: // }
0605: // }
0606: //
0607: // }
0608: // }
0609: //
0610: // /**
0611: // *
0612: // * @return may return {@code null} if this task has been cancelled
0613: // */
0614: // private String[] buildOppoClassNames(Element clsElement) {
0615: // String[] oppoClsNames;
0616: // String oppoClsName;
0617: //
0618: // Element clsParent = clsElement.getEnclosingElement();
0619: // if ((clsParent == null)
0620: // || !CLASS_LIKE_ELEM_TYPES.contains(clsParent.getKind())) {
0621: // oppoClsName = getOppoClassName(clsElement.getSimpleName().toString());
0622: // oppoClsNames = (oppoClsName != null)
0623: // ? new String[] {oppoClsName}
0624: // : null;
0625: // } else {
0626: // List<String> clsNames = new ArrayList<String>();
0627: // clsNames.add(clsElement.getSimpleName().toString());
0628: // do {
0629: // if (cancelled) {
0630: // return null;
0631: // }
0632: //
0633: // clsNames.add(clsParent.getSimpleName().toString());
0634: // clsParent = clsParent.getEnclosingElement();
0635: // } while ((clsParent != null)
0636: // && CLASS_LIKE_ELEM_TYPES.contains(clsParent.getKind()));
0637: //
0638: // if (cancelled) {
0639: // return null;
0640: // }
0641: //
0642: // final int size = clsNames.size();
0643: // oppoClsNames = new String[size];
0644: // for (int i = 0; i < size; i++) {
0645: // oppoClsName = getOppoClassName(clsNames.get(size - i - 1));
0646: // if (oppoClsName == null) {
0647: // break;
0648: // }
0649: // oppoClsNames[i] = oppoClsName;
0650: // }
0651: // }
0652: // return oppoClsNames;
0653: // }
0654: //
0655: // /**
0656: // */
0657: // private String getCanonicalClassName(String shortClassName) {
0658: // return (currFilePkgPrefix != null)
0659: // ? currFilePkgPrefix + shortClassName
0660: // : shortClassName;
0661: // }
0662: //
0663: // /**
0664: // */
0665: // private String getOppoClassName(String name) {
0666: // return sourceToTest ? getTestClassName(name)
0667: // : getSourceClassName(name);
0668: // }
0669: //
0670: // /**
0671: // */
0672: // private String getOppoMethodName(String name) {
0673: // return sourceToTest ? getTestMethodName(name)
0674: // : getSourceMethodName(name);
0675: // }
0676: //
0677: // }
0678:
0679: /**
0680: */
0681: private static String getTestResName(String baseResName, String ext) {
0682: StringBuilder buf = new StringBuilder(baseResName.length()
0683: + ext.length() + 10);
0684: buf.append(baseResName).append("Test"); //NOI18N
0685: if (ext.length() != 0) {
0686: buf.append('.').append(ext);
0687: }
0688: return buf.toString();
0689: }
0690:
0691: /**
0692: */
0693: private static String getSuiteResName(String baseResName) {
0694: if (baseResName.length() == 0) {
0695: return JUnitSettings.getDefault().getRootSuiteClassName();
0696: }
0697:
0698: final String suiteSuffix = "Suite"; //NOI18N
0699:
0700: String lastNamePart = baseResName.substring(baseResName
0701: .lastIndexOf('/') + 1);
0702:
0703: StringBuilder buf = new StringBuilder(baseResName.length()
0704: + lastNamePart.length() + suiteSuffix.length() + 6);
0705: buf.append(baseResName).append('/');
0706: buf.append(Character.toUpperCase(lastNamePart.charAt(0)))
0707: .append(lastNamePart.substring(1));
0708: buf.append(suiteSuffix);
0709: buf.append(".java"); //NOI18N
0710:
0711: return buf.toString();
0712: }
0713:
0714: /**
0715: */
0716: private static String getSrcResName(String testResName, String ext) {
0717: if (!testResName.endsWith("Test")) { //NOI18N
0718: return null;
0719: }
0720:
0721: StringBuilder buf = new StringBuilder(testResName.length()
0722: + ext.length());
0723: buf.append(testResName.substring(0, testResName.length() - 4));
0724: if (ext.length() != 0) {
0725: buf.append('.').append(ext);
0726: }
0727: return buf.toString();
0728: }
0729:
0730: /**
0731: */
0732: private static String getTestClassName(String baseClassName) {
0733: return baseClassName + "Test"; //NOI18N
0734: }
0735:
0736: /**
0737: */
0738: private static String getSourceClassName(String testClassName) {
0739: final String suffix = "Test"; //NOI18N
0740: final int suffixLen = suffix.length();
0741:
0742: return ((testClassName.length() > suffixLen) && testClassName
0743: .endsWith(suffix)) ? testClassName.substring(0,
0744: testClassName.length() - suffixLen) : null;
0745: }
0746:
0747: /**
0748: */
0749: private static String getTestMethodName(String baseMethodName) {
0750: final String prefix = "test"; //NOI18N
0751: final int prefixLen = prefix.length();
0752:
0753: StringBuffer buf = new StringBuffer(prefixLen
0754: + baseMethodName.length());
0755: buf.append(prefix).append(baseMethodName);
0756: buf.setCharAt(prefixLen, Character.toUpperCase(baseMethodName
0757: .charAt(0)));
0758: return buf.toString();
0759: }
0760:
0761: /**
0762: */
0763: private static String getSourceMethodName(String testMethodName) {
0764: final String prefix = "test"; //NOI18N
0765: final int prefixLen = prefix.length();
0766:
0767: return ((testMethodName.length() > prefixLen) && testMethodName
0768: .startsWith(prefix)) ? new StringBuilder(testMethodName
0769: .length()
0770: - prefixLen)
0771: .append(
0772: Character.toLowerCase(testMethodName
0773: .charAt(prefixLen))).append(
0774: testMethodName.substring(prefixLen + 1))
0775: .toString() : null;
0776: }
0777:
0778: /**
0779: * Creates test classes for given source classes.
0780: *
0781: * @param filesToTest source files for which test classes should be
0782: * created
0783: * @param targetRoot root folder of the target source root
0784: * @param params parameters of creating test class
0785: * @return created test files
0786: */
0787: @Override
0788: protected FileObject[] createTests(final FileObject[] filesToTest,
0789: final FileObject targetRoot,
0790: final Map<CreateTestParam, Object> params) {
0791: //XXX: not documented that in case that if filesToTest is <null>,
0792: //the target root param works as a target folder
0793:
0794: ProgressIndicator progress = new ProgressIndicator();
0795: progress.show();
0796:
0797: String msg = NbBundle.getMessage(CreateTestAction.class,
0798: "MSG_StatusBar_CreateTest_Begin"); //NOI18N
0799: progress.displayStatusText(msg);
0800:
0801: final TestCreator testCreator = new TestCreator(params,
0802: junitVer);
0803:
0804: CreationResults results;
0805: try {
0806: final String templateId;
0807: final String suiteTemplateId;
0808: boolean forTestSuite = (filesToTest != null)
0809: && (filesToTest.length != 0)
0810: && ((filesToTest.length > 1) || !filesToTest[0]
0811: .isData());
0812: final boolean useAnnotations;
0813: switch (junitVer) {
0814: case JUNIT3:
0815: templateId = "PROP_junit3_testClassTemplate"; //NOI18N
0816: suiteTemplateId = forTestSuite ? "PROP_junit3_testSuiteTemplate" //NOI18N
0817: : null;
0818: useAnnotations = TestUtil
0819: .areAnnotationsSupported(targetRoot);
0820: break;
0821: case JUNIT4:
0822: templateId = "PROP_junit4_testClassTemplate"; //NOI18N
0823: suiteTemplateId = forTestSuite ? "PROP_junit4_testSuiteTemplate" //NOI18N
0824: : null;
0825: useAnnotations = true;
0826: break;
0827: default:
0828: assert false;
0829: templateId = null;
0830: suiteTemplateId = null;
0831: useAnnotations = false;
0832: break;
0833: }
0834: DataObject doTestTempl = (templateId != null) ? loadTestTemplate(templateId)
0835: : null;
0836: if (doTestTempl == null) {
0837: return null;
0838: }
0839: DataObject doSuiteTempl = (suiteTemplateId != null) ? loadTestTemplate(suiteTemplateId)
0840: : null;
0841: if (forTestSuite && (doSuiteTempl == null)) {
0842: return null;
0843: }
0844:
0845: Map<String, Boolean> templateParams = createTemplateParams(params);
0846: if (useAnnotations) {
0847: templateParams.put(templatePropUseAnnotations,
0848: useAnnotations);
0849: }
0850:
0851: if ((filesToTest == null) || (filesToTest.length == 0)) {
0852: //XXX: Not documented that filesToTest may be <null>
0853:
0854: addTemplateParamEntry(params,
0855: CreateTestParam.INC_CODE_HINT, templateParams,
0856: templatePropMethodPH);
0857:
0858: String testClassName = (String) params
0859: .get(CreateTestParam.CLASS_NAME);
0860: assert testClassName != null;
0861: results = new CreationResults(1);
0862: DataObject testDataObj = createEmptyTest(targetRoot,
0863: testClassName, testCreator, templateParams,
0864: doTestTempl);
0865: if (testDataObj != null) {
0866: results.addCreated(testDataObj);
0867: }
0868:
0869: } else {
0870: ClassPath testClassPath = ClassPathSupport
0871: .createClassPath(new FileObject[] { targetRoot });
0872: if (!forTestSuite) {
0873: String testClassName = (String) params
0874: .get(CreateTestParam.CLASS_NAME);
0875: if (testClassName == null) {
0876: String srcClassName = ClassPath.getClassPath(
0877: filesToTest[0], SOURCE)
0878: .getResourceName(filesToTest[0], '.',
0879: false);
0880: testClassName = getTestClassName(srcClassName);
0881: }
0882: try {
0883: results = createSingleTest(filesToTest[0],
0884: testClassName, testCreator,
0885: templateParams, doTestTempl,
0886: testClassPath, false, //do not skip any classes
0887: null, //parent suite
0888: progress);
0889: } catch (CreationError ex) {
0890: ErrorManager.getDefault().notify(ex);
0891: results = new CreationResults(1);
0892: }
0893: } else {
0894: results = new CreationResults();
0895:
0896: // go through all nodes
0897: for (FileObject fileToTest : filesToTest) {
0898: try {
0899: results.combine(createTests(fileToTest,
0900: testCreator, templateParams,
0901: doTestTempl, doSuiteTempl,
0902: testClassPath, null, progress));
0903: } catch (CreationError e) {
0904: ErrorManager.getDefault().notify(e);
0905: }
0906: }
0907: }
0908: }
0909: } finally {
0910: progress.hide();
0911: }
0912:
0913: final Set<SkippedClass> skipped = results.getSkipped();
0914: final Set<DataObject> created = results.getCreated();
0915: if (!skipped.isEmpty()) {
0916: // something was skipped
0917: String message;
0918: if (skipped.size() == 1) {
0919: // one class? report it
0920: SkippedClass skippedClass = skipped.iterator().next();
0921:
0922: message = NbBundle.getMessage(DefaultPlugin.class,
0923: "MSG_skipped_class", //NOI18N
0924: skippedClass.clsName, strReason(
0925: skippedClass.reason, "COMMA", "AND"));//NOI18N
0926: } else {
0927: // more classes, report a general error
0928: // combine the results
0929: TestabilityResult reason = TestabilityResult.OK;
0930: for (SkippedClass sc : skipped) {
0931: reason = TestabilityResult.combine(reason,
0932: sc.reason);
0933: }
0934:
0935: message = NbBundle.getMessage(DefaultPlugin.class,
0936: "MSG_skipped_classes", //NOI18N
0937: strReason(reason, "COMMA", "OR")); //NOI18N
0938: }
0939: TestUtil.notifyUser(message,
0940: NotifyDescriptor.INFORMATION_MESSAGE);
0941:
0942: }
0943:
0944: if (created.isEmpty()) {
0945: Mutex.EVENT.writeAccess(new Runnable() {
0946: public void run() {
0947: TestUtil.notifyUser(
0948: NbBundle.getMessage(DefaultPlugin.class,
0949: "MSG_No_test_created"), //NOI18N
0950: NotifyDescriptor.INFORMATION_MESSAGE);
0951: }
0952: });
0953: }
0954:
0955: FileObject[] createdFiles;
0956: if (created.isEmpty()) {
0957: createdFiles = new FileObject[0];
0958: } else {
0959: createdFiles = new FileObject[created.size()];
0960: int i = 0;
0961: for (DataObject dObj : created) {
0962: createdFiles[i++] = dObj.getPrimaryFile();
0963: }
0964: }
0965: return createdFiles;
0966: }
0967:
0968: /**
0969: * Create a map of FreeMaker template parameters from a map
0970: * of {@code CreateTestParam}s.
0971: */
0972: public static final Map<String, Boolean> createTemplateParams(
0973: Map<CreateTestParam, Object> params) {
0974: Map<String, Boolean> result = new HashMap<String, Boolean>(7);
0975:
0976: addTemplateParamEntry(params, CreateTestParam.INC_CLASS_SETUP,
0977: result, templatePropBeforeClass);
0978: addTemplateParamEntry(params,
0979: CreateTestParam.INC_CLASS_TEAR_DOWN, result,
0980: templatePropAfterClass);
0981: addTemplateParamEntry(params, CreateTestParam.INC_SETUP,
0982: result, templatePropBefore);
0983: addTemplateParamEntry(params, CreateTestParam.INC_TEAR_DOWN,
0984: result, templatePropAfter);
0985: addTemplateParamEntry(params, CreateTestParam.INC_CODE_HINT,
0986: result, templatePropCodeHints);
0987:
0988: return result;
0989: }
0990:
0991: private static void addTemplateParamEntry(
0992: Map<CreateTestParam, Object> srcParams,
0993: CreateTestParam srcParamKey,
0994: Map<String, Boolean> templParams, String templParamKey) {
0995: Object value = srcParams.get(srcParamKey);
0996: if (value instanceof Boolean) {
0997: templParams.put(templParamKey, Boolean.class.cast(value));
0998: }
0999: }
1000:
1001: /**
1002: */
1003: public boolean setupJUnitVersionByProject(FileObject targetFolder) {
1004: return createTestActionCalled(new FileObject[] { targetFolder });
1005: }
1006:
1007: /**
1008: */
1009: @Override
1010: protected boolean createTestActionCalled(FileObject[] selectedFiles) {
1011: assert EventQueue.isDispatchThread();
1012:
1013: LOG_JUNIT_VER.finer("createTestActionCalled(...)"); //NOI18N
1014:
1015: Project project = FileOwnerQuery.getOwner(selectedFiles[0]);
1016: assert project != null; //PENDING
1017:
1018: boolean storeSettings;
1019: try {
1020: storeSettings = readProjectSettingsJUnitVer(project);
1021: if (!storeSettings) {
1022: LOG_JUNIT_VER
1023: .finest(" - will not be able to store JUnit version settings"); //NOI18N
1024: }
1025: } catch (IllegalStateException ex) {
1026: String projectName = ProjectUtils.getInformation(project)
1027: .getDisplayName();
1028: DialogDisplayer.getDefault().notify(
1029: new NotifyDescriptor.Message(NbBundle.getMessage(
1030: getClass(),
1031: "MSG_NoTestFolderFoundInProject",//NOI18N
1032: projectName),
1033: NotifyDescriptor.WARNING_MESSAGE));
1034: return false;
1035: }
1036:
1037: if (junitVer != null) {
1038: switch (junitVer) {
1039: case JUNIT3:
1040: return true;
1041: case JUNIT4:
1042: String sourceLevel = TestUtil
1043: .getSourceLevel(selectedFiles[0]);
1044: if (sourceLevel == null) { //could not get source level
1045: return true;
1046: }
1047:
1048: if (sourceLevel.compareTo("1.5") >= 0) { //NOI18N
1049: return true;
1050: } else if (askUserLastWasJUnit4NowSource14(sourceLevel)) {
1051: junitVer = JUnitVersion.JUNIT3;
1052: if (storeSettings) {
1053: storeProjectSettingsJUnitVer(project);
1054: }
1055: return true;
1056: }
1057: return false;
1058: default:
1059: assert false;
1060: return false;
1061: }
1062: }
1063:
1064: readSystemSettingsJUnitVer();
1065: if (junitVer != null) {
1066: switch (junitVer) {
1067: case JUNIT3:
1068: if (storeSettings) {
1069: storeProjectSettingsJUnitVer(project);
1070: }
1071: return true;
1072: case JUNIT4:
1073: String sourceLevel = TestUtil
1074: .getSourceLevel(selectedFiles[0]);
1075: if ((sourceLevel != null)
1076: && (sourceLevel.compareTo("1.5")) >= 0) { //NOI18N
1077: if (storeSettings) {
1078: storeProjectSettingsJUnitVer(project);
1079: }
1080: return true;
1081: } else if (sourceLevel == null) {
1082: String msgKey = "MSG_select_junit_version_srclvl_unknown";//NOI18N
1083: junitVer = askUserWhichJUnitToUse(msgKey, true,
1084: true);
1085: if ((junitVer != null) && storeSettings) {
1086: storeProjectSettingsJUnitVer(project);
1087: }
1088: return (junitVer != null);
1089: } else if (informUserOnlyJUnit3Applicable(sourceLevel)) {
1090: junitVer = JUnitVersion.JUNIT3;
1091: if (storeSettings) {
1092: storeProjectSettingsJUnitVer(project);
1093: }
1094: return true;
1095: }
1096: return false;
1097: default:
1098: assert false;
1099: return false;
1100: }
1101: }
1102:
1103: String msgKey;
1104: boolean offerJUnit4;
1105: boolean showSourceLevelReqs;
1106: String sourceLevel = TestUtil.getSourceLevel(selectedFiles[0]);
1107: if (sourceLevel == null) {
1108: msgKey = "MSG_select_junit_version_srclvl_unknown"; //NOI18N
1109: offerJUnit4 = true;
1110: showSourceLevelReqs = true;
1111: } else {
1112: msgKey = "MSG_select_junit_version"; //NOI18N
1113: offerJUnit4 = (sourceLevel.compareTo("1.5") >= 0); //NOI18N
1114: showSourceLevelReqs = !offerJUnit4;
1115: }
1116: junitVer = askUserWhichJUnitToUse(msgKey, offerJUnit4,
1117: showSourceLevelReqs);
1118: if ((junitVer != null) && storeSettings) {
1119: storeProjectSettingsJUnitVer(project);
1120: }
1121: return (junitVer != null);
1122: }
1123:
1124: /**
1125: */
1126: private boolean askUserLastWasJUnit4NowSource14(String sourceLevel) {
1127: assert EventQueue.isDispatchThread();
1128:
1129: JComponent msg = createMessageComponent(
1130: "MSG_last_was_junit4_what_now", //NOI18N
1131: sourceLevel);
1132: Object selectOption = NbBundle.getMessage(getClass(),
1133: "LBL_create_junit3_tests"); //NOI18N
1134: Object answer = DialogDisplayer.getDefault().notify(
1135: new DialogDescriptor(
1136: wrapDialogContent(msg),
1137: NbBundle.getMessage(getClass(),
1138: "LBL_title_cannot_use_junit4"), //NOI18N
1139: true, new Object[] { selectOption,
1140: CANCEL_OPTION }, selectOption,
1141: DialogDescriptor.DEFAULT_ALIGN, (HelpCtx) null,
1142: (ActionListener) null));
1143:
1144: return answer == selectOption;
1145: }
1146:
1147: /**
1148: */
1149: private boolean informUserOnlyJUnit3Applicable(String sourceLevel) {
1150: assert EventQueue.isDispatchThread();
1151:
1152: JComponent msg = createMessageComponent(
1153: "MSG_cannot_use_default_junit4", //NOI18N
1154: sourceLevel);
1155: // Object selectOption = NbBundle.getMessage(
1156: // getClass(),
1157: // "LBL_create_junit3_tests"); //NOI18N
1158: JButton button = new JButton();
1159: Mnemonics.setLocalizedText(button, bundle
1160: .getString("LBL_Select"));
1161: button.getAccessibleContext().setAccessibleName(
1162: "AN_create_junit3_tests");
1163: button.getAccessibleContext().setAccessibleDescription(
1164: "AD_create_junit3_tests");
1165:
1166: Object answer = DialogDisplayer.getDefault().notify(
1167: new DialogDescriptor(
1168: wrapDialogContent(msg),
1169: NbBundle.getMessage(getClass(),
1170: "LBL_title_cannot_use_junit4"), //NOI18N
1171: true, //modal
1172: new Object[] { button, CANCEL_OPTION }, button,
1173: DialogDescriptor.DEFAULT_ALIGN, (HelpCtx) null,
1174: (ActionListener) null));
1175:
1176: return answer == button;
1177: }
1178:
1179: // private String getText(String bundleKey) {
1180: // return NbBundle.getMessage(getClass(), bundleKey);
1181: // }
1182:
1183: /**
1184: */
1185: private JUnitVersion askUserWhichJUnitToUse(String msgKey,
1186: boolean offerJUnit4, boolean showSourceLevelCondition) {
1187: assert EventQueue.isDispatchThread();
1188:
1189: JRadioButton rbtnJUnit3 = new JRadioButton();
1190: Mnemonics.setLocalizedText(rbtnJUnit3, bundle
1191: .getString("LBL_JUnit3_generator"));
1192: rbtnJUnit3.getAccessibleContext().setAccessibleDescription(
1193: bundle.getString("AD_JUnit3_generator"));
1194:
1195: JRadioButton rbtnJUnit4 = new JRadioButton();
1196: Mnemonics.setLocalizedText(rbtnJUnit4,
1197: showSourceLevelCondition ? bundle
1198: .getString("LBL_JUnit4_generator_reqs") //NOI18N
1199: : bundle.getString("LBL_JUnit4_generator")); //NOI18N
1200: rbtnJUnit4.getAccessibleContext().setAccessibleDescription(
1201: bundle.getString("AD_JUnit4_generator"));
1202:
1203: ButtonGroup group = new ButtonGroup();
1204: group.add(rbtnJUnit3);
1205: group.add(rbtnJUnit4);
1206:
1207: if (offerJUnit4) {
1208: rbtnJUnit4.setSelected(true);
1209: } else {
1210: rbtnJUnit3.setSelected(true);
1211: rbtnJUnit4.setEnabled(false);
1212: }
1213:
1214: JComponent msg = createMessageComponent(msgKey);
1215:
1216: JPanel choicePanel = new JPanel(new GridLayout(0, 1, 0, 3));
1217: choicePanel.add(rbtnJUnit3);
1218: choicePanel.add(rbtnJUnit4);
1219:
1220: JPanel panel = new JPanel(new BorderLayout(0, 12));
1221: panel.add(msg, BorderLayout.NORTH);
1222: panel.add(choicePanel, BorderLayout.CENTER);
1223:
1224: JButton button = new JButton();
1225: Mnemonics.setLocalizedText(button, bundle
1226: .getString("LBL_Select"));
1227: button.getAccessibleContext().setAccessibleName("AN_Select");
1228: button.getAccessibleContext().setAccessibleDescription(
1229: "AD_Select");
1230:
1231: // Object selectOption = bundle.getString("LBL_Select"); //NOI18N
1232: Object answer = DialogDisplayer
1233: .getDefault()
1234: .notify(
1235: new DialogDescriptor(
1236: wrapDialogContent(panel),
1237: bundle
1238: .getString("LBL_title_select_generator"),//NOI18N
1239: true,
1240: new Object[] { button, CANCEL_OPTION },
1241: button,
1242: DialogDescriptor.DEFAULT_ALIGN,
1243: new HelpCtx(
1244: "org.netbeans.modules.junit.select_junit_version"),//NOI18N
1245: (ActionListener) null));
1246:
1247: if (answer == button) {
1248: JUnitVersion ver;
1249: if (rbtnJUnit3.isSelected()) {
1250: ver = JUnitVersion.JUNIT3;
1251: } else if (rbtnJUnit4.isSelected()) {
1252: ver = JUnitVersion.JUNIT4;
1253: } else {
1254: assert false;
1255: ver = null;
1256: }
1257: return ver;
1258: } else {
1259: return null;
1260: }
1261: }
1262:
1263: /**
1264: */
1265: private JComponent createMessageComponent(String msgKey,
1266: String... args) {
1267: String message = NbBundle.getMessage(getClass(), msgKey, args);
1268:
1269: return GuiUtils.createMultilineLabel(message);
1270: }
1271:
1272: /**
1273: */
1274: private static JComponent wrapDialogContent(JComponent comp) {
1275: return wrapDialogContent(comp, true);
1276: }
1277:
1278: /**
1279: */
1280: private static JComponent wrapDialogContent(JComponent comp,
1281: boolean selfResizing) {
1282: JComponent result;
1283:
1284: if ((comp.getBorder() != null) || selfResizing) {
1285: result = selfResizing ? new SelfResizingPanel()
1286: : new JPanel();
1287: result.setLayout(new GridLayout());
1288: result.add(comp);
1289: } else {
1290: result = comp;
1291: }
1292: result.setBorder(BorderFactory
1293: .createEmptyBorder(12, 12, 12, 12));
1294: result.getAccessibleContext().setAccessibleDescription(
1295: bundle.getString("AD_title_select_generator"));
1296: return result;
1297: }
1298:
1299: /**
1300: * Gets JUnit version info from the project and stores it
1301: * into field {@link #junitVer}.
1302: * If the "junit version" info is not available,
1303: * {@code null} is stored.
1304: *
1305: * @param project project from which the information is to be obtained
1306: * @return {@code true} of the set of project's libraries could be
1307: * determined, {@code false} if it could not be determined
1308: * @exception java.lang.IllegalStateException
1309: * if the project does not contain any test folders
1310: * @see #junitVer
1311: */
1312: private boolean readProjectSettingsJUnitVer(Project project)
1313: throws IllegalStateException {
1314: assert project != null;
1315: if (LOG_JUNIT_VER.isLoggable(FINER)) {
1316: LOG_JUNIT_VER.finer("readProjectSettingsJUnitVer(" //NOI18N
1317: + ProjectUtils.getInformation(project)
1318: .getDisplayName() + ')');
1319: }
1320:
1321: junitVer = null;
1322:
1323: final boolean hasJUnit3;
1324: final boolean hasJUnit4;
1325: final ClassPath classPath = getTestClassPath(project); //may throw ISE
1326: if (classPath != null) {
1327: hasJUnit3 = (classPath.findResource(JUNIT3_SPECIFIC) != null);
1328: hasJUnit4 = (classPath.findResource(JUNIT4_SPECIFIC) != null);
1329: } else {
1330: hasJUnit3 = false;
1331: hasJUnit4 = false;
1332: }
1333:
1334: if (hasJUnit3 != hasJUnit4) {
1335: junitVer = hasJUnit3 ? JUnitVersion.JUNIT3
1336: : JUnitVersion.JUNIT4;
1337: if (LOG_JUNIT_VER.isLoggable(FINEST)) {
1338: LOG_JUNIT_VER.finest(" - detected version " + junitVer);//NOI18N
1339: }
1340: } else {
1341: LOG_JUNIT_VER.finest(" - no version detected"); //NOI18N
1342: }
1343: return (classPath != null);
1344: }
1345:
1346: /**
1347: * Finds classpath used for compilation of tests.
1348: *
1349: * @param project project whose classpath should be found
1350: * @return test classpath of the given project, or {@code null} if it could
1351: * not be determined
1352: * @exception java.lang.IllegalStateException
1353: * if no test folders were found in the project
1354: */
1355: private static ClassPath getTestClassPath(final Project project)
1356: throws IllegalStateException {
1357: assert project != null;
1358: if (LOG_JUNIT_VER.isLoggable(FINER)) {
1359: LOG_JUNIT_VER.finer("getTestClassPath(" //NOI18N
1360: + ProjectUtils.getInformation(project)
1361: .getDisplayName() + ')');
1362: }
1363:
1364: final Collection<FileObject> testFolders = Utils
1365: .getTestFolders(project);
1366: if (testFolders.isEmpty()) {
1367: LOG_JUNIT_VER.finest(" - no test folders found"); //NOI18N
1368: throw new IllegalStateException();
1369: }
1370:
1371: final ClassPathProvider cpProvider = project.getLookup()
1372: .lookup(ClassPathProvider.class);
1373: if (cpProvider == null) {
1374: LOG_JUNIT_VER.finest(" - ClassPathProvider not found"); //NOI18N
1375: return null;
1376: }
1377:
1378: for (FileObject testRoot : testFolders) {
1379: ClassPath testClassPath = cpProvider.findClassPath(
1380: testRoot, COMPILE);
1381: if (testClassPath != null) {
1382: if (LOG_JUNIT_VER.isLoggable(FINEST)) {
1383: LOG_JUNIT_VER.finest(" - returning: " //NOI18N
1384: + testClassPath);
1385: }
1386: return testClassPath;
1387: }
1388: }
1389:
1390: LOG_JUNIT_VER.finest(" - no compile classpath for tests found");//NOI18N
1391: return null;
1392: }
1393:
1394: /**
1395: * Stores JUnit version to the project's configuration file.
1396: *
1397: * @param project project whose configuration file is to be checked
1398: * @see #junitVer
1399: */
1400: private void storeProjectSettingsJUnitVer(final Project project) {
1401: assert junitVer != null;
1402:
1403: if (LOG_JUNIT_VER.isLoggable(FINER)) {
1404: LOG_JUNIT_VER.finer("storeProjectSettignsJUnitVer(" //NOI18N
1405: + ProjectUtils.getInformation(project)
1406: .getDisplayName() + ')');
1407: }
1408:
1409: final boolean hasJUnit3;
1410: final boolean hasJUnit4;
1411: final ClassPath classPath = getTestClassPath(project);
1412: if (classPath != null) {
1413: hasJUnit3 = (classPath.findResource(JUNIT3_SPECIFIC) != null);
1414: hasJUnit4 = (classPath.findResource(JUNIT4_SPECIFIC) != null);
1415: } else {
1416: hasJUnit3 = false;
1417: hasJUnit4 = false;
1418: }
1419:
1420: final Pattern pattern = Pattern
1421: .compile("^junit(?:_|\\W)+([34])(?:\\b|_).*"); //NOI18N
1422:
1423: JUnitLibraryComparator libraryComparator = null;
1424:
1425: Library libraryToAdd = null;
1426: Collection<Library> librariesToRemove = null;
1427:
1428: LOG_JUNIT_VER.finest(" - checking libraries:"); //NOI18N
1429: Library[] libraries = LibraryManager.getDefault()
1430: .getLibraries();
1431: for (Library library : libraries) {
1432: String name = library.getName().toLowerCase();
1433: if (LOG_JUNIT_VER.isLoggable(FINEST)) {
1434: LOG_JUNIT_VER.finest(" " + name);
1435: }
1436: if (!name.startsWith("junit")) { //NOI18N
1437: LOG_JUNIT_VER.finest(" - not a JUnit library"); //NOI18N
1438: continue;
1439: }
1440:
1441: boolean add = false;
1442: boolean remove = false;
1443: Matcher matcher;
1444: final String verNumToAdd;
1445: if ((junitVer == JUnitVersion.JUNIT3) && !hasJUnit3) {
1446: verNumToAdd = "3"; //NOI18N
1447: } else if ((junitVer == JUnitVersion.JUNIT4) && !hasJUnit4) {
1448: verNumToAdd = "4"; //NOI18N
1449: } else {
1450: verNumToAdd = null;
1451: }
1452: String verNumToRemove = (junitVer == JUnitVersion.JUNIT3) ? "4"
1453: : "3"; //NOI18N
1454: if (name.equals("junit")) { //NOI18N
1455: add = (verNumToAdd == "3"); //NOI18N
1456: remove = (verNumToRemove == "3"); //NOI18N
1457: } else if ((matcher = pattern.matcher(name)).matches()) {
1458: String verNum = matcher.group(1);
1459: add = verNum.equals(verNumToAdd);
1460: remove = verNum.equals(verNumToRemove);
1461: }
1462: if (add) {
1463: LOG_JUNIT_VER.finest(" - to be added"); //NOI18N
1464: if (libraryToAdd == null) {
1465: libraryToAdd = library;
1466: } else {
1467: /*
1468: * If there are multiple conforming libraries, we only want
1469: * to add one - the most recent one (i.e. having the highest
1470: * version number).
1471: */
1472: LOG_JUNIT_VER.finest(" - will be compared:");//NOI18N
1473: if (libraryComparator == null) {
1474: libraryComparator = new JUnitLibraryComparator();
1475: }
1476: if (libraryComparator
1477: .compare(libraryToAdd, library) > 0) {
1478: LOG_JUNIT_VER.finest(" - it won"); //NOI18N
1479: libraryToAdd = library;
1480: } else {
1481: LOG_JUNIT_VER.finest(" - it lost"); //NOI18N
1482: }
1483: }
1484: }
1485: if (remove) {
1486: LOG_JUNIT_VER.finest(" - to be removed"); //NOI18N
1487: if (librariesToRemove == null) {
1488: librariesToRemove = new ArrayList<Library>(2);
1489: }
1490: librariesToRemove.add(library);
1491: }
1492: }
1493: if ((libraryToAdd == null) && (librariesToRemove == null)) {
1494: return;
1495: }
1496:
1497: final List<FileObject> projectArtifacts = getProjectTestArtifacts(project);
1498: if (projectArtifacts.isEmpty()) {
1499: displayMessage("MSG_cannot_set_junit_ver", //NOI18N
1500: WARNING_MESSAGE);
1501: return;
1502: }
1503:
1504: final Library[] libsToAdd, libsToRemove;
1505: if (libraryToAdd != null) {
1506: libsToAdd = new Library[] { libraryToAdd };
1507: } else {
1508: libsToAdd = null;
1509: }
1510: if (librariesToRemove != null) {
1511: libsToRemove = librariesToRemove
1512: .toArray(new Library[librariesToRemove.size()]);
1513: } else {
1514: libsToRemove = null;
1515: }
1516: assert (libsToAdd != null) || (libsToRemove != null);
1517:
1518: class LibrarySetModifier implements Runnable {
1519: public void run() {
1520: boolean modified = false;
1521: try {
1522: if (libsToAdd != null) {
1523: for (FileObject prjArtifact : projectArtifacts) {
1524: modified |= ProjectClassPathModifier
1525: .addLibraries(libsToAdd,
1526: prjArtifact, COMPILE);
1527: }
1528: }
1529: if (libsToRemove != null) {
1530: for (FileObject prjArtifact : projectArtifacts) {
1531: modified |= ProjectClassPathModifier
1532: .removeLibraries(libsToRemove,
1533: prjArtifact, COMPILE);
1534: }
1535: }
1536: } catch (UnsupportedOperationException ex) {
1537: String prjName = ProjectUtils.getInformation(
1538: project).getDisplayName();
1539: ErrorManager
1540: .getDefault()
1541: .log(
1542: WARNING,
1543: "Project "
1544: + prjName //NOI18N
1545: + ": Could not modify set of JUnit libraries" //NOI18N
1546: + " - operation not supported by the project.");//NOI18N
1547: } catch (IOException ex) {
1548: ErrorManager.getDefault().notify(ERROR, ex);
1549: }
1550: if (modified) {
1551: try {
1552: ProjectManager.getDefault()
1553: .saveProject(project);
1554: } catch (IOException ex) {
1555: ErrorManager.getDefault().notify(ERROR, ex);
1556: }
1557: }
1558: }
1559: }
1560: ProjectManager.mutex().writeAccess(new LibrarySetModifier());
1561: }
1562:
1563: /**
1564: * Schedules displaying of a message to the event-dispatching thread.
1565: *
1566: * @param bundleKey resource bundle key of the message
1567: * @param msgType type of the message
1568: * (e.g. {@code NotifyDescriptor.INFORMATION_MESSAGE})
1569: */
1570: private static void displayMessage(String bundleKey, int msgType) {
1571: DialogDisplayer.getDefault().notifyLater(
1572: new NotifyDescriptor.Message(NbBundle.getMessage(
1573: DefaultPlugin.class, bundleKey), msgType));
1574: }
1575:
1576: /**
1577: * Finds a project artifact used as an argument to method
1578: * {@code ProjectClassPathModifier.removeLibraries(...)
1579: * when modifying the set of JUnit libraries (used for tests).
1580: *
1581: * @param project project for which the project artifact should be found
1582: * @return list of test project artifacts, or {@code null} an empty list
1583: * if no one could be determined
1584: */
1585: private static List<FileObject> getProjectTestArtifacts(
1586: final Project project) {
1587: assert project != null;
1588:
1589: final ClassPathProvider cpProvider = project.getLookup()
1590: .lookup(ClassPathProvider.class);
1591: if (cpProvider == null) {
1592: Collections.<FileObject> emptyList();
1593: }
1594:
1595: final Collection<FileObject> testFolders = Utils
1596: .getTestFolders(project);
1597: if (testFolders.isEmpty()) {
1598: Collections.<FileObject> emptyList();
1599: }
1600:
1601: List<FileObject> result = null;
1602: for (FileObject testRoot : testFolders) {
1603: ClassPath testClassPath = cpProvider.findClassPath(
1604: testRoot, ClassPath.COMPILE);
1605: if (testClassPath != null) {
1606: if (result == null) {
1607: if (testFolders.size() == 1) {
1608: return Collections
1609: .<FileObject> singletonList(testRoot);
1610: } else {
1611: result = new ArrayList<FileObject>(3);
1612: }
1613: }
1614: result.add(testRoot);
1615: }
1616: }
1617: return (result != null) ? result : Collections
1618: .<FileObject> emptyList();
1619: }
1620:
1621: /**
1622: * Reads information about preferred JUnit version from the IDE settings
1623: * and stores is into field {@link #junitVer}.
1624: *
1625: * @see #junitVer
1626: */
1627: private void readSystemSettingsJUnitVer() {
1628: String value = JUnitSettings.getDefault().getGenerator();
1629: if ((value == null) || value.equals(JUNIT_GENERATOR_ASK_USER)) {
1630: junitVer = null;
1631: } else {
1632: try {
1633: junitVer = Enum.valueOf(JUnitVersion.class, value
1634: .toUpperCase());
1635: } catch (IllegalArgumentException ex) {
1636: junitVer = null;
1637: }
1638: }
1639: }
1640:
1641: /**
1642: * Creates a new test class.
1643: *
1644: * @param targetRoot <!-- //PENDING -->
1645: * @param testClassName <!-- //PENDING -->
1646: * @param testCreator {@code TestCreator} to be used for filling
1647: * the test class template
1648: * @param templateDataObj {@code DataObject} representing
1649: * the test file template
1650: * @return the created test, or {@code null} if no test was created
1651: */
1652: private DataObject createEmptyTest(FileObject targetRoot,
1653: String testClassName, TestCreator testCreator,
1654: final Map<String, ? extends Object> templateParams,
1655: DataObject templateDataObj) {
1656: if (testClassName == null) {
1657: throw new IllegalArgumentException("testClassName = null"); //NOI18N
1658: }
1659:
1660: DataObject testDataObj = null;
1661: try {
1662: DataFolder targetFolderDataObj = DataFolder
1663: .findFolder(targetRoot);
1664: testDataObj = templateDataObj.createFromTemplate(
1665: targetFolderDataObj, testClassName, templateParams);
1666:
1667: /* fill in setup etc. according to dialog settings */
1668: testCreator.createEmptyTest(testDataObj.getPrimaryFile());
1669: } catch (IOException ex) {
1670: ErrorManager.getDefault().notify(ex);
1671: }
1672: return testDataObj;
1673: }
1674:
1675: /**
1676: *
1677: */
1678: private static CreationResults createSingleTest(
1679: FileObject sourceFile, String testClassName,
1680: final TestCreator testCreator,
1681: final Map<String, ? extends Object> templateParams,
1682: DataObject templateDataObj, ClassPath testClassPath,
1683: boolean skipNonTestable, List<String> parentSuite,
1684: ProgressIndicator progress) throws CreationError {
1685:
1686: List<SkippedClass> nonTestable;
1687: List<ElementHandle<TypeElement>> testable;
1688: try {
1689: JavaSource javaSource = JavaSource
1690: .forFileObject(sourceFile);
1691: if (skipNonTestable) {
1692: nonTestable = new ArrayList<SkippedClass>();
1693: testable = TopClassFinder.findTestableTopClasses(
1694: javaSource, testCreator, nonTestable);
1695: } else {
1696: nonTestable = Collections.<SkippedClass> emptyList();
1697: testable = TopClassFinder.findTopClasses(javaSource);
1698: }
1699: } catch (IOException ex) {
1700: throw new CreationError(ex);
1701: }
1702:
1703: CreationResults result = new CreationResults(4);
1704: if (!nonTestable.isEmpty()) {
1705: result.addSkipped(nonTestable);
1706: }
1707: if (!testable.isEmpty()) {
1708: String packageName = TestUtil.getPackageName(ClassPath
1709: .getClassPath(sourceFile, ClassPath.SOURCE)
1710: .getResourceName(sourceFile, '.', false));
1711:
1712: /* used only if (testClassName != null): */
1713: boolean defClassProcessed = false;
1714:
1715: try {
1716: for (ElementHandle<TypeElement> clsToTest : testable) {
1717: String testResourceName;
1718: String srcClassNameShort = TestUtil
1719: .getSimpleName(clsToTest.getQualifiedName());
1720: if (testClassName == null) {
1721: testResourceName = TestUtil
1722: .getTestClassFullName(
1723: srcClassNameShort, packageName);
1724: testClassName = testResourceName.replace('/',
1725: '.');
1726: } else if (!defClassProcessed
1727: && srcClassNameShort.equals(sourceFile
1728: .getName())) {
1729: testResourceName = testClassName.replace('.',
1730: '/');
1731: defClassProcessed = true;
1732: } else {
1733: if (packageName == null) {
1734: packageName = TestUtil
1735: .getPackageName(testClassName);
1736: }
1737: testResourceName = TestUtil
1738: .getTestClassFullName(
1739: srcClassNameShort, packageName);
1740: }
1741:
1742: /* find or create the test class DataObject: */
1743: DataObject testDataObj = null;
1744: FileObject testFile = testClassPath
1745: .findResource(testResourceName + ".java");//NOI18N
1746: boolean isNew = (testFile == null);
1747: if (testFile == null) {
1748: testDataObj = createTestClass(testClassPath,
1749: testResourceName, templateDataObj,
1750: templateParams);
1751: testFile = testDataObj.getPrimaryFile();
1752: }
1753:
1754: testCreator.createSimpleTest(clsToTest, testFile,
1755: isNew);
1756: if (testDataObj == null) {
1757: testDataObj = DataObject.find(testFile);
1758: }
1759: save(testDataObj);
1760:
1761: result.addCreated(testDataObj);
1762: // add the test class to the parent's suite
1763: if (parentSuite != null) {
1764: parentSuite.add(testClassName);
1765: }
1766: }
1767: } catch (IOException ex) { //incl. DataObjectNotFoundException
1768: throw new CreationError(ex);
1769: }
1770: }
1771:
1772: return result;
1773: }
1774:
1775: /**
1776: *
1777: */
1778: private static CreationResults createTests(
1779: final FileObject srcFileObj, final TestCreator testCreator,
1780: final Map<String, ? extends Object> templateParams,
1781: DataObject doTestT, DataObject doSuiteT,
1782: final ClassPath testClassPath, List<String> parentSuite,
1783: ProgressIndicator progress) throws CreationError {
1784:
1785: CreationResults results;
1786: if (srcFileObj.isFolder()) {
1787: results = new CreationResults();
1788:
1789: List<String> mySuite = new LinkedList<String>();
1790:
1791: progress.setMessage(getScanningMsg(srcFileObj.getName()));
1792:
1793: for (FileObject childFileObj : srcFileObj.getChildren()) {
1794: if (progress.isCanceled()) {
1795: results.setAbborted();
1796: break;
1797: }
1798: results.combine(createTests(childFileObj, testCreator,
1799: templateParams, doTestT, doSuiteT,
1800: testClassPath, mySuite, progress));
1801: if (results.isAbborted()) {
1802: break;
1803: }
1804: }
1805:
1806: // if everything went ok, and the option is enabled,
1807: // create a suite for the folder .
1808: if (!results.isAbborted()
1809: && !mySuite.isEmpty()
1810: && JUnitSettings.getDefault()
1811: .isGenerateSuiteClasses()) {
1812: createSuiteTest(srcFileObj, (String) null, testCreator,
1813: templateParams, doSuiteT, testClassPath,
1814: mySuite, parentSuite, progress);
1815: }
1816: } else if (srcFileObj.isData()
1817: && TestUtil.isJavaFile(srcFileObj)) {
1818: results = createSingleTest(srcFileObj,
1819: (String) null, //use the default clsName
1820: testCreator, templateParams, doTestT,
1821: testClassPath, true, parentSuite, progress);
1822: } else {
1823: results = CreationResults.EMPTY;
1824: }
1825: return results;
1826: }
1827:
1828: /**
1829: *
1830: */
1831: private static DataObject createSuiteTest(FileObject folder,
1832: String suiteName, final TestCreator testCreator,
1833: final Map<String, ? extends Object> templateParams,
1834: DataObject templateDataObj, ClassPath testClassPath,
1835: List<String> classesToInclude, List<String> parentSuite,
1836: ProgressIndicator progress) throws CreationError {
1837:
1838: // find correct package name
1839: ClassPath cp = ClassPath.getClassPath(folder, SOURCE);
1840: assert cp != null : "SOURCE classpath was not found for "
1841: + folder; //NOI18N
1842: if (cp == null) {
1843: return null;
1844: }
1845:
1846: String pkg = cp.getResourceName(folder, '/', false);
1847: String dotPkg = pkg.replace('/', '.');
1848: String fullSuiteName = (suiteName != null) ? pkg + '/'
1849: + suiteName : TestUtil.convertPackage2SuiteName(pkg);
1850:
1851: String classNames = makeListOfClasses(classesToInclude, null);
1852: String classes = makeListOfClasses(classesToInclude, ".class"); //NOI18N
1853:
1854: final Map<String, Object> suiteTemplParams = new HashMap<String, Object>(
1855: templateParams);
1856: suiteTemplParams.put(templatePropClassNames, classNames);
1857: suiteTemplParams.put(templatePropClasses, classes);
1858:
1859: try {
1860: /* find or create the test class DataObject: */
1861: DataObject testDataObj = null;
1862: FileObject testFile = testClassPath
1863: .findResource(fullSuiteName + ".java"); //NOI18N
1864: boolean isNew = (testFile == null);
1865: if (testFile == null) {
1866: testDataObj = createTestClass(testClassPath,
1867: fullSuiteName, templateDataObj,
1868: suiteTemplParams);
1869: testFile = testDataObj.getPrimaryFile();
1870: }
1871:
1872: // List<String> processedClasses;
1873: // JavaSource testSrc = JavaSource.forFileObject(testFile);
1874: try {
1875: // processedClasses = testCreator.createTestSuite(classesToInclude,
1876: // testSrc,
1877: // isNew);
1878: if (testDataObj == null) {
1879: testDataObj = DataObject.find(testFile);
1880: }
1881: save(testDataObj);
1882: } catch (Exception ex) {
1883: ErrorManager.getDefault()
1884: .notify(ErrorManager.ERROR, ex);
1885: return null;
1886: }
1887:
1888: // add the suite class to the list of members of the parent
1889: // if ((parentSuite != null) && !processedClasses.isEmpty()) {
1890: // for (String simpleClassName : processedClasses) {
1891: // parentSuite.add(dotPkg.length() != 0
1892: // ? dotPkg + '.' + simpleClassName
1893: // : simpleClassName);
1894: // }
1895: // }
1896: return testDataObj;
1897: } catch (IOException ioe) {
1898: throw new CreationError(ioe);
1899: }
1900: }
1901:
1902: /**
1903: * Makes a string contaning comma-separated list of the given names.
1904: * If the {@code suffix} parameter is non-{@code null}, each of the given
1905: * names is appended a given suffix.
1906: * <p>
1907: * Examples:
1908: * <pre>
1909: * makeListOfClasses(<"Alpha", "Beta", "Gamma">, null)
1910: * => "Alpha,Beta,Gamma"
1911: * makeListOfClasses(<"Alpha", "Beta", "Gamma">, ".class")
1912: * => "Alpha.class,Beta.class,Gamma.class"
1913: * </pre>
1914: */
1915: private static final String makeListOfClasses(
1916: final List<String> clsNames, final String suffix) {
1917: if (clsNames.isEmpty()) {
1918: return ""; //NOI18N
1919: }
1920:
1921: if (clsNames.size() == 1) {
1922: return (suffix == null) ? clsNames.get(0) : clsNames.get(0)
1923: + suffix;
1924: }
1925:
1926: StringBuilder buf = new StringBuilder(128);
1927: boolean first = true;
1928: for (String clsName : clsNames) {
1929: if (!first) {
1930: buf.append(',');
1931: }
1932: buf.append(clsName);
1933: if (suffix != null) {
1934: buf.append(suffix);
1935: }
1936: first = false;
1937: }
1938: return buf.toString();
1939: }
1940:
1941: /**
1942: *
1943: */
1944: public DataObject createSuiteTest(
1945: final FileObject targetRootFolder,
1946: final FileObject targetFolder, final String suiteName,
1947: final Map<CreateTestParam, Object> params) {
1948: return createSuiteTest(targetRootFolder, targetFolder,
1949: suiteName, params, createTemplateParams(params));
1950: }
1951:
1952: /**
1953: *
1954: */
1955: public DataObject createSuiteTest(
1956: final FileObject targetRootFolder,
1957: final FileObject targetFolder, final String suiteName,
1958: final Map<CreateTestParam, Object> params,
1959: final Map<String, ? extends Object> templateParams) {
1960: TestCreator testCreator = new TestCreator(params, junitVer);
1961: ClassPath testClassPath = ClassPathSupport
1962: .createClassPath(new FileObject[] { targetRootFolder });
1963: List<String> testClassNames = TestUtil.getJavaFileNames(
1964: targetFolder, testClassPath);
1965:
1966: final String templateId;
1967: switch (junitVer) {
1968: case JUNIT3:
1969: templateId = "PROP_junit3_testClassTemplate"; //NOI18N
1970: break;
1971: case JUNIT4:
1972: templateId = "PROP_junit4_testClassTemplate"; //NOI18N
1973: break;
1974: default:
1975: assert false;
1976: templateId = null;
1977: break;
1978: }
1979: final DataObject doSuiteTempl = loadTestTemplate(templateId);
1980: if (doSuiteTempl == null) {
1981: return null;
1982: }
1983:
1984: DataObject suiteDataObj;
1985: try {
1986: return createSuiteTest(targetFolder, suiteName,
1987: testCreator, templateParams, doSuiteTempl,
1988: testClassPath, new LinkedList<String>(
1989: testClassNames), null, //parent suite
1990: null); //progress indicator
1991: } catch (CreationError ex) {
1992: return null;
1993: }
1994: }
1995:
1996: /**
1997: */
1998: private static DataObject createTestClass(ClassPath cp,
1999: String testClassName, DataObject templateDataObj,
2000: final Map<String, ? extends Object> templateParams)
2001: throws DataObjectNotFoundException, IOException {
2002:
2003: assert cp.getRoots().length == 1;
2004: FileObject root = cp.getRoots()[0];
2005: int index = testClassName.lastIndexOf('/');
2006: String pkg = index > -1 ? testClassName.substring(0, index)
2007: : ""; //NOI18N
2008: String clazz = index > -1 ? testClassName.substring(index + 1)
2009: : testClassName;
2010:
2011: // create package if it does not exist
2012: if (pkg.length() > 0) {
2013: root = FileUtil.createFolder(root, pkg); //IOException
2014: }
2015: // instantiate template into the package
2016: return templateDataObj.createFromTemplate( //IOException
2017: DataFolder.findFolder(root), clazz, templateParams);
2018: }
2019:
2020: /**
2021: *
2022: */
2023: private static void save(DataObject dataObj) throws IOException {
2024: SaveCookie sc = dataObj.getCookie(SaveCookie.class);
2025: if (null != sc) {
2026: sc.save();
2027: }
2028: }
2029:
2030: /**
2031: * Loads a test template.
2032: * If the template loading fails, displays an error message.
2033: *
2034: * @param templateID bundle key identifying the template type
2035: * @return loaded template, or <code>null</code> if the template
2036: * could not be loaded
2037: */
2038: private static DataObject loadTestTemplate(String templateID) {
2039: // get the Test class template
2040: String path = NbBundle.getMessage(DefaultPlugin.class,
2041: templateID);
2042: try {
2043: FileObject fo = Repository.getDefault()
2044: .getDefaultFileSystem().findResource(path);
2045: if (fo == null) {
2046: noTemplateMessage(path);
2047: return null;
2048: }
2049: return DataObject.find(fo);
2050: } catch (DataObjectNotFoundException e) {
2051: noTemplateMessage(path);
2052: return null;
2053: }
2054: }
2055:
2056: /**
2057: *
2058: */
2059: private static void noTemplateMessage(String temp) {
2060: String msg = NbBundle.getMessage(CreateTestAction.class,
2061: "MSG_template_not_found", //NOI18N
2062: temp);
2063: NotifyDescriptor descr = new NotifyDescriptor.Message(msg,
2064: NotifyDescriptor.ERROR_MESSAGE);
2065: DialogDisplayer.getDefault().notify(descr);
2066: }
2067:
2068: /**
2069: * A helper method to create the reason string from a result
2070: * and two message bundle keys that indicate the separators to be used instead
2071: * of "," and " and " in a connected reason like:
2072: * "abstract, package-private and without testable methods".
2073: * <p>
2074: * The values of the keys are expected to be framed by two extra characters
2075: * (e.g. as in " and "), which are stripped off. These characters serve to
2076: * preserve the spaces in the properties file.
2077: *
2078: * @param reason the TestabilityResult to represent
2079: * @param commaKey bundle key for the connective to be used instead of ", "
2080: * @param andKey bundle key for the connective to be used instead of "and"
2081: * @return String composed of the reasons contained in
2082: * <code>reason</code> separated by the values of commaKey and
2083: * andKey.
2084: */
2085: private static String strReason(TestabilityResult reason,
2086: String commaKey, String andKey) {
2087: String strComma = NbBundle.getMessage(CreateTestAction.class,
2088: commaKey);
2089: String strAnd = NbBundle.getMessage(CreateTestAction.class,
2090: andKey);
2091: String strReason = reason.getReason( // string representation of the reasons
2092: strComma.substring(1, strComma.length() - 1), strAnd
2093: .substring(1, strAnd.length() - 1));
2094:
2095: return strReason;
2096:
2097: }
2098:
2099: /**
2100: *
2101: */
2102: private static String getCreatingMsg(String className) {
2103: return NbBundle.getMessage(DefaultPlugin.class,
2104: "FMT_generator_status_creating", //NOI18N
2105: className);
2106: }
2107:
2108: /**
2109: *
2110: */
2111: private static String getScanningMsg(String sourceName) {
2112: return NbBundle.getMessage(DefaultPlugin.class,
2113: "FMT_generator_status_scanning", //NOI18N
2114: sourceName);
2115: }
2116:
2117: /**
2118: *
2119: */
2120: private static String getIgnoringMsg(String sourceName,
2121: String reason) {
2122: return NbBundle.getMessage(DefaultPlugin.class,
2123: "FMT_generator_status_ignoring", //NOI18N
2124: sourceName);
2125: }
2126:
2127: /**
2128: * Error thrown by failed test creation.
2129: */
2130: @SuppressWarnings("serial")
2131: private static final class CreationError extends Exception {
2132: CreationError() {
2133: };
2134:
2135: CreationError(Throwable cause) {
2136: super (cause);
2137: }
2138: }
2139:
2140: /**
2141: * Utility class representing the results of a test creation
2142: * process. It gatheres all tests (as DataObject) created and all
2143: * classes (as JavaClasses) for which no test was created.
2144: */
2145: static final class CreationResults {
2146: static final CreationResults EMPTY = new CreationResults();
2147:
2148: Set<DataObject> created; // Set< createdTest : DataObject >
2149: Set<SkippedClass> skipped;
2150: boolean abborted = false;
2151:
2152: CreationResults() {
2153: this (20);
2154: }
2155:
2156: CreationResults(int expectedSize) {
2157: created = new HashSet<DataObject>(expectedSize * 2, 0.5f);
2158: skipped = new HashSet<SkippedClass>(expectedSize * 2, 0.5f);
2159: }
2160:
2161: void setAbborted() {
2162: abborted = true;
2163: }
2164:
2165: /**
2166: * Returns true if the process of creation was abborted. The
2167: * result contains the results gathered so far.
2168: */
2169: boolean isAbborted() {
2170: return abborted;
2171: }
2172:
2173: /**
2174: * Adds a new entry to the set of created tests.
2175: * @return true if it was added, false if it was present before
2176: */
2177: boolean addCreated(DataObject test) {
2178: return created.add(test);
2179: }
2180:
2181: /**
2182: */
2183: boolean addSkipped(SkippedClass skippedClass) {
2184: return skipped.add(skippedClass);
2185: }
2186:
2187: /**
2188: */
2189: void addSkipped(Collection<SkippedClass> skippedClasses) {
2190: if (!skippedClasses.isEmpty()) {
2191: skipped.addAll(skippedClasses);
2192: }
2193: }
2194:
2195: /**
2196: * Returns a set of classes that were skipped in the process.
2197: * @return Set<SkippedClass>
2198: */
2199: Set<SkippedClass> getSkipped() {
2200: return skipped;
2201: }
2202:
2203: /**
2204: * Returns a set of test data objects created.
2205: * @return Set<DataObject>
2206: */
2207: Set<DataObject> getCreated() {
2208: return created;
2209: }
2210:
2211: /**
2212: * Combines two results into one. If any of the results is an
2213: * abborted result, the combination is also abborted. The
2214: * collections of created and skipped classes are unified.
2215: * @param rhs the other CreationResult to combine into this
2216: */
2217: void combine(CreationResults rhs) {
2218: if (rhs.abborted) {
2219: this .abborted = true;
2220: }
2221:
2222: this.created.addAll(rhs.created);
2223: this.skipped.addAll(rhs.skipped);
2224: }
2225:
2226: }
2227:
2228: }
|