You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by ti...@apache.org on 2017/08/03 12:48:06 UTC
[2/3] maven-surefire git commit: [SUREFIRE-1222] ForkClient attempts
to consume unrelated lines
http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/64ae8e88/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedChannelDecoderTest.java
----------------------------------------------------------------------
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedChannelDecoderTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedChannelDecoderTest.java
new file mode 100644
index 0000000..06849f0
--- /dev/null
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/output/ForkedChannelDecoderTest.java
@@ -0,0 +1,666 @@
+package org.apache.maven.plugin.surefire.booterclient.output;
+
+/*
+ * 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.surefire.booter.ForkedChannelEncoder;
+import org.apache.maven.surefire.report.ReportEntry;
+import org.apache.maven.surefire.report.RunMode;
+import org.apache.maven.surefire.report.SafeThrowable;
+import org.apache.maven.surefire.report.StackTraceWriter;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.runners.Enclosed;
+import org.junit.experimental.theories.DataPoints;
+import org.junit.experimental.theories.FromDataPoints;
+import org.junit.experimental.theories.Theories;
+import org.junit.experimental.theories.Theory;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.LineNumberReader;
+import java.io.PrintStream;
+import java.io.StringReader;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.util.Arrays;
+import java.util.Map;
+
+import static java.nio.charset.Charset.defaultCharset;
+import static javax.xml.bind.DatatypeConverter.printBase64Binary;
+import static org.apache.maven.plugin.surefire.booterclient.output.ForkedChannelDecoder.toReportEntry;
+import static org.apache.maven.surefire.report.RunMode.NORMAL_RUN;
+import static org.fest.assertions.Assertions.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.junit.rules.ExpectedException.none;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+/**
+ * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
+ * @since 2.20.1
+ */
+@RunWith( Enclosed.class )
+public class ForkedChannelDecoderTest
+{
+ public static class DecoderOperationsTest
+ {
+ @Rule
+ public final ExpectedException rule = none();
+
+ @Test
+ public void shouldBeFailSafe()
+ {
+ Charset encoding = Charset.defaultCharset();
+ assertThat( ForkedChannelDecoder.decode( null, encoding ) ).isNull();
+ assertThat( ForkedChannelDecoder.decode( "-", encoding ) ).isNull();
+ assertThat( ForkedChannelDecoder.decodeToInteger( null ) ).isNull();
+ assertThat( ForkedChannelDecoder.decodeToInteger( "-" ) ).isNull();
+ assertThat( ForkedChannelDecoder.decodeToBytes( null ) ).isNull();
+ assertThat( ForkedChannelDecoder.decodeToBytes( "-" ) ).isNull();
+ }
+
+ @Test
+ public void shouldHaveSystemProperty() throws IOException
+ {
+ Stream out = Stream.newStream();
+ ForkedChannelEncoder forkedChannelEncoder = new ForkedChannelEncoder( defaultCharset(), out );
+ forkedChannelEncoder.sendSystemProperties();
+
+ ForkedChannelDecoder decoder = new ForkedChannelDecoder();
+ decoder.setSystemPropertiesListener( new PropertyEventAssertionListener( NORMAL_RUN ) );
+ LineNumberReader reader = out.newReader( defaultCharset() );
+ for ( String line; ( line = reader.readLine() ) != null; )
+ {
+ decoder.handleEvent( line, new AssertionErrorHandler() );
+ }
+ assertThat( reader.getLineNumber() ).isPositive();
+ }
+
+ @Test
+ public void shouldRecognizeEmptyStream4ReportEntry()
+ {
+ ReportEntry reportEntry = toReportEntry( null, null, "", null, null, "", "", "", null );
+ assertThat( reportEntry ).isNull();
+
+ reportEntry = toReportEntry( defaultCharset(), "", "", "", "", "-", "", "", "" );
+ assertThat( reportEntry ).isNotNull();
+ assertThat( reportEntry.getStackTraceWriter() ).isNull();
+ assertThat( reportEntry.getSourceName() ).isEmpty();
+ assertThat( reportEntry.getName() ).isEmpty();
+ assertThat( reportEntry.getGroup() ).isEmpty();
+ assertThat( reportEntry.getNameWithGroup() ).isEmpty();
+ assertThat( reportEntry.getMessage() ).isEmpty();
+ assertThat( reportEntry.getElapsed() ).isNull();
+
+ rule.expect( NumberFormatException.class );
+ toReportEntry( defaultCharset(), "", "", "", "", "", "", "", "" );
+ fail();
+ }
+
+ @Test
+ public void testCreatingReportEntry()
+ {
+ final Charset utf8 = Charset.forName( "UTF-8" );
+
+ final String exceptionMessage = "msg";
+ final String encodedExceptionMsg = printBase64Binary( toArray( utf8.encode( exceptionMessage ) ) );
+
+ final String smartStackTrace = "MyTest:86 >> Error";
+ final String encodedSmartStackTrace = printBase64Binary( toArray( utf8.encode( smartStackTrace ) ) );
+
+ final String stackTrace = "Exception: msg\ntrace line 1\ntrace line 2";
+ final String encodedStackTrace = printBase64Binary( toArray( utf8.encode( stackTrace ) ) );
+
+ final String trimmedStackTrace = "trace line 1\ntrace line 2";
+ final String encodedTrimmedStackTrace = printBase64Binary( toArray( utf8.encode( trimmedStackTrace ) ) );
+
+ SafeThrowable safeThrowable = new SafeThrowable( exceptionMessage );
+ StackTraceWriter stackTraceWriter = mock( StackTraceWriter.class );
+ when( stackTraceWriter.getThrowable() ).thenReturn( safeThrowable );
+ when( stackTraceWriter.smartTrimmedStackTrace() ).thenReturn( smartStackTrace );
+ when( stackTraceWriter.writeTrimmedTraceToString() ).thenReturn( trimmedStackTrace );
+ when( stackTraceWriter.writeTraceToString() ).thenReturn( stackTrace );
+
+ ReportEntry reportEntry = mock( ReportEntry.class );
+ when( reportEntry.getElapsed() ).thenReturn( 102 );
+ when( reportEntry.getGroup() ).thenReturn( "this group" );
+ when( reportEntry.getMessage() ).thenReturn( "skipped test" );
+ when( reportEntry.getName() ).thenReturn( "my test" );
+ when( reportEntry.getNameWithGroup() ).thenReturn( "name with group" );
+ when( reportEntry.getSourceName() ).thenReturn( "pkg.MyTest" );
+ when( reportEntry.getStackTraceWriter() ).thenReturn( stackTraceWriter );
+
+ String encodedSourceName = printBase64Binary( toArray( utf8.encode( reportEntry.getSourceName() ) ) );
+ String encodedName = printBase64Binary( toArray( utf8.encode( reportEntry.getName() ) ) );
+ String encodedGroup = printBase64Binary( toArray( utf8.encode( reportEntry.getGroup() ) ) );
+ String encodedMessage = printBase64Binary( toArray( utf8.encode( reportEntry.getMessage() ) ) );
+
+ ReportEntry decodedReportEntry = toReportEntry( utf8, encodedSourceName, encodedName, encodedGroup,
+ encodedMessage, "-", null, null, null
+ );
+
+ assertThat( decodedReportEntry ).isNotNull();
+ assertThat( decodedReportEntry.getSourceName() ).isEqualTo( reportEntry.getSourceName() );
+ assertThat( decodedReportEntry.getName() ).isEqualTo( reportEntry.getName() );
+ assertThat( decodedReportEntry.getGroup() ).isEqualTo( reportEntry.getGroup() );
+ assertThat( decodedReportEntry.getMessage() ).isEqualTo( reportEntry.getMessage() );
+ assertThat( decodedReportEntry.getStackTraceWriter() ).isNull();
+
+ decodedReportEntry = toReportEntry( utf8, encodedSourceName, encodedName, encodedGroup, encodedMessage, "-",
+ encodedExceptionMsg, encodedSmartStackTrace, null
+ );
+
+ assertThat( decodedReportEntry ).isNotNull();
+ assertThat( decodedReportEntry.getSourceName() ).isEqualTo( reportEntry.getSourceName() );
+ assertThat( decodedReportEntry.getName() ).isEqualTo( reportEntry.getName() );
+ assertThat( decodedReportEntry.getGroup() ).isEqualTo( reportEntry.getGroup() );
+ assertThat( decodedReportEntry.getMessage() ).isEqualTo( reportEntry.getMessage() );
+ assertThat( decodedReportEntry.getElapsed() ).isNull();
+ assertThat( decodedReportEntry.getStackTraceWriter() ).isNull();
+
+ decodedReportEntry = toReportEntry( utf8, encodedSourceName, encodedName, encodedGroup, encodedMessage,
+ "1003", encodedExceptionMsg, encodedSmartStackTrace, null
+ );
+
+ assertThat( decodedReportEntry ).isNotNull();
+ assertThat( decodedReportEntry.getSourceName() ).isEqualTo( reportEntry.getSourceName() );
+ assertThat( decodedReportEntry.getName() ).isEqualTo( reportEntry.getName() );
+ assertThat( decodedReportEntry.getGroup() ).isEqualTo( reportEntry.getGroup() );
+ assertThat( decodedReportEntry.getMessage() ).isEqualTo( reportEntry.getMessage() );
+ assertThat( decodedReportEntry.getElapsed() ).isEqualTo( 1003 );
+ assertThat( decodedReportEntry.getStackTraceWriter() ).isNull();
+
+ decodedReportEntry = toReportEntry( utf8, encodedSourceName, encodedName, encodedGroup, encodedMessage,
+ "1003", encodedExceptionMsg, encodedSmartStackTrace,
+ encodedStackTrace
+ );
+
+ assertThat( decodedReportEntry ).isNotNull();
+ assertThat( decodedReportEntry.getSourceName() ).isEqualTo( reportEntry.getSourceName() );
+ assertThat( decodedReportEntry.getName() ).isEqualTo( reportEntry.getName() );
+ assertThat( decodedReportEntry.getGroup() ).isEqualTo( reportEntry.getGroup() );
+ assertThat( decodedReportEntry.getMessage() ).isEqualTo( reportEntry.getMessage() );
+ assertThat( decodedReportEntry.getElapsed() ).isEqualTo( 1003 );
+ assertThat( decodedReportEntry.getStackTraceWriter() ).isNotNull();
+ assertThat( decodedReportEntry.getStackTraceWriter().getThrowable().getMessage() ).isNotNull();
+ assertThat( decodedReportEntry.getStackTraceWriter().getThrowable().getMessage() )
+ .isEqualTo( exceptionMessage );
+ assertThat( decodedReportEntry.getStackTraceWriter().smartTrimmedStackTrace() )
+ .isEqualTo( smartStackTrace );
+ assertThat( decodedReportEntry.getStackTraceWriter().writeTraceToString() ).isEqualTo( stackTrace );
+ assertThat( decodedReportEntry.getStackTraceWriter().writeTrimmedTraceToString() ).isEqualTo( stackTrace );
+
+ decodedReportEntry = toReportEntry( utf8, encodedSourceName, encodedName, encodedGroup, encodedMessage,
+ "1003", encodedExceptionMsg, encodedSmartStackTrace,
+ encodedTrimmedStackTrace
+ );
+
+ assertThat( decodedReportEntry ).isNotNull();
+ assertThat( decodedReportEntry.getSourceName() ).isEqualTo( reportEntry.getSourceName() );
+ assertThat( decodedReportEntry.getName() ).isEqualTo( reportEntry.getName() );
+ assertThat( decodedReportEntry.getGroup() ).isEqualTo( reportEntry.getGroup() );
+ assertThat( decodedReportEntry.getMessage() ).isEqualTo( reportEntry.getMessage() );
+ assertThat( decodedReportEntry.getElapsed() ).isEqualTo( 1003 );
+ assertThat( decodedReportEntry.getStackTraceWriter() ).isNotNull();
+ assertThat( decodedReportEntry.getStackTraceWriter().getThrowable().getMessage() ).isNotNull();
+ assertThat( decodedReportEntry.getStackTraceWriter().getThrowable().getMessage() )
+ .isEqualTo( exceptionMessage );
+ assertThat( decodedReportEntry.getStackTraceWriter().smartTrimmedStackTrace() )
+ .isEqualTo( smartStackTrace );
+ assertThat( decodedReportEntry.getStackTraceWriter().writeTraceToString() ).isEqualTo( trimmedStackTrace );
+ assertThat( decodedReportEntry.getStackTraceWriter().writeTrimmedTraceToString() )
+ .isEqualTo( trimmedStackTrace );
+ }
+
+ @Test
+ public void shouldSendByeEvent() throws IOException
+ {
+ Stream out = Stream.newStream();
+ ForkedChannelEncoder forkedChannelEncoder = new ForkedChannelEncoder( defaultCharset(), out );
+ forkedChannelEncoder.bye();
+ String read = new String( out.toByteArray(), defaultCharset() );
+ assertThat( read )
+ .isEqualTo( ":maven:surefire:std:out:bye:normal-run\n" );
+ LineNumberReader lines = out.newReader( defaultCharset() );
+ ForkedChannelDecoder decoder = new ForkedChannelDecoder();
+ decoder.setByeListener( new EventAssertionListener( NORMAL_RUN ) );
+ decoder.handleEvent( lines.readLine(), new AssertionErrorHandler() );
+ assertThat( lines.readLine() )
+ .isNull();
+ }
+
+ @Test
+ public void shouldSendStopOnNextTestEvent() throws IOException
+ {
+
+ Stream out = Stream.newStream();
+ ForkedChannelEncoder forkedChannelEncoder = new ForkedChannelEncoder( defaultCharset(), out );
+ forkedChannelEncoder.stopOnNextTest();
+ String read = new String( out.toByteArray(), defaultCharset() );
+ assertThat( read )
+ .isEqualTo( ":maven:surefire:std:out:stopOnNextTest:normal-run\n" );
+ LineNumberReader lines = out.newReader( defaultCharset() );
+ ForkedChannelDecoder decoder = new ForkedChannelDecoder();
+ decoder.setStopOnNextTestListener( new EventAssertionListener( NORMAL_RUN ) );
+ decoder.handleEvent( lines.readLine(), new AssertionErrorHandler() );
+ assertThat( lines.readLine() )
+ .isNull();
+ }
+
+ @Test
+ public void shouldSendNextTestEvent() throws IOException
+ {
+
+ Stream out = Stream.newStream();
+ ForkedChannelEncoder forkedChannelEncoder = new ForkedChannelEncoder( defaultCharset(), out );
+ forkedChannelEncoder.acquireNextTest();
+ String read = new String( out.toByteArray(), defaultCharset() );
+ assertThat( read )
+ .isEqualTo( ":maven:surefire:std:out:nextTest:normal-run\n" );
+ LineNumberReader lines = out.newReader( defaultCharset() );
+ ForkedChannelDecoder decoder = new ForkedChannelDecoder();
+ decoder.setAcquireNextTestListener( new EventAssertionListener( NORMAL_RUN ) );
+ decoder.handleEvent( lines.readLine(), new AssertionErrorHandler() );
+ assertThat( lines.readLine() )
+ .isNull();
+ }
+
+ @Test
+ public void testConsole() throws IOException
+ {
+ Stream out = Stream.newStream();
+
+ ForkedChannelEncoder forkedChannelEncoder = new ForkedChannelEncoder( defaultCharset(), out );
+ forkedChannelEncoder.console( "msg" );
+
+ LineNumberReader lines = out.newReader( defaultCharset() );
+ ForkedChannelDecoder decoder = new ForkedChannelDecoder();
+ decoder.setConsoleInfoListener( new StringEventAssertionListener( "msg" ) );
+ decoder.handleEvent( lines.readLine(), new AssertionErrorHandler() );
+ assertThat( lines.readLine() )
+ .isNull();
+ }
+
+ @Test
+ public void testError() throws IOException
+ {
+ Stream out = Stream.newStream();
+
+ ForkedChannelEncoder forkedChannelEncoder = new ForkedChannelEncoder( defaultCharset(), out );
+ forkedChannelEncoder.error( "msg" );
+
+ LineNumberReader lines = out.newReader( defaultCharset() );
+ ForkedChannelDecoder decoder = new ForkedChannelDecoder();
+ decoder.setConsoleErrorListener( new StackTraceEventListener( "msg", "stack trace" ) );
+ decoder.handleEvent( lines.readLine(), new AssertionErrorHandler() );
+ assertThat( lines.readLine() )
+ .isNull();
+ }
+
+ @Test
+ public void testDebug() throws IOException
+ {
+ Stream out = Stream.newStream();
+
+ ForkedChannelEncoder forkedChannelEncoder = new ForkedChannelEncoder( defaultCharset(), out );
+ forkedChannelEncoder.debug( "msg" );
+
+ LineNumberReader lines = out.newReader( defaultCharset() );
+ ForkedChannelDecoder decoder = new ForkedChannelDecoder();
+ decoder.setConsoleDebugListener( new StringEventAssertionListener( "msg" ) );
+ decoder.handleEvent( lines.readLine(), new AssertionErrorHandler() );
+ assertThat( lines.readLine() )
+ .isNull();
+ }
+
+ @Test
+ public void testWarning() throws IOException
+ {
+ Stream out = Stream.newStream();
+
+ ForkedChannelEncoder forkedChannelEncoder = new ForkedChannelEncoder( defaultCharset(), out );
+ forkedChannelEncoder.warning( "msg" );
+
+ LineNumberReader lines = out.newReader( defaultCharset() );
+ ForkedChannelDecoder decoder = new ForkedChannelDecoder();
+ decoder.setConsoleWarningListener( new StringEventAssertionListener( "msg" ) );
+ decoder.handleEvent( lines.readLine(), new AssertionErrorHandler() );
+ assertThat( lines.readLine() )
+ .isNull();
+ }
+
+ @Test
+ public void testStdOutStream() throws IOException
+ {
+ Charset streamEncoding = Charset.forName( "UTF-8" );
+ Stream out = Stream.newStream();
+ ForkedChannelEncoder forkedChannelEncoder = new ForkedChannelEncoder( streamEncoding, out );
+
+ final Charset encoding = defaultCharset();
+ byte[] msgArray = toArray( encoding.encode( "msg" ) );
+ assertThat( encoding.decode( ByteBuffer.wrap( msgArray ) ).toString() ).isEqualTo( "msg" );
+ forkedChannelEncoder.stdOut( msgArray, 0, msgArray.length );
+
+ LineNumberReader printedLines = out.newReader( defaultCharset() );
+ ForkedChannelDecoder decoder = new ForkedChannelDecoder();
+ decoder.setStdOutListener( new BinaryEventAssertionListener( NORMAL_RUN, encoding,
+ "msg".getBytes( encoding )
+ )
+ );
+ decoder.handleEvent( printedLines.readLine(), new AssertionErrorHandler() );
+ assertThat( printedLines.readLine() )
+ .isNull();
+ }
+
+ @Test
+ public void testStdErrStream() throws IOException
+ {
+ Charset streamEncoding = Charset.forName( "ISO-8859-1" );
+ Stream out = Stream.newStream();
+ ForkedChannelEncoder forkedChannelEncoder = new ForkedChannelEncoder( streamEncoding, out );
+
+ final Charset encoding = defaultCharset();
+ byte[] msgArray = toArray( encoding.encode( "msg" ) );
+ assertThat( encoding.decode( ByteBuffer.wrap( msgArray ) ).toString() ).isEqualTo( "msg" );
+ forkedChannelEncoder.stdErr( msgArray, 0, msgArray.length );
+
+ LineNumberReader printedLines = out.newReader( defaultCharset() );
+ ForkedChannelDecoder decoder = new ForkedChannelDecoder();
+ decoder.setStdErrListener( new BinaryEventAssertionListener( NORMAL_RUN, encoding,
+ "msg".getBytes( encoding )
+ )
+ );
+ decoder.handleEvent( printedLines.readLine(), new AssertionErrorHandler() );
+ assertThat( printedLines.readLine() )
+ .isNull();
+ }
+
+ @Test
+ public void shouldCountSameNumberOfSystemProperties() throws IOException
+ {
+ Stream out = Stream.newStream();
+
+ Charset streamEncoding = Charset.forName( "ISO-8859-1" );
+ ForkedChannelEncoder forkedChannelEncoder = new ForkedChannelEncoder( streamEncoding, out );
+ forkedChannelEncoder.sendSystemProperties();
+
+ LineNumberReader printedLines = out.newReader( streamEncoding );
+ ForkedChannelDecoder decoder = new ForkedChannelDecoder();
+ decoder.setSystemPropertiesListener( new PropertyEventAssertionListener( NORMAL_RUN ) );
+ decoder.handleEvent( printedLines.readLine(), new AssertionErrorHandler() );
+ }
+ }
+
+ @RunWith( Theories.class )
+ public static class ReportEntryTest
+ {
+ @DataPoints( value = "operation" )
+ public static String[][] operations = { { "testSetStarting", "setTestSetStartingListener" },
+ { "testSetCompleted", "setTestSetCompletedListener" },
+ { "testStarting", "setTestStartingListener" },
+ { "testSucceeded", "setTestSucceededListener" },
+ { "testFailed", "setTestFailedListener" },
+ { "testSkipped", "setTestSkippedListener" },
+ { "testError", "setTestErrorListener" },
+ { "testAssumptionFailure", "setTestAssumptionFailureListener" }
+ };
+
+ @DataPoints( value = "reportedMessage" )
+ public static String[] reportedMessage = { null, "skipped test" };
+
+ @DataPoints( value = "elapsed" )
+ public static Integer[] elapsed = { null, 102 };
+
+ @DataPoints( value = "trim" )
+ public static boolean[] trim = { false, true };
+
+ @DataPoints( value = "msg" )
+ public static boolean[] msg = { false, true };
+
+ @DataPoints( value = "smart" )
+ public static boolean[] smart = { false, true };
+
+ @DataPoints( value = "trace" )
+ public static boolean[] trace = { false, true };
+
+ @Theory
+ public void testReportEntryOperations( @FromDataPoints( "operation" ) String[] operation,
+ @FromDataPoints( "reportedMessage" ) String reportedMessage,
+ @FromDataPoints( "elapsed" ) Integer elapsed,
+ @FromDataPoints( "trim" ) boolean trim,
+ @FromDataPoints( "msg" ) boolean msg,
+ @FromDataPoints( "smart" ) boolean smart,
+ @FromDataPoints( "trace" ) boolean trace )
+ throws Exception
+ {
+ String exceptionMessage = msg ? "msg" : null;
+ String smartStackTrace = smart ? "MyTest:86 >> Error" : null;
+ String exceptionStackTrace =
+ trace ? ( trim ? "trace line 1\ntrace line 2" : "Exception: msg\ntrace line 1\ntrace line 2" )
+ : null;
+
+ StackTraceWriter stackTraceWriter = null;
+ if ( exceptionStackTrace != null )
+ {
+ SafeThrowable safeThrowable = new SafeThrowable( exceptionMessage );
+ stackTraceWriter = mock( StackTraceWriter.class );
+ when( stackTraceWriter.getThrowable() ).thenReturn( safeThrowable );
+ when( stackTraceWriter.smartTrimmedStackTrace() ).thenReturn( smartStackTrace );
+ when( stackTraceWriter.writeTrimmedTraceToString() ).thenReturn( exceptionStackTrace );
+ when( stackTraceWriter.writeTraceToString() ).thenReturn( exceptionStackTrace );
+ }
+
+ ReportEntry reportEntry = mock( ReportEntry.class );
+ when( reportEntry.getElapsed() ).thenReturn( elapsed );
+ when( reportEntry.getGroup() ).thenReturn( "this group" );
+ when( reportEntry.getMessage() ).thenReturn( reportedMessage );
+ when( reportEntry.getName() ).thenReturn( "my test" );
+ when( reportEntry.getNameWithGroup() ).thenReturn( "name with group" );
+ when( reportEntry.getSourceName() ).thenReturn( "pkg.MyTest" );
+ when( reportEntry.getStackTraceWriter() ).thenReturn( stackTraceWriter );
+
+ Stream out = Stream.newStream();
+
+ ForkedChannelEncoder forkedChannelEncoder = new ForkedChannelEncoder( defaultCharset(), out );
+
+ ForkedChannelEncoder.class.getMethod( operation[0], ReportEntry.class, boolean.class )
+ .invoke( forkedChannelEncoder, reportEntry, trim );
+
+ ForkedChannelDecoder forkedChannelDecoder = new ForkedChannelDecoder();
+
+ ForkedChannelDecoder.class.getMethod( operation[1], ForkedProcessReportEventListener.class )
+ .invoke( forkedChannelDecoder, new ReportEventAssertionListener( reportEntry ) );
+
+ forkedChannelDecoder.handleEvent( out.newReader( defaultCharset() ).readLine(),
+ new AssertionErrorHandler()
+ );
+ }
+ }
+
+ private static class AssertionErrorHandler implements ForkedChannelDecoderErrorHandler
+ {
+ public void handledError( String line, Throwable e )
+ {
+ if ( e != null )
+ {
+ e.printStackTrace();
+ }
+ fail( line + ( e == null ? "" : "\n" + e.getLocalizedMessage() ) );
+ }
+ }
+
+ private static class PropertyEventAssertionListener implements ForkedProcessPropertyEventListener
+ {
+ private final Map sysProps = System.getProperties();
+ private final RunMode runMode;
+
+ PropertyEventAssertionListener( RunMode runMode )
+ {
+ this.runMode = runMode;
+ }
+
+ public void handle( String key, String value )
+ {
+ assertTrue( sysProps.containsKey( key ) );
+ assertThat( sysProps.get( key ) ).isEqualTo( value );
+ }
+ }
+
+ private static class EventAssertionListener implements ForkedProcessEventListener
+ {
+ public void handle()
+ {
+ }
+ }
+
+ private static class StringEventAssertionListener implements ForkedProcessStringEventListener
+ {
+ private final String msg;
+
+ StringEventAssertionListener( String msg )
+ {
+ this.msg = msg;
+ }
+
+ public void handle( String msg )
+ {
+ assertThat( msg )
+ .isEqualTo( this.msg );
+ }
+ }
+
+ private static class StackTraceEventListener implements ForkedProcessStackTraceEventListener
+ {
+ private final String msg;
+ private final String stackTrace;
+
+ StackTraceEventListener( String msg, String stackTrace )
+ {
+ this.msg = msg;
+ this.stackTrace = stackTrace;
+ }
+
+ @Override
+ public void handle( String msg, String stackTrace )
+ {
+ assertThat( msg )
+ .isEqualTo( this.msg );
+
+ assertThat( stackTrace )
+ .isEqualTo( this.stackTrace );
+ }
+ }
+
+ private static class BinaryEventAssertionListener implements ForkedProcessBinaryEventListener
+ {
+ private final RunMode runMode;
+ private final Charset encoding;
+ private final byte[] binary;
+
+ BinaryEventAssertionListener( RunMode runMode, Charset encoding, byte[] binary )
+ {
+ this.runMode = runMode;
+ this.encoding = encoding;
+ this.binary = binary;
+ }
+
+ public void handle( RunMode runMode, Charset encoding, byte[] binary )
+ {
+ assertThat( runMode )
+ .isEqualTo( this.runMode );
+
+ assertThat( encoding )
+ .isEqualTo( this.encoding );
+
+ assertThat( binary )
+ .isEqualTo( this.binary );
+ }
+ }
+
+ private static class ReportEventAssertionListener implements ForkedProcessReportEventListener
+ {
+ private final ReportEntry reportEntry;
+
+ ReportEventAssertionListener( ReportEntry reportEntry )
+ {
+ this.reportEntry = reportEntry;
+ }
+
+ public void handle( RunMode runMode, ReportEntry reportEntry )
+ {
+ assertThat( reportEntry.getSourceName() ).isEqualTo( this.reportEntry.getSourceName() );
+ assertThat( reportEntry.getName() ).isEqualTo( this.reportEntry.getName() );
+ assertThat( reportEntry.getGroup() ).isEqualTo( this.reportEntry.getGroup() );
+ assertThat( reportEntry.getMessage() ).isEqualTo( this.reportEntry.getMessage() );
+ assertThat( reportEntry.getElapsed() ).isEqualTo( this.reportEntry.getElapsed() );
+ if ( reportEntry.getStackTraceWriter() == null )
+ {
+ assertThat( this.reportEntry.getStackTraceWriter() ).isNull();
+ }
+ else
+ {
+ assertThat( this.reportEntry.getStackTraceWriter() ).isNotNull();
+
+ assertThat( reportEntry.getStackTraceWriter().getThrowable().getMessage() )
+ .isEqualTo( this.reportEntry.getStackTraceWriter().getThrowable().getMessage() );
+
+ assertThat( reportEntry.getStackTraceWriter().getThrowable().getLocalizedMessage() )
+ .isEqualTo( this.reportEntry.getStackTraceWriter().getThrowable().getLocalizedMessage() );
+
+ assertThat( reportEntry.getStackTraceWriter().smartTrimmedStackTrace() )
+ .isEqualTo( this.reportEntry.getStackTraceWriter().smartTrimmedStackTrace() );
+ }
+ }
+ }
+
+ private static class Stream extends PrintStream
+ {
+ private final ByteArrayOutputStream out;
+
+ public Stream( ByteArrayOutputStream out )
+ {
+ super( out, true );
+ this.out = out;
+ }
+
+ byte[] toByteArray()
+ {
+ return out.toByteArray();
+ }
+
+ LineNumberReader newReader( Charset streamCharset )
+ {
+ return new LineNumberReader( new StringReader( new String( toByteArray(), streamCharset ) ) );
+ }
+
+ static Stream newStream()
+ {
+ return new Stream( new ByteArrayOutputStream() );
+ }
+ }
+
+ private static byte[] toArray( ByteBuffer buffer )
+ {
+ return Arrays.copyOfRange( buffer.array(), buffer.arrayOffset(), buffer.arrayOffset() + buffer.remaining() );
+ }
+}
http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/64ae8e88/maven-surefire-common/src/test/java/org/apache/maven/surefire/JUnit4SuiteTest.java
----------------------------------------------------------------------
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 9fb45bf..0c92635 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
@@ -30,6 +30,7 @@ import org.apache.maven.plugin.surefire.booterclient.ForkConfigurationTest;
import org.apache.maven.plugin.surefire.booterclient.ForkingRunListenerTest;
import org.apache.maven.plugin.surefire.booterclient.lazytestprovider.TestLessInputStreamBuilderTest;
import org.apache.maven.plugin.surefire.booterclient.lazytestprovider.TestProvidingInputStreamTest;
+import org.apache.maven.plugin.surefire.booterclient.output.ForkClientTest;
import org.apache.maven.plugin.surefire.report.DefaultReporterFactoryTest;
import org.apache.maven.plugin.surefire.report.StatelessXmlReporterTest;
import org.apache.maven.plugin.surefire.report.WrappedReportEntryTest;
@@ -75,6 +76,7 @@ import org.junit.runners.Suite;
SurefireReflectorTest.class,
ImmutableMapTest.class,
SurefireHelperTest.class,
+ ForkClientTest.class
} )
@RunWith( Suite.class )
public class JUnit4SuiteTest
http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/64ae8e88/surefire-api/pom.xml
----------------------------------------------------------------------
diff --git a/surefire-api/pom.xml b/surefire-api/pom.xml
index 5f0f2fd..b705e0a 100644
--- a/surefire-api/pom.xml
+++ b/surefire-api/pom.xml
@@ -40,6 +40,11 @@
<groupId>org.apache.maven.shared</groupId>
<artifactId>maven-shared-utils</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-core</artifactId>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<build>
http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/64ae8e88/surefire-api/src/main/java/org/apache/maven/surefire/booter/BaseProviderFactory.java
----------------------------------------------------------------------
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/BaseProviderFactory.java b/surefire-api/src/main/java/org/apache/maven/surefire/booter/BaseProviderFactory.java
index 2a713ef..a794255 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/BaseProviderFactory.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/booter/BaseProviderFactory.java
@@ -136,7 +136,8 @@ public class BaseProviderFactory
{
boolean trim = reporterConfiguration.isTrimStackTrace();
PrintStream out = reporterConfiguration.getOriginalSystemOut();
- return insideFork ? new ForkingRunListener( out, ROOT_CHANNEL, trim ) : new DefaultDirectConsoleReporter( out );
+ return insideFork ? new ForkingRunListener( new ForkedChannelEncoder( out ), ROOT_CHANNEL, trim )
+ : new DefaultDirectConsoleReporter( out );
}
public void setTestRequest( TestRequest testRequest )
http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/64ae8e88/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkedChannelEncoder.java
----------------------------------------------------------------------
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkedChannelEncoder.java b/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkedChannelEncoder.java
new file mode 100644
index 0000000..f63fd7e
--- /dev/null
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkedChannelEncoder.java
@@ -0,0 +1,432 @@
+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 org.apache.maven.plugin.surefire.log.api.ConsoleLoggerUtils;
+import org.apache.maven.surefire.report.ReportEntry;
+import org.apache.maven.surefire.report.RunMode;
+import org.apache.maven.surefire.report.SafeThrowable;
+import org.apache.maven.surefire.report.StackTraceWriter;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.charset.Charset;
+import java.util.Map.Entry;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import static java.lang.System.arraycopy;
+import static javax.xml.bind.DatatypeConverter.printBase64Binary;
+import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_BYE;
+import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_CONSOLE_INFO;
+import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_CONSOLE_DEBUG;
+import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_CONSOLE_ERROR;
+import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_NEXT_TEST;
+import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_STDERR;
+import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_STDOUT;
+import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_STOP_ON_NEXT_TEST;
+import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_SYSPROPS;
+import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_TESTSET_COMPLETED;
+import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_TESTSET_STARTING;
+import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_TEST_ASSUMPTIONFAILURE;
+import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_TEST_ERROR;
+import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_TEST_FAILED;
+import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_TEST_SKIPPED;
+import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_TEST_STARTING;
+import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_TEST_SUCCEEDED;
+import static org.apache.maven.surefire.booter.ForkedProcessEvent.BOOTERCODE_CONSOLE_WARNING;
+import static org.apache.maven.surefire.booter.ForkedProcessEvent.MAGIC_NUMBER;
+import static org.apache.maven.surefire.report.RunMode.NORMAL_RUN;
+import static org.apache.maven.surefire.report.RunMode.RERUN;
+import static org.apache.maven.surefire.util.internal.ObjectUtils.requireNonNull;
+
+/**
+ * magic number : opcode : run mode [: opcode specific data]*
+ * <p/>
+ *
+ * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
+ * @since 2.20.1
+ */
+public final class ForkedChannelEncoder
+{
+ private static final Charset ASCII = Charset.forName( "US-ASCII" );
+ private static final Charset UTF_8 = Charset.forName( "UTF-8" );
+
+ private final Charset defaultCharset = Charset.defaultCharset();
+ private final Charset streamCharset;
+ private final OutputStream out;
+ private final RunMode runMode;
+ private boolean trouble;
+
+ public ForkedChannelEncoder( OutputStream out )
+ {
+ this( ASCII, out, NORMAL_RUN );
+ }
+
+ public ForkedChannelEncoder( Charset streamCharset, OutputStream out )
+ {
+ this( streamCharset, out, NORMAL_RUN );
+ }
+
+ private ForkedChannelEncoder( Charset streamCharset, OutputStream out, RunMode runMode )
+ {
+ this.streamCharset = requireNonNull( streamCharset );
+ this.out = requireNonNull( out );
+ this.runMode = requireNonNull( runMode );
+ }
+
+ public ForkedChannelEncoder asRerunMode()
+ {
+ return new ForkedChannelEncoder( streamCharset, out, RERUN );
+ }
+
+ public ForkedChannelEncoder asNormalMode()
+ {
+ return new ForkedChannelEncoder( streamCharset, out, NORMAL_RUN );
+ }
+
+ public boolean checkError()
+ {
+ return trouble;
+ }
+
+ public void sendSystemProperties()
+ {
+ SortedMap<String, String> sortedProperties = new TreeMap<String, String>();
+ for ( Entry<?, ?> entry : System.getProperties().entrySet() )
+ {
+ Object key = entry.getKey();
+ Object value = entry.getValue();
+ if ( key instanceof String && ( value == null || value instanceof String ) )
+ {
+ sortedProperties.put( (String) key, (String) value );
+ }
+ }
+
+ for ( Entry<String, String> entry : sortedProperties.entrySet() )
+ {
+ String key = entry.getKey();
+ Object value = entry.getValue();
+ String valueAsString = value == null ? null : value.toString();
+ StringBuilder event = encode( BOOTERCODE_SYSPROPS, runMode, key, valueAsString );
+ encodeAndPrintEvent( event );
+ }
+ }
+
+ public void testSetStarting( ReportEntry reportEntry, boolean trimStackTraces )
+ {
+ encode( BOOTERCODE_TESTSET_STARTING, runMode, reportEntry, trimStackTraces );
+ }
+
+ public void testSetCompleted( ReportEntry reportEntry, boolean trimStackTraces )
+ {
+ encode( BOOTERCODE_TESTSET_COMPLETED, runMode, reportEntry, trimStackTraces );
+ }
+
+ public void testStarting( ReportEntry reportEntry, boolean trimStackTraces )
+ {
+ encode( BOOTERCODE_TEST_STARTING, runMode, reportEntry, trimStackTraces );
+ }
+
+ public void testSucceeded( ReportEntry reportEntry, boolean trimStackTraces )
+ {
+ encode( BOOTERCODE_TEST_SUCCEEDED, runMode, reportEntry, trimStackTraces );
+ }
+
+ public void testFailed( ReportEntry reportEntry, boolean trimStackTraces )
+ {
+ encode( BOOTERCODE_TEST_FAILED, runMode, reportEntry, trimStackTraces );
+ }
+
+ public void testSkipped( ReportEntry reportEntry, boolean trimStackTraces )
+ {
+ encode( BOOTERCODE_TEST_SKIPPED, runMode, reportEntry, trimStackTraces );
+ }
+
+ public void testError( ReportEntry reportEntry, boolean trimStackTraces )
+ {
+ encode( BOOTERCODE_TEST_ERROR, runMode, reportEntry, trimStackTraces );
+ }
+
+ public void testAssumptionFailure( ReportEntry reportEntry, boolean trimStackTraces )
+ {
+ encode( BOOTERCODE_TEST_ASSUMPTIONFAILURE, runMode, reportEntry, trimStackTraces );
+ }
+
+ public void stdOut( byte[] buf, int off, int len )
+ {
+ StringBuilder event =
+ stdOutErr( BOOTERCODE_STDOUT.getOpcode(), runMode.geRunName(), buf, off, len, defaultCharset );
+ encodeAndPrintEvent( event );
+ }
+
+ public void stdErr( byte[] buf, int off, int len )
+ {
+ StringBuilder event =
+ stdOutErr( BOOTERCODE_STDERR.getOpcode(), runMode.geRunName(), buf, off, len, defaultCharset );
+ encodeAndPrintEvent( event );
+ }
+
+ public void console( String msg )
+ {
+ StringBuilder event = print( BOOTERCODE_CONSOLE_INFO.getOpcode(), runMode.geRunName(), UTF_8, msg );
+ encodeAndPrintEvent( event );
+ }
+
+ public void error( String msg )
+ {
+ StringBuilder event = print( BOOTERCODE_CONSOLE_ERROR.getOpcode(), runMode.geRunName(), UTF_8, msg );
+ encodeAndPrintEvent( event );
+ }
+
+ public void error( Throwable t )
+ {
+ error( t.getLocalizedMessage(), ConsoleLoggerUtils.toString( t ) );
+ }
+
+ public void error( String msg, String stackTrace )
+ {
+ StringBuilder event = print( BOOTERCODE_CONSOLE_ERROR.getOpcode(), runMode.geRunName(), UTF_8, msg, stackTrace );
+ encodeAndPrintEvent( event );
+ }
+
+ public void debug( String msg )
+ {
+ StringBuilder event = print( BOOTERCODE_CONSOLE_DEBUG.getOpcode(), runMode.geRunName(), UTF_8, msg );
+ encodeAndPrintEvent( event );
+ }
+
+ public void warning( String msg )
+ {
+ StringBuilder event = print( BOOTERCODE_CONSOLE_WARNING.getOpcode(), runMode.geRunName(), UTF_8, msg );
+ encodeAndPrintEvent( event );
+ }
+
+ public void bye()
+ {
+ encodeOpcode( BOOTERCODE_BYE );
+ }
+
+ public void stopOnNextTest()
+ {
+ encodeOpcode( BOOTERCODE_STOP_ON_NEXT_TEST );
+ }
+
+ public void acquireNextTest()
+ {
+ encodeOpcode( BOOTERCODE_NEXT_TEST );
+ }
+
+ private void encode( ForkedProcessEvent operation, RunMode runMode, ReportEntry reportEntry,
+ boolean trimStackTraces )
+ {
+ StringBuilder event = encode( operation.getOpcode(), runMode.geRunName(), reportEntry, trimStackTraces );
+ encodeAndPrintEvent( event );
+ }
+
+ private void encodeOpcode( ForkedProcessEvent operation )
+ {
+ StringBuilder event = encodeOpcode( operation.getOpcode(), runMode.geRunName() );
+ encodeAndPrintEvent( event );
+ }
+
+ private void encodeAndPrintEvent( StringBuilder command )
+ {
+ byte[] array = command.append( '\n' ).toString().getBytes( streamCharset );
+ synchronized ( out )
+ {
+ try
+ {
+ out.write( array );
+ out.flush();
+ }
+ catch ( IOException e )
+ {
+ // todo loguj do dum filu pozri ForkingRunListener
+ trouble = true;
+ }
+ }
+ }
+
+ static StringBuilder encode( ForkedProcessEvent operation, RunMode runMode, String... args )
+ {
+ StringBuilder encodedTo = encodeHeader( operation.getOpcode(), runMode.geRunName(), UTF_8 )
+ .append( ':' );
+
+ for ( int i = 0; i < args.length; )
+ {
+ String arg = args[i++];
+ base64WithUtf8( encodedTo, arg == null ? "-" : arg );
+ if ( i != args.length )
+ {
+ encodedTo.append( ':' );
+ }
+ }
+ return encodedTo;
+ }
+
+ static void encode( StringBuilder encoded, StackTraceWriter stw, boolean trimStackTraces )
+ {
+ encoded.append( ':' );
+
+ SafeThrowable throwable = stw == null ? null : stw.getThrowable();
+ String message = throwable == null ? null : throwable.getLocalizedMessage();
+ base64WithUtf8( encoded, message );
+
+ encoded.append( ':' );
+
+ String smartStackTrace = stw == null ? null : stw.smartTrimmedStackTrace();
+ base64WithUtf8( encoded, smartStackTrace );
+
+ encoded.append( ':' );
+
+ String stackTrace = stw == null ? null : toStackTrace( stw, trimStackTraces );
+ base64WithUtf8( encoded, stackTrace );
+ }
+
+ /**
+ * Used operations:<br/>
+ * <p>
+ * <ul>
+ * <li>{@link ForkedProcessEvent#BOOTERCODE_TESTSET_STARTING},</li>
+ * <li>{@link ForkedProcessEvent#BOOTERCODE_TESTSET_COMPLETED},</li>
+ * <li>{@link ForkedProcessEvent#BOOTERCODE_TEST_STARTING},</li>
+ * <li>{@link ForkedProcessEvent#BOOTERCODE_TEST_SUCCEEDED},</li>
+ * <li>{@link ForkedProcessEvent#BOOTERCODE_TEST_FAILED},</li>
+ * <li>{@link ForkedProcessEvent#BOOTERCODE_TEST_ERROR},</li>
+ * <li>{@link ForkedProcessEvent#BOOTERCODE_TEST_SKIPPED},</li>
+ * <li>{@link ForkedProcessEvent#BOOTERCODE_TEST_ASSUMPTIONFAILURE}.</li>
+ * </ul>
+ * </p>
+ */
+ static StringBuilder encode( String operation, String runMode, ReportEntry reportEntry, boolean trimStackTraces )
+ {
+ StringBuilder encodedTo = encodeHeader( operation, runMode, UTF_8 )
+ .append( ':' );
+
+ base64WithUtf8( encodedTo, reportEntry.getSourceName() );
+ encodedTo.append( ':' );
+ base64WithUtf8( encodedTo, reportEntry.getName() );
+ encodedTo.append( ':' );
+ base64WithUtf8( encodedTo, reportEntry.getGroup() );
+ encodedTo.append( ':' );
+ base64WithUtf8( encodedTo, reportEntry.getMessage() );
+ encodedTo.append( ':' )
+ .append( reportEntry.getElapsed() == null ? "-" : reportEntry.getElapsed().toString() );
+ encode( encodedTo, reportEntry.getStackTraceWriter(), trimStackTraces );
+
+ return encodedTo;
+ }
+
+ static StringBuilder stdOutErr( String operation, String runMode, byte[] buf, int off, int len,
+ Charset bufEncoding )
+ {
+ final byte[] encodeBytes;
+ if ( off == 0 && buf.length == len )
+ {
+ encodeBytes = buf;
+ }
+ else
+ {
+ encodeBytes = new byte[len];
+ arraycopy( buf, off, encodeBytes, 0, len );
+ }
+ return encodeMessage( operation, runMode, bufEncoding, printBase64Binary( encodeBytes ) );
+ }
+
+ /**
+ * Used in {@link #console(String)}, {@link #error(String)}, {@link #debug(String)} and {@link #warning(String)}
+ * and private methods extending the buffer.
+ */
+ static StringBuilder print( String operation, String runMode, Charset msgEncoding, String... msgs )
+ {
+ String[] encodedMsgs = new String[msgs.length];
+ for ( int i = 0; i < encodedMsgs.length; i++ )
+ {
+ String msg = encodedMsgs[i];
+ encodedMsgs[i] = toBase64( msg, msgEncoding );
+ }
+ return encodeMessage( operation, runMode, msgEncoding, encodedMsgs );
+ }
+
+ static StringBuilder encodeMessage( String operation, String runMode, Charset encoding, String... msgs )
+ {
+ StringBuilder builder = encodeHeader( operation, runMode, encoding );
+ for ( String msg : msgs )
+ {
+ builder.append( ':' )
+ .append( msg );
+
+ }
+ return builder;
+ }
+
+ static StringBuilder encodeHeader( String operation, String runMode, Charset encoding )
+ {
+ return encodeOpcode( operation, runMode )
+ .append( ':' )
+ .append( encoding.name() );
+ }
+
+ /**
+ * Used in {@link #bye()}, {@link #stopOnNextTest()} and {@link #encodeOpcode(ForkedProcessEvent)}
+ * and private methods extending the buffer.
+ *
+ * @param operation opcode
+ * @param runMode run mode
+ * @return encoded command
+ */
+ static StringBuilder encodeOpcode( String operation, String runMode )
+ {
+ return new StringBuilder( 128 )
+ .append( MAGIC_NUMBER )
+ .append( operation )
+ .append( ':' )
+ .append( runMode );
+ }
+
+ static String base64WithUtf8( String msg )
+ {
+ if ( msg == null )
+ {
+ return "-";
+ }
+ else
+ {
+ byte[] binary = msg.getBytes( UTF_8 );
+ return printBase64Binary( binary );
+ }
+ }
+
+ static void base64WithUtf8( StringBuilder encoded, String msg )
+ {
+ encoded.append( base64WithUtf8( msg ) );
+ }
+
+ private static String toStackTrace( StackTraceWriter stw, boolean trimStackTraces )
+ {
+ return trimStackTraces ? stw.writeTrimmedTraceToString() : stw.writeTraceToString();
+ }
+
+ static String toBase64( String msg, Charset encoding )
+ {
+ return msg == null ? "-" : printBase64Binary( msg.getBytes( encoding ) );
+ }
+}
http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/64ae8e88/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkedProcessEvent.java
----------------------------------------------------------------------
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkedProcessEvent.java b/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkedProcessEvent.java
new file mode 100644
index 0000000..229367e
--- /dev/null
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkedProcessEvent.java
@@ -0,0 +1,123 @@
+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.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import static java.util.Collections.unmodifiableMap;
+
+/**
+ * Events sent back to the plugin process.
+ *
+ * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
+ * @since 2.20.1
+ */
+public enum ForkedProcessEvent
+{
+ BOOTERCODE_SYSPROPS( "sysProp", 0 ),
+
+ BOOTERCODE_TESTSET_STARTING( "testSetStarting", 1 ),
+ BOOTERCODE_TESTSET_COMPLETED( "testSetCompleted", 1 ),
+ BOOTERCODE_TEST_STARTING( "testStarting", 1 ),
+ BOOTERCODE_TEST_SUCCEEDED( "testSucceeded", 1 ),
+ BOOTERCODE_TEST_FAILED( "testFailed", 1 ),
+ BOOTERCODE_TEST_SKIPPED( "testSkipped", 1 ),
+ BOOTERCODE_TEST_ERROR( "testError", 1 ),
+ BOOTERCODE_TEST_ASSUMPTIONFAILURE( "testAssumptionFailure", 1 ),
+
+ BOOTERCODE_STDOUT( "stdOutStream", 2 ),
+ BOOTERCODE_STDERR( "stdErrStream", 2 ),
+
+ BOOTERCODE_CONSOLE_INFO( "console", 3 ),
+ BOOTERCODE_CONSOLE_DEBUG( "debug", 3 ),
+ BOOTERCODE_CONSOLE_WARNING( "warning", 3 ),
+ BOOTERCODE_CONSOLE_ERROR( "error", 4 ),
+
+ BOOTERCODE_BYE( "bye", 5 ),
+ BOOTERCODE_STOP_ON_NEXT_TEST( "stopOnNextTest", 5 ),
+ BOOTERCODE_NEXT_TEST( "nextTest", 5 ),
+
+ BOOTERCODE_JVM_EXIT_ERROR( "jvmExitError", 6 );
+
+ public static final String MAGIC_NUMBER = ":maven:surefire:std:out:";
+
+ public static final Map<String, ForkedProcessEvent> EVENTS = events();
+
+ private static Map<String, ForkedProcessEvent> events()
+ {
+ Map<String, ForkedProcessEvent> events = new ConcurrentHashMap<String, ForkedProcessEvent>();
+ for ( ForkedProcessEvent event : values() )
+ {
+ events.put( event.getOpcode(), event );
+ }
+ return unmodifiableMap( events );
+ }
+
+
+ private final String opcode;
+ private final int category;
+
+ ForkedProcessEvent( String opcode, int category )
+ {
+ this.opcode = opcode;
+ this.category = category;
+ }
+
+ public String getOpcode()
+ {
+ return opcode;
+ }
+
+ public boolean isSysPropCategory()
+ {
+ return category == 0;
+ }
+
+ public boolean isTestCategory()
+ {
+ return category == 1;
+ }
+
+ public boolean isStandardStreamCategory()
+ {
+ return category == 2;
+ }
+
+ public boolean isConsoleCategory()
+ {
+ return category == 3;
+ }
+
+ public boolean isConsoleErrorCategory()
+ {
+ return category == 4;
+ }
+
+ public boolean isControlCategory()
+ {
+ return category == 5;
+ }
+
+ public boolean isJvmExitError()
+ {
+ return category == 6;
+ }
+}
http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/64ae8e88/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkingReporterFactory.java
----------------------------------------------------------------------
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkingReporterFactory.java b/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkingReporterFactory.java
index def345d..59c6bcb 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkingReporterFactory.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/booter/ForkingReporterFactory.java
@@ -19,13 +19,12 @@ package org.apache.maven.surefire.booter;
* under the License.
*/
-import java.io.PrintStream;
-import java.util.concurrent.atomic.AtomicInteger;
-
import org.apache.maven.surefire.report.ReporterFactory;
import org.apache.maven.surefire.report.RunListener;
import org.apache.maven.surefire.suite.RunResult;
+import java.util.concurrent.atomic.AtomicInteger;
+
/**
* Creates ForkingReporters, which are typically one instance per TestSet or thread.
* This factory is only used inside forks.
@@ -39,19 +38,19 @@ public class ForkingReporterFactory
{
private final boolean isTrimstackTrace;
- private final PrintStream originalSystemOut;
+ private final ForkedChannelEncoder eventChannel;
private final AtomicInteger testSetChannelId = new AtomicInteger( 1 );
- public ForkingReporterFactory( boolean trimstackTrace, PrintStream originalSystemOut )
+ public ForkingReporterFactory( boolean trimstackTrace, ForkedChannelEncoder eventChannel )
{
isTrimstackTrace = trimstackTrace;
- this.originalSystemOut = originalSystemOut;
+ this.eventChannel = eventChannel;
}
public RunListener createReporter()
{
- return new ForkingRunListener( originalSystemOut, testSetChannelId.getAndIncrement(), isTrimstackTrace );
+ return new ForkingRunListener( eventChannel, testSetChannelId.getAndIncrement(), isTrimstackTrace );
}
public RunResult close()
http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/64ae8e88/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 6c0842a..ffe029f 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
@@ -28,15 +28,19 @@ import org.apache.maven.surefire.report.ConsoleOutputReceiver;
import org.apache.maven.surefire.report.ConsoleStream;
import org.apache.maven.surefire.report.ReportEntry;
import org.apache.maven.surefire.report.RunListener;
+import org.apache.maven.surefire.report.RunMode;
import org.apache.maven.surefire.report.SafeThrowable;
import org.apache.maven.surefire.report.SimpleReportEntry;
import org.apache.maven.surefire.report.StackTraceWriter;
import static java.lang.Integer.toHexString;
import static java.nio.charset.Charset.defaultCharset;
+import static org.apache.maven.surefire.report.RunMode.NORMAL_RUN;
+import static org.apache.maven.surefire.util.internal.ObjectUtils.requireNonNull;
import static org.apache.maven.surefire.util.internal.StringUtils.encodeStringForForkCommunication;
import static org.apache.maven.surefire.util.internal.StringUtils.escapeBytesToPrintable;
import static org.apache.maven.surefire.util.internal.StringUtils.escapeToPrintable;
+import static org.apache.maven.surefire.util.internal.StringUtils.isBlank;
/**
* Encodes the full output of the test run to the stdout stream.
@@ -84,11 +88,11 @@ public class ForkingRunListener
*/
public static final byte BOOTERCODE_CONSOLE = (byte) 'H';
- public static final byte BOOTERCODE_SYSPROPS = (byte) 'I';
+ public static final byte BOOTERCODE_SYSPROPS = (byte) 'I';//
- public static final byte BOOTERCODE_NEXT_TEST = (byte) 'N';
+ public static final byte BOOTERCODE_NEXT_TEST = (byte) 'N';//
- public static final byte BOOTERCODE_STOP_ON_NEXT_TEST = (byte) 'S';
+ public static final byte BOOTERCODE_STOP_ON_NEXT_TEST = (byte) 'S';//
/**
* ERROR logger
@@ -111,7 +115,7 @@ public class ForkingRunListener
public static final byte BOOTERCODE_WARNING = (byte) 'W';
- private final PrintStream target;
+ private final ForkedChannelEncoder target;
private final int testSetChannelId;
@@ -121,7 +125,9 @@ public class ForkingRunListener
private final byte[] stdErrHeader;
- public ForkingRunListener( PrintStream target, int testSetChannelId, boolean trimStackTraces )
+ private volatile RunMode runMode = NORMAL_RUN;
+
+ public ForkingRunListener( ForkedChannelEncoder target, int testSetChannelId, boolean trimStackTraces )
{
this.target = target;
this.testSetChannelId = testSetChannelId;
@@ -176,6 +182,13 @@ public class ForkingRunListener
encodeAndWriteToTarget( toString( BOOTERCODE_STOP_ON_NEXT_TEST, new SimpleReportEntry(), testSetChannelId ) );
}
+ public RunMode markAs( RunMode currentRunMode )
+ {
+ RunMode runMode = this.runMode;
+ this.runMode = requireNonNull( currentRunMode );
+ return runMode;
+ }
+
void sendProps()
{
Properties systemProperties = System.getProperties();
@@ -260,7 +273,7 @@ public class ForkingRunListener
public void error( String message, Throwable t )
{
- error( ConsoleLoggerUtils.toString( message, t ) );
+ error( ConsoleLoggerUtils.toString( message, t ) );//tu daj localized msg a potom string:stacktrace
}
public void error( Throwable t )
@@ -355,7 +368,7 @@ public class ForkingRunListener
private static void nullableEncoding( StringBuilder stringBuilder, String source )
{
- if ( source == null || source.length() == 0 )
+ if ( isBlank( source ) )
{
stringBuilder.append( "null" );
}
http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/64ae8e88/surefire-api/src/main/java/org/apache/maven/surefire/report/RunListener.java
----------------------------------------------------------------------
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/report/RunListener.java b/surefire-api/src/main/java/org/apache/maven/surefire/report/RunListener.java
index b964430..74e8e9b 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/report/RunListener.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/report/RunListener.java
@@ -93,4 +93,13 @@ public interface RunListener
* (The event is fired after the Nth test failed to signal skipping the rest of test-set.)
*/
void testExecutionSkippedByUser();
+
+ /**
+ * Marks the listener with run mode, e.g. normal run or re-run.
+ *
+ * @param currentRunMode set current run
+ * @return previous run mode; never returns null
+ * @throws NullPointerException if <code>currentRunMode</code> is null
+ */
+ RunMode markAs( RunMode currentRunMode );
}
http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/64ae8e88/surefire-api/src/main/java/org/apache/maven/surefire/report/RunMode.java
----------------------------------------------------------------------
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/report/RunMode.java b/surefire-api/src/main/java/org/apache/maven/surefire/report/RunMode.java
new file mode 100644
index 0000000..0323d9a
--- /dev/null
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/report/RunMode.java
@@ -0,0 +1,60 @@
+package org.apache.maven.surefire.report;
+
+/*
+ * 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.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import static java.util.Collections.unmodifiableMap;
+
+/**
+ * Determines the purpose the provider started the tests. It can be either normal run or re-run.
+ *
+ * @author <a href="mailto:tibordigana@apache.org">Tibor Digana (tibor17)</a>
+ * @since 2.20.1
+ */
+public enum RunMode
+{
+ NORMAL_RUN( "normal-run" ), RERUN( "re-run" );
+
+ public static final Map<String, RunMode> MODES = modes();
+
+ private static Map<String, RunMode> modes()
+ {
+ Map<String, RunMode> modes = new ConcurrentHashMap<String, RunMode>();
+ for ( RunMode mode : values() )
+ {
+ modes.put( mode.geRunName(), mode );
+ }
+ return unmodifiableMap( modes );
+ }
+
+ private final String runName;
+
+ RunMode( String runName )
+ {
+ this.runName = runName;
+ }
+
+ public String geRunName()
+ {
+ return runName;
+ }
+}
http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/64ae8e88/surefire-api/src/main/java/org/apache/maven/surefire/testset/TestListResolver.java
----------------------------------------------------------------------
diff --git a/surefire-api/src/main/java/org/apache/maven/surefire/testset/TestListResolver.java b/surefire-api/src/main/java/org/apache/maven/surefire/testset/TestListResolver.java
index e2ae963..66cef8d 100644
--- a/surefire-api/src/main/java/org/apache/maven/surefire/testset/TestListResolver.java
+++ b/surefire-api/src/main/java/org/apache/maven/surefire/testset/TestListResolver.java
@@ -74,7 +74,7 @@ public class TestListResolver
for ( String request : split( csvTests, "," ) )
{
request = request.trim();
- if ( request.length() != 0 && !request.equals( "!" ) )
+ if ( !request.isEmpty() && !request.equals( "!" ) )
{
resolveTestRequest( request, patterns, includedFilters, excludedFilters );
}
@@ -249,7 +249,7 @@ public class TestListResolver
}
aggregatedTest += aggregatedTest( "!", getExcludedPatterns() );
- return aggregatedTest.length() == 0 ? "" : aggregatedTest;
+ return aggregatedTest.isEmpty() ? "" : aggregatedTest;
}
public Set<ResolvedTest> getIncludedPatterns()
@@ -309,7 +309,7 @@ public class TestListResolver
static String removeExclamationMark( String s )
{
- return s.length() != 0 && s.charAt( 0 ) == '!' ? s.substring( 1 ) : s;
+ return !s.isEmpty() && s.charAt( 0 ) == '!' ? s.substring( 1 ) : s;
}
private static void updatedFilters( boolean isExcluded, ResolvedTest test, IncludedExcludedPatterns patterns,
@@ -334,7 +334,7 @@ public class TestListResolver
for ( ResolvedTest test : tests )
{
String readableTest = test.toString();
- if ( readableTest.length() != 0 )
+ if ( !readableTest.isEmpty() )
{
if ( aggregatedTest.length() != 0 )
{
@@ -357,7 +357,7 @@ public class TestListResolver
if ( exc != null )
{
exc = exc.trim();
- if ( exc.length() != 0 )
+ if ( !exc.isEmpty() )
{
if ( exc.contains( "!" ) )
{
@@ -457,8 +457,8 @@ public class TestListResolver
if ( isRegexPrefixedPattern( request ) )
{
final String[] unwrapped = unwrapRegex( request );
- final boolean hasClass = unwrapped[0].length() != 0;
- final boolean hasMethod = unwrapped[1].length() != 0;
+ final boolean hasClass = !unwrapped[0].isEmpty();
+ final boolean hasMethod = !unwrapped[1].isEmpty();
if ( hasClass && hasMethod )
{
test = new ResolvedTest( unwrapped[0], unwrapped[1], true );
http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/64ae8e88/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 d1838b2..44410de 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,11 +19,6 @@ 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;
/**
@@ -62,8 +57,6 @@ public final class StringUtils
private static final byte[] HEX_CHARS = {
'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";
@@ -148,216 +141,6 @@ public final class StringUtils
}
/**
- * Escape the specified string to a representation that only consists of nicely printable characters, without any
- * newlines and without a comma.
- * <p>
- * The reverse-method is {@link #unescapeString(StringBuilder, CharSequence)}.
- *
- * @param target target string buffer. The required space will be up to {@code str.getBytes().length * 5} chars.
- * @param str String to escape values in, may be {@code null}.
- */
- @SuppressWarnings( "checkstyle:magicnumber" )
- public static void escapeToPrintable( StringBuilder target, CharSequence str )
- {
- if ( target == null )
- {
- throw new IllegalArgumentException( "The target buffer must not be null" );
- }
- if ( str == null )
- {
- return;
- }
-
- for ( int i = 0; i < str.length(); i++ )
- {
- char c = str.charAt( i );
-
- // handle non-nicely printable chars and the comma
- if ( c < 32 || c > 126 || c == '\\' || c == ',' )
- {
- target.append( '\\' );
- target.append( (char) HEX_CHARS[( 0xF000 & c ) >> 12] );
- target.append( (char) HEX_CHARS[( 0x0F00 & c ) >> 8] );
- target.append( (char) HEX_CHARS[( 0x00F0 & c ) >> 4] );
- target.append( (char) HEX_CHARS[( 0x000F & c )] );
- }
- else
- {
- target.append( c );
- }
- }
- }
-
- /**
- * Reverses the effect of {@link #escapeToPrintable(StringBuilder, CharSequence)}.
- *
- * @param target target string buffer
- * @param str the String to un-escape, as created by {@link #escapeToPrintable(StringBuilder, CharSequence)}
- */
- public static void unescapeString( StringBuilder target, CharSequence str )
- {
- if ( target == null )
- {
- throw new IllegalArgumentException( "The target buffer must not be null" );
- }
- if ( str == null )
- {
- return;
- }
-
- for ( int i = 0; i < str.length(); i++ )
- {
- char ch = str.charAt( i );
-
- if ( ch == '\\' )
- {
- target.append( (char) (
- digit( str.charAt( ++i ) ) << 12
- | digit( str.charAt( ++i ) ) << 8
- | digit( str.charAt( ++i ) ) << 4
- | digit( str.charAt( ++i ) )
- ) );
- }
- else
- {
- target.append( ch );
- }
- }
- }
-
- private static int digit( char ch )
- {
- if ( ch >= 'a' )
- {
- return 10 + ch - 'a';
- }
- else if ( ch >= 'A' )
- {
- return 10 + ch - 'A';
- }
- else
- {
- return ch - '0';
- }
- }
-
- /**
- * Escapes the bytes in the array {@code str} to contain only 'printable' bytes.
- * <p>
- * Escaping is done by encoding the non-nicely printable bytes to {@code '\' + upperCaseHexBytes(byte)}.
- * <p>
- * A save length of {@code out} is {@code len * 3 + outoff}.
- * <p>
- * The reverse-method is {@link #unescapeBytes(byte[], String)}.
- *
- * @param out output buffer
- * @param outoff offset in the output buffer
- * @param input input buffer
- * @param off offset in the input buffer
- * @param len number of bytes to copy from the input buffer
- * @return number of bytes written to {@code out}
- */
- @SuppressWarnings( "checkstyle:magicnumber" )
- public static int escapeBytesToPrintable( byte[] out, int outoff, byte[] input, int off, int len )
- {
- if ( out == null )
- {
- throw new IllegalArgumentException( "The output array must not be null" );
- }
- if ( input == null || input.length == 0 )
- {
- return 0;
- }
- int outputPos = outoff;
- int end = off + len;
- for ( int i = off; i < end; i++ )
- {
- byte b = input[i];
-
- // handle non-nicely printable bytes
- if ( b < 32 || b > 126 || b == '\\' || b == ',' )
- {
- int upper = ( 0xF0 & b ) >> 4;
- int lower = ( 0x0F & b );
- out[outputPos++] = '\\';
- out[outputPos++] = HEX_CHARS[upper];
- out[outputPos++] = HEX_CHARS[lower];
- }
- else
- {
- out[outputPos++] = b;
- }
- }
-
- return outputPos - outoff;
- }
-
- /**
- * Reverses the effect of {@link #escapeBytesToPrintable(byte[], int, byte[], int, int)}.
- *
- * @param str the input String
- * @param charsetName the charset name
- * @return the number of bytes written to {@code out}
- */
- public static ByteBuffer unescapeBytes( String str, String charsetName )
- {
- int outPos = 0;
-
- if ( str == null )
- {
- 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 );
-
- if ( ch == '\\' )
- {
- int upper = digit( str.charAt( ++i ) );
- int lower = digit( str.charAt( ++i ) );
- out[outPos++] = (byte) ( upper << 4 | lower );
- }
- else
- {
- out[outPos++] = (byte) ch;
- }
- }
-
- 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 );
- }
- }
-
- /**
*
* @param buffer Examined StringBuffer
* @param pattern a pattern which should start in <code>buffer</code>
http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/64ae8e88/surefire-api/src/test/java/org/apache/maven/JUnit4SuiteTest.java
----------------------------------------------------------------------
diff --git a/surefire-api/src/test/java/org/apache/maven/JUnit4SuiteTest.java b/surefire-api/src/test/java/org/apache/maven/JUnit4SuiteTest.java
index c43a3a6..d64b5a5 100644
--- a/surefire-api/src/test/java/org/apache/maven/JUnit4SuiteTest.java
+++ b/surefire-api/src/test/java/org/apache/maven/JUnit4SuiteTest.java
@@ -39,7 +39,6 @@ import org.apache.maven.surefire.util.TestsToRunTest;
import org.apache.maven.surefire.util.UrlUtilsTest;
import org.apache.maven.surefire.util.internal.ByteBufferTest;
import org.apache.maven.surefire.util.internal.ConcurrencyUtilsTest;
-import org.apache.maven.surefire.util.internal.StringUtilsTest;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
@@ -60,7 +59,6 @@ import org.junit.runners.Suite;
TestListResolverTest.class,
ByteBufferTest.class,
ConcurrencyUtilsTest.class,
- StringUtilsTest.class,
DefaultDirectoryScannerTest.class,
RunOrderCalculatorTest.class,
RunOrderTest.class,