Package org.apache.maven.surefire.booter

Source Code of org.apache.maven.surefire.booter.ForkingRunListener

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.io.PrintStream;
import java.util.Enumeration;
import java.util.Properties;

import org.apache.maven.surefire.report.ConsoleLogger;
import org.apache.maven.surefire.report.ConsoleOutputReceiver;
import org.apache.maven.surefire.report.ReportEntry;
import org.apache.maven.surefire.report.RunListener;
import org.apache.maven.surefire.report.SafeThrowable;
import org.apache.maven.surefire.report.StackTraceWriter;
import org.apache.maven.surefire.util.internal.StringUtils;

/**
* Encodes the full output of the test run to the stdout stream.
* <p/>
* This class and the ForkClient contain the full definition of the
* "wire-level" protocol used by the forked process. The protocol
* is *not* part of any public api and may change without further
* notice.
* <p/>
* This class is threadsafe.
* <p/>
* The synchronization in the underlying PrintStream (target instance)
* is used to preserve thread safety of the output stream. To perform
* multiple writes/prints for a single request, they must
* synchronize on "target" variable in this class.
*
* @author Kristian Rosenvold
*/
public class ForkingRunListener
    implements RunListener, ConsoleLogger, ConsoleOutputReceiver
{
    public static final byte BOOTERCODE_TESTSET_STARTING = (byte) '1';

    public static final byte BOOTERCODE_TESTSET_COMPLETED = (byte) '2';

    public static final byte BOOTERCODE_STDOUT = (byte) '3';

    public static final byte BOOTERCODE_STDERR = (byte) '4';

    public static final byte BOOTERCODE_TEST_STARTING = (byte) '5';

    public static final byte BOOTERCODE_TEST_SUCCEEDED = (byte) '6';

    public static final byte BOOTERCODE_TEST_ERROR = (byte) '7';

    public static final byte BOOTERCODE_TEST_FAILED = (byte) '8';

    public static final byte BOOTERCODE_TEST_SKIPPED = (byte) '9';

    public static final byte BOOTERCODE_TEST_ASSUMPTIONFAILURE = (byte) 'G';

    public static final byte BOOTERCODE_CONSOLE = (byte) 'H';

    public static final byte BOOTERCODE_SYSPROPS = (byte) 'I';

    public static final byte BOOTERCODE_NEXT_TEST = (byte) 'N';

    public static final byte BOOTERCODE_ERROR = (byte) 'X';

    public static final byte BOOTERCODE_BYE = (byte) 'Z';


    private final PrintStream target;

    private final Integer testSetChannelId;

    private final boolean trimStackTraces;

    private final byte[] stdOutHeader;

    private final byte[] stdErrHeader;

    public ForkingRunListener( PrintStream target, int testSetChannelId, boolean trimStackTraces )
    {
        this.target = target;
        this.testSetChannelId = testSetChannelId;
        this.trimStackTraces = trimStackTraces;
        stdOutHeader = createHeader( BOOTERCODE_STDOUT, testSetChannelId );
        stdErrHeader = createHeader( BOOTERCODE_STDERR, testSetChannelId );
        sendProps();
    }

    public void testSetStarting( ReportEntry report )
    {
        target.print( toString( BOOTERCODE_TESTSET_STARTING, report, testSetChannelId ) );
    }

    public void testSetCompleted( ReportEntry report )
    {
        target.print( toString( BOOTERCODE_TESTSET_COMPLETED, report, testSetChannelId ) );
    }

    public void testStarting( ReportEntry report )
    {
        target.print( toString( BOOTERCODE_TEST_STARTING, report, testSetChannelId ) );
    }

    public void testSucceeded( ReportEntry report )
    {
        target.print( toString( BOOTERCODE_TEST_SUCCEEDED, report, testSetChannelId ) );
    }

    public void testAssumptionFailure( ReportEntry report )
    {
        target.print( toString( BOOTERCODE_TEST_ASSUMPTIONFAILURE, report, testSetChannelId ) );
    }

    public void testError( ReportEntry report )
    {
        target.print( toString( BOOTERCODE_TEST_ERROR, report, testSetChannelId ) );
    }

    public void testFailed( ReportEntry report )
    {
        target.print( toString( BOOTERCODE_TEST_FAILED, report, testSetChannelId ) );
    }

    public void testSkipped( ReportEntry report )
    {
        target.print( toString( BOOTERCODE_TEST_SKIPPED, report, testSetChannelId ) );
    }

    void sendProps()
    {
        Properties systemProperties = System.getProperties();

        if ( systemProperties != null )
        {
            Enumeration propertyKeys = systemProperties.propertyNames();

            while ( propertyKeys.hasMoreElements() )
            {
                String key = (String) propertyKeys.nextElement();

                String value = systemProperties.getProperty( key );

                if ( value == null )
                {
                    value = "null";
                }
                target.print( toPropertyString( key, value ) );
            }
        }
    }

    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 = StringUtils.escapeBytesToPrintable( content, 0, buf, off, len );
        content[i++] = (byte) '\n';

        synchronized ( target ) // See notes about synchronization/thread safety in class javadoc
        {
            target.write( header, 0, header.length );
            target.write( content, 0, i );
        }
    }

    public static byte[] createHeader( byte booterCode, int testSetChannel )
    {
        byte[] header = new byte[7];
        header[0] = booterCode;
        header[1] = (byte) ',';
        header[6] = (byte) ',';

        int i = testSetChannel;
        int charPos = 6;
        int radix = 1 << 4;
        int mask = radix - 1;
        do
        {
            header[--charPos] = (byte) digits[i & mask];
            i >>>= 4;
        }
        while ( i != 0 );

        while ( charPos > 2 )
        {
            header[--charPos] = (byte) '0';
        }
        return header;
    }

    private final static char[] digits =
        { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
            'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' };


    public void info( String message )
    {
        if ( message == null )
        {
            return;
        }

        StringBuilder sb = new StringBuilder( 7 + message.length() * 5 );
        append( sb, BOOTERCODE_CONSOLE );comma( sb );
        append( sb, Integer.toHexString( testSetChannelId ) );comma( sb );
        StringUtils.escapeToPrintable( sb, message );

        sb.append( '\n' );
        target.print( sb.toString() );
    }

    private String toPropertyString( String key, String value )
    {
        StringBuilder stringBuilder = new StringBuilder();

        append( stringBuilder, BOOTERCODE_SYSPROPS );comma( stringBuilder );
        append( stringBuilder, Integer.toHexString( testSetChannelId ) );comma( stringBuilder );

        StringUtils.escapeToPrintable( stringBuilder, key );
        comma( stringBuilder );
        StringUtils.escapeToPrintable( stringBuilder, value );
        stringBuilder.append( "\n" );
        return stringBuilder.toString();
    }

    private String toString( byte operationCode, ReportEntry reportEntry, Integer testSetChannelId )
    {
        StringBuilder stringBuilder = new StringBuilder();
        append( stringBuilder, operationCode ); comma( stringBuilder );
        append( stringBuilder, Integer.toHexString( testSetChannelId ) );comma( stringBuilder );

        nullableEncoding( stringBuilder, reportEntry.getSourceName() );
        comma( stringBuilder );
        nullableEncoding( stringBuilder, reportEntry.getName() );
        comma( stringBuilder );
        nullableEncoding( stringBuilder, reportEntry.getGroup() );
        comma( stringBuilder );
        nullableEncoding( stringBuilder, reportEntry.getMessage() );
        comma( stringBuilder );
        nullableEncoding( stringBuilder, reportEntry.getElapsed() );
        encode( stringBuilder, reportEntry.getStackTraceWriter() );
        stringBuilder.append( "\n" );
        return stringBuilder.toString();
    }

    private static void comma( StringBuilder stringBuilder )
    {
        stringBuilder.append( "," );
    }

    private ForkingRunListener append( StringBuilder stringBuilder, String message )
    {
        stringBuilder.append( encode( message ) );
        return this;
    }

    private ForkingRunListener 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() );
        }
    }

    private String encode( String source )
    {
        return source;
    }


    private static void nullableEncoding( StringBuilder stringBuilder, String source )
    {
        if ( source == null || source.length() == 0 )
        {
            stringBuilder.append( "null" );
        }
        else
        {
            StringUtils.escapeToPrintable( stringBuilder, source );
        }
    }

    private void encode( StringBuilder stringBuilder, StackTraceWriter stackTraceWriter )
    {
        encode( stringBuilder, stackTraceWriter, trimStackTraces );
    }

    public static void encode( StringBuilder stringBuilder, StackTraceWriter stackTraceWriter, boolean trimStackTraces )
    {
        if ( stackTraceWriter != null )
        {
            comma( stringBuilder );
            //noinspection ThrowableResultOfMethodCallIgnored
            final SafeThrowable throwable = stackTraceWriter.getThrowable();
            if ( throwable != null )
            {
                String message = throwable.getLocalizedMessage();
                nullableEncoding( stringBuilder, message );
            }
            comma( stringBuilder );
            nullableEncoding( stringBuilder, stackTraceWriter.smartTrimmedStackTrace() );
            comma( stringBuilder );
            nullableEncoding( stringBuilder, trimStackTraces
                ? stackTraceWriter.writeTrimmedTraceToString()
                : stackTraceWriter.writeTraceToString() );
        }
    }
}
TOP

Related Classes of org.apache.maven.surefire.booter.ForkingRunListener

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.