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

mockit.internal.startup.Startup Maven / Gradle / Ivy

There is a newer version: 0.999.4
Show newest version
/*
 * JMockit
 * Copyright (c) 2006-2009 Rogério Liesenfeld
 * All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
package mockit.internal.startup;

import java.io.*;
import java.lang.instrument.*;
import java.util.*;

import org.objectweb.asm2.*;

import mockit.integration.junit3.internal.*;
import mockit.integration.junit4.internal.*;
import mockit.integration.testng.internal.*;
import mockit.internal.*;
import mockit.internal.expectations.*;
import mockit.internal.state.*;

/**
 * This is the "agent class" that initializes the JMockit "Java agent". It is not intended for use
 * in client code. It must be public, however, so the JVM can call the premain method,
 * which as the name implies is called before the main
method. * * @see #premain(String, Instrumentation) */ public final class Startup { static final String javaSpecVersion = System.getProperty("java.specification.version"); static final boolean jdk6OrLater = "1.6".equals(javaSpecVersion) || "1.7".equals(javaSpecVersion); private static Instrumentation instrumentation; private static final Properties startupTools = new Properties(); private static final List defaultTools = new ArrayList(); static { InputStream properties = Startup.class.getResourceAsStream("/jmockit.properties"); try { startupTools.load(properties); } catch (IOException e) { throw new RuntimeException(e); } finally { try { properties.close(); } catch (IOException ignore) {} } String[] defaultToolsArray = startupTools.getProperty("defaultTools", "").split("\\s+"); Collections.addAll(defaultTools, defaultToolsArray); } private Startup() {} public static boolean isJava6OrLater() { return jdk6OrLater; } /** * This method must only be called by the JVM, to provide the instrumentation object. In order * for this to occur, the JVM must be started with "-javaagent:jmockit.jar" as a command line * parameter (assuming the jar file is in the current directory). *

* It is also possible to load other instrumentation tools at this time, * according to any agent arguments provided as "-javaagent:jmockit.jar=agentArgs" in the JVM * command line. There are two types of instrumentation tools:

  1. A {@link * ClassFileTransformer class file transformer}, which will be instantiated and added to the JVM * instrumentation service. Such a class must be public and have a public constructor accepting * two parameters: the first of type Map<String, byte[]>, which will receive a * map for storing the transformed classes; and the second of type String, which * will receive any tool arguments.
  2. An external mock, which can be any * class with a public no-args constructor. Such a class will be used to redefine one or more * real classes, in a manner similar to the behavior of * {@link mockit.Mockit#redefineMethods(Class, Class)}. The real classes can be specified in one of two * ways: by providing a regular * expression matching class names as the tool arguments, or by annotating the external mock * class with {@link mockit.MockClass}.
*

* If you encounter a {@link VerifyError} in some test, try running it with the * -noverify JVM parameter. * * @param agentArgs zero or more instrumentation tool specifications (separated * by semicolons if more than one); each tool specification must be expressed as * "<tool class name>[=tool arguments]", where the class names are fully * qualified, and the corresponding class files must be present in the * classpath; the part between square brackets is optional * @param inst the instrumentation service provided by the JVM */ public static void premain(String agentArgs, Instrumentation inst) throws Exception { initialize(agentArgs, inst); } @SuppressWarnings({"UnusedDeclaration"}) public static void agentmain(String agentArgs, Instrumentation inst) throws Exception { initialize(agentArgs, inst); } private static void initialize(String agentArgs, Instrumentation inst) throws IOException, ClassNotFoundException { instrumentation = inst; // Pre-load the mocking bridge to avoid a ClassCircularityError. Class.forName("mockit.internal.MockingBridge"); loadInternalStartupMocks(); if (agentArgs != null && agentArgs.length() > 0) { processAgentArgs(agentArgs); } for (String toolSpec : defaultTools) { loadExternalTool(toolSpec, true); } instrumentation.addTransformer(new ProxyRegistrationTransformer()); instrumentation.addTransformer(new ExpectationsTransformer(inst)); } private static void loadInternalStartupMocks() { setUpInternalStartupMock(TestSuiteDecorator.class); setUpInternalStartupMock(JUnitTestCaseDecorator.class); setUpInternalStartupMock(RunNotifierDecorator.class); setUpInternalStartupMock(BlockJUnit4ClassRunnerDecorator.class); setUpInternalStartupMock(TestNGTestRunnerDecorator.class); TestRun.mockFixture().turnRedefinedClassesIntoFixedOnes(); } private static void setUpInternalStartupMock(Class mockClass) { Object mock; //noinspection CatchGenericClass,OverlyBroadCatchBlock try { //noinspection ClassNewInstance mock = mockClass.newInstance(); } catch (Throwable ignored) { // OK, simply ignore the internal startup mock if it can't be loaded for some reason, // such as not having the necessary third-party class files in the classpath. return; } new RedefinitionEngine(mock, mockClass, true).setUpStartupMock(); } private static void processAgentArgs(String agentArgs) throws IOException { String[] externalToolSpecs = agentArgs.split("\\s*;\\s*"); for (String toolSpec : externalToolSpecs) { loadExternalTool(toolSpec, false); } } private static void loadExternalTool(String toolSpec, boolean byDefault) throws IOException { String[] classAndArgs = toolSpec.split("\\s*=\\s*"); String toolClassName = classAndArgs[0]; String toolArgs = classAndArgs.length == 1 ? null : classAndArgs[1]; if (!byDefault) { defaultTools.remove(toolClassName); } String toolKey = "startupTools." + toolClassName; if (startupTools.containsKey(toolKey)) { toolClassName = startupTools.getProperty(toolKey); } ClassReader cr; if (byDefault) { try { cr = ClassFile.readClass(toolClassName); } catch (IOException ignore) { // OK, don't load if not in the classpath. return; } } else { cr = ClassFile.readClass(toolClassName); } loadExternalTool(toolClassName, toolArgs, cr); } private static void loadExternalTool(String toolClassName, String toolArgs, ClassReader cr) { ToolLoader toolLoader = new ToolLoader(toolClassName, toolArgs); try { cr.accept(toolLoader, true); } catch (IllegalStateException ignore) { return; } String toolArgsDescription = toolArgs == null ? "" : '=' + toolArgs; System.out.println("JMockit: loaded external tool " + toolClassName + toolArgsDescription); } public static Instrumentation instrumentation() { return instrumentation; } public static void verifyInitialization() { if (instrumentation == null) { new AgentInitialization().initializeAccordingToJDKVersion(); } } }



© 2015 - 2025 Weber Informatics LLC | Privacy Policy