/** * Copyright (C) 2010-2017 Gordon Fraser, Andrea Arcuri and EvoSuite * contributors * * This file is part of EvoSuite. * * EvoSuite is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation, either version 3.0 of the License, or * (at your option) any later version. * * EvoSuite 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 * Lesser Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with EvoSuite. If not, see <http://www.gnu.org/licenses/>. */ package org.evosuite.testcarver.capture; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import org.evosuite.TimeController; import org.evosuite.testcarver.exception.CapturerException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.io.xml.StaxDriver; public final class Capturer { private static CaptureLog currentLog; private static boolean isCaptureStarted = false; private static boolean isShutdownHookAdded = false; private static final ArrayList<CaptureLog> logs = new ArrayList<CaptureLog>(); public static final String DEFAULT_SAVE_LOC = "captured.log"; private static final ArrayList<String[]> classesToBeObserved = new ArrayList<String[]>(); private static final transient Logger logger = LoggerFactory.getLogger(Capturer.class); /* * TODO this needs refactoring. */ @Deprecated private static void initShutdownHook() { Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() { @Override public void run() { logger.info("shutting down..."); Capturer.stopCapture(); Capturer.postProcess(); logger.info("shut down"); } })); } @Deprecated public static void postProcess() { /* if(! Capturer.isCapturing()) { if(! logs.isEmpty()) { try { // LOG.info("Saving captured log to {}", DEFAULT_SAVE_LOC); // final File targetFile = new File(DEFAULT_SAVE_LOC); // Capturer.save(new FileOutputStream(targetFile)); PostProcessor.init(); final ArrayList<String> pkgNames = new ArrayList<String>(); final ArrayList<Class<?>[]> obsClasses = new ArrayList<Class<?>[]>(); int searchIndex; for(String[] classNames : Capturer.classesToBeObserved) { searchIndex = classNames[0].lastIndexOf('.'); if(searchIndex > -1) { pkgNames.add(classNames[0].substring(0, searchIndex)); } else { pkgNames.add(""); } final Class<?> [] clazzes = new Class<?>[classNames.length]; for(int j = 0; j < classNames.length; j++) { clazzes[j] = Class.forName(classNames[j]); } obsClasses.add(clazzes); } PostProcessor.process(logs, pkgNames, obsClasses); Capturer.clear(); } catch(final Exception e) { logger.error("an error occurred while post proccessin", e); } } } */ } public static void save(final OutputStream out) throws IOException { if (out == null) { throw new NullPointerException("given OutputStream must not be null"); } final XStream xstream = new XStream(); xstream.toXML(logs, out); out.close(); } @SuppressWarnings("unchecked") public static void load(final InputStream in) { if (in == null) { throw new NullPointerException("given InputStream must not be null"); } final XStream xstream = new XStream(new StaxDriver()); logs.addAll((ArrayList<CaptureLog>) xstream.fromXML(in)); } public static void clear() { currentLog = null; logs.clear(); classesToBeObserved.clear(); isCaptureStarted = false; FieldRegistry.clear(); } public static void startCapture() { logger.info("Starting Capturer..."); if (isCaptureStarted) { throw new IllegalStateException("Capture has already been started"); } currentLog = new CaptureLog(); isCaptureStarted = true; FieldRegistry.restoreForegoingGETSTATIC(); logger.info("Capturer has been started successfully"); } public static void startCapture(final String classesToBeObservedString) { if (classesToBeObservedString == null) { final String msg = "no arguments specified"; logger.error(msg); throw new CapturerException(msg); } final ArrayList<String> args = new ArrayList<String>( Arrays.asList(classesToBeObservedString.split("\\s+"))); if (args.isEmpty()) { final String msg = "no class to be observed specified"; logger.error(msg); throw new CapturerException(msg); } // start Capturer if not active yet // NOTE: Stopping the capture and saving the corresponding logs is handled in the ShutdownHook // which is automatically initialized in the Capturer Capturer.startCapture(args); } public static void startCapture(final List<String> classesToBeObserved) { logger.info("Starting Capturer..."); if (isCaptureStarted) { throw new IllegalStateException("Capture has already been started"); } /* * TODO need refactoring * if(! isShutdownHookAdded) { initShutdownHook(); isShutdownHookAdded = true; } */ currentLog = new CaptureLog(); isCaptureStarted = true; final int size = classesToBeObserved.size(); final String[] clazzes = new String[size]; for (int i = 0; i < size; i++) { clazzes[i] = classesToBeObserved.get(i); } Capturer.classesToBeObserved.add(clazzes); FieldRegistry.restoreForegoingGETSTATIC(); logger.info("Capturer has been started successfully"); } public static CaptureLog stopCapture() { logger.info("Stopping Capturer..."); if (isCaptureStarted) { isCaptureStarted = false; logs.add(currentLog); final CaptureLog log = currentLog; currentLog = null; logger.info("Capturer has been stopped successfully"); FieldRegistry.clear(); logger.debug("Done"); return log; } logger.debug("Done"); return null; } public static boolean isCapturing() { return isCaptureStarted; } public static void setCapturing(final boolean isCapturing) { Capturer.isCaptureStarted = isCapturing; } public static void capture(final int captureId, final Object receiver, final String methodName, final String methodDesc, final Object[] methodParams) { try { if (isCapturing()) { //(currentLog) { setCapturing(false); if (logger.isDebugEnabled()) { logger.debug("Method call captured: captureId={} receiver={} type={} method={} methodDesc={} params={}", captureId, System.identityHashCode(receiver), receiver.getClass().getName(), methodName, methodDesc, Arrays.toString(methodParams)); } currentLog.log(captureId, receiver, methodName, methodDesc, methodParams); if(TimeController.getInstance().isThereStillTimeInThisPhase()) setCapturing(true); //} } } catch(Throwable t) { // TODO: Handle properly? logger.debug(t.toString()); } } @SuppressWarnings("unchecked") public static List<CaptureLog> getCaptureLogs() { return (List<CaptureLog>) logs.clone(); } public static void enable(final int captureId, final Object receiver, final Object returnValue) { try { if (isCapturing()) { //(currentLog) { setCapturing(false); if (logger.isDebugEnabled()) { logger.debug("enabled: capturedId={}", captureId); //logger.debug("enabled: capturedId={} receiver={} returnValue={} returnValueOID={}", // new Object[] { captureId, // System.identityHashCode(receiver), System.identityHashCode(returnValue), // System.identityHashCode(returnValue) }); } currentLog.logEnd(captureId, receiver, returnValue); setCapturing(true); //} } } catch(Throwable t) { // TODO: Handle properly logger.debug(t.toString()); } } }