/*
* Copyright 2015-2017 the original author or authors.
*
* All rights reserved. This program and the accompanying materials are
* made available under the terms of the Eclipse Public License v1.0 which
* accompanies this distribution and is available at
*
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.junit.platform.launcher;
import static java.util.stream.Collectors.toList;
import static org.junit.platform.commons.meta.API.Usage.Experimental;
import static org.junit.platform.engine.FilterResult.includedIf;
import java.util.Arrays;
import java.util.List;
import org.junit.platform.commons.meta.API;
import org.junit.platform.commons.util.Preconditions;
import org.junit.platform.engine.Filter;
import org.junit.platform.engine.FilterResult;
import org.junit.platform.engine.TestEngine;
/**
* An {@code EngineFilter} is applied to all {@link TestEngine TestEngines}
* before they are used.
*
* <p><strong>Warning</strong>: be cautious when registering multiple competing
* {@link #includeEngines include} {@code EngineFilters} or multiple competing
* {@link #excludeEngines exclude} {@code EngineFilters} for the same discovery
* request since doing so will likely lead to undesirable results (i.e., zero
* engines being active).
*
* @since 1.0
* @see #includeEngines(String...)
* @see #excludeEngines(String...)
* @see LauncherDiscoveryRequest
*/
@API(Experimental)
public class EngineFilter implements Filter<TestEngine> {
/**
* Create a new <em>include</em> {@code EngineFilter} based on the
* supplied engine IDs.
*
* <p>Only {@code TestEngines} with matching engine IDs will be
* <em>included</em> within the test discovery and execution.
*
* @param engineIds the list of engine IDs to match against; never {@code null}
* or empty; individual IDs must also not be null or blank
* @see #includeEngines(String...)
*/
public static EngineFilter includeEngines(String... engineIds) {
return includeEngines(Arrays.asList(engineIds));
}
/**
* Create a new <em>include</em> {@code EngineFilter} based on the
* supplied engine IDs.
*
* <p>Only {@code TestEngines} with matching engine IDs will be
* <em>included</em> within the test discovery and execution.
*
* @param engineIds the list of engine IDs to match against; never {@code null}
* or empty; individual IDs must also not be null or blank
* @see #includeEngines(String...)
*/
public static EngineFilter includeEngines(List<String> engineIds) {
return new EngineFilter(engineIds, Type.INCLUDE);
}
/**
* Create a new <em>exclude</em> {@code EngineFilter} based on the
* supplied engine IDs.
*
* <p>{@code TestEngines} with matching engine IDs will be
* <em>excluded</em> from test discovery and execution.
*
* @param engineIds the list of engine IDs to match against; never {@code null}
* or empty; individual IDs must also not be null or blank
* @see #excludeEngines(List)
*/
public static EngineFilter excludeEngines(String... engineIds) {
return excludeEngines(Arrays.asList(engineIds));
}
/**
* Create a new <em>exclude</em> {@code EngineFilter} based on the
* supplied engine IDs.
*
* <p>{@code TestEngines} with matching engine IDs will be
* <em>excluded</em> from test discovery and execution.
*
* @param engineIds the list of engine IDs to match against; never {@code null}
* or empty; individual IDs must also not be null or blank
* @see #includeEngines(String...)
*/
public static EngineFilter excludeEngines(List<String> engineIds) {
return new EngineFilter(engineIds, Type.EXCLUDE);
}
private final List<String> engineIds;
private final Type type;
private EngineFilter(List<String> engineIds, Type type) {
this.engineIds = validateAndTrim(engineIds);
this.type = type;
}
@Override
public FilterResult apply(TestEngine testEngine) {
Preconditions.notNull(testEngine, "TestEngine must not be null");
String engineId = testEngine.getId();
Preconditions.notBlank(engineId, "TestEngine ID must not be null or blank");
if (this.type == Type.INCLUDE) {
return includedIf(this.engineIds.stream().anyMatch(engineId::equals), //
() -> String.format("Engine ID [%s] is in included list [%s]", engineId, this.engineIds), //
() -> String.format("Engine ID [%s] is not in included list [%s]", engineId, this.engineIds));
}
else {
return includedIf(this.engineIds.stream().noneMatch(engineId::equals), //
() -> String.format("Engine ID [%s] is not in excluded list [%s]", engineId, this.engineIds), //
() -> String.format("Engine ID [%s] is in excluded list [%s]", engineId, this.engineIds));
}
}
@Override
public String toString() {
return String.format("%s that %s engines with IDs %s", getClass().getSimpleName(), this.type.verb,
this.engineIds);
}
private static List<String> validateAndTrim(List<String> engineIds) {
Preconditions.notEmpty(engineIds, "engine ID list must not be null or empty");
// @formatter:off
return engineIds.stream()
.distinct()
.peek(id -> Preconditions.notBlank(id, "engine ID must not be null or blank"))
.map(String::trim)
.collect(toList());
// @formatter:on
}
private enum Type {
INCLUDE("includes"),
EXCLUDE("excludes");
private final String verb;
private Type(String verb) {
this.verb = verb;
}
}
}