blob: aba41f91e406669940be5f79876e19e942636f52 [file] [log] [blame]
/* Copyright (C) 2003 Vladimir Roubtsov. All rights reserved.
*
* This program and the accompanying materials are made available under
* the terms of the Common Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/cpl-v10.html
*
* $Id: ReportGenerator.java,v 1.1.1.1.2.1 2004/07/16 23:32:30 vlad_r Exp $
*/
package com.vladium.emma.report.txt;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedList;
import com.vladium.util.Files;
import com.vladium.util.IProperties;
import com.vladium.util.asserts.$assert;
import com.vladium.emma.IAppConstants;
import com.vladium.emma.IAppErrorCodes;
import com.vladium.emma.EMMAProperties;
import com.vladium.emma.EMMARuntimeException;
import com.vladium.emma.data.ICoverageData;
import com.vladium.emma.data.IMetaData;
import com.vladium.emma.report.AbstractReportGenerator;
import com.vladium.emma.report.AllItem;
import com.vladium.emma.report.ClassItem;
import com.vladium.emma.report.IItem;
import com.vladium.emma.report.IItemAttribute;
import com.vladium.emma.report.ItemComparator;
import com.vladium.emma.report.MethodItem;
import com.vladium.emma.report.PackageItem;
import com.vladium.emma.report.SourcePathCache;
import com.vladium.emma.report.SrcFileItem;
// ----------------------------------------------------------------------------
/**
* @author Vlad Roubtsov, (C) 2003
*/
public
final class ReportGenerator extends AbstractReportGenerator
implements IAppErrorCodes
{
// public: ................................................................
// TODO: this is prototype quality, needs major cleanup
// IReportGenerator:
public String getType ()
{
return TYPE;
}
public void process (final IMetaData mdata, final ICoverageData cdata,
final SourcePathCache cache, final IProperties properties)
throws EMMARuntimeException
{
initialize (mdata, cdata, cache, properties);
long start = 0, end;
final boolean trace1 = m_log.atTRACE1 ();
if (trace1) start = System.currentTimeMillis ();
{
m_queue = new LinkedList ();
for (m_queue.add (m_view.getRoot ()); ! m_queue.isEmpty (); )
{
final IItem head = (IItem) m_queue.removeFirst ();
head.accept (this, null);
}
line ();
close ();
}
if (trace1)
{
end = System.currentTimeMillis ();
m_log.trace1 ("process", "[" + getType () + "] report generated in " + (end - start) + " ms");
}
}
public void cleanup ()
{
m_queue = null;
close ();
super.cleanup ();
}
// IItemVisitor:
public Object visit (final AllItem item, final Object ctx)
{
File outFile = m_settings.getOutFile ();
if (outFile == null)
{
outFile = new File ("coverage.txt");
m_settings.setOutFile (outFile);
}
final File fullOutFile = Files.newFile (m_settings.getOutDir (), outFile);
m_log.info ("writing [" + getType () + "] report to [" + fullOutFile.getAbsolutePath () + "] ...");
openOutFile (fullOutFile, m_settings.getOutEncoding (), true);
// build ID stamp:
try
{
final StringBuffer label = new StringBuffer (101);
label.append ("[");
label.append (IAppConstants.APP_NAME);
label.append (" v"); label.append (IAppConstants.APP_VERSION_WITH_BUILD_ID_AND_TAG);
label.append (" report, generated ");
label.append (new Date (EMMAProperties.getTimeStamp ()));
label.append ("]");
m_out.write (label.toString ());
m_out.newLine ();
m_out.flush ();
}
catch (IOException ioe)
{
throw new EMMARuntimeException (IAppErrorCodes.REPORT_IO_FAILURE, ioe);
}
final int [] columns = m_settings.getColumnOrder ();
line ();
// [all] coverage summary row:
addTitleRow ("OVERALL COVERAGE SUMMARY", 0, 1);
{
// header row:
addHeaderRow (item, columns);
// coverage row:
addItemRow (item, columns);
}
// [all] stats summary table ([all] only):
addTitleRow ("OVERALL STATS SUMMARY", 1, 1);
{
row ("total packages:" + m_separator + item.getChildCount ());
row ("total classes:" + m_separator + item.getAggregate (IItem.TOTAL_CLASS_COUNT));
row ("total methods:" + m_separator + item.getAggregate (IItem.TOTAL_METHOD_COUNT));
if (m_srcView && m_hasSrcFileInfo)
{
row ("total executable files:" + m_separator + item.getAggregate (IItem.TOTAL_SRCFILE_COUNT));
if (m_hasLineNumberInfo)
row ("total executable lines:" + m_separator + item.getAggregate (IItem.TOTAL_LINE_COUNT));
}
}
final boolean deeper = (m_settings.getDepth () > item.getMetadata ().getTypeID ());
// render package summary rows:
addTitleRow ("COVERAGE BREAKDOWN BY PACKAGE", 1, 1);
{
boolean headerDone = false;
final ItemComparator order = m_typeSortComparators [PackageItem.getTypeMetadata ().getTypeID ()];
for (Iterator packages = item.getChildren (order); packages.hasNext (); )
{
final IItem pkg = (IItem) packages.next ();
if (! headerDone)
{
// header row:
addHeaderRow (pkg, columns);
headerDone = true;
}
// coverage row:
addItemRow (pkg, columns);
if (deeper) m_queue.addLast (pkg);
}
}
return ctx;
}
public Object visit (final PackageItem item, final Object ctx)
{
if (m_verbose) m_log.verbose (" report: processing package [" + item.getName () + "] ...");
final int [] columns = m_settings.getColumnOrder ();
line ();
// coverage summary row:
addTitleRow ("COVERAGE SUMMARY FOR PACKAGE [".concat (item.getName ()).concat ("]"), 0, 1);
{
// header row:
addHeaderRow (item, columns);
// coverage row:
addItemRow (item, columns);
}
final boolean deeper = (m_settings.getDepth () > item.getMetadata ().getTypeID ());
// render child summary rows:
final String summaryTitle = m_srcView ? "COVERAGE BREAKDOWN BY SOURCE FILE" : "COVERAGE BREAKDOWN BY CLASS";
addTitleRow (summaryTitle, 1, 1);
{
boolean headerDone = false;
final ItemComparator order = m_typeSortComparators [m_srcView ? SrcFileItem.getTypeMetadata ().getTypeID () : ClassItem.getTypeMetadata ().getTypeID ()];
for (Iterator srcORclsFiles = item.getChildren (order); srcORclsFiles.hasNext (); )
{
final IItem srcORcls = (IItem) srcORclsFiles.next ();
if (! headerDone)
{
// header row:
addHeaderRow (srcORcls, columns);
headerDone = true;
}
// coverage row:
addItemRow (srcORcls, columns);
if (deeper) m_queue.addLast (srcORcls);
}
}
return ctx;
}
public Object visit (final SrcFileItem item, final Object ctx)
{
final int [] columns = m_settings.getColumnOrder ();
line ();
// coverage summary row:
addTitleRow ("COVERAGE SUMMARY FOR SOURCE FILE [".concat (item.getName ()).concat ("]"), 0, 1);
{
// header row:
addHeaderRow (item, columns);
// coverage row:
addItemRow (item, columns);
}
// render child summary rows:
addTitleRow ("COVERAGE BREAKDOWN BY CLASS AND METHOD", 1, 1);
{
boolean headerDone = false;
final ItemComparator order = m_typeSortComparators [ClassItem.getTypeMetadata ().getTypeID ()];
for (Iterator classes = item.getChildren (order); classes.hasNext (); )
{
final IItem cls = (IItem) classes.next ();
if (! headerDone)
{
// header row:
addHeaderRow (cls, columns);
headerDone = true;
}
// coverage row:
//addItemRow (child, columns);
addTitleRow ("class [" + cls.getName () + "] methods", 0, 0);
// TODO: select the right comparator here
final ItemComparator order2 = m_typeSortComparators [MethodItem.getTypeMetadata ().getTypeID ()];
for (Iterator methods = cls.getChildren (order2); methods.hasNext (); )
{
final MethodItem method = (MethodItem) methods.next ();
addItemRow (method, columns);
}
}
}
return ctx;
}
public Object visit (final ClassItem item, final Object ctx)
{
final int [] columns = m_settings.getColumnOrder ();
line ();
// coverage summary row:
addTitleRow ("COVERAGE SUMMARY FOR CLASS [".concat (item.getName ()).concat ("]"), 0, 1);
{
// header row:
addHeaderRow (item, columns);
// coverage row:
addItemRow (item, columns);
}
// render child summary rows:
addTitleRow ("COVERAGE BREAKDOWN BY METHOD", 1, 1);
{
final ItemComparator order = m_typeSortComparators [MethodItem.getTypeMetadata ().getTypeID ()];
for (Iterator methods = item.getChildren (order); methods.hasNext (); )
{
final IItem method = (IItem) methods.next ();
// coverage row:
addItemRow (method, columns);
}
}
return ctx;
}
// protected: .............................................................
// package: ...............................................................
// private: ...............................................................
private void addTitleRow (final String text, final int hlines, final int flines)
{
for (int i = 0; i < hlines; ++ i) eol ();
row (new StringBuffer (text).append (":"));
for (int i = 0; i < flines; ++ i) eol ();
}
private void addHeaderRow (final IItem item, final int [] columns)
{
if ($assert.ENABLED)
{
$assert.ASSERT (item != null, "null input: item");
$assert.ASSERT (columns != null, "null input: columns");
}
// header row:
final StringBuffer buf = new StringBuffer ();
for (int c = 0, cLimit = columns.length; c < cLimit; ++ c)
{
final int attrID = columns [c];
final IItemAttribute attr = item.getAttribute (attrID, m_settings.getUnitsType ());
if (attr != null)
{
buf.append ('[');
buf.append (attr.getName ());
buf.append (']');
}
if (c != cLimit - 1) buf.append (m_separator);
}
row (buf);
}
/*
* No header row, just data rows.
*/
private void addItemRow (final IItem item, final int [] columns)
{
if ($assert.ENABLED)
{
$assert.ASSERT (item != null, "null input: item");
$assert.ASSERT (columns != null, "null input: columns");
}
final StringBuffer buf = new StringBuffer (11); // TODO: reuse a buffer
for (int c = 0, cLimit = columns.length; c < cLimit; ++ c)
{
final int attrID = columns [c];
final IItemAttribute attr = item.getAttribute (attrID, m_settings.getUnitsType ());
if (attr != null)
{
boolean fail = (m_metrics [attrID] > 0) && ! attr.passes (item, m_metrics [attrID]);
if (fail)
{
//buf.append ('(');
//buf.append ("! ");
attr.format (item, buf);
buf.append ('!');
//buf.append (')');
}
else
{
attr.format (item, buf);
}
}
if (c != cLimit - 1) buf.append (m_separator);
}
row (buf);
}
private void row (final StringBuffer str)
{
if ($assert.ENABLED) $assert.ASSERT (str != null, "str = null");
try
{
m_out.write (str.toString ());
m_out.newLine ();
}
catch (IOException ioe)
{
throw new EMMARuntimeException (IAppErrorCodes.REPORT_IO_FAILURE, ioe);
}
}
private void row (final String str)
{
if ($assert.ENABLED) $assert.ASSERT (str != null, "str = null");
try
{
m_out.write (str);
m_out.newLine ();
}
catch (IOException ioe)
{
throw new EMMARuntimeException (IAppErrorCodes.REPORT_IO_FAILURE, ioe);
}
}
private void line ()
{
try
{
m_out.write (LINE);
m_out.newLine ();
}
catch (IOException ioe)
{
throw new EMMARuntimeException (IAppErrorCodes.REPORT_IO_FAILURE, ioe);
}
}
private void eol ()
{
try
{
m_out.newLine ();
}
catch (IOException ioe)
{
throw new EMMARuntimeException (IAppErrorCodes.REPORT_IO_FAILURE, ioe);
}
}
private void close ()
{
if (m_out != null)
{
try
{
m_out.flush ();
m_out.close ();
}
catch (IOException ioe)
{
throw new EMMARuntimeException (IAppErrorCodes.REPORT_IO_FAILURE, ioe);
}
finally
{
m_out = null;
}
}
}
private void openOutFile (final File file, final String encoding, final boolean mkdirs)
{
try
{
if (mkdirs)
{
final File parent = file.getParentFile ();
if (parent != null) parent.mkdirs ();
}
m_out = new BufferedWriter (new OutputStreamWriter (new FileOutputStream (file), encoding), IO_BUF_SIZE);
}
catch (UnsupportedEncodingException uee)
{
// TODO: error code
throw new EMMARuntimeException (uee);
}
// note: in J2SDK 1.3 FileOutputStream constructor's throws clause
// was narrowed to FileNotFoundException:
catch (IOException fnfe) // FileNotFoundException
{
// TODO: error code
throw new EMMARuntimeException (fnfe);
}
}
private char m_separator = '\t'; // TODO: set this
private LinkedList /* IITem */ m_queue;
private BufferedWriter m_out;
private static final String TYPE = "txt";
private static final String LINE = "-------------------------------------------------------------------------------";
private static final int IO_BUF_SIZE = 32 * 1024;
} // end of class
// ----------------------------------------------------------------------------