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

com.peterphi.std.guice.testing.GuiceRegistryBuilder Maven / Gradle / Ivy

The newest version!
package com.peterphi.std.guice.testing;

import com.google.inject.Module;
import com.peterphi.std.guice.apploader.BasicSetup;
import com.peterphi.std.guice.apploader.GuiceProperties;
import com.peterphi.std.guice.apploader.GuiceRole;
import com.peterphi.std.guice.apploader.impl.GuiceBuilder;
import com.peterphi.std.guice.apploader.impl.GuiceRegistry;
import com.peterphi.std.guice.common.ClassScannerFactory;
import com.peterphi.std.guice.testing.com.peterphi.std.guice.testing.annotations.Automock;
import com.peterphi.std.guice.testing.com.peterphi.std.guice.testing.annotations.GuiceConfig;
import com.peterphi.std.guice.testing.com.peterphi.std.guice.testing.annotations.TestConfig;
import com.peterphi.std.guice.testing.com.peterphi.std.guice.testing.annotations.TestModule;
import com.peterphi.std.io.PropertyFile;
import org.junit.runners.model.FrameworkField;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.TestClass;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;

class GuiceRegistryBuilder
{
	public static GuiceRegistry createRegistry(TestClass clazz)
	{
		final GuiceConfig config = getGuiceConfig(clazz);

		if (config != null && config.setup().length > 1)
			throw new IllegalArgumentException("May only have a maximum of 1 setup class for @GuiceConfig annotation!");

		return createRegistry(config, clazz);
	}


	private static GuiceRegistry createRegistry(GuiceConfig config, TestClass clazz)
	{
		GuiceRegistry registry = new GuiceRegistry();

		ClassScannerFactory scanner = null;
		GuiceRole[] roles = null;
		if (config != null)
		{
			if (config.packages().length > 0 || config.classPackages().length > 0)
			{
				Set packages = new HashSet<>();

				packages.addAll(Arrays.asList(config.packages()));

				for (Class c : config.classPackages())
					packages.add(c.getPackage().getName());

				scanner = new ClassScannerFactory(packages.toArray(new String[packages.size()]));
			}

			if (config.role().length > 0)
			{
				List instances = new ArrayList<>();

				for (Class role : config.role())
				{
					try
					{
						instances.add(role.newInstance());
					}
					catch (Exception e)
					{
						throw new IllegalArgumentException("Error instantiating GuiceRole " + role, e);
					}
				}

				roles = instances.toArray(new GuiceRole[instances.size()]);
			}
		}

		GuiceBuilder builder = registry.getBuilder();

		if (scanner != null)
			builder.withScannerFactory(scanner);
		else
			builder.withNoScannerFactory();

		if (config != null && config.config().length > 0)
			builder.withConfig(config.config());

		if (config != null)
			builder.withAutoLoadRoles(config.autoLoadRoles());

		if (roles != null)
			builder.withRole(roles);

		// Add local method config sources
		{
			validateGuiceTestConfigMethods(clazz);

			for (Object src : clazz.getAnnotatedMethodValues(null, TestConfig.class, Object.class))
			{
				if (src instanceof Properties)
					builder.withConfig((Properties) src);
				else if (src instanceof PropertyFile)
					builder.withConfig((PropertyFile) src);
			}
		}

		// Add local method module sources
		{
			validateGuiceTestModuleMethods(clazz);

			builder.withRole(new ModuleAddingGuiceRole(clazz.getAnnotatedMethodValues(null, TestModule.class, Module.class)));
		}

		// Auto-detect @Automock annotated fields in the test and create mocks for them
		{
			List fields = clazz.getAnnotatedFields(Automock.class);

			if (fields.size() > 0)
				builder.withRole(new ModuleAddingGuiceRole(new AutomockAnnotatedMockModule(clazz.getJavaClass(), fields)));
		}

		// Make sure we set the unit test property so roles are aware they're running in a unit test (e.g. so they don't auto-register REST services)
		{
			PropertyFile props = new PropertyFile();
			props.set(GuiceProperties.UNIT_TEST, "true");
			builder.withConfig(props);
		}

		// Add the Setup class, or if none is specified then add local modules:
		if (config != null && config.setup().length > 0)
		{
			builder.withSetup(config.setup()[0]);
		}
		else
		{
			builder.withSetup(new BasicSetup());
		}

		return registry;
	}


	private static void validateGuiceTestConfigMethods(final TestClass clazz)
	{
		List> classes = Arrays.asList(Properties.class, PropertyFile.class);

		// Add local method config sources:
		for (FrameworkMethod method : clazz.getAnnotatedMethods(TestConfig.class))
		{
			try
			{
				if (!method.isStatic())
					throw new IllegalArgumentException("Method must be static!");

				if (!classes.contains(method.getReturnType()))
					throw new IllegalArgumentException("Method must return one of " + classes);
			}
			catch (Throwable t)
			{
				throw new RuntimeException("Error in @GuiceTestConfig annotated method " +
				                           method.getMethod() +
				                           " in test " +
				                           clazz.getJavaClass(), t);
			}
		}
	}


	private static void validateGuiceTestModuleMethods(final TestClass clazz)
	{
		for (FrameworkMethod method : clazz.getAnnotatedMethods(TestModule.class))
		{
			try
			{
				if (!method.isStatic())
					throw new IllegalArgumentException("Method must be static!");

				if (!method.getReturnType().equals(Module.class))
					throw new IllegalArgumentException("Method must return " + Module.class);
			}
			catch (Throwable t)
			{
				throw new RuntimeException("Error in @GuiceTestModule annotated method " +
				                           method.getMethod() +
				                           " in test " +
				                           clazz.getJavaClass(), t);
			}
		}
	}


	private static GuiceConfig getGuiceConfig(TestClass clazz)
	{
		return clazz.getJavaClass().getAnnotation(GuiceConfig.class);
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy