/* Copyright (c) 2003-2007 Ricebridge. All Rights Reserved.
 *
 * This file is available under the terms and conditions of the
 * Ricebridge "Open Source API" policy; Ricebridge grants use of this
 * copyrighted work under the terms of a BSD-style license only. See
 * http://www.opensource.org/licenses/bsd-license.php for more
 * information.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 
 *  - Redistributions of source code must retain the above copyright
 *  notice, this list of conditions and the following disclaimer.
 *
 *  - Redistributions in binary form must reproduce the above
 *  copyright notice, this list of conditions and the following
 *  disclaimer in the documentation and/or other materials provided
 *  with the distribution.
 *
 *  - Neither the name of the Ricebridge nor the names of its
 *  contributors may be used to endorse or promote products derived
 *  from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.  
 */

package com.ricebridge.csvman.test;


import com.ricebridge.csvman.*;
import com.ricebridge.data.Text;

import org.jostraca.util.*;

import junit.framework.*;
import junit.textui.*;

import java.util.*;
import java.io.*;


/** Test cases for {@link com.ricebridge.csvman.CsvHandler}.
 *    <p>The <b><a href="CsvHandlerTest.java.html">Source Code</a></b> of this Java class 
 *    is available under a <a href="http://www.opensource.org/licenses/bsd-license.php">BSD-style license</a>.</p>
 */
public class CsvHandlerTest extends TestCase {

  // standard test methods
  
  public CsvHandlerTest( String pName ) {
    super( pName );
  }

  public static TestSuite suite() {
    return new TestSuite( CsvHandlerTest.class );
  }

  public static void main( String[] pArgs ) {
    TestRunner.run( suite() );
  }


  public void testLifecycle() {
    CsvHandler ch = new CsvHandler();
    ch.setText( new Text("1,foo,\"a\",bar\n2,baz") );
    ch.setCsvSpec( new CsvSpec() );

    TestLineListener ln = new TestLineListener();
    ch.setLineListener( ln );
    ch.load();
    assertEquals( "START:LINE1:LINE2:END:", ln.sb.toString() );
  }



  public void testAddLineReturn() {
    CsvHandler ch = new CsvHandler();
    ch.setText( new Text( "1,11,111\n"+
                          "2,22,222\n"+
                          "bad,line\n"+
                          "3,33,333\n" ) );
    CsvSpec cs = new CsvSpec();
    ch.setCsvSpec( cs );

    // test stop on error
    TestLineListener ln = null;
    try {
      ln = new TestLineListener();
      ch.setLineListener( ln );
      ch.load();
      fail();
    }
    catch( Exception e ) {
      assertEquals( "START:LINE1:LINE2:BAD3:END:", ln.sb.toString() );
      assertEquals( 3, ch.getLineCount() );
      assertEquals( 1, ch.getBadLineCount() );
      assertEquals( "A line was rejected due to invalid data and caused processing to halt. The line was: 'bad,line'.", e.toString() );
      assertEquals( 1, ch.getBadLines().size() );
      assertEquals( "[[CSV:BadLine:3:bad prefix:SEMANTIC:bad,line]]", ch.getBadLines().toString() );
    }

    // test ignore bad lines
    cs.setIgnoreBadLines( true );
    ln = new TestLineListener();
    ch.setLineListener( ln );
    ch.load();
    
    assertEquals( 4, ch.getLineCount() );
    assertEquals( 1, ch.getBadLineCount() );
    assertEquals( 1, ch.getBadLines().size() );
    assertEquals( "[[CSV:BadLine:3:bad prefix:SEMANTIC:bad,line]]", ch.getBadLines().toString() );
    assertEquals( "START:LINE1:LINE2:BAD3:LINE4:END:", ln.sb.toString() );


    // test many bad lines
    ch.setText( new Text( "1,11,111\n"+
                          "bad,line1\n"+
                          "2,22,222\n"+
                          "bad,line2\n"+
                          "3,33,333\n" ) );
    ln = new TestLineListener();
    ch.setLineListener( ln );
    ch.load();
    assertEquals( 5, ch.getLineCount() );
    assertEquals( 2, ch.getBadLineCount() );
    assertEquals( 2, ch.getBadLines().size() );
    assertEquals( "[[CSV:BadLine:2:bad prefix:SEMANTIC:bad,line1], [CSV:BadLine:4:bad prefix:SEMANTIC:bad,line2]]", 
                  ch.getBadLines().toString() );
  }



  public void testSaveBadLines() {
    ArrayList data = new ArrayList();
    data.add( new String[] { "1", "11", "111" }  );
    data.add( new String[] { "2", "22", "222" }  );
    data.add( new String[] { "3", "33", "333" }  );
    
    String gs 
      = "1,11,111\n"
      + "2,22,222\n"
      + "3,33,333\n"
      ;

    CsvHandler ch = new CsvHandler();
    CsvSpec cs = new CsvSpec();
    ch.setCsvSpec( cs );

    TestLineProvider lp = null;
    String           s  = null;
    ByteArrayOutputStream baos = null;

    lp = new TestLineProvider( data );
    ch.setLineProvider( lp ); baos = new ByteArrayOutputStream(); ch.setOutputStream( baos );
    ch.save();    
    s = TextUtil.replace( baos.toString(), "\r\n", "\n" );

    assertEquals( gs, s );
    assertEquals( 3, ch.getLineCount() ); 
    assertEquals( 3, ch.getSavedLines() ); 
    assertEquals( 0, ch.getBadLineCount() ); 
    assertEquals( "[]", ch.getBadLines().toString() );
    assertEquals( "SP:HNL:NL:HNL:NL:HNL:NL:HNL:EP:", 
                  lp.sb.toString() );


    try {
      lp = new TestLineProvider( data );
      lp.iFailOnNextLine = 2;
      ch.setLineProvider( lp ); baos = new ByteArrayOutputStream(); ch.setOutputStream( baos );
      ch.save();    
      fail();
    }
    catch( CsvManagerException csvme ) {
      assertEquals( "SP:HNL:NL:HNL:NL:FAILNL2:EP:", lp.sb.toString() );
      assertTrue( csvme.getBadLine().toString().startsWith("[CSV:BadLine:2:The LineProvider com.ricebridge.csvman.test.CsvHandlerTest$TestLineProvider threw an Exception from method nextLineImpl: java.lang.RuntimeException: nextLine") );
      assertTrue( TextUtil.replace(csvme.getBadLine().toString(),"\r\n","\n").endsWith("no data available for bad line, previous line was: [1, 11, 111]]") );

      assertEquals( 2, ch.getLineCount() );
      assertEquals( 1, ch.getSavedLines() ); 
      assertEquals( 1, ch.getBadLineCount() );
      assertEquals( 1, ch.getBadLines().size() );

      assertTrue( ch.getBadLines().toString().startsWith("[[CSV:BadLine:2:The LineProvider com.ricebridge.csvman.test.CsvHandlerTest$TestLineProvider threw an Exception from method nextLineImpl: java.lang.RuntimeException: nextLine") );
      assertTrue( TextUtil.replace(ch.getBadLines().toString(),"\r\n","\n").endsWith("no data available for bad line, previous line was: [1, 11, 111]]]") );

    }
    catch( Exception e ) {
      e.printStackTrace();
      fail();
    }


    cs.setIgnoreBadLines( true );    
    lp = new TestLineProvider( data );
    lp.iFailOnNextLine = 2;
    ch.setLineProvider( lp ); baos = new ByteArrayOutputStream(); ch.setOutputStream( baos );
    ch.save();    
    assertEquals( "SP:HNL:NL:HNL:NL:FAILNL2:HNL:NL:HNL:EP:", lp.sb.toString() );
    assertEquals( 3, ch.getLineCount() );
    assertEquals( 2, ch.getSavedLines() ); 
    assertEquals( 1, ch.getBadLineCount() );
    assertEquals( 1, ch.getBadLines().size() );
    assertTrue( ch.getBadLines().toString().startsWith("[[CSV:BadLine:2:The LineProvider com.ricebridge.csvman.test.CsvHandlerTest$TestLineProvider threw an Exception from method nextLineImpl: java.lang.RuntimeException: nextLine") );
    assertTrue( TextUtil.replace(ch.getBadLines().toString(),"\r\n","\n").endsWith("no data available for bad line, previous line was: [1, 11, 111]]]") );


    // hasNextLine fails => line reading stops
    cs.setIgnoreBadLines( true );    
    lp = new TestLineProvider( data );
    lp.iFailOnHasNextLine = 1;
    ch.setLineProvider( lp ); baos = new ByteArrayOutputStream(); ch.setOutputStream( baos );
    ch.save();    
    assertEquals( "SP:HNL:NL:HNL:FAILHNL1:EP:", lp.sb.toString() );
    assertEquals( 2, ch.getLineCount() );
    assertEquals( 1, ch.getSavedLines() ); 
    assertEquals( 1, ch.getBadLineCount() );
    assertEquals( 1, ch.getBadLines().size() );
    assertTrue( ch.getBadLines().toString().startsWith("[[CSV:BadLine:2:The LineProvider com.ricebridge.csvman.test.CsvHandlerTest$TestLineProvider threw an Exception from method hasNextLineImpl: java.lang.RuntimeException: hasNextLine") );


    cs.setIgnoreBadLines( true );    
    lp = new TestLineProvider( data );
    lp.iFailOnStartSave = true;
    ch.setLineProvider( lp ); baos = new ByteArrayOutputStream(); ch.setOutputStream( baos );
    ch.save();    
    assertEquals( "SP:FAILSS:EP:", lp.sb.toString() );
    assertEquals( 0, ch.getLineCount() );
    assertEquals( 0, ch.getSavedLines() ); 
    assertEquals( 1, ch.getBadLineCount() );
    assertEquals( 1, ch.getBadLines().size() );

    cs.setIgnoreBadLines( true );    
    lp = new TestLineProvider( data );
    lp.iFailOnEndSave = true;
    ch.setLineProvider( lp ); baos = new ByteArrayOutputStream(); ch.setOutputStream( baos );
    ch.save();    
    assertEquals( "SP:HNL:NL:HNL:NL:HNL:NL:HNL:EP:FAILES:", lp.sb.toString() );
    assertEquals( 3, ch.getLineCount() );
    assertEquals( 3, ch.getSavedLines() ); 
    assertEquals( 1, ch.getBadLineCount() );
    assertEquals( 1, ch.getBadLines().size() );
  }



  /** Test LineListener */
  public static final class TestLineListener extends CustomLineListener {
    public StringBuffer sb = new StringBuffer();
    public StringBuffer data = new StringBuffer();

    public void startProcessImpl() {
      sb.append("START:");
    }
    public void endProcessImpl() {
      sb.append("END:");
    }
    public BadLine handleLineImpl( String[] pLine, int pNumFields, long pLineNumber, String pOriginalLine ) {
      if( "bad".equals(pLine[0]) ) {
        sb.append("BAD"+pLineNumber+":");
        return new BadLine( pLineNumber, pOriginalLine, "bad prefix" );
      }
      sb.append("LINE"+pLineNumber+":");
      data.append( Arrays.asList(pLine)+"\n" );
      return null;
    }
    public void handleBadLineImpl( BadLine pBadLine ) throws Exception {
      super.handleBadLineImpl( pBadLine );
      sb.append("BAD:");
    }
  }



  public static final class TestLineProvider extends CustomLineProvider {

    public StringBuffer sb = new StringBuffer();

    public boolean iFailOnStartSave    = false;
    public boolean iFailOnEndSave      = false;
    public int     iFailOnNextLine     = -1;
    //public int     iFailOnNextField    = -1;
    public int     iFailOnHasNextLine  = -1;
    //public int     iFailOnHasNextField = -1;


    protected List     iData        = null;
    //protected String[] iCurrentLine = null;
    protected long     iLineIndex   = 0;
    //protected int      iFieldIndex  = 0;

    public TestLineProvider( List pData ) {
      iData = pData;
    }

    public void startProcessImpl() {
      sb.append("SP:");
      if( iFailOnStartSave ) { sb.append("FAILSS:"); throw new RuntimeException("startSave"); }
      //iCurrentLine = null;
      iLineIndex   = 0;
      //iFieldIndex  = 0;
    }

    public void endProcessImpl() {
      sb.append("EP:");
      if( iFailOnEndSave ) { sb.append("FAILES:"); throw new RuntimeException("endSave"); }
      // do nothing
    }

    public boolean hasNextLineImpl() {
      sb.append("HNL:");
      if( iLineIndex == iFailOnHasNextLine ) { sb.append("FAILHNL"+iLineIndex+":"); throw new RuntimeException("hasNextLine"); }
      return iLineIndex < iData.size();
    }

    /*
    public boolean hasNextFieldImpl() {
      sb.append("HNF:");
      if( iFieldIndex == iFailOnHasNextField ) { sb.append("FAILHNF:"); throw new RuntimeException("hasNextField"); }
      return iFieldIndex < iCurrentLine.length;
    }
    
    public String  nextFieldImpl() {
      sb.append("NF:");
      String out = iCurrentLine[iFieldIndex++];
      if( iFieldIndex == iFailOnNextField ) { sb.append("FAILNF:"); throw new RuntimeException("nextField"); }
      return out;
    }
    */

    public String[] nextLineImpl() {
      sb.append("NL:");
      String[] line = (String[]) iData.get( (int) iLineIndex );
      iLineIndex++;
      if( iLineIndex == iFailOnNextLine ) { sb.append("FAILNL"+iLineIndex+":"); throw new RuntimeException("nextLine"); }
      return line;
    }
  }


}



Syntax Highlighting created using the com.Ostermiller.Syntax package.
Wednesday, June 20 2007 at 22:16