/* * Copyright 2017-2020 original authors * * 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 * * https://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 io.micronaut.test.condition; import io.micronaut.context.ApplicationContext; import io.micronaut.context.BeanContext; import io.micronaut.context.condition.Condition; import io.micronaut.context.condition.ConditionContext; import io.micronaut.core.naming.NameUtils; import io.micronaut.inject.BeanDefinition; import io.micronaut.test.annotation.MockBean; import java.util.Optional; /** * A custom {@link Condition} that enables inner classes and {@link MockBean} instances only for the scope of the test. * * @author graemerocher * @since 1.0 */ public class TestActiveCondition implements Condition { public static final String ACTIVE_MOCKS = "micronaut.test.spock.active.mocks"; /** * Deprecated please use {@link #ACTIVE_SPEC_CLAZZ} instead. */ @Deprecated public static final String ACTIVE_SPEC_NAME = "micronaut.test.active.spec"; public static final String ACTIVE_SPEC_CLAZZ = "micronaut.test.active.spec.clazz"; @Override public boolean matches(ConditionContext context) { if (context.getComponent() instanceof BeanDefinition) { BeanDefinition<?> definition = (BeanDefinition<?>) context.getComponent(); final BeanContext beanContext = context.getBeanContext(); final Optional<Class<?>> declaringType = definition.getDeclaringType(); if (beanContext instanceof ApplicationContext) { ApplicationContext applicationContext = (ApplicationContext) beanContext; final Class activeSpecClazz = applicationContext.get(ACTIVE_SPEC_CLAZZ, Class.class).orElse(null); final String activeSpecName = Optional.ofNullable(activeSpecClazz).map(clazz -> clazz.getPackage().getName() + "." + clazz.getSimpleName()).orElse(null); if (definition.isAnnotationPresent(MockBean.class) && declaringType.isPresent()) { final Class<?> declaringTypeClass = declaringType.get(); String declaringTypeName = declaringTypeClass.getName(); if (activeSpecClazz != null) { if (definition.isProxy()) { final String packageName = NameUtils.getPackageName(activeSpecName); final String simpleName = NameUtils.getSimpleName(activeSpecName); final String rootName = packageName + ".$" + simpleName; return declaringTypeClass.isAssignableFrom(activeSpecClazz) || declaringTypeName.equals(rootName) || declaringTypeName.startsWith(rootName + "$"); } else { return declaringTypeClass.isAssignableFrom(activeSpecClazz) || activeSpecName.equals(declaringTypeName) || declaringTypeName.startsWith(activeSpecName + "$"); } } else { context.fail( "@MockBean of type " + definition.getBeanType() + " not within scope of parent test." ); return false; } } else { if (activeSpecName != null) { boolean beanTypeMatches = activeSpecName.equals(definition.getBeanType().getName()); return beanTypeMatches || (declaringType.isPresent() && activeSpecClazz == declaringType.get()); } else { return false; } } } else { return false; } } else { return true; } } }