Package br.eti.kinoshita.tap4j.consumer

Source Code of br.eti.kinoshita.tap4j.consumer.DefaultTapConsumer

/*
* The MIT License
*
* Copyright (c) <2010> <Bruno P. Kinoshita>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package br.eti.kinoshita.tap4j.consumer;

import java.io.File;
import java.io.PrintWriter;
import java.util.List;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang.StringUtils;

import br.eti.kinoshita.tap4j.model.BailOut;
import br.eti.kinoshita.tap4j.model.Comment;
import br.eti.kinoshita.tap4j.model.Directive;
import br.eti.kinoshita.tap4j.model.Footer;
import br.eti.kinoshita.tap4j.model.Header;
import br.eti.kinoshita.tap4j.model.Plan;
import br.eti.kinoshita.tap4j.model.SkipPlan;
import br.eti.kinoshita.tap4j.model.TapResult;
import br.eti.kinoshita.tap4j.model.TestResult;
import br.eti.kinoshita.tap4j.model.TestSet;
import br.eti.kinoshita.tap4j.model.Text;
import br.eti.kinoshita.tap4j.util.DirectiveValues;
import br.eti.kinoshita.tap4j.util.StatusValues;

/**
* @author Bruno P. Kinoshita - http://www.kinoshita.eti.br
* @since 1.0
*/
public class DefaultTapConsumer
extends AbstractTapConsumer
{
  /* -- Regular expressions -- */
 
  public static final String REGEX_HEADER = "\\s*TAP\\s*version\\s*(\\d+)\\s*(#\\s*(.*))?";
 
  public static final String REGEX_PLAN = "\\s*(\\d)+(\\.{2})(\\d)+\\s*(skip\\s*([^#]+))?\\s*(#\\s*(.*))?";
 
  public static final String REGEX_TEST_RESULT = "\\s*(ok|not ok)\\s*(\\d+)?\\s*([^#]*)?\\s*(#\\s*(SKIP|TODO)\\s*([^#]+))?\\s*(#\\s*(.*))?";
 
  public static final String REGEX_BAIL_OUT = "\\s*Bail out!\\s*([^#]+)?\\s*(#\\s*(.*))?";
 
  public static final String REGEX_COMMENT = "\\s*#\\s*(.*)";
 
  public static final String REGEX_FOOTER = "\\s*TAP\\s*([^#]*)?\\s*(#\\s*(.*))?";
 
  /* -- REGEX -- */
  protected Pattern headerREGEX = Pattern.compile( REGEX_HEADER );
  protected Pattern planREGEX = Pattern.compile( REGEX_PLAN );
  protected Pattern testResultREGEX = Pattern.compile( REGEX_TEST_RESULT );
  protected Pattern bailOutREGEX = Pattern.compile ( REGEX_BAIL_OUT );
  protected Pattern commentREGEX = Pattern.compile ( REGEX_COMMENT );
  protected Pattern footerREGEX = Pattern.compile ( REGEX_FOOTER );
 
  protected boolean isFirstLine = true;
 
  protected boolean isHeaderSet = false;
  protected boolean isPlanSet = false;
 
  protected boolean isPlanBeforeTestResult = false;
 
  // Helper String to check the Footer
  protected String lastLine = null;
 
  public boolean isPlanBeforeTestResult()
  {
    return this.isPlanBeforeTestResult;
  }
 
  /* (non-Javadoc)
   * @see br.eti.kinoshita.tap4j.TapConsumer#parseLine(java.lang.String)
   */
  public void parseLine( String tapLine )
  throws TapParserException
  {
    if ( StringUtils.isEmpty( tapLine ) )
    {
      return;
    }
   
    Matcher matcher = null;
   
    // Comment
    matcher = commentREGEX.matcher( tapLine );
    if ( matcher.matches() )
    {
      this.extractComment( matcher );
      return;
    }
   
    // Last line that is not a comment.
    lastLine = tapLine;
   
    // Header
    matcher = headerREGEX.matcher( tapLine );
    if ( matcher.matches() )
    {
     
      this.checkTAPHeaderParsingLocationAndDuplicity();
     
      this.extractHeader ( matcher );
      this.isFirstLine = false;
      return;
    }
   
    // Plan
    matcher = planREGEX.matcher( tapLine );
    if ( matcher.matches() )
    {
     
      this.checkTAPPlanDuplicity();
     
      this.checkIfTAPPlanIsSetBeforeTestResultsOrBailOut();
     
      this.extractPlan ( matcher);
      this.isFirstLine = false;
      return;
    }
   
    // Test Result
    matcher = testResultREGEX.matcher( tapLine );
    if ( matcher.matches() )
    {
      this.extractTestResult ( matcher );
      return;
    }
   
    // Bail Out
    matcher = bailOutREGEX.matcher( tapLine );
    if ( matcher.matches() )
    {
      this.extractBailOut( matcher );
      return;
    }
   
    // Footer
    matcher = footerREGEX.matcher( tapLine );
    if ( matcher.matches() )
    {
      this.extractFooter( matcher );
      return;
    }
   
    // Any text. It should not be parsed by the consumer.
    final Text text = new Text( tapLine );
    this.tapLines.add( text );
  }

  /**
   * Checks if the TAP Plan is set before any Test Result or Bail Out.
   */
  protected void checkIfTAPPlanIsSetBeforeTestResultsOrBailOut()
  {
    if ( this.testResults.size() <= 0 && this.bailOuts.size() <= 0 )
    {
      this.isPlanBeforeTestResult = true;
    }
  }

  /**
   * Checks the Header location and duplicity. The Header must be the first
   * element and cannot occurs more than on time. However the Header is
   * optional.
   */
  protected void checkTAPHeaderParsingLocationAndDuplicity()
  throws TapParserException
  {
    if ( isHeaderSet )
    {
      throw new TapParserException( "Duplicated TAP Header found." );
    }
    if ( ! isFirstLine )
    {
      throw new TapParserException( "Invalid position of TAP Header. It must be the first element (apart of Comments) in the TAP Stream." );
    }
    isHeaderSet = true;
  }
 
  /**
   * Checks if there are more than one TAP Plan in the TAP Stream.
   */
  protected void checkTAPPlanDuplicity()
  throws TapParserException
  {
    if ( isPlanSet )
    {
      throw new TapParserException( "Duplicated TAP Plan found." );
    }
    isPlanSet = true;
  }

  /**
   * This method is called after the TAP Stream has already been parsed.
   * So we just check if the plan was found before test result or bail outs.
   * If so, skip this check. Otherwise, we shall check if the last line
   * is the TAP Plan.
   */
  protected void checkTAPPlanPosition()
  throws TapParserException
  {
    if ( ! this.isPlanBeforeTestResult )
    {
      Matcher matcher = planREGEX.matcher( lastLine );
     
      if ( matcher.matches() )
      {
        return; // OK
      }
     
      throw new TapParserException("Invalid position of TAP Plan.");
    }
  }
 
  /**
   * Extracts the Header from a TAP Line.
   *
   * @param matcher REGEX Matcher.
   */
  protected void extractHeader( Matcher matcher )
  {
    final Integer version = Integer.parseInt( matcher.group( 1 ) );
   
    final Header header = new Header( version );
   
    final String commentToken = matcher.group( 2 );
   
    if ( commentToken != null )
    {
      String text = matcher.group( 3 );
      final Comment comment = new Comment ( text );
      header.setComment( comment );
    }
   
    this.header = header;
  }
 
  /**
   * @param matcher REGEX Matcher.
   */
  protected void extractPlan( Matcher matcher )
  {
    Integer initialTest = Integer.parseInt( matcher.group(1) );
    Integer lastTest = Integer.parseInt( matcher.group(3) );
   
    Plan plan = null;
    plan = new Plan( initialTest, lastTest );
   
    String skipToken = matcher.group(4);
    if ( skipToken != null )
    {
      String reason = matcher.group( 5 );
      final SkipPlan skip = new SkipPlan( reason );
      plan.setSkip(skip);
    }
   
    String commentToken = matcher.group( 6 );
    if ( commentToken != null )
    {
      String text = matcher.group ( 7 );
      final Comment comment = new Comment( text );
      plan.setComment( comment );
    }
   
    this.plan = plan;
  }

  /**
   * @param matcher REGEX Matcher.
   */
  protected void extractTestResult( Matcher matcher )
  {
    TestResult testResult = null;
   
    final String okOrNotOk = matcher.group(1);
    StatusValues status = null;
    if ( okOrNotOk.trim().equals("ok"))
    {
      status = StatusValues.OK;
    }
    else // regex mate...
    {
      status = StatusValues.NOT_OK;
    }
   
    Integer testNumber = Integer.parseInt(matcher.group(2));
    testResult = new TestResult( status, testNumber );     
   
    testResult.setDescription(matcher.group(3));
   
    String directiveToken = matcher.group(4);
    if ( directiveToken != null )
    {
      String directiveText = matcher.group(5);
      DirectiveValues directiveValue = null;
      if ( directiveText.trim().equals("TODO"))
      {
        directiveValue = DirectiveValues.TODO;
      } else
      {
        directiveValue = DirectiveValues.SKIP;
      }
      String reason = matcher.group( 6 );
      Directive directive = new Directive( directiveValue, reason );
      testResult.setDirective( directive );
    }
   
    String commentToken = matcher.group( 7 );
    if ( commentToken != null )
    {
      String text = matcher.group ( 8 );
      final Comment comment = new Comment( text );
      testResult.setComment( comment );
    }
   
    this.testResults.add( testResult );
    this.tapLines.add( testResult );
  }
 
  /**
   * @param matcher REGEX Matcher.
   */
  protected void extractBailOut( Matcher matcher )
  {
    String reason = matcher.group(1);
   
    BailOut bailOut = new BailOut( reason );
   
    String commentToken = matcher.group( 2 );
   
    if ( commentToken != null )
    {
      String text = matcher.group( 3 );
      Comment comment = new Comment( text );
      bailOut.setComment( comment );
    }
   
    this.bailOuts.add( bailOut );
    this.tapLines.add( bailOut );
  }
 
  /**
   * @param matcher REGEX Matcher.
   */
  protected void extractComment( Matcher matcher )
  {
    String text = matcher.group ( 1 );
    Comment comment = new Comment ( text );
   
    this.comments.add( comment );
    this.tapLines.add( comment );
  }
 
  /**
   * Simply extracts the footer from the TAP line.
   *
   * @param matcher REGEX Matcher.
   */
  protected void extractFooter( Matcher matcher )
  {
    String text = matcher.group ( 1 );       
    Footer footer = new Footer( text );
   
    final String commentToken = matcher.group( 2 );
   
    if ( commentToken != null )
    {
      String commentText = matcher.group( 3 );
      final Comment comment = new Comment ( commentText );
      footer.setComment( comment );
    }
   
    this.footer = footer;
  }

  /* (non-Javadoc)
   * @see br.eti.kinoshita.tap4j.TapConsumer#parseTapStream(java.lang.String)
   */
  public void parseTapStream( String tapStream ) throws TapParserException
  {
    Scanner scanner = null;
   
    try
    {
      scanner = new Scanner( tapStream );
      String line = null;
     
      while ( scanner.hasNextLine() )
      {
        line = scanner.nextLine();
        if ( StringUtils.isNotBlank(line) )
        {
          this.parseLine( line );
        }       
      }
     
      this.checkTAPPlanPosition();
    }
    catch ( Exception e )
    {
      throw new TapParserException( "Error parsing TAP Stream: " + e.getMessage(), e );
    }
    finally
    {
      if ( scanner != null )
      {
        scanner.close();
      }
    }
  }

  /* (non-Javadoc)
   * @see br.eti.kinoshita.tap4j.TapConsumer#parseFile(java.io.File)
   */
  public void parseFile( File tapFile ) throws TapParserException
  {
    Scanner scanner = null;
   
    try
    {
      scanner = new Scanner( tapFile );
      String line = null;
     
      while ( scanner.hasNextLine() )
      {
        line = scanner.nextLine();
        if ( StringUtils.isNotBlank(line) )
        {
          this.parseLine( line );
        }
      }
     
      this.checkTAPPlanPosition();
    }
    catch ( Exception e )
    {
      throw new TapParserException( "Error parsing TAP Stream: " + e.getMessage(), e );
    }
    finally
    {
      if ( scanner != null )
      {
        scanner.close();
      }
    }
  }

  /* (non-Javadoc)
   * @see br.eti.kinoshita.tap4j.TapConsumer#printSummary(java.io.PrintWriter)
   */
  public void printSummary( PrintWriter pw )
  {
    TestSet testSet = this.getTestSet();
    String summary = testSet.getSummary();
    pw.println( summary );
  }

  /* (non-Javadoc)
   * @see br.eti.kinoshita.tap4j.TapConsumer#printDetails(java.io.PrintWriter)
   */
  public void printDetails( PrintWriter pw )
  {
    TestSet testSet = this.getTestSet();
    if ( testSet.getHeader() != null )
    {
      pw.println( testSet.getHeader().toString() );
    }
    if ( testSet.getPlan() != null )
    {
      pw.println( testSet.getPlan().toString() );
    }
    List<TapResult> tapLines = testSet.getTapLines();
    for ( TapResult tapLine :  tapLines)
    {
      pw.println( tapLine.toString() );
    }
    if ( testSet.getFooter() != null )
    {
      pw.println( testSet.getFooter().toString() );
    }
  }

}
TOP

Related Classes of br.eti.kinoshita.tap4j.consumer.DefaultTapConsumer

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.