Repository: maven-surefire Updated Branches: refs/heads/master 2b4629c71 -> c26bc4b9e
[SUREFIRE-1137] Ensure that all communication with the forked process is encoded with a fixed 8-bit charset, to fix sysout/syserr encoding in case the fork ends up with a different default charset than the main process Project: http://git-wip-us.apache.org/repos/asf/maven-surefire/repo Commit: http://git-wip-us.apache.org/repos/asf/maven-surefire/commit/c26bc4b9 Tree: http://git-wip-us.apache.org/repos/asf/maven-surefire/tree/c26bc4b9 Diff: http://git-wip-us.apache.org/repos/asf/maven-surefire/diff/c26bc4b9 Branch: refs/heads/master Commit: c26bc4b9e60de515e7e730207ebf0aacb372dd04 Parents: 2b4629c Author: Andreas Gudian <agud...@apache.org> Authored: Tue Feb 3 22:30:08 2015 +0100 Committer: Andreas Gudian <agud...@apache.org> Committed: Thu Feb 5 20:54:02 2015 +0100 ---------------------------------------------------------------------- .../surefire/booterclient/ForkStarter.java | 5 +- .../TestProvidingInputStream.java | 4 +- .../booterclient/output/ForkClient.java | 33 +++++++++-- .../surefire/report/DirectConsoleOutput.java | 16 ++++- .../booterclient/ForkingRunListenerTest.java | 6 +- pom.xml | 2 +- .../surefire/booter/ForkingRunListener.java | 62 ++++++++------------ .../surefire/report/ConsoleOutputCapture.java | 8 +-- .../surefire/util/internal/StringUtils.java | 57 ++++++++++++++---- .../surefire/util/internal/StringUtilsTest.java | 9 +-- .../maven/surefire/booter/ForkedBooter.java | 18 ++++-- .../maven/surefire/booter/LazyTestsToRun.java | 17 +++++- .../maven/surefire/its/ConsoleOutputIT.java | 47 +++++++++++++-- .../maven/surefire/its/fixture/TestFile.java | 2 +- .../src/test/resources/consoleOutput/pom.xml | 17 ++---- .../src/test/java/consoleOutput/Test1.java | 17 +++--- 16 files changed, 220 insertions(+), 100 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/c26bc4b9/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkStarter.java ---------------------------------------------------------------------- diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkStarter.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkStarter.java index 12b224a..b1755ba 100644 --- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkStarter.java +++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkStarter.java @@ -22,6 +22,7 @@ package org.apache.maven.plugin.surefire.booterclient; import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; @@ -68,6 +69,7 @@ import org.apache.maven.surefire.report.StackTraceWriter; import org.apache.maven.surefire.suite.RunResult; import org.apache.maven.surefire.testset.TestRequest; import org.apache.maven.surefire.util.DefaultScanResult; +import org.apache.maven.surefire.util.internal.StringUtils; import static org.apache.maven.surefire.booter.Classpath.join; @@ -468,7 +470,8 @@ public class ForkStarter final int timeout = forkedProcessTimeoutInSeconds > 0 ? forkedProcessTimeoutInSeconds : 0; final int result = CommandLineUtils.executeCommandLine( cli, testProvidingInputStream, threadedStreamConsumer, - threadedStreamConsumer, timeout, inputStreamCloser ); + threadedStreamConsumer, timeout, inputStreamCloser, + Charset.forName( StringUtils.FORK_STREAM_CHARSET_NAME ) ); if ( result != RunResult.SUCCESS ) { throw new SurefireBooterForkException( "Error occurred in starting fork, check output in log" ); http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/c26bc4b9/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/TestProvidingInputStream.java ---------------------------------------------------------------------- diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/TestProvidingInputStream.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/TestProvidingInputStream.java index a33ce62..e7a5032 100644 --- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/TestProvidingInputStream.java +++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/lazytestprovider/TestProvidingInputStream.java @@ -24,6 +24,8 @@ import java.io.InputStream; import java.util.Queue; import java.util.concurrent.Semaphore; +import static org.apache.maven.surefire.util.internal.StringUtils.encodeStringForForkCommunication; + /** * An {@link InputStream} that, when read, provides test class names out of a queue. * <p/> @@ -90,7 +92,7 @@ public class TestProvidingInputStream String currentElement = testItemQueue.poll(); if ( currentElement != null ) { - currentBuffer = currentElement.getBytes(); + currentBuffer = encodeStringForForkCommunication( currentElement ); currentPos = 0; } else http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/c26bc4b9/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkClient.java ---------------------------------------------------------------------- diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkClient.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkClient.java index 7a2a15b..b6bbd55 100644 --- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkClient.java +++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/output/ForkClient.java @@ -22,6 +22,7 @@ package org.apache.maven.plugin.surefire.booterclient.output; import java.io.BufferedReader; import java.io.IOException; import java.io.StringReader; +import java.nio.ByteBuffer; import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -140,14 +141,10 @@ public class ForkClient } break; case ForkingRunListener.BOOTERCODE_STDOUT: - byte[] bytes = new byte[remaining.length()]; - int len = StringUtils.unescapeBytes( bytes, remaining ); - getOrCreateConsoleOutputReceiver( channelNumber ).writeTestOutput( bytes, 0, len, true ); + writeTestOutput( channelNumber, remaining, true ); break; case ForkingRunListener.BOOTERCODE_STDERR: - bytes = new byte[remaining.length()]; - len = StringUtils.unescapeBytes( bytes, remaining ); - getOrCreateConsoleOutputReceiver( channelNumber ).writeTestOutput( bytes, 0, len, false ); + writeTestOutput( channelNumber, remaining, false ); break; case ForkingRunListener.BOOTERCODE_CONSOLE: getOrCreateConsoleLogger( channelNumber ).info( createConsoleMessage( remaining ) ); @@ -184,6 +181,30 @@ public class ForkClient } } + private void writeTestOutput( final Integer channelNumber, final String remaining, boolean isStdout ) + { + int csNameEnd = remaining.indexOf( ',' ); + String charsetName = remaining.substring( 0, csNameEnd ); + String byteEncoded = remaining.substring( csNameEnd + 1 ); + ByteBuffer unescaped = StringUtils.unescapeBytes( byteEncoded, charsetName ); + + if ( unescaped.hasArray() ) + { + byte[] convertedBytes = unescaped.array(); + + getOrCreateConsoleOutputReceiver( channelNumber ) + .writeTestOutput( convertedBytes, unescaped.position(), unescaped.remaining(), isStdout ); + } + else + { + byte[] convertedBytes = new byte[unescaped.remaining()]; + unescaped.get( convertedBytes, 0, unescaped.remaining() ); + + getOrCreateConsoleOutputReceiver( channelNumber ) + .writeTestOutput( convertedBytes, 0, convertedBytes.length, isStdout ); + } + } + public void consumeMultiLineContent( String s ) throws IOException { http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/c26bc4b9/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/DirectConsoleOutput.java ---------------------------------------------------------------------- diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/DirectConsoleOutput.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/DirectConsoleOutput.java index ab710e9..bd5ba7c 100644 --- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/DirectConsoleOutput.java +++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/report/DirectConsoleOutput.java @@ -20,6 +20,11 @@ package org.apache.maven.plugin.surefire.report; */ import java.io.PrintStream; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.CharacterCodingException; +import java.nio.charset.Charset; + import org.apache.maven.surefire.report.ReportEntry; /** @@ -47,7 +52,16 @@ public class DirectConsoleOutput public void writeTestOutput( byte[] buf, int off, int len, boolean stdout ) { PrintStream stream = stdout ? sout : serr; - stream.write( buf, off, len ); + + try + { + CharBuffer decode = Charset.defaultCharset().newDecoder().decode( ByteBuffer.wrap( buf, off, len ) ); + stream.append( decode ); + } + catch ( CharacterCodingException e ) + { + stream.write( buf, off, len ); + } } public void testSetStarting( ReportEntry reportEntry ) http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/c26bc4b9/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkingRunListenerTest.java ---------------------------------------------------------------------- diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkingRunListenerTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkingRunListenerTest.java index ca64092..fd85b44 100644 --- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkingRunListenerTest.java +++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkingRunListenerTest.java @@ -22,9 +22,11 @@ package org.apache.maven.plugin.surefire.booterclient; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.PrintStream; +import java.nio.charset.Charset; import java.util.List; import java.util.Properties; import java.util.StringTokenizer; + import org.apache.maven.plugin.surefire.booterclient.output.ForkClient; import org.apache.maven.surefire.booter.ForkingRunListener; import org.apache.maven.surefire.report.CategorizedReportEntry; @@ -72,14 +74,14 @@ public class ForkingRunListenerTest { final byte[] header = ForkingRunListener.createHeader( (byte) 'F', 0xCAFE ); String asString = new String( header ); - assertEquals( "F,cafe,", asString ); + assertEquals( "F,cafe," + Charset.defaultCharset().name() + ",", asString ); } public void testHeaderCreationShort() { final byte[] header = ForkingRunListener.createHeader( (byte) 'F', 0xE ); String asString = new String( header ); - assertEquals( "F,000e,", asString ); + assertEquals( "F,e," + Charset.defaultCharset().name() + ",", asString ); } public void testSetStarting() http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/c26bc4b9/pom.xml ---------------------------------------------------------------------- diff --git a/pom.xml b/pom.xml index 1d6087c..68f270e 100644 --- a/pom.xml +++ b/pom.xml @@ -206,7 +206,7 @@ <dependency> <groupId>org.apache.maven.shared</groupId> <artifactId>maven-shared-utils</artifactId> - <version>0.4</version> + <version>0.8-SNAPSHOT</version> </dependency> <dependency> <groupId>org.apache.maven.shared</groupId> http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/c26bc4b9/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkingRunListener.java ---------------------------------------------------------------------- diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkingRunListener.java b/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkingRunListener.java index 5874d0b..77af0d5 100644 --- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkingRunListener.java +++ b/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkingRunListener.java @@ -20,6 +20,7 @@ package org.apache.maven.surefire.booter; */ import java.io.PrintStream; +import java.nio.charset.Charset; import java.util.Enumeration; import java.util.Properties; @@ -31,6 +32,8 @@ import org.apache.maven.surefire.report.SafeThrowable; import org.apache.maven.surefire.report.StackTraceWriter; import org.apache.maven.surefire.util.internal.StringUtils; +import static org.apache.maven.surefire.util.internal.StringUtils.encodeStringForForkCommunication; + /** * Encodes the full output of the test run to the stdout stream. * <p/> @@ -81,7 +84,6 @@ public class ForkingRunListener public static final byte BOOTERCODE_BYE = (byte) 'Z'; - private final PrintStream target; private final int testSetChannelId; @@ -104,42 +106,42 @@ public class ForkingRunListener public void testSetStarting( ReportEntry report ) { - target.print( toString( BOOTERCODE_TESTSET_STARTING, report, testSetChannelId ) ); + encodeAndWriteToTarget( toString( BOOTERCODE_TESTSET_STARTING, report, testSetChannelId ) ); } public void testSetCompleted( ReportEntry report ) { - target.print( toString( BOOTERCODE_TESTSET_COMPLETED, report, testSetChannelId ) ); + encodeAndWriteToTarget( toString( BOOTERCODE_TESTSET_COMPLETED, report, testSetChannelId ) ); } public void testStarting( ReportEntry report ) { - target.print( toString( BOOTERCODE_TEST_STARTING, report, testSetChannelId ) ); + encodeAndWriteToTarget( toString( BOOTERCODE_TEST_STARTING, report, testSetChannelId ) ); } public void testSucceeded( ReportEntry report ) { - target.print( toString( BOOTERCODE_TEST_SUCCEEDED, report, testSetChannelId ) ); + encodeAndWriteToTarget( toString( BOOTERCODE_TEST_SUCCEEDED, report, testSetChannelId ) ); } public void testAssumptionFailure( ReportEntry report ) { - target.print( toString( BOOTERCODE_TEST_ASSUMPTIONFAILURE, report, testSetChannelId ) ); + encodeAndWriteToTarget( toString( BOOTERCODE_TEST_ASSUMPTIONFAILURE, report, testSetChannelId ) ); } public void testError( ReportEntry report ) { - target.print( toString( BOOTERCODE_TEST_ERROR, report, testSetChannelId ) ); + encodeAndWriteToTarget( toString( BOOTERCODE_TEST_ERROR, report, testSetChannelId ) ); } public void testFailed( ReportEntry report ) { - target.print( toString( BOOTERCODE_TEST_FAILED, report, testSetChannelId ) ); + encodeAndWriteToTarget( toString( BOOTERCODE_TEST_FAILED, report, testSetChannelId ) ); } public void testSkipped( ReportEntry report ) { - target.print( toString( BOOTERCODE_TEST_SKIPPED, report, testSetChannelId ) ); + encodeAndWriteToTarget( toString( BOOTERCODE_TEST_SKIPPED, report, testSetChannelId ) ); } void sendProps() @@ -148,7 +150,7 @@ public class ForkingRunListener if ( systemProperties != null ) { - Enumeration propertyKeys = systemProperties.propertyNames(); + Enumeration<?> propertyKeys = systemProperties.propertyNames(); while ( propertyKeys.hasMoreElements() ) { @@ -160,7 +162,7 @@ public class ForkingRunListener { value = "null"; } - target.print( toPropertyString( key, value ) ); + encodeAndWriteToTarget( toPropertyString( key, value ) ); } } } @@ -182,34 +184,14 @@ public class ForkingRunListener public static byte[] createHeader( byte booterCode, int testSetChannel ) { - byte[] header = new byte[7]; - header[0] = booterCode; - header[1] = (byte) ','; - header[6] = (byte) ','; - - int i = testSetChannel; - int charPos = 6; - int radix = 1 << 4; - int mask = radix - 1; - do - { - header[--charPos] = (byte) DIGITS[i & mask]; - i >>>= 4; - } - while ( i != 0 ); + StringBuilder sb = new StringBuilder(); + sb.append( (char) booterCode ).append( ',' ); + sb.append( Integer.toString( testSetChannel, 16 ) ).append( ',' ); + sb.append( Charset.defaultCharset().name() ).append( ',' ); - while ( charPos > 2 ) - { - header[--charPos] = (byte) '0'; - } - return header; + return encodeStringForForkCommunication( sb.toString() ); } - private static final char[] DIGITS = - { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', - 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' }; - - public void info( String message ) { if ( message != null ) @@ -220,10 +202,16 @@ public class ForkingRunListener StringUtils.escapeToPrintable( sb, message ); sb.append( '\n' ); - target.print( sb.toString() ); + encodeAndWriteToTarget( sb.toString() ); } } + private void encodeAndWriteToTarget( String string ) + { + byte[] encodeBytes = encodeStringForForkCommunication( string ); + target.write( encodeBytes, 0, encodeBytes.length ); + } + private String toPropertyString( String key, String value ) { StringBuilder stringBuilder = new StringBuilder(); http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/c26bc4b9/surefire-api/src/main/java/org/apache/maven/surefire/report/ConsoleOutputCapture.java ---------------------------------------------------------------------- diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/report/ConsoleOutputCapture.java b/surefire-api/src/main/java/org/apache/maven/surefire/report/ConsoleOutputCapture.java index 7421703..27b0ee2 100644 --- a/surefire-api/src/main/java/org/apache/maven/surefire/report/ConsoleOutputCapture.java +++ b/surefire-api/src/main/java/org/apache/maven/surefire/report/ConsoleOutputCapture.java @@ -22,7 +22,6 @@ package org.apache.maven.surefire.report; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.PrintStream; -import org.apache.maven.surefire.util.internal.ByteBuffer; /** * Deals with system.out/err. @@ -78,17 +77,14 @@ public class ConsoleOutputCapture } } - static final byte[] NL = new byte[]{ (byte) '\n' }; - public void println( String s ) { if ( s == null ) { s = "null"; // Shamelessly taken from super.print } - final byte[] bytes = s.getBytes(); - final byte[] join = ByteBuffer.join( bytes, 0, bytes.length, NL, 0, 1 ); - target.writeTestOutput( join, 0, join.length, isStdout ); + final byte[] bytes = ( s + "\n" ).getBytes(); + target.writeTestOutput( bytes, 0, bytes.length, isStdout ); } public void close() http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/c26bc4b9/surefire-api/src/main/java/org/apache/maven/surefire/util/internal/StringUtils.java ---------------------------------------------------------------------- diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/util/internal/StringUtils.java b/surefire-api/src/main/java/org/apache/maven/surefire/util/internal/StringUtils.java index f9137cf..3f29f8a 100644 --- a/surefire-api/src/main/java/org/apache/maven/surefire/util/internal/StringUtils.java +++ b/surefire-api/src/main/java/org/apache/maven/surefire/util/internal/StringUtils.java @@ -19,6 +19,11 @@ package org.apache.maven.surefire.util.internal; * under the License. */ +import java.io.UnsupportedEncodingException; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.CharacterCodingException; +import java.nio.charset.Charset; import java.util.StringTokenizer; /** @@ -56,6 +61,11 @@ public class StringUtils '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + private static final Charset DEFAULT_CHARSET = Charset.defaultCharset(); + + // 8-bit charset Latin-1 + public static final String FORK_STREAM_CHARSET_NAME = "ISO-8859-1"; + public static String[] split( String text, String separator ) { int max = -1; @@ -264,24 +274,21 @@ public class StringUtils /** * Reverses the effect of {@link #escapeBytesToPrintable(byte[], int, byte[], int, int)}. - * <p> - * A save length of {@code out} is {@code str.length()} * - * @param out the target byte array * @param str the input String + * @param charsetName the charset name * @return the number of bytes written to {@code out} */ - public static int unescapeBytes( byte[] out, String str ) + public static ByteBuffer unescapeBytes( String str, String charsetName ) { int outPos = 0; - if ( out == null ) - { - throw new IllegalArgumentException( "The output array must not be null" ); - } + if ( str == null ) { - return 0; + return ByteBuffer.wrap( new byte[0] ); } + + byte[] out = new byte[str.length()]; for ( int i = 0; i < str.length(); i++ ) { char ch = str.charAt( i ); @@ -297,6 +304,36 @@ public class StringUtils out[outPos++] = (byte) ch; } } - return outPos; + + Charset sourceCharset = Charset.forName( charsetName ); + if ( !DEFAULT_CHARSET.equals( sourceCharset ) ) + { + CharBuffer decodedFromSourceCharset; + try + { + decodedFromSourceCharset = sourceCharset.newDecoder().decode( ByteBuffer.wrap( out, 0, outPos ) ); + ByteBuffer defaultEncoded = DEFAULT_CHARSET.encode( decodedFromSourceCharset ); + + return defaultEncoded; + } + catch ( CharacterCodingException e ) + { + // ignore and fall through to the non-recoded version + } + } + + return ByteBuffer.wrap( out, 0, outPos ); + } + + public static byte[] encodeStringForForkCommunication( String string ) + { + try + { + return string.getBytes( FORK_STREAM_CHARSET_NAME ); + } + catch ( UnsupportedEncodingException e ) + { + throw new RuntimeException( "The JVM must support Charset " + FORK_STREAM_CHARSET_NAME, e ); + } } } http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/c26bc4b9/surefire-api/src/test/java/org/apache/maven/surefire/util/internal/StringUtilsTest.java ---------------------------------------------------------------------- diff --git a/surefire-api/src/test/java/org/apache/maven/surefire/util/internal/StringUtilsTest.java b/surefire-api/src/test/java/org/apache/maven/surefire/util/internal/StringUtilsTest.java index 89a8c50..c1c8d73 100644 --- a/surefire-api/src/test/java/org/apache/maven/surefire/util/internal/StringUtilsTest.java +++ b/surefire-api/src/test/java/org/apache/maven/surefire/util/internal/StringUtilsTest.java @@ -19,6 +19,8 @@ package org.apache.maven.surefire.util.internal; * under the License. */ +import java.nio.charset.Charset; + import junit.framework.TestCase; /** @@ -82,14 +84,13 @@ public class StringUtilsTest assertEquals( escapedBytes, escapedString.length() ); - byte[] unescaped = new byte[input.length]; - int unescapeBytes = StringUtils.unescapeBytes( unescaped, escapedString ); + java.nio.ByteBuffer unescaped = StringUtils.unescapeBytes( escapedString, Charset.defaultCharset().name() ); - assertEquals( input.length, unescapeBytes ); + assertEquals( input.length, unescaped.remaining() - unescaped.position() ); for ( int i = 0; i < input.length; i++ ) { - assertEquals( "At position " + i, input[i], unescaped[i] ); + assertEquals( "At position " + i, input[i], unescaped.get() ); } } } http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/c26bc4b9/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 fcd44d8..2f43d4c 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 @@ -34,6 +34,8 @@ import org.apache.maven.surefire.suite.RunResult; import org.apache.maven.surefire.testset.TestSetFailedException; import org.apache.maven.surefire.util.ReflectionUtils; +import static org.apache.maven.surefire.util.internal.StringUtils.encodeStringForForkCommunication; + /** * The part of the booter that is unique to a forked vm. * <p/> @@ -109,19 +111,19 @@ public class ForkedBooter new LegacyPojoStackTraceWriter( "test subystem", "no method", t.getTargetException() ); StringBuilder stringBuilder = new StringBuilder(); ForkingRunListener.encode( stringBuilder, stackTraceWriter, false ); - originalOut.println( ( (char) ForkingRunListener.BOOTERCODE_ERROR ) - + ",0," + stringBuilder.toString() ); + encodeAndWriteToOutput( ( (char) ForkingRunListener.BOOTERCODE_ERROR ) + + ",0," + stringBuilder.toString() + "\n" , originalOut ); } catch ( Throwable t ) { StackTraceWriter stackTraceWriter = new LegacyPojoStackTraceWriter( "test subystem", "no method", t ); StringBuilder stringBuilder = new StringBuilder(); ForkingRunListener.encode( stringBuilder, stackTraceWriter, false ); - originalOut.println( ( (char) ForkingRunListener.BOOTERCODE_ERROR ) - + ",0," + stringBuilder.toString() ); + encodeAndWriteToOutput( ( (char) ForkingRunListener.BOOTERCODE_ERROR ) + + ",0," + stringBuilder.toString() + "\n", originalOut ); } // Say bye. - originalOut.println( ( (char) ForkingRunListener.BOOTERCODE_BYE ) + ",0,BYE!" ); + encodeAndWriteToOutput( ( (char) ForkingRunListener.BOOTERCODE_BYE ) + ",0,BYE!\n", originalOut ); originalOut.flush(); // noinspection CallToSystemExit exit( 0 ); @@ -136,6 +138,12 @@ public class ForkedBooter } } + private static void encodeAndWriteToOutput( String string, PrintStream out ) + { + byte[] encodeBytes = encodeStringForForkCommunication( string ); + out.write( encodeBytes, 0, encodeBytes.length ); + } + private static final long SYSTEM_EXIT_TIMEOUT = 30 * 1000; private static void exit( final int returnCode ) http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/c26bc4b9/surefire-booter/src/main/java/org/apache/maven/surefire/booter/LazyTestsToRun.java ---------------------------------------------------------------------- diff --git a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/LazyTestsToRun.java b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/LazyTestsToRun.java index 404e5fa..b0d9728 100644 --- a/surefire-booter/src/main/java/org/apache/maven/surefire/booter/LazyTestsToRun.java +++ b/surefire-booter/src/main/java/org/apache/maven/surefire/booter/LazyTestsToRun.java @@ -24,6 +24,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.PrintStream; +import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; @@ -32,6 +33,9 @@ import java.util.List; import org.apache.maven.surefire.util.ReflectionUtils; import org.apache.maven.surefire.util.TestsToRun; +import static org.apache.maven.surefire.util.internal.StringUtils.FORK_STREAM_CHARSET_NAME; +import static org.apache.maven.surefire.util.internal.StringUtils.encodeStringForForkCommunication; + /** * A variant of TestsToRun that is provided with test class names * from an {@link InputStream} (e.g. {@code System.in}). The method @@ -64,7 +68,14 @@ class LazyTestsToRun this.originalOutStream = originalOutStream; - inputReader = new BufferedReader( new InputStreamReader( testSource ) ); + try + { + inputReader = new BufferedReader( new InputStreamReader( testSource, FORK_STREAM_CHARSET_NAME ) ); + } + catch ( UnsupportedEncodingException e ) + { + throw new RuntimeException( "The JVM must support Charset " + FORK_STREAM_CHARSET_NAME, e ); + } } protected void addWorkItem( String className ) @@ -77,7 +88,9 @@ class LazyTestsToRun protected void requestNextTest() { - originalOutStream.print( ( (char) ForkingRunListener.BOOTERCODE_NEXT_TEST ) + ",0,want more!\n" ); + byte[] encoded = + encodeStringForForkCommunication( ( (char) ForkingRunListener.BOOTERCODE_NEXT_TEST ) + ",0,want more!\n" ); + originalOutStream.write( encoded, 0, encoded.length ); } private class BlockingIterator http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/c26bc4b9/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/ConsoleOutputIT.java ---------------------------------------------------------------------- diff --git a/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/ConsoleOutputIT.java b/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/ConsoleOutputIT.java index cfce481..830341d 100644 --- a/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/ConsoleOutputIT.java +++ b/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/ConsoleOutputIT.java @@ -19,6 +19,8 @@ package org.apache.maven.surefire.its; * under the License. */ +import java.nio.charset.Charset; + import org.apache.maven.surefire.its.fixture.OutputValidator; import org.apache.maven.surefire.its.fixture.SurefireJUnit4IntegrationTestCase; import org.apache.maven.surefire.its.fixture.TestFile; @@ -33,13 +35,48 @@ public class ConsoleOutputIT extends SurefireJUnit4IntegrationTestCase { @Test - public void properNewlines() + public void properNewlinesAndEncodingWithDefaultEncodings() + { + final OutputValidator outputValidator = + unpack( "/consoleOutput" ).forkOnce().executeTest(); + + validate( outputValidator, true ); + } + + @Test + public void properNewlinesAndEncodingWithDifferentEncoding() { final OutputValidator outputValidator = - unpack( "/consoleOutput" ).redirectToFile( true ).setJUnitVersion( "4.7" ).executeTest(); - TestFile surefireReportsFile = outputValidator.getSurefireReportsFile( "consoleOutput.Test1-output.txt" ); - surefireReportsFile.assertContainsText( "SoutAgain" ); - surefireReportsFile.assertContainsText( "Printline in shutdown hook" ); + unpack( "/consoleOutput" ).forkOnce().argLine( "-Dfile.encoding=UTF-16" ).executeTest(); + + validate( outputValidator, true ); + } + + @Test + public void properNewlinesAndEncodingWithoutFork() + { + final OutputValidator outputValidator = + unpack( "/consoleOutput" ).forkNever().executeTest(); + + validate( outputValidator, false ); + } + + private void validate( final OutputValidator outputValidator, boolean includeShutdownHook ) + { + TestFile xmlReportFile = outputValidator.getSurefireReportsXmlFile( "TEST-consoleOutput.Test1.xml" ); + xmlReportFile.assertContainsText( "SoutLine" ); + xmlReportFile.assertContainsText( "äöüÃ" ); + xmlReportFile.assertContainsText( "failing with ü" ); + + TestFile outputFile = outputValidator.getSurefireReportsFile( "consoleOutput.Test1-output.txt" ); + outputFile.assertContainsText( "SoutAgain" ); + outputFile.assertContainsText( "SoutLine" ); + outputFile.assertContainsText( "äöüÃ" ); + + if ( includeShutdownHook ) + { + outputFile.assertContainsText( "Printline in shutdown hook" ); + } } @Test http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/c26bc4b9/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/fixture/TestFile.java ---------------------------------------------------------------------- diff --git a/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/fixture/TestFile.java b/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/fixture/TestFile.java index 3c76c62..61736df 100644 --- a/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/fixture/TestFile.java +++ b/surefire-integration-tests/src/test/java/org/apache/maven/surefire/its/fixture/TestFile.java @@ -51,7 +51,7 @@ public class TestFile this( file, Charset.defaultCharset(), surefireVerifier); } - public TestFile( File file, Charset charset,OutputValidator surefireVerifier ) + public TestFile( File file, Charset charset, OutputValidator surefireVerifier ) { this.file = file; this.encoding = charset; http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/c26bc4b9/surefire-integration-tests/src/test/resources/consoleOutput/pom.xml ---------------------------------------------------------------------- diff --git a/surefire-integration-tests/src/test/resources/consoleOutput/pom.xml b/surefire-integration-tests/src/test/resources/consoleOutput/pom.xml index b19dbd2..2602eef 100644 --- a/surefire-integration-tests/src/test/resources/consoleOutput/pom.xml +++ b/surefire-integration-tests/src/test/resources/consoleOutput/pom.xml @@ -20,7 +20,7 @@ <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> - <version>${junit.version}</version> + <version>4.7</version> </dependency> </dependencies> <build> @@ -29,23 +29,18 @@ <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <configuration> + <redirectTestOutputToFile>true</redirectTestOutputToFile> + <testFailureIgnore>true</testFailureIgnore> <forkMode>${forkMode}</forkMode> - <printSummary>${printSummary}</printSummary> - <reportFormat>${reportFormat}</reportFormat> <includes> <include>**/Test*.java</include> </includes> </configuration> </plugin> </plugins> - </build> - <properties> - <junit.version>4.8.1</junit.version> - <forkMode>once</forkMode> - <printSummary>true</printSummary> - <reportFormat>brief</reportFormat> - </properties> - + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + </properties> </project> http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/c26bc4b9/surefire-integration-tests/src/test/resources/consoleOutput/src/test/java/consoleOutput/Test1.java ---------------------------------------------------------------------- diff --git a/surefire-integration-tests/src/test/resources/consoleOutput/src/test/java/consoleOutput/Test1.java b/surefire-integration-tests/src/test/resources/consoleOutput/src/test/java/consoleOutput/Test1.java index 2682c6e..8994251 100644 --- a/surefire-integration-tests/src/test/resources/consoleOutput/src/test/java/consoleOutput/Test1.java +++ b/surefire-integration-tests/src/test/resources/consoleOutput/src/test/java/consoleOutput/Test1.java @@ -23,6 +23,8 @@ import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; +import static org.junit.Assert.fail; + public class Test1 { static @@ -47,32 +49,33 @@ public class Test1 public Test1(){ System.out.println("In constructor"); } + @Test - public void testSystemOut() + public void testStdOut() { - char c = 'C'; System.out.print( "Sout" ); System.out.print( "Again" ); System.out.print( "\n" ); System.out.print( c ); System.out.println( "SoutLine" ); - System.out.println( "A" ); + System.out.println( "äöüÃ" ); System.out.println( "" ); System.out.println( "==END==" ); - } + fail( "failing with ü" ); + } + @Test - public void testSystemErr() + public void testStdErr() { char e = 'E'; System.err.print( "Serr" ); System.err.print( "\n" ); System.err.print( e ); System.err.println( "SerrLine" ); - System.err.println( "A" ); + System.err.println( "äöüÃ" ); System.err.println( "" ); System.err.println( "==END==" ); } - }