001package io.avaje.inject.test;
002
003import io.avaje.inject.BeanScope;
004import io.avaje.inject.BeanScopeBuilder;
005import org.junit.jupiter.api.extension.AfterEachCallback;
006import org.junit.jupiter.api.extension.BeforeEachCallback;
007import org.junit.jupiter.api.extension.ExtensionContext;
008import org.junit.jupiter.api.extension.ExtensionContext.Namespace;
009
010import java.util.ArrayList;
011import java.util.List;
012
013/**
014 * Junit 5 extension for avaje inject.
015 * <p>
016 * Supports injection for fields annotated with <code>@Mock, @Spy, @Captor, @Inject</code>.
017 */
018public class InjectExtension implements BeforeEachCallback, AfterEachCallback {
019
020  private final static Namespace INJECT_NS = Namespace.create("io.avaje.inject");
021
022  private final static String BEAN_SCOPE = "BEAN_SCOPE";
023
024  /**
025   * Callback that is invoked <em>before</em> each test is invoked.
026   */
027  @Override
028  public void beforeEach(final ExtensionContext context) {
029    final List<MetaReader> readers = createMetaReaders(context);
030
031    final BeanScopeBuilder builder = BeanScope.newBuilder();
032    for (MetaReader reader : readers) {
033      reader.build(builder);
034    }
035
036    final BeanScope beanScope = builder.build();
037    for (MetaReader reader : readers) {
038      reader.setFromScope(beanScope);
039    }
040    context.getStore(INJECT_NS).put(BEAN_SCOPE, beanScope);
041  }
042
043  /**
044   * Return the list of MetaReaders - 1 per test instance.
045   */
046  private List<MetaReader> createMetaReaders(ExtensionContext context) {
047    final List<Object> testInstances = context.getRequiredTestInstances().getAllInstances();
048    final List<MetaReader> readers = new ArrayList<>(testInstances.size());
049    for (Object testInstance : testInstances) {
050      readers.add(new MetaReader(testInstance));
051    }
052    return readers;
053  }
054
055  /**
056   * Callback that is invoked <em>after</em> each test has been invoked.
057   */
058  @Override
059  public void afterEach(ExtensionContext context) {
060    final BeanScope beanScope = (BeanScope) context.getStore(INJECT_NS).remove(BEAN_SCOPE);
061    if (beanScope != null) {
062      beanScope.close();
063    }
064  }
065
066}