Repository: maven-surefire Updated Branches: refs/heads/master d7592d670 -> a85d3276d
[SUREFIRE-1454] Speedup Standard Output if Tests Project: http://git-wip-us.apache.org/repos/asf/maven-surefire/repo Commit: http://git-wip-us.apache.org/repos/asf/maven-surefire/commit/a85d3276 Tree: http://git-wip-us.apache.org/repos/asf/maven-surefire/tree/a85d3276 Diff: http://git-wip-us.apache.org/repos/asf/maven-surefire/diff/a85d3276 Branch: refs/heads/master Commit: a85d3276dbf6728ec855992352d613142aac41d3 Parents: d7592d6 Author: Tibor17 <tibordig...@apache.org> Authored: Sat Dec 16 21:01:48 2017 +0100 Committer: Tibor17 <tibordig...@apache.org> Committed: Sat Dec 16 21:04:49 2017 +0100 ---------------------------------------------------------------------- .../surefire/booter/ForkingRunListener.java | 29 ++----- .../surefire/util/internal/StringUtils.java | 79 +++++++++++++------- .../surefire/util/internal/StringUtilsTest.java | 31 ++++++-- 3 files changed, 85 insertions(+), 54 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/a85d3276/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 a060469..ce806b9 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 @@ -29,6 +29,7 @@ import org.apache.maven.surefire.report.SafeThrowable; import org.apache.maven.surefire.report.SimpleReportEntry; import org.apache.maven.surefire.report.StackTraceWriter; import org.apache.maven.surefire.report.TestSetReportEntry; +import org.apache.maven.surefire.util.internal.StringUtils.EncodedArray; import java.io.PrintStream; import java.util.Map.Entry; @@ -188,7 +189,7 @@ public class ForkingRunListener encodeAndWriteToTarget( toString( BOOTERCODE_STOP_ON_NEXT_TEST, new SimpleReportEntry(), testSetChannelId ) ); } - void sendProps() + private void sendProps() { for ( Entry<String, String> entry : systemProps().entrySet() ) { @@ -200,18 +201,11 @@ public class ForkingRunListener @Override public void writeTestOutput( byte[] buf, int off, int len, boolean stdout ) { - byte[] header = stdout ? stdOutHeader : stdErrHeader; - byte[] content = - new byte[buf.length * 3 + 1]; // Hex-escaping can be up to 3 times length of a regular byte. - int i = escapeBytesToPrintable( content, 0, buf, off, len ); - content[i++] = (byte) '\n'; - byte[] encodeBytes = new byte[header.length + i]; - System.arraycopy( header, 0, encodeBytes, 0, header.length ); - System.arraycopy( content, 0, encodeBytes, header.length, i ); + EncodedArray encodedArray = escapeBytesToPrintable( stdout ? stdOutHeader : stdErrHeader, buf, off, len ); synchronized ( target ) // See notes about synchronization/thread safety in class javadoc { - target.write( encodeBytes, 0, encodeBytes.length ); + target.write( encodedArray.getArray(), 0, encodedArray.getSize() ); target.flush(); if ( target.checkError() ) { @@ -361,28 +355,19 @@ public class ForkingRunListener stringBuilder.append( "," ); } - private ForkingRunListener append( StringBuilder stringBuilder, String message ) + private void append( StringBuilder stringBuilder, String message ) { stringBuilder.append( encode( message ) ); - return this; } - private ForkingRunListener append( StringBuilder stringBuilder, byte b ) + private void append( StringBuilder stringBuilder, byte b ) { stringBuilder.append( (char) b ); - return this; } private void nullableEncoding( StringBuilder stringBuilder, Integer source ) { - if ( source == null ) - { - stringBuilder.append( "null" ); - } - else - { - stringBuilder.append( source.toString() ); - } + stringBuilder.append( source == null ? "null" : source.toString() ); } private String encode( String source ) http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/a85d3276/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 b32d5d0..23d372c 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 @@ -218,58 +218,62 @@ public final class StringUtils } /** - * Escapes the bytes in the array {@code str} to contain only 'printable' bytes. - * <p> + * Escapes the bytes in the array {@code input} to contain only 'printable' bytes. + * <br> * 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> + * <br> * The reverse-method is {@link #unescapeBytes(String, String)}. + * <br> + * The returned byte array is started with aligned sequence {@code header} and finished by {@code \n}. * - * @param out output buffer - * @param outoff offset in the output buffer + * @param header prefix header * @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} + * @throws NullPointerException if the specified parameter {@code header} or {@code input} is null + * @throws IndexOutOfBoundsException if {@code off} or {@code len} is out of range + * ({@code off < 0 || len < 0 || off >= input.length || len > input.length || off > len}) */ @SuppressWarnings( "checkstyle:magicnumber" ) - public static int escapeBytesToPrintable( byte[] out, int outoff, byte[] input, int off, int len ) + public static EncodedArray escapeBytesToPrintable( final byte[] header, final byte[] input, final int off, + final int len ) { - if ( out == null ) - { - throw new IllegalArgumentException( "The output array must not be null" ); - } - if ( input == null || input.length == 0 ) + if ( off < 0 || len < 0 || off >= input.length || len > input.length || off > len ) { - return 0; + throw new IndexOutOfBoundsException( + "off < 0 || len < 0 || off >= input.length || len > input.length || off > len" ); } - int outputPos = outoff; - int end = off + len; + // Hex-escaping can be up to 3 times length of a regular byte. Last character is '\n', see (+1). + final byte[] encodeBytes = new byte[header.length + 3 * len + 1]; + System.arraycopy( header, 0, encodeBytes, 0, header.length ); + int outputPos = header.length; + final int end = off + len; for ( int i = off; i < end; i++ ) { - byte b = input[i]; + final 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]; + final int upper = ( 0xF0 & b ) >> 4; + final int lower = ( 0x0F & b ); + encodeBytes[outputPos++] = '\\'; + encodeBytes[outputPos++] = HEX_CHARS[upper]; + encodeBytes[outputPos++] = HEX_CHARS[lower]; } else { - out[outputPos++] = b; + encodeBytes[outputPos++] = b; } } + encodeBytes[outputPos++] = (byte) '\n'; - return outputPos - outoff; + return new EncodedArray( encodeBytes, outputPos ); } /** - * Reverses the effect of {@link #escapeBytesToPrintable(byte[], int, byte[], int, int)}. + * Reverses the effect of {@link #escapeBytesToPrintable(byte[], byte[], int, int)}. * * @param str the input String * @param charsetName the charset name @@ -349,4 +353,29 @@ public final class StringUtils return true; } } + + /** + * Escaped string to byte array with offset 0 and certain length. + */ + public static final class EncodedArray + { + private final byte[] array; + private final int size; + + private EncodedArray( byte[] array, int size ) + { + this.array = array; + this.size = size; + } + + public byte[] getArray() + { + return array; + } + + public int getSize() + { + return size; + } + } } http://git-wip-us.apache.org/repos/asf/maven-surefire/blob/a85d3276/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 c1c8d73..dea6c9b 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,9 +19,13 @@ package org.apache.maven.surefire.util.internal; * under the License. */ +import java.nio.ByteBuffer; import java.nio.charset.Charset; import junit.framework.TestCase; +import org.apache.maven.surefire.util.internal.StringUtils.EncodedArray; + +import static org.junit.Assert.assertArrayEquals; /** * @author Andreas Gudian @@ -76,21 +80,34 @@ public class StringUtilsTest input[i] = b; } - byte[] escaped = new byte[input.length * 3]; - - int escapedBytes = StringUtils.escapeBytesToPrintable( escaped, 0, input, 0, input.length ); + EncodedArray encodedArray = StringUtils.escapeBytesToPrintable( new byte[0], input, 0, input.length ); - String escapedString = new String( escaped, 0, escapedBytes ); + String escapedString = new String( encodedArray.getArray(), 0, encodedArray.getSize() ); - assertEquals( escapedBytes, escapedString.length() ); + assertEquals( encodedArray.getSize(), escapedString.length() ); - java.nio.ByteBuffer unescaped = StringUtils.unescapeBytes( escapedString, Charset.defaultCharset().name() ); + ByteBuffer unescaped = StringUtils.unescapeBytes( escapedString, Charset.defaultCharset().name() ); - assertEquals( input.length, unescaped.remaining() - unescaped.position() ); + assertEquals( input.length + 1, unescaped.remaining() - unescaped.position() ); for ( int i = 0; i < input.length; i++ ) { assertEquals( "At position " + i, input[i], unescaped.get() ); } } + + public void testEscapeWithHeader() + { + byte[] header = { (byte) 'a' }; + byte[] input = { (byte) '1' }; + + EncodedArray encodedArray = StringUtils.escapeBytesToPrintable( header, input, 0, input.length ); + assertEquals( 3, encodedArray.getSize() ); + + byte[] expectedResult = new byte[] { (byte) 'a', (byte) '1', (byte) '\n' }; + byte[] actualResult = new byte[encodedArray.getSize()]; + System.arraycopy( encodedArray.getArray(), 0, actualResult, 0, encodedArray.getSize() ); + + assertArrayEquals( expectedResult, actualResult ); + } }