/*
* 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.engine;
import static org.junit.platform.commons.meta.API.Usage.Experimental;
import java.util.Optional;
import org.junit.platform.commons.meta.API;
import org.junit.platform.commons.util.PackageUtils;
/**
* A {@code TestEngine} facilitates <em>discovery</em> and <em>execution</em> of
* tests for a particular programming model.
*
* <p>For example, JUnit provides a {@code TestEngine} that discovers and
* executes tests written using the JUnit Jupiter programming model.
*
* <p>Every {@code TestEngine} must {@linkplain #getId provide its own unique ID},
* {@linkplain #discover discover tests} from
* {@link EngineDiscoveryRequest EngineDiscoveryRequests},
* and {@linkplain #execute execute those tests} according to
* {@link ExecutionRequest ExecutionRequests}.
*
* <p>In order to facilitate test discovery within IDEs and tools prior
* to launching the JUnit Platform, {@code TestEngine} implementations are
* encouraged to make use of the
* {@link org.junit.platform.commons.annotation.Testable @Testable} annotation.
* For example, the {@code @Test} and {@code @TestFactory} annotations in JUnit
* Jupiter are meta-annotated with {@code @Testable}. Consult the Javadoc for
* {@code @Testable} for further details.
*
* @see org.junit.platform.engine.EngineDiscoveryRequest
* @see org.junit.platform.engine.ExecutionRequest
* @see org.junit.platform.commons.annotation.Testable
* @since 1.0
*/
@API(Experimental)
public interface TestEngine {
/**
* Get the ID that uniquely identifies this test engine.
*
* <p>Each test engine must provide a unique ID. For example, JUnit Vintage
* and JUnit Jupiter use {@code "junit-vintage"} and {@code "junit-jupiter"},
* respectively. When in doubt, you may use the fully qualified name of your
* custom {@code TestEngine} implementation class.
*/
String getId();
/**
* Discover tests according to the supplied {@link EngineDiscoveryRequest}.
*
* <p>The supplied {@link UniqueId} must be used as the unique ID of the
* returned root {@link TestDescriptor}. In addition, the {@code UniqueId}
* must be used to create unique IDs for children of the root's descriptor
* by calling {@link UniqueId#append}.
*
* @param discoveryRequest the discovery request
* @param uniqueId the unique ID to be used for this test engine's
* {@code TestDescriptor}
* @return the root {@code TestDescriptor} of this engine, typically an
* instance of {@code EngineDescriptor}
* @see org.junit.platform.engine.support.descriptor.EngineDescriptor
*/
TestDescriptor discover(EngineDiscoveryRequest discoveryRequest, UniqueId uniqueId);
/**
* Execute tests according to the supplied {@link ExecutionRequest}.
*
* <p>The {@code request} passed to this method contains the root
* {@link TestDescriptor} that was previously returned by {@link #discover},
* the {@link EngineExecutionListener} to be notified of test execution
* events, and {@link ConfigurationParameters} that may influence test execution.
*
* @param request the request to execute tests for
*/
void execute(ExecutionRequest request);
/**
* Get the <em>Group ID</em> of the JAR in which this test engine is packaged.
*
* <p>This information is used solely for debugging and reporting purposes.
*
* <p>The default implementation simply returns an empty {@link Optional},
* signaling that the group ID is unknown.
*
* <p>Concrete test engine implementations may override this method in
* order to provide a known group ID.
*
* @return an {@code Optional} containing the group ID; never {@code null}
* but potentially empty if the group ID is unknown
* @see #getArtifactId()
* @see #getVersion()
*/
default Optional<String> getGroupId() {
return Optional.empty();
}
/**
* Get the <em>Artifact ID</em> of the JAR in which this test engine is packaged.
*
* <p>This information is used solely for debugging and reporting purposes.
*
* <p>The default implementation assumes the implementation title is equivalent
* to the artifact ID and therefore attempts to query the
* {@linkplain Package#getImplementationTitle() implementation title}
* from the package attributes for the {@link Package} in which the engine
* resides. Note that a package only has attributes if the information is
* defined in the {@link java.util.jar.Manifest Manifest} of the JAR
* containing that package, and if the class loader created the
* {@link Package} instance with the attributes from the manifest.
*
* <p>If the implementation title cannot be queried from the package
* attributes, the default implementation simply returns an empty
* {@link Optional}.
*
* <p>Concrete test engine implementations may override this method in
* order to determine the artifact ID by some other means.
*
* @return an {@code Optional} containing the artifact ID; never
* {@code null} but potentially empty if the artifact ID is unknown
* @see Class#getPackage()
* @see Package#getImplementationTitle()
* @see #getGroupId()
* @see #getVersion()
*/
default Optional<String> getArtifactId() {
return PackageUtils.getAttribute(getClass(), Package::getImplementationTitle);
}
/**
* Get the version of this test engine.
*
* <p>This information is used solely for debugging and reporting purposes.
*
* <p>Initially, the default implementation tries to retrieve the engine
* version from the manifest attribute named: {@code "Engine-Version-" + getId()}
*
* <p>Then the default implementation attempts to query the
* {@linkplain Package#getImplementationVersion() implementation version}
* from the package attributes for the {@link Package} in which the engine
* resides. Note that a package only has attributes if the information is
* defined in the {@link java.util.jar.Manifest Manifest} of the JAR
* containing that package, and if the class loader created the
* {@link Package} instance with the attributes from the manifest.
*
* <p>If the implementation version cannot be queried from the package
* attributes, the default implementation returns {@code "DEVELOPMENT"}.
*
* <p>Concrete test engine implementations may override this method to
* determine the version by some other means.
*
* @return an {@code Optional} containing the version; never {@code null}
* but potentially empty if the version is unknown
* @see Class#getPackage()
* @see Package#getImplementationVersion()
* @see #getGroupId()
* @see #getArtifactId()
*/
default Optional<String> getVersion() {
Optional<String> standalone = PackageUtils.getAttribute(getClass(), "Engine-Version-" + getId());
if (standalone.isPresent()) {
return standalone;
}
return Optional.of(
PackageUtils.getAttribute(getClass(), Package::getImplementationVersion).orElse("DEVELOPMENT"));
}
}