KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > junit > output > JUnitOutputReader


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.output;
21
22 import java.io.File JavaDoc;
23 import java.io.FileInputStream JavaDoc;
24 import java.io.IOException JavaDoc;
25 import java.io.InputStreamReader JavaDoc;
26 import java.io.StringReader JavaDoc;
27 import java.net.MalformedURLException JavaDoc;
28 import java.net.URL JavaDoc;
29 import java.nio.charset.UnsupportedCharsetException JavaDoc;
30 import java.text.MessageFormat JavaDoc;
31 import java.util.Arrays JavaDoc;
32 import java.util.logging.Level JavaDoc;
33 import java.util.logging.Logger JavaDoc;
34 import java.util.Collection JavaDoc;
35 import java.util.GregorianCalendar JavaDoc;
36 import java.util.LinkedHashSet JavaDoc;
37 import java.util.StringTokenizer JavaDoc;
38 import java.util.regex.Matcher JavaDoc;
39 import org.apache.tools.ant.module.spi.AntEvent;
40 import org.apache.tools.ant.module.spi.AntSession;
41 import org.apache.tools.ant.module.spi.TaskStructure;
42 import org.netbeans.api.java.classpath.ClassPath;
43 import org.netbeans.api.java.platform.JavaPlatform;
44 import org.netbeans.api.java.platform.JavaPlatformManager;
45 import org.netbeans.api.java.queries.SourceForBinaryQuery;
46 import org.netbeans.api.progress.ProgressHandle;
47 import org.netbeans.api.progress.ProgressHandleFactory;
48 import org.openide.ErrorManager;
49 import org.openide.filesystems.FileObject;
50 import org.openide.filesystems.FileUtil;
51 import org.openide.util.NbBundle;
52 import org.xml.sax.SAXException JavaDoc;
53 import static java.util.Calendar.MILLISECOND JavaDoc;
54 import static org.netbeans.modules.junit.output.RegexpUtils.NESTED_EXCEPTION_PREFIX;
55 import static org.netbeans.modules.junit.output.RegexpUtils.OUTPUT_DELIMITER_PREFIX;
56 import static org.netbeans.modules.junit.output.RegexpUtils.TESTCASE_PREFIX;
57 import static org.netbeans.modules.junit.output.RegexpUtils.TESTSUITE_PREFIX;
58 import static org.netbeans.modules.junit.output.RegexpUtils.TESTSUITE_STATS_PREFIX;
59 import static org.netbeans.modules.junit.output.RegexpUtils.XML_DECL_PREFIX;
60
61 /**
62  * Obtains events from a single session of an Ant <code>junit</code> task
63  * and builds a {@link Report}.
64  * The events are delivered by the {@link JUnitAntLogger}.
65  *
66  * @see JUnitAntLogger
67  * @see Report
68  * @author Marian Petras
69  */

70 final class JUnitOutputReader {
71     
72     private static final int MAX_REPORT_FILE_SIZE = 1 << 19; //512 kBytes
73
/** number of progress bar workunits */
74     private static final int PROGRESS_WORKUNITS = 1000;
75     /** */
76     private static final int UPDATE_DELAY = 300; //milliseconds
77

78     /** */
79     private static final String JavaDoc XML_FORMATTER_CLASS_NAME
80             = "org.apache.tools.ant.taskdefs.optional.junit.XMLJUnitResultFormatter";//NOI18N
81

82     /**
83      * number of test suites that are going to be executed
84      *
85      * @see #executedSuitesCount
86      */

87     private int expectedSuitesCount = 0;
88     /**
89      * number of test suites executed so far
90      *
91      * @see #expectedSuitesCount
92      */

93     private int executedSuitesCount = 0;
94     /**
95      * did we already get statistics of tests/failures/errors for the current
96      * report?
97      */

98     private boolean testsuiteStatsKnown = false; //see issue #74979
99

100     /** */
101     private final AntSession session;
102     /** */
103     private final TaskType sessionType;
104     /**
105      * handle to the progress indicator
106      */

107     private ProgressHandle progressHandle;
108     /**
109      * whether the progress handle is in determinate mode
110      *
111      * @see #progressHandle
112      */

113     private boolean isDeterminateProgress;
114     /** */
115     private MessageFormat JavaDoc progressStepFormatSuiteName;
116     /** */
117     private MessageFormat JavaDoc progressStepFormatAnonymous;
118     /** whether XML report is expected */
119     private boolean expectXmlReport;
120     /** */
121     private final File JavaDoc antScript;
122     /** */
123     private final long timeOfSessionStart;
124     
125     /** */
126     private RegexpUtils regexp = RegexpUtils.getInstance();
127     
128     /** */
129     private Report topReport;
130     /** */
131     private Report report;
132     /** */
133     private Report.Testcase testcase;
134     /** */
135     private Report.Trouble trouble;
136     /** */
137     private TroubleParser troubleParser;
138     /** */
139     private String JavaDoc suiteName;
140     
141     /** */
142     private StringBuffer JavaDoc xmlOutputBuffer;
143     
144     /**
145      * Are we reading standard output or standard error output?
146      * This variable is used only when reading output from the test cases
147      * (when {@link #outputBuffer} is non-<code>null</code>).
148      * If <code>true</code>, standard output is being read,
149      * if <code>false</code>, standard error output is being read.
150      */

151     private boolean readingOutputReport;
152     /** */
153     private boolean lastHeaderBrief;
154     /** */
155     private boolean waitingForIssueStatus;
156     /** */
157     private final Manager manager = Manager.getInstance();
158     /** */
159     private String JavaDoc classpath;
160     /** */
161     private ClassPath platformSources;
162     
163     
164     /** Creates a new instance of JUnitOutputReader */
165     JUnitOutputReader(final AntSession session,
166                       final TaskType sessionType,
167                       final long timeOfSessionStart) {
168         this.session = session;
169         this.sessionType = sessionType;
170         this.antScript = session.getOriginatingScript();
171         this.timeOfSessionStart = timeOfSessionStart;
172     }
173     
174     /**
175      */

176     void verboseMessageLogged(final AntEvent event) {
177         final String JavaDoc msg = event.getMessage();
178         if (msg == null) {
179             return;
180         }
181         
182         /* Look for classpaths: */
183
184         /* Code copied from JavaAntLogger */
185
186         Matcher JavaDoc matcher;
187
188         matcher = RegexpUtils.CLASSPATH_ARGS.matcher(msg);
189         if (matcher.find()) {
190             this.classpath = matcher.group(1);
191         }
192         // XXX should also probably clear classpath when taskFinished called
193
matcher = RegexpUtils.JAVA_EXECUTABLE.matcher(msg);
194         if (matcher.find()) {
195             String JavaDoc executable = matcher.group(1);
196             ClassPath platformSrcs = findPlatformSources(executable);
197             if (platformSrcs != null) {
198                 this.platformSources = platformSrcs;
199             }
200         }
201     }
202     
203     /**
204      */

205     void messageLogged(final AntEvent event) {
206         final String JavaDoc msg = event.getMessage();
207         if (msg == null) {
208             return;
209         }
210         
211         //<editor-fold defaultstate="collapsed" desc="if (waitingForIssueStatus) ...">
212
if (waitingForIssueStatus) {
213             assert testcase != null;
214             
215             Matcher JavaDoc matcher = regexp.getTestcaseIssuePattern().matcher(msg);
216             if (matcher.matches()) {
217                 boolean error = (matcher.group(1) == null);
218             
219                 trouble = (testcase.trouble = new Report.Trouble(error));
220                 waitingForIssueStatus = false;
221                 return;
222             } else {
223                 report.reportTest(testcase);
224                 waitingForIssueStatus = false;
225             }
226         }//</editor-fold>
227
//<editor-fold defaultstate="collapsed" desc="if (xmlOutputBuffer != null) ...">
228
if (xmlOutputBuffer != null) {
229             xmlOutputBuffer.append(msg).append('\n');
230             if (msg.equals("</testsuite>")) { //NOI18N
231
closePreviousReport();
232             }
233             return;
234         }//</editor-fold>
235
//<editor-fold defaultstate="collapsed" desc="if (readingOutputReport) ...">
236
if (readingOutputReport) {
237             if (msg.startsWith(OUTPUT_DELIMITER_PREFIX)) {
238                 Matcher JavaDoc matcher = regexp.getOutputDelimPattern().matcher(msg);
239                 if (matcher.matches() && (matcher.group(1) == null)) {
240                     readingOutputReport = false;
241                 }
242             }
243             return;
244         }//</editor-fold>
245
//<editor-fold defaultstate="collapsed" desc="if (trouble != null) ...">
246
if (trouble != null) {
247             if (troubleParser == null) {
248                 troubleParser = new TroubleParser(trouble, regexp);
249             }
250             if (troubleParser.processMessage(msg)) {
251                 troubleParser = null;
252                 
253                 if ((trouble.stackTrace != null) && (trouble.stackTrace.length != 0)) {
254                     setClasspathSourceRoots();
255                 }
256
257                 report.reportTest(testcase);
258                 
259                 trouble = null;
260                 testcase = null;
261             }
262             return;
263         }//</editor-fold>
264

265         //<editor-fold defaultstate="collapsed" desc="TESTCASE_PREFIX">
266
if (msg.startsWith(TESTCASE_PREFIX)) {
267
268             if (report == null) {
269                 return;
270             }
271             
272             String JavaDoc header = msg.substring(TESTCASE_PREFIX.length());
273             
274             boolean success =
275                 lastHeaderBrief
276                 ? tryParseBriefHeader(header)
277                     || !(lastHeaderBrief = !tryParsePlainHeader(header))
278                 : tryParsePlainHeader(header)
279                     || (lastHeaderBrief = tryParseBriefHeader(header));
280             if (success) {
281                 waitingForIssueStatus = !lastHeaderBrief;
282             }
283         }//</editor-fold>
284
//<editor-fold defaultstate="collapsed" desc="OUTPUT_DELIMITER_PREFIX">
285
else if (msg.startsWith(OUTPUT_DELIMITER_PREFIX)
286                 && regexp.getOutputDelimPattern().matcher(msg).matches()) {
287             if (report == null) {
288                 return;
289             }
290             readingOutputReport = true;
291         }//</editor-fold>
292
//<editor-fold defaultstate="collapsed" desc="XML_DECL_PREFIX">
293
else if (expectXmlReport && msg.startsWith(XML_DECL_PREFIX)) {
294             Matcher JavaDoc matcher = regexp.getXmlDeclPattern().matcher(msg.trim());
295             if (matcher.matches()) {
296                 suiteStarted(null);
297                 
298                 xmlOutputBuffer = new StringBuffer JavaDoc(4096);
299                 xmlOutputBuffer.append(msg);
300             }
301         }//</editor-fold>
302
//<editor-fold defaultstate="collapsed" desc="TESTSUITE_PREFIX">
303
else if (msg.startsWith(TESTSUITE_PREFIX)) {
304             suiteName = msg.substring(TESTSUITE_PREFIX.length());
305             if (regexp.getFullJavaIdPattern().matcher(suiteName).matches()){
306                 suiteStarted(suiteName);
307                 report.resultsDir = determineResultsDir(event);
308             }
309         }//</editor-fold>
310
//<editor-fold defaultstate="collapsed" desc="TESTSUITE_STATS_PREFIX">
311
else if (msg.startsWith(TESTSUITE_STATS_PREFIX)) {
312
313             if (report == null) {
314                 return;
315             }
316             if (testsuiteStatsKnown) {
317                 return; //see issue #74979
318
}
319             
320             Matcher JavaDoc matcher = regexp.getSuiteStatsPattern().matcher(msg);
321             if (matcher.matches()) {
322                 assert report != null;
323                 
324                 try {
325                     report.totalTests = Integer.parseInt(matcher.group(1));
326                     report.failures = Integer.parseInt(matcher.group(2));
327                     report.errors = Integer.parseInt(matcher.group(3));
328                     report.elapsedTimeMillis
329                             = regexp.parseTimeMillis(matcher.group(4));
330                 } catch (NumberFormatException JavaDoc ex) {
331                     //if the string matches the pattern, this should not happen
332
assert false;
333                 }
334             }
335             testsuiteStatsKnown = true;
336         }//</editor-fold>
337
//<editor-fold defaultstate="collapsed" desc="Test ... FAILED">
338
else if ((suiteName != null)
339                 && msg.startsWith("Test ") //NOI18N
340
&& msg.endsWith(" FAILED") //NOI18N
341
&& msg.equals("Test " + suiteName + " FAILED")) { //NOI18N
342
suiteName = null;
343             //PENDING - stop the timer (if any)?
344
//PENDING - perform immediate update (if necessary)?
345
}
346         //</editor-fold>
347
//<editor-fold defaultstate="collapsed" desc="output">
348
else {
349             displayOutput(msg,
350                           event.getLogLevel() == AntEvent.LOG_WARN);
351         }
352         //</editor-fold>
353
}
354     
355     /**
356      * Tries to determine test results directory.
357      *
358      * @param event Ant event serving as a source of information
359      * @return <code>File<code> object representing the results directory,
360      * or <code>null</code> if the results directory could not be
361      * determined
362      */

363     private static File JavaDoc determineResultsDir(final AntEvent event) {
364         File JavaDoc resultsDir = null;
365         String JavaDoc dirName = null;
366         
367         final String JavaDoc taskName = event.getTaskName();
368         if (taskName != null) {
369             if (taskName.equals("junit")) { //NOI18N
370
dirName = determineJunitTaskResultsDir(event);
371             } else if (taskName.equals("java")) { //NOI18N
372
dirName = determineJavaTaskResultsDir(event);
373             }
374         }
375         
376         if (dirName != null) {
377             resultsDir = new File JavaDoc(dirName);
378             if (!resultsDir.isAbsolute()) {
379                 resultsDir = new File JavaDoc(event.getProperty("basedir"), //NOI18N
380
dirName);
381             }
382             if (!resultsDir.exists() || !resultsDir.isDirectory()) {
383                 resultsDir = null;
384             }
385         } else {
386             resultsDir = null;
387         }
388         
389         return resultsDir;
390     }
391     
392     /**
393      */

394     private static String JavaDoc determineJunitTaskResultsDir(final AntEvent event) {
395         final TaskStructure taskStruct = event.getTaskStructure();
396         if (taskStruct == null) {
397             return null;
398         }
399         
400         String JavaDoc dirName = null;
401         boolean hasXmlFileOutput = false;
402         
403         for (TaskStructure taskChild : taskStruct.getChildren()) {
404             String JavaDoc taskChildName = taskChild.getName();
405             if (taskChildName.equals("batchtest") //NOI18N
406
|| taskChildName.equals("test")) { //NOI18N
407
String JavaDoc dirAttr = taskChild.getAttribute("todir"); //NOI18N
408
dirName = (dirAttr != null)
409                           ? event.evaluate(dirAttr)
410                           : "."; //NOI18N
411
/* default is the current directory (Ant manual) */
412                 
413             } else if (taskChildName.equals("formatter")) { //NOI18N
414
if (hasXmlFileOutput) {
415                     continue;
416                 }
417                 String JavaDoc typeAttr = taskChild.getAttribute("type"); //NOI18N
418
if ((typeAttr != null)
419                         && "xml".equals(event.evaluate(typeAttr))) { //NOI18N
420
String JavaDoc useFileAttr
421                             = taskChild.getAttribute("usefile"); //NOI18N
422
if ((useFileAttr == null)
423                         || "true".equals(event.evaluate(useFileAttr))) {//NOI18N
424
hasXmlFileOutput = true;
425                     }
426                 }
427             }
428         }
429         
430         return hasXmlFileOutput ? dirName : null;
431     }
432     
433     /**
434      */

435     private static String JavaDoc determineJavaTaskResultsDir(final AntEvent event) {
436         final TaskStructure taskStruct = event.getTaskStructure();
437         if (taskStruct == null) {
438             return null;
439         }
440         
441         for (TaskStructure taskChild : taskStruct.getChildren()) {
442             String JavaDoc taskChildName = taskChild.getName();
443             if (taskChildName.equals("arg")) { //NOI18N
444
String JavaDoc valueAttr = taskChild.getAttribute("value"); //NOI18N
445
if (valueAttr != null) {
446                     valueAttr = event.evaluate(valueAttr);
447                     if (valueAttr.startsWith("formatter=")) { //NOI18N
448
String JavaDoc formatter = valueAttr.substring("formatter=".length());//NOI18N
449
int commaIndex = formatter.indexOf(',');
450                         if ((commaIndex != -1)
451                                 && formatter.substring(0, commaIndex).equals(XML_FORMATTER_CLASS_NAME)) {
452                             String JavaDoc fullReportFileName = formatter.substring(commaIndex + 1);
453                             int lastSlashIndex = fullReportFileName.lastIndexOf('/');
454                             String JavaDoc dirName = (lastSlashIndex != -1)
455                                               ? fullReportFileName.substring(0, lastSlashIndex)
456                                               : "."; //NOI18N
457
if (dirName.length() != 0) {
458                                 return dirName;
459                             }
460                         }
461                     }
462                 }
463             }
464         }
465             
466         return null;
467     }
468     
469     /**
470      */

471     private Report createReport(final String JavaDoc suiteName) {
472         Report report = new Report(suiteName);
473         report.antScript = antScript;
474         
475         report.classpath = classpath;
476         report.platformSources = platformSources;
477         
478         this.classpath = null;
479         this.platformSources = null;
480         
481         return report;
482     }
483     
484     /**
485      */

486     private ClassPath findPlatformSources(final String JavaDoc javaExecutable) {
487         
488         /* Copied from JavaAntLogger */
489         
490         final JavaPlatform[] platforms = JavaPlatformManager.getDefault()
491                                          .getInstalledPlatforms();
492         for (int i = 0; i < platforms.length; i++) {
493             FileObject fo = platforms[i].findTool("java"); //NOI18N
494
if (fo != null) {
495                 File JavaDoc f = FileUtil.toFile(fo);
496                 if (f.getAbsolutePath().startsWith(javaExecutable)) {
497                     return platforms[i].getSourceFolders();
498                 }
499             }
500         }
501         return null;
502     }
503     
504     /**
505      * Finds source roots corresponding to the apparently active classpath
506      * (as reported by logging from Ant when it runs the Java launcher
507      * with -cp) and stores it in the current report.
508      * <!-- copied from JavaAntLogger -->
509      * <!-- XXX: move to class Report -->
510      */

511     private void setClasspathSourceRoots() {
512         
513         /* Copied from JavaAntLogger */
514         
515         if (report == null) {
516             return;
517         }
518         
519         if (report.classpathSourceRoots != null) { //already set
520
return;
521         }
522         
523         if (report.classpath == null) {
524             return;
525         }
526         
527         Collection JavaDoc<FileObject> sourceRoots = new LinkedHashSet JavaDoc<FileObject>();
528         final StringTokenizer JavaDoc tok = new StringTokenizer JavaDoc(report.classpath,
529                                                         File.pathSeparator);
530         while (tok.hasMoreTokens()) {
531             String JavaDoc binrootS = tok.nextToken();
532             File JavaDoc f = FileUtil.normalizeFile(new File JavaDoc(binrootS));
533             URL JavaDoc binroot;
534             try {
535                 binroot = f.toURI().toURL();
536             } catch (MalformedURLException JavaDoc e) {
537                 throw new AssertionError JavaDoc(e);
538             }
539             if (FileUtil.isArchiveFile(binroot)) {
540                 URL JavaDoc root = FileUtil.getArchiveRoot(binroot);
541                 if (root != null) {
542                     binroot = root;
543                 }
544             }
545             FileObject[] someRoots = SourceForBinaryQuery
546                                      .findSourceRoots(binroot).getRoots();
547             sourceRoots.addAll(Arrays.asList(someRoots));
548         }
549
550         if (report.platformSources != null) {
551             sourceRoots.addAll(Arrays.asList(report.platformSources.getRoots()));
552         } else {
553             // no platform found. use default one:
554
JavaPlatform platform = JavaPlatform.getDefault();
555             // in unit tests the default platform may be null:
556
if (platform != null) {
557                 sourceRoots.addAll(
558                         Arrays.asList(platform.getSourceFolders().getRoots()));
559             }
560         }
561         report.classpathSourceRoots = sourceRoots;
562         
563         /*
564          * The following fields are no longer necessary
565          * once the source classpath is defined:
566          */

567         report.classpath = null;
568         report.platformSources = null;
569     }
570     
571     /**
572      * Notifies that a test (Ant) task was just started.
573      *
574      * @param expectedSuitesCount expected number of test suites going to be
575      * executed by this task
576      */

577     void testTaskStarted(int expectedSuitesCount, boolean expectXmlOutput) {
578         this.expectXmlReport = expectXmlOutput;
579         
580         final boolean willBeDeterminateProgress = (expectedSuitesCount > 0);
581         if (progressHandle == null) {
582             progressHandle = ProgressHandleFactory.createHandle(
583                 NbBundle.getMessage(getClass(), "MSG_ProgressMessage"));//NOI18N
584

585             if (willBeDeterminateProgress) {
586                 this.expectedSuitesCount = expectedSuitesCount;
587                 progressHandle.start(PROGRESS_WORKUNITS);
588                 progressHandle.progress(PROGRESS_WORKUNITS / 100);
589             } else {
590                 progressHandle.start();
591             }
592         } else if (willBeDeterminateProgress) {
593             if (!isDeterminateProgress) {
594                 progressHandle.switchToDeterminate(PROGRESS_WORKUNITS);
595             }
596             this.expectedSuitesCount += expectedSuitesCount;
597             updateProgress();
598         } else if (isDeterminateProgress /* and will be indeterminate */ ) {
599             progressHandle.switchToIndeterminate();
600         }//else
601
//is indeterminate and will be indeterminate - no change
602
//
603
isDeterminateProgress = willBeDeterminateProgress;
604         
605         Manager.getInstance().testStarted(session,
606                                           sessionType);
607     }
608     
609     /**
610      */

611     void testTaskFinished() {
612         expectedSuitesCount = executedSuitesCount;
613         if (isDeterminateProgress) {
614             /*
615              * The above assignment statement might set expectedSuitesCount
616              * to zero which would cause a "division by zero" exception
617              * if method updateProgress() was called. That's why we bypass
618              * the method and set the progress bar to 100% directly.
619              */

620             progressHandle.progress(PROGRESS_WORKUNITS);
621         }
622     }
623     
624     /**
625      * Updates the progress bar according to the current values of
626      * {@link #executedSuitesCount} and {@link #expectedSuitesCount}.
627      */

628     private void updateProgress() {
629         assert progressHandle != null;
630         
631         progressHandle.progress(getProcessedWorkunits());
632     }
633     
634     /**
635      * Updates the progress message - displays name of the running suite.
636      *
637      * @param suiteName name of the running suite, or {@code null}
638      */

639     private String JavaDoc getProgressStepMessage(String JavaDoc suiteName) {
640         String JavaDoc msg;
641         
642         if (isDeterminateProgress) {
643             MessageFormat JavaDoc messageFormat;
644             Object JavaDoc[] messageParams;
645             if (suiteName != null) {
646                 if (progressStepFormatSuiteName == null) {
647                     progressStepFormatSuiteName = new MessageFormat JavaDoc(
648                             NbBundle.getMessage(
649                                   getClass(),
650                                   "MSG_ProgressStepMessage")); //NOI18N
651
}
652                 messageFormat = progressStepFormatSuiteName;
653                 messageParams = new Object JavaDoc[] {suiteName,
654                                               executedSuitesCount + 1,
655                                               expectedSuitesCount};
656             } else {
657                 if (progressStepFormatAnonymous == null) {
658                     progressStepFormatAnonymous = new MessageFormat JavaDoc(
659                             NbBundle.getMessage(
660                                   getClass(),
661                                   "MSG_ProgressStepMessageAnonymous")); //NOI18N
662
}
663                 messageFormat = progressStepFormatAnonymous;
664                 messageParams = new Object JavaDoc[] {executedSuitesCount + 1,
665                                               expectedSuitesCount};
666             }
667             msg = messageFormat.format(messageParams, new StringBuffer JavaDoc(), null)
668                   .toString();
669         } else {
670             msg = (suiteName != null) ? suiteName : ""; //NOI18N
671
}
672         return msg;
673     }
674     
675     /**
676      *
677      */

678     private int getProcessedWorkunits() {
679         try {
680         return executedSuitesCount * PROGRESS_WORKUNITS / expectedSuitesCount;
681         } catch (Exception JavaDoc ex) {
682             return 0;
683         }
684     }
685     
686     /**
687      */

688     void buildFinished(final AntEvent event) {
689         try {
690             finishReport(event.getException());
691             Manager.getInstance().sessionFinished(session,
692                                                   sessionType);
693         } finally {
694             progressHandle.finish();
695         }
696     }
697     
698     /**
699      * Notifies that a test suite was just started.
700      *
701      * @param suiteName name of the suite; or {@code null}
702      * if the suite name is unknown
703      */

704     private Report suiteStarted(final String JavaDoc suiteName) {
705         closePreviousReport();
706         report = createReport(suiteName);
707         
708         String JavaDoc stepMessage = getProgressStepMessage(suiteName);
709         if (expectedSuitesCount <= executedSuitesCount) {
710             expectedSuitesCount = executedSuitesCount + 1;
711         }
712         if (executedSuitesCount != 0) {
713             progressHandle.progress(stepMessage, getProcessedWorkunits());
714         } else {
715             progressHandle.progress(stepMessage);
716         }
717                 
718         Manager.getInstance().displaySuiteRunning(session,
719                                                   sessionType,
720                                                   suiteName);
721         return report;
722     }
723     
724     /**
725      */

726     private void suiteFinished(final Report report) {
727         executedSuitesCount++;
728         
729         Manager.getInstance().displayReport(session, sessionType, report);
730     }
731     
732     /**
733      */

734     void finishReport(final Throwable JavaDoc exception) {
735         if (waitingForIssueStatus) {
736             assert testcase != null;
737             
738             report.reportTest(testcase);
739         }
740         closePreviousReport();
741         
742         //<editor-fold defaultstate="collapsed" desc="disabled code">
743
//PENDING:
744
/*
745         int errStatus = ResultWindow.ERR_STATUS_OK;
746         if (exception != null) {
747             if (exception instanceof java.lang.ThreadDeath) {
748                 errStatus = ResultWindow.ERR_STATUS_INTERRUPTED;
749             } else {
750                 errStatus = ResultWindow.ERR_STATUS_EXCEPTION;
751             }
752         }
753          */

754         
755         /*
756         //PENDING: final int status = errStatus;
757         Mutex.EVENT.postWriteRequest(new Runnable() {
758             public void run() {
759                 //PENDING:
760                 //ResultWindow resultView = ResultWindow.getInstance();
761                 //resultView.displayReport(topReport, status, antScript);
762                 
763                 final TopComponent resultWindow = ResultWindow.getDefault();
764                 resultWindow.open();
765                 resultWindow.requestActive();
766             }
767         });
768          */

769         //</editor-fold>
770
}
771     
772     //------------------ UPDATE OF DISPLAY -------------------
773

774     /**
775      */

776     private void displayOutput(final String JavaDoc text, final boolean error) {
777         Manager.getInstance().displayOutput(session, sessionType, text, error);
778     }
779     
780     //--------------------------------------------------------
781

782     /**
783      */

784     private boolean tryParsePlainHeader(String JavaDoc testcaseHeader) {
785         final Matcher JavaDoc matcher = regexp.getTestcaseHeaderPlainPattern()
786                                 .matcher(testcaseHeader);
787         if (matcher.matches()) {
788             String JavaDoc methodName = matcher.group(1);
789             int timeMillis = regexp.parseTimeMillisNoNFE(matcher.group(2));
790             
791             testcase = new Report.Testcase();
792             testcase.className = null;
793             testcase.name = methodName;
794             testcase.timeMillis = timeMillis;
795             
796             trouble = null;
797             troubleParser = null;
798             
799             return true;
800         } else {
801             return false;
802         }
803     }
804     
805     /**
806      */

807     private boolean tryParseBriefHeader(String JavaDoc testcaseHeader) {
808         final Matcher JavaDoc matcher = regexp.getTestcaseHeaderBriefPattern()
809                                 .matcher(testcaseHeader);
810         if (matcher.matches()) {
811             String JavaDoc methodName = matcher.group(1);
812             String JavaDoc clsName = matcher.group(2);
813             boolean error = (matcher.group(3) == null);
814
815             testcase = new Report.Testcase();
816             testcase.className = clsName;
817             testcase.name = methodName;
818             testcase.timeMillis = -1;
819
820             trouble = (testcase.trouble = new Report.Trouble(error));
821             
822             return true;
823         } else {
824             return false;
825         }
826     }
827     
828     /**
829      */

830     private void closePreviousReport() {
831         if (xmlOutputBuffer != null) {
832             try {
833                 String JavaDoc xmlOutput = xmlOutputBuffer.toString();
834                 xmlOutputBuffer = null; //allow GC before parsing XML
835
Report xmlReport;
836                 xmlReport = XmlOutputParser.parseXmlOutput(
837                                                 new StringReader JavaDoc(xmlOutput));
838                 report.update(xmlReport);
839             } catch (SAXException JavaDoc ex) {
840                 /* initialization of the parser failed, ignore the output */
841             } catch (IOException JavaDoc ex) {
842                 assert false; //should not happen (StringReader)
843
}
844         } else if ((report != null) && (report.resultsDir != null)) {
845             /*
846              * We have parsed the output but it seems that we also have
847              * an XML report file available - let's use it:
848              */

849             
850             File JavaDoc reportFile = new File JavaDoc(
851                               report.resultsDir,
852                               "TEST-" + report.suiteClassName + ".xml");//NOI18N
853
if (reportFile.exists() && isValidReportFile(reportFile)) {
854                 final long fileSize = reportFile.length();
855                 if ((fileSize > 0l) && (fileSize <= MAX_REPORT_FILE_SIZE)) {
856                     try {
857                         Report fileReport;
858                         fileReport = XmlOutputParser.parseXmlOutput(
859                                 new InputStreamReader JavaDoc(
860                                         new FileInputStream JavaDoc(reportFile),
861                                         "UTF-8")); //NOI18N
862
report.update(fileReport);
863                     } catch (UnsupportedCharsetException JavaDoc ex) {
864                         assert false;
865                     } catch (SAXException JavaDoc ex) {
866                         /* This exception has already been handled. */
867                     } catch (IOException JavaDoc ex) {
868                         /*
869                          * Failed to read the report file - but we still have
870                          * the report built from the Ant output.
871                          */

872                         int severity = ErrorManager.INFORMATIONAL;
873                         ErrorManager errMgr = ErrorManager.getDefault();
874                         if (errMgr.isLoggable(severity)) {
875                             errMgr.notify(
876                                     severity,
877                                     errMgr.annotate(
878      ex,
879      "I/O exception while reading JUnit XML report file from JUnit: "));//NOI18N
880
}
881                     }
882                 }
883             }
884         }
885         if (report != null) {
886             suiteFinished(report);
887         }
888         
889         xmlOutputBuffer = null;
890         readingOutputReport = false;
891         testcase = null;
892         trouble = null;
893         troubleParser = null;
894         report = null;
895         testsuiteStatsKnown = false;
896     }
897     
898     /**
899      */

900     private boolean isValidReportFile(File JavaDoc reportFile) {
901         if (!reportFile.isFile() || !reportFile.canRead()) {
902             return false;
903         }
904         
905         long lastModified = reportFile.lastModified();
906         long timeDelta = lastModified - timeOfSessionStart;
907         
908         final Logger JavaDoc logger = Logger.getLogger("org.netbeans.modules.junit.outputreader.timestamps");//NOI18N
909
final Level JavaDoc logLevel = Level.FINER;
910         if (logger.isLoggable(logLevel)) {
911             logger.log(logLevel, "Report file: " + reportFile.getPath());//NOI18N
912

913             final GregorianCalendar JavaDoc timeStamp = new GregorianCalendar JavaDoc();
914             
915             timeStamp.setTimeInMillis(timeOfSessionStart);
916             logger.log(logLevel, "Session start: " + String.format("%1$tT.%2$03d", timeStamp, timeStamp.get(MILLISECOND)));//NOI18N
917

918             timeStamp.setTimeInMillis(lastModified);
919             logger.log(logLevel, "Report timestamp: " + String.format("%1$tT.%2$03d", timeStamp, timeStamp.get(MILLISECOND)));//NOI18N
920
}
921         
922         if (timeDelta >= 0) {
923             return true;
924         }
925         
926         /*
927          * Normally we would return 'false' here, but:
928          *
929          * We must take into account that modification timestamps of files
930          * usually do not hold milliseconds, just seconds.
931          * The worst case we must accept is that the session started
932          * on YYYY.MM.DD hh:mm:ss.999 and the file was saved exactly in the same
933          * millisecond but its time stamp is just YYYY.MM.DD hh:mm:ss, i.e
934          * 999 milliseconds earlier.
935          */

936         return -timeDelta <= timeOfSessionStart % 1000;
937         
938 // if (timeDelta < -999) {
939
// return false;
940
// }
941
//
942
// final GregorianCalendar sessStartCal = new GregorianCalendar();
943
// sessStartCal.setTimeInMillis(timeOfSessionStart);
944
// int sessStartMillis = sessStartCal.get(MILLISECOND);
945
// if (timeDelta < -sessStartMillis) {
946
// return false;
947
// }
948
//
949
// final GregorianCalendar fileModCal = new GregorianCalendar();
950
// fileModCal.setTimeInMillis(lastModified);
951
// if (fileModCal.get(MILLISECOND) != 0) {
952
// /* So the file's timestamp does hold milliseconds! */
953
// return false;
954
// }
955
//
956
// /*
957
// * Now we know that milliseconds are not part of file's timestamp.
958
// * Let's substract the milliseconds part and check whether the delta is
959
// * non-negative, now that we only check seconds:
960
// */
961
// return lastModified >= (timeOfSessionStart - sessStartMillis);
962
}
963     
964 }
965
Popular Tags