001package de.cuioss.test.jsf.junit5; 002 003import static de.cuioss.test.jsf.util.ConfigurationHelper.configureApplication; 004import static de.cuioss.test.jsf.util.ConfigurationHelper.configureComponents; 005import static de.cuioss.test.jsf.util.ConfigurationHelper.configureManagedBeans; 006import static de.cuioss.test.jsf.util.ConfigurationHelper.configureRequestConfig; 007 008import java.util.ArrayList; 009import java.util.LinkedHashSet; 010import java.util.List; 011import java.util.Objects; 012import java.util.Optional; 013import java.util.Set; 014import java.util.stream.Collectors; 015 016import org.apache.myfaces.test.mock.MockFacesContext; 017import org.junit.jupiter.api.extension.AfterEachCallback; 018import org.junit.jupiter.api.extension.ExtensionContext; 019import org.junit.jupiter.api.extension.ExtensionContext.Namespace; 020import org.junit.jupiter.api.extension.TestInstancePostProcessor; 021import org.junit.platform.commons.logging.Logger; 022import org.junit.platform.commons.logging.LoggerFactory; 023import org.junit.platform.commons.support.AnnotationSupport; 024 025import de.cuioss.test.jsf.config.JsfTestConfiguration; 026import de.cuioss.test.jsf.util.ConfigurableApplication; 027import de.cuioss.test.jsf.util.JsfEnvironmentConsumer; 028import de.cuioss.test.jsf.util.JsfEnvironmentHolder; 029import de.cuioss.test.jsf.util.JsfRuntimeSetup; 030 031/** 032 * Starts and Configures the {@link JsfRuntimeSetup}, wraps it into an 033 * {@link JsfEnvironmentHolder} and inject it into an 034 * {@link JsfEnvironmentConsumer} if available 035 * 036 * @author Oliver Wolff 037 * 038 */ 039public class JsfSetupExtension implements TestInstancePostProcessor, AfterEachCallback { 040 041 private static final Logger LOGGER = LoggerFactory.getLogger(JsfSetupExtension.class); 042 043 /** 044 * Identifies the {@link Namespace} under which the concrete instance of 045 * {@link JsfRuntimeSetup} is stored . 046 */ 047 public static final Namespace NAMESPACE = Namespace.create("test", "jsf", "JsfRuntimeSetup"); 048 049 @Override 050 @SuppressWarnings("squid:S3655") 051 public void postProcessTestInstance(Object testInstance, ExtensionContext context) throws Exception { 052 var setup = new JsfRuntimeSetup(); 053 LOGGER.info(() -> "Starting JSF-Environment"); 054 setup.setUp(); 055 put(setup, context); 056 057 var useIdentityResourceBundle = false; 058 List<EnableJsfEnvironment> environments = new ArrayList<>(); 059 retrieveEnableJSFAnnotations(testInstance.getClass(), environments); 060 if (!environments.isEmpty()) { 061 // Use the outermost annotation 062 useIdentityResourceBundle = environments.get(0).useIdentityResourceBundle(); 063 } 064 065 var environment = new JsfEnvironmentHolder(setup); 066 ConfigurableApplication.createWrapAndRegister((MockFacesContext) environment.getFacesContext()) 067 .setUseIdentityResouceBundle(useIdentityResourceBundle); 068 069 // Ensure that the ConfigurableApplication is set for 070 // JsfRuntimeSetup#getApplication 071 setup.setApplication(environment.getFacesContext().getApplication()); 072 073 LOGGER.debug(() -> "Registering Decorators"); 074 Set<JsfTestConfiguration> decoratorAnnotations = new LinkedHashSet<>(16); 075 076 retrieveDecoratorAnnotations(testInstance.getClass(), decoratorAnnotations); 077 decoratorAnnotations = decoratorAnnotations.stream().filter(Objects::nonNull).collect(Collectors.toSet()); 078 079 configureApplication(testInstance, environment.getApplicationConfigDecorator(), decoratorAnnotations); 080 configureComponents(testInstance, environment.getComponentConfigDecorator(), decoratorAnnotations); 081 configureManagedBeans(testInstance, environment.getBeanConfigDecorator(), decoratorAnnotations); 082 configureRequestConfig(testInstance, environment.getRequestConfigDecorator(), decoratorAnnotations); 083 084 if (testInstance instanceof JsfEnvironmentConsumer) { 085 ((JsfEnvironmentConsumer) testInstance).setEnvironmentHolder(environment); 086 } 087 } 088 089 private void retrieveDecoratorAnnotations(Class<?> type, Set<JsfTestConfiguration> result) { 090 if (null == type || Object.class.equals(type)) { 091 return; 092 } 093 result.addAll(AnnotationSupport.findRepeatableAnnotations(type, JsfTestConfiguration.class)); 094 retrieveDecoratorAnnotations(type.getSuperclass(), result); 095 } 096 097 private void retrieveEnableJSFAnnotations(Class<?> type, List<EnableJsfEnvironment> result) { 098 if (null == type || Object.class.equals(type)) { 099 return; 100 } 101 result.addAll(AnnotationSupport.findRepeatableAnnotations(type, EnableJsfEnvironment.class)); 102 retrieveEnableJSFAnnotations(type.getSuperclass(), result); 103 } 104 105 @Override 106 public void afterEach(ExtensionContext context) { 107 LOGGER.debug(() -> "Tear-Down JSF-Environment"); 108 get(context).ifPresent(JsfRuntimeSetup::tearDown); 109 } 110 111 private static void put(JsfRuntimeSetup runtimeSetup, ExtensionContext context) { 112 context.getStore(NAMESPACE).put(JsfRuntimeSetup.class.getName(), runtimeSetup); 113 } 114 115 private Optional<JsfRuntimeSetup> get(ExtensionContext context) { 116 return Optional.ofNullable((JsfRuntimeSetup) context.getStore(NAMESPACE).get(JsfRuntimeSetup.class.getName())); 117 } 118}