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

net.jqwik.engine.execution.TestInstanceCreator Maven / Gradle / Ivy

There is a newer version: 1.9.1
Show newest version
package net.jqwik.engine.execution;

import java.lang.reflect.*;
import java.util.*;

import org.junit.platform.engine.*;

import net.jqwik.api.*;
import net.jqwik.api.lifecycle.*;
import net.jqwik.engine.descriptor.*;
import net.jqwik.engine.support.*;

class TestInstanceCreator {
	private final ContainerLifecycleContext containerLifecycleContext;
	private final Class containerClass;
	private final ContainerClassDescriptor containerDescriptor;
	private final ProvidePropertyInstanceHook providePropertyInstance;

	TestInstanceCreator(
		ContainerLifecycleContext containerLifecycleContext,
		ContainerClassDescriptor containerDescriptor,
		ProvidePropertyInstanceHook providePropertyInstanceHook
	) {
		this.containerLifecycleContext = containerLifecycleContext;
		this.containerClass = containerLifecycleContext.optionalContainerClass().orElseThrow(
			() -> {
				String message = String.format("Container [%s] cannot be instantiated", containerLifecycleContext.label());
				return new JqwikException(message);
			}
		);
		this.containerDescriptor = containerDescriptor;
		this.providePropertyInstance = providePropertyInstanceHook;
	}

	Object create() {
		if (providePropertyInstance.equals(ProvidePropertyInstanceHook.DEFAULT)) {
			return create(containerClass, containerDescriptor);
		}
		try {
			return providePropertyInstance.provide(containerClass);
		} catch (Throwable throwable) {
			JqwikExceptionSupport.rethrowIfBlacklisted(throwable);
			String message = String.format(
				"ProvidePropertyInstanceHook [%s] cannot provide instance for class [%s]",
				providePropertyInstance,
				containerClass
			);
			throw new JqwikException(message, throwable);
		}
	}

	private Object create(
		Class instanceClass,
		TestDescriptor descriptor
	) {
		List> constructors = allAccessibleConstructors(instanceClass);
		if (constructors.size() == 0) {
			String message = String.format("Test container class [%s] has no accessible constructor", instanceClass.getName());
			throw new JqwikException(message);
		}
		if (constructors.size() > 1) {
			String message = String.format("Test container class [%s] has more than one accessible constructor", instanceClass.getName());
			throw new JqwikException(message);
		}
		Constructor constructor = constructors.get(0);
		return newInstance(instanceClass, constructor, descriptor);
	}

	private Object newInstance(
		Class instanceClass,
		Constructor constructor,
		TestDescriptor descriptor
	) {
		if (JqwikReflectionSupport.isInnerClass(instanceClass)) {
			return newInstanceOfInnerContainer(constructor, descriptor);
		} else {
			return JqwikReflectionSupport.newInstance(
				constructor,
				resolveParameters(constructor, null)
			);
		}
	}

	private Object newInstanceOfInnerContainer(Constructor constructor, TestDescriptor descriptor) {
		TestDescriptor parentDescriptor = descriptor.getParent().orElse(descriptor);
		ContainerClassDescriptor parentClassDescriptor = (ContainerClassDescriptor) parentDescriptor;
		Class parentClass = parentClassDescriptor.getContainerClass();
		Object parentInstance = create(parentClass, parentDescriptor);
		return JqwikReflectionSupport.newInstance(
			constructor,
			resolveParameters(constructor, parentInstance)
		);
	}

	private List> allAccessibleConstructors(Class instanceClass) {
		List> constructors = new ArrayList<>(Arrays.asList(instanceClass.getConstructors()));
		for (Constructor declaredConstructor : instanceClass.getDeclaredConstructors()) {
			if (!constructors.contains(declaredConstructor)) {
				constructors.add(declaredConstructor);
			}
		}
		return constructors;
	}

	private Object[] resolveParameters(
		Constructor constructor,
		Object parent
	) {
		Object[] args = new Object[constructor.getParameterCount()];
		for (int i = 0; i < args.length; i++) {
			final int index = i;
			if (index == 0 && parent != null) {
				args[index] = parent;
			} else {
				args[index] = containerLifecycleContext
								  .resolveParameter(constructor, index)
								  .map(parameterSupplier -> parameterSupplier.get(Optional.empty()))
								  .orElseThrow(() -> {
									  String info = "No matching resolver could be found";
									  return new CannotResolveParameterException(constructor.getParameters()[index], info);
								  });
			}
		}
		return args;
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy