com.sun.tdk.jcov.report.ClassCoverage.java Source code

Java tutorial

Introduction

Here is the source code for com.sun.tdk.jcov.report.ClassCoverage.java

Source

/*
 * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */
package com.sun.tdk.jcov.report;

import com.sun.tdk.jcov.data.Scale;
import com.sun.tdk.jcov.filter.MemberFilter;
import com.sun.tdk.jcov.instrument.DataClass;
import com.sun.tdk.jcov.instrument.DataField;
import com.sun.tdk.jcov.instrument.DataMethod;
import com.sun.tdk.jcov.report.javap.JavapClass;
import com.sun.tdk.jcov.util.Utils;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.objectweb.asm.Opcodes;

/**
 * <p> This class provides access to class coverage information. Sums of
 * underlying coverage information can be obtained by
 * <code>getData(DataType)</code> method using DataType.CLASS, DataType.METHOD,
 * DataType.FIELD, DataType.BLOCK, DataType.BRANCH, DataType.LINE. </p> <p> To
 * access specific method/field information use
 * <code>getMethodCoverageList()</code> and
 * <code>getFieldCoverageList()</code> methods </p>
 *
 * @see ProductCoverage
 * @see DataType
 * @see CoverageData
 *
 * @author Dmitry Fazunenko
 * @author Alexey Fedorchenko
 */
public class ClassCoverage extends AbstractCoverage {

    private String source;
    private boolean javapSource = false;
    private JavapClass javapClass;
    private List<MethodCoverage> methods = new ArrayList<MethodCoverage>();
    private List<FieldCoverage> fields = new ArrayList<FieldCoverage>();
    private LineCoverage lineCoverage = new LineCoverage();
    private DataType[] supportedColumns = { DataType.CLASS, DataType.METHOD, DataType.FIELD, DataType.BLOCK,
            DataType.BRANCH, DataType.LINE };
    private int access;
    private String fullname;
    private String name;
    private String packagename;

    /**
     * <p> Creates new ClassCoverage instance. </p>
     *
     * @param clz DataClass to read data from
     * @param srcRootPaths Paths for sources
     * @param filter Allows to filter read data
     */
    public ClassCoverage(DataClass clz, String srcRootPaths[], MemberFilter filter) {
        this(clz, srcRootPaths, null, filter);
    }

    public ClassCoverage(DataClass clz, String srcRootPaths[], List<JavapClass> javapClasses, MemberFilter filter) {
        this(clz, srcRootPaths, null, filter, false);
    }

    public ClassCoverage(DataClass clz, String srcRootPaths[], List<JavapClass> javapClasses, MemberFilter filter,
            boolean anonym) {
        access = clz.getAccess();
        fullname = clz.getFullname();
        name = clz.getName();
        packagename = clz.getPackageName();

        for (DataMethod method : clz.getMethods()) {
            if (filter != null && !filter.accept(clz, method)) {
                continue;
            }

            MethodCoverage methodCoverage = new MethodCoverage(method);
            methodCoverage.setAnonymOn(anonym);
            if (method.getName() != null && method.getName().matches("\\$\\d.*")) {
                methodCoverage.setInAnonymClass(true);
            }
            methods.add(methodCoverage);
            lineCoverage.processLineCoverage(methodCoverage.getLineCoverage());
        }
        for (DataField field : clz.getFields()) {
            if (filter != null && !filter.accept(clz, field)) {
                continue;
            }

            FieldCoverage fieldCoverage = new FieldCoverage(field);
            fields.add(fieldCoverage);
        }

        if (javapClasses == null) {
            this.source = findBestSource(clz, srcRootPaths);
        } else {
            javapSource = true;

            for (JavapClass jpClass : javapClasses) {
                if (jpClass != null && jpClass.getClassName() != null && (jpClass.getClassName()).equals(name)) {

                    javapClass = jpClass;
                    break;
                }
            }
        }

        Collections.sort(methods);
        Collections.sort(fields);
    }

    /**
     * @return true if the class doesn't contain neither methods or fields
     */
    public boolean isEmpty() {
        return methods.isEmpty() && fields.isEmpty();
    }

    /**
     * <p> Use getAccess() method to check for more specific modifiers.
     * getAccess() method returns a bit-mask of org.objectweb.asm.Opcodes
     * constants. </p>
     *
     * @return true if class access modifiers are <b>public</b> or
     * <b>protected</b>
     * @see ClassCoverage#getAccess()
     */
    public boolean isPublicAPI() {
        return (access & (Opcodes.ACC_PUBLIC | Opcodes.ACC_PROTECTED)) != 0;
    }

    /**
     * <p> Use getAccess() method to check for more specific modifiers.
     * getAccess() method returns a bit-mask of org.objectweb.asm.Opcodes
     * constants. </p>
     *
     * @return true if class is <b>public</b> or <b>protected</b>
     * @see ClassCoverage#getAccess()
     */
    public boolean isPublic() {
        return (access & Opcodes.ACC_PUBLIC) != 0;
    }

    /**
     * <p> Use getAccess() method to check for more specific modifiers.
     * getAccess() method returns a bit-mask of org.objectweb.asm.Opcodes
     * constants. </p>
     *
     * @return true if class is <b>public</b>
     * @see ClassCoverage#getAccess()
     */
    public boolean isPrivate() {
        return (access & Opcodes.ACC_PRIVATE) != 0;
    }

    /**
     * <p> Use getAccess() method to check for more specific modifiers.
     * getAccess() method returns a bit-mask of org.objectweb.asm.Opcodes
     * constants. </p>
     *
     * @return true if class is <b>protected</b>
     * @see ClassCoverage#getAccess()
     */
    public boolean isProtected() {
        return (access & Opcodes.ACC_PROTECTED) != 0;
    }

    /**
     * <p> Use getAccess() method to check for more specific modifiers.
     * getAccess() method returns a bit-mask of org.objectweb.asm.Opcodes
     * constants. </p>
     *
     * @return true if class is <b>abstract</b>
     * @see ClassCoverage#getAccess()
     */
    public boolean isAbstract() {
        return (access & Opcodes.ACC_ABSTRACT) != 0;
    }

    /**
     * <p> Use getAccess() method to check for more specific modifiers.
     * getAccess() method returns a bit-mask of org.objectweb.asm.Opcodes
     * constants. </p>
     *
     * @return true if class is <b>final</b>
     * @see ClassCoverage#getAccess()
     */
    public boolean isFinal() {
        return (access & Opcodes.ACC_FINAL) != 0;
    }

    /**
     * <p> Use this method to check for specific modifiers. </p>
     *
     * @return Access bit-mask of org.objectweb.asm.Opcodes constants.
     * @see Opcodes
     */
    public int getAccess() {
        return access;
    }

    /**
     * @param test Number of a test in the testlist
     * @return true when any method in this class is marked as hit by the
     * <b>test</b> bit in scales
     * @see Scale
     */
    public boolean isCoveredByTest(int test) {
        for (MethodCoverage method : methods) {
            Scale s = method.getScale();
            if (s != null && s.isBitSet(test)) {
                return true;
            }
        }
        return false;
    }

    /**
     * @return classname in VM notation
     */
    public String getName() {
        return name;
    }

    /**
     * @return getData(DataType.CLASS_COVERED) > 0;
     */
    public boolean isCovered() {
        for (MethodCoverage method : methods) {
            if (method.count > 0) {
                return true;
            }
        }
        return false;
    }

    /**
     * @return methods in this class
     */
    public List<MethodCoverage> getMethods() {
        return methods;
    }

    /**
     * @return fields in this class
     */
    public List<FieldCoverage> getFields() {
        return fields;
    }

    /**
     * @return package name in VM notation
     */
    public String getPackageName() {
        return packagename;
    }

    /**
     * @return canonical classname
     */
    public String getFullClassName() {
        return fullname.replace('/', '.');
    }

    /**
     * @return classname in VM notation ('/' as package separators)
     */
    public String getFullClassNameFilename() {
        return fullname;
    }

    /**
     * Get class sourcefile
     *
     * @return class sourcefile
     */
    public String getSource() {
        return source;
    }

    public boolean isJavapSource() {
        return javapSource;
    }

    public JavapClass getJavapClass() {
        return javapClass;
    }

    /**
     * Coverage kind (used in HTML reports as header for label)
     *
     * @return DataType.CLASS
     */
    public DataType getDataType() {
        return DataType.CLASS;
    }

    protected DataType[] getDataTypes() {
        return supportedColumns;
    }

    /**
     * Returns true if passed line is covered, false otherwise.
     *
     * @param lineNum line number
     * @return true if passed line is covered, false otherwise.
     */
    public boolean isLineCovered(int lineNum) {
        return lineCoverage.isLineCovered(lineNum);
    }

    /**
     * Returns true if the line with the given number contains java code
     *
     * @param lineNum line number
     * @return true if the line with the given number contains java code
     */
    public boolean isCode(long lineNum) {
        return lineCoverage.isCode(lineNum);
    }

    /**
     * <p> Allows to get sums over the coverage of this class. E.g.
     * getData(DataType.METHOD) will return coverage data containing the total
     * number of methods in this class and number of covered methods in this
     * class. </p> <p> Allows to sum though CLASS, METHOD, FIELD, BLOCK, BRANCH
     * and LINE types </p>
     *
     * @param column Type to sum
     * @return CoverageData representing 2 fields - total number of members and
     * number of covered members
     * @see DataType
     * @see CoverageData
     */
    public CoverageData getData(DataType column, int testNumber) {
        switch (column) {
        case CLASS:
            for (MethodCoverage method : methods) {
                if (method.count > 0 && (testNumber < 0 || method.isCoveredByTest(testNumber))) {
                    return new CoverageData(1, 1);
                }
            }
            return new CoverageData(0, 1);
        case METHOD:
        case BLOCK:
        case BRANCH:
            CoverageData covered = new CoverageData(0, 0);
            for (MethodCoverage method : methods) {
                if (testNumber < 0 || method.isCoveredByTest(testNumber)) {
                    covered.add(method.getData(column, testNumber));
                } else {
                    covered.add(new CoverageData(0, method.getData(column, testNumber).getTotal()));
                }
            }
            return covered;
        case FIELD:
            covered = new CoverageData(0, 0);
            for (FieldCoverage field : fields) {
                covered.add(field.getData(column));
            }
            return covered;
        case LINE:
            return new CoverageData(lineCoverage.getCovered(), lineCoverage.getTotal());
        default:
            return new CoverageData();
        }
    }

    public CoverageData getData(DataType column) {
        return getData(column, -1);
    }

    /**
     * Finds a source that is the most acceptable for this DataClass
     *
     * @param clz
     * @param source_paths
     * @return
     */
    private static String findBestSource(DataClass clz, String[] source_paths) {

        if (source_paths == null) {
            return clz.getSource();
        }

        final char sep = File.separatorChar;

        String source_name = clz.getSource();
        boolean dummy = false;

        if (source_name == null) {
            String clzName = clz.getName();
            int indexOf = clzName.indexOf('$');
            if (indexOf > 0) {
                clzName = clzName.substring(0, indexOf);
            } else {
                clzName = clzName + ".java";
            }

            source_name = clzName;
            dummy = true;
        }

        if (source_name.startsWith(pref) && source_name.endsWith(suff)) {
            source_name = source_name.substring(0, source_name.length() - suff.length());
            source_name = source_name.substring(pref.length());
            dummy = true;
        }
        source_name = source_name.replace('/', sep);
        source_name = source_name.replace('\\', sep);
        source_name = Utils.basename(source_name);
        if (dummy) {
            int i = source_name.indexOf("$");
            if (i > 0) {
                source_name = source_name.substring(0, i) + ".java";
            }
        }
        String pckg = clz.getPackageName();
        source_name = pckg.replace('/', File.separatorChar) + sep + source_name;

        for (int i = 0; i < source_paths.length; i++) {
            File f = new File(source_paths[i] + source_name);
            if (f.exists()) {
                return f.getAbsolutePath();
            }
        }
        return clz.getSource(); // not found
    }

    static final String pref = "<UNKNOWN_SOURCE/";
    static final String suff = ">";
}