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

com.github.sbt.junit.jupiter.internal.JupiterRunner Maven / Gradle / Ivy

The newest version!
/*
 * jupiter-interface
 *
 * Copyright (c) 2017, Michael Aichler.
 * All rights reserved.
 *
 * 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
 *
 *     http://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 com.github.sbt.junit.jupiter.internal;

import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass;
import static org.junit.platform.engine.discovery.DiscoverySelectors.selectMethod;
import static org.junit.platform.launcher.TagFilter.excludeTags;
import static org.junit.platform.launcher.TagFilter.includeTags;

import com.github.sbt.junit.jupiter.api.JupiterTestListener;
import com.github.sbt.junit.jupiter.api.StreamPair;
import com.github.sbt.junit.jupiter.internal.event.Dispatcher;
import com.github.sbt.junit.jupiter.internal.event.LoggingEventHandler;
import com.github.sbt.junit.jupiter.internal.filter.GlobFilter;
import com.github.sbt.junit.jupiter.internal.filter.TestFilter;
import com.github.sbt.junit.jupiter.internal.listeners.OutputCapturingTestListener;
import com.github.sbt.junit.jupiter.internal.listeners.SummaryPrintingTestListener;
import com.github.sbt.junit.jupiter.internal.options.Options;
import com.github.sbt.junit.jupiter.internal.options.OptionsParser;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.junit.platform.engine.DiscoverySelector;
import org.junit.platform.engine.Filter;
import org.junit.platform.launcher.Launcher;
import org.junit.platform.launcher.TestExecutionListener;
import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder;
import org.junit.platform.launcher.core.LauncherFactory;
import sbt.testing.EventHandler;
import sbt.testing.Logger;
import sbt.testing.Runner;
import sbt.testing.Task;
import sbt.testing.TaskDef;

/** @author Michael Aichler */
public class JupiterRunner implements Runner {

  private final StreamPair systemStreamPair;
  private final ClassLoader testClassLoader;
  private final String[] args;
  private final String[] remoteArgs;
  private final Options options;

  public JupiterRunner(
      String[] args,
      String[] remoteArgs,
      ClassLoader testClassLoader,
      StreamPair systemStreamPair) {

    this.args = args;
    this.remoteArgs = remoteArgs;
    this.testClassLoader = testClassLoader;
    this.systemStreamPair = systemStreamPair;
    this.options = new OptionsParser().parse(args);
  }

  @Override
  public String[] args() {

    return args;
  }

  @Override
  public String done() {

    return "";
  }

  @Override
  public String[] remoteArgs() {

    return remoteArgs;
  }

  @Override
  public Task[] tasks(TaskDef[] taskDefs) {

    return Arrays.stream(taskDefs).map(JupiterTask::new).toArray(Task[]::new);
  }

  /**
   * Jupiter test task.
   *
   * @author Michael Aichler
   */
  class JupiterTask implements Task {

    final TaskDef taskDef;

    JupiterTask(TaskDef taskDef) {

      this.taskDef = taskDef;
    }

    @Override
    public String[] tags() {

      return new String[0];
    }

    @Override
    public Task[] execute(EventHandler eventHandler, Logger[] loggers) {

      return new WithCustomProperties(new JupiterTaskExecutor(loggers, eventHandler, taskDef))
          .execute();
    }

    @Override
    public TaskDef taskDef() {

      return taskDef;
    }
  }

  /**
   * Jupiter test task executor.
   *
   * @author Michael Aichler
   */
  class JupiterTaskExecutor {

    final Logger[] loggers;
    final EventHandler eventHandler;
    final TaskDef taskDef;

    JupiterTaskExecutor(Logger[] loggers, EventHandler eventHandler, TaskDef taskDef) {

      this.loggers = loggers;
      this.taskDef = taskDef;
      this.eventHandler =
          options
              .getDispatchEventsTracePath()
              .map(path -> (EventHandler) new LoggingEventHandler(path, eventHandler))
              .orElse(eventHandler);
    }

    Task[] execute() {

      String testSuiteName = taskDef.fullyQualifiedName();

      Configuration configuration = new Configuration(testSuiteName, loggers, options);
      Dispatcher dispatcher = new Dispatcher(configuration, eventHandler);

      SummaryPrintingTestListener summaryListener = new SummaryPrintingTestListener(configuration);
      TestExecutionListener outputCapturingListener =
          new OutputCapturingTestListener(configuration, systemStreamPair);

      JupiterTestListener testListener = configuration.getTestListener();

      try {
        LauncherDiscoveryRequestBuilder builder = LauncherDiscoveryRequestBuilder.request();
        builder.selectors(testSelector(testSuiteName));
        builder.filters(testFilters(dispatcher));

        Launcher launcher = LauncherFactory.create();

        launcher.registerTestExecutionListeners(dispatcher);
        launcher.registerTestExecutionListeners(outputCapturingListener);
        launcher.registerTestExecutionListeners(summaryListener);
        launcher.registerTestExecutionListeners(testListener);

        configuration
            .createRunListener(testClassLoader)
            .ifPresent(launcher::registerTestExecutionListeners);

        launcher.execute(builder.build(), new TestExecutionListener[0]);

        return new Task[0];
      } catch (Throwable t) {
        dispatcher.executionFailed(testSuiteName, t);
        t.printStackTrace();
        return new Task[0];
      }
    }

    private DiscoverySelector testSelector(String testClassName) {

      if (testClassName.contains("#")) {
        return selectMethod(testClassName);
      }

      return selectClass(testClassName);
    }

    private Filter[] testFilters(Dispatcher dispatcher) {

      List> filters = new ArrayList<>();

      if (!options.getExcludeTags().isEmpty()) {
        filters.add(excludeTags(options.getExcludeTags()));
      }

      if (!options.getIncludeTags().isEmpty()) {
        filters.add(includeTags(options.getIncludeTags()));
      }

      TestFilter.create(options.getTestFilters(), dispatcher).ifPresent(filters::add);
      GlobFilter.create(options.getGlobPatterns(), dispatcher).ifPresent(filters::add);

      return filters.toArray(new Filter[filters.size()]);
    }
  }

  class WithCustomProperties {

    private final JupiterTaskExecutor wrapped;
    private final Map tempProperties = new HashMap<>();

    WithCustomProperties(JupiterTaskExecutor wrapped) {

      this.wrapped = wrapped;
    }

    Task[] execute() {

      try {
        createTempProperties(options.getSystemProperties());
        return wrapped.execute();
      } finally {
        restoreSystemProperties();
      }
    }

    private void createTempProperties(Map systemProperties) {

      synchronized (System.getProperties()) {
        for (Map.Entry entry : systemProperties.entrySet()) {
          tempProperties.put(entry.getKey(), entry.getValue());
          System.setProperty(entry.getKey(), entry.getValue());
        }
      }
    }

    private void restoreSystemProperties() {

      synchronized (System.getProperties()) {
        tempProperties.forEach(
            (key, value) -> {
              if (null == value) {
                System.clearProperty(key);
              } else {
                System.setProperty(key, value);
              }
            });
        tempProperties.clear();
      }
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy