com.fitbur.jestify.junit.spring.IntegrationTestReifier.java Source code

Java tutorial

Introduction

Here is the source code for com.fitbur.jestify.junit.spring.IntegrationTestReifier.java

Source

/*
 * Copyright 2015 Sharmarke Aden <saden1 at gmail.org>.
 *
 * 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 com.fitbur.jestify.junit.spring;

import com.fitbur.jestify.api.Cut;
import com.fitbur.jestify.api.Mock;
import com.fitbur.jestify.api.Module;
import com.fitbur.jestify.core.TestReifier;
import com.fitbur.jestify.core.descriptor.CutDescriptor;
import com.fitbur.jestify.core.descriptor.FieldDescriptor;
import com.fitbur.jestify.core.descriptor.ParameterDescriptor;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Optional;
import javax.inject.Provider;
import static org.mockito.AdditionalAnswers.delegatesTo;
import org.mockito.MockSettings;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.withSettings;
import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROTOTYPE;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.ResolvableType;

/**
 *
 * @author Sharmarke Aden <saden1 at gmail.org>
 */
public class IntegrationTestReifier implements TestReifier<Object[]> {

    private final AnnotationConfigApplicationContext appContext;
    private final Object testInstance;

    public IntegrationTestReifier(AnnotationConfigApplicationContext appContext, Object testInstance) {
        this.appContext = appContext;
        this.testInstance = testInstance;
    }

    @Override
    public Object reifyField(FieldDescriptor fieldDescriptor, ParameterDescriptor parameterDescriptor) {
        return AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
            try {
                Object instance;
                Field field = fieldDescriptor.getField();
                Type fieldType = field.getGenericType();
                field.setAccessible(true);

                Optional<Mock> optMock = fieldDescriptor.getMock();
                if (optMock.isPresent()) {
                    Mock mock = optMock.get();
                    Object value = field.get(testInstance);
                    //if the field value is set then create a mock otherwise create a mock
                    //that delegates to the value
                    if (value == null) {
                        MockSettings settings = withSettings().defaultAnswer(mock.answer());

                        if (mock.extraInterfaces().length > 0) {
                            settings.extraInterfaces(mock.extraInterfaces());

                        }

                        instance = mock(field.getType(), settings);
                    } else {
                        instance = mock(field.getType(), delegatesTo(value));
                    }

                } else {
                    ResolvableType resolver = ResolvableType.forType(fieldType);

                    Class rawType;

                    if (resolver.hasGenerics()) {
                        if (resolver.isAssignableFrom(Provider.class)
                                || resolver.isAssignableFrom(Optional.class)) {
                            rawType = resolver.getRawClass();
                        } else {
                            rawType = resolver.resolve();
                        }
                    } else {
                        rawType = (Class) fieldType;
                    }

                    instance = appContext.getBean(rawType);
                }

                field.set(testInstance, instance);
                fieldDescriptor.setInstance(instance);
                parameterDescriptor.setInstance(instance);

                return instance;
            } catch (IllegalAccessException | IllegalArgumentException e) {
                throw new RuntimeException(e);
            }
        });

    }

    @Override
    public Object reifyCut(CutDescriptor cutDescriptor, Object[] arguments) {
        return AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
            try {
                Cut cut = cutDescriptor.getCut();
                Field field = cutDescriptor.getField();
                Type fieldType = field.getGenericType();
                String fieldName = field.getName();

                field.setAccessible(true);

                Constructor<?> constructor = cutDescriptor.getConstructor();
                constructor.setAccessible(true);

                ResolvableType resolver = ResolvableType.forType(fieldType);

                Class rawType;

                if (resolver.hasGenerics()) {
                    if (resolver.isAssignableFrom(Provider.class) || resolver.isAssignableFrom(Optional.class)) {
                        rawType = resolver.getRawClass();
                    } else {
                        rawType = resolver.resolve();
                    }
                } else {
                    rawType = resolver.resolve();
                }

                Module module = testInstance.getClass().getDeclaredAnnotation(Module.class);

                GenericBeanDefinition bean = new GenericBeanDefinition();
                bean.setBeanClass(rawType);
                bean.setAutowireCandidate(false);
                bean.setScope(SCOPE_PROTOTYPE);
                bean.setPrimary(true);
                bean.setLazyInit(true);
                bean.setRole(RootBeanDefinition.ROLE_APPLICATION);
                bean.setAutowireMode(RootBeanDefinition.AUTOWIRE_NO);
                appContext.registerBeanDefinition(fieldName, bean);
                if (module != null) {
                    appContext.register(module.value());
                }
                appContext.refresh();

                Object instance = appContext.getBean(fieldName, arguments);

                if (cut.value()) {
                    instance = spy(instance);
                }

                field.set(testInstance, instance);

                return instance;
            } catch (SecurityException | IllegalAccessException | IllegalArgumentException e) {
                throw new RuntimeException(e);
            }
        });
    }

}