http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/ec354cc7/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ModularClasspathForkConfiguration.java
----------------------------------------------------------------------
diff --git 
a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ModularClasspathForkConfiguration.java
 
b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ModularClasspathForkConfiguration.java
new file mode 100644
index 0000000..2b47c03
--- /dev/null
+++ 
b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ModularClasspathForkConfiguration.java
@@ -0,0 +1,230 @@
+package org.apache.maven.plugin.surefire.booterclient;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+import 
org.apache.maven.plugin.surefire.booterclient.lazytestprovider.OutputStreamFlushableCommandline;
+import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
+import org.apache.maven.surefire.booter.AbstractPathConfiguration;
+import org.apache.maven.surefire.booter.Classpath;
+import org.apache.maven.surefire.booter.ModularClasspath;
+import org.apache.maven.surefire.booter.ModularClasspathConfiguration;
+import org.apache.maven.surefire.booter.StartupConfiguration;
+import org.apache.maven.surefire.booter.SurefireBooterForkException;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.ModuleVisitor;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import static java.io.File.createTempFile;
+import static java.io.File.pathSeparatorChar;
+import static 
org.apache.maven.plugin.surefire.SurefireHelper.escapeToPlatformPath;
+import static org.objectweb.asm.Opcodes.ASM6;
+
+/**
+ * @author <a href="mailto:tibordig...@apache.org";>Tibor Digana (tibor17)</a>
+ * @since 2.21.0.Jigsaw
+ */
+public class ModularClasspathForkConfiguration
+        extends DefaultForkConfiguration
+{
+    @SuppressWarnings( "checkstyle:parameternumber" )
+    public ModularClasspathForkConfiguration( @Nonnull Classpath bootClasspath,
+                                              @Nonnull File tempDirectory,
+                                              @Nullable String debugLine,
+                                              @Nonnull File workingDirectory,
+                                              @Nonnull Properties 
modelProperties,
+                                              @Nullable String argLine,
+                                              @Nonnull Map<String, String> 
environmentVariables,
+                                              boolean debug,
+                                              int forkCount,
+                                              boolean reuseForks,
+                                              @Nonnull Platform pluginPlatform,
+                                              @Nonnull ConsoleLogger log )
+    {
+        super( bootClasspath, tempDirectory, debugLine, workingDirectory, 
modelProperties, argLine,
+                environmentVariables, debug, forkCount, reuseForks, 
pluginPlatform, log );
+    }
+
+    @Override
+    protected void resolveClasspath( OutputStreamFlushableCommandline cli, 
String startClass,
+                                     StartupConfiguration config )
+            throws SurefireBooterForkException
+    {
+        try
+        {
+            AbstractPathConfiguration pathConfig = 
config.getClasspathConfiguration();
+
+            ModularClasspathConfiguration modularClasspathConfiguration =
+                    pathConfig.toRealPath( ModularClasspathConfiguration.class 
);
+
+            ModularClasspath modularClasspath = 
modularClasspathConfiguration.getModularClasspath();
+
+            File descriptor = modularClasspath.getModuleDescriptor();
+            List<String> modulePath = modularClasspath.getModulePath();
+            Collection<String> packages = modularClasspath.getPackages();
+            File patchFile = modularClasspath.getPatchFile();
+            List<String> classpath = toCompleteClasspath( config );
+
+            File argsFile = createArgsFile( descriptor, modulePath, classpath, 
packages, patchFile, startClass );
+
+            //todo what if path have spaces
+            cli.createArg().setValue( "@" + escapeToPlatformPath( 
argsFile.getAbsolutePath() ) );
+        }
+        catch ( IOException e )
+        {
+            throw new SurefireBooterForkException( "Error creating args file", 
e );
+        }
+    }
+
+    File createArgsFile( File moduleDescriptor, List<String> modulePath, 
List<String> classPath,
+                         Collection<String> packages, File patchFile, String 
startClassName )
+            throws IOException
+    {
+        File surefireArgs = createTempFile( "surefireargs", "", 
getTempDirectory() );
+        if ( !isDebug() )
+        {
+            surefireArgs.deleteOnExit();
+        }
+
+        BufferedWriter writer = null;
+        try
+        {
+            writer = new BufferedWriter( new FileWriter( surefireArgs ) );
+
+            if ( modulePath != null && !modulePath.isEmpty() )
+            {
+                writer.write( "--module-path" );
+                writer.newLine();
+
+                for ( Iterator<String> it = modulePath.iterator(); 
it.hasNext(); )
+                {
+                    writer.append( it.next() );
+                    if ( it.hasNext() )
+                    {
+                        writer.append( pathSeparatorChar );
+                    }
+                }
+
+                writer.newLine();
+            }
+
+            if ( classPath != null && !classPath.isEmpty() )
+            {
+                writer.write( "--class-path" );
+                writer.newLine();
+                for ( Iterator<String> it = classPath.iterator(); 
it.hasNext(); )
+                {
+                    writer.append( it.next() );
+                    if ( it.hasNext() )
+                    {
+                        writer.append( pathSeparatorChar );
+                    }
+                }
+
+                writer.newLine();
+            }
+
+            //todo may return null
+            final String moduleName = toModuleName( moduleDescriptor );
+
+            writer.write( "--patch-module" );
+            writer.newLine();
+            writer.append( moduleName )
+                    .append( '=' )
+                    .append( patchFile.getPath() );
+
+            writer.newLine();
+
+            for ( String pkg : packages )
+            {
+                writer.write( "--add-exports" );
+                writer.newLine();
+                writer.append( moduleName )
+                        .append( '/' )
+                        .append( pkg )
+                        .append( '=' )
+                        .append( "ALL-UNNAMED" );
+
+                writer.newLine();
+            }
+
+            writer.write( "--add-modules" );
+            writer.newLine();
+            writer.append( moduleName );
+
+            writer.newLine();
+
+            writer.write( "--add-reads" );
+            writer.newLine();
+            writer.append( moduleName )
+                    .append( '=' )
+                    .append( "ALL-UNNAMED" );
+
+            writer.newLine();
+
+            writer.write( startClassName );
+
+            writer.newLine();
+        }
+        finally
+        {
+            if ( writer != null )
+            {
+                writer.close();
+            }
+        }
+
+        return surefireArgs;
+    }
+
+    private static String toModuleName( File moduleDescriptor ) throws 
IOException
+    {
+        if ( moduleDescriptor == null || !moduleDescriptor.isFile() )
+        {
+            return null;
+        }
+
+        final StringBuilder sb = new StringBuilder();
+        new ClassReader( new FileInputStream( moduleDescriptor ) ).accept( new 
ClassVisitor( ASM6 )
+        {
+            @Override
+            public ModuleVisitor visitModule( String name, int access, String 
version )
+            {
+                sb.setLength( 0 );
+                sb.append( name );
+                return super.visitModule( name, access, version );
+            }
+        }, 0 );
+
+        return sb.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/ec354cc7/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/Platform.java
----------------------------------------------------------------------
diff --git 
a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/Platform.java
 
b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/Platform.java
index 10b16dc..4762453 100644
--- 
a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/Platform.java
+++ 
b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/Platform.java
@@ -19,6 +19,7 @@ package org.apache.maven.plugin.surefire.booterclient;
  * under the License.
  */
 
+import org.apache.maven.plugin.surefire.JdkAttributes;
 import org.apache.maven.surefire.booter.SystemUtils;
 
 import java.util.concurrent.Callable;
@@ -35,20 +36,28 @@ import static 
org.apache.maven.surefire.util.internal.DaemonThreadFactory.newDae
  */
 public final class Platform
 {
-    private final RunnableFuture<Long> pidJob;
+    private final RunnableFuture<Long> pluginPidJob;
+
+    private volatile JdkAttributes jdk;
 
     public Platform()
     {
         // the job may take 50 or 80 ms
-        pidJob = new FutureTask<Long>( pidJob() );
-        newDaemonThread( pidJob ).start();
+        this( new FutureTask<Long>( pidJob() ), null );
+        newDaemonThread( pluginPidJob ).start();
     }
 
-    public Long getPid()
+    private Platform( RunnableFuture<Long> pluginPidJob, JdkAttributes jdk )
+    {
+        this.pluginPidJob = pluginPidJob;
+        this.jdk = jdk;
+    }
+
+    public Long getPluginPid()
     {
         try
         {
-            return pidJob.get();
+            return pluginPidJob.get();
         }
         catch ( Exception e )
         {
@@ -56,6 +65,16 @@ public final class Platform
         }
     }
 
+    public JdkAttributes getJdkExecAttributesForTests()
+    {
+        return jdk;
+    }
+
+    public Platform withJdkExecAttributesForTests( JdkAttributes jdk )
+    {
+        return new Platform( pluginPidJob, jdk );
+    }
+
     private static Callable<Long> pidJob()
     {
         return new Callable<Long>()

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/ec354cc7/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/util/Relocator.java
----------------------------------------------------------------------
diff --git 
a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/util/Relocator.java
 
b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/util/Relocator.java
index 2237698..9d7706b 100644
--- 
a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/util/Relocator.java
+++ 
b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/util/Relocator.java
@@ -21,47 +21,38 @@ package org.apache.maven.plugin.surefire.util;
 
 
 import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
 
 /**
  * Relocates class names when running with relocated provider
  *
  * @author Kristian Rosenvold
  */
-public class Relocator
+public final class Relocator
 {
     private static final String RELOCATION_BASE = "org.apache.maven.surefire.";
+    private static final String PACKAGE_DELIMITER = "shadefire";
 
-    @Nullable
-    private final String relocation;
-
-    public Relocator( @Nullable String relocation )
-    {
-        this.relocation = relocation;
-    }
-
-    public Relocator()
+    private Relocator()
     {
-        relocation = "shadefire";
+        throw new IllegalStateException( "no instantiable constructor" );
     }
 
-    @Nullable private String getRelocation()
+    @Nonnull
+    public static String relocate( @Nonnull String className )
     {
-        return relocation;
-    }
-
-    @Nonnull public String relocate( @Nonnull String className )
-    {
-        if ( relocation == null )
+        if ( className.contains( PACKAGE_DELIMITER ) )
         {
             return className;
         }
-        if ( className.contains( relocation ) )
+        else
         {
-            return className;
+            if ( !className.startsWith( RELOCATION_BASE ) )
+            {
+                throw new IllegalArgumentException( "'" + className + "' 
should start with '" + RELOCATION_BASE + "'" );
+            }
+            String rest = className.substring( RELOCATION_BASE.length() );
+            final String s = RELOCATION_BASE + PACKAGE_DELIMITER + ".";
+            return s + rest;
         }
-        String rest = className.substring( RELOCATION_BASE.length() );
-        final String s = RELOCATION_BASE + getRelocation() + ".";
-        return s + rest;
     }
 }

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/ec354cc7/maven-surefire-common/src/main/java/org/apache/maven/surefire/providerapi/ServiceLoader.java
----------------------------------------------------------------------
diff --git 
a/maven-surefire-common/src/main/java/org/apache/maven/surefire/providerapi/ServiceLoader.java
 
b/maven-surefire-common/src/main/java/org/apache/maven/surefire/providerapi/ServiceLoader.java
index 8753ff1..00b8b74 100644
--- 
a/maven-surefire-common/src/main/java/org/apache/maven/surefire/providerapi/ServiceLoader.java
+++ 
b/maven-surefire-common/src/main/java/org/apache/maven/surefire/providerapi/ServiceLoader.java
@@ -43,7 +43,7 @@ import static 
org.apache.maven.surefire.util.ReflectionUtils.getConstructor;
  *
  * @since 2.20
  */
-public class ServiceLoader
+public final class ServiceLoader
 {
 
     @Nonnull

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/ec354cc7/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/AbstractSurefireMojoTest.java
----------------------------------------------------------------------
diff --git 
a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/AbstractSurefireMojoTest.java
 
b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/AbstractSurefireMojoTest.java
index a44bea4..d2e280e 100644
--- 
a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/AbstractSurefireMojoTest.java
+++ 
b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/AbstractSurefireMojoTest.java
@@ -19,37 +19,278 @@ package org.apache.maven.plugin.surefire;
  * under the License.
  */
 
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.handler.ArtifactHandler;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.surefire.booter.ClassLoaderConfiguration;
+import org.apache.maven.surefire.booter.Classpath;
+import org.apache.maven.surefire.booter.ModularClasspathConfiguration;
+import org.apache.maven.surefire.booter.StartupConfiguration;
+import org.apache.maven.surefire.suite.RunResult;
+import org.apache.maven.surefire.util.DefaultScanResult;
+import org.codehaus.plexus.languages.java.jpms.LocationManager;
+import org.codehaus.plexus.languages.java.jpms.ResolvePathsRequest;
+import org.codehaus.plexus.languages.java.jpms.ResolvePathsResult;
+import 
org.codehaus.plexus.languages.java.jpms.ResolvePathsResult.ModuleNameSource;
+import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
-import org.mockito.runners.MockitoJUnitRunner;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
 
 import java.io.File;
 import java.io.IOException;
+import java.lang.reflect.Field;
 import java.nio.file.Path;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
 
+import static java.util.Arrays.asList;
+import static java.util.Collections.singleton;
 import static org.apache.commons.lang3.JavaVersion.JAVA_1_7;
 import static org.apache.commons.lang3.SystemUtils.IS_OS_WINDOWS;
 import static org.apache.commons.lang3.SystemUtils.isJavaVersionAtLeast;
 import static org.fest.assertions.Assertions.assertThat;
 import static org.junit.Assume.assumeTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
+import static org.powermock.api.mockito.PowerMockito.*;
+import static org.powermock.api.support.membermodification.MemberMatcher.field;
+import static org.powermock.reflect.Whitebox.invokeMethod;
 
 /**
  * Test for {@link AbstractSurefireMojo}.
  */
-@RunWith( MockitoJUnitRunner.class )
+@RunWith( PowerMockRunner.class )
+@PrepareForTest( { AbstractSurefireMojo.class, ResolvePathsRequest.class } )
+@Ignore
 public class AbstractSurefireMojoTest
 {
+    private Mojo mojo;
+
     @Mock
-    private AbstractSurefireMojo mojo;
+    private LocationManager locationManager;
+
+    @Before
+    public void initMojo() throws IllegalAccessException
+    {
+        mojo = new Mojo();
+        Field f = field( AbstractSurefireMojo.class, "locationManager" );
+        f.setAccessible( true );
+        f.set( mojo, locationManager );
+    }
+
+    @Test
+    public void shouldGenerateTestClasspath() throws Exception
+    {
+        AbstractSurefireMojo mojo = spy( this.mojo );
+
+        when( mojo.getClassesDirectory() ).thenReturn( new File( 
"target/classes" ) );
+        when( mojo.getTestClassesDirectory() ).thenReturn( new File( 
"target/test-classes" ) );
+        when( mojo.getClasspathDependencyScopeExclude() ).thenReturn( 
"runtime" );
+        when( mojo.getClasspathDependencyExcludes() ).thenReturn( new 
String[]{ "g3:a3" } );
+        doReturn( mock( Artifact.class ) ).when( mojo, "getTestNgArtifact" );
+        doNothing().when( mojo, "addTestNgUtilsArtifacts", any() );
+
+        Set<Artifact> artifacts = new HashSet<Artifact>();
+
+        Artifact a1 = mock( Artifact.class );
+        when( a1.getGroupId() ).thenReturn( "g1" );
+        when( a1.getArtifactId() ).thenReturn( "a1" );
+        when( a1.getVersion() ).thenReturn( "1" );
+        when( a1.getScope() ).thenReturn( "runtime" );
+        when( a1.getDependencyConflictId() ).thenReturn( "g1:a1:jar" );
+        when( a1.getId() ).thenReturn( "g1:a1:jar:1" );
+        artifacts.add( a1 );
+
+        ArtifactHandler artifactHandler = mock( ArtifactHandler.class );
+        when( artifactHandler.isAddedToClasspath() ).thenReturn( true );
+
+        Artifact a2 = mock( Artifact.class );
+        when( a2.getGroupId() ).thenReturn( "g2" );
+        when( a2.getArtifactId() ).thenReturn( "a2" );
+        when( a2.getVersion() ).thenReturn( "2" );
+        when( a2.getScope() ).thenReturn( "test" );
+        when( a2.getDependencyConflictId() ).thenReturn( "g2:a2:jar" );
+        when( a2.getId() ).thenReturn( "g2:a2:jar:2" );
+        when( a2.getFile() ).thenReturn( new File( "a2-2.jar" ) );
+        when( a2.getArtifactHandler() ).thenReturn( artifactHandler );
+        artifacts.add( a2 );
+
+        Artifact a3 = mock( Artifact.class );
+        when( a3.getGroupId() ).thenReturn( "g3" );
+        when( a3.getArtifactId() ).thenReturn( "a3" );
+        when( a3.getVersion() ).thenReturn( "3" );
+        when( a3.getScope() ).thenReturn( "test" );
+        when( a3.getDependencyConflictId() ).thenReturn( "g3:a3:jar" );
+        when( a3.getId() ).thenReturn( "g3:a3:jar:3" );
+        when( a3.getFile() ).thenReturn( new File( "a3-3.jar" ) );
+        when( a3.getArtifactHandler() ).thenReturn( artifactHandler );
+        artifacts.add( a3 );
+
+        MavenProject project = mock( MavenProject.class );
+        when( project.getArtifacts() ).thenReturn( artifacts );
+        when( mojo.getProject() ).thenReturn( project );
+
+        Classpath cp = invokeMethod( mojo, "generateTestClasspath" );
+
+        verifyPrivate( mojo, times( 1 ) ).invoke( "generateTestClasspath" );
+        verify( mojo, times( 1 ) ).getClassesDirectory();
+        verify( mojo, times( 1 ) ).getTestClassesDirectory();
+        verify( mojo, times( 3 ) ).getClasspathDependencyScopeExclude();
+        verify( mojo, times( 2 ) ).getClasspathDependencyExcludes();
+        verify( artifactHandler, times( 1 ) ).isAddedToClasspath();
+        verifyPrivate( mojo, times( 1 ) ).invoke( "getTestNgArtifact" );
+        verifyPrivate( mojo, times( 1 ) ).invoke( "addTestNgUtilsArtifacts", 
eq( cp.getClassPath() ) );
+
+        assertThat( cp.getClassPath() ).hasSize( 3 );
+        assertThat( cp.getClassPath().get( 0 ) ).endsWith( "test-classes" );
+        assertThat( cp.getClassPath().get( 1 ) ).endsWith( "classes" );
+        assertThat( cp.getClassPath().get( 2 ) ).endsWith( "a2-2.jar" );
+    }
+
+    @Test
+    public void shouldHaveStartupConfigForNonModularClasspath()
+            throws Exception
+    {
+        AbstractSurefireMojo mojo = spy( this.mojo );
+        Classpath testClasspath = new Classpath( asList( "junit.jar", 
"hamcrest.jar" ) );
+
+        doReturn( testClasspath ).when( mojo, "generateTestClasspath" );
+        doReturn( 1 ).when( mojo, "getEffectiveForkCount" );
+        doReturn( true ).when( mojo, "effectiveIsEnableAssertions" );
+        when( mojo.isChildDelegation() ).thenReturn( false );
+
+        ClassLoaderConfiguration classLoaderConfiguration = new 
ClassLoaderConfiguration( false, true );
+
+        Classpath providerClasspath = new Classpath( singleton( 
"surefire-provider.jar" ) );
+
+        Classpath inprocClasspath =
+                new Classpath( asList( "surefire-api.jar", 
"surefire-common.jar", "surefire-provider.jar" ) );
+
+        StartupConfiguration conf = invokeMethod( mojo, 
"newStartupConfigForNonModularClasspath",
+                classLoaderConfiguration, providerClasspath, inprocClasspath, 
"org.asf.Provider" );
+
+        verify( mojo, times( 1 ) ).effectiveIsEnableAssertions();
+        verify( mojo, times( 1 ) ).isChildDelegation();
+        verifyPrivate( mojo, times( 1 ) ).invoke( "generateTestClasspath" );
+        verify( mojo, times( 1 ) ).getEffectiveForkCount();
+        verifyStatic( times( 1 ) );
+        ResolvePathsRequest.withStrings( eq( testClasspath.getClassPath() ) );
+
+        assertThat( conf.getClassLoaderConfiguration() )
+                .isSameAs( classLoaderConfiguration );
+
+        assertThat( ( Object ) 
conf.getClasspathConfiguration().getTestClasspath() )
+                .isSameAs( testClasspath );
+
+        assertThat( ( Object ) 
conf.getClasspathConfiguration().getProviderClasspath() )
+                .isSameAs( providerClasspath );
+
+        assertThat( ( Object ) 
conf.getClasspathConfiguration().isClassPathConfig() )
+                .isEqualTo( true );
+
+        assertThat( ( Object ) 
conf.getClasspathConfiguration().isModularPathConfig() )
+                .isEqualTo( false );
+
+        assertThat( ( Object ) 
conf.getClasspathConfiguration().isEnableAssertions() )
+                .isEqualTo( true );
+
+        assertThat( conf.getProviderClassName() )
+                .isEqualTo( "org.asf.Provider" );
+    }
+
+    @Test
+    public void shouldHaveStartupConfigForModularClasspath()
+            throws Exception
+    {
+        AbstractSurefireMojo mojo = spy( this.mojo );
+
+        Classpath testClasspath = new Classpath( asList( "non-modular.jar", 
"modular.jar", "target/classes",
+                "junit.jar", "hamcrest.jar" ) );
+
+        doReturn( testClasspath ).when( mojo, "generateTestClasspath" );
+        doReturn( 1 ).when( mojo, "getEffectiveForkCount" );
+        doReturn( true ).when( mojo, "effectiveIsEnableAssertions" );
+        when( mojo.isChildDelegation() ).thenReturn( false );
+        when( mojo.getTestClassesDirectory() ).thenReturn( new File( 
"target/test-classes" ) );
+
+        DefaultScanResult scanResult = mock( DefaultScanResult.class );
+        when( scanResult.getClasses() ).thenReturn( asList( "org.apache.A", 
"org.apache.B" ) );
+
+        ClassLoaderConfiguration classLoaderConfiguration = new 
ClassLoaderConfiguration( false, true );
+
+        Classpath providerClasspath = new Classpath( singleton( 
"surefire-provider.jar" ) );
+
+        File moduleInfo = new File( "target/classes/module-info.class" );
+
+        @SuppressWarnings( "unchecked" )
+        ResolvePathsRequest<String> req = mock( ResolvePathsRequest.class );
+        mockStatic( ResolvePathsRequest.class );
+        when( ResolvePathsRequest.withStrings( eq( 
testClasspath.getClassPath() ) ) ).thenReturn( req );
+        when( req.setMainModuleDescriptor( eq( moduleInfo.getAbsolutePath() ) 
) ).thenReturn( req );
+
+        @SuppressWarnings( "unchecked" )
+        ResolvePathsResult<String> res = mock( ResolvePathsResult.class );
+        when( res.getClasspathElements() ).thenReturn( asList( 
"non-modular.jar", "junit.jar", "hamcrest.jar" ) );
+        Map<String, ModuleNameSource> mod = new LinkedHashMap<String, 
ModuleNameSource>();
+        mod.put( "modular.jar", null );
+        mod.put( "target/classes", null );
+        when( res.getModulepathElements() ).thenReturn( mod );
+        when( locationManager.resolvePaths( eq( req ) ) ).thenReturn( res );
+
+        StartupConfiguration conf = invokeMethod( mojo, 
"newStartupConfigForModularClasspath",
+                classLoaderConfiguration, providerClasspath, 
"org.asf.Provider", moduleInfo, scanResult );
+
+        verify( mojo, times( 1 ) ).effectiveIsEnableAssertions();
+        verify( mojo, times( 1 ) ).isChildDelegation();
+        verifyPrivate( mojo, times( 1 ) ).invoke( "generateTestClasspath" );
+        verify( mojo, times( 1 ) ).getEffectiveForkCount();
+        verify( mojo, times( 1 ) ).getTestClassesDirectory();
+        verify( scanResult, times( 1 ) ).getClasses();
+        verifyStatic( times( 1 ) );
+        ResolvePathsRequest.withStrings( eq( testClasspath.getClassPath() ) );
+        verify( req, times( 1 ) ).setMainModuleDescriptor( eq( 
moduleInfo.getAbsolutePath() ) );
+        verify( res, times( 1 ) ).getClasspathElements();
+        verify( res, times( 1 ) ).getModulepathElements();
+        verify( locationManager, times( 1 ) ).resolvePaths( eq( req ) );
+
+        assertThat( conf ).isNotNull();
+        assertThat( conf.isShadefire() ).isFalse();
+        assertThat( conf.isProviderMainClass() ).isFalse();
+        assertThat( conf.isManifestOnlyJarRequestedAndUsable() ).isFalse();
+        assertThat( conf.getClassLoaderConfiguration() ).isSameAs( 
classLoaderConfiguration );
+        assertThat( conf.getProviderClassName() ).isEqualTo( 
"org.asf.Provider" );
+        assertThat( conf.getActualClassName() ).isEqualTo( "org.asf.Provider" 
);
+        assertThat( conf.getClasspathConfiguration() ).isNotNull();
+        assertThat( ( Object ) 
conf.getClasspathConfiguration().getTestClasspath() )
+                .isEqualTo( new Classpath( res.getClasspathElements() ) );
+        assertThat( ( Object ) 
conf.getClasspathConfiguration().getProviderClasspath() ).isSameAs( 
providerClasspath );
+        assertThat( conf.getClasspathConfiguration() ).isInstanceOf( 
ModularClasspathConfiguration.class );
+        ModularClasspathConfiguration mcc = ( ModularClasspathConfiguration ) 
conf.getClasspathConfiguration();
+        assertThat( mcc.getModularClasspath().getModuleDescriptor() 
).isEqualTo( moduleInfo );
+        assertThat( mcc.getModularClasspath().getPackages() ).containsOnly( 
"org.apache" );
+        assertThat( mcc.getModularClasspath().getPatchFile() ).isEqualTo( new 
File( "target/test-classes" ) );
+        assertThat( mcc.getModularClasspath().getModulePath() 
).containsExactly( "modular.jar", "target/classes" );
+        assertThat( ( Object ) mcc.getTestClasspath() ).isEqualTo( new 
Classpath( res.getClasspathElements() ) );
+    }
 
     @Test
     public void shouldHaveTmpDirectory() throws IOException
     {
         assumeTrue( isJavaVersionAtLeast( JAVA_1_7 ) );
 
-        Path path = (Path) AbstractSurefireMojo.createTmpDirectoryWithJava7( 
"surefire" );
+        Path path = ( Path ) AbstractSurefireMojo.createTmpDirectoryWithJava7( 
"surefire" );
 
         assertThat( path )
                 .isNotNull();
@@ -86,6 +327,7 @@ public class AbstractSurefireMojoTest
     @Test
     public void shouldExistTmpDirectory()
     {
+        AbstractSurefireMojo mojo = mock( AbstractSurefireMojo.class );
         when( mojo.getTempDir() ).thenReturn( "surefireX" );
         when( mojo.getProjectBuildDirectory() ).thenReturn( new File( 
System.getProperty( "user.dir" ), "target" ) );
         when( mojo.createSurefireBootDirectoryInTemp() ).thenCallRealMethod();
@@ -110,16 +352,363 @@ public class AbstractSurefireMojoTest
         assertThat( tmp ).isNotNull();
         assertThat( tmp ).exists();
         assertThat( tmp.getAbsolutePath() )
-              .startsWith( IS_OS_WINDOWS ? System.getProperty( 
"java.io.tmpdir" ) : System.getProperty( "user.dir" ) );
+                .startsWith(
+                        IS_OS_WINDOWS ? System.getProperty( "java.io.tmpdir" ) 
: System.getProperty( "user.dir" ) );
         if ( IS_OS_WINDOWS )
         {
             assertThat( tmp.getName() )
                     .startsWith( "surefireX" );
-        }
-        else
+        } else
         {
             assertThat( tmp.getName() )
                     .isEqualTo( "surefireX" );
         }
     }
+
+    public static class Mojo
+            extends AbstractSurefireMojo
+    {
+        @Override
+        protected String getPluginName()
+        {
+            return null;
+        }
+
+        @Override
+        protected int getRerunFailingTestsCount()
+        {
+            return 0;
+        }
+
+        @Override
+        public boolean isSkipTests()
+        {
+            return false;
+        }
+
+        @Override
+        public void setSkipTests( boolean skipTests )
+        {
+
+        }
+
+        @Override
+        public boolean isSkipExec()
+        {
+            return false;
+        }
+
+        @Override
+        public void setSkipExec( boolean skipExec )
+        {
+
+        }
+
+        @Override
+        public boolean isSkip()
+        {
+            return false;
+        }
+
+        @Override
+        public void setSkip( boolean skip )
+        {
+
+        }
+
+        @Override
+        public File getBasedir()
+        {
+            return null;
+        }
+
+        @Override
+        public void setBasedir( File basedir )
+        {
+
+        }
+
+        @Override
+        public File getTestClassesDirectory()
+        {
+            return null;
+        }
+
+        @Override
+        public void setTestClassesDirectory( File testClassesDirectory )
+        {
+
+        }
+
+        @Override
+        public File getClassesDirectory()
+        {
+            return null;
+        }
+
+        @Override
+        public void setClassesDirectory( File classesDirectory )
+        {
+
+        }
+
+        @Override
+        public File getReportsDirectory()
+        {
+            return null;
+        }
+
+        @Override
+        public void setReportsDirectory( File reportsDirectory )
+        {
+
+        }
+
+        @Override
+        public String getTest()
+        {
+            return null;
+        }
+
+        @Override
+        public void setTest( String test )
+        {
+
+        }
+
+        @Override
+        public List<String> getIncludes()
+        {
+            return null;
+        }
+
+        @Override
+        public File getIncludesFile()
+        {
+            return null;
+        }
+
+        @Override
+        public void setIncludes( List<String> includes )
+        {
+
+        }
+
+        @Override
+        public boolean isPrintSummary()
+        {
+            return false;
+        }
+
+        @Override
+        public void setPrintSummary( boolean printSummary )
+        {
+
+        }
+
+        @Override
+        public String getReportFormat()
+        {
+            return null;
+        }
+
+        @Override
+        public void setReportFormat( String reportFormat )
+        {
+
+        }
+
+        @Override
+        public boolean isUseFile()
+        {
+            return false;
+        }
+
+        @Override
+        public void setUseFile( boolean useFile )
+        {
+
+        }
+
+        @Override
+        public String getDebugForkedProcess()
+        {
+            return null;
+        }
+
+        @Override
+        public void setDebugForkedProcess( String debugForkedProcess )
+        {
+
+        }
+
+        @Override
+        public int getForkedProcessTimeoutInSeconds()
+        {
+            return 0;
+        }
+
+        @Override
+        public void setForkedProcessTimeoutInSeconds( int 
forkedProcessTimeoutInSeconds )
+        {
+
+        }
+
+        @Override
+        public int getForkedProcessExitTimeoutInSeconds()
+        {
+            return 0;
+        }
+
+        @Override
+        public void setForkedProcessExitTimeoutInSeconds( int 
forkedProcessTerminationTimeoutInSeconds )
+        {
+
+        }
+
+        @Override
+        public double getParallelTestsTimeoutInSeconds()
+        {
+            return 0;
+        }
+
+        @Override
+        public void setParallelTestsTimeoutInSeconds( double 
parallelTestsTimeoutInSeconds )
+        {
+
+        }
+
+        @Override
+        public double getParallelTestsTimeoutForcedInSeconds()
+        {
+            return 0;
+        }
+
+        @Override
+        public void setParallelTestsTimeoutForcedInSeconds( double 
parallelTestsTimeoutForcedInSeconds )
+        {
+
+        }
+
+        @Override
+        public boolean isUseSystemClassLoader()
+        {
+            return false;
+        }
+
+        @Override
+        public void setUseSystemClassLoader( boolean useSystemClassLoader )
+        {
+
+        }
+
+        @Override
+        public boolean isUseManifestOnlyJar()
+        {
+            return false;
+        }
+
+        @Override
+        public void setUseManifestOnlyJar( boolean useManifestOnlyJar )
+        {
+
+        }
+
+        @Override
+        public Boolean getFailIfNoSpecifiedTests()
+        {
+            return null;
+        }
+
+        @Override
+        public void setFailIfNoSpecifiedTests( boolean failIfNoSpecifiedTests )
+        {
+
+        }
+
+        @Override
+        public int getSkipAfterFailureCount()
+        {
+            return 0;
+        }
+
+        @Override
+        public String getShutdown()
+        {
+            return null;
+        }
+
+        @Override
+        public File getExcludesFile()
+        {
+            return null;
+        }
+
+        @Override
+        protected List<File> suiteXmlFiles()
+        {
+            return null;
+        }
+
+        @Override
+        protected boolean hasSuiteXmlFiles()
+        {
+            return false;
+        }
+
+        @Override
+        public File[] getSuiteXmlFiles()
+        {
+            return new File[0];
+        }
+
+        @Override
+        public void setSuiteXmlFiles( File[] suiteXmlFiles )
+        {
+
+        }
+
+        @Override
+        public String getRunOrder()
+        {
+            return null;
+        }
+
+        @Override
+        public void setRunOrder( String runOrder )
+        {
+
+        }
+
+        @Override
+        protected void handleSummary( RunResult summary, Exception 
firstForkException )
+                throws MojoExecutionException, MojoFailureException
+        {
+
+        }
+
+        @Override
+        protected boolean isSkipExecution()
+        {
+            return false;
+        }
+
+        @Override
+        protected String[] getDefaultIncludes()
+        {
+            return new String[0];
+        }
+
+        @Override
+        protected String getReportSchemaLocation()
+        {
+            return null;
+        }
+
+        @Override
+        protected Artifact getMojoArtifact()
+        {
+            return null;
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/ec354cc7/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/BooterDeserializerStartupConfigurationTest.java
----------------------------------------------------------------------
diff --git 
a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/BooterDeserializerStartupConfigurationTest.java
 
b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/BooterDeserializerStartupConfigurationTest.java
index 035add0..fc00bcd 100644
--- 
a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/BooterDeserializerStartupConfigurationTest.java
+++ 
b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/BooterDeserializerStartupConfigurationTest.java
@@ -60,12 +60,14 @@ public class BooterDeserializerStartupConfigurationTest
     public void testClassPathConfiguration()
         throws IOException
     {
-        ClasspathConfiguration reloadedClasspathConfiguration =
+        AbstractPathConfiguration reloadedClasspathConfiguration =
             getReloadedStartupConfiguration().getClasspathConfiguration();
-        assertEquals( classpathConfiguration, reloadedClasspathConfiguration );
+
+        assertTrue( reloadedClasspathConfiguration instanceof 
ClasspathConfiguration );
+        assertCpConfigEquals( classpathConfiguration, (ClasspathConfiguration) 
reloadedClasspathConfiguration );
     }
 
-    private void assertEquals( ClasspathConfiguration expectedConfiguration,
+    private void assertCpConfigEquals( ClasspathConfiguration 
expectedConfiguration,
                                ClasspathConfiguration actualConfiguration )
     {
         assertEquals( expectedConfiguration.getTestClasspath().getClassPath(),

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/ec354cc7/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkConfigurationTest.java
----------------------------------------------------------------------
diff --git 
a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkConfigurationTest.java
 
b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkConfigurationTest.java
index b49e164..2d7f335 100644
--- 
a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkConfigurationTest.java
+++ 
b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkConfigurationTest.java
@@ -23,23 +23,31 @@ import org.apache.commons.io.FileUtils;
 import org.apache.commons.lang3.RandomStringUtils;
 import org.apache.commons.lang3.SystemUtils;
 import org.apache.maven.plugin.surefire.JdkAttributes;
+import org.apache.maven.plugin.surefire.log.api.NullConsoleLogger;
 import org.apache.maven.shared.utils.StringUtils;
 import org.apache.maven.shared.utils.cli.Commandline;
 import org.apache.maven.surefire.booter.Classpath;
+import org.apache.maven.surefire.booter.ClasspathConfiguration;
+import org.apache.maven.surefire.booter.StartupConfiguration;
 import org.apache.maven.surefire.booter.SurefireBooterForkException;
 import org.junit.Test;
 
 import java.io.File;
 import java.io.IOException;
 import java.util.Collections;
+import java.util.List;
 import java.util.Properties;
 
+import static java.util.Collections.singletonList;
+import static org.apache.maven.surefire.booter.Classpath.emptyClasspath;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
 public class ForkConfigurationTest
 {
+    private static final StartupConfiguration STARTUP_CONFIG = new 
StartupConfiguration( "", null, null, false, false );
+
     @Test
     public void 
testCreateCommandLine_UseSystemClassLoaderForkOnce_ShouldConstructManifestOnlyJar()
         throws IOException, SurefireBooterForkException
@@ -47,8 +55,11 @@ public class ForkConfigurationTest
         ForkConfiguration config = getForkConfiguration( (String) null );
         File cpElement = getTempClasspathFile();
 
-        Commandline cli =
-            config.createCommandLine( Collections.singletonList( 
cpElement.getAbsolutePath() ), true, false, null, 1 );
+        List<String> cp = singletonList( cpElement.getAbsolutePath() );
+        ClasspathConfiguration cpConfig = new ClasspathConfiguration( new 
Classpath( cp ), null, null, true, true );
+        StartupConfiguration startup = new StartupConfiguration( "", cpConfig, 
null, false, false );
+
+        Commandline cli = config.createCommandLine( startup, 1 );
 
         String line = StringUtils.join( cli.getCommandline(), " " );
         assertTrue( line.contains( "-jar" ) );
@@ -59,12 +70,14 @@ public class ForkConfigurationTest
         throws IOException, SurefireBooterForkException
     {
         // SUREFIRE-657
+        ForkConfiguration config = getForkConfiguration( "abc\ndef" );
         File cpElement = getTempClasspathFile();
-        ForkConfiguration forkConfiguration = getForkConfiguration( "abc\ndef" 
);
 
-        final Commandline commandLine =
-            forkConfiguration.createCommandLine( Collections.singletonList( 
cpElement.getAbsolutePath() ), false, false,
-                                                 null, 1 );
+        List<String> cp = singletonList( cpElement.getAbsolutePath() );
+        ClasspathConfiguration cpConfig = new ClasspathConfiguration( new 
Classpath( cp ), null, null, true, true );
+        StartupConfiguration startup = new StartupConfiguration( "", cpConfig, 
null, false, false );
+
+        Commandline commandLine = config.createCommandLine( startup, 1 );
         assertTrue( commandLine.toString().contains( "abc def" ) );
     }
 
@@ -80,13 +93,16 @@ public class ForkConfigurationTest
 
         File cwd = new File( baseDir, "fork_${surefire.forkNumber}" );
 
+        ClasspathConfiguration cpConfig = new ClasspathConfiguration( 
emptyClasspath(), null, null, true, true );
+        StartupConfiguration startup = new StartupConfiguration( "", cpConfig, 
null, false, false );
         ForkConfiguration config = getForkConfiguration( null, 
cwd.getCanonicalFile() );
-        Commandline commandLine = config.createCommandLine( 
Collections.<String>emptyList(), true, false, null, 1 );
+        Commandline commandLine = config.createCommandLine( startup, 1 );
 
         File forkDirectory = new File( baseDir, "fork_1" );
         forkDirectory.deleteOnExit();
-        assertTrue( forkDirectory.getCanonicalPath().equals(
-            commandLine.getShell().getWorkingDirectory().getCanonicalPath() ) 
);
+
+        String shellWorkDir = 
commandLine.getShell().getWorkingDirectory().getCanonicalPath();
+        assertEquals( shellWorkDir,  forkDirectory.getCanonicalPath() );
     }
 
     @Test
@@ -107,7 +123,7 @@ public class ForkConfigurationTest
 
         try
         {
-            config.createCommandLine( Collections.<String>emptyList(), true, 
false, null, 1 );
+            config.createCommandLine( STARTUP_CONFIG, 1 );
         }
         catch ( SurefireBooterForkException sbfe )
         {
@@ -137,7 +153,7 @@ public class ForkConfigurationTest
 
         try
         {
-            config.createCommandLine( Collections.<String>emptyList(), true, 
false, null, 1 );
+            config.createCommandLine( STARTUP_CONFIG, 1 );
         }
         catch ( SurefireBooterForkException sbfe )
         {
@@ -182,8 +198,18 @@ public class ForkConfigurationTest
     private static ForkConfiguration getForkConfiguration( String argLine, 
String jvm, File cwd )
         throws IOException
     {
-        return new ForkConfiguration( Classpath.emptyClasspath(), null, null, 
new JdkAttributes( jvm, false ),
-                                            cwd, new Properties(), argLine, 
null, false, 1, false, new Platform() );
+        Platform platform = new Platform().withJdkExecAttributesForTests( new 
JdkAttributes( jvm, false ) );
+        File tmpDir = File.createTempFile( "target", "surefire" );
+        tmpDir.delete();
+        tmpDir.mkdirs();
+        return new JarManifestForkConfiguration( emptyClasspath(), tmpDir, 
null,
+                cwd, new Properties(), argLine, Collections.<String, 
String>emptyMap(), false, 1, false,
+                platform, new NullConsoleLogger() );
+
+        /*
+        return new ClasspathForkConfiguration( emptyClasspath(), null, null,
+                cwd, new Properties(), argLine, null, false, 1, false, 
platform, new NullConsoleLogger() );
+                */
     }
 
     // based on 
http://stackoverflow.com/questions/2591083/getting-version-of-java-in-runtime

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/ec354cc7/maven-surefire-common/src/test/java/org/apache/maven/surefire/util/RelocatorTest.java
----------------------------------------------------------------------
diff --git 
a/maven-surefire-common/src/test/java/org/apache/maven/surefire/util/RelocatorTest.java
 
b/maven-surefire-common/src/test/java/org/apache/maven/surefire/util/RelocatorTest.java
index 3cec846..4d5951a 100644
--- 
a/maven-surefire-common/src/test/java/org/apache/maven/surefire/util/RelocatorTest.java
+++ 
b/maven-surefire-common/src/test/java/org/apache/maven/surefire/util/RelocatorTest.java
@@ -32,15 +32,13 @@ public class RelocatorTest
 
     public void testFoo()
     {
-        Relocator relocator = new Relocator( "shadefire" );
         String cn = "org.apache.maven.surefire.report.ForkingConsoleReporter";
-        assertEquals( 
"org.apache.maven.surefire.shadefire.report.ForkingConsoleReporter", 
relocator.relocate( cn ) );
+        assertEquals( 
"org.apache.maven.surefire.shadefire.report.ForkingConsoleReporter", 
Relocator.relocate( cn ) );
     }
 
     public void testRelocation()
     {
-        Relocator relocator = new Relocator( "shadefire" );
         String org1 = "org.apache.maven.surefire.fooz.Baz";
-        assertEquals( "org.apache.maven.surefire.shadefire.fooz.Baz", 
relocator.relocate( org1 ) );
+        assertEquals( "org.apache.maven.surefire.shadefire.fooz.Baz", 
Relocator.relocate( org1 ) );
     }
 }

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/ec354cc7/maven-surefire-plugin/src/test/java/org/apache/maven/plugin/surefire/SurefirePluginTest.java
----------------------------------------------------------------------
diff --git 
a/maven-surefire-plugin/src/test/java/org/apache/maven/plugin/surefire/SurefirePluginTest.java
 
b/maven-surefire-plugin/src/test/java/org/apache/maven/plugin/surefire/SurefirePluginTest.java
index 5fa6df0..4cbbf00 100644
--- 
a/maven-surefire-plugin/src/test/java/org/apache/maven/plugin/surefire/SurefirePluginTest.java
+++ 
b/maven-surefire-plugin/src/test/java/org/apache/maven/plugin/surefire/SurefirePluginTest.java
@@ -20,7 +20,6 @@ package org.apache.maven.plugin.surefire;
 
 
 import java.lang.reflect.Field;
-import org.apache.maven.plugin.surefire.booterclient.ForkConfiguration;
 import org.apache.maven.toolchain.Toolchain;
 
 import junit.framework.TestCase;
@@ -35,7 +34,7 @@ public class SurefirePluginTest
         SurefirePlugin surefirePlugin = new SurefirePlugin();
         setFieldValue( surefirePlugin, "toolchain", new MyToolChain() );
         setFieldValue( surefirePlugin, "forkMode", "never" );
-        assertEquals( ForkConfiguration.FORK_ONCE, 
surefirePlugin.getEffectiveForkMode() );
+        assertEquals( "once", surefirePlugin.getEffectiveForkMode() );
     }
 
     public void testForkCountComputation()

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/ec354cc7/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 4f0bf58..79c459c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -88,7 +88,7 @@
   <properties>
     <mavenVersion>2.2.1</mavenVersion>
     <!-- <shadedVersion>2.12.4</shadedVersion> commented out due to 
https://issues.apache.org/jira/browse/MRELEASE-799 -->
-    <mavenPluginPluginVersion>3.3</mavenPluginPluginVersion>
+    <mavenPluginPluginVersion>3.5</mavenPluginPluginVersion>
     <commonsLang3Version>3.5</commonsLang3Version>
     <commonsIoVersion>2.5</commonsIoVersion>
     <mavenSharedUtilsVersion>0.9</mavenSharedUtilsVersion>
@@ -233,10 +233,31 @@
       </dependency>
       <dependency>
         <groupId>org.apache.maven.shared</groupId>
+        <artifactId>maven-common-artifact-filters</artifactId>
+        <version>1.3</version>
+        <exclusions>
+          <exclusion>
+            <groupId>org.apache.maven.shared</groupId>
+            <artifactId>maven-plugin-testing-harness</artifactId>
+          </exclusion>
+        </exclusions>
+      </dependency>
+      <dependency>
+        <groupId>org.fusesource.jansi</groupId>
+        <artifactId>jansi</artifactId>
+        <version>1.13</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.maven.shared</groupId>
         <artifactId>maven-verifier</artifactId>
         <version>1.6</version>
       </dependency>
       <dependency>
+        <groupId>org.codehaus.plexus</groupId>
+        <artifactId>plexus-java</artifactId>
+        <version>0.9.3</version>
+      </dependency>
+      <dependency>
         <groupId>org.mockito</groupId>
         <artifactId>mockito-core</artifactId>
         <version>1.10.19</version>
@@ -379,15 +400,23 @@
               <goals>
                 <goal>check</goal>
               </goals>
+              <configuration>
+                <signature>
+                  <groupId>org.codehaus.mojo.signature</groupId>
+                  <artifactId>java16</artifactId>
+                  <version>1.1</version>
+                </signature>
+                <excludeDependencies>
+                  <param>org.codehaus.plexus:plexus-java</param>
+                  <param>org.ow2.asm:asm</param>
+                </excludeDependencies>
+                <ignores>
+                  <param>org.objectweb.asm.*</param>
+                  <param>org.codehaus.plexus.languages.java.jpms.*</param>
+                </ignores>
+              </configuration>
             </execution>
           </executions>
-          <configuration>
-            <signature>
-              <groupId>org.codehaus.mojo.signature</groupId>
-              <artifactId>java16</artifactId>
-              <version>1.1</version>
-            </signature>
-          </configuration>
         </plugin>
         <plugin>
           <artifactId>maven-surefire-plugin</artifactId>
@@ -408,7 +437,7 @@
         </plugin>
         <plugin>
           <artifactId>maven-shade-plugin</artifactId>
-          <version>3.0.0</version>
+          <version>3.1.0</version>
         </plugin>
         <plugin>
           <artifactId>maven-plugin-plugin</artifactId>
@@ -475,6 +504,24 @@
               </rules>
             </configuration>
           </execution>
+          <execution>
+            <id>enforce-bytecode-version</id>
+            <goals>
+              <goal>enforce</goal>
+            </goals>
+            <configuration>
+              <rules>
+                <enforceBytecodeVersion>
+                  <maxJdkVersion>${maven.compiler.target}</maxJdkVersion>
+                  <excludes>
+                    <exclude>org.codehaus.plexus:plexus-java</exclude>
+                    <exclude>org.ow2.asm:asm</exclude>
+                  </excludes>
+                </enforceBytecodeVersion>
+              </rules>
+              <fail>true</fail>
+            </configuration>
+          </execution>
         </executions>
       </plugin>
       <plugin>

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/ec354cc7/surefire-api/src/main/java/org/apache/maven/surefire/util/DefaultScanResult.java
----------------------------------------------------------------------
diff --git 
a/surefire-api/src/main/java/org/apache/maven/surefire/util/DefaultScanResult.java
 
b/surefire-api/src/main/java/org/apache/maven/surefire/util/DefaultScanResult.java
index a00a3b5..db04a35 100644
--- 
a/surefire-api/src/main/java/org/apache/maven/surefire/util/DefaultScanResult.java
+++ 
b/surefire-api/src/main/java/org/apache/maven/surefire/util/DefaultScanResult.java
@@ -32,33 +32,33 @@ import java.util.Set;
 public class DefaultScanResult
     implements ScanResult
 {
-    private final List<String> files;
+    private final List<String> classes;
 
     private static final String SCAN_RESULT_NUMBER = "tc.";
 
-    public DefaultScanResult( List<String> files )
+    public DefaultScanResult( List<String> classes )
     {
-        this.files = Collections.unmodifiableList( files );
+        this.classes = Collections.unmodifiableList( classes );
     }
 
     @Override
     public int size()
     {
-        return files.size();
+        return classes.size();
     }
 
     @Override
     public String getClassName( int index )
     {
-        return files.get( index );
+        return classes.get( index );
     }
 
     @Override
     public void writeTo( Map<String, String> properties )
     {
-        for ( int i = 0, size = files.size(); i < size; i++ )
+        for ( int i = 0, size = classes.size(); i < size; i++ )
         {
-            properties.put( SCAN_RESULT_NUMBER + i, files.get( i ) );
+            properties.put( SCAN_RESULT_NUMBER + i, classes.get( i ) );
         }
     }
 
@@ -79,12 +79,12 @@ public class DefaultScanResult
 
     public boolean isEmpty()
     {
-        return files.isEmpty();
+        return classes.isEmpty();
     }
 
-    public List getFiles()
+    public List<String> getClasses()
     {
-        return files;
+        return classes;
     }
 
     @Override
@@ -145,8 +145,8 @@ public class DefaultScanResult
     {
         if ( other != null )
         {
-            List<String> src = new ArrayList<String>( files );
-            src.addAll( other.files );
+            List<String> src = new ArrayList<String>( classes );
+            src.addAll( other.classes );
             return new DefaultScanResult( src );
         }
         else

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/ec354cc7/surefire-api/src/test/java/org/apache/maven/surefire/util/ScanResultTest.java
----------------------------------------------------------------------
diff --git 
a/surefire-api/src/test/java/org/apache/maven/surefire/util/ScanResultTest.java 
b/surefire-api/src/test/java/org/apache/maven/surefire/util/ScanResultTest.java
index 02c2d22..c5fd85f 100644
--- 
a/surefire-api/src/test/java/org/apache/maven/surefire/util/ScanResultTest.java
+++ 
b/surefire-api/src/test/java/org/apache/maven/surefire/util/ScanResultTest.java
@@ -41,9 +41,9 @@ public class ScanResultTest
         scanResult.writeTo( serialized );
 
         DefaultScanResult read = DefaultScanResult.from( serialized );
-        List files1 = read.getFiles();
-        assertEquals( 2, files1.size() );
-        assertTrue( files1.contains( "abc" ) );
-        assertTrue( files1.contains( "cde" ) );
+        List classes = read.getClasses();
+        assertEquals( 2, classes.size() );
+        assertTrue( classes.contains( "abc" ) );
+        assertTrue( classes.contains( "cde" ) );
     }
 }

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/ec354cc7/surefire-booter/src/main/java/org/apache/maven/surefire/booter/AbstractPathConfiguration.java
----------------------------------------------------------------------
diff --git 
a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/AbstractPathConfiguration.java
 
b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/AbstractPathConfiguration.java
new file mode 100644
index 0000000..5f0b67e
--- /dev/null
+++ 
b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/AbstractPathConfiguration.java
@@ -0,0 +1,115 @@
+package org.apache.maven.surefire.booter;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+import static org.apache.maven.surefire.booter.Classpath.emptyClasspath;
+import static org.apache.maven.surefire.booter.Classpath.join;
+
+/**
+ * @author <a href="mailto:tibordig...@apache.org";>Tibor Digana (tibor17)</a>
+ * @since 2.21.0.Jigsaw
+ */
+public abstract class AbstractPathConfiguration
+{
+    public static final String CHILD_DELEGATION = "childDelegation";
+
+    public static final String ENABLE_ASSERTIONS = "enableAssertions";
+
+    public static final String CLASSPATH = "classPathUrl.";
+
+    public static final String SUREFIRE_CLASSPATH = "surefireClassPathUrl.";
+
+    private final Classpath surefireClasspathUrls;
+
+    /**
+     * Whether to enable assertions or not
+     * (can be affected by the fork arguments, and the ability to do so based 
on the JVM).
+     */
+    private final boolean enableAssertions;
+
+    // todo: @deprecated because the IsolatedClassLoader is really isolated - 
no parent.
+    private final boolean childDelegation;
+
+    protected AbstractPathConfiguration( Classpath surefireClasspathUrls,
+                                         boolean enableAssertions, boolean 
childDelegation )
+    {
+        if ( !( isClassPathConfig() ^ isModularPathConfig() ) )
+        {
+            throw new IllegalStateException( "modular path and class path 
should be exclusive" );
+        }
+        this.surefireClasspathUrls = surefireClasspathUrls;
+        this.enableAssertions = enableAssertions;
+        this.childDelegation = childDelegation;
+    }
+
+    public abstract Classpath getTestClasspath();
+
+    /**
+     * Must be exclusive with {@link #isClassPathConfig()}.
+     *
+     * @return {@code true} if <tt>this</tt> is {@link 
ModularClasspathConfiguration}.
+     */
+    public abstract boolean isModularPathConfig();
+
+    /**
+     * Must be exclusive with {@link #isModularPathConfig()}.
+     *
+     * @return {@code true} if <tt>this</tt> is {@link ClasspathConfiguration}.
+     */
+    public abstract boolean isClassPathConfig();
+
+    protected Classpath getInprocClasspath()
+    {
+        return emptyClasspath();
+    }
+
+    public <T extends AbstractPathConfiguration> T toRealPath( Class<T> type )
+    {
+        if ( isClassPathConfig() && type == ClasspathConfiguration.class
+                || isModularPathConfig() && type == 
ModularClasspathConfiguration.class )
+        {
+            return type.cast( this );
+        }
+        throw new IllegalStateException( "no target matched " + type );
+    }
+
+    public ClassLoader createMergedClassLoader()
+            throws SurefireExecutionException
+    {
+        return join( getInprocClasspath(), getTestClasspath() )
+                .createClassLoader( isChildDelegation(), isEnableAssertions(), 
"test" );
+    }
+
+    public Classpath getProviderClasspath()
+    {
+        return surefireClasspathUrls;
+    }
+
+    public boolean isEnableAssertions()
+    {
+        return enableAssertions;
+    }
+
+    @Deprecated
+    public boolean isChildDelegation()
+    {
+        return childDelegation;
+    }
+}

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/ec354cc7/surefire-booter/src/main/java/org/apache/maven/surefire/booter/Classpath.java
----------------------------------------------------------------------
diff --git 
a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/Classpath.java 
b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/Classpath.java
index 7b22712..bcbed4f 100644
--- 
a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/Classpath.java
+++ 
b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/Classpath.java
@@ -191,34 +191,25 @@ public class Classpath implements Iterable<String>
 
     public String getLogMessage( String descriptor )
     {
-        StringBuilder result = new StringBuilder();
-        result.append( descriptor ).append( " classpath:" );
+        StringBuilder result = new StringBuilder( descriptor );
         for ( String element : unmodifiableElements )
         {
-            result.append( "  " ).append( element );
+            result.append( "  " )
+                    .append( element );
         }
         return result.toString();
     }
 
     public String getCompactLogMessage( String descriptor )
     {
-        StringBuilder result = new StringBuilder();
-        result.append( descriptor ).append( " classpath:" );
+        StringBuilder result = new StringBuilder( descriptor );
         for ( String element : unmodifiableElements )
         {
             result.append( "  " );
             if ( element != null )
             {
                 int pos = element.lastIndexOf( File.separatorChar );
-                if ( pos >= 0 )
-                {
-                    result.append( element.substring( pos + 1 ) );
-                }
-                else
-                {
-                    result.append( element );
-                }
-
+                result.append( pos == -1 ? element : element.substring( pos + 
1 ) );
             }
             else
             {

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/ec354cc7/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ClasspathConfiguration.java
----------------------------------------------------------------------
diff --git 
a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ClasspathConfiguration.java
 
b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ClasspathConfiguration.java
index 0e84315..a288f2a 100644
--- 
a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ClasspathConfiguration.java
+++ 
b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ClasspathConfiguration.java
@@ -19,6 +19,8 @@ package org.apache.maven.surefire.booter;
  * under the License.
  */
 
+import static org.apache.maven.surefire.booter.Classpath.emptyClasspath;
+
 /**
  * Represents the classpaths for the BooterConfiguration.
  * <br>
@@ -27,88 +29,61 @@ package org.apache.maven.surefire.booter;
  * @author Emmanuel Venisse
  * @author Kristian Rosenvold
  */
-public class ClasspathConfiguration
+public class ClasspathConfiguration extends AbstractPathConfiguration
 {
-    public static final String CHILD_DELEGATION = "childDelegation";
-
-    public static final String ENABLE_ASSERTIONS = "enableAssertions";
-
-    public static final String CLASSPATH = "classPathUrl.";
-
-    public static final String SUREFIRE_CLASSPATH = "surefireClassPathUrl.";
-
-    private final Classpath classpathUrls;
-
-    private final Classpath surefireClasspathUrls;
+    private final Classpath testClasspathUrls;
 
     /**
      * The surefire classpath to use when invoking in-process with the plugin
      */
     private final Classpath inprocClasspath;
 
-    /**
-     * Whether to enable assertions or not (can be affected by the fork 
arguments, and the ability to do so based on the
-     * JVM).
-     */
-    private final boolean enableAssertions;
-
-    // todo: @deprecated because the IsolatedClassLoader is really isolated - 
no parent.
-    private final boolean childDelegation;
-
     public ClasspathConfiguration( boolean enableAssertions, boolean 
childDelegation )
     {
-        this( Classpath.emptyClasspath(), Classpath.emptyClasspath(), 
Classpath.emptyClasspath(), enableAssertions,
-              childDelegation );
+        this( emptyClasspath(), emptyClasspath(), emptyClasspath(), 
enableAssertions, childDelegation );
     }
 
     ClasspathConfiguration( PropertiesWrapper properties )
     {
-        this( properties.getClasspath( CLASSPATH ), properties.getClasspath( 
SUREFIRE_CLASSPATH ),
-              Classpath.emptyClasspath(),
+        this( properties.getClasspath( CLASSPATH ), properties.getClasspath( 
SUREFIRE_CLASSPATH ), emptyClasspath(),
               properties.getBooleanProperty( ENABLE_ASSERTIONS ), 
properties.getBooleanProperty( CHILD_DELEGATION ) );
     }
 
-    public ClasspathConfiguration( Classpath testClasspath, Classpath 
surefireClassPathUrls, Classpath inprocClasspath,
-                                   boolean enableAssertions, boolean 
childDelegation )
+    public ClasspathConfiguration( Classpath testClasspathUrls, Classpath 
surefireClassPathUrls,
+                                   Classpath inprocClasspath, boolean 
enableAssertions, boolean childDelegation )
     {
-        this.enableAssertions = enableAssertions;
-        this.childDelegation = childDelegation;
+        super( surefireClassPathUrls, enableAssertions, childDelegation );
+        this.testClasspathUrls = testClasspathUrls;
         this.inprocClasspath = inprocClasspath;
-        this.classpathUrls = testClasspath;
-        this.surefireClasspathUrls = surefireClassPathUrls;
-    }
-
-    public ClassLoader createMergedClassLoader()
-        throws SurefireExecutionException
-    {
-        return Classpath.join( inprocClasspath, classpathUrls )
-            .createClassLoader( childDelegation, enableAssertions, "test" );
     }
 
-    public Classpath getProviderClasspath()
+    @Override
+    protected Classpath getInprocClasspath()
     {
-        return surefireClasspathUrls;
+        return inprocClasspath;
     }
 
     public Classpath getTestClasspath()
     {
-        return classpathUrls;
+        return testClasspathUrls;
     }
 
-    public void trickClassPathWhenManifestOnlyClasspath()
-        throws SurefireExecutionException
+    @Override
+    public final boolean isModularPathConfig()
     {
-            System.setProperty( "surefire.real.class.path", 
System.getProperty( "java.class.path" ) );
-            getTestClasspath().writeToSystemProperty( "java.class.path" );
+        return !isClassPathConfig();
     }
 
-    public boolean isEnableAssertions()
+    @Override
+    public final boolean isClassPathConfig()
     {
-        return enableAssertions;
+        return true;
     }
 
-    public boolean isChildDelegation()
+    public void trickClassPathWhenManifestOnlyClasspath()
+        throws SurefireExecutionException
     {
-        return childDelegation;
+        System.setProperty( "surefire.real.class.path", System.getProperty( 
"java.class.path" ) );
+        getTestClasspath().writeToSystemProperty( "java.class.path" );
     }
 }

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/ec354cc7/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ForkedBooter.java
----------------------------------------------------------------------
diff --git 
a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ForkedBooter.java
 
b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ForkedBooter.java
index d00abc5..81872a8 100644
--- 
a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ForkedBooter.java
+++ 
b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ForkedBooter.java
@@ -88,7 +88,7 @@ public final class ForkedBooter
     {
         BooterDeserializer booterDeserializer =
                 new BooterDeserializer( createSurefirePropertiesIfFileExists( 
tmpDir, surefirePropsFileName ) );
-        // todo: print PID in debug console logger in version 2.20.2
+        // todo: print PID in debug console logger in version 2.21.2
         pingScheduler = isDebugging() ? null : listenToShutdownCommands( 
booterDeserializer.getPluginPid() );
         setSystemProperties( new File( tmpDir, 
effectiveSystemPropertiesFileName ) );
 
@@ -96,20 +96,24 @@ public final class ForkedBooter
         DumpErrorSingleton.getSingleton().init( dumpFileName, 
providerConfiguration.getReporterConfiguration() );
 
         startupConfiguration = booterDeserializer.getProviderConfiguration();
-        systemExitTimeoutInSeconds =
-                providerConfiguration.systemExitTimeout( 
DEFAULT_SYSTEM_EXIT_TIMEOUT_IN_SECONDS );
+        systemExitTimeoutInSeconds = providerConfiguration.systemExitTimeout( 
DEFAULT_SYSTEM_EXIT_TIMEOUT_IN_SECONDS );
 
-        ClasspathConfiguration classpathConfiguration = 
startupConfiguration.getClasspathConfiguration();
-        if ( startupConfiguration.isManifestOnlyJarRequestedAndUsable() )
+        AbstractPathConfiguration classpathConfiguration = 
startupConfiguration.getClasspathConfiguration();
+
+        if ( classpathConfiguration.isClassPathConfig() )
         {
-            classpathConfiguration.trickClassPathWhenManifestOnlyClasspath();
+            if ( startupConfiguration.isManifestOnlyJarRequestedAndUsable() )
+            {
+                classpathConfiguration.toRealPath( 
ClasspathConfiguration.class )
+                        .trickClassPathWhenManifestOnlyClasspath();
+            }
+            startupConfiguration.writeSurefireTestClasspathProperty();
         }
 
         ClassLoader classLoader = currentThread().getContextClassLoader();
         classLoader.setDefaultAssertionStatus( 
classpathConfiguration.isEnableAssertions() );
-        startupConfiguration.writeSurefireTestClasspathProperty();
-        testSet = createTestSet( providerConfiguration.getTestForFork(),
-                                       
providerConfiguration.isReadTestsFromInStream(), classLoader );
+        boolean readTestsFromCommandReader = 
providerConfiguration.isReadTestsFromInStream();
+        testSet = createTestSet( providerConfiguration.getTestForFork(), 
readTestsFromCommandReader, classLoader );
     }
 
     private void execute()

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/ec354cc7/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ModularClasspath.java
----------------------------------------------------------------------
diff --git 
a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ModularClasspath.java
 
b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ModularClasspath.java
new file mode 100644
index 0000000..0d7b8eb
--- /dev/null
+++ 
b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ModularClasspath.java
@@ -0,0 +1,70 @@
+package org.apache.maven.surefire.booter;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+import java.io.File;
+import java.util.Collection;
+import java.util.List;
+
+import static java.util.Collections.unmodifiableCollection;
+import static java.util.Collections.unmodifiableList;
+
+/**
+ * Jigsaw class-path and module-path.
+ *
+ * @author <a href="mailto:tibordig...@apache.org";>Tibor Digana (tibor17)</a>
+ * @since 2.21.0.Jigsaw
+ */
+public final class ModularClasspath
+{
+    private final File moduleDescriptor;
+    private final List<String> modulePath;
+    private final Collection<String> packages;
+    private final File patchFile;
+
+    public ModularClasspath( File moduleDescriptor, List<String> modulePath, 
Collection<String> packages,
+                             File patchFile )
+    {
+        this.moduleDescriptor = moduleDescriptor;
+        this.modulePath = modulePath;
+        this.packages = packages;
+        this.patchFile = patchFile;
+    }
+
+    public File getModuleDescriptor()
+    {
+        return moduleDescriptor;
+    }
+
+    public List<String> getModulePath()
+    {
+        return unmodifiableList( modulePath );
+    }
+
+    public Collection<String> getPackages()
+    {
+        return unmodifiableCollection( packages );
+    }
+
+    public File getPatchFile()
+    {
+        return patchFile;
+    }
+}

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/ec354cc7/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ModularClasspathConfiguration.java
----------------------------------------------------------------------
diff --git 
a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ModularClasspathConfiguration.java
 
b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ModularClasspathConfiguration.java
new file mode 100644
index 0000000..655b864
--- /dev/null
+++ 
b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/ModularClasspathConfiguration.java
@@ -0,0 +1,62 @@
+package org.apache.maven.surefire.booter;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+/**
+ * @author <a href="mailto:tibordig...@apache.org";>Tibor Digana (tibor17)</a>
+ * @since 2.21.0.Jigsaw
+ */
+public class ModularClasspathConfiguration extends AbstractPathConfiguration
+{
+    private final ModularClasspath modularClasspath;
+    private final Classpath testClasspathUrls;
+
+    public ModularClasspathConfiguration( ModularClasspath modularClasspath, 
Classpath testClasspathUrls,
+                                          Classpath surefireClasspathUrls, 
boolean enableAssertions,
+                                          boolean childDelegation )
+    {
+        super( surefireClasspathUrls, enableAssertions, childDelegation );
+        this.modularClasspath = modularClasspath;
+        this.testClasspathUrls = testClasspathUrls;
+    }
+
+    @Override
+    public Classpath getTestClasspath()
+    {
+        return testClasspathUrls;
+    }
+
+    @Override
+    public final boolean isModularPathConfig()
+    {
+        return true;
+    }
+
+    @Override
+    public final boolean isClassPathConfig()
+    {
+        return !isModularPathConfig();
+    }
+
+    public ModularClasspath getModularClasspath()
+    {
+        return modularClasspath;
+    }
+}

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/ec354cc7/surefire-booter/src/main/java/org/apache/maven/surefire/booter/StartupConfiguration.java
----------------------------------------------------------------------
diff --git 
a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/StartupConfiguration.java
 
b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/StartupConfiguration.java
index 91530b7..7dd30ff 100644
--- 
a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/StartupConfiguration.java
+++ 
b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/StartupConfiguration.java
@@ -26,20 +26,15 @@ package org.apache.maven.surefire.booter;
  */
 public class StartupConfiguration
 {
-    private final String providerClassName;
-
-    private final ClasspathConfiguration classpathConfiguration;
+    private static final String SUREFIRE_TEST_CLASSPATH = 
"surefire.test.class.path";
 
+    private final String providerClassName;
+    private final AbstractPathConfiguration classpathConfiguration;
     private final ClassLoaderConfiguration classLoaderConfiguration;
-
     private final boolean isForkRequested;
-
     private final boolean isInForkedVm;
 
-    private static final String SUREFIRE_TEST_CLASSPATH = 
"surefire.test.class.path";
-
-
-    public StartupConfiguration( String providerClassName, 
ClasspathConfiguration classpathConfiguration,
+    public StartupConfiguration( String providerClassName, 
AbstractPathConfiguration classpathConfiguration,
                                  ClassLoaderConfiguration 
classLoaderConfiguration, boolean isForkRequested,
                                  boolean inForkedVm )
     {
@@ -63,11 +58,12 @@ public class StartupConfiguration
                                          true );
     }
 
-    public ClasspathConfiguration getClasspathConfiguration()
+    public AbstractPathConfiguration getClasspathConfiguration()
     {
         return classpathConfiguration;
     }
 
+    @Deprecated
     public boolean useSystemClassLoader()
     {
         // todo; I am not totally convinced this logic is as simple as it 
could be
@@ -86,11 +82,7 @@ public class StartupConfiguration
 
     public String getActualClassName()
     {
-        if ( isProviderMainClass() )
-        {
-            return stripEnd( providerClassName, "#main" );
-        }
-        return providerClassName;
+        return isProviderMainClass() ? stripEnd( providerClassName, "#main" ) 
: providerClassName;
     }
 
     /**
@@ -120,7 +112,7 @@ public class StartupConfiguration
         }
         else
         {
-            while ( ( end != 0 ) && ( strip.indexOf( str.charAt( end - 1 ) ) 
!= -1 ) )
+            while ( end != 0 && strip.indexOf( str.charAt( end - 1 ) ) != -1 )
             {
                 end--;
             }
@@ -140,8 +132,6 @@ public class StartupConfiguration
 
     public void writeSurefireTestClasspathProperty()
     {
-        ClasspathConfiguration classpathConfiguration = 
getClasspathConfiguration();
-        classpathConfiguration.getTestClasspath().writeToSystemProperty( 
SUREFIRE_TEST_CLASSPATH );
+        getClasspathConfiguration().getTestClasspath().writeToSystemProperty( 
SUREFIRE_TEST_CLASSPATH );
     }
-
 }

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/ec354cc7/surefire-booter/src/test/java/org/apache/maven/surefire/booter/SystemUtilsTest.java
----------------------------------------------------------------------
diff --git 
a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/SystemUtilsTest.java
 
b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/SystemUtilsTest.java
index 1917cbb..a7222ab 100644
--- 
a/surefire-booter/src/test/java/org/apache/maven/surefire/booter/SystemUtilsTest.java
+++ 
b/surefire-booter/src/test/java/org/apache/maven/surefire/booter/SystemUtilsTest.java
@@ -44,6 +44,7 @@ import static org.junit.Assume.assumeTrue;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyDouble;
 import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.when;
 import static org.powermock.api.mockito.PowerMockito.mockStatic;
 import static org.powermock.api.mockito.PowerMockito.verifyStatic;
@@ -322,10 +323,10 @@ public class SystemUtilsTest
                 assertThat( SystemUtils.isJava9AtLeast( path.getAbsolutePath() 
) ).isFalse();
             }
 
-            verifyStatic( Mockito.times( 0 ) );
+            verifyStatic( times( 0 ) );
             SystemUtils.toJdkVersionFromReleaseFile( any( File.class ) );
 
-            verifyStatic( Mockito.times( 1 ) );
+            verifyStatic( times( 1 ) );
             SystemUtils.isBuiltInJava9AtLeast();
         }
 

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/ec354cc7/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/ModulePathIT.java
----------------------------------------------------------------------
diff --git 
a/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/ModulePathIT.java
 
b/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/ModulePathIT.java
new file mode 100644
index 0000000..3c3d2c6
--- /dev/null
+++ 
b/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/ModulePathIT.java
@@ -0,0 +1,45 @@
+package org.apache.maven.surefire.its;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+import org.junit.Test;
+
+import java.io.IOException;
+
+public class ModulePathIT
+        extends AbstractJigsawIT
+{
+    @Test
+    public void testModulePath()
+            throws IOException
+    {
+        assumeJigsaw()
+                .debugLogging()
+                .executeTest()
+                .verifyErrorFreeLog()
+                .assertTestSuiteResults( 2 );
+    }
+
+    @Override
+    protected String getProjectDirectoryName()
+    {
+        return "modulepath";
+    }
+}

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/ec354cc7/surefire-integration-tests/src/test/resources/modulepath/pom.xml
----------------------------------------------------------------------
diff --git a/surefire-integration-tests/src/test/resources/modulepath/pom.xml 
b/surefire-integration-tests/src/test/resources/modulepath/pom.xml
new file mode 100644
index 0000000..e4a7783
--- /dev/null
+++ b/surefire-integration-tests/src/test/resources/modulepath/pom.xml
@@ -0,0 +1,45 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/maven-v4_0_0.xsd";>
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>foo</groupId>
+    <artifactId>app</artifactId>
+    <version>1.0.0-SNAPSHOT</version>
+
+    <name>app</name>
+
+    <properties>
+        <maven.compiler.release>9</maven.compiler.release>
+    </properties>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>3.6.2</version>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <version>${surefire.version}</version>
+            </plugin>
+        </plugins>
+    </build>
+
+    <dependencies>
+        <dependency>
+            <groupId>joda-time</groupId>
+            <artifactId>joda-time</artifactId>
+            <version>2.9.9</version>
+        </dependency>
+        <dependency>
+            <groupId>org.testng</groupId>
+            <artifactId>testng</artifactId>
+            <version>6.11</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+</project>

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/ec354cc7/surefire-integration-tests/src/test/resources/modulepath/src/main/java/com/app/Main.java
----------------------------------------------------------------------
diff --git 
a/surefire-integration-tests/src/test/resources/modulepath/src/main/java/com/app/Main.java
 
b/surefire-integration-tests/src/test/resources/modulepath/src/main/java/com/app/Main.java
new file mode 100644
index 0000000..6a44492
--- /dev/null
+++ 
b/surefire-integration-tests/src/test/resources/modulepath/src/main/java/com/app/Main.java
@@ -0,0 +1,34 @@
+package com.app;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+import org.joda.time.DateTime;
+
+public class Main
+{
+    public static void main( String... args )
+    {
+        System.out.println( "module path => " + System.getProperty( 
"jdk.module.path" ) );
+        System.out.println( " class path => " + System.getProperty( 
"java.class.path" ) );
+
+        DateTime dt = new DateTime();
+        System.out.println( dt );
+    }
+}

http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/ec354cc7/surefire-integration-tests/src/test/resources/modulepath/src/main/java/module-info.java
----------------------------------------------------------------------
diff --git 
a/surefire-integration-tests/src/test/resources/modulepath/src/main/java/module-info.java
 
b/surefire-integration-tests/src/test/resources/modulepath/src/main/java/module-info.java
new file mode 100644
index 0000000..5f3eed4
--- /dev/null
+++ 
b/surefire-integration-tests/src/test/resources/modulepath/src/main/java/module-info.java
@@ -0,0 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+module com.app {
+    requires joda.time;
+}

Reply via email to