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

mockit.internal.state.MockClasses Maven / Gradle / Ivy

Go to download

JMockit is a Java toolkit for automated developer testing. It contains mocking/faking APIs and a code coverage tool, supporting both JUnit and TestNG. The mocking APIs allow all kinds of Java code, without testability restrictions, to be tested in isolation from selected dependencies.

There is a newer version: 1.49
Show newest version
/*
 * Copyright (c) 2006 Rogério Liesenfeld
 * This file is subject to the terms of the MIT license (see LICENSE.txt).
 */
package mockit.internal.state;

import java.lang.reflect.*;
import java.util.*;
import java.util.Map.*;
import javax.annotation.*;

import mockit.*;
import mockit.internal.mockups.*;
import mockit.internal.util.*;

public final class MockClasses
{
   private static final Field INVOKED_INSTANCE_FIELD;
   private static final Method ON_TEAR_DOWN_METHOD;
   static
   {
      try {
         INVOKED_INSTANCE_FIELD = MockUp.class.getDeclaredField("invokedInstance");
         INVOKED_INSTANCE_FIELD.setAccessible(true);

         ON_TEAR_DOWN_METHOD = MockUp.class.getDeclaredMethod("onTearDown");
         ON_TEAR_DOWN_METHOD.setAccessible(true);
      }
      catch (NoSuchFieldException e)  { throw new RuntimeException(e); }
      catch (NoSuchMethodException e) { throw new RuntimeException(e); }
   }

   private static void notifyOfTearDown(@Nonnull MockUp mockUp)
   {
      try { ON_TEAR_DOWN_METHOD.invoke(mockUp); }
      catch (IllegalAccessException ignore) {}
      catch (InvocationTargetException e) { e.getCause().printStackTrace(); }
   }

   public static final class MockUpInstances
   {
      @Nonnull public final MockUp initialMockUp;
      boolean hasMockupsForSingleInstances;

      MockUpInstances(@Nonnull MockUp initialMockUp)
      {
         this.initialMockUp = initialMockUp;
         hasMockupsForSingleInstances = false;
      }

      public boolean hasMockUpsForSingleInstances() { return hasMockupsForSingleInstances; }

      void notifyMockUpOfTearDown() { notifyOfTearDown(initialMockUp); }
   }

   @Nonnull private final Map> startupMocks;
   @Nonnull private final Map, MockUpInstances> mockupClassesToMockupInstances;
   @Nonnull private final Map> mockedToMockupInstances;
   @Nonnull public final MockStates mockStates;

   MockClasses()
   {
      startupMocks = new IdentityHashMap>(8);
      mockupClassesToMockupInstances = new IdentityHashMap, MockUpInstances>();
      mockedToMockupInstances = new IdentityHashMap>();
      mockStates = new MockStates();
   }

   public void addMock(@Nonnull String mockClassDesc, @Nonnull MockUp mockUp)
   {
      startupMocks.put(mockClassDesc, mockUp);
   }

   public void addMock(@Nonnull MockUp mockUp)
   {
      Class mockUpClass = mockUp.getClass();
      MockUpInstances newData = new MockUpInstances(mockUp);
      mockupClassesToMockupInstances.put(mockUpClass, newData);
   }

   public void addMock(@Nonnull MockUp mockUp, @Nonnull Object mockedInstance)
   {
      MockUp previousMockup = mockedToMockupInstances.put(mockedInstance, mockUp);
      assert previousMockup == null;

      MockUpInstances mockUpInstances = mockupClassesToMockupInstances.get(mockUp.getClass());
      mockUpInstances.hasMockupsForSingleInstances = true;
   }

   @Nullable
   MockUp getMock(@Nonnull String mockUpClassDesc, @Nullable Object mockedInstance)
   {
      if (mockedInstance != null) {
         MockUp mockUpForSingleInstance = mockedToMockupInstances.get(mockedInstance);

         if (mockUpForSingleInstance != null) {
            return mockUpForSingleInstance;
         }
      }

      MockUp startupMock = startupMocks.get(mockUpClassDesc);

      if (startupMock != null) {
         return startupMock;
      }

      Class mockUpClass = ClassLoad.loadByInternalName(mockUpClassDesc);
      MockUpInstances mockUpInstances = mockupClassesToMockupInstances.get(mockUpClass);
      Object invokedInstance = mockedInstance;

      if (mockedInstance == null) {
         invokedInstance = Void.class;
      }
      else if (mockUpInstances.hasMockUpsForSingleInstances()) {
         return null;
      }

      try { INVOKED_INSTANCE_FIELD.set(mockUpInstances.initialMockUp, invokedInstance); }
      catch (IllegalAccessException ignore) {}

      return mockUpInstances.initialMockUp;
   }

   @Nullable
   public MockUpInstances findPreviouslyAppliedMockUps(@Nonnull MockUp newMockUp)
   {
      Class mockUpClass = newMockUp.getClass();
      MockUpInstances mockUpInstances = mockupClassesToMockupInstances.get(mockUpClass);

      if (mockUpInstances != null && mockUpInstances.hasMockupsForSingleInstances) {
         mockStates.copyMockStates(mockUpInstances.initialMockUp, newMockUp);
      }

      return mockUpInstances;
   }

   private void discardMockupInstances(@Nonnull Map> previousMockInstances)
   {
      if (!previousMockInstances.isEmpty()) {
         mockedToMockupInstances.entrySet().retainAll(previousMockInstances.entrySet());
      }
      else if (!mockedToMockupInstances.isEmpty()) {
         mockedToMockupInstances.clear();
      }
   }

   private void discardMockupInstancesExceptPreviousOnes(@Nonnull Map, Boolean> previousMockupClasses)
   {
      updatePreviousMockups(previousMockupClasses);

      for (Entry, MockUpInstances> mockupClassAndInstances : mockupClassesToMockupInstances.entrySet()) {
         Class mockupClass = mockupClassAndInstances.getKey();

         if (!previousMockupClasses.containsKey(mockupClass)) {
            MockUpInstances mockUpInstances = mockupClassAndInstances.getValue();
            mockUpInstances.notifyMockUpOfTearDown();
         }
      }

      mockupClassesToMockupInstances.keySet().retainAll(previousMockupClasses.keySet());
   }

   private void updatePreviousMockups(@Nonnull Map, Boolean> previousMockupClasses)
   {
      for (Entry, Boolean> mockupClassAndData : previousMockupClasses.entrySet()) {
         Class mockupClass = mockupClassAndData.getKey();
         MockUpInstances mockUpData = mockupClassesToMockupInstances.get(mockupClass);
         mockUpData.hasMockupsForSingleInstances = mockupClassAndData.getValue();
      }
   }

   private void discardAllMockupInstances()
   {
      if (!mockupClassesToMockupInstances.isEmpty()) {
         for (MockUpInstances mockUpInstances : mockupClassesToMockupInstances.values()) {
            mockUpInstances.notifyMockUpOfTearDown();
         }

         mockupClassesToMockupInstances.clear();
      }
   }

   public void discardStartupMocks()
   {
      for (MockUp startupMockup : startupMocks.values()) {
         notifyOfTearDown(startupMockup);
      }
   }

   final class SavePoint
   {
      @Nonnull private final Map> previousMockInstances;
      @Nonnull private final Map, Boolean> previousMockupClasses;

      SavePoint()
      {
         previousMockInstances = new IdentityHashMap>(mockedToMockupInstances);
         previousMockupClasses = new IdentityHashMap, Boolean>();

         for (Entry, MockUpInstances> mockUpClassAndData : mockupClassesToMockupInstances.entrySet()) {
            Class mockUpClass = mockUpClassAndData.getKey();
            MockUpInstances mockUpData = mockUpClassAndData.getValue();
            previousMockupClasses.put(mockUpClass, mockUpData.hasMockupsForSingleInstances);
         }
      }

      void rollback()
      {
         discardMockupInstances(previousMockInstances);

         if (!previousMockupClasses.isEmpty()) {
            discardMockupInstancesExceptPreviousOnes(previousMockupClasses);
         }
         else {
            discardAllMockupInstances();
         }
      }
   }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy