content: package in.oneton.idea.spring.assistant.plugin.suggestion.service;
  
  import org.junit.jupiter.api.extension.ExtensionContext;
  import org.junit.jupiter.api.extension.ExtensionContext.Namespace;
  import org.junit.jupiter.api.extension.ExtensionContext.Store;
  import org.junit.jupiter.api.extension.ParameterContext;
  import org.junit.jupiter.api.extension.ParameterResolver;
  import org.junit.jupiter.api.extension.TestInstancePostProcessor;
  import org.mockito.Mock;
  import org.mockito.MockitoAnnotations;
  
  import java.lang.reflect.Parameter;
  
  import static org.mockito.Mockito.mock;
  
  /**
   * {@code MockitoExtension} showcases the {@link TestInstancePostProcessor}
   * and {@link ParameterResolver} extension APIs of JUnit 5 by providing
   * dependency injection support at the field level and at the method parameter
   * level via Mockito 2.x's {@link Mock @Mock} annotation.
   *
   * @since 5.0
   */
  public class MockitoExtension implements TestInstancePostProcessor, ParameterResolver {
  
    @Override
    public void postProcessTestInstance(Object testInstance, ExtensionContext context) {
      MockitoAnnotations.initMocks(testInstance);
    }
  
    @Override
    public boolean supportsParameter(ParameterContext parameterContext,
        ExtensionContext extensionContext) {
      return parameterContext.getParameter().isAnnotationPresent(Mock.class);
    }
  
    @Override
    public Object resolveParameter(ParameterContext parameterContext,
        ExtensionContext extensionContext) {
      return getMock(parameterContext.getParameter(), extensionContext);
    }
  
    private Object getMock(Parameter parameter, ExtensionContext extensionContext) {
      Class<?> mockType = parameter.getType();
      Store mocks = extensionContext.getStore(Namespace.create(MockitoExtension.class, mockType));
      String mockName = getMockName(parameter);
  
      if (mockName != null) {
        return mocks.getOrComputeIfAbsent(mockName, key -> mock(mockType, mockName));
      } else {
        return mocks.getOrComputeIfAbsent(mockType.getCanonicalName(), key -> mock(mockType));
      }
    }
  
    private String getMockName(Parameter parameter) {
      String explicitMockName = parameter.getAnnotation(Mock.class).name().trim();
      if (!explicitMockName.isEmpty()) {
        return explicitMockName;
      } else if (parameter.isNamePresent()) {
        return parameter.getName();
      }
      return null;
    }
  
  }
  