All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com_atlassian_clover.Clover Maven / Gradle / Ivy

Go to download

Clover is an award winning code coverage and testing tool for Java and Groovy. It integrates easily with Maven, Ant, Grails, Eclipse and IntelliJ IDEA as well as with continuous integration servers such as Bamboo, Jenkins or Hudson. Note: before Clover 4.0 this artifact was named com.cenqua.clover:clover.

The newest version!
package com_atlassian_clover;

import com.atlassian.clover.instr.ForInstrumentation;
import com.atlassian.clover.CloverNames;
import com.atlassian.clover.CloverProperties;
import com.atlassian.clover.recorder.DelayedRecorder;
import com.atlassian.clover.Environment;
import com.atlassian.clover.ErrorInfo;
import com.atlassian.clover.recorder.FixedSizeCoverageRecorder;
import com.atlassian.clover.recorder.GrowableCoverageRecorder;
import com.atlassian.clover.Logger;
import com.atlassian.clover.recorder.NullRecorder;
import com.atlassian.clover.RecorderLogging;
import com.atlassian.clover.recorder.SharedCoverageRecorder;
import com.atlassian.clover.remote.DistributedClover;
import com.atlassian.clover.remote.RpcMessage;

import java.io.File;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;

/**
 * user-accessible runtime control for Clover
 */
public final class Clover {
    public static final int NO_SLICE = -1;
    public static final String SECURITY_EXCEPTION_MSG =
            "[CLOVER] FATAL ERROR: Clover could not be initialised because it has insufficient security privileges. "
            + "Please consult the Clover documentation on the security policy file changes required.";

    /**
     * Indicates if Clover has already initialised or in the process of initialisation.
     */
    private static volatile boolean initialisedOrInitialising = false;
    /**
     * The underlying Clover Runtime. Is either an instance of UnitialisedRuntime or InitialisedRuntime and
     * starts off as an UninitialisedRuntime.
     */
    private static volatile Runtime runtime = new UninitialisedRuntime();

    /**
     * Ensure Clover initialisation occurs. Supports re-entrant
     * calls so that initialisation only ever happens once. See CLOV-952
     *
     * @return for most use cases, will return an instance of InitialisedRuntime
     *         but where re-entrant calls occur and !initialisedOrInitialising for the first
     *         call, will return an instance of UninitialisedRuntime for all but the first in
     *         the call chain
     */
    private synchronized static Runtime ensureInitialised() {
        if (!initialisedOrInitialising) {
            initialisedOrInitialising = true;
            //it is possible that InitialisedRuntime's constructor may
            //cause certain customer systems to reentrantly call ensureInitialised()
            //which we must guard against with initialisedOrInitialising
            runtime = new InitialisedRuntime();
        }
        return runtime;
    }

    public static boolean isInitialised() {
        return runtime instanceof InitialisedRuntime;
    }

    ///CLOVER:OFF
    private Clover() {
    }
    ///CLOVER:ON

    /**
     * tell all reachable Clover recorders to flush
     */
    @ForInstrumentation
    public static void globalFlush() {
        ensureInitialised().globalFlush();
    }

    public static int getCurrentSlice() {
        return ensureInitialised().getCurrentSlice();
    }

    public static String getCurrentType() {
        return ensureInitialised().getCurrentType();
    }

    public static long getCurrentSliceStart() {
        return ensureInitialised().getCurrentSliceStart();
    }

    public static int getCurrentTestRunID() {
        return ensureInitialised().getCurrentTestRunID();
    }

    @ForInstrumentation
    public static CoverageRecorder getRecorder(
            final String initChars, final long dbVersion, final long cfgbits, final int maxNumElements,
            final CloverProfile[] profiles, final String[] nvpProperties) {
        return ensureInitialised().getRecorder(initChars, dbVersion, cfgbits, maxNumElements, profiles, nvpProperties);
    }

    public static int getTypeID(String runtimeType) {
        return ensureInitialised().getTypeID(runtimeType);
    }

    /**
     * For testing purposes only
     */
    public static void resetRecorders() {
        ensureInitialised().resetRecorders();
    }

    /**
     * @return whether any coverage recording has been attempted
     */
    public static boolean hasRecorded() {
        return ensureInitialised().hasRecorded();
    }

    public static void allRecordersFlush() {
        ensureInitialised().allRecordersFlush();
    }

    /**
     * Remebmer to update {@link com.atlassian.clover.remote.RpcMessage#METHODS} if you change method's signature.
     */
    public static void allRecordersSliceStart(final String type, final int slice, final long startTime) {
        ensureInitialised().allRecordersSliceStart(type, slice, startTime);
    }

    /**
     * Remebmer to update {@link com.atlassian.clover.remote.RpcMessage#METHODS} if you change method signature.
     */
    public static void allRecordersSliceEnd(final String type, final String method, final String runtimeTestName,
                                            final int slice, final int p, final ErrorInfo ei) {
        ensureInitialised().allRecordersSliceEnd(type, method, runtimeTestName, slice, p, ei);
    }

    /**
     * This is only public for CompilationCombinationTest#recordExecution
     */
    public static CoverageRecorder createRecorder(String dbName, long dbVersion, long cfgbits, int maxNumElements,
            CloverProfile profile, CloverProperties properties) {
        return ensureInitialised().createRecorder(dbName, dbVersion, cfgbits, maxNumElements, profile, properties);
    }

    // these two methods live here rather than in RecordingFile to limit the recording-time dependencies. RecordingFile
    // makes use of regex matchers which require JDK 1.4.

    /**
     * Returns Math.abs() for integer value. It ensures that returned value is always non-negative
     * (yes, Math.abs() can return negative value). In case of value=-2147483648 it returns
     * the nearest possible absolute value i.e. +2147483647.
     *
     * @param value input value
     * @return int non-negative Math.abs()
     */
    private static int abs(int value) {
        return (value != Integer.MIN_VALUE ? Math.abs(value) : Integer.MAX_VALUE);
    }

    /**
     * Returns Math.abs() for long value. It ensures that returned value is always non-negative
     * (yes, Math.abs() can return negative value). In case of value=-9223372036854775808 it returns
     * the nearest possible absolute value, i.e. +9223372036854775807.
     *
     * @param value input value
     * @return long non-negative Math.abs()
     */
    private static long abs(long value) {
        return (value != Long.MIN_VALUE ? Math.abs(value) : Long.MAX_VALUE);
    }

    /**
     * Generate a unique file name for recording snapshot.
     * See com.atlassian.clover.recorder.RecordingTranscripts#STD_REC_SUFFIX - regexp for recording name
     *
     * @param hash   unique hash identifying the coverage recorder
     * @param dbname base name of the clover database (used as prefix)
     * @param timestamp     snapshot timestamp
     * @return String generated file name
     */
    public static String getRecordingName(int hash, String dbname, long timestamp) {
        // make sure that we don't have a negative number to ensure that generated suffix components
        // match '[0-9a-z]*' pattern. yep, Math.abs can return negative value
        return dbname
                + Integer.toString(abs(hash), 36) + "_"
                + Long.toString(abs(timestamp), 36);
    }

    /**
     * Generate a unique file name for test slice recording snapshot.
     * See com.atlassian.clover.recorder.RecordingTranscripts#SLICE_SUFFIX - regexp for slice recording name
     * @param typeid    the runtime type id of the slice
     * @param methodID  test method identified
     * @param runID     number of test run of the method
     * @param hash      unique hash identifying the coverage recorder
     * @param dbname    base name of the clover database (used as prefix)
     * @param timestamp snapshot timestamp
     * @return String generated file name
     */
    public static String getSliceRecordingName(int typeid, int methodID, int runID, int hash, String dbname, long timestamp) {
        long globalSliceID = ((long) typeid) << 32 | methodID;
        // make sure that we don't have a negative number to ensure that generated suffix components
        // match '[0-9a-z]*' pattern
        return dbname
                + Long.toString(abs(globalSliceID), 36) + "_"
                + Integer.toString(abs(runID), 36) + "_"
                + Integer.toString(abs(hash), 36) + "_"
                + Long.toString(abs(timestamp), 36) + ".s";
    }

    ///CLOVER:OFF
    @ForInstrumentation
    public static void l(String m) {
        ensureInitialised().l(m);
    }

    @ForInstrumentation
    public static void l(String m, Throwable t) {
        ensureInitialised().l(m, t);
    }
    ///CLOVER:ON

    /**
     * @return an ErrorInfo holding the message and stactrace of Throwable t. *
     */
    public static ErrorInfo getErrorInfo(Throwable t) {
        return ensureInitialised().getErrorInfo(t);
    }

    @ForInstrumentation
    public static CoverageRecorder getNullRecorder() {
        return NullRecorder.INSTANCE;
    }

    public static String stackTraceFor(Throwable throwable) {
        return ensureInitialised().stackTraceFor(throwable);
    }

    /**
     * Utility method for resolving the registry file. Is safe to run whether Clover is initialised or not
     */
    static File resolveRegistryFile(String dbName, CloverProperties properties) {
        try {
            String initStringProp = Environment.substituteSysPropRefs(properties.getProperty(CloverNames.PROP_INITSTRING));
            if (initStringProp != null && initStringProp.length() > 0) {
                Logger.getInstance().verbose("overriding initstring: " + initStringProp);
                return new File(initStringProp);
            }
            String initStringBaseProp = Environment.substituteSysPropRefs(
                    properties.getProperty(CloverNames.PROP_INITSTRING_BASEDIR));
            if (initStringBaseProp != null && initStringBaseProp.length() > 0) {
                Logger.getInstance().verbose("overriding initstring basedir: " + initStringBaseProp);
                File dbFile = new File(dbName);
                return new File(initStringBaseProp, dbFile.getName());
            }
            String initStringPrefixProp = Environment.substituteSysPropRefs(
                    properties.getProperty(CloverNames.PROP_INITSTRING_PREFIX));
            if (initStringPrefixProp != null && initStringPrefixProp.length() > 0) {
                // HACK - this code does not take into acccount any drive letters that may be present
                // on dbName. To use a prefix, users should set relative="yes" to prevent the dbName being resolved
                // prior to this method
                Logger.getInstance().verbose("prepending initstring prefix: " + initStringPrefixProp);
                String newInit = initStringPrefixProp + dbName;
                // handle the case where two separators collide
                if ((initStringPrefixProp.endsWith("/") || initStringPrefixProp.endsWith("\\")) &&
                        (dbName.startsWith("\\") || dbName.startsWith("/"))) {
                    newInit = initStringPrefixProp + dbName.substring(1);
                }
                return new File(newInit);
            }
        } catch (SecurityException e) {
            ///CLOVER:OFF
            Logger.getInstance().verbose("Failed to retrieve Clover properties " + CloverNames.PROP_INITSTRING + "*", e);
            ///CLOVER:ON
            // ignore. can't do much if no perms, and don't want to complain about it because
            // the user most probably hasn't set any anyway.
        }
        return new File(dbName);
    }

    /**
     * Clover's runtime
     */
    private interface Runtime {
        void globalFlush();

        int getCurrentSlice();

        String getCurrentType();

        long getCurrentSliceStart();

        int getCurrentTestRunID();

        CoverageRecorder getRecorder(String initChars, long dbVersion, long cfgbits, int maxNumElements,
                CloverProfile[] profiles, String... nvpProperties);

        int getTypeID(String runtimeType);

        void resetRecorders();

        boolean hasRecorded();

        void allRecordersFlush();

        /**
         * Remebmer to update {@link com.atlassian.clover.remote.RpcMessage#METHODS} if you change method's signature.
         */
        void allRecordersSliceStart(String type, int slice, long startTime);

        /**
         * Remebmer to update {@link com.atlassian.clover.remote.RpcMessage#METHODS} if you change method's signature.
         */
        void allRecordersSliceEnd(String type, String method, String runtimeTestName, int slice, int p, ErrorInfo ei);

        CoverageRecorder createRecorder(String dbName, long dbVersion, long cfgbits, int maxNumElements,
                CloverProfile profile, CloverProperties properties);

        void l(String m);

        void l(String m, Throwable t);

        ErrorInfo getErrorInfo(Throwable t);

        String stackTraceFor(Throwable throwable);
    }

    /**
     * The unititialised Clover runtime. Most methods will fail with an IllegalStateException.
     * Notable exceptions are getRecorder(...) methods which will return a
     * {@link com.atlassian.clover.recorder.DelayedRecorder}
     * instance which will start collecting coverage once Clover is initialised
     */
    private static class UninitialisedRuntime implements Runtime {
        private void throwNotInitialisedException() {
            throw new IllegalStateException("Clover runtime not yet initialised.");
        }

        @Override
        public void globalFlush() {
            //no-op
        }

        @Override
        public boolean hasRecorded() {
            return false;
        }

        @Override
        public void l(String m) {
            //no-op
        }

        @Override
        public void l(String m, Throwable t) {
            //no-op
        }

        @Override
        public CoverageRecorder getRecorder(String initString, long dbVersion, long cfgbits, int maxNumElements,
                CloverProfile[] profiles, String... nvpProperties) {
            return new DelayedRecorder(initString, dbVersion, cfgbits, maxNumElements, profiles, nvpProperties);
        }

        @Override
        public int getCurrentSlice() {
            throwNotInitialisedException();
            return 0;
        }

        @Override
        public String getCurrentType() {
            throwNotInitialisedException();
            return null;
        }

        @Override
        public long getCurrentSliceStart() {
            throwNotInitialisedException();
            return 0;
        }

        @Override
        public int getCurrentTestRunID() {
            throwNotInitialisedException();
            return 0;
        }

        @Override
        public int getTypeID(String runtimeType) {
            throwNotInitialisedException();
            return 0;
        }

        @Override
        public void resetRecorders() {
            throwNotInitialisedException();
        }

        @Override
        public void allRecordersFlush() {
            throwNotInitialisedException();
        }

        @Override
        public void allRecordersSliceStart(String type, int slice, long startTime) {
            throwNotInitialisedException();
        }

        /**
         * Remebmer to update {@link com.atlassian.clover.remote.RpcMessage#METHODS} if you change method signature.
         */
        @Override
        public void allRecordersSliceEnd(String type, String method, String runtimeTestName,
                                         int slice, int p, ErrorInfo ei) {
            throwNotInitialisedException();
        }

        @Override
        public CoverageRecorder createRecorder(String dbName, long dbVersion, long cfgbits, int maxNumElements,
                CloverProfile profile, CloverProperties properties) {
            throwNotInitialisedException();
            return null;
        }

        @Override
        public ErrorInfo getErrorInfo(Throwable t) {
            throwNotInitialisedException();
            return null;
        }

        @Override
        public String stackTraceFor(Throwable throwable) {
            throwNotInitialisedException();
            return null;
        }
    }

    /**
     * The initialised Clover runtime
     */
    private static class InitialisedRuntime implements Runtime {
        private int currentSlice = NO_SLICE;
        private long currentSliceStart = 0;
        private String currentType;
        private int typeID;

        private int testRunID = 0;
        private final Map typeIDs;

        public InitialisedRuntime() {
            RecorderLogging.init();
            typeID = Math.abs((int) (System.currentTimeMillis() + Clover.class.hashCode()));
            typeIDs = Collections.synchronizedMap(new HashMap());
        }

        /**
         * tell all reachable Clover recorders to flush
         */
        @Override
        public void globalFlush() {
            allRecordersFlush();
        }

        @Override
        public int getCurrentSlice() {
            return currentSlice;
        }

        @Override
        public String getCurrentType() {
            return currentType;
        }

        @Override
        public long getCurrentSliceStart() {
            return currentSliceStart;
        }

        @Override
        public int getCurrentTestRunID() {
            return testRunID;
        }

        /**
         * map of configured recorder instances *
         */
        private final HashMap RECORDERS = new HashMap<>();

        private DistributedClover distributedRuntime = null;

        /**
         * Cached value of 'clover.profile' system property
         */
        private volatile String cloverProfileName;

        /**
         * Gets called from a static initialisation block in an inner class in each instrumented Java source file.
         */
        @Override
        public CoverageRecorder getRecorder(final String initString,
                final long dbVersion,
                final long cfgbits,
                final int maxNumElements,
                final CloverProfile[] profiles,
                final String... nvpProperties) {

            final CloverProperties properties = new CloverProperties(nvpProperties);

            return AccessController.doPrivileged(new PrivilegedAction() {
                @Override
                public CoverageRecorder run() {
                    // find current profile (if any)
                    final CloverProfile currentProfile = selectCloverProfile(profiles);
                    // use proper key depending on coverage recorder type
                    final String recorderKey =
                            (currentProfile != null && currentProfile.getCoverageRecorder() == CloverProfile.CoverageRecorderType.SHARED) ?
                                    initString + "_" + cfgbits                      // shared
                                    : initString + "_" + dbVersion + "_" + cfgbits; // fixed or growable

                    CoverageRecorder recorder;
                    synchronized (RECORDERS) {
                        // find existing recorder ...
                        recorder = RECORDERS.get(recorderKey);
                        if (recorder != null) {
                            // ... and resize if necessary
                            Logger.getInstance().debug("[found existing recorder for " + recorderKey + "]");
                            recorder = recorder.withCapacityFor(maxNumElements);
                        } else {
                            // ... or create new one
                            if (Logger.isDebug()) {
                                Logger.getInstance().debug(
                                        "Clover.getRecorder("
                                                + initString + ", "
                                                + dbVersion + ", "
                                                + cfgbits + ", "
                                                + maxNumElements + ", "
                                                + properties + ") "
                                                + "resulting in new recorder called from (first 10 stack elements):\n" +
                                                callerChain(10));
                            }

                            Logger.getInstance().debug("[creating new recorder for " + recorderKey + "]");
                            recorder = createRecorder(initString, dbVersion, cfgbits, maxNumElements, currentProfile, properties);
                            recorder.startRun();
                        }

                        // growable/shared recorders may have emitted a new proxy so use this as the latest version
                        RECORDERS.put(recorderKey, recorder);

                        if (distributedRuntime == null) {
                            distributedRuntime = new DistributedClover(properties, currentProfile);
                        }

                        return recorder;
                    }
                }
            });
        }

        private String callerChain(int maxDepth) {
            final LinkedList elements = new LinkedList<>(
                    Arrays.asList(new Exception().getStackTrace()));
            elements.removeFirst();
            elements.removeFirst();
            final StringBuilder buf = new StringBuilder();
            final Iterator iterator = elements.iterator();
            int depth = 0;
            while (iterator.hasNext() && depth < maxDepth) {
                final StackTraceElement element = iterator.next();
                if (element.getClassName().startsWith("sun.reflect")
                        || element.getClassName().startsWith("java.lang.reflect")) {
                    iterator.remove();
                } else {
                    buf.append(element);
                    buf.append("\n");
                    depth++;
                }
            }
            return buf.toString();
        }

        @Override
        public int getTypeID(String runtimeType) {
            int result;
            Integer val = typeIDs.get(runtimeType);
            if (val == null) {
                //Not thread-safe but also not important (implies a multi-threaded test which we don't support)
                result = typeID++;
                typeIDs.put(runtimeType, result);
            } else {
                result = val;
            }
            return result;
        }

        /**
         * For testing purposes only
         */
        @Override
        public void resetRecorders() {
            synchronized (RECORDERS) {
                RECORDERS.clear();
            }
        }

        /**
         * @return whether any coverage recording has been attempted
         */
        @Override
        public boolean hasRecorded() {
            return RECORDERS.size() > 0;
        }

        @Override
        public void allRecordersFlush() {
            AccessController.doPrivileged(new PrivilegedAction() {
                @Override
                public Void run() {
                    synchronized (RECORDERS) {
                        for (CoverageRecorder recorder : RECORDERS.values()) {
                            recorder.forceFlush();
                        }
                    }
                    return null;
                }
            });
        }

        @Override
        public void allRecordersSliceStart(final String type, final int slice, final long startTime) {
            AccessController.doPrivileged(new PrivilegedAction() {
                @Override
                public Void run() {
                    synchronized (RECORDERS) {
                        currentSlice = slice;
                        currentSliceStart = startTime > 0 ? startTime : System.currentTimeMillis();
                        currentType = type;

                        for (CoverageRecorder recorder : RECORDERS.values()) {
                            recorder.sliceStart(type, currentSliceStart, slice, testRunID);
                        }
                        if (distributedRuntime != null) {
                            // see CajoTcpRecorderListener.allRecordersSliceStart signature
                            distributedRuntime.remoteFlush(
                                    RpcMessage.createMethodStart(type, slice, currentSliceStart));
                        }
                    }
                    return null;
                }
            });
        }

        @Override
        public void allRecordersSliceEnd(final String type, final String method, /*@Nullable*/ final String runtimeTestName,
                                         final int slice, final int p, final ErrorInfo ei) {
            AccessController.doPrivileged(new PrivilegedAction() {
                @Override
                public Void run() {
                    synchronized (RECORDERS) {
                        currentSlice = NO_SLICE;
                        long ts = System.currentTimeMillis();
                        for (CoverageRecorder recorder : RECORDERS.values()) {
                            recorder.sliceEnd(type, method, runtimeTestName, ts, slice, testRunID, p, ei);
                        }
                        if (distributedRuntime != null) {
                            // see CajoTcpRecorderListener.allRecordersSliceEnd signature
                            distributedRuntime.remoteFlush(
                                    RpcMessage.createMethodEnd(type, method, runtimeTestName, slice, p, ei));
                        }
                        testRunID++;
                    }

                    return null;
                }
            });

        }

        /**
         * This is only public for CompilationCombinationTest#recordExecution
         */
        @Override
        public CoverageRecorder createRecorder(String dbName, long dbVersion, long cfgbits, int maxNumElements,
                CloverProfile currentProfile, CloverProperties properties) {
            File dbFile = resolveRegistryFile(dbName, properties);

            try {
                // return null recorder if user wants to disable Clover at runtime
                if (isDisableClover()) {
                    Logger.getInstance().verbose("CLOVER: The system property '" + CloverNames.PROP_ENABLE + "' is set to false. Coverage recording is disabled.");
                    return NullRecorder.INSTANCE;
                }

                if ( (currentProfile == null || currentProfile.getCoverageRecorder() == CloverProfile.CoverageRecorderType.FIXED)
                        && (dbFile.exists() && !dbFile.isDirectory() && dbFile.canRead()) ) {
                    // fixed coverage recorder when: no profiles or specified in a profile and database is accessible
                    return FixedSizeCoverageRecorder.createFor(dbFile, dbVersion, maxNumElements, cfgbits);
                } else if (currentProfile != null && currentProfile.getCoverageRecorder() == CloverProfile.CoverageRecorderType.GROWABLE) {
                    // growable coverage recorder: when specified in a profile
                    return GrowableCoverageRecorder.createFor(dbFile.getAbsolutePath(), dbVersion, cfgbits, maxNumElements);
                } else if (currentProfile != null && currentProfile.getCoverageRecorder() == CloverProfile.CoverageRecorderType.SHARED) {
                    // shared coverage recorder: when specified in a profile
                    return SharedCoverageRecorder.createFor(dbFile.getAbsolutePath(), dbVersion, cfgbits, maxNumElements);
                } else {
                    logRecorderCreationFailure(dbFile, null);
                }
            } catch (SecurityException e) {
                Logger.getInstance().warn(SECURITY_EXCEPTION_MSG);
                logRecorderCreationFailure(dbFile, e);
            } catch (Throwable e) {
                logRecorderCreationFailure(dbFile, e);
                if (e instanceof Error) {
                    throw (Error) e;
                }
            }

            return NullRecorder.INSTANCE;
        }

        /**
         * Returns true if Clover coverage recording shall be disabled at runtime.
         * @return true if disabled, false if enabled
         */
        private boolean isDisableClover() {
            try {
                String cloverEnable = System.getProperty(CloverNames.PROP_ENABLE);
                // disable Clover only if user explicitly sets this property to false
                return cloverEnable != null && (cloverEnable.equalsIgnoreCase("false") || cloverEnable.equalsIgnoreCase("no"));
            } catch (SecurityException ex) {
                Logger.getInstance().verbose("Unable to read '" + CloverNames.PROP_ENABLE + "' property. Assuming that Clover is enabled.");
                return false;
            }
        }

        /**
         * Select proper runtime profile:
         * 
         * 1. profiles are not empty?
         *    YES: 2. read {@link CloverNames#PROP_CLOVER_PROFILE} property. success?
         *            YES: ok
         *            NO: assume profile name = "default"
         *         3. find profile on a list. found?
         *            YES: return profile
         *            NO: return null
         *    NO: return null
         * 
* * Note: call in AccessController.doPrivileged() as it reads system property. * * @param profiles available profiles to choose from * @return CloverProfile or null */ private CloverProfile selectCloverProfile(final CloverProfile[] profiles) { // 1. profiles are empty? if (profiles == null || profiles.length == 0) { Logger.getInstance().debug("CLOVER: No profiles defined in instrumented classes. Using standard settings."); return null; } // 2. read system property or take cached value if (cloverProfileName == null) { synchronized(this) { try { cloverProfileName = System.getProperty(CloverNames.PROP_CLOVER_PROFILE); if (cloverProfileName == null) { Logger.getInstance().debug("CLOVER: System property '" + CloverNames.PROP_CLOVER_PROFILE + "' was not found. Assuming the 'default' profile."); cloverProfileName = CloverProfile.DEFAULT_NAME; } } catch (SecurityException ex) { Logger.getInstance().verbose("CLOVER: Unable to read '" + CloverNames.PROP_CLOVER_PROFILE + "' system property. Assuming the 'default' profile.", ex); cloverProfileName = CloverProfile.DEFAULT_NAME; } } } // 3. profile found? for (CloverProfile profile : profiles) { if (profile.getName().equals(cloverProfileName)) { Logger.getInstance().verbose( "CLOVER: Using profile '" + cloverProfileName + "' with settings " + "[coverageRecorder=" + profile.getCoverageRecorder() + ( profile.getDistributedCoverage() != null ? " distributedCoverage=" + profile.getDistributedCoverage().getConfigString() : "") + "]"); return profile; } } Logger.getInstance().verbose( "CLOVER: Profile '" + cloverProfileName + "' not found in instrumented classes. Using standard settings."); return null; } private void logRecorderCreationFailure(File dbFile, Throwable t) { Logger.getInstance().error("CLOVER: Unable to load the coverage database at \"" + dbFile.getAbsolutePath() + "\""); Logger.getInstance().error("CLOVER: No coverage data will be gathered."); if (t != null) { Logger.getInstance().error("CLOVER: " + t.getClass().getName()); if (t.getMessage() != null) { Logger.getInstance().error("CLOVER: " + t.getMessage(), t); } } } ///CLOVER:OFF @Override public void l(String m) { Logger.getInstance().error(m); } @Override public void l(String m, Throwable t) { Logger.getInstance().error(m, t); } ///CLOVER:ON /** * @return an ErrorInfo holding the message and stactrace of Throwable t. * */ @Override public ErrorInfo getErrorInfo(Throwable t) { return t == null ? null : new ErrorInfo(t.getMessage(), stackTraceFor(t)); } @Override public String stackTraceFor(Throwable throwable) { StringWriter sw = new StringWriter(); throwable.printStackTrace(new PrintWriter(sw)); return sw.toString(); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy