poi-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From n...@apache.org
Subject svn commit: r659485 [2/3] - in /poi/branches/ooxml: ./ src/documentation/content/xdocs/ src/examples/src/org/apache/poi/hslf/ src/examples/src/org/apache/poi/hslf/usermodel/ src/examples/src/org/apache/poi/hslf/usermodel/examples/ src/java/org/apache/p...
Date Fri, 23 May 2008 09:48:28 GMT
Modified: poi/branches/ooxml/src/scratchpad/src/org/apache/poi/hwpf/model/FSPATable.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/scratchpad/src/org/apache/poi/hwpf/model/FSPATable.java?rev=659485&r1=659484&r2=659485&view=diff
==============================================================================
--- poi/branches/ooxml/src/scratchpad/src/org/apache/poi/hwpf/model/FSPATable.java (original)
+++ poi/branches/ooxml/src/scratchpad/src/org/apache/poi/hwpf/model/FSPATable.java Fri May 23 02:48:23 2008
@@ -21,17 +21,18 @@
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 
 /**
  * This class holds all the FSPA (File Shape Address) structures.
  * 
  * @author Squeeself
  */
-public class FSPATable 
+public final class FSPATable 
 {
-    protected ArrayList shapes = new ArrayList();
-    protected HashMap cps = new HashMap();
-    protected List _text;
+    private final List _shapes = new ArrayList();
+    private final Map _shapeIndexesByPropertyStart = new HashMap();
+    private final List _text;
     
     public FSPATable(byte[] tableStream, int fcPlcspa, int lcbPlcspa, List tpt)
     {
@@ -46,32 +47,35 @@
             GenericPropertyNode property = plex.getProperty(i);
             FSPA fspa = new FSPA(property.getBytes(), 0);
             
-            shapes.add(fspa);
-            cps.put(Integer.valueOf(property.getStart()), Integer.valueOf(i));
+            _shapes.add(fspa);
+            _shapeIndexesByPropertyStart.put(new Integer(property.getStart()), new Integer(i));
         }
     }
     
     public FSPA getFspaFromCp(int cp)
     {
-        Integer idx = (Integer)cps.get(Integer.valueOf(cp));
-        if (idx == null)
+        Integer idx = (Integer)_shapeIndexesByPropertyStart.get(new Integer(cp));
+        if (idx == null) {
             return null;
-        return (FSPA)shapes.get(idx.intValue());
+        }
+        return (FSPA)_shapes.get(idx.intValue());
     }
     
-    public List getShapes()
+    public FSPA[] getShapes()
     {
-        return shapes;
+        FSPA[] result = new FSPA[_shapes.size()];
+        _shapes.toArray(result);
+        return result;
     }
     
     public String toString()
     {
         StringBuffer buf = new StringBuffer();
-        buf.append("[FPSA PLC size=").append(shapes.size()).append("]\n");
-        for (Iterator it = cps.keySet().iterator(); it.hasNext(); )
+        buf.append("[FPSA PLC size=").append(_shapes.size()).append("]\n");
+        for (Iterator it = _shapeIndexesByPropertyStart.keySet().iterator(); it.hasNext(); )
         {
             Integer i = (Integer) it.next();
-            FSPA fspa = (FSPA) shapes.get(((Integer)cps.get(i)).intValue());
+            FSPA fspa = (FSPA) _shapes.get(((Integer)_shapeIndexesByPropertyStart.get(i)).intValue());
             buf.append("  [FC: ").append(i.toString()).append("] ");
             buf.append(fspa.toString());
             buf.append("\n");

Modified: poi/branches/ooxml/src/scratchpad/src/org/apache/poi/hwpf/model/FileInformationBlock.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/scratchpad/src/org/apache/poi/hwpf/model/FileInformationBlock.java?rev=659485&r1=659484&r2=659485&view=diff
==============================================================================
--- poi/branches/ooxml/src/scratchpad/src/org/apache/poi/hwpf/model/FileInformationBlock.java (original)
+++ poi/branches/ooxml/src/scratchpad/src/org/apache/poi/hwpf/model/FileInformationBlock.java Fri May 23 02:48:23 2008
@@ -294,6 +294,16 @@
       _longHandler.setLong(FIBLongHandler.CBMAC, cbMac);
     }
 
+	public int getCcpText()
+	{
+	  return _longHandler.getLong(FIBLongHandler.CCPTEXT);
+	}
+
+	public void setCcpText(int ccpText)
+	{
+	  _longHandler.setLong(FIBLongHandler.CCPTEXT, ccpText);
+	}
+
     public void clearOffsetsSizes()
     {
       _fieldHandler.clearFields();

Modified: poi/branches/ooxml/src/scratchpad/src/org/apache/poi/hwpf/model/TextPiece.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/scratchpad/src/org/apache/poi/hwpf/model/TextPiece.java?rev=659485&r1=659484&r2=659485&view=diff
==============================================================================
--- poi/branches/ooxml/src/scratchpad/src/org/apache/poi/hwpf/model/TextPiece.java (original)
+++ poi/branches/ooxml/src/scratchpad/src/org/apache/poi/hwpf/model/TextPiece.java Fri May 23 02:48:23 2008
@@ -90,12 +90,20 @@
 
    public void adjustForDelete(int start, int length)
    {
+
+	   if (usesUnicode()) {
+
+		   start /= 2;
+		   length /= 2;
+	   }
+
 	   int myStart = getStart();
 	   int myEnd = getEnd();
 	   int end = start + length;
 
 	   /* do we have to delete from this text piece? */
 	   if (start <= myEnd && end >= myStart) {
+
 		   /* find where the deleted area overlaps with this text piece */
 		   int overlapStart = Math.max(myStart, start);
 		   int overlapEnd = Math.min(myEnd, end);

Modified: poi/branches/ooxml/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Range.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Range.java?rev=659485&r1=659484&r2=659485&view=diff
==============================================================================
--- poi/branches/ooxml/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Range.java (original)
+++ poi/branches/ooxml/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Range.java Fri May 23 02:48:23 2008
@@ -227,6 +227,25 @@
   }
 
   /**
+   * Does any <code>TextPiece</code> in this Range use unicode?
+   *
+   *	@return	true if it does and false if it doesn't
+   */
+  public boolean usesUnicode() {
+
+	initText();
+
+	for (int i = _textStart; i < _textEnd; i++)
+	{
+	  TextPiece piece = (TextPiece)_text.get(i);
+	  if (piece.usesUnicode())
+		  return true;
+	}
+
+	return false;
+  }
+
+  /**
    * Gets the text that this Range contains.
    *
    * @return The text for this range.
@@ -306,13 +325,19 @@
     // Since this is the first item in our list, it is safe to assume that
     // _start >= tp.getStart()
     int insertIndex = _start - tp.getStart();
+	if (tp.usesUnicode())
+		insertIndex /= 2;
     sb.insert(insertIndex, text);
+
     int adjustedLength = _doc.getTextTable().adjustForInsert(_textStart, text.length());
     _doc.getCharacterTable().adjustForInsert(_charStart, adjustedLength);
     _doc.getParagraphTable().adjustForInsert(_parStart, adjustedLength);
     _doc.getSectionTable().adjustForInsert(_sectionStart, adjustedLength);
     adjustForInsert(text.length());
 
+	// update the FIB.CCPText field
+	adjustFIB(text.length());
+
     return getCharacterRun(0);
   }
 
@@ -489,6 +514,7 @@
 
   public void delete()
   {
+
     initAll();
 
     int numSections = _sections.size();
@@ -519,6 +545,12 @@
     	TextPiece piece = (TextPiece)_text.get(x);
     	piece.adjustForDelete(_start, _end - _start);
     }
+
+	// update the FIB.CCPText field
+	if (usesUnicode())
+		adjustFIB(-((_end - _start) / 2));
+	else
+		adjustFIB(-(_end - _start));
   }
 
   /**
@@ -828,12 +860,26 @@
   }
 
   /**
+   *	Adjust the value of <code>FIB.CCPText</code> after an insert or a delete...
+   *
+   *	@param	adjustment	The (signed) value that should be added to <code>FIB.CCPText</code>
+   */
+  protected void adjustFIB(int adjustment) {
+
+	// update the FIB.CCPText field (this should happen once per adjustment, so we don't want it in
+	// adjustForInsert() or it would get updated multiple times if the range has a parent)
+	// without this, OpenOffice.org (v. 2.2.x) does not see all the text in the document
+	_doc.getFileInformationBlock().setCcpText(_doc.getFileInformationBlock().getCcpText() + adjustment);
+  }
+
+  /**
    * adjust this range after an insert happens.
    * @param length the length to adjust for
    */
   private void adjustForInsert(int length)
   {
     _end += length;
+
     reset();
     Range parent = (Range)_parent.get();
     if (parent != null)
@@ -842,4 +888,14 @@
     }
   }
 
+
+	public int getStartOffset() {
+
+		return _start;
+	}
+
+	public int getEndOffset() {
+
+		return _end;
+	}
 }

Modified: poi/branches/ooxml/src/testcases/org/apache/poi/hssf/model/TestFormulaParser.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/testcases/org/apache/poi/hssf/model/TestFormulaParser.java?rev=659485&r1=659484&r2=659485&view=diff
==============================================================================
--- poi/branches/ooxml/src/testcases/org/apache/poi/hssf/model/TestFormulaParser.java (original)
+++ poi/branches/ooxml/src/testcases/org/apache/poi/hssf/model/TestFormulaParser.java Fri May 23 02:48:23 2008
@@ -55,120 +55,99 @@
 
 /**
  * Test the low level formula parser functionality. High level tests are to
- *  be done via usermodel/HSSFCell.setFormulaValue() .
- * Some tests are also done in scratchpad, if they need
- *  HSSFFormulaEvaluator, which is there
+ * be done via usermodel/HSSFCell.setFormulaValue().
  */
 public final class TestFormulaParser extends TestCase {
 
-    /**
-     * @return parsed token array already confirmed not <code>null</code>
-     */
-    private static Ptg[] parseFormula(String s) {
-    	// TODO - replace multiple copies of this code with calls to this method
-        FormulaParser fp = new FormulaParser(s, null);
-        fp.parse();
-        Ptg[] result = fp.getRPNPtg();
-        assertNotNull("Ptg array should not be null", result);
-        return result;
-    }
-
-    public void testSimpleFormula() {
-        FormulaParser fp = new FormulaParser("2+2",null);
-        fp.parse();
-        Ptg[] ptgs = fp.getRPNPtg();
-        assertTrue("three tokens expected, got "+ptgs.length,ptgs.length == 3);
-    }
-    public void testFormulaWithSpace1() {
-        FormulaParser fp = new FormulaParser(" 2 + 2 ",null);
-        fp.parse();
-        Ptg[] ptgs = fp.getRPNPtg();
-        assertTrue("three tokens expected, got "+ptgs.length,ptgs.length == 3);
-        assertTrue("",(ptgs[0] instanceof IntPtg));
-        assertTrue("",(ptgs[1] instanceof IntPtg));
-        assertTrue("",(ptgs[2] instanceof AddPtg));
-    }
-
-    public void testFormulaWithSpace2() {
-        Ptg[] ptgs;
-        FormulaParser fp;
-        fp = new FormulaParser("2+ sum( 3 , 4) ",null);
-        fp.parse();
-        ptgs = fp.getRPNPtg();
-        assertTrue("five tokens expected, got "+ptgs.length,ptgs.length == 5);
-    }
-
-     public void testFormulaWithSpaceNRef() {
-        Ptg[] ptgs;
-        FormulaParser fp;
-        fp = new FormulaParser("sum( A2:A3 )",null);
-        fp.parse();
-        ptgs = fp.getRPNPtg();
-        assertTrue("two tokens expected, got "+ptgs.length,ptgs.length == 2);
-    }
-
-    public void testFormulaWithString() {
-        Ptg[] ptgs;
-        FormulaParser fp;
-        fp = new FormulaParser("\"hello\" & \"world\" ",null);
-        fp.parse();
-        ptgs = fp.getRPNPtg();
-        assertTrue("three token expected, got " + ptgs.length, ptgs.length == 3);
-    }
-
-    public void testTRUE() throws Exception {
-        FormulaParser fp = new FormulaParser("TRUE", null);
-        fp.parse();
-        Ptg[] asts = fp.getRPNPtg();
-        assertEquals(1, asts.length);
-        BoolPtg flag  = (BoolPtg) asts[0];
-        assertEquals(true, flag.getValue());
-    }
-
-    public void testYN() throws Exception {
-        final String yn = "IF(TRUE,\"Y\",\"N\")";
-        FormulaParser fp = new FormulaParser(yn, null);
-        fp.parse();
-        Ptg[] asts = fp.getRPNPtg();
-        assertEquals(7, asts.length);
-
-        BoolPtg flag  = (BoolPtg) asts[0];
-		AttrPtg funif = (AttrPtg) asts[1];
-        StringPtg y = (StringPtg) asts[2];
-		AttrPtg goto1 = (AttrPtg) asts[3];
-        StringPtg n = (StringPtg) asts[4];
-
-
-        assertEquals(true, flag.getValue());
-        assertEquals("Y", y.getValue());
-        assertEquals("N", n.getValue());
-        assertEquals("IF", funif.toFormulaString((HSSFWorkbook) null));
-        assertTrue("Goto ptg exists", goto1.isGoto());
-    }
-
-	public void testSimpleIf() throws Exception {
-		final String simpleif = "IF(1=1,0,1)";
-		FormulaParser fp = new FormulaParser(simpleif, null);
+	/**
+	 * @return parsed token array already confirmed not <code>null</code>
+	 */
+	private static Ptg[] parseFormula(String s) {
+		FormulaParser fp = new FormulaParser(s, null);
 		fp.parse();
-		Ptg[] asts = fp.getRPNPtg();
-		assertEquals(9, asts.length);
-		
-		IntPtg op1 = (IntPtg) asts[0];
-		IntPtg op2 = (IntPtg) asts[1];
-		EqualPtg eq = (EqualPtg) asts[2];		
-		AttrPtg ifPtg = (AttrPtg) asts[3];
-		IntPtg res1 = (IntPtg) asts[4];
-				
-		AttrPtg ptgGoto= (AttrPtg) asts[5];		
-		assertEquals("Goto 1 Length", (short)10, ptgGoto.getData());
-		
-		IntPtg res2 = (IntPtg) asts[6];		
-		AttrPtg ptgGoto2 = (AttrPtg) asts[7];		
-		assertEquals("Goto 2 Length", (short)3, ptgGoto2.getData());
-		
-		assertEquals("If FALSE offset", (short)7, ifPtg.getData());
+		Ptg[] result = fp.getRPNPtg();
+		assertNotNull("Ptg array should not be null", result);
+		return result;
+	}
+
+	public void testSimpleFormula() {
+		Ptg[] ptgs = parseFormula("2+2");
+		assertEquals(3, ptgs.length);
+	}
+
+	public void testFormulaWithSpace1() {
+		Ptg[] ptgs = parseFormula(" 2 + 2 ");
+		assertEquals(3, ptgs.length);
+		assertTrue("",(ptgs[0] instanceof IntPtg));
+		assertTrue("",(ptgs[1] instanceof IntPtg));
+		assertTrue("",(ptgs[2] instanceof AddPtg));
+	}
+
+	public void testFormulaWithSpace2() {
+		Ptg[] ptgs = parseFormula("2+ sum( 3 , 4) ");
+		assertEquals(5, ptgs.length);
+	}
+
+	public void testFormulaWithSpaceNRef() {
+		Ptg[] ptgs = parseFormula("sum( A2:A3 )");
+		assertEquals(2, ptgs.length);
+	}
+
+	public void testFormulaWithString() {
+		Ptg[] ptgs = parseFormula("\"hello\" & \"world\" ");
+		assertEquals(3, ptgs.length);
+	}
+
+	public void testTRUE() {
+		Ptg[] ptgs = parseFormula("TRUE");
+		assertEquals(1, ptgs.length);
+		BoolPtg flag  = (BoolPtg) ptgs[0];
+		assertEquals(true, flag.getValue());
+	}
+
+	public void testYN() {
+		Ptg[] ptgs = parseFormula("IF(TRUE,\"Y\",\"N\")");
+		assertEquals(7, ptgs.length);
+
+		BoolPtg flag  = (BoolPtg) ptgs[0];
+		AttrPtg funif = (AttrPtg) ptgs[1];
+		StringPtg y = (StringPtg) ptgs[2];
+		AttrPtg goto1 = (AttrPtg) ptgs[3];
+		StringPtg n = (StringPtg) ptgs[4];
+
+
+		assertEquals(true, flag.getValue());
+		assertEquals("Y", y.getValue());
+		assertEquals("N", n.getValue());
+		assertEquals("IF", funif.toFormulaString((HSSFWorkbook) null));
+		assertTrue("Goto ptg exists", goto1.isGoto());
+	}
+
+	public void testSimpleIf() {
+		String formula = "IF(1=1,0,1)";
+
+		Class[] expectedClasses = {
+			IntPtg.class,
+			IntPtg.class,
+			EqualPtg.class,
+			AttrPtg.class,
+			IntPtg.class,
+			AttrPtg.class,
+			IntPtg.class,
+			AttrPtg.class,
+			FuncVarPtg.class,
+		};
+		confirmTokenClasses(formula, expectedClasses);
 		
-		FuncVarPtg funcPtg = (FuncVarPtg)asts[8];
+		Ptg[] ptgs = parseFormula(formula);
+
+		AttrPtg ifPtg = (AttrPtg) ptgs[3];
+		AttrPtg ptgGoto= (AttrPtg) ptgs[5];
+		assertEquals("Goto 1 Length", 10, ptgGoto.getData());
+
+		AttrPtg ptgGoto2 = (AttrPtg) ptgs[7];
+		assertEquals("Goto 2 Length", 3, ptgGoto2.getData());
+		assertEquals("If FALSE offset", 7, ifPtg.getData());
 	}
 
 	/**
@@ -176,753 +155,714 @@
 	 *
 	 */
 	public void testNestedFunctionIf() {
-		String function = "IF(A1=B1,AVERAGE(A1:B1),AVERAGE(A2:B2))";
+		Ptg[] ptgs = parseFormula("IF(A1=B1,AVERAGE(A1:B1),AVERAGE(A2:B2))");
+		assertEquals(11, ptgs.length);
 
-		FormulaParser fp = new FormulaParser(function, null);
-		fp.parse();
-		Ptg[] asts = fp.getRPNPtg();
-		assertEquals("11 Ptgs expected", 11, asts.length);
-
-		assertTrue("IF Attr set correctly", (asts[3] instanceof AttrPtg));
-		AttrPtg ifFunc = (AttrPtg)asts[3];
+		assertTrue("IF Attr set correctly", (ptgs[3] instanceof AttrPtg));
+		AttrPtg ifFunc = (AttrPtg)ptgs[3];
 		assertTrue("It is not an if", ifFunc.isOptimizedIf());
-		
-		assertTrue("Average Function set correctly", (asts[5] instanceof FuncVarPtg));
+
+		assertTrue("Average Function set correctly", (ptgs[5] instanceof FuncVarPtg));
 	}
-	
-	public void testIfSingleCondition(){
-		String function = "IF(1=1,10)";
 
-		FormulaParser fp = new FormulaParser(function, null);
-		fp.parse();
-		Ptg[] asts = fp.getRPNPtg();
-		assertEquals("7 Ptgs expected", 7, asts.length);
+	public void testIfSingleCondition(){
+		Ptg[] ptgs = parseFormula("IF(1=1,10)");
+		assertEquals(7, ptgs.length);
 
-		assertTrue("IF Attr set correctly", (asts[3] instanceof AttrPtg));
-		AttrPtg ifFunc = (AttrPtg)asts[3];
+		assertTrue("IF Attr set correctly", (ptgs[3] instanceof AttrPtg));
+		AttrPtg ifFunc = (AttrPtg)ptgs[3];
 		assertTrue("It is not an if", ifFunc.isOptimizedIf());
-		
-		assertTrue("Single Value is not an IntPtg", (asts[4] instanceof IntPtg));
-		IntPtg intPtg = (IntPtg)asts[4];
+
+		assertTrue("Single Value is not an IntPtg", (ptgs[4] instanceof IntPtg));
+		IntPtg intPtg = (IntPtg)ptgs[4];
 		assertEquals("Result", (short)10, intPtg.getValue());
-		
-		assertTrue("Ptg is not a Variable Function", (asts[6] instanceof FuncVarPtg));
-		FuncVarPtg funcPtg = (FuncVarPtg)asts[6];
+
+		assertTrue("Ptg is not a Variable Function", (ptgs[6] instanceof FuncVarPtg));
+		FuncVarPtg funcPtg = (FuncVarPtg)ptgs[6];
 		assertEquals("Arguments", 2, funcPtg.getNumberOfOperands());
 	}
 
 	public void testSumIf() {
-		String function ="SUMIF(A1:A5,\">4000\",B1:B5)";
-		FormulaParser fp = new FormulaParser(function, null);
-		fp.parse();
-		Ptg[] asts = fp.getRPNPtg();
-		assertEquals("4 Ptgs expected", 4, asts.length);
+		Ptg[] ptgs = parseFormula("SUMIF(A1:A5,\">4000\",B1:B5)");
+		assertEquals(4, ptgs.length);
 	}
-	
+
 	/**
 	 * Bug Reported by xt-jens.riis@nokia.com (Jens Riis)
 	 * Refers to Bug <a href="http://issues.apache.org/bugzilla/show_bug.cgi?id=17582">#17582</a>
 	 *
 	 */
-	public void testNonAlphaFormula(){
+	public void testNonAlphaFormula() {
 		String currencyCell = "F3";
-		String function="\"TOTAL[\"&"+currencyCell+"&\"]\"";
+		Ptg[] ptgs = parseFormula("\"TOTAL[\"&"+currencyCell+"&\"]\"");
+		assertEquals(5, ptgs.length);
+		assertTrue ("Ptg[0] is a string", (ptgs[0] instanceof StringPtg));
+		StringPtg firstString = (StringPtg)ptgs[0];
 
-		Ptg[] asts = parseFormula(function);
-		assertEquals("5 ptgs expected", 5, asts.length);
-		assertTrue ("Ptg[0] is a string", (asts[0] instanceof StringPtg));
-		StringPtg firstString = (StringPtg)asts[0];		
-		
 		assertEquals("TOTAL[", firstString.getValue());
 		//the PTG order isn't 100% correct but it still works - dmui
 	}
 
 	public void testSimpleLogical() {
-      Ptg[] ptgs = parseFormula("IF(A1<A2,B1,B2)");
-      assertEquals("Ptg array length", 9, ptgs.length);
-      assertEquals("3rd Ptg is less than", LessThanPtg.class, ptgs[2].getClass());
+	 Ptg[] ptgs = parseFormula("IF(A1<A2,B1,B2)");
+	 assertEquals(9, ptgs.length);
+	 assertEquals("3rd Ptg is less than", LessThanPtg.class, ptgs[2].getClass());
 	}
-	
+
 	public void testParenIf() {
 		Ptg[] ptgs = parseFormula("IF((A1+A2)<=3,\"yes\",\"no\")");
-		assertEquals("Ptg array length", 12, ptgs.length);
+		assertEquals(12, ptgs.length);
 		assertEquals("6th Ptg is less than equal",LessEqualPtg.class,ptgs[5].getClass());
 		assertEquals("11th Ptg is not a goto (Attr) ptg",AttrPtg.class,ptgs[10].getClass());
 	}
-	
+
 	public void testEmbeddedIf() {
 		Ptg[] ptgs = parseFormula("IF(3>=1,\"*\",IF(4<>1,\"first\",\"second\"))");
-		assertEquals("Ptg array length", 17, ptgs.length);
-		
+		assertEquals(17, ptgs.length);
+
 		assertEquals("6th Ptg is not a goto (Attr) ptg",AttrPtg.class,ptgs[5].getClass());
 		assertEquals("9th Ptg is not a not equal ptg",NotEqualPtg.class,ptgs[8].getClass());
 		assertEquals("15th Ptg is not the inner IF variable function ptg",FuncVarPtg.class,ptgs[14].getClass());
 	}
-	
-    public void testMacroFunction() {
-    	HSSFWorkbook w = new HSSFWorkbook();
-        FormulaParser fp = new FormulaParser("FOO()", w);
-        fp.parse();
-        Ptg[] ptg = fp.getRPNPtg();
-
-        // the name gets encoded as the first arg
-        NamePtg tname = (NamePtg) ptg[0];
-        assertEquals("FOO", tname.toFormulaString(w));
-
-        AbstractFunctionPtg tfunc = (AbstractFunctionPtg) ptg[1];
-        assertTrue(tfunc.isExternalFunction());
-    }
-
-    public void testEmbeddedSlash() {
-        FormulaParser fp = new FormulaParser("HYPERLINK(\"http://www.jakarta.org\",\"Jakarta\")",null);
-        fp.parse();
-        Ptg[] ptg = fp.getRPNPtg();
-        assertTrue("first ptg is string",ptg[0] instanceof StringPtg);
-        assertTrue("second ptg is string",ptg[1] instanceof StringPtg);
-    }
 
-    public void testConcatenate() {
-		FormulaParser fp = new FormulaParser("CONCATENATE(\"first\",\"second\")", null);
+	public void testMacroFunction() {
+		HSSFWorkbook w = new HSSFWorkbook();
+		FormulaParser fp = new FormulaParser("FOO()", w);
 		fp.parse();
 		Ptg[] ptg = fp.getRPNPtg();
-		assertTrue("first ptg is string", ptg[0] instanceof StringPtg);
-		assertTrue("second ptg is string", ptg[1] instanceof StringPtg);
+
+		// the name gets encoded as the first arg
+		NamePtg tname = (NamePtg) ptg[0];
+		assertEquals("FOO", tname.toFormulaString(w));
+
+		AbstractFunctionPtg tfunc = (AbstractFunctionPtg) ptg[1];
+		assertTrue(tfunc.isExternalFunction());
 	}
 
-    public void testWorksheetReferences()
-    {
-    	HSSFWorkbook wb = new HSSFWorkbook();
-    	
-    	wb.createSheet("NoQuotesNeeded");
-    	wb.createSheet("Quotes Needed Here &#$@");
-    	
-    	HSSFSheet sheet = wb.createSheet("Test");
-    	HSSFRow row = sheet.createRow(0);
-    	HSSFCell cell;
-    	
-    	cell = row.createCell((short)0);
-    	cell.setCellFormula("NoQuotesNeeded!A1");
-    	
-    	cell = row.createCell((short)1);
-    	cell.setCellFormula("'Quotes Needed Here &#$@'!A1");
-    }
-
-    public void testUnaryMinus()
-    {
-		FormulaParser fp = new FormulaParser("-A1", null);
-		fp.parse();
-		Ptg[] ptg = fp.getRPNPtg();
-		assertTrue("got 2 ptgs", ptg.length == 2);
-		assertTrue("first ptg is reference",ptg[0] instanceof ReferencePtg);
-		assertTrue("second ptg is Minus",ptg[1] instanceof UnaryMinusPtg);
-     }
-
-    public void testUnaryPlus()
-    {
-		FormulaParser fp = new FormulaParser("+A1", null);
-		fp.parse();
-		Ptg[] ptg = fp.getRPNPtg();
-		assertTrue("got 2 ptgs", ptg.length == 2);
-		assertTrue("first ptg is reference",ptg[0] instanceof ReferencePtg);
-		assertTrue("second ptg is Plus",ptg[1] instanceof UnaryPlusPtg);
-     }
+	public void testEmbeddedSlash() {
+		Ptg[] ptgs = parseFormula("HYPERLINK(\"http://www.jakarta.org\",\"Jakarta\")");
+		assertTrue("first ptg is string", ptgs[0] instanceof StringPtg);
+		assertTrue("second ptg is string", ptgs[1] instanceof StringPtg);
+	}
+
+	public void testConcatenate() {
+		Ptg[] ptgs = parseFormula("CONCATENATE(\"first\",\"second\")");
+		assertTrue("first ptg is string", ptgs[0] instanceof StringPtg);
+		assertTrue("second ptg is string", ptgs[1] instanceof StringPtg);
+	}
+
+	public void testWorksheetReferences() {
+		HSSFWorkbook wb = new HSSFWorkbook();
+
+		wb.createSheet("NoQuotesNeeded");
+		wb.createSheet("Quotes Needed Here &#$@");
+
+		HSSFSheet sheet = wb.createSheet("Test");
+		HSSFRow row = sheet.createRow(0);
+		HSSFCell cell;
+
+		cell = row.createCell((short)0);
+		cell.setCellFormula("NoQuotesNeeded!A1");
 
-	public void testLeadingSpaceInString()
-	{
+		cell = row.createCell((short)1);
+		cell.setCellFormula("'Quotes Needed Here &#$@'!A1");
+	}
+
+	public void testUnaryMinus() {
+		Ptg[] ptgs = parseFormula("-A1");
+		assertEquals(2, ptgs.length);
+		assertTrue("first ptg is reference",ptgs[0] instanceof ReferencePtg);
+		assertTrue("second ptg is Minus",ptgs[1] instanceof UnaryMinusPtg);
+	}
+
+	public void testUnaryPlus() {
+		Ptg[] ptgs = parseFormula("+A1");
+		assertEquals(2, ptgs.length);
+		assertTrue("first ptg is reference",ptgs[0] instanceof ReferencePtg);
+		assertTrue("second ptg is Plus",ptgs[1] instanceof UnaryPlusPtg);
+	}
+
+	public void testLeadingSpaceInString() {
 		String value = "  hi  ";
-		FormulaParser fp = new FormulaParser("\"" + value + "\"", null);
-		fp.parse();
-		Ptg[] ptg = fp.getRPNPtg();
+		Ptg[] ptgs = parseFormula("\"" + value + "\"");
 
-		assertTrue("got 1 ptg", ptg.length == 1);
-		assertTrue("ptg0 is a StringPtg", ptg[0] instanceof StringPtg);
-		assertTrue("ptg0 contains exact value", ((StringPtg)ptg[0]).getValue().equals(value));
-	}
-	
-	public void testLookupAndMatchFunctionArgs()
-	{
-		FormulaParser fp = new FormulaParser("lookup(A1, A3:A52, B3:B52)", null);
-		fp.parse();
-		Ptg[] ptg = fp.getRPNPtg();
+		assertEquals(1, ptgs.length);
+		assertTrue("ptg0 is a StringPtg", ptgs[0] instanceof StringPtg);
+		assertTrue("ptg0 contains exact value", ((StringPtg)ptgs[0]).getValue().equals(value));
+	}
 
-		assertTrue("got 4 ptg", ptg.length == 4);
-		assertTrue("ptg0 has Value class", ptg[0].getPtgClass() == Ptg.CLASS_VALUE);
-		
-		fp = new FormulaParser("match(A1, A3:A52)", null);
-		fp.parse();
-		ptg = fp.getRPNPtg();
+	public void testLookupAndMatchFunctionArgs() {
+		Ptg[] ptgs = parseFormula("lookup(A1, A3:A52, B3:B52)");
+
+		assertEquals(4, ptgs.length);
+		assertTrue("ptg0 has Value class", ptgs[0].getPtgClass() == Ptg.CLASS_VALUE);
+
+		ptgs = parseFormula("match(A1, A3:A52)");
 
-		assertTrue("got 3 ptg", ptg.length == 3);
-		assertTrue("ptg0 has Value class", ptg[0].getPtgClass() == Ptg.CLASS_VALUE);
+		assertEquals(3, ptgs.length);
+		assertTrue("ptg0 has Value class", ptgs[0].getPtgClass() == Ptg.CLASS_VALUE);
 	}
-	
+
 	/** bug 33160*/
 	public void testLargeInt() {
-		FormulaParser fp = new FormulaParser("40", null);
-		fp.parse();
-		Ptg[] ptg=fp.getRPNPtg();
-		assertTrue("ptg is Int, is "+ptg[0].getClass(),ptg[0] instanceof IntPtg);
-		
-		fp = new FormulaParser("40000", null);
-		fp.parse();
-		ptg=fp.getRPNPtg();
-		assertTrue("ptg should be  IntPtg, is "+ptg[0].getClass(), ptg[0] instanceof IntPtg);
+		Ptg[] ptgs = parseFormula("40");
+		assertTrue("ptg is Int, is "+ptgs[0].getClass(),ptgs[0] instanceof IntPtg);
+
+		ptgs = parseFormula("40000");
+		assertTrue("ptg should be  IntPtg, is "+ptgs[0].getClass(), ptgs[0] instanceof IntPtg);
 	}
 
 	/** bug 33160, testcase by Amol Deshmukh*/
 	public void testSimpleLongFormula() {
-		FormulaParser fp = new FormulaParser("40000/2", null);
-		fp.parse();
-		Ptg[] ptgs = fp.getRPNPtg();
-		assertTrue("three tokens expected, got " + ptgs.length, ptgs.length == 3);
+		Ptg[] ptgs = parseFormula("40000/2");
+		assertEquals(3, ptgs.length);
 		assertTrue("IntPtg", (ptgs[0] instanceof IntPtg));
 		assertTrue("IntPtg", (ptgs[1] instanceof IntPtg));
 		assertTrue("DividePtg", (ptgs[2] instanceof DividePtg));
 	}
-	
+
 	/** bug 35027, underscore in sheet name */
 	public void testUnderscore() {
 		HSSFWorkbook wb = new HSSFWorkbook();
-    	
-    	wb.createSheet("Cash_Flow");
-    	
-    	HSSFSheet sheet = wb.createSheet("Test");
-    	HSSFRow row = sheet.createRow(0);
-    	HSSFCell cell;
-    	
-    	cell = row.createCell((short)0);
-    	cell.setCellFormula("Cash_Flow!A1");
-		
+
+		wb.createSheet("Cash_Flow");
+
+		HSSFSheet sheet = wb.createSheet("Test");
+		HSSFRow row = sheet.createRow(0);
+		HSSFCell cell;
+
+		cell = row.createCell((short)0);
+		cell.setCellFormula("Cash_Flow!A1");
+	}
+
+	// bug 38396 : Formula with exponential numbers not parsed correctly.
+	public void testExponentialParsing() {
+		Ptg[] ptgs;
+		ptgs = parseFormula("1.3E21/2");
+		assertEquals(3, ptgs.length);
+		assertTrue("NumberPtg", (ptgs[0] instanceof NumberPtg));
+		assertTrue("IntPtg", (ptgs[1] instanceof IntPtg));
+		assertTrue("DividePtg", (ptgs[2] instanceof DividePtg));
+
+		ptgs = parseFormula("1322E21/2");
+		assertEquals(3, ptgs.length);
+		assertTrue("NumberPtg", (ptgs[0] instanceof NumberPtg));
+		assertTrue("IntPtg", (ptgs[1] instanceof IntPtg));
+		assertTrue("DividePtg", (ptgs[2] instanceof DividePtg));
+
+		ptgs = parseFormula("1.3E1/2");
+		assertEquals(3, ptgs.length);
+		assertTrue("NumberPtg", (ptgs[0] instanceof NumberPtg));
+		assertTrue("IntPtg", (ptgs[1] instanceof IntPtg));
+		assertTrue("DividePtg", (ptgs[2] instanceof DividePtg));
+	}
+
+	public void testExponentialInSheet() {
+		HSSFWorkbook wb = new HSSFWorkbook();
+
+		wb.createSheet("Cash_Flow");
+
+		HSSFSheet sheet = wb.createSheet("Test");
+		HSSFRow row = sheet.createRow(0);
+		HSSFCell cell = row.createCell((short)0);
+		String formula = null;
+
+		cell.setCellFormula("1.3E21/3");
+		formula = cell.getCellFormula();
+		assertEquals("Exponential formula string", "1.3E21/3", formula);
+
+		cell.setCellFormula("-1.3E21/3");
+		formula = cell.getCellFormula();
+		assertEquals("Exponential formula string", "-1.3E21/3", formula);
+
+		cell.setCellFormula("1322E21/3");
+		formula = cell.getCellFormula();
+		assertEquals("Exponential formula string", "1.322E24/3", formula);
+
+		cell.setCellFormula("-1322E21/3");
+		formula = cell.getCellFormula();
+		assertEquals("Exponential formula string", "-1.322E24/3", formula);
+
+		cell.setCellFormula("1.3E1/3");
+		formula = cell.getCellFormula();
+		assertEquals("Exponential formula string", "13.0/3", formula);
+
+		cell.setCellFormula("-1.3E1/3");
+		formula = cell.getCellFormula();
+		assertEquals("Exponential formula string", "-13.0/3", formula);
+
+		cell.setCellFormula("1.3E-4/3");
+		formula = cell.getCellFormula();
+		assertEquals("Exponential formula string", "1.3E-4/3", formula);
+
+		cell.setCellFormula("-1.3E-4/3");
+		formula = cell.getCellFormula();
+		assertEquals("Exponential formula string", "-1.3E-4/3", formula);
+
+		cell.setCellFormula("13E-15/3");
+		formula = cell.getCellFormula();
+		assertEquals("Exponential formula string", "1.3E-14/3", formula);
+
+		cell.setCellFormula("-13E-15/3");
+		formula = cell.getCellFormula();
+		assertEquals("Exponential formula string", "-1.3E-14/3", formula);
+
+		cell.setCellFormula("1.3E3/3");
+		formula = cell.getCellFormula();
+		assertEquals("Exponential formula string", "1300.0/3", formula);
+
+		cell.setCellFormula("-1.3E3/3");
+		formula = cell.getCellFormula();
+		assertEquals("Exponential formula string", "-1300.0/3", formula);
+
+		cell.setCellFormula("1300000000000000/3");
+		formula = cell.getCellFormula();
+		assertEquals("Exponential formula string", "1.3E15/3", formula);
+
+		cell.setCellFormula("-1300000000000000/3");
+		formula = cell.getCellFormula();
+		assertEquals("Exponential formula string", "-1.3E15/3", formula);
+
+		cell.setCellFormula("-10E-1/3.1E2*4E3/3E4");
+		formula = cell.getCellFormula();
+		assertEquals("Exponential formula string", "-1.0/310.0*4000.0/30000.0", formula);
+	}
+
+	public void testNumbers() {
+		HSSFWorkbook wb = new HSSFWorkbook();
+
+		wb.createSheet("Cash_Flow");
+
+		HSSFSheet sheet = wb.createSheet("Test");
+		HSSFRow row = sheet.createRow(0);
+		HSSFCell cell = row.createCell((short)0);
+		String formula = null;
+
+		// starts from decimal point
+
+		cell.setCellFormula(".1");
+		formula = cell.getCellFormula();
+		assertEquals("0.1", formula);
+
+		cell.setCellFormula("+.1");
+		formula = cell.getCellFormula();
+		assertEquals("+0.1", formula);
+
+		cell.setCellFormula("-.1");
+		formula = cell.getCellFormula();
+		assertEquals("-0.1", formula);
+
+		// has exponent
+
+		cell.setCellFormula("10E1");
+		formula = cell.getCellFormula();
+		assertEquals("100.0", formula);
+
+		cell.setCellFormula("10E+1");
+		formula = cell.getCellFormula();
+		assertEquals("100.0", formula);
+
+		cell.setCellFormula("10E-1");
+		formula = cell.getCellFormula();
+		assertEquals("1.0", formula);
+	}
+
+	public void testRanges() {
+		HSSFWorkbook wb = new HSSFWorkbook();
+
+		wb.createSheet("Cash_Flow");
+
+		HSSFSheet sheet = wb.createSheet("Test");
+		HSSFRow row = sheet.createRow(0);
+		HSSFCell cell = row.createCell((short)0);
+		String formula = null;
+
+		cell.setCellFormula("A1.A2");
+		formula = cell.getCellFormula();
+		assertEquals("A1:A2", formula);
+
+		cell.setCellFormula("A1..A2");
+		formula = cell.getCellFormula();
+		assertEquals("A1:A2", formula);
+
+		cell.setCellFormula("A1...A2");
+		formula = cell.getCellFormula();
+		assertEquals("A1:A2", formula);
+	}
+
+	/**
+	 * Test for bug observable at svn revision 618865 (5-Feb-2008)<br/>
+	 * a formula consisting of a single no-arg function got rendered without the function braces
+	 */
+	public void testToFormulaStringZeroArgFunction() {
+		HSSFWorkbook book = new HSSFWorkbook();
+
+		Ptg[] ptgs = {
+				new FuncPtg(10),
+		};
+		assertEquals("NA()", FormulaParser.toFormulaString(book, ptgs));
+	}
+
+	public void testPercent() {
+		Ptg[] ptgs;
+		ptgs = parseFormula("5%");
+		assertEquals(2, ptgs.length);
+		assertEquals(ptgs[0].getClass(), IntPtg.class);
+		assertEquals(ptgs[1].getClass(), PercentPtg.class);
+
+		// spaces OK
+		ptgs = parseFormula(" 250 % ");
+		assertEquals(2, ptgs.length);
+		assertEquals(ptgs[0].getClass(), IntPtg.class);
+		assertEquals(ptgs[1].getClass(), PercentPtg.class);
+
+
+		// double percent OK
+		ptgs = parseFormula("12345.678%%");
+		assertEquals(3, ptgs.length);
+		assertEquals(ptgs[0].getClass(), NumberPtg.class);
+		assertEquals(ptgs[1].getClass(), PercentPtg.class);
+		assertEquals(ptgs[2].getClass(), PercentPtg.class);
+
+		// percent of a bracketed expression
+		ptgs = parseFormula("(A1+35)%*B1%");
+		assertEquals(8, ptgs.length);
+		assertEquals(ptgs[4].getClass(), PercentPtg.class);
+		assertEquals(ptgs[6].getClass(), PercentPtg.class);
+
+		// percent of a text quantity
+		ptgs = parseFormula("\"8.75\"%");
+		assertEquals(2, ptgs.length);
+		assertEquals(ptgs[0].getClass(), StringPtg.class);
+		assertEquals(ptgs[1].getClass(), PercentPtg.class);
+
+		// percent to the power of
+		ptgs = parseFormula("50%^3");
+		assertEquals(4, ptgs.length);
+		assertEquals(ptgs[0].getClass(), IntPtg.class);
+		assertEquals(ptgs[1].getClass(), PercentPtg.class);
+		assertEquals(ptgs[2].getClass(), IntPtg.class);
+		assertEquals(ptgs[3].getClass(), PowerPtg.class);
+
+		//
+		// things that parse OK but would *evaluate* to an error
+
+		ptgs = parseFormula("\"abc\"%");
+		assertEquals(2, ptgs.length);
+		assertEquals(ptgs[0].getClass(), StringPtg.class);
+		assertEquals(ptgs[1].getClass(), PercentPtg.class);
+
+		ptgs = parseFormula("#N/A%");
+		assertEquals(2, ptgs.length);
+		assertEquals(ptgs[0].getClass(), ErrPtg.class);
+		assertEquals(ptgs[1].getClass(), PercentPtg.class);
+	}
+
+	/**
+	 * Tests combinations of various operators in the absence of brackets
+	 */
+	public void testPrecedenceAndAssociativity() {
+
+		Class[] expClss;
+
+		// TRUE=TRUE=2=2  evaluates to FALSE
+		expClss = new Class[] { BoolPtg.class, BoolPtg.class, EqualPtg.class,
+				IntPtg.class, EqualPtg.class, IntPtg.class, EqualPtg.class,  };
+		confirmTokenClasses("TRUE=TRUE=2=2", expClss);
+
+
+		//  2^3^2	evaluates to 64 not 512
+		expClss = new Class[] { IntPtg.class, IntPtg.class, PowerPtg.class,
+				IntPtg.class, PowerPtg.class, };
+		confirmTokenClasses("2^3^2", expClss);
+
+		// "abc" & 2 + 3 & "def"   evaluates to "abc5def"
+		expClss = new Class[] { StringPtg.class, IntPtg.class, IntPtg.class,
+				AddPtg.class, ConcatPtg.class, StringPtg.class, ConcatPtg.class, };
+		confirmTokenClasses("\"abc\"&2+3&\"def\"", expClss);
+
+
+		//  (1 / 2) - (3 * 4)
+		expClss = new Class[] { IntPtg.class, IntPtg.class, DividePtg.class,
+				IntPtg.class, IntPtg.class, MultiplyPtg.class, SubtractPtg.class, };
+		confirmTokenClasses("1/2-3*4", expClss);
+
+		// 2 * (2^2)
+		expClss = new Class[] { IntPtg.class, IntPtg.class, IntPtg.class, PowerPtg.class, MultiplyPtg.class, };
+		// NOT: (2 *2) ^ 2 -> int int multiply int power
+		confirmTokenClasses("2*2^2", expClss);
+
+		//  2^200% -> 2 not 1.6E58
+		expClss = new Class[] { IntPtg.class, IntPtg.class, PercentPtg.class, PowerPtg.class, };
+		confirmTokenClasses("2^200%", expClss);
+	}
+
+	private static void confirmTokenClasses(String formula, Class[] expectedClasses) {
+		Ptg[] ptgs = parseFormula(formula);
+		assertEquals(expectedClasses.length, ptgs.length);
+		for (int i = 0; i < expectedClasses.length; i++) {
+			if(expectedClasses[i] != ptgs[i].getClass()) {
+				fail("difference at token[" + i + "]: expected ("
+					+ expectedClasses[i].getName() + ") but got ("
+					+ ptgs[i].getClass().getName() + ")");
+			}
+		}
+	}
+
+	public void testPower() {
+		confirmTokenClasses("2^5", new Class[] { IntPtg.class, IntPtg.class, PowerPtg.class, });
+	}
+
+	private static Ptg parseSingleToken(String formula, Class ptgClass) {
+		Ptg[] ptgs = parseFormula(formula);
+		assertEquals(1, ptgs.length);
+		Ptg result = ptgs[0];
+		assertEquals(ptgClass, result.getClass());
+		return result;
+	}
+
+	public void testParseNumber() {
+		IntPtg ip;
+
+		// bug 33160
+		ip = (IntPtg) parseSingleToken("40", IntPtg.class);
+		assertEquals(40, ip.getValue());
+		ip = (IntPtg) parseSingleToken("40000", IntPtg.class);
+		assertEquals(40000, ip.getValue());
+
+		// check the upper edge of the IntPtg range:
+		ip = (IntPtg) parseSingleToken("65535", IntPtg.class);
+		assertEquals(65535, ip.getValue());
+		NumberPtg np = (NumberPtg) parseSingleToken("65536", NumberPtg.class);
+		assertEquals(65536, np.getValue(), 0);
+
+		np = (NumberPtg) parseSingleToken("65534.6", NumberPtg.class);
+		assertEquals(65534.6, np.getValue(), 0);
 	}
 
-    // bug 38396 : Formula with exponential numbers not parsed correctly.
-    public void testExponentialParsing() {
-        FormulaParser fp = new FormulaParser("1.3E21/2", null);
-        fp.parse();
-        Ptg[] ptgs = fp.getRPNPtg();
-        assertTrue("three tokens expected, got " + ptgs.length, ptgs.length == 3);
-        assertTrue("NumberPtg", (ptgs[0] instanceof NumberPtg));
-        assertTrue("IntPtg", (ptgs[1] instanceof IntPtg));
-        assertTrue("DividePtg", (ptgs[2] instanceof DividePtg));
-
-        fp = new FormulaParser("1322E21/2", null);
-        fp.parse();
-        ptgs = fp.getRPNPtg();
-        assertTrue("three tokens expected, got " + ptgs.length, ptgs.length == 3);
-        assertTrue("NumberPtg", (ptgs[0] instanceof NumberPtg));
-        assertTrue("IntPtg", (ptgs[1] instanceof IntPtg));
-        assertTrue("DividePtg", (ptgs[2] instanceof DividePtg));
-
-        fp = new FormulaParser("1.3E1/2", null);
-        fp.parse();
-        ptgs = fp.getRPNPtg();
-        assertTrue("three tokens expected, got " + ptgs.length, ptgs.length == 3);
-        assertTrue("NumberPtg", (ptgs[0] instanceof NumberPtg));
-        assertTrue("IntPtg", (ptgs[1] instanceof IntPtg));
-        assertTrue("DividePtg", (ptgs[2] instanceof DividePtg));
-
-    }
-    public void testExponentialInSheet() throws Exception {
-        HSSFWorkbook wb = new HSSFWorkbook();
-
-        wb.createSheet("Cash_Flow");
-
-        HSSFSheet sheet = wb.createSheet("Test");
-        HSSFRow row = sheet.createRow(0);
-        HSSFCell cell = row.createCell((short)0);
-        String formula = null;
-
-        cell.setCellFormula("1.3E21/3");
-        formula = cell.getCellFormula();
-        assertEquals("Exponential formula string", "1.3E21/3", formula);
-
-        cell.setCellFormula("-1.3E21/3");
-        formula = cell.getCellFormula();
-        assertEquals("Exponential formula string", "-1.3E21/3", formula);
-
-        cell.setCellFormula("1322E21/3");
-        formula = cell.getCellFormula();
-        assertEquals("Exponential formula string", "1.322E24/3", formula);
-
-        cell.setCellFormula("-1322E21/3");
-        formula = cell.getCellFormula();
-        assertEquals("Exponential formula string", "-1.322E24/3", formula);
-
-        cell.setCellFormula("1.3E1/3");
-        formula = cell.getCellFormula();
-        assertEquals("Exponential formula string", "13.0/3", formula);
-
-        cell.setCellFormula("-1.3E1/3");
-        formula = cell.getCellFormula();
-        assertEquals("Exponential formula string", "-13.0/3", formula);
-
-        cell.setCellFormula("1.3E-4/3");
-        formula = cell.getCellFormula();
-        assertEquals("Exponential formula string", "1.3E-4/3", formula);
-
-        cell.setCellFormula("-1.3E-4/3");
-        formula = cell.getCellFormula();
-        assertEquals("Exponential formula string", "-1.3E-4/3", formula);
-
-        cell.setCellFormula("13E-15/3");
-        formula = cell.getCellFormula();
-        assertEquals("Exponential formula string", "1.3E-14/3", formula);
-
-        cell.setCellFormula("-13E-15/3");
-        formula = cell.getCellFormula();
-        assertEquals("Exponential formula string", "-1.3E-14/3", formula);
-
-        cell.setCellFormula("1.3E3/3");
-        formula = cell.getCellFormula();
-        assertEquals("Exponential formula string", "1300.0/3", formula);
-
-        cell.setCellFormula("-1.3E3/3");
-        formula = cell.getCellFormula();
-        assertEquals("Exponential formula string", "-1300.0/3", formula);
-
-        cell.setCellFormula("1300000000000000/3");
-        formula = cell.getCellFormula();
-        assertEquals("Exponential formula string", "1.3E15/3", formula);
-
-        cell.setCellFormula("-1300000000000000/3");
-        formula = cell.getCellFormula();
-        assertEquals("Exponential formula string", "-1.3E15/3", formula);
-
-        cell.setCellFormula("-10E-1/3.1E2*4E3/3E4");
-        formula = cell.getCellFormula();
-        assertEquals("Exponential formula string", "-1.0/310.0*4000.0/30000.0", formula);
-    }
-
-     public static void main(String [] args) {
-        System.out.println("Testing org.apache.poi.hssf.record.formula.FormulaParser");
-        junit.textui.TestRunner.run(TestFormulaParser.class);
-    }
-
-    public void testNumbers() {
-        HSSFWorkbook wb = new HSSFWorkbook();
-
-        wb.createSheet("Cash_Flow");
-
-        HSSFSheet sheet = wb.createSheet("Test");
-        HSSFRow row = sheet.createRow(0);
-        HSSFCell cell = row.createCell((short)0);
-        String formula = null;
-
-        // starts from decimal point
-
-        cell.setCellFormula(".1");
-        formula = cell.getCellFormula();
-        assertEquals("0.1", formula);
-
-        cell.setCellFormula("+.1");
-        formula = cell.getCellFormula();
-        assertEquals("+0.1", formula);
-
-        cell.setCellFormula("-.1");
-        formula = cell.getCellFormula();
-        assertEquals("-0.1", formula);
-
-        // has exponent
-
-        cell.setCellFormula("10E1");
-        formula = cell.getCellFormula();
-        assertEquals("100.0", formula);
-
-        cell.setCellFormula("10E+1");
-        formula = cell.getCellFormula();
-        assertEquals("100.0", formula);
-
-        cell.setCellFormula("10E-1");
-        formula = cell.getCellFormula();
-        assertEquals("1.0", formula);
-    }
-
-    public void testRanges() {
-        HSSFWorkbook wb = new HSSFWorkbook();
-
-        wb.createSheet("Cash_Flow");
-
-        HSSFSheet sheet = wb.createSheet("Test");
-        HSSFRow row = sheet.createRow(0);
-        HSSFCell cell = row.createCell((short)0);
-        String formula = null;
-
-        cell.setCellFormula("A1.A2");
-        formula = cell.getCellFormula();
-        assertEquals("A1:A2", formula);
-
-        cell.setCellFormula("A1..A2");
-        formula = cell.getCellFormula();
-        assertEquals("A1:A2", formula);
-
-        cell.setCellFormula("A1...A2");
-        formula = cell.getCellFormula();
-        assertEquals("A1:A2", formula);
-    }
-
-    /**
-     * Test for bug observable at svn revision 618865 (5-Feb-2008)<br/>
-     * a formula consisting of a single no-arg function got rendered without the function braces
-     */
-    public void testToFormulaStringZeroArgFunction() {
-    	HSSFWorkbook book = new HSSFWorkbook();
-
-        Ptg[] ptgs = {
-                new FuncPtg(10),
-        };
-        assertEquals("NA()", FormulaParser.toFormulaString(book, ptgs));
-    }
-
-    public void testPercent() {
-        Ptg[] ptgs;
-        ptgs = parseFormula("5%");
-        assertEquals(2, ptgs.length);
-        assertEquals(ptgs[0].getClass(), IntPtg.class);
-        assertEquals(ptgs[1].getClass(), PercentPtg.class);
-
-        // spaces OK
-        ptgs = parseFormula(" 250 % ");
-        assertEquals(2, ptgs.length);
-        assertEquals(ptgs[0].getClass(), IntPtg.class);
-        assertEquals(ptgs[1].getClass(), PercentPtg.class);
-
-
-        // double percent OK
-        ptgs = parseFormula("12345.678%%");
-        assertEquals(3, ptgs.length);
-        assertEquals(ptgs[0].getClass(), NumberPtg.class);
-        assertEquals(ptgs[1].getClass(), PercentPtg.class);
-        assertEquals(ptgs[2].getClass(), PercentPtg.class);
-
-        // percent of a bracketed expression
-        ptgs = parseFormula("(A1+35)%*B1%");
-        assertEquals(8, ptgs.length);
-        assertEquals(ptgs[4].getClass(), PercentPtg.class);
-        assertEquals(ptgs[6].getClass(), PercentPtg.class);
-
-        // percent of a text quantity
-        ptgs = parseFormula("\"8.75\"%");
-        assertEquals(2, ptgs.length);
-        assertEquals(ptgs[0].getClass(), StringPtg.class);
-        assertEquals(ptgs[1].getClass(), PercentPtg.class);
-
-        // percent to the power of
-        ptgs = parseFormula("50%^3");
-        assertEquals(4, ptgs.length);
-        assertEquals(ptgs[0].getClass(), IntPtg.class);
-        assertEquals(ptgs[1].getClass(), PercentPtg.class);
-        assertEquals(ptgs[2].getClass(), IntPtg.class);
-        assertEquals(ptgs[3].getClass(), PowerPtg.class);
-
-        //
-        // things that parse OK but would *evaluate* to an error
-
-        ptgs = parseFormula("\"abc\"%");
-        assertEquals(2, ptgs.length);
-        assertEquals(ptgs[0].getClass(), StringPtg.class);
-        assertEquals(ptgs[1].getClass(), PercentPtg.class);
-
-        ptgs = parseFormula("#N/A%");
-        assertEquals(2, ptgs.length);
-        assertEquals(ptgs[0].getClass(), ErrPtg.class);
-        assertEquals(ptgs[1].getClass(), PercentPtg.class);
-    }
-
-    /**
-     * Tests combinations of various operators in the absence of brackets
-     */
-    public void testPrecedenceAndAssociativity() {
-
-        Class[] expClss;
-
-        // TRUE=TRUE=2=2  evaluates to FALSE
-        expClss = new Class[] { BoolPtg.class, BoolPtg.class, EqualPtg.class,
-                IntPtg.class, EqualPtg.class, IntPtg.class, EqualPtg.class,  };
-        confirmTokenClasses("TRUE=TRUE=2=2", expClss);
-
-
-        //  2^3^2    evaluates to 64 not 512
-        expClss = new Class[] { IntPtg.class, IntPtg.class, PowerPtg.class,
-                IntPtg.class, PowerPtg.class, };
-        confirmTokenClasses("2^3^2", expClss);
-
-        // "abc" & 2 + 3 & "def"   evaluates to "abc5def"
-        expClss = new Class[] { StringPtg.class, IntPtg.class, IntPtg.class,
-                AddPtg.class, ConcatPtg.class, StringPtg.class, ConcatPtg.class, };
-        confirmTokenClasses("\"abc\"&2+3&\"def\"", expClss);
-
-
-        //  (1 / 2) - (3 * 4)
-        expClss = new Class[] { IntPtg.class, IntPtg.class, DividePtg.class,
-                IntPtg.class, IntPtg.class, MultiplyPtg.class, SubtractPtg.class, };
-        confirmTokenClasses("1/2-3*4", expClss);
-
-        // 2 * (2^2)
-        expClss = new Class[] { IntPtg.class, IntPtg.class, IntPtg.class, PowerPtg.class, MultiplyPtg.class, };
-        // NOT: (2 *2) ^ 2 -> int int multiply int power
-        confirmTokenClasses("2*2^2", expClss);
-
-        //  2^200% -> 2 not 1.6E58
-        expClss = new Class[] { IntPtg.class, IntPtg.class, PercentPtg.class, PowerPtg.class, };
-        confirmTokenClasses("2^200%", expClss);
-    }
-
-    private static void confirmTokenClasses(String formula, Class[] expectedClasses) {
-        Ptg[] ptgs = parseFormula(formula);
-        assertEquals(expectedClasses.length, ptgs.length);
-        for (int i = 0; i < expectedClasses.length; i++) {
-            if(expectedClasses[i] != ptgs[i].getClass()) {
-                fail("difference at token[" + i + "]: expected ("
-                    + expectedClasses[i].getName() + ") but got ("
-                    + ptgs[i].getClass().getName() + ")");
-            }
-        }
-    }
-
-    public void testPower() {
-        confirmTokenClasses("2^5", new Class[] { IntPtg.class, IntPtg.class, PowerPtg.class, });
-    }
-
-    private static Ptg parseSingleToken(String formula, Class ptgClass) {
-        Ptg[] ptgs = parseFormula(formula);
-        assertEquals(1, ptgs.length);
-        Ptg result = ptgs[0];
-        assertEquals(ptgClass, result.getClass());
-        return result;
-    }
-
-    public void testParseNumber() {
-        IntPtg ip;
-
-        // bug 33160
-        ip = (IntPtg) parseSingleToken("40", IntPtg.class);
-        assertEquals(40, ip.getValue());
-        ip = (IntPtg) parseSingleToken("40000", IntPtg.class);
-        assertEquals(40000, ip.getValue());
-
-        // check the upper edge of the IntPtg range:
-        ip = (IntPtg) parseSingleToken("65535", IntPtg.class);
-        assertEquals(65535, ip.getValue());
-        NumberPtg np = (NumberPtg) parseSingleToken("65536", NumberPtg.class);
-        assertEquals(65536, np.getValue(), 0);
-
-        np = (NumberPtg) parseSingleToken("65534.6", NumberPtg.class);
-        assertEquals(65534.6, np.getValue(), 0);
-    }
-
-    public void testMissingArgs() {
-
-        Class[] expClss;
-
-        expClss = new Class[] { ReferencePtg.class, MissingArgPtg.class, ReferencePtg.class,
-                FuncVarPtg.class, };
-        confirmTokenClasses("if(A1, ,C1)", expClss);
-
-        expClss = new Class[] { MissingArgPtg.class, AreaPtg.class, MissingArgPtg.class,
-                FuncVarPtg.class, };
-        confirmTokenClasses("counta( , A1:B2, )", expClss);
-    }
-
-    public void testParseErrorLiterals() {
-
-        confirmParseErrorLiteral(ErrPtg.NULL_INTERSECTION, "#NULL!");
-        confirmParseErrorLiteral(ErrPtg.DIV_ZERO, "#DIV/0!");
-        confirmParseErrorLiteral(ErrPtg.VALUE_INVALID, "#VALUE!");
-        confirmParseErrorLiteral(ErrPtg.REF_INVALID, "#REF!");
-        confirmParseErrorLiteral(ErrPtg.NAME_INVALID, "#NAME?");
-        confirmParseErrorLiteral(ErrPtg.NUM_ERROR, "#NUM!");
-        confirmParseErrorLiteral(ErrPtg.N_A, "#N/A");
-    }
-
-    private static void confirmParseErrorLiteral(ErrPtg expectedToken, String formula) {
-        assertEquals(expectedToken, parseSingleToken(formula, ErrPtg.class));
-    }
-
-    /**
-     * To aid readability the parameters have been encoded with single quotes instead of double
-     * quotes.  This method converts single quotes to double quotes before performing the parse
-     * and result check.
-     */
-    private static void confirmStringParse(String singleQuotedValue) {
-        // formula: internal quotes become double double, surround with double quotes
-        String formula = '"' + singleQuotedValue.replaceAll("'", "\"\"") + '"';
-        String expectedValue = singleQuotedValue.replace('\'', '"');
-
-        StringPtg sp = (StringPtg) parseSingleToken(formula, StringPtg.class);
-        assertEquals(expectedValue, sp.getValue());
-    }
-    public void testParseStringLiterals_bug28754() {
-
-        StringPtg sp;
-        try {
-            sp = (StringPtg) parseSingleToken("\"test\"\"ing\"", StringPtg.class);
-        } catch (RuntimeException e) {
-            if(e.getMessage().startsWith("Cannot Parse")) {
-                throw new AssertionFailedError("Identified bug 28754a");
-            }
-            throw e;
-        }
-        assertEquals("test\"ing", sp.getValue());
-
-        HSSFWorkbook wb = new HSSFWorkbook();
-        HSSFSheet sheet = wb.createSheet();
-        wb.setSheetName(0, "Sheet1");
-
-        HSSFRow row = sheet.createRow(0);
-        HSSFCell cell = row.createCell((short)0);
-        cell.setCellFormula("right(\"test\"\"ing\", 3)");
-        String actualCellFormula = cell.getCellFormula();
-        if("RIGHT(\"test\"ing\",3)".equals(actualCellFormula)) {
-            throw new AssertionFailedError("Identified bug 28754b");
-        }
-        assertEquals("RIGHT(\"test\"\"ing\",3)", actualCellFormula);
-    }
-
-    public void testParseStringLiterals() {
-        confirmStringParse("goto considered harmful");
-
-        confirmStringParse("goto 'considered' harmful");
-
-        confirmStringParse("");
-        confirmStringParse("'");
-        confirmStringParse("''");
-        confirmStringParse("' '");
-        confirmStringParse(" ' ");
-    }
-
-    public void testParseSumIfSum() {
-        String formulaString;
-        Ptg[] ptgs;
-        ptgs = parseFormula("sum(5, 2, if(3>2, sum(A1:A2), 6))");
-        formulaString = FormulaParser.toFormulaString(null, ptgs);
-        assertEquals("SUM(5,2,IF(3>2,SUM(A1:A2),6))", formulaString);
-
-        ptgs = parseFormula("if(1<2,sum(5, 2, if(3>2, sum(A1:A2), 6)),4)");
-        formulaString = FormulaParser.toFormulaString(null, ptgs);
-        assertEquals("IF(1<2,SUM(5,2,IF(3>2,SUM(A1:A2),6)),4)", formulaString);
-    }
-    public void testParserErrors() {
-        parseExpectedException("1 2");
-        parseExpectedException(" 12 . 345  ");
-        parseExpectedException("1 .23  ");
-
-        parseExpectedException("sum(#NAME)");
-        parseExpectedException("1 + #N / A * 2");
-        parseExpectedException("#value?");
-        parseExpectedException("#DIV/ 0+2");
-
-
-        parseExpectedException("IF(TRUE)");
-        parseExpectedException("countif(A1:B5, C1, D1)");
-    }
-
-    private static void parseExpectedException(String formula) {
-        try {
-            parseFormula(formula);
-            throw new AssertionFailedError("expected parse exception");
-        } catch (FormulaParseException e) {
-            // expected during successful test
-            assertNotNull(e.getMessage());
-        } catch (RuntimeException e) {
-            e.printStackTrace();
-            fail("Wrong exception:" + e.getMessage());
-        }
-    }
-
-    public void testSetFormulaWithRowBeyond32768_Bug44539() {
-
-        HSSFWorkbook wb = new HSSFWorkbook();
-        HSSFSheet sheet = wb.createSheet();
-        wb.setSheetName(0, "Sheet1");
-
-        HSSFRow row = sheet.createRow(0);
-        HSSFCell cell = row.createCell((short)0);
-        cell.setCellFormula("SUM(A32769:A32770)");
-        if("SUM(A-32767:A-32766)".equals(cell.getCellFormula())) {
-            fail("Identified bug 44539");
-        }
-        assertEquals("SUM(A32769:A32770)", cell.getCellFormula());
-    }
-
-    public void testSpaceAtStartOfFormula() {
-        // Simulating cell formula of "= 4" (note space)
-        // The same Ptg array can be observed if an excel file is saved with that exact formula
-
-        AttrPtg spacePtg = AttrPtg.createSpace(AttrPtg.SpaceType.SPACE_BEFORE, 1);
-        Ptg[] ptgs = { spacePtg, new IntPtg(4), };
-        String formulaString;
-        try {
-            formulaString = FormulaParser.toFormulaString(null, ptgs);
-        } catch (IllegalStateException e) {
-            if(e.getMessage().equalsIgnoreCase("too much stuff left on the stack")) {
-                throw new AssertionFailedError("Identified bug 44609");
-            }
-            // else some unexpected error
-            throw e;
-        }
-        // FormulaParser strips spaces anyway
-        assertEquals("4", formulaString);
-
-        ptgs = new Ptg[] { new IntPtg(3), spacePtg, new IntPtg(4), spacePtg, new AddPtg()};
-        formulaString = FormulaParser.toFormulaString(null, ptgs);
-        assertEquals("3+4", formulaString);
-    }
-
-    /**
-     * Checks some internal error detecting logic ('stack underflow error' in toFormulaString)
-     */
-    public void testTooFewOperandArgs() {
-        // Simulating badly encoded cell formula of "=/1"
-        // Not sure if Excel could ever produce this
-        Ptg[] ptgs = {
-                // Excel would probably have put tMissArg here
-                new IntPtg(1),
-                new DividePtg(),
-        };
-        try {
-            FormulaParser.toFormulaString(null, ptgs);
-            fail("Expected exception was not thrown");
-        } catch (IllegalStateException e) {
-            // expected during successful test
-            assertTrue(e.getMessage().startsWith("Too few arguments suppled to operation token"));
-        }
-    }
-    /**
-     * Make sure that POI uses the right Func Ptg when encoding formulas.  Functions with variable
-     * number of args should get FuncVarPtg, functions with fixed args should get FuncPtg.<p/>
-     * 
-     * Prior to the fix for bug 44675 POI would encode FuncVarPtg for all functions.  In many cases
-     * Excel tolerates the wrong Ptg and evaluates the formula OK (e.g. SIN), but in some cases 
-     * (e.g. COUNTIF) Excel fails to evaluate the formula, giving '#VALUE!' instead. 
-     */
-    public void testFuncPtgSelection() {
-        HSSFWorkbook book = new HSSFWorkbook();
-        Ptg[] ptgs;
-        ptgs = FormulaParser.parse("countif(A1:A2, 1)", book);
-        assertEquals(3, ptgs.length);
-        if(FuncVarPtg.class == ptgs[2].getClass()) {
-            throw new AssertionFailedError("Identified bug 44675");
-        }
-        assertEquals(FuncPtg.class, ptgs[2].getClass());
-        ptgs = FormulaParser.parse("sin(1)", book);
-        assertEquals(2, ptgs.length);
-        assertEquals(FuncPtg.class, ptgs[1].getClass());
-    }
-    
-    public void testWrongNumberOfFunctionArgs() {
-        confirmArgCountMsg("sin()", "Too few arguments to function 'SIN'. Expected 1 but got 0.");
-        confirmArgCountMsg("countif(1, 2, 3, 4)", "Too many arguments to function 'COUNTIF'. Expected 2 but got 4.");
-        confirmArgCountMsg("index(1, 2, 3, 4, 5, 6)", "Too many arguments to function 'INDEX'. At most 4 were expected but got 6.");
-        confirmArgCountMsg("vlookup(1, 2)", "Too few arguments to function 'VLOOKUP'. At least 3 were expected but got 2.");
-    }
-
-    private static void confirmArgCountMsg(String formula, String expectedMessage) {
-        HSSFWorkbook book = new HSSFWorkbook();
-        try {
-            FormulaParser.parse(formula, book);
-            throw new AssertionFailedError("Didn't get parse exception as expected");
-        } catch (FormulaParseException e) {
-            assertEquals(expectedMessage, e.getMessage());
-        }
-    }
+	public void testMissingArgs() {
+
+		Class[] expClss;
+
+		expClss = new Class[] { ReferencePtg.class, MissingArgPtg.class, ReferencePtg.class,
+				FuncVarPtg.class, };
+		confirmTokenClasses("if(A1, ,C1)", expClss);
+
+		expClss = new Class[] { MissingArgPtg.class, AreaPtg.class, MissingArgPtg.class,
+				FuncVarPtg.class, };
+		confirmTokenClasses("counta( , A1:B2, )", expClss);
+	}
+
+	public void testParseErrorLiterals() {
+
+		confirmParseErrorLiteral(ErrPtg.NULL_INTERSECTION, "#NULL!");
+		confirmParseErrorLiteral(ErrPtg.DIV_ZERO, "#DIV/0!");
+		confirmParseErrorLiteral(ErrPtg.VALUE_INVALID, "#VALUE!");
+		confirmParseErrorLiteral(ErrPtg.REF_INVALID, "#REF!");
+		confirmParseErrorLiteral(ErrPtg.NAME_INVALID, "#NAME?");
+		confirmParseErrorLiteral(ErrPtg.NUM_ERROR, "#NUM!");
+		confirmParseErrorLiteral(ErrPtg.N_A, "#N/A");
+	}
+
+	private static void confirmParseErrorLiteral(ErrPtg expectedToken, String formula) {
+		assertEquals(expectedToken, parseSingleToken(formula, ErrPtg.class));
+	}
+
+	/**
+	 * To aid readability the parameters have been encoded with single quotes instead of double
+	 * quotes.  This method converts single quotes to double quotes before performing the parse
+	 * and result check.
+	 */
+	private static void confirmStringParse(String singleQuotedValue) {
+		// formula: internal quotes become double double, surround with double quotes
+		String formula = '"' + singleQuotedValue.replaceAll("'", "\"\"") + '"';
+		String expectedValue = singleQuotedValue.replace('\'', '"');
+
+		StringPtg sp = (StringPtg) parseSingleToken(formula, StringPtg.class);
+		assertEquals(expectedValue, sp.getValue());
+	}
+	public void testParseStringLiterals_bug28754() {
+
+		StringPtg sp;
+		try {
+			sp = (StringPtg) parseSingleToken("\"test\"\"ing\"", StringPtg.class);
+		} catch (RuntimeException e) {
+			if(e.getMessage().startsWith("Cannot Parse")) {
+				throw new AssertionFailedError("Identified bug 28754a");
+			}
+			throw e;
+		}
+		assertEquals("test\"ing", sp.getValue());
+
+		HSSFWorkbook wb = new HSSFWorkbook();
+		HSSFSheet sheet = wb.createSheet();
+		wb.setSheetName(0, "Sheet1");
+
+		HSSFRow row = sheet.createRow(0);
+		HSSFCell cell = row.createCell((short)0);
+		cell.setCellFormula("right(\"test\"\"ing\", 3)");
+		String actualCellFormula = cell.getCellFormula();
+		if("RIGHT(\"test\"ing\",3)".equals(actualCellFormula)) {
+			throw new AssertionFailedError("Identified bug 28754b");
+		}
+		assertEquals("RIGHT(\"test\"\"ing\",3)", actualCellFormula);
+	}
+
+	public void testParseStringLiterals() {
+		confirmStringParse("goto considered harmful");
+
+		confirmStringParse("goto 'considered' harmful");
+
+		confirmStringParse("");
+		confirmStringParse("'");
+		confirmStringParse("''");
+		confirmStringParse("' '");
+		confirmStringParse(" ' ");
+	}
+
+	public void testParseSumIfSum() {
+		String formulaString;
+		Ptg[] ptgs;
+		ptgs = parseFormula("sum(5, 2, if(3>2, sum(A1:A2), 6))");
+		formulaString = FormulaParser.toFormulaString(null, ptgs);
+		assertEquals("SUM(5,2,IF(3>2,SUM(A1:A2),6))", formulaString);
+
+		ptgs = parseFormula("if(1<2,sum(5, 2, if(3>2, sum(A1:A2), 6)),4)");
+		formulaString = FormulaParser.toFormulaString(null, ptgs);
+		assertEquals("IF(1<2,SUM(5,2,IF(3>2,SUM(A1:A2),6)),4)", formulaString);
+	}
+	public void testParserErrors() {
+		parseExpectedException("1 2");
+		parseExpectedException(" 12 . 345  ");
+		parseExpectedException("1 .23  ");
+
+		parseExpectedException("sum(#NAME)");
+		parseExpectedException("1 + #N / A * 2");
+		parseExpectedException("#value?");
+		parseExpectedException("#DIV/ 0+2");
+
+
+		parseExpectedException("IF(TRUE)");
+		parseExpectedException("countif(A1:B5, C1, D1)");
+	}
+
+	private static void parseExpectedException(String formula) {
+		try {
+			parseFormula(formula);
+			throw new AssertionFailedError("expected parse exception");
+		} catch (FormulaParseException e) {
+			// expected during successful test
+			assertNotNull(e.getMessage());
+		} catch (RuntimeException e) {
+			e.printStackTrace();
+			fail("Wrong exception:" + e.getMessage());
+		}
+	}
+
+	public void testSetFormulaWithRowBeyond32768_Bug44539() {
+
+		HSSFWorkbook wb = new HSSFWorkbook();
+		HSSFSheet sheet = wb.createSheet();
+		wb.setSheetName(0, "Sheet1");
+
+		HSSFRow row = sheet.createRow(0);
+		HSSFCell cell = row.createCell((short)0);
+		cell.setCellFormula("SUM(A32769:A32770)");
+		if("SUM(A-32767:A-32766)".equals(cell.getCellFormula())) {
+			fail("Identified bug 44539");
+		}
+		assertEquals("SUM(A32769:A32770)", cell.getCellFormula());
+	}
+
+	public void testSpaceAtStartOfFormula() {
+		// Simulating cell formula of "= 4" (note space)
+		// The same Ptg array can be observed if an excel file is saved with that exact formula
+
+		AttrPtg spacePtg = AttrPtg.createSpace(AttrPtg.SpaceType.SPACE_BEFORE, 1);
+		Ptg[] ptgs = { spacePtg, new IntPtg(4), };
+		String formulaString;
+		try {
+			formulaString = FormulaParser.toFormulaString(null, ptgs);
+		} catch (IllegalStateException e) {
+			if(e.getMessage().equalsIgnoreCase("too much stuff left on the stack")) {
+				throw new AssertionFailedError("Identified bug 44609");
+			}
+			// else some unexpected error
+			throw e;
+		}
+		// FormulaParser strips spaces anyway
+		assertEquals("4", formulaString);
+
+		ptgs = new Ptg[] { new IntPtg(3), spacePtg, new IntPtg(4), spacePtg, new AddPtg()};
+		formulaString = FormulaParser.toFormulaString(null, ptgs);
+		assertEquals("3+4", formulaString);
+	}
+
+	/**
+	 * Checks some internal error detecting logic ('stack underflow error' in toFormulaString)
+	 */
+	public void testTooFewOperandArgs() {
+		// Simulating badly encoded cell formula of "=/1"
+		// Not sure if Excel could ever produce this
+		Ptg[] ptgs = {
+				// Excel would probably have put tMissArg here
+				new IntPtg(1),
+				new DividePtg(),
+		};
+		try {
+			FormulaParser.toFormulaString(null, ptgs);
+			fail("Expected exception was not thrown");
+		} catch (IllegalStateException e) {
+			// expected during successful test
+			assertTrue(e.getMessage().startsWith("Too few arguments suppled to operation token"));
+		}
+	}
+	/**
+	 * Make sure that POI uses the right Func Ptg when encoding formulas.  Functions with variable
+	 * number of args should get FuncVarPtg, functions with fixed args should get FuncPtg.<p/>
+	 * 
+	 * Prior to the fix for bug 44675 POI would encode FuncVarPtg for all functions.  In many cases
+	 * Excel tolerates the wrong Ptg and evaluates the formula OK (e.g. SIN), but in some cases 
+	 * (e.g. COUNTIF) Excel fails to evaluate the formula, giving '#VALUE!' instead. 
+	 */
+	public void testFuncPtgSelection() {
+
+		Ptg[] ptgs;
+		ptgs = parseFormula("countif(A1:A2, 1)");
+		assertEquals(3, ptgs.length);
+		if(FuncVarPtg.class == ptgs[2].getClass()) {
+			throw new AssertionFailedError("Identified bug 44675");
+		}
+		assertEquals(FuncPtg.class, ptgs[2].getClass());
+		ptgs = parseFormula("sin(1)");
+		assertEquals(2, ptgs.length);
+		assertEquals(FuncPtg.class, ptgs[1].getClass());
+	}
+
+	public void testWrongNumberOfFunctionArgs() {
+		confirmArgCountMsg("sin()", "Too few arguments to function 'SIN'. Expected 1 but got 0.");
+		confirmArgCountMsg("countif(1, 2, 3, 4)", "Too many arguments to function 'COUNTIF'. Expected 2 but got 4.");
+		confirmArgCountMsg("index(1, 2, 3, 4, 5, 6)", "Too many arguments to function 'INDEX'. At most 4 were expected but got 6.");
+		confirmArgCountMsg("vlookup(1, 2)", "Too few arguments to function 'VLOOKUP'. At least 3 were expected but got 2.");
+	}
+
+	private static void confirmArgCountMsg(String formula, String expectedMessage) {
+		HSSFWorkbook book = new HSSFWorkbook();
+		try {
+			FormulaParser.parse(formula, book);
+			throw new AssertionFailedError("Didn't get parse exception as expected");
+		} catch (FormulaParseException e) {
+			assertEquals(expectedMessage, e.getMessage());
+		}
+	}
+
+	public void testParseErrorExpecteMsg() {
+
+		try {
+			parseFormula("round(3.14;2)");
+			throw new AssertionFailedError("Didn't get parse exception as expected");
+		} catch (FormulaParseException e) {
+			assertEquals("Parse error near char 10 ';' in specified formula 'round(3.14;2)'. Expected ',' or ')'", e.getMessage());
+		}
+	}
 }

Modified: poi/branches/ooxml/src/testcases/org/apache/poi/hssf/model/TestSheet.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/testcases/org/apache/poi/hssf/model/TestSheet.java?rev=659485&r1=659484&r2=659485&view=diff
==============================================================================
--- poi/branches/ooxml/src/testcases/org/apache/poi/hssf/model/TestSheet.java (original)
+++ poi/branches/ooxml/src/testcases/org/apache/poi/hssf/model/TestSheet.java Fri May 23 02:48:23 2008
@@ -17,6 +17,7 @@
 
 package org.apache.poi.hssf.model;
 
+import junit.framework.AssertionFailedError;
 import junit.framework.TestCase;
 import org.apache.poi.hssf.record.*;
 import org.apache.poi.hssf.record.aggregates.ColumnInfoRecordsAggregate;
@@ -351,5 +352,25 @@
         xfindex = sheet.getXFIndexForColAt((short) 10);
         assertEquals(DEFAULT_IDX, xfindex);
     }
+
+    /**
+     * Prior to bug 45066, POI would get the estimated sheet size wrong 
+     * when an <tt>UncalcedRecord</tt> was present.<p/>
+     */
+    public void testUncalcSize_bug45066() {
+
+        List records = new ArrayList();
+        records.add(new BOFRecord());
+        records.add(new UncalcedRecord());
+        records.add(new EOFRecord());
+        Sheet sheet = Sheet.createSheet( records, 0, 0 );
+
+        int estimatedSize = sheet.getSize();
+        int serializedSize = sheet.serialize(0, new byte[estimatedSize]);
+        if (serializedSize != estimatedSize) {
+            throw new AssertionFailedError("Identified bug 45066 b");
+        }
+        assertEquals(50, serializedSize);
+    }
 }
 

Modified: poi/branches/ooxml/src/testcases/org/apache/poi/hssf/record/formula/function/ExcelFileFormatDocFunctionExtractor.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/testcases/org/apache/poi/hssf/record/formula/function/ExcelFileFormatDocFunctionExtractor.java?rev=659485&r1=659484&r2=659485&view=diff
==============================================================================
--- poi/branches/ooxml/src/testcases/org/apache/poi/hssf/record/formula/function/ExcelFileFormatDocFunctionExtractor.java (original)
+++ poi/branches/ooxml/src/testcases/org/apache/poi/hssf/record/formula/function/ExcelFileFormatDocFunctionExtractor.java Fri May 23 02:48:23 2008
@@ -26,9 +26,12 @@
 import java.io.OutputStream;
 import java.io.PrintStream;
 import java.io.UnsupportedEncodingException;
+import java.math.BigInteger;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.net.URLConnection;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -37,7 +40,6 @@
 import java.util.Map;
 import java.util.Set;
 import java.util.Stack;
-import java.util.zip.CRC32;
 import java.util.zip.ZipException;
 import java.util.zip.ZipFile;
 
@@ -149,7 +151,6 @@
 	
 	private static final class FunctionDataCollector {
 
-
 		private final Map _allFunctionsByIndex;
 		private final Map _allFunctionsByName;
 		private final Set _groupFunctionIndexes;
@@ -184,25 +185,29 @@
 			_allFunctionsByName.put(funcName, fd);
 		}
 
+		/**
+		 * Some extra validation here.
+		 * Any function which changes definition will have a footnote in the source document
+		 */
 		private void checkRedefinedFunction(boolean hasNote, String funcName, Integer funcIxKey) {
 			FunctionData fdPrev;
+			// check by index
 			fdPrev = (FunctionData) _allFunctionsByIndex.get(funcIxKey);
 			if(fdPrev != null) {
-				if(fdPrev.hasFootnote() && hasNote) {
-					// func def can change if both have a foot-note
-					_allFunctionsByName.remove(fdPrev.getName());
-				} else {
-					throw new RuntimeException("changing function definition without foot-note");
+				if(!fdPrev.hasFootnote() || !hasNote) {
+					throw new RuntimeException("changing function [" 
+							+ funcIxKey + "] definition without foot-note");
 				}
+				_allFunctionsByName.remove(fdPrev.getName());
 			}
+			// check by name
 			fdPrev = (FunctionData) _allFunctionsByName.get(funcName);
 			if(fdPrev != null) {
-				if(fdPrev.hasFootnote() && hasNote) {
-					// func def can change if both have a foot-note
-					_allFunctionsByIndex.remove(new Integer(fdPrev.getIndex()));
-				} else {
-					throw new RuntimeException("changing function definition without foot-note");
+				if(!fdPrev.hasFootnote() || !hasNote) {
+					throw new RuntimeException("changing function '" 
+							+ funcName + "' definition without foot-note");
 				}
+				_allFunctionsByIndex.remove(new Integer(fdPrev.getIndex()));
 			}
 		}
 
@@ -237,9 +242,13 @@
 		private static final String[] TABLE_CELL_RELPATH_NAMES = {
 			"table:table-row", "table:table-cell", "text:p",	
 		};
-		private static final String[] NOTE_REF_RELPATH_NAMES = {
+		// after May 2008 there was one more style applied to the footnotes
+		private static final String[] NOTE_REF_RELPATH_NAMES_OLD = { 
 			"table:table-row", "table:table-cell", "text:p", "text:span", "text:note-ref",
 		};
+		private static final String[] NOTE_REF_RELPATH_NAMES = {
+			"table:table-row", "table:table-cell", "text:p", "text:span", "text:span", "text:note-ref",
+		};
 
 
 		private final Stack _elemNameStack;
@@ -368,6 +377,8 @@
 			} else if(matchesRelPath(TABLE_CELL_RELPATH_NAMES)) {
 				_textNodeBuffer.setLength(0);
 				_cellHasNote = false;
+			} else if(matchesRelPath(NOTE_REF_RELPATH_NAMES_OLD)) {
+				_cellHasNote = true;
 			} else if(matchesRelPath(NOTE_REF_RELPATH_NAMES)) {
 				_cellHasNote = true;
 			}
@@ -456,6 +467,9 @@
 	}
 
 	private static void processFile(File effDocFile, File outFile) {
+		if(!effDocFile.exists()) {
+			throw new RuntimeException("file '" + effDocFile.getAbsolutePath() + "' does not exist");
+		}
 		OutputStream os;
 		try {
 			os = new FileOutputStream(outFile);
@@ -475,7 +489,7 @@
 		ps.println("# Created by (" + genClass.getName() + ")");
 		// identify the source file
 		ps.print("# from source file '" + SOURCE_DOC_FILE_NAME + "'");
-		ps.println(" (size=" + effDocFile.length() + ", crc=" + getFileCRC(effDocFile) + ")");
+		ps.println(" (size=" + effDocFile.length() + ", md5=" + getFileMD5(effDocFile) + ")");
 		ps.println("#");
 		ps.println("#Columns: (index, name, minParams, maxParams, returnClass, paramClasses, isVolatile, hasFootnote )");
 		ps.println("");
@@ -490,6 +504,14 @@
 			throw new RuntimeException(e);
 		}
 		ps.close();
+		
+		String canonicalOutputFileName;
+		try {
+			canonicalOutputFileName = outFile.getCanonicalPath();
+		} catch (IOException e) {
+			throw new RuntimeException(e);
+		}
+		System.out.println("Successfully output to '" + canonicalOutputFileName + "'");
 	}
 
 	private static void outputLicenseHeader(PrintStream ps) {
@@ -519,8 +541,14 @@
 	/**
 	 * Helps identify the source file
 	 */
-	private static String getFileCRC(File f) {
-		CRC32 crc = new CRC32();
+	private static String getFileMD5(File f) {
+		MessageDigest m;
+		try {
+			m = MessageDigest.getInstance("MD5");
+		} catch (NoSuchAlgorithmException e) {
+			throw new RuntimeException(e);
+		}
+
 		byte[]buf = new byte[2048];
 		try {
 			InputStream is = new FileInputStream(f);
@@ -529,21 +557,17 @@
 				if(bytesRead<1) { 
 					break;
 				}
-				crc.update(buf, 0, bytesRead);
+				m.update(buf, 0, bytesRead);
 			}
 			is.close();
 		} catch (IOException e) {
 			throw new RuntimeException(e);
 		}
-		return "0x" + Long.toHexString(crc.getValue()).toUpperCase();
+		
+		return "0x" + new BigInteger(1, m.digest()).toString(16);
 	}
 
-	private static File getSourceFile() {
-		if (false) {
-			File dir = new File("c:/temp");
-			File effDocFile = new File(dir, SOURCE_DOC_FILE_NAME);
-			return effDocFile;
-		}
+	private static File downloadSourceFile() {
 		URL url;
 		try {
 			url = new URL("http://sc.openoffice.org/" + SOURCE_DOC_FILE_NAME);
@@ -557,7 +581,7 @@
 			URLConnection conn = url.openConnection();
 			InputStream is = conn.getInputStream();
 			System.out.println("downloading " + url.toExternalForm());
-			result = File.createTempFile("excelfileformat", "odt");
+			result = File.createTempFile("excelfileformat", ".odt");
 			OutputStream os = new FileOutputStream(result);
 			while(true) {
 				int bytesRead = is.read(buf);
@@ -577,12 +601,17 @@
 
 	public static void main(String[] args) {
 
-		File effDocFile = getSourceFile();
-		if(!effDocFile.exists()) {
-			throw new RuntimeException("file '" + effDocFile.getAbsolutePath() + "' does not exist");
-		}
-
 		File outFile = new File("functionMetadata-asGenerated.txt");
-		processFile(effDocFile, outFile);
+
+		if (false) { // set true to use local file
+			File dir = new File("c:/temp");
+			File effDocFile = new File(dir, SOURCE_DOC_FILE_NAME);
+			processFile(effDocFile, outFile);
+			return;
+		}
+		
+		File tempEFFDocFile = downloadSourceFile();
+		processFile(tempEFFDocFile, outFile);
+		tempEFFDocFile.delete();
 	}
 }

Modified: poi/branches/ooxml/src/testcases/org/apache/poi/hssf/record/formula/function/TestParseMissingBuiltInFuncs.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/testcases/org/apache/poi/hssf/record/formula/function/TestParseMissingBuiltInFuncs.java?rev=659485&r1=659484&r2=659485&view=diff
==============================================================================
--- poi/branches/ooxml/src/testcases/org/apache/poi/hssf/record/formula/function/TestParseMissingBuiltInFuncs.java (original)
+++ poi/branches/ooxml/src/testcases/org/apache/poi/hssf/record/formula/function/TestParseMissingBuiltInFuncs.java Fri May 23 02:48:23 2008
@@ -21,7 +21,6 @@
 import junit.framework.TestCase;
 
 import org.apache.poi.hssf.model.FormulaParser;
-import org.apache.poi.hssf.model.Workbook;
 import org.apache.poi.hssf.record.formula.AbstractFunctionPtg;
 import org.apache.poi.hssf.record.formula.FuncPtg;
 import org.apache.poi.hssf.record.formula.FuncVarPtg;
@@ -29,7 +28,7 @@
 import org.apache.poi.hssf.usermodel.HSSFWorkbook;
 /**
  * Tests parsing of some built-in functions that were not properly
- * registered in POI as bug #44675, #44733 (March/April 2008).
+ * registered in POI as of bug #44675, #44733 (March/April 2008).
  * 
  * @author Josh Micich
  */
@@ -76,7 +75,7 @@
 	}
 	
 	public void testUsdollar() {
-		confirmFunc("USDOLLAR(1)", 2, false, 204);
+		confirmFunc("USDOLLAR(1)", 2, true, 204);
 	}
 
 	public void testDBCS() {

Modified: poi/branches/ooxml/src/testcases/org/apache/poi/hssf/record/formula/function/TestReadMissingBuiltInFuncs.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/testcases/org/apache/poi/hssf/record/formula/function/TestReadMissingBuiltInFuncs.java?rev=659485&r1=659484&r2=659485&view=diff
==============================================================================
--- poi/branches/ooxml/src/testcases/org/apache/poi/hssf/record/formula/function/TestReadMissingBuiltInFuncs.java (original)
+++ poi/branches/ooxml/src/testcases/org/apache/poi/hssf/record/formula/function/TestReadMissingBuiltInFuncs.java Fri May 23 02:48:23 2008
@@ -17,22 +17,18 @@
 
 package org.apache.poi.hssf.record.formula.function;
 
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
 import java.lang.reflect.InvocationTargetException;
 
+import junit.framework.AssertionFailedError;
+import junit.framework.TestCase;
+
 import org.apache.poi.hssf.HSSFTestDataSamples;
 import org.apache.poi.hssf.record.RecordFormatException;
 import org.apache.poi.hssf.usermodel.HSSFSheet;
 import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-
-import junit.framework.AssertionFailedError;
-import junit.framework.TestCase;
 /**
  * Tests reading from a sample spreadsheet some built-in functions that were not properly
- * registered in POI as bug #44675, #44733 (March/April 2008).
+ * registered in POI as of bug #44675, #44733 (March/April 2008).
  * 
  * @author Josh Micich
  */

Modified: poi/branches/ooxml/src/testcases/org/apache/poi/hssf/usermodel/AllUserModelTests.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/testcases/org/apache/poi/hssf/usermodel/AllUserModelTests.java?rev=659485&r1=659484&r2=659485&view=diff
==============================================================================
--- poi/branches/ooxml/src/testcases/org/apache/poi/hssf/usermodel/AllUserModelTests.java (original)
+++ poi/branches/ooxml/src/testcases/org/apache/poi/hssf/usermodel/AllUserModelTests.java Fri May 23 02:48:23 2008
@@ -28,7 +28,7 @@
 public class AllUserModelTests {
 	
 	public static Test suite() {
-		TestSuite result = new TestSuite("Tests for org.apache.poi.hssf.usermodel");
+		TestSuite result = new TestSuite(AllUserModelTests.class.getName());
 		
 		result.addTestSuite(TestBugs.class);
 		result.addTestSuite(TestCellStyle.class);
@@ -58,6 +58,7 @@
 		result.addTestSuite(TestHSSFSheetSetOrder.class);
 		result.addTestSuite(TestHSSFTextbox.class);
 		result.addTestSuite(TestHSSFWorkbook.class);
+		result.addTestSuite(TestLinkTable.class);
 		result.addTestSuite(TestNamedRange.class);
 		result.addTestSuite(TestOLE2Embeding.class);
 		result.addTestSuite(TestPOIFSProperties.class);

Modified: poi/branches/ooxml/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFCell.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFCell.java?rev=659485&r1=659484&r2=659485&view=diff
==============================================================================
--- poi/branches/ooxml/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFCell.java (original)
+++ poi/branches/ooxml/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFCell.java Fri May 23 02:48:23 2008
@@ -58,6 +58,30 @@
         }
     }
     
+    public void testSetValues() throws Exception {
+        HSSFWorkbook book = new HSSFWorkbook();
+        HSSFSheet sheet = book.createSheet("test");
+        HSSFRow row = sheet.createRow(0);
+
+        HSSFCell cell = row.createCell((short)0);
+        
+        cell.setCellValue(1.2);
+        assertEquals(1.2, cell.getNumericCellValue(), 0.0001);
+        assertEquals(HSSFCell.CELL_TYPE_NUMERIC, cell.getCellType());
+        
+        cell.setCellValue(false);
+        assertEquals(false, cell.getBooleanCellValue());
+        assertEquals(HSSFCell.CELL_TYPE_BOOLEAN, cell.getCellType());
+        
+        cell.setCellValue(new HSSFRichTextString("Foo"));
+        assertEquals("Foo", cell.getRichStringCellValue().getString());
+        assertEquals(HSSFCell.CELL_TYPE_STRING, cell.getCellType());
+        
+        cell.setCellValue(new HSSFRichTextString("345"));
+        assertEquals("345", cell.getRichStringCellValue().getString());
+        assertEquals(HSSFCell.CELL_TYPE_STRING, cell.getCellType());
+    }
+    
     /**
      * test that Boolean and Error types (BoolErrRecord) are supported properly.
      */

Modified: poi/branches/ooxml/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFDateUtil.java
URL: http://svn.apache.org/viewvc/poi/branches/ooxml/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFDateUtil.java?rev=659485&r1=659484&r2=659485&view=diff
==============================================================================
--- poi/branches/ooxml/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFDateUtil.java (original)
+++ poi/branches/ooxml/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFDateUtil.java Fri May 23 02:48:23 2008
@@ -266,6 +266,8 @@
         formats = new String[] {
                 "yyyy-mm-dd hh:mm:ss", "yyyy/mm/dd HH:MM:SS", 
                 "mm/dd HH:MM", "yy/mmm/dd SS",
+                "mm/dd HH:MM AM", "mm/dd HH:MM am",
+                "mm/dd HH:MM PM", "mm/dd HH:MM pm" 
         };
         for(int i=0; i<formats.length; i++) {
             assertTrue( HSSFDateUtil.isADateFormat(formatId, formats[i]) );



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


Mime
View raw message