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 2020/09/16 13:27:57 UTC
[maven-surefire] branch base64 updated: unit tests cleanup and
employed default and non-default charset in the algorithm
This is an automated email from the ASF dual-hosted git repository.
tibordigana pushed a commit to branch base64
in repository https://gitbox.apache.org/repos/asf/maven-surefire.git
The following commit(s) were added to refs/heads/base64 by this push:
new 5c9524d unit tests cleanup and employed default and non-default charset in the algorithm
5c9524d is described below
commit 5c9524d4539df457ed9121053155e1e903f02617
Author: tibordigana <ti...@apache.org>
AuthorDate: Wed Sep 16 15:27:47 2020 +0200
unit tests cleanup and employed default and non-default charset in the algorithm
---
.../surefire/extensions/EventConsumerThread.java | 64 ++-
.../extensions/EventConsumerThreadTest.java | 638 +++++++++------------
2 files changed, 322 insertions(+), 380 deletions(-)
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/EventConsumerThread.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/EventConsumerThread.java
index 45c6d0d..34787b8 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/EventConsumerThread.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/extensions/EventConsumerThread.java
@@ -78,7 +78,7 @@ import static org.apache.maven.plugin.surefire.extensions.EventConsumerThread.St
import static org.apache.maven.plugin.surefire.extensions.EventConsumerThread.StreamReadStatus.OVERFLOW;
import static org.apache.maven.plugin.surefire.extensions.EventConsumerThread.StreamReadStatus.UNDERFLOW;
import static org.apache.maven.surefire.api.booter.Constants.MAGIC_NUMBER;
-import static org.apache.maven.surefire.api.booter.Constants.STREAM_ENCODING;
+import static org.apache.maven.surefire.api.booter.Constants.DEFAULT_STREAM_ENCODING;
import static org.apache.maven.surefire.api.report.CategorizedReportEntry.reportEntry;
/**
@@ -148,7 +148,7 @@ public class EventConsumerThread extends CloseableDaemonThread
private static final int BUFFER_SIZE = 1024;
private static final byte[] MAGIC_NUMBER_BYTES = MAGIC_NUMBER.getBytes( US_ASCII );
- private static final byte[] STREAM_ENCODING_BYTES = STREAM_ENCODING.name().getBytes( US_ASCII );
+ private static final byte[] DEFAULT_STREAM_ENCODING_BYTES = DEFAULT_STREAM_ENCODING.name().getBytes( US_ASCII );
private static final int DELIMITER_LENGTH = 1;
private static final int BYTE_LENGTH = 1;
private static final int INT_LENGTH = 4;
@@ -227,10 +227,10 @@ public class EventConsumerThread extends CloseableDaemonThread
runMode = runModes.get( readSegment( memento ) );
break;
case STRING_ENCODING:
- memento.charset = readCharset( memento );
+ memento.setCharset( readCharset( memento ) );
break;
case DATA_STRING:
- readString( memento );
+ memento.data.add( readString( memento ) );
break;
case DATA_INT:
memento.data.add( readInt( memento ) );
@@ -282,7 +282,7 @@ public class EventConsumerThread extends CloseableDaemonThread
return eventTypes.get( readSegment( memento ) );
}
- protected void readString( Memento memento ) throws IOException, MalformedFrameException
+ protected String readString( Memento memento ) throws IOException, MalformedFrameException
{
memento.cb.clear();
if ( read( memento, INT_LENGTH + DELIMITER_LENGTH ) == EOF )
@@ -296,9 +296,10 @@ public class EventConsumerThread extends CloseableDaemonThread
throw new EOFException();
}
+ final String string;
if ( readCount == 0 )
{
- memento.data.add( "" );
+ string = "";
}
else if ( readCount == 1 )
{
@@ -307,14 +308,15 @@ public class EventConsumerThread extends CloseableDaemonThread
throw new EOFException();
}
byte oneChar = memento.bb.get();
- memento.data.add( oneChar == 0 ? null : String.valueOf( (char) oneChar ) );
+ string = oneChar == 0 ? null : String.valueOf( (char) oneChar );
}
else
{
- memento.data.add( readString( memento, readCount ) );
+ string = readString( memento, readCount );
}
checkDelimiter( memento );
+ return string;
}
@Nonnull
@@ -353,19 +355,22 @@ public class EventConsumerThread extends CloseableDaemonThread
int offset = bb.arrayOffset() + bb.position();
bb.position( bb.position() + length );
boolean isDefaultEncoding = false;
- if ( length == STREAM_ENCODING_BYTES.length )
+ if ( length == DEFAULT_STREAM_ENCODING_BYTES.length )
{
isDefaultEncoding = true;
for ( int i = 0; i < length; i++ )
{
- isDefaultEncoding &= STREAM_ENCODING_BYTES[i] == array[offset + i];
+ isDefaultEncoding &= DEFAULT_STREAM_ENCODING_BYTES[i] == array[offset + i];
}
}
try
{
Charset charset =
- isDefaultEncoding ? STREAM_ENCODING : Charset.forName( new String( array, offset, length, US_ASCII ) );
+ isDefaultEncoding
+ ? DEFAULT_STREAM_ENCODING
+ : Charset.forName( new String( array, offset, length, US_ASCII ) );
+
checkDelimiter( memento );
return charset;
}
@@ -609,7 +614,7 @@ public class EventConsumerThread extends CloseableDaemonThread
String readString( @Nonnull final Memento memento, @Nonnegative final int totalBytes )
throws IOException, MalformedFrameException
{
- memento.decoder.reset();
+ memento.getDecoder().reset();
final CharBuffer output = memento.cb;
output.clear();
final ByteBuffer input = memento.bb;
@@ -632,7 +637,7 @@ public class EventConsumerThread extends CloseableDaemonThread
{
boolean endOfChunk = output.remaining() >= bytesToRead;
boolean endOfOutput = isLastChunk && endOfChunk;
- int readInputBytes = decode( memento.decoder, input, output, bytesToDecode, endOfOutput,
+ int readInputBytes = decode( memento.getDecoder(), input, output, bytesToDecode, endOfOutput,
memento.line.positionByteBuffer );
bytesToDecode -= readInputBytes;
countDecodedBytes += readInputBytes;
@@ -646,7 +651,7 @@ public class EventConsumerThread extends CloseableDaemonThread
}
}
- memento.decoder.reset();
+ memento.getDecoder().reset();
output.clear();
return toString( strings );
@@ -794,7 +799,7 @@ public class EventConsumerThread extends CloseableDaemonThread
return;
}
ConsoleLogger logger = arguments.getConsoleLogger();
- String s = toString( STREAM_ENCODING );
+ String s = toString( DEFAULT_STREAM_ENCODING );
if ( s.contains( PRINTABLE_JVM_NATIVE_STREAM ) )
{
if ( logger.isDebugEnabled() )
@@ -833,27 +838,46 @@ public class EventConsumerThread extends CloseableDaemonThread
class Memento
{
- final CharsetDecoder decoder;
+ private final CharsetDecoder defaultDecoder;
+ private CharsetDecoder currentDecoder;
final BufferedStream line = new BufferedStream( 32 );
final List<Object> data = new ArrayList<>();
final CharBuffer cb = CharBuffer.allocate( BUFFER_SIZE );
final ByteBuffer bb = ByteBuffer.allocate( BUFFER_SIZE );
- Charset charset;
Memento()
{
- decoder = STREAM_ENCODING.newDecoder()
+ defaultDecoder = DEFAULT_STREAM_ENCODING.newDecoder()
.onMalformedInput( REPLACE )
.onUnmappableCharacter( REPLACE );
}
void reset()
{
- charset = null;
+ currentDecoder = null;
+ }
+
+ CharsetDecoder getDecoder()
+ {
+ return currentDecoder == null ? defaultDecoder : currentDecoder;
+ }
+
+ void setCharset( Charset charset )
+ {
+ if ( charset.name().equals( defaultDecoder.charset().name() ) )
+ {
+ currentDecoder = defaultDecoder;
+ }
+ else
+ {
+ currentDecoder = charset.newDecoder()
+ .onMalformedInput( REPLACE )
+ .onUnmappableCharacter( REPLACE );
+ }
}
}
- static class Segment
+ private static class Segment
{
private final byte[] array;
private final int fromIndex;
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/extensions/EventConsumerThreadTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/extensions/EventConsumerThreadTest.java
index 0979399..a599e54 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/extensions/EventConsumerThreadTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/extensions/EventConsumerThreadTest.java
@@ -2,491 +2,409 @@ package org.apache.maven.plugin.surefire.extensions;
import org.apache.maven.plugin.surefire.extensions.EventConsumerThread.Memento;
import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
-import org.apache.maven.surefire.api.booter.ForkedProcessEventType;
+import org.apache.maven.surefire.api.event.Event;
import org.apache.maven.surefire.extensions.EventHandler;
import org.apache.maven.surefire.extensions.ForkNodeArguments;
import org.apache.maven.surefire.extensions.util.CountdownCloseable;
-import org.fest.assertions.Assertions;
-import org.junit.Before;
import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameter;
-import org.junit.runners.Parameterized.Parameters;
-import org.mockito.Mockito;
import javax.annotation.Nonnull;
import java.io.Closeable;
+import java.io.EOFException;
import java.io.File;
-import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
-import java.nio.channels.Channel;
import java.nio.channels.ReadableByteChannel;
-import java.nio.charset.CharacterCodingException;
-import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
-import java.nio.charset.CoderResult;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.SortedSet;
-import java.util.TreeMap;
-import java.util.TreeSet;
-import java.util.concurrent.TimeUnit;
+import static java.lang.Math.min;
import static java.nio.charset.CodingErrorAction.REPLACE;
import static java.nio.charset.StandardCharsets.UTF_8;
-import static org.apache.maven.plugin.surefire.extensions.EventConsumerThreadTest.StreamReadStatus.EOF;
-import static org.apache.maven.plugin.surefire.extensions.EventConsumerThreadTest.StreamReadStatus.OVERFLOW;
-import static org.apache.maven.plugin.surefire.extensions.EventConsumerThreadTest.StreamReadStatus.UNDERFLOW;
-import static org.apache.maven.surefire.api.booter.Constants.STREAM_ENCODING;
+import static org.apache.maven.surefire.api.booter.Constants.DEFAULT_STREAM_ENCODING;
import static org.fest.assertions.Assertions.assertThat;
-//import static org.mockito.Mockito.mock;
-
-//@RunWith( Parameterized.class )
+import static org.powermock.reflect.Whitebox.invokeMethod;
+
+/**
+ * The performance of "get( Integer )" is 13.5 nano seconds on i5/2.6GHz:
+ * <pre>
+ * {@code
+ * TreeMap<Integer, ForkedProcessEventType> map = new TreeMap<>();
+ * map.get( hash );
+ * }
+ * </pre>
+ *
+ * <br> The performance of getting event type by Segment is 33.7 nano seconds:
+ * <pre>
+ * {@code
+ * Map<Segment, ForkedProcessEventType> map = new HashMap<>();
+ * byte[] array = ForkedProcessEventType.BOOTERCODE_STDOUT.getOpcode().getBytes( UTF_8 );
+ * map.get( new Segment( array, 0, array.length ) );
+ * }
+ * </pre>
+ *
+ * <br> The performance of decoder:
+ * <pre>
+ * {@code
+ * CharsetDecoder decoder = STREAM_ENCODING.newDecoder()
+ * .onMalformedInput( REPLACE )
+ * .onUnmappableCharacter( REPLACE );
+ * ByteBuffer buffer = ByteBuffer.wrap( ForkedProcessEventType.BOOTERCODE_STDOUT.getOpcode().getBytes( UTF_8 ) );
+ * CharBuffer chars = CharBuffer.allocate( 100 );
+ * decoder.reset().decode( buffer, chars, true );
+ *
+ * String s = chars.flip().toString(); // 37 nanos = CharsetDecoder + toString
+ *
+ * buffer.clear();
+ * chars.clear();
+ *
+ * ForkedProcessEventType.byOpcode( s ); // 65 nanos = CharsetDecoder + toString + byOpcode
+ * }
+ * </pre>
+ *
+ * <br> The performance of decoding 100 bytes via CharacterDecoder - 71 nano seconds:
+ * <pre>
+ * {@code
+ * decoder.reset()
+ * .decode( buffer, chars, true ); // CharsetDecoder 71 nanos
+ * chars.flip().toString(); // CharsetDecoder + toString = 91 nanos
+ * }
+ * </pre>
+ *
+ * <br> The performance of a pure string creation (instead of decoder) - 31.5 nano seconds:
+ * <pre>
+ * {@code
+ * byte[] b = {};
+ * new String( b, UTF_8 );
+ * }
+ * </pre>
+ *
+ * <br> The performance of CharsetDecoder with empty ByteBuffer:
+ * <pre>
+ * {@code
+ * CharsetDecoder + ByteBuffer.allocate( 0 ) makes 11.5 nanos
+ * CharsetDecoder + ByteBuffer.allocate( 0 ) + toString() makes 16.1 nanos
+ * }
+ * </pre>
+ */
public class EventConsumerThreadTest
{
- @Parameters
- public static Iterable<Object> channels()
- {
- return Arrays.asList( (Object) complexEncodings() );
- }
+ private static final CountdownCloseable COUNTDOWN_CLOSEABLE = new CountdownCloseable( new MockCloseable(), 0 );
- @Parameter
- public Channel channel;
+ private static final String PATTERN1 =
+ "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789";
- private static Channel complexEncodings()
- {
- byte[] bytes = new byte[]{(byte) -30, (byte) -126, (byte) -84, 'a', 'b', (byte) 0xc2, (byte) 0xa9, 'c'};
- bytes = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789".getBytes( UTF_8 );
- return new Channel( bytes, 1 );
- }
+ private static final String PATTERN2 = "€ab©c";
+
+ private static final byte[] PATTERN2_BYTES =
+ new byte[]{(byte) -30, (byte) -126, (byte) -84, 'a', 'b', (byte) 0xc2, (byte) 0xa9, 'c'};
- private static Channel complexEncodings( int chunkSize )
+ @Test
+ public void shouldDecodeHappyCase() throws Exception
{
- byte[] bytes = new byte[]{(byte) -30, (byte) -126, (byte) -84, 'a', 'b', (byte) 0xc2, (byte) 0xa9, 'c'};
- bytes = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789".getBytes( UTF_8 );
- return new Channel( bytes, chunkSize );
+ CharsetDecoder decoder = UTF_8.newDecoder()
+ .onMalformedInput( REPLACE )
+ .onUnmappableCharacter( REPLACE );
+ ByteBuffer input = ByteBuffer.allocate( 1024 );
+ input.put( PATTERN2_BYTES )
+ .flip();
+ int bytesToDecode = PATTERN2_BYTES.length;
+ CharBuffer output = CharBuffer.allocate( 1024 );
+ int readBytes =
+ invokeMethod( EventConsumerThread.class, "decode", decoder, input, output, bytesToDecode, true, 0 );
+
+ assertThat( readBytes )
+ .isEqualTo( bytesToDecode );
+
+ assertThat( output.flip().toString() )
+ .isEqualTo( PATTERN2 );
}
@Test
- public void test5() throws IOException, InterruptedException
+ public void shouldDecodeShifted() throws Exception
{
- /*final CharsetDecoder decoder = STREAM_ENCODING.newDecoder()
+ CharsetDecoder decoder = UTF_8.newDecoder()
.onMalformedInput( REPLACE )
.onUnmappableCharacter( REPLACE );
- final CharBuffer chars = CharBuffer.allocate(5);
-
- final int totalBytes = 7;
-
- int countDecodedBytes = 0;
- int countReadBytes = 0;
- final ByteBuffer buffer = ByteBuffer.wrap(new byte[4]);
+ ByteBuffer input = ByteBuffer.allocate( 1024 );
+ input.put( PATTERN1.getBytes( UTF_8 ) )
+ .put( 90, (byte) 'A' )
+ .put( 91, (byte) 'B' )
+ .put( 92, (byte) 'C' )
+ .position( 90 );
+ CharBuffer output = CharBuffer.allocate( 1024 );
+ int readBytes =
+ invokeMethod( EventConsumerThread.class, "decode", decoder, input, output, 2, true, 0 );
+
+ assertThat( readBytes )
+ .isEqualTo( 2 );
+
+ assertThat( output.flip().toString() )
+ .isEqualTo( "AB" );
+ }
- buffer.clear();
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldNotDecode() throws Exception
+ {
+ CharsetDecoder decoder = UTF_8.newDecoder();
+ ByteBuffer input = ByteBuffer.allocate( 100 );
+ int bytesToDecode = 101;
+ CharBuffer output = CharBuffer.allocate( 1000 );
+ invokeMethod( EventConsumerThread.class, "decode", decoder, input, output, bytesToDecode, true, 0 );
+ }
- int positionChars = chars.position();
- int startPosition;
- List<String> strings = new ArrayList<>();
- do
- {
- startPosition = buffer.position();
- buffer.limit( startPosition );
- read( buffer, totalBytes - countReadBytes );
- decoder.decode(buffer, chars, countDecodedBytes >= totalBytes );
- final boolean hasDecodedNewBytes = chars.position() != positionChars;
- if ( hasDecodedNewBytes )
- {
- countDecodedBytes += buffer.position() - startPosition;
- positionChars = chars.position();
- }
- countReadBytes += buffer.limit() - startPosition;
- buffer.compact();
- strings.add( chars.flip().toString() );
- chars.clear();
- }
- while ( countReadBytes < totalBytes );
- decoder.reset();
+ @Test( expected = EOFException.class )
+ public void shouldNotReadString() throws Exception
+ {
+ Channel channel = new Channel( PATTERN1.getBytes(), PATTERN1.length() );
+ channel.read( ByteBuffer.allocate( 100 ) );
- String s = toString( strings );*/
- channel = complexEncodings(100);
+ EventConsumerThread thread = new EventConsumerThread( "t", channel,
+ new MockEventHandler<Event>(), COUNTDOWN_CLOSEABLE, new MockForkNodeArguments() );
- Closeable c = new Closeable()
- {
- @Override
- public void close() throws IOException
- {
+ Memento memento = thread.new Memento();
+ memento.bb.position( 0 ).limit( 0 );
+ thread.readString( memento, 10 );
+ }
- }
- };
+ @Test
+ public void shouldReadString() throws Exception
+ {
+ Channel channel = new Channel( PATTERN1.getBytes(), PATTERN1.length() );
- EventHandler eh = new EventHandler()
- {
- @Override
- public void handleEvent( @Nonnull Object event )
- {
+ EventConsumerThread thread = new EventConsumerThread( "t", channel,
+ new MockEventHandler<Event>(), COUNTDOWN_CLOSEABLE, new MockForkNodeArguments() );
- }
- };
+ Memento memento = thread.new Memento();
+ memento.bb.position( 0 ).limit( 0 );
+ String s = thread.readString( memento, 10 );
+ assertThat( s )
+ .isEqualTo( "0123456789" );
+ }
- ForkNodeArguments forkNodeArguments = new ForkNodeArguments()
+ @Test
+ public void shouldReadStringShiftedBuffer() throws Exception
+ {
+ StringBuilder s = new StringBuilder( 1100 );
+ for ( int i = 0; i < 11; i++ )
{
- @Nonnull
- @Override
- public String getSessionId()
- {
- return null;
- }
-
- @Override
- public int getForkChannelId()
- {
- return 0;
- }
-
- @Nonnull
- @Override
- public File dumpStreamText( @Nonnull String text )
- {
- return null;
- }
-
- @Override
- public void logWarningAtEnd( @Nonnull String text )
- {
+ s.append( PATTERN1 );
+ }
- }
+ Channel channel = new Channel( s.toString().getBytes( UTF_8 ), s.length() );
- @Nonnull
- @Override
- public ConsoleLogger getConsoleLogger()
- {
- return null;
- }
- };
+ EventConsumerThread thread = new EventConsumerThread( "t", channel,
+ new MockEventHandler<Event>(), COUNTDOWN_CLOSEABLE, new MockForkNodeArguments() );
- CountdownCloseable closeable = new CountdownCloseable( c, 0 );
- EventConsumerThread thread = new EventConsumerThread( "t", channel, eh, closeable,
- forkNodeArguments );
- Memento memento = new Memento();
- TimeUnit.SECONDS.sleep( 2 );
- System.gc();
- TimeUnit.SECONDS.sleep( 5 );
- long l1 = System.currentTimeMillis();
- for (int i = 0; i < 10_000_000; i++) {
- //memento.cb.clear();
- memento.bb.position(0);
- memento.bb.limit(memento.bb.capacity());
- memento.bytesCounter = 100;//7
- memento.data.clear();
- channel.reset();
- thread.readString( memento );
- }
-
- long l2 = System.currentTimeMillis();
- System.out.println(l2 - l1);
- /*assertThat( s )
- .isEqualTo( "€ab©" );*/
+ Memento memento = thread.new Memento();
+ // whatever position will be compacted to 0
+ memento.bb.position( 974 ).limit( 974 );
+ assertThat( thread.readString( memento, PATTERN1.length() + 3 ) )
+ .isEqualTo( PATTERN1 + "012" );
}
@Test
- public void test6() throws InterruptedException
+ public void shouldReadStringShiftedInput() throws Exception
{
- CharsetDecoder decoder = STREAM_ENCODING.newDecoder()
- .onMalformedInput( REPLACE )
- .onUnmappableCharacter( REPLACE );
- // CharsetDecoder + ByteBuffer.allocate( 0 ) makes 11.5 nanos
- // CharsetDecoder + ByteBuffer.allocate( 0 ) + toString() makes 16.1 nanos
- ByteBuffer buffer = ByteBuffer.wrap( "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789".getBytes( UTF_8 ) );
- CharBuffer chars = CharBuffer.allocate( 100 );
- TimeUnit.SECONDS.sleep( 2 );
- System.gc();
- TimeUnit.SECONDS.sleep( 5 );
- long l1 = System.currentTimeMillis();
- for ( int i = 0; i < 10_000_000; i++ )
+ StringBuilder s = new StringBuilder( 1100 );
+ for ( int i = 0; i < 11; i++ )
{
- decoder
- .reset()
- .decode( buffer, chars, true ); // CharsetDecoder 71 nanos
- chars.flip().toString();//CharsetDecoder + toString = 91 nanos
- buffer.clear();
- chars.clear();
+ s.append( PATTERN1 );
}
- long l2 = System.currentTimeMillis();
- System.out.println(l2 - l1);
- }
- @Test
- public void test7() throws Exception {
- byte[] b = {};
- TimeUnit.SECONDS.sleep( 2 );
- System.gc();
- TimeUnit.SECONDS.sleep( 5 );
- String s = null;
- long l1 = System.currentTimeMillis();
- for (int i = 0; i < 10_000_000; i++) {
- s = new String(b, UTF_8);
- }
+ Channel channel = new Channel( s.toString().getBytes( UTF_8 ), s.length() );
+ channel.read( ByteBuffer.allocate( 997 ) );
- long l2 = System.currentTimeMillis();
- System.out.println(l2 - l1);
- System.out.println(s);
- }
+ EventConsumerThread thread = new EventConsumerThread( "t", channel,
+ new MockEventHandler<Event>(), COUNTDOWN_CLOSEABLE, new MockForkNodeArguments() );
- @Test
- public void test8() {
- ForkedProcessEventType[] enums = ForkedProcessEventType.values();
- SortedSet<Integer> s = new TreeSet<>();
- for (ForkedProcessEventType e : enums) {
- if (s.contains( e.getOpcode().length() )) {
- System.out.println("obsahuje " + e + " s dlzkou " + e.getOpcode().length() + " s has codom " + e.getOpcode().hashCode());
- }
- s.add( e.getOpcode().length() );
- }
+ Memento memento = thread.new Memento();
+ memento.bb.limit( 0 );
+ assertThat( thread.readString( memento, PATTERN1.length() ) )
+ .isEqualTo( "789" + PATTERN1.substring( 0, 97 ) );
}
@Test
- public void test9() throws InterruptedException
+ public void shouldReadMultipleStringsAndShiftedInput() throws Exception
{
- ForkedProcessEventType[] enums = ForkedProcessEventType.values();
- TreeMap<Integer, ForkedProcessEventType> map = new TreeMap<>();
- for (ForkedProcessEventType e : enums) {
- map.put( e.getOpcode().hashCode(), e );
+ StringBuilder s = new StringBuilder( 5000 );
+
+ for ( int i = 0; i < 50; i++ )
+ {
+ s.append( PATTERN1 );
}
- TimeUnit.SECONDS.sleep( 2 );
- System.gc();
- TimeUnit.SECONDS.sleep( 5 );
- ForkedProcessEventType s = null;
- int hash = ForkedProcessEventType.BOOTERCODE_STDOUT.hashCode();
- long l1 = System.currentTimeMillis();
- for (int i = 0; i < 10_000_000; i++) {
- s = map.get( hash );
+
+ Channel channel = new Channel( s.toString().getBytes( UTF_8 ), s.length() );
+ channel.read( ByteBuffer.allocate( 1997 ) );
+
+ EventConsumerThread thread = new EventConsumerThread( "t", channel,
+ new MockEventHandler<Event>(), COUNTDOWN_CLOSEABLE, new MockForkNodeArguments() );
+
+ Memento memento = thread.new Memento();
+ // whatever position will be compacted to 0
+ memento.bb.position( 974 ).limit( 974 );
+
+ StringBuilder expected = new StringBuilder( "789" );
+ for ( int i = 0; i < 11; i++ )
+ {
+ expected.append( PATTERN1 );
}
- long l2 = System.currentTimeMillis();
- System.out.println(l2 - l1);
- System.out.println(s);
+ expected.setLength( 1100 );
+ assertThat( thread.readString( memento, 1100 ) )
+ .isEqualTo( expected.toString() );
}
@Test
- public void test10() throws InterruptedException
+ public void shouldDecode3BytesEncodedSymbol() throws Exception
{
- ForkedProcessEventType[] enums = ForkedProcessEventType.values();
- Map<Segment, ForkedProcessEventType> map = new HashMap<>();
- for (ForkedProcessEventType e : enums) {
- byte[] array = e.getOpcode().getBytes();
- map.put( new Segment( array, 0, array.length ), e );
- }
- TimeUnit.SECONDS.sleep( 2 );
- System.gc();
- TimeUnit.SECONDS.sleep( 5 );
- ForkedProcessEventType s = null;
- byte[] array = ForkedProcessEventType.BOOTERCODE_STDOUT.getOpcode().getBytes();
- Segment segment = new Segment( array, 0, array.length );
- long l1 = System.currentTimeMillis();
- for (int i = 0; i < 10_000_000; i++) {
- s = map.get( new Segment( array, 0, array.length ) ); // 33.7 nanos
+ byte[] encodedSymbol = new byte[] {(byte) -30, (byte) -126, (byte) -84};
+ int countSymbols = 1024;
+ byte[] input = new byte[encodedSymbol.length * countSymbols];
+ for ( int i = 0; i < countSymbols; i++ )
+ {
+ System.arraycopy( encodedSymbol, 0, input, encodedSymbol.length * i, encodedSymbol.length );
}
- long l2 = System.currentTimeMillis();
- System.out.println(l2 - l1);
- System.out.println(s);
+
+ Channel channel = new Channel( input, 2 );
+ EventConsumerThread thread = new EventConsumerThread( "t", channel,
+ new MockEventHandler<Event>(), COUNTDOWN_CLOSEABLE, new MockForkNodeArguments() );
+ Memento memento = thread.new Memento();
+ memento.bb.position( 0 ).limit( 0 );
+ String decodedOutput = thread.readString( memento, input.length );
+
+ assertThat( decodedOutput )
+ .isEqualTo( new String( input, 0, input.length, UTF_8 ) );
}
@Test
- public void test11() throws InterruptedException
+ public void shouldDecode100Bytes()
{
- CharsetDecoder decoder = STREAM_ENCODING.newDecoder()
+ CharsetDecoder decoder = DEFAULT_STREAM_ENCODING.newDecoder()
.onMalformedInput( REPLACE )
.onUnmappableCharacter( REPLACE );
- ByteBuffer buffer = ByteBuffer.wrap( ForkedProcessEventType.BOOTERCODE_STDOUT.getOpcode().getBytes( UTF_8 ) );
+ // empty stream: CharsetDecoder + ByteBuffer.allocate( 0 ) makes 11.5 nanos
+ // empty stream: CharsetDecoder + ByteBuffer.allocate( 0 ) + toString() makes 16.1 nanos
+ ByteBuffer buffer = ByteBuffer.wrap( PATTERN1.getBytes( UTF_8 ) );
CharBuffer chars = CharBuffer.allocate( 100 );
+ /* uncomment this section for a proper measurement of the exec time
TimeUnit.SECONDS.sleep( 2 );
System.gc();
TimeUnit.SECONDS.sleep( 5 );
+ */
+ String s = null;
long l1 = System.currentTimeMillis();
for ( int i = 0; i < 10_000_000; i++ )
{
- decoder
- .reset()
- .decode( buffer, chars, true );
- String s = chars.flip().toString(); // 37 nanos = CharsetDecoder + toString
+ decoder.reset()
+ .decode( buffer, chars, true ); // CharsetDecoder 71 nanos
+ s = chars.flip().toString(); // CharsetDecoder + toString = 91 nanos
buffer.clear();
chars.clear();
- ForkedProcessEventType.byOpcode( s ); // 65 nanos = CharsetDecoder + toString + byOpcode
}
long l2 = System.currentTimeMillis();
- System.out.println(l2 - l1);
+ System.out.println( "decoded 100 bytes within " + ( l2 - l1 ) );
+ assertThat( s )
+ .isEqualTo( PATTERN1 );
}
- @Test
- public void test12() throws InterruptedException
+ private static class Channel implements ReadableByteChannel
{
- StringBuilder builder = new StringBuilder( 256 );
- TimeUnit.SECONDS.sleep( 2 );
- System.gc();
- TimeUnit.SECONDS.sleep( 5 );
- byte[] array = ForkedProcessEventType.BOOTERCODE_STDOUT.getOpcode().getBytes();
- long l1 = System.currentTimeMillis();
- for (int i = 0; i < 10_000_000; i++) {
- builder.setLength( 0 );
- for ( byte b : array )
- {
- char c = (char) b;
- if ( c == ':' ) break;
- builder.append( c );
- }
- }
- long l2 = System.currentTimeMillis();
- System.out.println(l2 - l1);
- System.out.println( builder.toString() );
- }
-
- private static class Segment {
- private final byte[] array;
- private final int fromIndex;
- private final int length;
- private final int hashCode;
-
- public Segment( byte[] array, int fromIndex, int length )
- {
- this.array = array;
- this.fromIndex = fromIndex;
- this.length = length;
-
- int hashCode = 0;
- int i = fromIndex;
- for (int loops = length >> 1; loops-- != 0; )
- {
- hashCode = 31 * hashCode + array[i++];
- hashCode = 31 * hashCode + array[i++];
- }
- this.hashCode = i == fromIndex + length ? hashCode : 31 * hashCode + array[i];
- }
+ private final byte[] bytes;
+ private final int chunkSize;
+ private int i;
- @Override
- public int hashCode()
+ public Channel( byte[] bytes, int chunkSize )
{
- return hashCode;
+ this.bytes = bytes;
+ this.chunkSize = chunkSize;
}
@Override
- public boolean equals( Object obj )
+ public int read( ByteBuffer dst )
{
- if ( !( obj instanceof Segment ) )
+ if ( i == bytes.length )
{
- return false;
+ return -1;
}
-
- Segment that = (Segment) obj;
- if ( that.length != length )
+ else if ( dst.hasRemaining() )
{
- return false;
+ int length = min( min( chunkSize, bytes.length - i ), dst.remaining() ) ;
+ dst.put( bytes, i, length );
+ i += length;
+ return length;
}
-
- for ( int i = 0; i < length; i++ )
+ else
{
- if ( that.array[that.fromIndex + i] != array[fromIndex + i] )
- {
- return false;
- }
+ return 0;
}
- return true;
}
- }
-
- private static String toString( List<String> strings )
- {
- if ( strings.size() == 1 )
+ @Override
+ public boolean isOpen()
{
- return strings.get( 0 );
+ return false;
}
- StringBuilder concatenated = new StringBuilder();
- for ( String s : strings )
+
+ @Override
+ public void close()
{
- concatenated.append( s );
}
- return concatenated.toString();
}
- private StreamReadStatus read( ByteBuffer buffer, int recommendedCount ) throws IOException
+ private static class MockCloseable implements Closeable
{
- if ( buffer.remaining() >= recommendedCount && buffer.position() != 0 )
+ @Override
+ public void close()
{
- return OVERFLOW;
}
- else
+ }
+
+ private static class MockEventHandler<T> implements EventHandler<T>
+ {
+ @Override
+ public void handleEvent( @Nonnull T event )
{
- int mark = buffer.position();
- buffer.position( buffer.limit() );
- buffer.limit( buffer.capacity() );
- boolean isEnd = false;
- while ( !isEnd && buffer.position() - mark < recommendedCount && buffer.position() != buffer.limit() )
- {
- isEnd = channel.read( buffer ) == -1;
- }
- buffer.limit( buffer.position() );
- buffer.position( mark );
- return isEnd ? EOF : ( buffer.remaining() >= recommendedCount ? OVERFLOW : UNDERFLOW );
}
}
- private static class Channel implements ReadableByteChannel
+ private static class MockForkNodeArguments implements ForkNodeArguments
{
- private final byte[] bytes;
- private final int chunkSize;
- private int i;
-
- public Channel( byte[] bytes, int chunkSize )
+ @Nonnull
+ @Override
+ public String getSessionId()
{
- this.bytes = bytes;
- this.chunkSize = chunkSize;
+ return null;
}
- public void reset()
+ @Override
+ public int getForkChannelId()
{
- i = 0;
+ return 0;
}
+ @Nonnull
@Override
- public int read( ByteBuffer dst )
+ public File dumpStreamText( @Nonnull String text )
{
- if ( i == bytes.length )
- {
- return -1;
- }
- else if ( dst.hasRemaining() )
- {
- int length = Math.min( chunkSize, bytes.length - i );
- dst.put( bytes, i, length );
- i += length;
- return length;
- }
- else
- {
- return 0;
- }
+ return null;
}
+ @Nonnull
@Override
- public boolean isOpen()
+ public File dumpStreamException( Throwable t )
{
- return false;
+ return null;
}
@Override
- public void close() throws IOException
+ public void logWarningAtEnd( @Nonnull String text )
{
}
- }
- enum StreamReadStatus
- {
- UNDERFLOW,
- OVERFLOW,
- EOF
+ @Nonnull
+ @Override
+ public ConsoleLogger getConsoleLogger()
+ {
+ return null;
+ }
}
}