You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@poi.apache.org by dm...@apache.org on 2003/03/15 02:57:42 UTC

cvs commit: jakarta-poi/src/testcases/org/apache/poi/hssf/usermodel TestFormulas.java

dmui        2003/03/14 17:57:42

  Modified:    src/java/org/apache/poi/hssf/model FormulaParser.java
               src/java/org/apache/poi/hssf/record/formula
                        AbstractFunctionPtg.java AttrPtg.java
               src/testcases/org/apache/poi/hssf/model
                        TestFormulaParser.java
               src/testcases/org/apache/poi/hssf/usermodel
                        TestFormulas.java
  Log:
  FormulaParser changes to support IF function(s)
  
  Revision  Changes    Path
  1.8       +159 -13   jakarta-poi/src/java/org/apache/poi/hssf/model/FormulaParser.java
  
  Index: FormulaParser.java
  ===================================================================
  RCS file: /home/cvs/jakarta-poi/src/java/org/apache/poi/hssf/model/FormulaParser.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- FormulaParser.java	9 Oct 2002 00:05:52 -0000	1.7
  +++ FormulaParser.java	15 Mar 2003 01:57:41 -0000	1.8
  @@ -2,7 +2,7 @@
   /* ====================================================================
    * The Apache Software License, Version 1.1
    *
  - * Copyright (c) 2002 The Apache Software Foundation.  All rights
  + * Copyright (c) 2002, 2003 The Apache Software Foundation.  All rights
    * reserved.
    *
    * Redistribution and use in source and binary forms, with or without
  @@ -56,12 +56,34 @@
   
   package org.apache.poi.hssf.model;
   
  -import org.apache.poi.hssf.record.formula.*;
  -import org.apache.poi.hssf.util.SheetReferences;
  -
   import java.util.ArrayList;
  +import java.util.Iterator;
  +import java.util.LinkedList;
   import java.util.List;
   
  +import org.apache.poi.hssf.record.formula.AbstractFunctionPtg;
  +import org.apache.poi.hssf.record.formula.AddPtg;
  +import org.apache.poi.hssf.record.formula.Area3DPtg;
  +import org.apache.poi.hssf.record.formula.AreaPtg;
  +import org.apache.poi.hssf.record.formula.AttrPtg;
  +import org.apache.poi.hssf.record.formula.BoolPtg;
  +import org.apache.poi.hssf.record.formula.ConcatPtg;
  +import org.apache.poi.hssf.record.formula.DividePtg;
  +import org.apache.poi.hssf.record.formula.EqualPtg;
  +import org.apache.poi.hssf.record.formula.FuncVarPtg;
  +import org.apache.poi.hssf.record.formula.IntPtg;
  +import org.apache.poi.hssf.record.formula.MultiplyPtg;
  +import org.apache.poi.hssf.record.formula.NumberPtg;
  +import org.apache.poi.hssf.record.formula.OperationPtg;
  +import org.apache.poi.hssf.record.formula.ParenthesisPtg;
  +import org.apache.poi.hssf.record.formula.PowerPtg;
  +import org.apache.poi.hssf.record.formula.Ptg;
  +import org.apache.poi.hssf.record.formula.Ref3DPtg;
  +import org.apache.poi.hssf.record.formula.ReferencePtg;
  +import org.apache.poi.hssf.record.formula.StringPtg;
  +import org.apache.poi.hssf.record.formula.SubtractPtg;
  +import org.apache.poi.hssf.util.SheetReferences;
  +
   
   /**
    * This class parses a formula string into a List of tokens in RPN order.
  @@ -90,6 +112,12 @@
       private int formulaLength;
       
       private List tokens = new java.util.Stack();
  +    
  +    /**
  +     * Using an unsynchronized linkedlist to implement a stack since we're not multi-threaded.
  +     */
  +    private List functionTokens = new LinkedList();
  +    
       //private Stack tokens = new java.util.Stack();
       private List result = new ArrayList();
       private int numParen;
  @@ -98,6 +126,7 @@
       private static char CR = '\n';
       
      private char look;              // Lookahead Character
  +   private boolean inFunction = false;
      
      private Workbook book;
       
  @@ -297,25 +326,140 @@
           }
       }
       
  +    /**
  +     * Adds a pointer to the last token to the latest function argument list.
  +     * @param obj
  +     */
  +    private void addArgumentPointer() {
  +		if (this.functionTokens.size() > 0) {
  +			//no bounds check because this method should not be called unless a token array is setup by function()
  +			List arguments = (List)this.functionTokens.get(0);
  +			arguments.add(tokens.get(tokens.size()-1));
  +		}
  +    }
  +    
       private void function(String name) {
  +    	//average 2 args per function
  +    	this.functionTokens.add(0, new ArrayList(2));
  +    	
           Match('(');
           int numArgs = Arguments();
           Match(')');
  -        tokens.add(getFunction(name,(byte)numArgs));
  +                
  +        Ptg functionPtg = getFunction(name,(byte)numArgs);
  +        
  +		tokens.add(functionPtg);
  + 
  + 		//remove what we just put in
  +		this.functionTokens.remove(0);
       }
       
  +    /**
  +     * Adds the size of all the ptgs after the provided index (inclusive).
  +     * <p>
  +     * Initially used to count a goto
  +     * @param index
  +     * @return int
  +     */
  +    private int getPtgSize(int index) {
  +    	int count = 0;
  +    	
  +    	Iterator ptgIterator = tokens.listIterator(index);
  +    	while (ptgIterator.hasNext()) {
  +    		Ptg ptg = (Ptg)ptgIterator.next();
  +    		count+=ptg.getSize();
  +    	}
  +    	
  +    	return count;
  +    }
  +    
  +    private int getPtgSize(int start, int end) {
  +		int count = 0;
  +    	int index = start;
  +		Iterator ptgIterator = tokens.listIterator(index);
  +		while (ptgIterator.hasNext() && index <= end) {
  +			Ptg ptg = (Ptg)ptgIterator.next();
  +			count+=ptg.getSize();
  +			index++;
  +		}
  +    	
  +		return count;
  +    }
  +    
  +    /**
  +     * Generates the variable function ptg for the formula.
  +     * <p>
  +     * For IF Formulas, additional PTGs are added to the tokens 
  +     * @param name
  +     * @param numArgs
  +     * @return Ptg a null is returned if we're in an IF formula, it needs extreme manipulation and is handled in this function
  +     */
       private Ptg getFunction(String name,byte numArgs) {
           Ptg retval = null;
  -        //retval = new FuncVarPtg(name,numArgs);
  -       if (name.equals("IF")) {
  -            AttrPtg ptg = new AttrPtg();
  -            ptg.setData((short)6); //sums don't care but this is what excel does.
  -            ptg.setOptimizedIf(true);
  -            retval = ptg;
  +        
  +       if (name.equals("IF")) {			
  +			retval = new FuncVarPtg(AbstractFunctionPtg.ATTR_NAME, numArgs);
  +			
  +			//simulated pop, no bounds checking because this list better be populated by function()       	
  +			List argumentPointers = (List)this.functionTokens.get(0);
  +
  +			
  +            AttrPtg ifPtg = new AttrPtg();
  +			ifPtg.setData((short)7); //mirroring excel output
  +			ifPtg.setOptimizedIf(true);
  +		
  +            if (argumentPointers.size() != 2  && argumentPointers.size() != 3) {
  +            	throw new IllegalArgumentException("["+argumentPointers.size()+"] Arguments Found - An IF formula requires 2 or 3 arguments. IF(CONDITION, TRUE_VALUE, FALSE_VALUE [OPTIONAL]");            	
  +            }
  +            
  +            //Biffview of an IF formula record indicates the attr ptg goes after the condition ptgs and are
  +            //tracked in the argument pointers
  +            //The beginning first argument pointer is the last ptg of the condition
  +            int ifIndex = tokens.indexOf(argumentPointers.get(0))+1;
  +            tokens.add(ifIndex, ifPtg);
  +             
  +            //we now need a goto ptgAttr to skip to the end of the formula after a true condition
  +            //the true condition is should be inserted after the last ptg in the first argument
  +			 
  +			int gotoIndex = tokens.indexOf(argumentPointers.get(1))+1;
  +			
  +			AttrPtg goto1Ptg = new AttrPtg();
  +			goto1Ptg.setGoto(true);
  +			
  +						
  +			tokens.add(gotoIndex, goto1Ptg);
  +            
  +            
  +            if (numArgs > 2) { //only add false jump if there is a false condition
  +            
  +	            //second goto to skip past the function ptg
  +	            AttrPtg goto2Ptg = new AttrPtg();
  +	            goto2Ptg.setGoto(true);            
  +	            goto2Ptg.setData((short)(retval.getSize()-1));
  +				//Page 472 of the Microsoft Excel Developer's kit states that:
  +				//The b(or w) field specifies the number byes (or words to skip, minus 1
  +	            
  +	            tokens.add(goto2Ptg); //this goes after all the arguments are defined
  +            }
  +            
  +            //data portion of the if ptg points to the false subexpression (Page 472 of MS Excel Developer's kit)
  +            //count the number of bytes after the ifPtg to the False Subexpression
  +            //doesn't specify -1 in the documentation
  +			ifPtg.setData((short)(getPtgSize(ifIndex+1, gotoIndex)));            
  +            
  +            //count all the additional (goto) ptgs but dont count itself
  +			int ptgCount = this.getPtgSize(gotoIndex)-goto1Ptg.getSize()+retval.getSize();
  +			if (ptgCount > (int)Short.MAX_VALUE) {
  +				throw new RuntimeException("Ptg Size exceeds short when being specified for a goto ptg in an if");
  +			}
  +			
  +			goto1Ptg.setData((short)(ptgCount-1));
  +			
           } else {
  -            retval = new FuncVarPtg(name,numArgs);
  +        	
  +			retval = new FuncVarPtg(name,numArgs);
           }
  -        
  +		
           return retval; 
       }
       
  @@ -451,6 +595,8 @@
               if (look == '*') Multiply();
               if (look == '/') Divide();
           }
  +        addArgumentPointer();
  +        
       }
       
       
  
  
  
  1.8       +56 -1     jakarta-poi/src/java/org/apache/poi/hssf/record/formula/AbstractFunctionPtg.java
  
  Index: AbstractFunctionPtg.java
  ===================================================================
  RCS file: /home/cvs/jakarta-poi/src/java/org/apache/poi/hssf/record/formula/AbstractFunctionPtg.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- AbstractFunctionPtg.java	6 Nov 2002 02:40:41 -0000	1.7
  +++ AbstractFunctionPtg.java	15 Mar 2003 01:57:41 -0000	1.8
  @@ -1,3 +1,56 @@
  +/* ====================================================================
  + * The Apache Software License, Version 1.1
  + *
  + * Copyright (c) 2002, 2003 The Apache Software Foundation.  All rights
  + * reserved.
  + *
  + * Redistribution and use in source and binary forms, with or without
  + * modification, are permitted provided that the following conditions
  + * are met:
  + *
  + * 1. Redistributions of source code must retain the above copyright
  + *    notice, this list of conditions and the following disclaimer.
  + *
  + * 2. Redistributions in binary form must reproduce the above copyright
  + *    notice, this list of conditions and the following disclaimer in
  + *    the documentation and/or other materials provided with the
  + *    distribution.
  + *
  + * 3. The end-user documentation included with the redistribution,
  + *    if any, must include the following acknowledgment:
  + *       "This product includes software developed by the
  + *        Apache Software Foundation (http://www.apache.org/)."
  + *    Alternately, this acknowledgment may appear in the software itself,
  + *    if and wherever such third-party acknowledgments normally appear.
  + *
  + * 4. The names "Apache" and "Apache Software Foundation" and
  + *    "Apache POI" must not be used to endorse or promote products
  + *    derived from this software without prior written permission. For
  + *    written permission, please contact apache@apache.org.
  + *
  + * 5. Products derived from this software may not be called "Apache",
  + *    "Apache POI", nor may "Apache" appear in their name, without
  + *    prior written permission of the Apache Software Foundation.
  + *
  + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  + * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  + * SUCH DAMAGE.
  + * ====================================================================
  + *
  + * This software consists of voluntary contributions made by many
  + * individuals on behalf of the Apache Software Foundation.  For more
  + * information on the Apache Software Foundation, please see
  + * <http://www.apache.org/>.
  + */
   package org.apache.poi.hssf.record.formula;
   
   import org.apache.poi.util.BinaryTree;
  @@ -13,7 +66,9 @@
    * @author Andrew C. Oliver (acoliver at apache dot org)
    */
   public abstract class AbstractFunctionPtg extends OperationPtg {
  -    
  +	//constant used allow a ptgAttr to be mapped properly for its functionPtg
  +	public static final String ATTR_NAME = "specialflag";
  +	    
       private final static int  SIZE = 4;    
       
       private static BinaryTree map = produceHash(); 
  
  
  
  1.15      +9 -1      jakarta-poi/src/java/org/apache/poi/hssf/record/formula/AttrPtg.java
  
  Index: AttrPtg.java
  ===================================================================
  RCS file: /home/cvs/jakarta-poi/src/java/org/apache/poi/hssf/record/formula/AttrPtg.java,v
  retrieving revision 1.14
  retrieving revision 1.15
  diff -u -r1.14 -r1.15
  --- AttrPtg.java	6 Feb 2003 10:29:44 -0000	1.14
  +++ AttrPtg.java	15 Mar 2003 01:57:41 -0000	1.15
  @@ -2,7 +2,7 @@
   /* ====================================================================
    * The Apache Software License, Version 1.1
    *
  - * Copyright (c) 2002 The Apache Software Foundation.  All rights
  + * Copyright (c) 2002, 2003 The Apache Software Foundation.  All rights
    * reserved.
    *
    * Redistribution and use in source and binary forms, with or without
  @@ -144,6 +144,14 @@
           field_1_options=optiIf.setByteBoolean(field_1_options,bif);
       }
   
  +	/**
  +	 * Flags this ptg as a goto/jump 
  +	 * @param isGoto
  +	 */
  +	public void setGoto(boolean isGoto) {
  +		field_1_options=optGoto.setByteBoolean(field_1_options, isGoto);
  +	}
  +	
       // lets hope no one uses this anymore
       public boolean isBaxcel()
       {
  
  
  
  1.3       +133 -5    jakarta-poi/src/testcases/org/apache/poi/hssf/model/TestFormulaParser.java
  
  Index: TestFormulaParser.java
  ===================================================================
  RCS file: /home/cvs/jakarta-poi/src/testcases/org/apache/poi/hssf/model/TestFormulaParser.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- TestFormulaParser.java	1 Oct 2002 17:37:47 -0000	1.2
  +++ TestFormulaParser.java	15 Mar 2003 01:57:41 -0000	1.3
  @@ -1,3 +1,56 @@
  +/* ====================================================================
  + * The Apache Software License, Version 1.1
  + *
  + * Copyright (c) 2002, 2003 The Apache Software Foundation.  All rights
  + * reserved.
  + *
  + * Redistribution and use in source and binary forms, with or without
  + * modification, are permitted provided that the following conditions
  + * are met:
  + *
  + * 1. Redistributions of source code must retain the above copyright
  + *    notice, this list of conditions and the following disclaimer.
  + *
  + * 2. Redistributions in binary form must reproduce the above copyright
  + *    notice, this list of conditions and the following disclaimer in
  + *    the documentation and/or other materials provided with the
  + *    distribution.
  + *
  + * 3. The end-user documentation included with the redistribution,
  + *    if any, must include the following acknowledgment:
  + *       "This product includes software developed by the
  + *        Apache Software Foundation (http://www.apache.org/)."
  + *    Alternately, this acknowledgment may appear in the software itself,
  + *    if and wherever such third-party acknowledgments normally appear.
  + *
  + * 4. The names "Apache" and "Apache Software Foundation" and
  + *    "Apache POI" must not be used to endorse or promote products
  + *    derived from this software without prior written permission. For
  + *    written permission, please contact apache@apache.org.
  + *
  + * 5. Products derived from this software may not be called "Apache",
  + *    "Apache POI", nor may "Apache" appear in their name, without
  + *    prior written permission of the Apache Software Foundation.
  + *
  + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  + * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  + * SUCH DAMAGE.
  + * ====================================================================
  + *
  + * This software consists of voluntary contributions made by many
  + * individuals on behalf of the Apache Software Foundation.  For more
  + * information on the Apache Software Foundation, please see
  + * <http://www.apache.org/>.
  + */
   package org.apache.poi.hssf.model;
   
   import junit.framework.TestCase;
  @@ -80,20 +133,95 @@
           FormulaParser fp = new FormulaParser(yn, null);
           fp.parse();
           Ptg[] asts = fp.getRPNPtg();
  -        assertEquals(4, asts.length);
  +        assertEquals(7, asts.length);
   
           BoolPtg flag  = (BoolPtg) asts[0];
  -        StringPtg y = (StringPtg) asts[1];
  -        StringPtg n = (StringPtg) asts[2];
  -        AttrPtg funif = (AttrPtg) asts[3];
  +		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(new SheetReferences()));
  +        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);
  +		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());
  +		
  +		FuncVarPtg funcPtg = (FuncVarPtg)asts[8];
  +		
  +		
  +	}
  +    
  +	/**
  +	 * Make sure the ptgs are generated properly with two functions embedded
  +	 *
  +	 */
  +	public void testNestedFunctionIf() {
  +		String function = "IF(A1=B1,AVERAGE(A1:B1),AVERAGE(A2:B2))";
  +
  +		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("It is not an if", ifFunc.isOptimizedIf());
  +		
  +		assertTrue("Average Function set correctly", (asts[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);
  +
  +		assertTrue("IF Attr set correctly", (asts[3] instanceof AttrPtg));
  +		AttrPtg ifFunc = (AttrPtg)asts[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];
  +		assertEquals("Result", (short)10, intPtg.getValue());
  +		
  +		assertTrue("Ptg is not a Variable Function", (asts[6] instanceof FuncVarPtg));
  +		FuncVarPtg funcPtg = (FuncVarPtg)asts[6];
  +		assertEquals("Arguments", 2, funcPtg.getNumberOfOperands());
  +		
  +						
  +		
  +		
  +	}
  +	    
        public static void main(String [] args) {
           System.out.println("Testing org.apache.poi.hssf.record.formula.FormulaParser");
           junit.textui.TestRunner.run(TestFormulaParser.class);
  
  
  
  1.27      +51 -4     jakarta-poi/src/testcases/org/apache/poi/hssf/usermodel/TestFormulas.java
  
  Index: TestFormulas.java
  ===================================================================
  RCS file: /home/cvs/jakarta-poi/src/testcases/org/apache/poi/hssf/usermodel/TestFormulas.java,v
  retrieving revision 1.26
  retrieving revision 1.27
  diff -u -r1.26 -r1.27
  --- TestFormulas.java	24 Oct 2002 02:14:29 -0000	1.26
  +++ TestFormulas.java	15 Mar 2003 01:57:41 -0000	1.27
  @@ -2,7 +2,7 @@
   /* ====================================================================
    * The Apache Software License, Version 1.1
    *
  - * Copyright (c) 2002 The Apache Software Foundation.  All rights
  + * Copyright (c) 2002, 2003 The Apache Software Foundation.  All rights
    * reserved.
    *
    * Redistribution and use in source and binary forms, with or without
  @@ -894,7 +894,7 @@
               
       }
   
  -/*    
  +    
       public void testIfFormulas()
           throws java.io.IOException
       {
  @@ -935,9 +935,56 @@
               assertTrue("expected: IF(A3=A1,\"A1\",\"A2\") got "+c.getCellFormula(), ("IF(A3=A1,\"A1\",\"A2\")").equals(c.getCellFormula()));
               //c = r.getCell((short)1);
               //assertTrue("expected: A!A1+A!B1 got: "+c.getCellFormula(), ("A!A1+A!B1").equals(c.getCellFormula()));
  -            in.close(); 
  +            in.close();
  +            
  +		File simpleIf = File.createTempFile("testSimpleIfFormulaWrite",".xls");
  +		out    = new FileOutputStream(simpleIf);
  +		wb     = new HSSFWorkbook();
  +		s      = wb.createSheet("Sheet1");
  +		r      = null;
  +		c      = null;
  +		r = s.createRow((short)0);
  +		c=r.createCell((short)0); c.setCellFormula("IF(1=1,0,1)");
  +            
  +		wb.write(out);
  +		out.close();
  +		assertTrue("file exists", simpleIf.exists());
  +			
  +		assertTrue("length of simpleIf file is zero", (simpleIf.length()>0));
  +			
  +		File nestedIf = File.createTempFile("testNestedIfFormula",".xls");
  +		out    = new FileOutputStream(nestedIf);
  +		wb     = new HSSFWorkbook();
  +		s      = wb.createSheet("Sheet1");
  +		r      = null;
  +		c      = null;
  +		r = s.createRow((short)0);
  +		c=r.createCell((short)0);
  +		c.setCellValue(1);
  +
  +		c=r.createCell((short)1);
  +		c.setCellValue(3);
  +
  +			
  +		HSSFCell formulaCell=r.createCell((short)3); 
  +
  +		r = s.createRow((short)1);
  +		c=r.createCell((short)0);
  +		c.setCellValue(3);
  +
  +		c=r.createCell((short)1);
  +		c.setCellValue(7);
  +
  +		formulaCell.setCellFormula("IF(A1=B1,AVERAGE(A1:B1),AVERAGE(A2:B2))");
  +
  +            
  +		wb.write(out);
  +		out.close();
  +		assertTrue("file exists", nestedIf.exists());
  +			
  +		assertTrue("length of nestedIf file is zero", (nestedIf.length()>0));             
       }
  -*/
  +
       
       public static void main(String [] args) {
           System.out