root/trunk/src/java/org/jcoderz/phoenix/report/EmmaReportReader.java

Revision 1464, 10.7 kB (checked in by amandel, 3 years ago)

Small cleanup...

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Author Date Revision
Line 
1/*
2 * $Id$
3 *
4 * Copyright 2006, The jCoderZ.org Project. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 *    * Redistributions of source code must retain the above copyright
11 *      notice, this list of conditions and the following disclaimer.
12 *    * Redistributions in binary form must reproduce the above
13 *      copyright notice, this list of conditions and the following
14 *      disclaimer in the documentation and/or other materials
15 *      provided with the distribution.
16 *    * Neither the name of the jCoderZ.org Project nor the names of
17 *      its contributors may be used to endorse or promote products
18 *      derived from this software without specific prior written
19 *      permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS
25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33package org.jcoderz.phoenix.report;
34
35import java.io.File;
36import java.io.IOException;
37import java.util.ArrayList;
38import java.util.HashMap;
39import java.util.Iterator;
40import java.util.List;
41import java.util.Map;
42import java.util.Map.Entry;
43import java.util.logging.Level;
44import java.util.logging.Logger;
45
46import javax.xml.bind.JAXBException;
47
48import org.jcoderz.phoenix.report.jaxb.Item;
49import org.jcoderz.phoenix.report.jaxb.ObjectFactory;
50
51import com.vladium.emma.data.ClassDescriptor;
52import com.vladium.emma.data.DataFactory;
53import com.vladium.emma.data.ICoverageData;
54import com.vladium.emma.data.IMergeable;
55import com.vladium.emma.data.IMetaData;
56import com.vladium.emma.data.MethodDescriptor;
57import com.vladium.emma.data.ICoverageData.DataHolder;
58
59/**
60 * Reads the coverage report generated by emma (http://emma.sourceforge.net/).
61 *
62 * @author Andreas Mandel
63 */
64public class EmmaReportReader
65        extends AbstractReportReader
66{
67    /** JAXB context path. */
68    public static final String JCOVERAGE_JAXB_CONTEXT_PATH
69            = "org.jcoderz.phoenix.coverage.jaxb";
70
71    private static final String CLASSNAME
72            = EmmaReportReader.class.getName();
73
74    private static final Logger logger = Logger.getLogger(CLASSNAME);
75
76    /**
77     * Used if all branches of a line are covered. If there are 2
78     * branches in a line 1/2 of this value is assigned as hit
79     * counter.
80     */
81    private static final int EMMA_FULL_PERCENTAGE = 100;
82
83    private IMetaData mEmmaMetaData;
84    private ICoverageData mEmmaCoverageData;
85
86    EmmaReportReader ()
87            throws JAXBException
88    {
89        super(JCOVERAGE_JAXB_CONTEXT_PATH);
90    }
91
92    /** {@inheritDoc} */
93    public final void parse (File f)
94            throws JAXBException
95    {
96        try
97        {
98            final IMergeable[] emmaReport = DataFactory.load(f);
99            mEmmaMetaData = (IMetaData) emmaReport[DataFactory.TYPE_METADATA];
100            mEmmaCoverageData = (ICoverageData)
101                emmaReport[DataFactory.TYPE_COVERAGEDATA];
102            if (mEmmaMetaData == null)
103            {
104                logger.warning(
105                    "Read no meta data from emma in file '" + f + "'.");
106            }
107            if (mEmmaCoverageData == null)
108            {
109                logger.warning(
110                    "Read no coverage info from emma in file '" + f + "'.");
111            }
112        }
113        catch (IOException e)
114        {
115            throw new JAXBException("Cannot read Emma report at '"
116                +  f + "'.", e);
117        }
118    }
119
120    /** {@inheritDoc} */
121    public final Map<ResourceInfo, List<Item>> getItems ()
122        throws JAXBException
123    {
124        final Map<ResourceInfo, List<Item>> itemMap
125            = new HashMap<ResourceInfo, List<Item>>();
126
127        final Iterator<ClassDescriptor> i = mEmmaMetaData.iterator();
128        while (i.hasNext())
129        {
130            final ClassDescriptor clazz = i.next();
131            final String srcFileName = clazz.getSrcFileName();
132            final String fileName;
133            if (srcFileName != null)
134            {
135                fileName = srcFileName.substring(
136                    0, srcFileName.lastIndexOf('.'));
137            }
138            else
139            {   // fall back if data is not available.
140                fileName = clazz.getClassVMName().substring(
141                    clazz.getClassVMName().lastIndexOf('/') + 1);
142            }
143            final String classname
144                = clazz.getClassVMName().substring(
145                    clazz.getClassVMName().lastIndexOf('/') + 1);
146            final ResourceInfo source
147                = ResourceInfo.lookup(
148                    clazz.getPackageVMName().replaceAll("/", "."), fileName);
149            if (source != null)
150            {
151                if (logger.isLoggable(Level.FINER))
152                {
153                    logger.finer(
154                        "Processing coverage info for resource " + source);
155                }
156                processClazz(itemMap, source, clazz,
157                   mEmmaCoverageData == null
158                       ? null : mEmmaCoverageData.getCoverage(clazz));
159            }
160            else
161            {
162                if (logger.isLoggable(Level.FINER))
163                {
164                    logger.finer(
165                        "Ignoring coverage info for class "
166                        + clazz.getPackageVMName().replaceAll("/", ".") + "."
167                        + classname + "@" + clazz.getSrcFileName());
168                }
169            }
170        }
171        return itemMap;
172    }
173
174    private void processClazz (Map<ResourceInfo, List<Item>> itemMap, 
175        ResourceInfo source, ClassDescriptor clazz, DataHolder coverage)
176            throws JAXBException
177    {
178        logger.fine("Processing class '" + clazz.getName() + "'");
179
180        final Map<Integer, CoverageDetail> lineCoverage
181            = collectLineCoverage(clazz, coverage);
182
183        final List<Item> itemList
184            = createItemEntries(lineCoverage);
185
186        if (!itemList.isEmpty())
187        {
188            if (itemMap.containsKey(source))
189            {
190               final List<Item> l = itemMap.get(source);
191               l.addAll(itemList);
192            }
193            else
194            {
195               itemMap.put(source, itemList);
196            }
197        }
198    }
199
200    /**
201     * Collect all counters per line number mapping.
202     * Emma has a block view on the source but we need a line
203     * by line info.
204     * @param clazz the static info from emma
205     * @param coverage the dynamic coverage data
206     * @return a map mapping from line number to coverage data.
207     */
208    private Map<Integer, CoverageDetail> collectLineCoverage (
209        final ClassDescriptor clazz, DataHolder coverage)
210    {
211        final MethodDescriptor[] methods = clazz.getMethods();
212        final Map<Integer, CoverageDetail> lineCoverage
213            = new HashMap<Integer, CoverageDetail>();
214        for (int methodNr = 0; methodNr < methods.length; methodNr++)
215        {
216            final MethodDescriptor method = methods[methodNr];
217            if (method.getBlockSizes() != null
218                && method.getBlockMap() != null)
219            {
220                boolean[] methodCoverage = null;
221                if (coverage != null && coverage.m_coverage.length > methodNr)
222                {
223                    methodCoverage = coverage.m_coverage[methodNr];
224                }
225                final int[][] map = method.getBlockMap();
226                for (int blockNr = 0;
227                    blockNr < map.length; blockNr++)
228                {
229                    final int[] blockLines = map[blockNr];
230                    if (methodCoverage != null
231                        && methodCoverage.length > blockNr
232                        && methodCoverage[blockNr])
233                    {
234                        markCovered(lineCoverage, blockLines);
235                    }
236                    else
237                    {
238                        markNotCovered(lineCoverage, blockLines);
239                    }
240                }
241            }
242        }
243        return lineCoverage;
244    }
245
246    /**
247     * Creates finding report entries out of the line info.
248     * @param lineCoverage map from line number to its coverage info.
249     * @return a list of finding items.
250     * @throws JAXBException the the object creation for the jaxb
251     *  objects fails.
252     */
253    private List<Item> createItemEntries (
254        final Map<Integer, CoverageDetail> lineCoverage)
255        throws JAXBException
256    {
257        final List<Item> itemList = new ArrayList<Item>();
258        for (Entry<Integer, CoverageDetail> entry : lineCoverage.entrySet())
259        {
260           final CoverageDetail c = entry.getValue();
261           final Item item = new ObjectFactory().createItem();
262           item.setOrigin(Origin.COVERAGE);
263           if (c.mNotVisitedBranches > 0)
264           {
265               final int branches
266                   = c.mVisitedBranches + c.mNotVisitedBranches;
267               item.setCounter(
268                   (EMMA_FULL_PERCENTAGE * c.mVisitedBranches)
269                       / branches);
270           }
271           else
272           {
273               item.setCounter(EMMA_FULL_PERCENTAGE);
274           }
275           item.setLine(entry.getKey());
276           item.setSeverity(Severity.COVERAGE);
277           item.setFindingType("coverage"); // FIXME: use type
278           itemList.add(item);
279       }
280       return itemList;
281    }
282
283    private void markCovered (Map<Integer, CoverageDetail> lineCoverage,
284        int[] lines)
285    {
286        for (int line : lines)
287        {
288            getLine(lineCoverage, line).mVisitedBranches++;
289        }
290    }
291
292    private void markNotCovered (Map<Integer, CoverageDetail> lineCoverage,
293        int[] lines)
294    {
295        for (int line : lines)
296        {
297            getLine(lineCoverage, line).mNotVisitedBranches++;
298        }
299    }
300
301    private CoverageDetail getLine (
302        Map<Integer, CoverageDetail> lineCoverage, int line)
303    {
304        CoverageDetail result = lineCoverage.get(line);
305        if (result == null)
306        {
307            result = new CoverageDetail();
308            lineCoverage.put(line, result);
309        }
310        return result;
311    }
312
313
314    private static class CoverageDetail
315    {
316        private int mNotVisitedBranches;
317        private int mVisitedBranches;
318    }
319}
Note: See TracBrowser for help on using the browser.