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

mockit.internal.annotations.MockState Maven / Gradle / Ivy

The newest version!
/*
 * JMockit Annotations
 * Copyright (c) 2006-2010 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.annotations;

import java.lang.reflect.*;

import mockit.internal.util.*;

final class MockState
{
   private final Class realClass;
   final String mockNameAndDesc;

   // Expectations on the number of invocations of the mock as specified by the @Mock annotation,
   // initialized with the default values as specified in @Mock annotation definition:
   int expectedInvocations = -1;
   int minExpectedInvocations;
   int maxExpectedInvocations = -1;

   // Current mock invocation state:
   private int invocationCount;
   private ThreadLocal onReentrantCall;

   // Helper field just for synchronization:
   private final Object invocationCountLock = new Object();

   MockState(Class realClass, String mockNameAndDesc)
   {
      this.realClass = realClass;
      this.mockNameAndDesc = mockNameAndDesc;
   }

   Class getRealClass() { return realClass; }

   boolean isReentrant()
   {
      return onReentrantCall != null;
   }

   void makeReentrant()
   {
      onReentrantCall = new ThreadLocal()
      {
         @Override
         protected Boolean initialValue() { return false; }
      };
   }

   boolean isWithExpectations()
   {
      return expectedInvocations >= 0 || minExpectedInvocations > 0 || maxExpectedInvocations >= 0;
   }

   void update()
   {
      synchronized (invocationCountLock) {
         invocationCount++;
      }

      if (onReentrantCall != null) {
         onReentrantCall.set(true);
      }
   }

   boolean isOnReentrantCall()
   {
      return onReentrantCall != null && onReentrantCall.get();
   }

   void exitReentrantCall()
   {
      onReentrantCall.set(false);
   }

   void verifyExpectations()
   {
      int timesInvoked = getTimesInvoked();

      if (expectedInvocations >= 0 && timesInvoked != expectedInvocations) {
         throw new AssertionError(errorMessage("exactly", expectedInvocations, timesInvoked));
      }
      else if (timesInvoked < minExpectedInvocations) {
         throw new AssertionError(errorMessage("at least", minExpectedInvocations, timesInvoked));
      }
      else if (maxExpectedInvocations >= 0 && timesInvoked > maxExpectedInvocations) {
         throw new AssertionError(errorMessage("at most", maxExpectedInvocations, timesInvoked));
      }
   }

   int getTimesInvoked()
   {
      synchronized (invocationCountLock) {
         return invocationCount;
      }
   }

   private String errorMessage(String quantifier, int numExpectedInvocations, int timesInvoked)
   {
      String realClassName = getRealClassName();

      return
         "Expected " + quantifier + ' ' + numExpectedInvocations + " invocation(s) of " +
         new MethodFormatter(realClassName, mockNameAndDesc) + ", but was invoked " + timesInvoked + " time(s)";
   }

   private String getRealClassName()
   {
      if (realClass == null) {
         return null;
      }

      if (Proxy.isProxyClass(realClass)) {
         Class[] interfaces = realClass.getInterfaces();

         if (interfaces.length <= 2) {
            return interfaces[0].getName();
         }
      }

      return realClass.getName();
   }

   void reset()
   {
      synchronized (invocationCountLock) {
         invocationCount = 0;
      }
   }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy