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

org.springframework.mock.staticmock.AbstractMethodMockingControl.aj Maven / Gradle / Ivy

/*
 * Copyright 2002-2014 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.mock.staticmock;

import java.util.Arrays;
import java.util.LinkedList;

import org.aspectj.lang.annotation.SuppressAjWarnings;

import org.springframework.util.ObjectUtils;

/**
 * Abstract aspect to enable mocking of methods picked out by a pointcut.
 *
 * 

Sub-aspects must define: *

    *
  • The {@link #mockStaticsTestMethod()} pointcut to indicate call stacks * when mocking should be triggered *
  • The {@link #methodToMock()} pointcut to pick out method invocations to mock *
* * @author Rod Johnson * @author Ramnivas Laddad * @author Sam Brannen * @deprecated as of Spring 4.3, in favor of a custom aspect for such purposes */ @Deprecated public abstract aspect AbstractMethodMockingControl percflow(mockStaticsTestMethod()) { private final Expectations expectations = new Expectations(); private boolean recording = true; protected void expectReturnInternal(Object retVal) { if (!recording) { throw new IllegalStateException("Not recording: Cannot set return value"); } expectations.expectReturn(retVal); } protected void expectThrowInternal(Throwable throwable) { if (!recording) { throw new IllegalStateException("Not recording: Cannot set throwable value"); } expectations.expectThrow(throwable); } protected void playbackInternal() { recording = false; } protected void verifyInternal() { expectations.verify(); } protected void resetInternal() { expectations.reset(); recording = true; } private static enum CallResponse { undefined, return_, throw_ }; /** * Represents a list of expected calls to methods. */ // Public to allow inserted code to access: is this normal?? public class Expectations { /** * Represents an expected call to a method. */ private class Call { private final String signature; private final Object[] args; private CallResponse responseType = CallResponse.undefined; private Object responseObject; // return value or throwable Call(String signature, Object[] args) { this.signature = signature; this.args = args; } boolean responseTypeAlreadySet() { return responseType != CallResponse.undefined; } void setReturnValue(Object retVal) { this.responseObject = retVal; responseType = CallResponse.return_; } void setThrowable(Throwable throwable) { this.responseObject = throwable; responseType = CallResponse.throw_; } Object returnValue(String lastSig, Object[] args) { checkSignature(lastSig, args); return responseObject; } Object throwException(String lastSig, Object[] args) { checkSignature(lastSig, args); throw (RuntimeException) responseObject; } private void checkSignature(String lastSig, Object[] args) { if (!signature.equals(lastSig)) { throw new IllegalArgumentException("Signatures do not match"); } if (!Arrays.equals(this.args, args)) { throw new IllegalArgumentException("Arguments do not match"); } } @Override public String toString() { return String.format("Call with signature [%s] and arguments %s", this.signature, ObjectUtils.nullSafeToString(args)); } } /** * The list of recorded calls. */ private final LinkedList calls = new LinkedList(); /** * The number of calls already verified. */ private int verified; public void verify() { if (verified != calls.size()) { throw new IllegalStateException("Expected " + calls.size() + " calls, but received " + verified); } } /** * Validate the call and provide the expected return value. */ public Object respond(String lastSig, Object[] args) { Call c = nextCall(); switch (c.responseType) { case return_: { return c.returnValue(lastSig, args); } case throw_: { return c.throwException(lastSig, args); } default: { throw new IllegalStateException("Behavior of " + c + " not specified"); } } } private Call nextCall() { verified++; if (verified > calls.size()) { throw new IllegalStateException("Expected " + calls.size() + " calls, but received " + verified); } // The 'verified' count is 1-based; whereas, 'calls' is 0-based. return calls.get(verified - 1); } public void expectCall(String lastSig, Object[] lastArgs) { calls.add(new Call(lastSig, lastArgs)); } public boolean hasCalls() { return !calls.isEmpty(); } public void expectReturn(Object retVal) { Call c = calls.getLast(); if (c.responseTypeAlreadySet()) { throw new IllegalStateException("No method invoked before setting return value"); } c.setReturnValue(retVal); } public void expectThrow(Throwable throwable) { Call c = calls.getLast(); if (c.responseTypeAlreadySet()) { throw new IllegalStateException("No method invoked before setting throwable"); } c.setThrowable(throwable); } /** * Reset the internal state of this {@code Expectations} instance. */ public void reset() { this.calls.clear(); this.verified = 0; } } /** * Pointcut that identifies call stacks when mocking should be triggered. */ protected abstract pointcut mockStaticsTestMethod(); /** * Pointcut that identifies which method invocations to mock. */ protected abstract pointcut methodToMock(); @SuppressAjWarnings("adviceDidNotMatch") after() returning : mockStaticsTestMethod() { if (recording && (expectations.hasCalls())) { throw new IllegalStateException( "Calls have been recorded, but playback state was never reached. Set expectations and then call " + this.getClass().getSimpleName() + ".playback();"); } verifyInternal(); } @SuppressAjWarnings("adviceDidNotMatch") Object around() : methodToMock() && cflowbelow(mockStaticsTestMethod()) { if (recording) { expectations.expectCall(thisJoinPointStaticPart.toLongString(), thisJoinPoint.getArgs()); // Return value doesn't matter return null; } else { return expectations.respond(thisJoinPointStaticPart.toLongString(), thisJoinPoint.getArgs()); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy