You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@poi.apache.org by jo...@apache.org on 2008/12/01 20:59:47 UTC

svn commit: r722206 - in /poi/trunk/src: documentation/content/xdocs/ java/org/apache/poi/hssf/record/aggregates/ testcases/org/apache/poi/hssf/record/aggregates/

Author: josh
Date: Mon Dec  1 11:59:46 2008
New Revision: 722206

URL: http://svn.apache.org/viewvc?rev=722206&view=rev
Log:
Fix for bug 46312 - ValueRecordsAggregate should handle removal of new empty row

Modified:
    poi/trunk/src/documentation/content/xdocs/changes.xml
    poi/trunk/src/documentation/content/xdocs/status.xml
    poi/trunk/src/java/org/apache/poi/hssf/record/aggregates/ValueRecordsAggregate.java
    poi/trunk/src/testcases/org/apache/poi/hssf/record/aggregates/TestValueRecordsAggregate.java

Modified: poi/trunk/src/documentation/content/xdocs/changes.xml
URL: http://svn.apache.org/viewvc/poi/trunk/src/documentation/content/xdocs/changes.xml?rev=722206&r1=722205&r2=722206&view=diff
==============================================================================
--- poi/trunk/src/documentation/content/xdocs/changes.xml (original)
+++ poi/trunk/src/documentation/content/xdocs/changes.xml Mon Dec  1 11:59:46 2008
@@ -37,6 +37,7 @@
 
 		<!-- Don't forget to update status.xml too! -->
         <release version="3.5-beta5" date="2008-??-??">
+           <action dev="POI-DEVELOPERS" type="fix">46312 - Fixed ValueRecordsAggregate to handle removal of new empty row</action>
            <action dev="POI-DEVELOPERS" type="add">46269 - Improved error message when attempting to read BIFF2 file</action>
            <action dev="POI-DEVELOPERS" type="fix">46206 - Fixed Sheet to tolerate missing DIMENSION records</action>
            <action dev="POI-DEVELOPERS" type="add">46301 - added pivot table records: SXDI, SXVDEX, SXPI, SXIDSTM, SXVIEW, SXVD, SXVS, et al</action>

Modified: poi/trunk/src/documentation/content/xdocs/status.xml
URL: http://svn.apache.org/viewvc/poi/trunk/src/documentation/content/xdocs/status.xml?rev=722206&r1=722205&r2=722206&view=diff
==============================================================================
--- poi/trunk/src/documentation/content/xdocs/status.xml (original)
+++ poi/trunk/src/documentation/content/xdocs/status.xml Mon Dec  1 11:59:46 2008
@@ -34,6 +34,7 @@
 	<!-- Don't forget to update changes.xml too! -->
     <changes>
         <release version="3.5-beta5" date="2008-??-??">
+           <action dev="POI-DEVELOPERS" type="fix">46312 - Fixed ValueRecordsAggregate to handle removal of new empty row</action>
            <action dev="POI-DEVELOPERS" type="add">46269 - Improved error message when attempting to read BIFF2 file</action>
            <action dev="POI-DEVELOPERS" type="fix">46206 - Fixed Sheet to tolerate missing DIMENSION records</action>
            <action dev="POI-DEVELOPERS" type="add">46301 - added pivot table records: SXDI, SXVDEX, SXPI, SXIDSTM, SXVIEW, SXVD, SXVS, et al</action>

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/aggregates/ValueRecordsAggregate.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/aggregates/ValueRecordsAggregate.java?rev=722206&r1=722205&r2=722206&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/aggregates/ValueRecordsAggregate.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/aggregates/ValueRecordsAggregate.java Mon Dec  1 11:59:46 2008
@@ -40,279 +40,291 @@
  * @author Jason Height (jheight at chariot dot net dot au)
  */
 public final class ValueRecordsAggregate {
-    private int firstcell = -1;
-    private int lastcell  = -1;
-    private CellValueRecordInterface[][] records;
-
-    /** Creates a new instance of ValueRecordsAggregate */
-
-    public ValueRecordsAggregate()
-    {
-        records = new CellValueRecordInterface[30][]; // We start with 30 Rows.
-    }
-
-  public void insertCell(CellValueRecordInterface cell) {
-    short column = cell.getColumn();
-    int row = cell.getRow();
-    if (row >= records.length) {
-      CellValueRecordInterface[][] oldRecords = records;
-      int newSize = oldRecords.length * 2;
-      if(newSize<row+1) newSize=row+1;
-      records = new CellValueRecordInterface[newSize][];
-      System.arraycopy(oldRecords, 0, records, 0, oldRecords.length);
-    }
-    CellValueRecordInterface[] rowCells = records[row];
-    if (rowCells == null) {
-      int newSize = column + 1;
-      if(newSize<10) newSize=10;
-      rowCells = new CellValueRecordInterface[newSize];
-      records[row] = rowCells;
-    }
-    if (column >= rowCells.length) {
-      CellValueRecordInterface[] oldRowCells = rowCells;
-      int newSize = oldRowCells.length * 2;
-      if(newSize<column+1) newSize=column+1;
-      // if(newSize>257) newSize=257; // activate?
-      rowCells = new CellValueRecordInterface[newSize];
-      System.arraycopy(oldRowCells, 0, rowCells, 0, oldRowCells.length);
-      records[row] = rowCells;
-    }
-    rowCells[column] = cell;
-
-    if ((column < firstcell) || (firstcell == -1)) {
-      firstcell = column;
-    }
-    if ((column > lastcell) || (lastcell == -1)) {
-      lastcell = column;
-    }
-  }
-
-    public void removeCell(CellValueRecordInterface cell) {
-        if (cell == null) {
-            throw new IllegalArgumentException("cell must not be null");
-        }
-        int row = cell.getRow();
-        if (row >= records.length) {
-            throw new RuntimeException("cell row is out of range");
-        }
-        CellValueRecordInterface[] rowCells = records[row];
-        if (rowCells == null) {
-            throw new RuntimeException("cell row is already empty");
-        }
-        short column = cell.getColumn();
-        if (column >= rowCells.length) {
-            throw new RuntimeException("cell column is out of range");
-        }
-        rowCells[column] = null;
-    }
-
-    public void removeAllCellsValuesForRow(int rowIndex) {
-        if (rowIndex >= records.length) {
-            throw new IllegalArgumentException("Specified rowIndex " + rowIndex
-                    + " is outside the allowable range (0.." +records.length + ")");
-        }
-        records[rowIndex] = null;
-    }
-
-
-    public int getPhysicalNumberOfCells()
-    {
-    int count=0;
-    for(int r=0;r<records.length;r++) {
-      CellValueRecordInterface[] rowCells=records[r];
-      if (rowCells != null)
-        for(short c=0;c<rowCells.length;c++) {
-          if(rowCells[c]!=null) count++;
-        }
-    }
-    return count;
-    }
-
-    public int getFirstCellNum()
-    {
-        return firstcell;
-    }
-
-    public int getLastCellNum()
-    {
-        return lastcell;
-    }
-
-    /**
-     * Processes a single cell value record
-     * @param sfh used to resolve any shared-formulas/arrays/tables for the current sheet
-     */
-    public void construct(CellValueRecordInterface rec, RecordStream rs, SharedValueManager sfh) {
-        if (rec instanceof FormulaRecord) {
-            FormulaRecord formulaRec = (FormulaRecord)rec;
-            // read optional cached text value
-            StringRecord cachedText;
-            Class nextClass = rs.peekNextClass();
-            if (nextClass == StringRecord.class) {
-                cachedText = (StringRecord) rs.getNext();
-            } else {
-                cachedText = null;
-            }
-            insertCell(new FormulaRecordAggregate(formulaRec, cachedText, sfh));
-        } else {
-            insertCell(rec);
-        }
-    }
-
-    /** Tallies a count of the size of the cell records
-     *  that are attached to the rows in the range specified.
-     */
-    public int getRowCellBlockSize(int startRow, int endRow) {
-      MyIterator itr = new MyIterator(startRow, endRow);
-      int size = 0;
-      while (itr.hasNext()) {
-        CellValueRecordInterface cell = (CellValueRecordInterface)itr.next();
-        int row = cell.getRow();
-        if (row > endRow)
-          break;
-        if ((row >=startRow) && (row <= endRow))
-          size += ((RecordBase)cell).getRecordSize();
-      }
-      return size;
-    }
-
-    /** Returns true if the row has cells attached to it */
-    public boolean rowHasCells(int row) {
-        if (row > records.length-1) //previously this said row > records.length which means if
-            return false;  // if records.length == 60 and I pass "60" here I get array out of bounds
-      CellValueRecordInterface[] rowCells=records[row]; //because a 60 length array has the last index = 59
-      if(rowCells==null) return false;
-      for(int col=0;col<rowCells.length;col++) {
-        if(rowCells[col]!=null) return true;
-      }
-      return false;
-    }
-
-    /** Serializes the cells that are allocated to a certain row range*/
-    public int serializeCellRow(final int row, int offset, byte [] data)
-    {
-      MyIterator itr = new MyIterator(row, row);
-        int      pos = offset;
-
-        while (itr.hasNext())
-        {
-            CellValueRecordInterface cell = (CellValueRecordInterface)itr.next();
-            if (cell.getRow() != row)
-              break;
-            pos += (( RecordBase ) cell).serialize(pos, data);
-        }
-        return pos - offset;
-    }
-
-    public void visitCellsForRow(int rowIndex, RecordVisitor rv) {
-
-        CellValueRecordInterface[] cellRecs = records[rowIndex];
-        if (cellRecs != null) {
-            for (int i = 0; i < cellRecs.length; i++) {
-                CellValueRecordInterface cvr = cellRecs[i];
-                if (cvr == null) {
-                    continue;
-                }
-                if (cvr instanceof RecordAggregate) {
-                    RecordAggregate agg = (RecordAggregate) cvr;
-                    agg.visitContainedRecords(rv);
-                } else {
-                    Record rec = (Record) cvr;
-                    rv.visitRecord(rec);
-                }
-            }
-        }
-    }
-
-    public void updateFormulasAfterRowShift(FormulaShifter shifter, int currentExternSheetIndex) {
-        for (int i = 0; i < records.length; i++) {
-            CellValueRecordInterface[] rowCells = records[i];
-            if (rowCells == null) {
-                continue;
-            }
-            for (int j = 0; j < rowCells.length; j++) {
-                CellValueRecordInterface cell = rowCells[j];
-                if (cell instanceof FormulaRecordAggregate) {
-                	FormulaRecord fr = ((FormulaRecordAggregate)cell).getFormulaRecord();
-                    Ptg[] ptgs = fr.getParsedExpression(); // needs clone() inside this getter?
-                    if (shifter.adjustFormula(ptgs, currentExternSheetIndex)) {
-                        fr.setParsedExpression(ptgs);
-                    }
-                }
-            }
-        }
-    }
-
-    public CellValueRecordInterface[] getValueRecords() {
-        List temp = new ArrayList();
-
-        for (int i = 0; i < records.length; i++) {
-            CellValueRecordInterface[] rowCells = records[i];
-            if (rowCells == null) {
-                continue;
-            }
-            for (int j = 0; j < rowCells.length; j++) {
-                CellValueRecordInterface cell = rowCells[j];
-                if (cell != null) {
-                    temp.add(cell);
-                }
-            }
-        }
-
-        CellValueRecordInterface[] result = new CellValueRecordInterface[temp.size()];
-        temp.toArray(result);
-        return result;
-    }
-    public Iterator getIterator()
-    {
-    return new MyIterator();
-    }
-
-  private final class MyIterator implements Iterator {
-    short nextColumn=-1;
-    int nextRow,lastRow;
-
-    public MyIterator()
-    {
-      this.nextRow=0;
-      this.lastRow=records.length-1;
-      findNext();
-    }
-
-    public MyIterator(int firstRow,int lastRow)
-    {
-      this.nextRow=firstRow;
-      this.lastRow=lastRow;
-      findNext();
-    }
-
-    public boolean hasNext() {
-      return nextRow<=lastRow;
-    }
-    public Object next() {
-      Object o=records[nextRow][nextColumn];
-      findNext();
-      return o;
-    }
-    public void remove() {
-      throw new UnsupportedOperationException("gibt's noch nicht");
-    }
-
-    private void findNext() {
-      nextColumn++;
-      for(;nextRow<=lastRow;nextRow++) {
-                                           //previously this threw array out of bounds...
-        CellValueRecordInterface[] rowCells=(nextRow < records.length) ? records[nextRow] : null;
-        if(rowCells==null) { // This row is empty
-          nextColumn=0;
-          continue;
-        }
-        for(;nextColumn<rowCells.length;nextColumn++) {
-          if(rowCells[nextColumn]!=null) return;
-        }
-        nextColumn=0;
-      }
-    }
+	private static final int MAX_ROW_INDEX = 0XFFFF;
+	private int firstcell = -1;
+	private int lastcell  = -1;
+	private CellValueRecordInterface[][] records;
+
+	/** Creates a new instance of ValueRecordsAggregate */
+
+	public ValueRecordsAggregate() {
+		records = new CellValueRecordInterface[30][]; // We start with 30 Rows.
+	}
+
+	public void insertCell(CellValueRecordInterface cell) {
+		short column = cell.getColumn();
+		int row = cell.getRow();
+		if (row >= records.length) {
+			CellValueRecordInterface[][] oldRecords = records;
+			int newSize = oldRecords.length * 2;
+			if (newSize < row + 1)
+				newSize = row + 1;
+			records = new CellValueRecordInterface[newSize][];
+			System.arraycopy(oldRecords, 0, records, 0, oldRecords.length);
+		}
+		CellValueRecordInterface[] rowCells = records[row];
+		if (rowCells == null) {
+			int newSize = column + 1;
+			if (newSize < 10)
+				newSize = 10;
+			rowCells = new CellValueRecordInterface[newSize];
+			records[row] = rowCells;
+		}
+		if (column >= rowCells.length) {
+			CellValueRecordInterface[] oldRowCells = rowCells;
+			int newSize = oldRowCells.length * 2;
+			if (newSize < column + 1)
+				newSize = column + 1;
+			// if(newSize>257) newSize=257; // activate?
+			rowCells = new CellValueRecordInterface[newSize];
+			System.arraycopy(oldRowCells, 0, rowCells, 0, oldRowCells.length);
+			records[row] = rowCells;
+		}
+		rowCells[column] = cell;
+
+		if ((column < firstcell) || (firstcell == -1)) {
+			firstcell = column;
+		}
+		if ((column > lastcell) || (lastcell == -1)) {
+			lastcell = column;
+		}
+	}
+
+	public void removeCell(CellValueRecordInterface cell) {
+		if (cell == null) {
+			throw new IllegalArgumentException("cell must not be null");
+		}
+		int row = cell.getRow();
+		if (row >= records.length) {
+			throw new RuntimeException("cell row is out of range");
+		}
+		CellValueRecordInterface[] rowCells = records[row];
+		if (rowCells == null) {
+			throw new RuntimeException("cell row is already empty");
+		}
+		short column = cell.getColumn();
+		if (column >= rowCells.length) {
+			throw new RuntimeException("cell column is out of range");
+		}
+		rowCells[column] = null;
+	}
+
+	public void removeAllCellsValuesForRow(int rowIndex) {
+		if (rowIndex < 0 || rowIndex > MAX_ROW_INDEX) {
+			throw new IllegalArgumentException("Specified rowIndex " + rowIndex
+					+ " is outside the allowable range (0.." +MAX_ROW_INDEX + ")");
+		}
+		if (rowIndex >= records.length) {
+			// this can happen when the client code has created a row, 
+			// and then removes/replaces it before adding any cells. (see bug 46312) 
+			return;
+		} 
+		
+		records[rowIndex] = null;
+	}
+
+
+	public int getPhysicalNumberOfCells() {
+		int count = 0;
+		for (int r = 0; r < records.length; r++) {
+			CellValueRecordInterface[] rowCells = records[r];
+			if (rowCells != null) {
+				for (int c = 0; c < rowCells.length; c++) {
+					if (rowCells[c] != null)
+						count++;
+				}
+			}
+		}
+		return count;
+	}
+
+	public int getFirstCellNum() {
+		return firstcell;
+	}
+
+	public int getLastCellNum() {
+		return lastcell;
+	}
+
+	/**
+	 * Processes a single cell value record
+	 * @param sfh used to resolve any shared-formulas/arrays/tables for the current sheet
+	 */
+	public void construct(CellValueRecordInterface rec, RecordStream rs, SharedValueManager sfh) {
+		if (rec instanceof FormulaRecord) {
+			FormulaRecord formulaRec = (FormulaRecord)rec;
+			// read optional cached text value
+			StringRecord cachedText;
+			Class nextClass = rs.peekNextClass();
+			if (nextClass == StringRecord.class) {
+				cachedText = (StringRecord) rs.getNext();
+			} else {
+				cachedText = null;
+			}
+			insertCell(new FormulaRecordAggregate(formulaRec, cachedText, sfh));
+		} else {
+			insertCell(rec);
+		}
+	}
+
+	/** Tallies a count of the size of the cell records
+	 *  that are attached to the rows in the range specified.
+	 */
+	public int getRowCellBlockSize(int startRow, int endRow) {
+		MyIterator itr = new MyIterator(records, startRow, endRow);
+		int size = 0;
+		while (itr.hasNext()) {
+			CellValueRecordInterface cell = (CellValueRecordInterface) itr.next();
+			int row = cell.getRow();
+			if (row > endRow) {
+				break;
+			}
+			if ((row >= startRow) && (row <= endRow)) {
+				size += ((RecordBase) cell).getRecordSize();
+			}
+		}
+		return size;
+	}
+
+	/** Returns true if the row has cells attached to it */
+	public boolean rowHasCells(int row) {
+		if (row >= records.length) {
+			return false;
+		}
+		CellValueRecordInterface[] rowCells=records[row]; 
+		if(rowCells==null) return false;
+		for(int col=0;col<rowCells.length;col++) {
+			if(rowCells[col]!=null) return true;
+		}
+		return false;
+	}
+
+	/** Serializes the cells that are allocated to a certain row range*/
+	public int serializeCellRow(final int row, int offset, byte [] data)
+	{
+	  MyIterator itr = new MyIterator(records, row, row);
+		int	  pos = offset;
+
+		while (itr.hasNext())
+		{
+			CellValueRecordInterface cell = (CellValueRecordInterface)itr.next();
+			if (cell.getRow() != row)
+			  break;
+			pos += (( RecordBase ) cell).serialize(pos, data);
+		}
+		return pos - offset;
+	}
+
+	public void visitCellsForRow(int rowIndex, RecordVisitor rv) {
+
+		CellValueRecordInterface[] cellRecs = records[rowIndex];
+		if (cellRecs != null) {
+			for (int i = 0; i < cellRecs.length; i++) {
+				CellValueRecordInterface cvr = cellRecs[i];
+				if (cvr == null) {
+					continue;
+				}
+				if (cvr instanceof RecordAggregate) {
+					RecordAggregate agg = (RecordAggregate) cvr;
+					agg.visitContainedRecords(rv);
+				} else {
+					Record rec = (Record) cvr;
+					rv.visitRecord(rec);
+				}
+			}
+		}
+	}
+
+	public void updateFormulasAfterRowShift(FormulaShifter shifter, int currentExternSheetIndex) {
+		for (int i = 0; i < records.length; i++) {
+			CellValueRecordInterface[] rowCells = records[i];
+			if (rowCells == null) {
+				continue;
+			}
+			for (int j = 0; j < rowCells.length; j++) {
+				CellValueRecordInterface cell = rowCells[j];
+				if (cell instanceof FormulaRecordAggregate) {
+					FormulaRecord fr = ((FormulaRecordAggregate)cell).getFormulaRecord();
+					Ptg[] ptgs = fr.getParsedExpression(); // needs clone() inside this getter?
+					if (shifter.adjustFormula(ptgs, currentExternSheetIndex)) {
+						fr.setParsedExpression(ptgs);
+					}
+				}
+			}
+		}
+	}
+
+	public CellValueRecordInterface[] getValueRecords() {
+		List<CellValueRecordInterface> temp = new ArrayList<CellValueRecordInterface>();
+
+		for (int i = 0; i < records.length; i++) {
+			CellValueRecordInterface[] rowCells = records[i];
+			if (rowCells == null) {
+				continue;
+			}
+			for (int j = 0; j < rowCells.length; j++) {
+				CellValueRecordInterface cell = rowCells[j];
+				if (cell != null) {
+					temp.add(cell);
+				}
+			}
+		}
+
+		CellValueRecordInterface[] result = new CellValueRecordInterface[temp.size()];
+		temp.toArray(result);
+		return result;
+	}
+	public Iterator getIterator() {
+		return new MyIterator(records);
+	}
+
+  private static final class MyIterator implements Iterator {
+		private final CellValueRecordInterface[][] records;
+		private short nextColumn = -1;
+		private int nextRow, lastRow;
+
+		public MyIterator(CellValueRecordInterface[][] pRecords) {
+			this(pRecords, 0, pRecords.length - 1);
+		}
+
+		public MyIterator(CellValueRecordInterface[][] pRecords, int firstRow, int lastRow) {
+			records = pRecords;
+			this.nextRow = firstRow;
+			this.lastRow = lastRow;
+			findNext();
+		}
+
+		public boolean hasNext() {
+			return nextRow <= lastRow;
+		}
+
+		public Object next() {
+			Object o = records[nextRow][nextColumn];
+			findNext();
+			return o;
+		}
+
+		public void remove() {
+			throw new UnsupportedOperationException("gibt's noch nicht");
+		}
+
+		private void findNext() {
+			nextColumn++;
+			for (; nextRow <= lastRow; nextRow++) {
+				// previously this threw array out of bounds...
+				CellValueRecordInterface[] rowCells = (nextRow < records.length) ? records[nextRow]
+						: null;
+				if (rowCells == null) { // This row is empty
+					nextColumn = 0;
+					continue;
+				}
+				for (; nextColumn < rowCells.length; nextColumn++) {
+					if (rowCells[nextColumn] != null)
+						return;
+				}
+				nextColumn = 0;
+			}
+		}
 
-  }
+	}
 }

Modified: poi/trunk/src/testcases/org/apache/poi/hssf/record/aggregates/TestValueRecordsAggregate.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/testcases/org/apache/poi/hssf/record/aggregates/TestValueRecordsAggregate.java?rev=722206&r1=722205&r2=722206&view=diff
==============================================================================
--- poi/trunk/src/testcases/org/apache/poi/hssf/record/aggregates/TestValueRecordsAggregate.java (original)
+++ poi/trunk/src/testcases/org/apache/poi/hssf/record/aggregates/TestValueRecordsAggregate.java Mon Dec  1 11:59:46 2008
@@ -37,249 +37,282 @@
 import org.apache.poi.hssf.record.RecordBase;
 import org.apache.poi.hssf.record.SharedFormulaRecord;
 import org.apache.poi.hssf.record.WindowTwoRecord;
+import org.apache.poi.hssf.usermodel.HSSFRow;
 import org.apache.poi.hssf.usermodel.HSSFSheet;
 import org.apache.poi.hssf.usermodel.HSSFWorkbook;
 
+/**
+ * Tests for {@link ValueRecordsAggregate}
+ */
 public final class TestValueRecordsAggregate extends TestCase {
-    private static final String ABNORMAL_SHARED_FORMULA_FLAG_TEST_FILE = "AbnormalSharedFormulaFlag.xls";
-    private final ValueRecordsAggregate valueRecord = new ValueRecordsAggregate();
+	private static final String ABNORMAL_SHARED_FORMULA_FLAG_TEST_FILE = "AbnormalSharedFormulaFlag.xls";
+	private final ValueRecordsAggregate valueRecord = new ValueRecordsAggregate();
 
-    /**
-     * Make sure the shared formula DOESNT makes it to the FormulaRecordAggregate when being parsed
-     * as part of the value records
-     */
-    public void testSharedFormula() {
-        List records = new ArrayList();
-        records.add( new FormulaRecord() );
-        records.add( new SharedFormulaRecord() );
-        records.add(new WindowTwoRecord());
-
-        constructValueRecord(records);
-        Iterator iterator = valueRecord.getIterator();
-        RecordBase record = (RecordBase) iterator.next();
-        assertNotNull( "Row contains a value", record );
-        assertTrue( "First record is a FormulaRecordsAggregate", ( record instanceof FormulaRecordAggregate ) );
-        //Ensure that the SharedFormulaRecord has been converted
-        assertFalse( "SharedFormulaRecord is null", iterator.hasNext() );
-
-    }
-
-    private void constructValueRecord(List records) {
-        RowBlocksReader rbr = new RowBlocksReader(new RecordStream(records, 0));
-        SharedValueManager sfrh = rbr.getSharedFormulaManager();
-        RecordStream rs = rbr.getPlainRecordStream();
-        while(rs.hasNext()) {
-            Record rec = rs.getNext();
-            valueRecord.construct((CellValueRecordInterface)rec, rs, sfrh);
-        }
-    }
-
-    private static List testData() {
-        List records = new ArrayList();
-        FormulaRecord formulaRecord = new FormulaRecord();
-        BlankRecord blankRecord = new BlankRecord();
-        formulaRecord.setRow( 1 );
-        formulaRecord.setColumn( (short) 1 );
-        blankRecord.setRow( 2 );
-        blankRecord.setColumn( (short) 2 );
-        records.add( formulaRecord );
-        records.add( blankRecord );
-        records.add(new WindowTwoRecord());
-        return records;
-    }
-
-    public void testInsertCell() {
-        Iterator iterator = valueRecord.getIterator();
-        assertFalse( iterator.hasNext() );
-
-        BlankRecord blankRecord = newBlankRecord();
-        valueRecord.insertCell( blankRecord );
-        iterator = valueRecord.getIterator();
-        assertTrue( iterator.hasNext() );
-    }
-
-    public void testRemoveCell() {
-        BlankRecord blankRecord1 = newBlankRecord();
-        valueRecord.insertCell( blankRecord1 );
-        BlankRecord blankRecord2 = newBlankRecord();
-        valueRecord.removeCell( blankRecord2 );
-        Iterator iterator = valueRecord.getIterator();
-        assertFalse( iterator.hasNext() );
-
-        // removing an already empty cell just falls through
-        valueRecord.removeCell( blankRecord2 );
-    }
-
-    public void testGetPhysicalNumberOfCells() {
-        assertEquals(0, valueRecord.getPhysicalNumberOfCells());
-        BlankRecord blankRecord1 = newBlankRecord();
-        valueRecord.insertCell( blankRecord1 );
-        assertEquals(1, valueRecord.getPhysicalNumberOfCells());
-        valueRecord.removeCell( blankRecord1 );
-        assertEquals(0, valueRecord.getPhysicalNumberOfCells());
-    }
-
-    public void testGetFirstCellNum() {
-        assertEquals( -1, valueRecord.getFirstCellNum() );
-        valueRecord.insertCell( newBlankRecord( 2, 2 ) );
-        assertEquals( 2, valueRecord.getFirstCellNum() );
-        valueRecord.insertCell( newBlankRecord( 3, 3 ) );
-        assertEquals( 2, valueRecord.getFirstCellNum() );
-
-        // Note: Removal doesn't currently reset the first column.  It probably should but it doesn't.
-        valueRecord.removeCell( newBlankRecord( 2, 2 ) );
-        assertEquals( 2, valueRecord.getFirstCellNum() );
-    }
-
-    public void testGetLastCellNum() {
-        assertEquals( -1, valueRecord.getLastCellNum() );
-        valueRecord.insertCell( newBlankRecord( 2, 2 ) );
-        assertEquals( 2, valueRecord.getLastCellNum() );
-        valueRecord.insertCell( newBlankRecord( 3, 3 ) );
-        assertEquals( 3, valueRecord.getLastCellNum() );
-
-        // Note: Removal doesn't currently reset the last column.  It probably should but it doesn't.
-        valueRecord.removeCell( newBlankRecord( 3, 3 ) );
-        assertEquals( 3, valueRecord.getLastCellNum() );
-
-    }
-
-    public void testSerialize() {
-        byte[] actualArray = new byte[36];
-        byte[] expectedArray = new byte[]
-        {
-            (byte)0x06, (byte)0x00, (byte)0x16, (byte)0x00,
-            (byte)0x01, (byte)0x00, (byte)0x01, (byte)0x00,
-            (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
-            (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
-            (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
-            (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
-            (byte)0x00, (byte)0x00, (byte)0x01, (byte)0x02,
-            (byte)0x06, (byte)0x00, (byte)0x02, (byte)0x00,
-            (byte)0x02, (byte)0x00, (byte)0x00, (byte)0x00,
-        };
-        List records = testData();
-        constructValueRecord(records);
-        int bytesWritten = valueRecord.serializeCellRow(1, 0, actualArray );
-        bytesWritten += valueRecord.serializeCellRow(2, bytesWritten, actualArray );
-        assertEquals( 36, bytesWritten );
-        for (int i = 0; i < 36; i++)
-            assertEquals( expectedArray[i], actualArray[i] );
-    }
-
-    private static BlankRecord newBlankRecord()
-    {
-        return newBlankRecord( 2, 2 );
-    }
-
-    private static BlankRecord newBlankRecord( int col, int row)
-    {
-        BlankRecord blankRecord = new BlankRecord();
-        blankRecord.setRow( row );
-        blankRecord.setColumn( (short) col );
-        return blankRecord;
-    }
-
-    /**
-     * Sometimes the 'shared formula' flag (<tt>FormulaRecord.isSharedFormula()</tt>) is set when 
-     * there is no corresponding SharedFormulaRecord available. SharedFormulaRecord definitions do
-     * not span multiple sheets.  They are are only defined within a sheet, and thus they do not 
-     * have a sheet index field (only row and column range fields).<br/>
-     * So it is important that the code which locates the SharedFormulaRecord for each 
-     * FormulaRecord does not allow matches across sheets.</br> 
-     * 
-     * Prior to bugzilla 44449 (Feb 2008), POI <tt>ValueRecordsAggregate.construct(int, List)</tt> 
-     * allowed <tt>SharedFormulaRecord</tt>s to be erroneously used across sheets.  That incorrect
-     * behaviour is shown by this test.<p/>
-     * 
-     * <b>Notes on how to produce the test spreadsheet</b>:</p>
-     * The setup for this test (AbnormalSharedFormulaFlag.xls) is rather fragile, insomuchas 
-     * re-saving the file (either with Excel or POI) clears the flag.<br/>
-     * <ol>
-     * <li>A new spreadsheet was created in Excel (File | New | Blank Workbook).</li>
-     * <li>Sheet3 was deleted.</li>
-     * <li>Sheet2!A1 formula was set to '="second formula"', and fill-dragged through A1:A8.</li>
-     * <li>Sheet1!A1 formula was set to '="first formula"', and also fill-dragged through A1:A8.</li>
-     * <li>Four rows on Sheet1 "5" through "8" were deleted ('delete rows' alt-E D, not 'clear' Del).</li>
-     * <li>The spreadsheet was saved as AbnormalSharedFormulaFlag.xls.</li>
-     * </ol>
-     * Prior to the row delete action the spreadsheet has two <tt>SharedFormulaRecord</tt>s. One 
-     * for each sheet. To expose the bug, the shared formulas have been made to overlap.<br/>
-     * The row delete action (as described here) seems to to delete the 
-     * <tt>SharedFormulaRecord</tt> from Sheet1 (but not clear the 'shared formula' flags.<br/>
-     * There are other variations on this theme to create the same effect.  
-     * 
-     */
-    public void testSpuriousSharedFormulaFlag() {
-        
-        long actualCRC = getFileCRC(HSSFTestDataSamples.openSampleFileStream(ABNORMAL_SHARED_FORMULA_FLAG_TEST_FILE));
-        long expectedCRC = 2277445406L;
-        if(actualCRC != expectedCRC) {
-            System.err.println("Expected crc " + expectedCRC  + " but got " + actualCRC);
-            throw failUnexpectedTestFileChange();
-        }
-        HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook(ABNORMAL_SHARED_FORMULA_FLAG_TEST_FILE);
-        
-        HSSFSheet s = wb.getSheetAt(0); // Sheet1
-        
-        String cellFormula;
-        cellFormula = getFormulaFromFirstCell(s, 0); // row "1"
-        // the problem is not observable in the first row of the shared formula
-        if(!cellFormula.equals("\"first formula\"")) {
-            throw new RuntimeException("Something else wrong with this test case");
-        }
-        
-        // but the problem is observable in rows 2,3,4 
-        cellFormula = getFormulaFromFirstCell(s, 1); // row "2"
-        if(cellFormula.equals("\"second formula\"")) {
-            throw new AssertionFailedError("found bug 44449 (Wrong SharedFormulaRecord was used).");
-        }
-        if(!cellFormula.equals("\"first formula\"")) {
-            throw new RuntimeException("Something else wrong with this test case");
-        }
-    }
-    private static String getFormulaFromFirstCell(HSSFSheet s, int rowIx) {
-        return s.getRow(rowIx).getCell(0).getCellFormula();
-    }
-
-    /**
-     * If someone opened this particular test file in Excel and saved it, the peculiar condition
-     * which causes the target bug would probably disappear.  This test would then just succeed
-     * regardless of whether the fix was present.  So a CRC check is performed to make it less easy
-     * for that to occur.
-     */
-    private static RuntimeException failUnexpectedTestFileChange() {
-        String msg = "Test file '" + ABNORMAL_SHARED_FORMULA_FLAG_TEST_FILE + "' has changed.  "
-            + "This junit may not be properly testing for the target bug.  "
-            + "Either revert the test file or ensure that the new version "
-            + "has the right characteristics to test the target bug.";
-        // A breakpoint in ValueRecordsAggregate.handleMissingSharedFormulaRecord(FormulaRecord)
-        // should get hit during parsing of Sheet1.
-        // If the test spreadsheet is created as directed, this condition should occur.
-        // It is easy to upset the test spreadsheet (for example re-saving will destroy the 
-        // peculiar condition we are testing for). 
-        throw new RuntimeException(msg);
-    }
-
-    /**
-     * gets a CRC checksum for the content of a file
-     */
-    private static long getFileCRC(InputStream is) {
-        CRC32 crc = new CRC32();
-        byte[] buf = new byte[2048];
-        try {
-            while(true) {
-                int bytesRead = is.read(buf);
-                if(bytesRead < 1) {
-                    break;
-                }
-                crc.update(buf, 0, bytesRead);
-            }
-            is.close();
-        } catch (IOException e) {
-            throw new RuntimeException(e);
-        }
-        
-        return crc.getValue();
-    }
+	/**
+	 * Make sure the shared formula DOESNT makes it to the FormulaRecordAggregate when being parsed
+	 * as part of the value records
+	 */
+	public void testSharedFormula() {
+		List<Record> records = new ArrayList<Record>();
+		records.add(new FormulaRecord());
+		records.add(new SharedFormulaRecord());
+		records.add(new WindowTwoRecord());
+
+		constructValueRecord(records);
+		Iterator iterator = valueRecord.getIterator();
+		RecordBase record = (RecordBase) iterator.next();
+		assertNotNull( "Row contains a value", record );
+		assertTrue( "First record is a FormulaRecordsAggregate", ( record instanceof FormulaRecordAggregate ) );
+		//Ensure that the SharedFormulaRecord has been converted
+		assertFalse( "SharedFormulaRecord is null", iterator.hasNext() );
+
+	}
+
+	private void constructValueRecord(List records) {
+		RowBlocksReader rbr = new RowBlocksReader(new RecordStream(records, 0));
+		SharedValueManager sfrh = rbr.getSharedFormulaManager();
+		RecordStream rs = rbr.getPlainRecordStream();
+		while(rs.hasNext()) {
+			Record rec = rs.getNext();
+			valueRecord.construct((CellValueRecordInterface)rec, rs, sfrh);
+		}
+	}
+
+	private static List testData() {
+		List<Record> records = new ArrayList<Record>();
+		FormulaRecord formulaRecord = new FormulaRecord();
+		BlankRecord blankRecord = new BlankRecord();
+		formulaRecord.setRow(1);
+		formulaRecord.setColumn((short) 1);
+		blankRecord.setRow(2);
+		blankRecord.setColumn((short) 2);
+		records.add(formulaRecord);
+		records.add(blankRecord);
+		records.add(new WindowTwoRecord());
+		return records;
+	}
+
+	public void testInsertCell() {
+		Iterator iterator = valueRecord.getIterator();
+		assertFalse( iterator.hasNext() );
+
+		BlankRecord blankRecord = newBlankRecord();
+		valueRecord.insertCell( blankRecord );
+		iterator = valueRecord.getIterator();
+		assertTrue( iterator.hasNext() );
+	}
+
+	public void testRemoveCell() {
+		BlankRecord blankRecord1 = newBlankRecord();
+		valueRecord.insertCell( blankRecord1 );
+		BlankRecord blankRecord2 = newBlankRecord();
+		valueRecord.removeCell( blankRecord2 );
+		Iterator iterator = valueRecord.getIterator();
+		assertFalse( iterator.hasNext() );
+
+		// removing an already empty cell just falls through
+		valueRecord.removeCell( blankRecord2 );
+	}
+
+	public void testGetPhysicalNumberOfCells() {
+		assertEquals(0, valueRecord.getPhysicalNumberOfCells());
+		BlankRecord blankRecord1 = newBlankRecord();
+		valueRecord.insertCell( blankRecord1 );
+		assertEquals(1, valueRecord.getPhysicalNumberOfCells());
+		valueRecord.removeCell( blankRecord1 );
+		assertEquals(0, valueRecord.getPhysicalNumberOfCells());
+	}
+
+	public void testGetFirstCellNum() {
+		assertEquals( -1, valueRecord.getFirstCellNum() );
+		valueRecord.insertCell( newBlankRecord( 2, 2 ) );
+		assertEquals( 2, valueRecord.getFirstCellNum() );
+		valueRecord.insertCell( newBlankRecord( 3, 3 ) );
+		assertEquals( 2, valueRecord.getFirstCellNum() );
+
+		// Note: Removal doesn't currently reset the first column.  It probably should but it doesn't.
+		valueRecord.removeCell( newBlankRecord( 2, 2 ) );
+		assertEquals( 2, valueRecord.getFirstCellNum() );
+	}
+
+	public void testGetLastCellNum() {
+		assertEquals( -1, valueRecord.getLastCellNum() );
+		valueRecord.insertCell( newBlankRecord( 2, 2 ) );
+		assertEquals( 2, valueRecord.getLastCellNum() );
+		valueRecord.insertCell( newBlankRecord( 3, 3 ) );
+		assertEquals( 3, valueRecord.getLastCellNum() );
+
+		// Note: Removal doesn't currently reset the last column.  It probably should but it doesn't.
+		valueRecord.removeCell( newBlankRecord( 3, 3 ) );
+		assertEquals( 3, valueRecord.getLastCellNum() );
+
+	}
+
+	public void testSerialize() {
+		byte[] actualArray = new byte[36];
+		byte[] expectedArray = new byte[]
+		{
+			(byte)0x06, (byte)0x00, (byte)0x16, (byte)0x00,
+			(byte)0x01, (byte)0x00, (byte)0x01, (byte)0x00,
+			(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+			(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+			(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+			(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+			(byte)0x00, (byte)0x00, (byte)0x01, (byte)0x02,
+			(byte)0x06, (byte)0x00, (byte)0x02, (byte)0x00,
+			(byte)0x02, (byte)0x00, (byte)0x00, (byte)0x00,
+		};
+		List records = testData();
+		constructValueRecord(records);
+		int bytesWritten = valueRecord.serializeCellRow(1, 0, actualArray );
+		bytesWritten += valueRecord.serializeCellRow(2, bytesWritten, actualArray );
+		assertEquals( 36, bytesWritten );
+		for (int i = 0; i < 36; i++)
+			assertEquals( expectedArray[i], actualArray[i] );
+	}
+
+	private static BlankRecord newBlankRecord()
+	{
+		return newBlankRecord( 2, 2 );
+	}
+
+	private static BlankRecord newBlankRecord( int col, int row)
+	{
+		BlankRecord blankRecord = new BlankRecord();
+		blankRecord.setRow( row );
+		blankRecord.setColumn( (short) col );
+		return blankRecord;
+	}
+
+	/**
+	 * Sometimes the 'shared formula' flag (<tt>FormulaRecord.isSharedFormula()</tt>) is set when 
+	 * there is no corresponding SharedFormulaRecord available. SharedFormulaRecord definitions do
+	 * not span multiple sheets.  They are are only defined within a sheet, and thus they do not 
+	 * have a sheet index field (only row and column range fields).<br/>
+	 * So it is important that the code which locates the SharedFormulaRecord for each 
+	 * FormulaRecord does not allow matches across sheets.</br> 
+	 * 
+	 * Prior to bugzilla 44449 (Feb 2008), POI <tt>ValueRecordsAggregate.construct(int, List)</tt> 
+	 * allowed <tt>SharedFormulaRecord</tt>s to be erroneously used across sheets.  That incorrect
+	 * behaviour is shown by this test.<p/>
+	 * 
+	 * <b>Notes on how to produce the test spreadsheet</b>:</p>
+	 * The setup for this test (AbnormalSharedFormulaFlag.xls) is rather fragile, insomuchas 
+	 * re-saving the file (either with Excel or POI) clears the flag.<br/>
+	 * <ol>
+	 * <li>A new spreadsheet was created in Excel (File | New | Blank Workbook).</li>
+	 * <li>Sheet3 was deleted.</li>
+	 * <li>Sheet2!A1 formula was set to '="second formula"', and fill-dragged through A1:A8.</li>
+	 * <li>Sheet1!A1 formula was set to '="first formula"', and also fill-dragged through A1:A8.</li>
+	 * <li>Four rows on Sheet1 "5" through "8" were deleted ('delete rows' alt-E D, not 'clear' Del).</li>
+	 * <li>The spreadsheet was saved as AbnormalSharedFormulaFlag.xls.</li>
+	 * </ol>
+	 * Prior to the row delete action the spreadsheet has two <tt>SharedFormulaRecord</tt>s. One 
+	 * for each sheet. To expose the bug, the shared formulas have been made to overlap.<br/>
+	 * The row delete action (as described here) seems to to delete the 
+	 * <tt>SharedFormulaRecord</tt> from Sheet1 (but not clear the 'shared formula' flags.<br/>
+	 * There are other variations on this theme to create the same effect.  
+	 * 
+	 */
+	public void testSpuriousSharedFormulaFlag() {
+		
+		long actualCRC = getFileCRC(HSSFTestDataSamples.openSampleFileStream(ABNORMAL_SHARED_FORMULA_FLAG_TEST_FILE));
+		long expectedCRC = 2277445406L;
+		if(actualCRC != expectedCRC) {
+			System.err.println("Expected crc " + expectedCRC  + " but got " + actualCRC);
+			throw failUnexpectedTestFileChange();
+		}
+		HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook(ABNORMAL_SHARED_FORMULA_FLAG_TEST_FILE);
+		
+		HSSFSheet s = wb.getSheetAt(0); // Sheet1
+		
+		String cellFormula;
+		cellFormula = getFormulaFromFirstCell(s, 0); // row "1"
+		// the problem is not observable in the first row of the shared formula
+		if(!cellFormula.equals("\"first formula\"")) {
+			throw new RuntimeException("Something else wrong with this test case");
+		}
+		
+		// but the problem is observable in rows 2,3,4 
+		cellFormula = getFormulaFromFirstCell(s, 1); // row "2"
+		if(cellFormula.equals("\"second formula\"")) {
+			throw new AssertionFailedError("found bug 44449 (Wrong SharedFormulaRecord was used).");
+		}
+		if(!cellFormula.equals("\"first formula\"")) {
+			throw new RuntimeException("Something else wrong with this test case");
+		}
+	}
+	private static String getFormulaFromFirstCell(HSSFSheet s, int rowIx) {
+		return s.getRow(rowIx).getCell(0).getCellFormula();
+	}
+
+	/**
+	 * If someone opened this particular test file in Excel and saved it, the peculiar condition
+	 * which causes the target bug would probably disappear.  This test would then just succeed
+	 * regardless of whether the fix was present.  So a CRC check is performed to make it less easy
+	 * for that to occur.
+	 */
+	private static RuntimeException failUnexpectedTestFileChange() {
+		String msg = "Test file '" + ABNORMAL_SHARED_FORMULA_FLAG_TEST_FILE + "' has changed.  "
+			+ "This junit may not be properly testing for the target bug.  "
+			+ "Either revert the test file or ensure that the new version "
+			+ "has the right characteristics to test the target bug.";
+		// A breakpoint in ValueRecordsAggregate.handleMissingSharedFormulaRecord(FormulaRecord)
+		// should get hit during parsing of Sheet1.
+		// If the test spreadsheet is created as directed, this condition should occur.
+		// It is easy to upset the test spreadsheet (for example re-saving will destroy the 
+		// peculiar condition we are testing for). 
+		throw new RuntimeException(msg);
+	}
+
+	/**
+	 * gets a CRC checksum for the content of a file
+	 */
+	private static long getFileCRC(InputStream is) {
+		CRC32 crc = new CRC32();
+		byte[] buf = new byte[2048];
+		try {
+			while(true) {
+				int bytesRead = is.read(buf);
+				if(bytesRead < 1) {
+					break;
+				}
+				crc.update(buf, 0, bytesRead);
+			}
+			is.close();
+		} catch (IOException e) {
+			throw new RuntimeException(e);
+		}
+		
+		return crc.getValue();
+	}
+	public void testRemoveNewRow_bug46312() {
+		// To make bug occur, rowIndex needs to be >= ValueRecordsAggregate.records.length
+		int rowIndex = 30;
+		
+		ValueRecordsAggregate vra = new ValueRecordsAggregate();
+		try {
+			vra.removeAllCellsValuesForRow(rowIndex);
+		} catch (IllegalArgumentException e) {
+			if (e.getMessage().equals("Specified rowIndex 30 is outside the allowable range (0..30)")) {
+				throw new AssertionFailedError("Identified bug 46312");
+			}
+			throw e;
+		}
+
+		if (false) { // same bug as demonstrated through usermodel API
+
+			HSSFWorkbook wb = new HSSFWorkbook();
+			HSSFSheet sheet = wb.createSheet();
+			HSSFRow row = sheet.createRow(rowIndex);
+			if (false) { // must not add any cells to the new row if we want to see the bug
+				row.createCell(0); // this causes ValueRecordsAggregate.records to auto-extend
+			}
+			try {
+				sheet.createRow(rowIndex);
+			} catch (IllegalArgumentException e) {
+				throw new AssertionFailedError("Identified bug 46312");
+			}
+		}
+	}
 }



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@poi.apache.org
For additional commands, e-mail: commits-help@poi.apache.org