KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > junit > DefaultPlugin


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.modules.junit;
21
22 import java.io.IOException JavaDoc;
23 import java.net.URL JavaDoc;
24 import java.util.ArrayList JavaDoc;
25 import java.util.Collection JavaDoc;
26 import java.util.Collections JavaDoc;
27 import java.util.HashSet JavaDoc;
28 import java.util.LinkedList JavaDoc;
29 import java.util.List JavaDoc;
30 import java.util.Map JavaDoc;
31 import java.util.Set JavaDoc;
32 import javax.lang.model.element.TypeElement;
33 import org.netbeans.api.java.classpath.ClassPath;
34 import org.netbeans.api.java.queries.UnitTestForSourceQuery;
35 import org.netbeans.api.java.source.ElementHandle;
36 import org.netbeans.api.java.source.JavaSource;
37 import org.netbeans.modules.junit.TestabilityResult.SkippedClass;
38 import org.netbeans.modules.junit.plugin.JUnitPlugin;
39 import org.netbeans.modules.junit.plugin.JUnitPlugin.CreateTestParam;
40 import org.netbeans.modules.junit.plugin.JUnitPlugin.Location;
41 import org.netbeans.spi.java.classpath.support.ClassPathSupport;
42 import org.openide.DialogDisplayer;
43 import org.openide.ErrorManager;
44 import org.openide.NotifyDescriptor;
45 import org.openide.cookies.SaveCookie;
46 import org.openide.filesystems.FileObject;
47 import org.openide.filesystems.FileUtil;
48 import org.openide.filesystems.Repository;
49 import org.openide.loaders.DataFolder;
50 import org.openide.loaders.DataObject;
51 import org.openide.loaders.DataObjectNotFoundException;
52 import org.openide.util.Mutex;
53 import org.openide.util.NbBundle;
54 import static javax.lang.model.util.ElementFilter.methodsIn;
55 import static javax.lang.model.util.ElementFilter.typesIn;
56 import static org.netbeans.api.java.classpath.ClassPath.SOURCE;
57 import static org.netbeans.api.java.classpath.ClassPath.COMPILE;
58 import static org.netbeans.api.java.classpath.ClassPath.BOOT;
59 //import static org.netbeans.modules.junit.plugin.JUnitPlugin.Location.CLASS_LIKE_ELEM_TYPES;
60

61 /**
62  * Default JUnit plugin.
63  *
64  * @author Marian Petras
65  */

66 public final class DefaultPlugin extends JUnitPlugin {
67     
68     /**
69      *
70      */

71     protected Location getTestLocation(Location sourceLocation) {
72         FileObject fileObj = sourceLocation.getFileObject();
73         ClassPath srcCp;
74         
75         if ((srcCp = ClassPath.getClassPath(fileObj, SOURCE)) == null) {
76             return null;
77         }
78         
79         String JavaDoc baseResName = srcCp.getResourceName(fileObj, '/', false);
80         String JavaDoc testResName = !fileObj.isFolder()
81                              ? getTestResName(baseResName, fileObj.getExt())
82                              : getSuiteResName(baseResName);
83         assert testResName != null;
84         
85         return getOppositeLocation(sourceLocation,
86                                    srcCp,
87                                    testResName,
88                                    true);
89     }
90     
91     /**
92      *
93      */

94     protected Location getTestedLocation(Location testLocation) {
95         FileObject fileObj = testLocation.getFileObject();
96         ClassPath srcCp;
97         
98         if (fileObj.isFolder()
99                || ((srcCp = ClassPath.getClassPath(fileObj, SOURCE)) == null)) {
100             return null;
101         }
102         
103         String JavaDoc baseResName = srcCp.getResourceName(fileObj, '/', false);
104         String JavaDoc srcResName = getSrcResName(baseResName, fileObj.getExt());
105         if (srcResName == null) {
106             return null; //if the selectedFO is not a test class (by name)
107
}
108
109         return getOppositeLocation(testLocation,
110                                    srcCp,
111                                    srcResName,
112                                    false);
113     }
114     
115     /**
116      *
117      */

118     private static Location getOppositeLocation(
119                                     final Location sourceLocation,
120                                     final ClassPath fileObjCp,
121                                     final String JavaDoc oppoResourceName,
122                                     final boolean sourceToTest) {
123         FileObject fileObj = sourceLocation.getFileObject();
124         FileObject fileObjRoot;
125         
126         if ((fileObjRoot = fileObjCp.findOwnerRoot(fileObj)) == null) {
127             return null;
128         }
129         
130         URL JavaDoc[] oppoRootsURLs = sourceToTest
131                               ? UnitTestForSourceQuery.findUnitTests(fileObjRoot)
132                               : UnitTestForSourceQuery.findSources(fileObjRoot);
133         //if (sourceToTest && (oppoRootsURLs.length == 0)) {
134
// PENDING - offer creation of new unit tests root
135
//}
136
if ((oppoRootsURLs == null) || (oppoRootsURLs.length == 0)) {
137             return null;
138         }
139         
140         ClassPath oppoRootsClassPath = ClassPathSupport
141                                            .createClassPath(oppoRootsURLs);
142         final List JavaDoc<FileObject> oppoFiles = oppoRootsClassPath
143                                            .findAllResources(oppoResourceName);
144         if (oppoFiles.isEmpty()) {
145             //if (sourceToTest) {
146
// PENDING - offer creation of new test class
147
//}
148
return null;
149         }
150         
151 // final ElementHandle elementHandle = sourceLocation.getElementHandle();
152
// if (elementHandle == null) {
153
return new Location(oppoFiles.get(0)/*, null*/);
154 // }
155

156 // /* Build SOURCE classpath: */
157
// ClassPath[] srcCpDelegates = new ClassPath[2];
158
// if (sourceToTest) {
159
// srcCpDelegates[0] = fileObjCp;
160
// srcCpDelegates[1] = oppoRootsClassPath;
161
// } else {
162
// srcCpDelegates[0] = oppoRootsClassPath;
163
// srcCpDelegates[1] = fileObjCp;
164
// }
165
// ClassPath srcClassPath
166
// = ClassPathSupport.createProxyClassPath(srcCpDelegates);
167
//
168
// /* Build COMPILE classpath: */
169
// FileObject[] oppoRoots = oppoRootsClassPath.getRoots();
170
// ClassPath[] compCpDelegates = new ClassPath[oppoRoots.length + 1];
171
// int delegateIndex = 0;
172
// if (sourceToTest) {
173
// compCpDelegates[delegateIndex++]
174
// = ClassPath.getClassPath(fileObjRoot, COMPILE);
175
// }
176
// for (FileObject oppoRoot : oppoRoots) {
177
// compCpDelegates[delegateIndex++]
178
// = ClassPath.getClassPath(oppoRoot, COMPILE);
179
// }
180
// if (!sourceToTest) {
181
// compCpDelegates[delegateIndex++]
182
// = ClassPath.getClassPath(fileObjRoot, COMPILE);
183
// }
184
// ClassPath compClassPath
185
// = ClassPathSupport.createProxyClassPath(compCpDelegates);
186
//
187
// /* Obtain the BOOT classpath: */
188
// ClassPath bootClassPath = ClassPath.getClassPath(fileObj, BOOT);
189
//
190
// ClasspathInfo cpInfo = ClasspathInfo.create(bootClassPath,
191
// compClassPath,
192
// srcClassPath);
193
// List<FileObject> files = new ArrayList<FileObject>(oppoFiles.size() + 1);
194
// files.add(fileObj);
195
// files.addAll(oppoFiles);
196
// JavaSource javaSource = JavaSource.create(cpInfo, files);
197
//
198
// try {
199
// MatchFinder matchFinder = new MatchFinder(sourceLocation,
200
// oppoFiles,
201
// sourceToTest);
202
// javaSource.runUserActionTask(matchFinder, true);
203
// return matchFinder.getResult();
204
// } catch (IOException ex) {
205
// Logger.getLogger("global").log(Level.SEVERE, null, ex); //NOI18N
206
// return null;
207
// }
208
}
209     
210 // /**
211
// *
212
// */
213
// private static final class MatchFinder
214
// implements CancellableTask<CompilationController> {
215
// private final FileObject currFile;
216
// private final ElementHandle currElemHandle;
217
// private final List<FileObject> oppoFiles;
218
// private final boolean sourceToTest;
219
//
220
// private String currFilePkgPrefix;
221
// private Element currElement;
222
//
223
// private volatile boolean cancelled;
224
//
225
// private String[] oppoClassNames;
226
// private String oppoMethodName;
227
// private int bestCandidateClassNamesCount;
228
// private FileObject bestCandidateFile;
229
// private Element bestCandidateElement;
230
//
231
// /** */
232
// private FileObject oppoFile = null;
233
// /** storage for the result */
234
// private Element oppoElement = null;
235
//
236
// /**
237
// *
238
// */
239
// private MatchFinder(Location currLocation,
240
// List<FileObject> oppoFiles,
241
// boolean sourceToTest) {
242
// this.currFile = currLocation.getFileObject();
243
// this.currElemHandle = currLocation.getElementHandle();
244
// this.oppoFiles = oppoFiles;
245
// this.sourceToTest = sourceToTest;
246
// }
247
//
248
// /**
249
// * This method is run once for the file referred by
250
// * {@link #currLocation} and then once for each file contained
251
// * in {@link #oppoFiles}.
252
// *
253
// * @param controller controller for the current run of this method
254
// */
255
// public void run(CompilationController controller) throws IOException {
256
// if (oppoFile != null) {
257
// /* We already have the result. */
258
//
259
// /*
260
// * This should be only possible if there are multiple oppoFiles.
261
// */
262
// assert oppoFiles.size() > 1;
263
// return;
264
// }
265
//
266
// final FileObject runFile = controller.getFileObject();
267
// if (runFile == currFile) {
268
// resolveCurrentElement(controller); //--> currElement
269
// return;
270
// }
271
//
272
// if (currElement == null) {
273
// /*
274
// * The element for 'currLocation' was not resolved during
275
// * the first run of this method on this instance.
276
// */
277
// return;
278
// }
279
// if ((oppoClassNames == null) || (oppoClassNames.length == 0)) {
280
// return;
281
// }
282
//
283
// controller.toPhase(Phase.PARSED);
284
//
285
// final Elements elements = controller.getElements();
286
// TypeElement topClass = elements.getTypeElement(getCanonicalClassName(oppoClassNames[0]));
287
// if ((topClass != null)
288
// && !CLASS_LIKE_ELEM_TYPES.contains(topClass.getKind())) {
289
// topClass = null;
290
// }
291
// if (cancelled || (topClass == null)) {
292
// return;
293
// }
294
//
295
// int classNamesCount = 0;
296
// TypeElement bestClass = null;
297
// TypeElement theSubClass = topClass;
298
// while ((theSubClass != null) && (++classNamesCount < oppoClassNames.length)) {
299
// bestClass = theSubClass;
300
//
301
// String oppoClassName = oppoClassNames[classNamesCount];
302
// if (oppoClassName == null) {
303
// break;
304
// }
305
//
306
// theSubClass = null;
307
// for (TypeElement subClass : typesIn(bestClass.getEnclosedElements())) {
308
// if (cancelled) {
309
// return;
310
// }
311
//
312
// if (CLASS_LIKE_ELEM_TYPES.contains(subClass.getKind())
313
// && subClass.getSimpleName().toString().equals(oppoClassName)) {
314
// theSubClass = subClass;
315
// break;
316
// }
317
// }
318
// }
319
// if (cancelled) {
320
// return;
321
// }
322
// if (classNamesCount == oppoClassNames.length) {
323
// bestClass = theSubClass; //this does not get called in the above while (...) cycle
324
//
325
// if (oppoMethodName == null) {
326
// oppoFile = runFile;
327
// oppoElement = bestClass;
328
// } else {
329
// ExecutableElement testMethod = findOppoMethod(bestClass);
330
// if (testMethod != null) {
331
// /* We found the test method! */
332
// oppoFile = runFile;
333
// oppoElement = testMethod;
334
// }
335
// }
336
// if (oppoFile != null) {
337
// return;
338
// }
339
// }
340
//
341
// if (classNamesCount > bestCandidateClassNamesCount) {
342
// bestCandidateFile = runFile;
343
// bestCandidateElement = bestClass;
344
// bestCandidateClassNamesCount = classNamesCount;
345
// }
346
// }
347
//
348
// /**
349
// */
350
// private ExecutableElement findOppoMethod(TypeElement classElem) {
351
// for (ExecutableElement elem : methodsIn(classElem.getEnclosedElements())) {
352
// if (elem.getSimpleName().toString().equals(oppoMethodName)) {
353
// if (!sourceToTest) {
354
// return elem;
355
// }
356
// if (elem.getParameters().isEmpty()) {
357
// Set<Modifier> modifiers = elem.getModifiers();
358
// if (modifiers.contains(Modifier.PUBLIC)
359
// && !modifiers.contains(Modifier.STATIC)) {
360
// return elem;
361
// }
362
// }
363
// break;
364
// }
365
// }
366
// return null;
367
// }
368
//
369
// public void cancel() {
370
// cancelled = true;
371
// }
372
//
373
// /**
374
// */
375
// private Location getResult() {
376
// assert (oppoFile == null) == (oppoElement == null);
377
//
378
// return (oppoFile != null)
379
// ? new Location(oppoFile, oppoElement)
380
// : new Location(bestCandidateFile, bestCandidateElement);
381
// }
382
//
383
// /**
384
// * Resolves 'currElementHandle' and stores the result to 'currElement'.
385
// */
386
// private void resolveCurrentElement(CompilationController controller)
387
// throws IOException {
388
// String canonicalFileName
389
// = controller.getClasspathInfo().getClassPath(PathKind.SOURCE)
390
// .getResourceName(currFile, '.', false);
391
// int lastDotIndex = canonicalFileName.lastIndexOf('.');
392
// currFilePkgPrefix = (lastDotIndex != -1)
393
// ? canonicalFileName.substring(0, lastDotIndex + 1)
394
// : null;
395
//
396
// controller.toPhase(Phase.PARSED);
397
// if (cancelled) {
398
// return;
399
// }
400
// currElement = currElemHandle.resolve(controller);
401
// if (currElement == null) {
402
// Logger.getLogger(getClass().getName()).log(
403
// Level.INFO,
404
// "Could not resolve element " + currElemHandle); //NOI18N
405
// return;
406
// }
407
//
408
// if (cancelled) {
409
// return;
410
// }
411
//
412
// Element clsElement;
413
// ElementKind currElemKind = currElement.getKind();
414
// if (CLASS_LIKE_ELEM_TYPES.contains(currElement.getKind())) {
415
// clsElement = currElement;
416
// oppoMethodName = null;
417
// } else {
418
// clsElement = currElement.getEnclosingElement();
419
// oppoMethodName = (currElemKind == ElementKind.METHOD)
420
// ? getOppoMethodName(currElement.getSimpleName().toString())
421
// : null; //no rule for finding tests for initializers
422
// }
423
// assert CLASS_LIKE_ELEM_TYPES.contains(clsElement.getKind());
424
//
425
// if (cancelled) {
426
// return;
427
// }
428
//
429
// oppoClassNames = buildOppoClassNames(clsElement);
430
// if (oppoClassNames == null) {
431
// oppoMethodName = null;
432
// } else {
433
// for (int i = 0; i < oppoClassNames.length; i++) {
434
// if (oppoClassNames[i] == null) {
435
// if (i == 0) {
436
// oppoClassNames = null;
437
// } else {
438
// String[] newArray = new String[i];
439
// System.arraycopy(oppoClassNames, 0, newArray, 0, i);
440
// oppoClassNames = newArray;
441
// }
442
// oppoMethodName = null;
443
// break;
444
// }
445
// }
446
//
447
// }
448
// }
449
//
450
// /**
451
// *
452
// * @return may return {@code null} if this task has been cancelled
453
// */
454
// private String[] buildOppoClassNames(Element clsElement) {
455
// String[] oppoClsNames;
456
// String oppoClsName;
457
//
458
// Element clsParent = clsElement.getEnclosingElement();
459
// if ((clsParent == null)
460
// || !CLASS_LIKE_ELEM_TYPES.contains(clsParent.getKind())) {
461
// oppoClsName = getOppoClassName(clsElement.getSimpleName().toString());
462
// oppoClsNames = (oppoClsName != null)
463
// ? new String[] {oppoClsName}
464
// : null;
465
// } else {
466
// List<String> clsNames = new ArrayList<String>();
467
// clsNames.add(clsElement.getSimpleName().toString());
468
// do {
469
// if (cancelled) {
470
// return null;
471
// }
472
//
473
// clsNames.add(clsParent.getSimpleName().toString());
474
// clsParent = clsParent.getEnclosingElement();
475
// } while ((clsParent != null)
476
// && CLASS_LIKE_ELEM_TYPES.contains(clsParent.getKind()));
477
//
478
// if (cancelled) {
479
// return null;
480
// }
481
//
482
// final int size = clsNames.size();
483
// oppoClsNames = new String[size];
484
// for (int i = 0; i < size; i++) {
485
// oppoClsName = getOppoClassName(clsNames.get(size - i - 1));
486
// if (oppoClsName == null) {
487
// break;
488
// }
489
// oppoClsNames[i] = oppoClsName;
490
// }
491
// }
492
// return oppoClsNames;
493
// }
494
//
495
// /**
496
// */
497
// private String getCanonicalClassName(String shortClassName) {
498
// return (currFilePkgPrefix != null)
499
// ? currFilePkgPrefix + shortClassName
500
// : shortClassName;
501
// }
502
//
503
// /**
504
// */
505
// private String getOppoClassName(String name) {
506
// return sourceToTest ? getTestClassName(name)
507
// : getSourceClassName(name);
508
// }
509
//
510
// /**
511
// */
512
// private String getOppoMethodName(String name) {
513
// return sourceToTest ? getTestMethodName(name)
514
// : getSourceMethodName(name);
515
// }
516
//
517
// }
518

519     /**
520      */

521     private static String JavaDoc getTestResName(String JavaDoc baseResName, String JavaDoc ext) {
522         StringBuilder JavaDoc buf
523                 = new StringBuilder JavaDoc(baseResName.length() + ext.length() + 10);
524         buf.append(baseResName).append("Test"); //NOI18N
525
if (ext.length() != 0) {
526             buf.append('.').append(ext);
527         }
528         return buf.toString();
529     }
530     
531     /**
532      */

533     private static String JavaDoc getSuiteResName(String JavaDoc baseResName) {
534         if (baseResName.length() == 0) {
535             return JUnitSettings.getDefault().getRootSuiteClassName();
536         }
537         
538         final String JavaDoc suiteSuffix = "Suite"; //NOI18N
539

540         String JavaDoc lastNamePart
541                 = baseResName.substring(baseResName.lastIndexOf('/') + 1);
542
543         StringBuilder JavaDoc buf = new StringBuilder JavaDoc(baseResName.length()
544                                               + lastNamePart.length()
545                                               + suiteSuffix.length()
546                                               + 6);
547         buf.append(baseResName).append('/');
548         buf.append(Character.toUpperCase(lastNamePart.charAt(0)))
549            .append(lastNamePart.substring(1));
550         buf.append(suiteSuffix);
551         buf.append(".java"); //NOI18N
552

553         return buf.toString();
554     }
555     
556     /**
557      */

558     private static String JavaDoc getSrcResName(String JavaDoc testResName, String JavaDoc ext) {
559         if (!testResName.endsWith("Test")) { //NOI18N
560
return null;
561         }
562         
563         StringBuilder JavaDoc buf
564                 = new StringBuilder JavaDoc(testResName.length() + ext.length());
565         buf.append(testResName.substring(0, testResName.length() - 4));
566         if (ext.length() != 0) {
567             buf.append('.').append(ext);
568         }
569         return buf.toString();
570     }
571     
572     /**
573      */

574     private static String JavaDoc getTestClassName(String JavaDoc baseClassName) {
575         return baseClassName + "Test"; //NOI18N
576
}
577     
578     /**
579      */

580     private static String JavaDoc getSourceClassName(String JavaDoc testClassName) {
581         final String JavaDoc suffix = "Test"; //NOI18N
582
final int suffixLen = suffix.length();
583         
584         return ((testClassName.length() > suffixLen)
585                     && testClassName.endsWith(suffix))
586                ? testClassName.substring(0, testClassName.length() - suffixLen)
587                : null;
588     }
589     
590     /**
591      */

592     private static String JavaDoc getTestMethodName(String JavaDoc baseMethodName) {
593         final String JavaDoc prefix = "test"; //NOI18N
594
final int prefixLen = prefix.length();
595         
596         StringBuffer JavaDoc buf = new StringBuffer JavaDoc(prefixLen
597                                             + baseMethodName.length());
598         buf.append(prefix).append(baseMethodName);
599         buf.setCharAt(prefixLen,
600                       Character.toUpperCase(baseMethodName.charAt(0)));
601         return buf.toString();
602     }
603     
604     /**
605      */

606     private static String JavaDoc getSourceMethodName(String JavaDoc testMethodName) {
607         final String JavaDoc prefix = "test"; //NOI18N
608
final int prefixLen = prefix.length();
609         
610         return ((testMethodName.length() > prefixLen)
611                     && testMethodName.startsWith(prefix))
612                ? new StringBuilder JavaDoc(testMethodName.length() - prefixLen)
613                         .append(Character.toLowerCase(testMethodName.charAt(prefixLen)))
614                         .append(testMethodName.substring(prefixLen + 1))
615                         .toString()
616                : null;
617     }
618     
619     /**
620      * Creates test classes for given source classes.
621      *
622      * @param filesToTest source files for which test classes should be
623      * created
624      * @param targetRoot root folder of the target source root
625      * @param params parameters of creating test class
626      * @return created test files
627      */

628     @Override JavaDoc
629     protected FileObject[] createTests(
630                                 final FileObject[] filesToTest,
631                                 final FileObject targetRoot,
632                                 final Map JavaDoc<CreateTestParam, Object JavaDoc> params) {
633         //XXX: not documented that in case that if filesToTest is <null>,
634
//the target root param works as a target folder
635

636         ProgressIndicator progress = new ProgressIndicator();
637         progress.show();
638
639         String JavaDoc msg = NbBundle.getMessage(
640                     CreateTestAction.class,
641                     "MSG_StatusBar_CreateTest_Begin"); //NOI18N
642
progress.displayStatusText(msg);
643
644         final TestCreator testCreator = new TestCreator(params);
645         
646         CreationResults results;
647         try {
648             if ((filesToTest == null) || (filesToTest.length == 0)) {
649                 //XXX: Not documented that filesToTest may be <null>
650

651                 DataObject doTestTempl = loadTestTemplate(
652                                          "PROP_emptyTestClassTemplate");//NOI18N
653
if (doTestTempl == null) {
654                     return null;
655                 }
656                 
657                 String JavaDoc testClassName = (String JavaDoc) params.get(CreateTestParam.CLASS_NAME);
658                 assert testClassName != null;
659                 results = new CreationResults(1);
660                 DataObject testDataObj = createEmptyTest(targetRoot,
661                                                          testClassName,
662                                                          testCreator,
663                                                          doTestTempl);
664                 if (testDataObj != null) {
665                     results.addCreated(testDataObj);
666                 }
667                 
668             } else {
669                 DataObject doTestTempl = loadTestTemplate(
670                                          "PROP_testClassTemplate"); //NOI18N
671
if (doTestTempl == null) {
672                     return null;
673                 }
674                 
675                 ClassPath testClassPath = ClassPathSupport.createClassPath(
676                                                 new FileObject[] {targetRoot});
677                 
678                 if ((filesToTest.length == 1) && filesToTest[0].isData()) {
679                     String JavaDoc testClassName = (String JavaDoc) params.get(CreateTestParam.CLASS_NAME);
680                     if (testClassName == null) {
681                         String JavaDoc srcClassName
682                                 = ClassPath.getClassPath(filesToTest[0], SOURCE)
683                                   .getResourceName(filesToTest[0], '.', false);
684                         testClassName = getTestClassName(srcClassName);
685                     }
686                     try {
687                         results = createSingleTest(
688                                 filesToTest[0],
689                                 testClassName,
690                                 testCreator,
691                                 doTestTempl,
692                                 testClassPath,
693                                 false, //do not skip any classes
694
null, //parent suite
695
progress);
696                     } catch (CreationError ex) {
697                         ErrorManager.getDefault().notify(ex);
698                         results = new CreationResults(1);
699                     }
700                 } else {
701                     DataObject doSuiteTempl = loadTestTemplate(
702                                               "PROP_testSuiteTemplate");//NOI18N
703
if (doSuiteTempl == null) {
704                         return null;
705                     }
706                     
707                     results = new CreationResults();
708
709                     // go through all nodes
710
for (FileObject fileToTest : filesToTest) {
711                         try {
712                             results.combine(createTests(fileToTest,
713                                                         testCreator,
714                                                         doTestTempl,
715                                                         doSuiteTempl,
716                                                         testClassPath,
717                                                         null,
718                                                         progress));
719                         } catch (CreationError e) {
720                             ErrorManager.getDefault().notify(e);
721                         }
722                     }
723                 }
724             }
725         } finally {
726             progress.hide();
727         }
728
729         final Set JavaDoc<SkippedClass> skipped = results.getSkipped();
730         final Set JavaDoc<DataObject> created = results.getCreated();
731         if (!skipped.isEmpty()) {
732             // something was skipped
733
String JavaDoc message;
734             if (skipped.size() == 1) {
735                 // one class? report it
736
SkippedClass skippedClass = skipped.iterator().next();
737
738                 message = NbBundle.getMessage(
739                         DefaultPlugin.class,
740                         "MSG_skipped_class", //NOI18N
741
skippedClass.clsName,
742                         strReason(skippedClass.reason, "COMMA", "AND"));//NOI18N
743
} else {
744                 // more classes, report a general error
745
// combine the results
746
TestabilityResult reason = TestabilityResult.OK;
747                 for (SkippedClass sc : skipped) {
748                     reason = TestabilityResult.combine(reason, sc.reason);
749                 }
750
751                 message = NbBundle.getMessage(
752                         DefaultPlugin.class,
753                         "MSG_skipped_classes", //NOI18N
754
strReason(reason, "COMMA", "OR")); //NOI18N
755
}
756             TestUtil.notifyUser(message, NotifyDescriptor.INFORMATION_MESSAGE);
757
758         }
759         
760         if (created.isEmpty()) {
761             Mutex.EVENT.writeAccess(new Runnable JavaDoc() {
762                 public void run() {
763                     TestUtil.notifyUser(
764                             NbBundle.getMessage(
765                                     DefaultPlugin.class,
766                                     "MSG_No_test_created"), //NOI18N
767
NotifyDescriptor.INFORMATION_MESSAGE);
768                 }
769             });
770         }
771         
772         FileObject[] createdFiles;
773         if (created.isEmpty()) {
774             createdFiles = null;
775         } else {
776             createdFiles = new FileObject[created.size()];
777             int i = 0;
778             for (DataObject dObj : created) {
779                 createdFiles[i++] = dObj.getPrimaryFile();
780             }
781         }
782         return createdFiles;
783     }
784     
785     /**
786      * Creates a new test class.
787      *
788      * @param targetRoot <!-- //PENDING -->
789      * @param testClassName <!-- //PENDING -->
790      * @param testCreator {@code TestCreator} to be used for filling
791      * the test class template
792      * @param templateDataObj {@code DataObject} representing
793      * the test file template
794      * @return the created test, or {@code null} if no test was created
795      */

796     private DataObject createEmptyTest(FileObject targetRoot,
797                                        String JavaDoc testClassName,
798                                        TestCreator testCreator,
799                                        DataObject templateDataObj) {
800         if (testClassName == null) {
801             throw new IllegalArgumentException JavaDoc("testClassName = null"); //NOI18N
802
}
803         
804         DataObject testDataObj = null;
805         try {
806             DataFolder targetFolderDataObj = DataFolder.findFolder(targetRoot);
807             testDataObj = templateDataObj.createFromTemplate(
808                                             targetFolderDataObj, testClassName);
809
810             /* fill in setup etc. according to dialog settings */
811             FileObject testFileObj = testDataObj.getPrimaryFile();
812             JavaSource testSrc = JavaSource.forFileObject(testFileObj);
813             testCreator.createEmptyTest(testSrc);
814         } catch (IOException JavaDoc ex) {
815             ErrorManager.getDefault().notify(ex);
816         }
817         return testDataObj;
818     }
819     
820     /**
821      *
822      */

823     private static CreationResults createSingleTest(
824                 FileObject sourceFile,
825                 String JavaDoc testClassName,
826                 final TestCreator testCreator,
827                 DataObject templateDataObj,
828                 ClassPath testClassPath,
829                 boolean skipNonTestable,
830                 List JavaDoc<String JavaDoc> parentSuite,
831                 ProgressIndicator progress) throws CreationError {
832         
833         List JavaDoc<SkippedClass> nonTestable;
834         List JavaDoc<ElementHandle<TypeElement>> testable;
835         try {
836             JavaSource javaSource = JavaSource.forFileObject(sourceFile);
837             if (skipNonTestable) {
838                 nonTestable = new ArrayList JavaDoc<SkippedClass>();
839                 testable = TopClassFinder.findTestableTopClasses(javaSource,
840                                                                  testCreator,
841                                                                  nonTestable);
842             } else {
843                 nonTestable = Collections.<SkippedClass>emptyList();
844                 testable = TopClassFinder.findTopClasses(javaSource);
845             }
846         } catch (IOException JavaDoc ex) {
847             throw new CreationError(ex);
848         }
849         
850         CreationResults result = new CreationResults(4);
851         if (!nonTestable.isEmpty()) {
852             result.addSkipped(nonTestable);
853         }
854         if (!testable.isEmpty()) {
855             String JavaDoc packageName = TestUtil.getPackageName(ClassPath.getClassPath(sourceFile, ClassPath.SOURCE).getResourceName(sourceFile, '.', false));
856
857             /* used only if (testClassName != null): */
858             boolean defClassProcessed = false;
859
860             try {
861                 for (ElementHandle<TypeElement> clsToTest : testable) {
862                     String JavaDoc testResourceName;
863                     String JavaDoc srcClassNameShort
864                             = TestUtil.getSimpleName(clsToTest.getQualifiedName());
865                     if (testClassName == null) {
866                         testResourceName = TestUtil.getTestClassFullName(
867                                                 srcClassNameShort, packageName);
868                         testClassName = testResourceName.replace('/', '.');
869                     } else if (!defClassProcessed
870                                && srcClassNameShort.equals(sourceFile.getName())) {
871                         testResourceName = testClassName.replace('.', '/');
872                         defClassProcessed = true;
873                     } else {
874                         if (packageName == null) {
875                             packageName = TestUtil.getPackageName(testClassName);
876                         }
877                         testResourceName = TestUtil.getTestClassFullName(
878                                                 srcClassNameShort, packageName);
879                     }
880
881                     /* find or create the test class DataObject: */
882                     DataObject testDataObj = null;
883                     FileObject testFile = testClassPath.findResource(
884                                             testResourceName + ".java");//NOI18N
885
boolean isNew = (testFile == null);
886                     if (testFile == null) {
887                         testDataObj = createTestClass(testClassPath,
888                                                       testResourceName,
889                                                       templateDataObj);
890                         testFile = testDataObj.getPrimaryFile();
891                     }
892                     
893                     JavaSource testSrc = JavaSource.forFileObject(testFile);
894                     testCreator.createSimpleTest(clsToTest, testSrc, isNew);
895                     if (testDataObj == null) {
896                         testDataObj = DataObject.find(testFile);
897                     }
898                     save(testDataObj);
899                     
900                     result.addCreated(testDataObj);
901                     // add the test class to the parent's suite
902
if (parentSuite != null) {
903                         parentSuite.add(testClassName);
904                     }
905                 }
906             } catch (IOException JavaDoc ex) { //incl. DataObjectNotFoundException
907
throw new CreationError(ex);
908             }
909         }
910         
911         return result;
912     }
913     
914     /**
915      *
916      */

917     private static CreationResults createTests(
918                 final FileObject srcFileObj,
919                 final TestCreator testCreator,
920                 DataObject doTestT,
921                 DataObject doSuiteT,
922                 final ClassPath testClassPath,
923                 List JavaDoc<String JavaDoc> parentSuite,
924                 ProgressIndicator progress) throws CreationError {
925
926         CreationResults results;
927         if (srcFileObj.isFolder()) {
928             results = new CreationResults();
929
930             List JavaDoc<String JavaDoc> mySuite = new LinkedList JavaDoc<String JavaDoc>();
931             
932             progress.setMessage(getScanningMsg(srcFileObj.getName()), false);
933
934             for (FileObject childFileObj : srcFileObj.getChildren()) {
935                 if (progress.isCanceled()) {
936                     results.setAbborted();
937                     break;
938                 }
939                 results.combine(createTests(childFileObj,
940                                             testCreator,
941                                             doTestT,
942                                             doSuiteT,
943                                             testClassPath,
944                                             mySuite,
945                                             progress));
946                 if (results.isAbborted()) {
947                     break;
948                 }
949             }
950
951             // if everything went ok, and the option is enabled,
952
// create a suite for the folder .
953
if (!results.isAbborted()
954                     && !mySuite.isEmpty()
955                     && JUnitSettings.getDefault().isGenerateSuiteClasses()) {
956                 createSuiteTest(srcFileObj,
957                                 (String JavaDoc) null,
958                                 testCreator,
959                                 doSuiteT,
960                                 testClassPath,
961                                 mySuite,
962                                 parentSuite,
963                                 progress);
964             }
965         } else if (srcFileObj.isData() && TestUtil.isJavaFile(srcFileObj)) {
966             results = createSingleTest(srcFileObj,
967                                        (String JavaDoc) null, //use the default clsName
968
testCreator,
969                                        doTestT,
970                                        testClassPath,
971                                        true,
972                                        parentSuite,
973                                        progress);
974         } else {
975             results = CreationResults.EMPTY;
976         }
977         return results;
978     }
979
980     /**
981      *
982      */

983     private static DataObject createSuiteTest(
984             FileObject folder,
985             String JavaDoc suiteName,
986             final TestCreator testCreator,
987             DataObject templateDataObj,
988             ClassPath testClassPath,
989             List JavaDoc<String JavaDoc> classesToInclude,
990             List JavaDoc<String JavaDoc> parentSuite,
991             ProgressIndicator progress) throws CreationError {
992
993         // find correct package name
994
ClassPath cp = ClassPath.getClassPath(folder, SOURCE);
995         assert cp != null : "SOURCE classpath was not found for " + folder; //NOI18N
996
if (cp == null) {
997             return null;
998         }
999         
1000        String JavaDoc pkg = cp.getResourceName(folder, '/', false);
1001        String JavaDoc dotPkg = pkg.replace('/', '.');
1002        String JavaDoc fullSuiteName = (suiteName != null)
1003                               ? pkg + '/' + suiteName
1004                               : TestUtil.convertPackage2SuiteName(pkg);
1005
1006        try {
1007            /* find or create the test class DataObject: */
1008            DataObject testDataObj = null;
1009            FileObject testFile = testClassPath.findResource(
1010                                        fullSuiteName + ".java"); //NOI18N
1011
boolean isNew = (testFile == null);
1012            if (testFile == null) {
1013                testDataObj = createTestClass(testClassPath,
1014                                              fullSuiteName,
1015                                              templateDataObj);
1016                testFile = testDataObj.getPrimaryFile();
1017            }
1018            
1019            List JavaDoc<String JavaDoc> processedClasses;
1020            JavaSource testSrc = JavaSource.forFileObject(testFile);
1021            try {
1022                processedClasses = testCreator.createTestSuite(classesToInclude,
1023                                                               testSrc,
1024                                                               isNew);
1025                if (testDataObj == null) {
1026                    testDataObj = DataObject.find(testFile);
1027                }
1028                save(testDataObj);
1029            } catch (Exception JavaDoc ex) {
1030                ErrorManager.getDefault().notify(ErrorManager.ERROR, ex);
1031                return null;
1032            }
1033
1034            // add the suite class to the list of members of the parent
1035
if ((parentSuite != null) && !processedClasses.isEmpty()) {
1036                for (String JavaDoc simpleClassName : processedClasses) {
1037                    parentSuite.add(dotPkg.length() != 0
1038                                    ? dotPkg + '.' + simpleClassName
1039                                    : simpleClassName);
1040                }
1041            }
1042            return testDataObj;
1043        } catch (IOException JavaDoc ioe) {
1044            throw new CreationError(ioe);
1045        }
1046    }
1047
1048    /**
1049     *
1050     */

1051    public DataObject createSuiteTest(
1052                                final FileObject targetRootFolder,
1053                                final FileObject targetFolder,
1054                                final String JavaDoc suiteName,
1055                                final Map JavaDoc<CreateTestParam, Object JavaDoc> params) {
1056        TestCreator testCreator = new TestCreator(params);
1057        ClassPath testClassPath = ClassPathSupport.createClassPath(
1058                new FileObject[] {targetRootFolder});
1059        List JavaDoc<String JavaDoc> testClassNames = TestUtil.getJavaFileNames(targetFolder,
1060                                                                testClassPath);
1061        
1062        final DataObject doSuiteTempl
1063                = loadTestTemplate("PROP_testSuiteTemplate"); //NOI18N
1064
if (doSuiteTempl == null) {
1065            return null;
1066        }
1067        
1068        DataObject suiteDataObj;
1069        try {
1070            return createSuiteTest(targetFolder,
1071                                   suiteName,
1072                                   testCreator,
1073                                   doSuiteTempl,
1074                                   testClassPath,
1075                                   new LinkedList JavaDoc<String JavaDoc>(testClassNames),
1076                                   null, //parent suite
1077
null); //progress indicator
1078
} catch (CreationError ex) {
1079            return null;
1080        }
1081    }
1082    
1083    /**
1084     */

1085    private static DataObject createTestClass(
1086            ClassPath cp,
1087            String JavaDoc testClassName,
1088            DataObject templateDataObj) throws DataObjectNotFoundException,
1089                                               IOException JavaDoc {
1090        
1091        assert cp.getRoots().length == 1;
1092        FileObject root = cp.getRoots()[0];
1093        int index = testClassName.lastIndexOf('/');
1094        String JavaDoc pkg = index > -1 ? testClassName.substring(0, index)
1095                                : ""; //NOI18N
1096
String JavaDoc clazz = index > -1 ? testClassName.substring(index+1)
1097                                  : testClassName;
1098
1099        // create package if it does not exist
1100
if (pkg.length() > 0) {
1101            root = FileUtil.createFolder(root, pkg); //IOException
1102
}
1103        // instantiate template into the package
1104
return templateDataObj.createFromTemplate( //IOException
1105
DataFolder.findFolder(root),
1106                    clazz);
1107    }
1108
1109    /**
1110     *
1111     */

1112    private static void save(DataObject dataObj) throws IOException JavaDoc {
1113        SaveCookie sc = dataObj.getCookie(SaveCookie.class);
1114        if (null != sc) {
1115            sc.save();
1116        }
1117    }
1118        
1119    /**
1120     * Loads a test template.
1121     * If the template loading fails, displays an error message.
1122     *
1123     * @param templateID bundle key identifying the template type
1124     * @return loaded template, or <code>null</code> if the template
1125     * could not be loaded
1126     */

1127    private static DataObject loadTestTemplate(String JavaDoc templateID) {
1128        // get the Test class template
1129
String JavaDoc path = NbBundle.getMessage(DefaultPlugin.class,
1130                                          templateID);
1131        try {
1132            FileObject fo = Repository.getDefault().getDefaultFileSystem()
1133                            .findResource(path);
1134            if (fo == null) {
1135                noTemplateMessage(path);
1136                return null;
1137            }
1138            return DataObject.find(fo);
1139        }
1140        catch (DataObjectNotFoundException e) {
1141            noTemplateMessage(path);
1142            return null;
1143        }
1144    }
1145        
1146    /**
1147     *
1148     */

1149    private static void noTemplateMessage(String JavaDoc temp) {
1150        String JavaDoc msg = NbBundle.getMessage(
1151                CreateTestAction.class,
1152                "MSG_template_not_found", //NOI18N
1153
temp);
1154        NotifyDescriptor descr = new NotifyDescriptor.Message(
1155                msg,
1156                NotifyDescriptor.ERROR_MESSAGE);
1157        DialogDisplayer.getDefault().notify(descr);
1158    }
1159
1160    /**
1161     * A helper method to create the reason string from a result
1162     * and two message bundle keys that indicate the separators to be used instead
1163     * of "," and " and " in a connected reason like:
1164     * "abstract, package-private and without testable methods".
1165     * <p>
1166     * The values of the keys are expected to be framed by two extra characters
1167     * (e.g. as in " and "), which are stripped off. These characters serve to
1168     * preserve the spaces in the properties file.
1169     *
1170     * @param reason the TestabilityResult to represent
1171     * @param commaKey bundle key for the connective to be used instead of ", "
1172     * @param andKey bundle key for the connective to be used instead of "and"
1173     * @return String composed of the reasons contained in
1174     * <code>reason</code> separated by the values of commaKey and
1175     * andKey.
1176     */

1177    private static String JavaDoc strReason(TestabilityResult reason, String JavaDoc commaKey, String JavaDoc andKey) {
1178        String JavaDoc strComma = NbBundle.getMessage(CreateTestAction.class,commaKey);
1179        String JavaDoc strAnd = NbBundle.getMessage(CreateTestAction.class,andKey);
1180        String JavaDoc strReason = reason.getReason( // string representation of the reasons
1181
strComma.substring(1, strComma.length()-1),
1182                        strAnd.substring(1, strAnd.length()-1));
1183
1184        return strReason;
1185
1186    }
1187
1188    /**
1189     *
1190     */

1191    private static String JavaDoc getCreatingMsg(String JavaDoc className) {
1192        return NbBundle.getMessage(
1193                DefaultPlugin.class,
1194                "FMT_generator_status_creating", //NOI18N
1195
className);
1196    }
1197
1198    /**
1199     *
1200     */

1201    private static String JavaDoc getScanningMsg(String JavaDoc sourceName) {
1202        return NbBundle.getMessage(
1203                DefaultPlugin.class,
1204                "FMT_generator_status_scanning", //NOI18N
1205
sourceName);
1206    }
1207
1208    /**
1209     *
1210     */

1211    private static String JavaDoc getIgnoringMsg(String JavaDoc sourceName, String JavaDoc reason) {
1212        return NbBundle.getMessage(
1213                DefaultPlugin.class,
1214                "FMT_generator_status_ignoring", //NOI18N
1215
sourceName);
1216    }
1217
1218    
1219    /**
1220     * Error thrown by failed test creation.
1221     */

1222    private static final class CreationError extends Exception JavaDoc {
1223        CreationError() {};
1224        CreationError(Throwable JavaDoc cause) {
1225            super(cause);
1226        }
1227    }
1228    
1229    /**
1230     * Utility class representing the results of a test creation
1231     * process. It gatheres all tests (as DataObject) created and all
1232     * classes (as JavaClasses) for which no test was created.
1233     */

1234    static final class CreationResults {
1235        static final CreationResults EMPTY = new CreationResults();
1236
1237        Set JavaDoc<DataObject> created; // Set< createdTest : DataObject >
1238
Set JavaDoc<SkippedClass> skipped;
1239        boolean abborted = false;
1240
1241        CreationResults() { this(20);}
1242
1243        CreationResults(int expectedSize) {
1244            created = new HashSet JavaDoc<DataObject>(expectedSize * 2, 0.5f);
1245            skipped = new HashSet JavaDoc<SkippedClass>(expectedSize * 2, 0.5f);
1246        }
1247
1248        void setAbborted() {
1249            abborted = true;
1250        }
1251
1252        /**
1253         * Returns true if the process of creation was abborted. The
1254         * result contains the results gathered so far.
1255         */

1256        boolean isAbborted() {
1257            return abborted;
1258        }
1259
1260        /**
1261         * Adds a new entry to the set of created tests.
1262         * @return true if it was added, false if it was present before
1263         */

1264        boolean addCreated(DataObject test) {
1265            return created.add(test);
1266        }
1267
1268        /**
1269         */

1270        boolean addSkipped(SkippedClass skippedClass) {
1271            return skipped.add(skippedClass);
1272        }
1273        
1274        /**
1275         */

1276        void addSkipped(Collection JavaDoc<SkippedClass> skippedClasses) {
1277            if (!skippedClasses.isEmpty()) {
1278                skipped.addAll(skippedClasses);
1279            }
1280        }
1281
1282        /**
1283         * Returns a set of classes that were skipped in the process.
1284         * @return Set<SkippedClass>
1285         */

1286        Set JavaDoc<SkippedClass> getSkipped() {
1287            return skipped;
1288        }
1289
1290        /**
1291         * Returns a set of test data objects created.
1292         * @return Set<DataObject>
1293         */

1294        Set JavaDoc<DataObject> getCreated() {
1295            return created;
1296        }
1297
1298        /**
1299         * Combines two results into one. If any of the results is an
1300         * abborted result, the combination is also abborted. The
1301         * collections of created and skipped classes are unified.
1302         * @param rhs the other CreationResult to combine into this
1303         */

1304        void combine(CreationResults rhs) {
1305            if (rhs.abborted) {
1306                this.abborted = true;
1307            }
1308
1309            this.created.addAll(rhs.created);
1310            this.skipped.addAll(rhs.skipped);
1311        }
1312
1313    }
1314    
1315}
Popular Tags