/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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.apache.jackrabbit.commons; import java.lang.reflect.Method; import java.util.Arrays; import java.util.LinkedList; import junit.framework.TestCase; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; /** * Simple {@link TestCase} base class for mock-testing the abstract * JCR implementation classes in this package. */ public class MockCase extends TestCase implements MethodInterceptor { /** * Mock test state. Set to <code>true</code> when the mock methods * are being recorded, and to <code>false</code> when the methods are * being played back. */ private boolean recording; /** * The recorded mock call sequence. List of {@link MethodCall} objects. */ private LinkedList calls; /** * The abstract base class being tested. */ private Class base; /** * Creates a mocked proxy object for the given abstract base class and * starts recording calls to the object. * * @param base the abstract base class being tested * @return mocked proxy object */ protected Object record(Class base) { this.recording = true; this.calls = new LinkedList(); this.base = base; return Enhancer.create(base, base.getInterfaces(), this); } /** * Switches the test state to replaying and verifying the recorded * call sequence. */ protected void replay() { recording = false; } /** * Verifies that all recorded method calls were executed during * the verification phase. */ protected void verify() { assertTrue(calls.isEmpty()); } //---------------------------------------------------< MethodInterceptor > /** * Intercepts a method call to the mocked proxy object. Passes the * call through if the abstract base class being tested implements the * method, and records or verifies the method call otherwise. * * @param object the object on which the method is being called * @param method the method being called * @param args method arguments * @param proxy proxy for re-invoking the called method * @return method return value * @throws Throwable if an error occurs */ public Object intercept( Object object, Method method, Object[] args, MethodProxy proxy) throws Throwable { try { base.getDeclaredMethod(method.getName(), method.getParameterTypes()); return proxy.invokeSuper(object, args); } catch (NoSuchMethodException e) { if (recording) { calls.addLast(new MethodCall(method, args)); } else { assertFalse(calls.isEmpty()); MethodCall call = (MethodCall) calls.removeFirst(); call.assertCall(method, args); } return null; } } //----------------------------------------------------------< MethodCall > /** * Record of a method call. */ private static class MethodCall { /** * The method that was called. */ private final Method method; /** * The arguments that were passed to the method. */ private final Object[] args; /** * Creates a new method call record. * * @param method the method that was called * @param args the arguments that were passed to the method */ public MethodCall(Method method, Object[] args) { this.method = method; this.args = args; } /** * Verifies that the given method is the same as was recorded. * * @param method the method that was called * @param args the arguments that were passed to the method */ public void assertCall(Method method, Object[] args) { assertEquals(this.method, method); assertTrue(Arrays.equals(this.args, args)); } } }