This is an automated email from the ASF dual-hosted git repository.

tibordigana pushed a commit to branch SUREFIRE-1593
in repository https://gitbox.apache.org/repos/asf/maven-surefire.git

commit f5cca5bcc2c85060c21c82eea0081d016cb86909
Author: Tibor17 <tibordig...@apache.org>
AuthorDate: Fri Nov 16 22:55:02 2018 +0100

    [SUREFIRE-1593] 3.0.0-M1 produces invalid code sources on Windows
---
 .../booterclient/JarManifestForkConfiguration.java |  35 +++-
 .../JarManifestForkConfigurationTest.java          | 221 +++++++++++++++++++++
 .../org/apache/maven/surefire/JUnit4SuiteTest.java |   2 +
 3 files changed, 249 insertions(+), 9 deletions(-)

diff --git 
a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/JarManifestForkConfiguration.java
 
b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/JarManifestForkConfiguration.java
index 70f95d9..79db5c6 100644
--- 
a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/JarManifestForkConfiguration.java
+++ 
b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/JarManifestForkConfiguration.java
@@ -34,6 +34,7 @@ import java.io.IOException;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
@@ -42,6 +43,7 @@ import java.util.jar.JarEntry;
 import java.util.jar.JarOutputStream;
 import java.util.jar.Manifest;
 
+import static java.nio.file.Files.isDirectory;
 import static 
org.apache.maven.plugin.surefire.SurefireHelper.escapeToPlatformPath;
 
 /**
@@ -116,10 +118,10 @@ public final class JarManifestForkConfiguration
             StringBuilder cp = new StringBuilder();
             for ( Iterator<String> it = classPath.iterator(); it.hasNext(); )
             {
-                File classPathElement = new File( it.next() );
+                Path classPathElement = Paths.get( it.next() );
                 String uri = toClasspathElementUri( parent, classPathElement, 
dumpLogDirectory );
                 cp.append( uri );
-                if ( classPathElement.isDirectory() && !uri.endsWith( "/" ) )
+                if ( isDirectory( classPathElement ) && !uri.endsWith( "/" ) )
                 {
                     cp.append( '/' );
                 }
@@ -143,24 +145,39 @@ public final class JarManifestForkConfiguration
         }
     }
 
-    private static String toClasspathElementUri( @Nonnull Path parent,
-                                                 @Nonnull File 
classPathElement,
-                                                 @Nonnull File 
dumpLogDirectory )
+    static String relativize( @Nonnull Path parent, @Nonnull Path child )
+            throws IllegalArgumentException
+    {
+        return parent.relativize( child )
+                .toString();
+    }
+
+    static String toAbsoluteUri( @Nonnull Path absolutePath )
+    {
+        return absolutePath.toUri()
+                .toASCIIString();
+    }
+
+    static String toClasspathElementUri( @Nonnull Path parent,
+                                         @Nonnull Path classPathElement,
+                                         @Nonnull File dumpLogDirectory )
             throws IOException
     {
         try
         {
-            return new URI( null, parent.relativize( classPathElement.toPath() 
).toString(), null )
+            String relativeUriPath = relativize( parent, classPathElement )
+                    .replace( '\\', '/' );
+
+            return new URI( null, relativeUriPath, null )
                     .toASCIIString();
         }
         catch ( IllegalArgumentException e )
         {
-            String error = "Boot Manifest-JAR contains absolute paths in 
classpath " + classPathElement.getPath();
+            String error = "Boot Manifest-JAR contains absolute paths in 
classpath " + classPathElement;
             InPluginProcessDumpSingleton.getSingleton()
                     .dumpException( e, error, dumpLogDirectory );
 
-            return classPathElement.toURI()
-                    .toASCIIString();
+            return toAbsoluteUri( classPathElement );
         }
         catch ( URISyntaxException e )
         {
diff --git 
a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/JarManifestForkConfigurationTest.java
 
b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/JarManifestForkConfigurationTest.java
new file mode 100644
index 0000000..18b205a
--- /dev/null
+++ 
b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/JarManifestForkConfigurationTest.java
@@ -0,0 +1,221 @@
+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 java.io.File;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.file.Path;
+
+import 
org.apache.maven.plugin.surefire.booterclient.output.InPluginProcessDumpSingleton;
+
+import static 
org.apache.maven.plugin.surefire.booterclient.JarManifestForkConfiguration.relativize;
+import static 
org.apache.maven.plugin.surefire.booterclient.JarManifestForkConfiguration.toAbsoluteUri;
+import static 
org.apache.maven.plugin.surefire.booterclient.JarManifestForkConfiguration.toClasspathElementUri;
+import static org.fest.assertions.Assertions.assertThat;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.fest.util.Files.delete;
+import static org.fest.util.Files.newTemporaryFolder;
+import static org.mockito.ArgumentMatchers.same;
+import static org.powermock.api.mockito.PowerMockito.mock;
+import static org.powermock.api.mockito.PowerMockito.mockStatic;
+import static org.powermock.api.mockito.PowerMockito.when;
+
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+/**
+ * Unit tests for {@link JarManifestForkConfiguration}.
+ */
+@RunWith( PowerMockRunner.class )
+@PrepareForTest( { JarManifestForkConfiguration.class, 
InPluginProcessDumpSingleton.class } )
+public class JarManifestForkConfigurationTest
+{
+    private static final File TMP = newTemporaryFolder();
+
+    private static File dumpDirectory;
+
+    @BeforeClass
+    public static void createSystemTemporaryDir()
+    {
+        dumpDirectory = new File( TMP, "dump" );
+        assertThat( dumpDirectory.mkdir() )
+                .isTrue();
+    }
+
+    @AfterClass
+    public static void deleteSystemTemporaryDir()
+    {
+        delete( TMP );
+    }
+
+    @Test
+    public void relativeClasspathUnixSimple()
+        throws Exception
+    {
+        mockStatic( JarManifestForkConfiguration.class );
+        Path parent = mock( Path.class );
+        when( parent.toString() ).thenReturn( "/home/me/prj/target/surefire" );
+        Path classPathElement = mock( Path.class );
+        when( classPathElement.toString() ).thenReturn( 
"/home/me/.m2/repository/grp/art/1.0/art-1.0.jar" );
+        when( relativize( parent, classPathElement ) )
+                .thenReturn( "../../../.m2/repository/grp/art/1.0/art-1.0.jar" 
);
+        when( toClasspathElementUri( same( parent ), same( classPathElement ), 
same( dumpDirectory ) ) )
+                .thenCallRealMethod();
+        assertThat( toClasspathElementUri( parent, classPathElement, 
dumpDirectory ) )
+                .isEqualTo( "../../../.m2/repository/grp/art/1.0/art-1.0.jar" 
);
+    }
+
+    @Test
+    public void relativeClasspathUnixTricky()
+        throws Exception
+    {
+        mockStatic( JarManifestForkConfiguration.class );
+        Path parent = mock( Path.class );
+        when( parent.toString() ).thenReturn( "/home/me/prj/target/surefire" );
+        Path classPathElement = mock( Path.class );
+        when( classPathElement.toString() ).thenReturn( "/the Maven 
repo/grp/art/1.0/art-1.0.jar" );
+        when( relativize( parent, classPathElement ) )
+                .thenReturn( "../../../../../the Maven 
repo/grp/art/1.0/art-1.0.jar" );
+        when( toClasspathElementUri( same( parent ), same( classPathElement ), 
same( dumpDirectory ) ) )
+                .thenCallRealMethod();
+        assertThat( toClasspathElementUri( parent, classPathElement, 
dumpDirectory ) )
+                .isEqualTo( 
"../../../../../the%20Maven%20repo/grp/art/1.0/art-1.0.jar" );
+    }
+
+    @Test
+    public void relativeClasspathWindowsSimple()
+        throws Exception
+    {
+        mockStatic( JarManifestForkConfiguration.class );
+        Path parent = mock( Path.class );
+        when( parent.toString() ).thenReturn( "C:\\Windows\\Temp\\surefire" );
+        Path classPathElement = mock( Path.class );
+        when( classPathElement.toString() ).thenReturn( 
"C:\\Users\\me\\.m2\\repository\\grp\\art\\1.0\\art-1.0.jar" );
+        when( relativize( parent, classPathElement ) )
+                .thenReturn( 
"..\\..\\..\\Users\\me\\.m2\\repository\\grp\\art\\1.0\\art-1.0.jar" );
+        when( toClasspathElementUri( same( parent ), same( classPathElement ), 
same( dumpDirectory ) ) )
+                .thenCallRealMethod();
+        assertThat( toClasspathElementUri( parent, classPathElement, 
dumpDirectory ) )
+                .isEqualTo( 
"../../../Users/me/.m2/repository/grp/art/1.0/art-1.0.jar" );
+    }
+
+    @Test
+    public void relativeClasspathWindowsTricky()
+        throws Exception
+    {
+        mockStatic( JarManifestForkConfiguration.class );
+        Path parent = mock( Path.class );
+        when( parent.toString() ).thenReturn( "C:\\Windows\\Temp\\surefire" );
+        Path classPathElement = mock( Path.class );
+        when( classPathElement.toString() ).thenReturn( "C:\\Test 
User\\me\\.m2\\repository\\grp\\art\\1.0\\art-1.0.jar" );
+        when( relativize( parent, classPathElement ) )
+                .thenReturn( "..\\..\\..\\Test 
User\\me\\.m2\\repository\\grp\\art\\1.0\\art-1.0.jar" );
+        when( toClasspathElementUri( same( parent ), same( classPathElement ), 
same( dumpDirectory ) ) )
+                .thenCallRealMethod();
+        assertThat( toClasspathElementUri( parent, classPathElement, 
dumpDirectory ) )
+                .isEqualTo( 
"../../../Test%20User/me/.m2/repository/grp/art/1.0/art-1.0.jar" );
+    }
+
+    @Test
+    public void crossDriveWindows()
+        throws Exception
+    {
+        mockStatic( JarManifestForkConfiguration.class );
+        mockStatic( InPluginProcessDumpSingleton.class );
+        when( InPluginProcessDumpSingleton.getSingleton() ).thenReturn( mock( 
InPluginProcessDumpSingleton.class ) );
+        Path parent = mock( Path.class );
+        when( parent.toString() ).thenReturn( "C:\\Windows\\Temp\\surefire" );
+        Path classPathElement = mock( Path.class );
+        when( classPathElement.toString() ).thenReturn( 
"X:\\Users\\me\\.m2\\repository\\grp\\art\\1.0\\art-1.0.jar" );
+        when( classPathElement.toUri() )
+                .thenAnswer( new Answer<URI>()
+                {
+                    @Override
+                    public URI answer( InvocationOnMock invocation ) throws 
URISyntaxException
+                    {
+                        String path = invocation.getMock().toString();
+                        return new URI( "file", "", "/" + path.replace( '\\', 
'/' ), null );
+                    }
+                } );
+        when( relativize( same( parent ), same( classPathElement ) ) )
+                .thenThrow( new IllegalArgumentException() );
+        when( toClasspathElementUri( same( parent ), same( classPathElement ), 
same( dumpDirectory ) ) )
+                .thenCallRealMethod();
+        when( toAbsoluteUri( same( classPathElement ) ) )
+                .thenCallRealMethod();
+        assertThat( toClasspathElementUri( parent, classPathElement, 
dumpDirectory ) )
+                .isEqualTo( 
"file:///X:/Users/me/.m2/repository/grp/art/1.0/art-1.0.jar" );
+    }
+
+    @Test
+    public void shouldRelativizeOnRealPlatform()
+    {
+        Path parentDir = new File( TMP, "test-parent-1" )
+                .toPath();
+
+        Path testDir = new File( TMP, "@1 test with white spaces" )
+                .toPath();
+
+        String relativeTestDir = relativize( parentDir, testDir );
+
+        assertThat( relativeTestDir )
+                .isEqualTo( ".." + File.separator + "@1 test with white 
spaces" );
+    }
+
+    @Test
+    public void shouldMakeAbsoluteUriOnRealPlatform()
+            throws Exception
+    {
+        Path testDir = new File( TMP, "@2 test with white spaces" )
+                .toPath();
+
+        URI testDirUri = new URI( toAbsoluteUri( testDir ) );
+
+        assertThat( testDirUri.getScheme() )
+                .isEqualTo( "file" );
+
+        assertThat( testDirUri.getRawPath() )
+                .isEqualTo( testDir.toUri().getRawPath() );
+    }
+
+    @Test
+    public void shouldMakeRelativeUriOnRealPlatform()
+            throws Exception
+    {
+        Path parentDir = new File( TMP, "test-parent-2" )
+                .toPath();
+
+        Path testDir = new File( TMP, "@3 test with white spaces" )
+                .toPath();
+
+        String testDirUriPath = toClasspathElementUri( parentDir, testDir, 
dumpDirectory );
+
+        assertThat( testDirUriPath )
+                .isEqualTo( "../@3%20test%20with%20white%20spaces" );
+    }
+}
diff --git 
a/maven-surefire-common/src/test/java/org/apache/maven/surefire/JUnit4SuiteTest.java
 
b/maven-surefire-common/src/test/java/org/apache/maven/surefire/JUnit4SuiteTest.java
index 2ca1b39..2f1f01f 100644
--- 
a/maven-surefire-common/src/test/java/org/apache/maven/surefire/JUnit4SuiteTest.java
+++ 
b/maven-surefire-common/src/test/java/org/apache/maven/surefire/JUnit4SuiteTest.java
@@ -34,6 +34,7 @@ import 
org.apache.maven.plugin.surefire.booterclient.BooterDeserializerStartupCo
 import 
org.apache.maven.plugin.surefire.booterclient.DefaultForkConfigurationTest;
 import org.apache.maven.plugin.surefire.booterclient.ForkConfigurationTest;
 import org.apache.maven.plugin.surefire.booterclient.ForkingRunListenerTest;
+import 
org.apache.maven.plugin.surefire.booterclient.JarManifestForkConfigurationTest;
 import 
org.apache.maven.plugin.surefire.booterclient.ModularClasspathForkConfigurationTest;
 import 
org.apache.maven.plugin.surefire.booterclient.lazytestprovider.TestLessInputStreamBuilderTest;
 import 
org.apache.maven.plugin.surefire.booterclient.lazytestprovider.TestProvidingInputStreamTest;
@@ -85,6 +86,7 @@ public class JUnit4SuiteTest extends TestCase
         suite.addTest( new JUnit4TestAdapter( SurefireHelperTest.class ) );
         suite.addTest( new JUnit4TestAdapter( AbstractSurefireMojoTest.class ) 
);
         suite.addTest( new JUnit4TestAdapter( 
DefaultForkConfigurationTest.class ) );
+        suite.addTest( new JUnit4TestAdapter( 
JarManifestForkConfigurationTest.class ) );
         suite.addTest( new JUnit4TestAdapter( 
ModularClasspathForkConfigurationTest.class ) );
         suite.addTest( new JUnit4TestAdapter( 
AbstractSurefireMojoJava7PlusTest.class ) );
         suite.addTest( new JUnit4TestAdapter( ScannerUtilTest.class ) );

Reply via email to