You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@poi.apache.org by ni...@apache.org on 2008/02/04 11:48:32 UTC

svn commit: r618230 - in /poi/trunk/src: documentation/content/xdocs/ scratchpad/src/org/apache/poi/hssf/record/formula/functions/ scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/

Author: nick
Date: Mon Feb  4 02:48:29 2008
New Revision: 618230

URL: http://svn.apache.org/viewvc?rev=618230&view=rev
Log:
Implement CountA, CountIf, Index, Rows and Columns functions. Patch from Josh Micich in bug #44345

Added:
    poi/trunk/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/AllIndividualFunctionEvaluationTests.java   (with props)
    poi/trunk/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/EvalFactory.java   (with props)
    poi/trunk/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/NumericFunctionInvoker.java   (with props)
    poi/trunk/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/TestCountFuncs.java   (with props)
    poi/trunk/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/TestIndex.java   (with props)
    poi/trunk/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/TestRowCol.java   (with props)
Modified:
    poi/trunk/src/documentation/content/xdocs/changes.xml
    poi/trunk/src/documentation/content/xdocs/status.xml
    poi/trunk/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Columns.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Counta.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Countif.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Index.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Rows.java

Modified: poi/trunk/src/documentation/content/xdocs/changes.xml
URL: http://svn.apache.org/viewvc/poi/trunk/src/documentation/content/xdocs/changes.xml?rev=618230&r1=618229&r2=618230&view=diff
==============================================================================
--- poi/trunk/src/documentation/content/xdocs/changes.xml (original)
+++ poi/trunk/src/documentation/content/xdocs/changes.xml Mon Feb  4 02:48:29 2008
@@ -36,6 +36,7 @@
 
 		<!-- Don't forget to update status.xml too! -->
         <release version="3.1-beta1" date="2008-??-??">
+           <action dev="POI-DEVELOPERS" type="fix">44345 - Implement CountA, CountIf, Index, Rows and Columns functions</action>
            <action dev="POI-DEVELOPERS" type="fix">44336 - Properly escape sheet names as required when figuring out the text of formulas</action>
            <action dev="POI-DEVELOPERS" type="add">44326 - Improvements to how SystemOutLogger and CommonsLogger log messages with exceptions, and avoid an infinite loop with certain log messages with exceptions</action>
            <action dev="POI-DEVELOPERS" type="add">Support for a completed Record based "pull" stream, via org.apache.poi.hssf.eventusermodel.HSSFRecordStream, to complement the existing "push" Event User Model listener stuff</action>

Modified: poi/trunk/src/documentation/content/xdocs/status.xml
URL: http://svn.apache.org/viewvc/poi/trunk/src/documentation/content/xdocs/status.xml?rev=618230&r1=618229&r2=618230&view=diff
==============================================================================
--- poi/trunk/src/documentation/content/xdocs/status.xml (original)
+++ poi/trunk/src/documentation/content/xdocs/status.xml Mon Feb  4 02:48:29 2008
@@ -33,6 +33,7 @@
 	<!-- Don't forget to update changes.xml too! -->
     <changes>
         <release version="3.1-beta1" date="2008-??-??">
+           <action dev="POI-DEVELOPERS" type="fix">44345 - Implement CountA, CountIf, Index, Rows and Columns functions</action>
            <action dev="POI-DEVELOPERS" type="fix">44336 - Properly escape sheet names as required when figuring out the text of formulas</action>
            <action dev="POI-DEVELOPERS" type="add">44326 - Improvements to how SystemOutLogger and CommonsLogger log messages with exceptions, and avoid an infinite loop with certain log messages with exceptions</action>
            <action dev="POI-DEVELOPERS" type="add">Support for a completed Record based "pull" stream, via org.apache.poi.hssf.eventusermodel.HSSFRecordStream, to complement the existing "push" Event User Model listener stuff</action>

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Columns.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Columns.java?rev=618230&r1=618229&r2=618230&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Columns.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Columns.java Mon Feb  4 02:48:29 2008
@@ -14,12 +14,46 @@
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
-/*
- * Created on May 15, 2005
- *
- */
+
+
 package org.apache.poi.hssf.record.formula.functions;
 
-public class Columns extends NotImplementedFunction {
+import org.apache.poi.hssf.record.formula.eval.AreaEval;
+import org.apache.poi.hssf.record.formula.eval.ErrorEval;
+import org.apache.poi.hssf.record.formula.eval.Eval;
+import org.apache.poi.hssf.record.formula.eval.NumberEval;
+import org.apache.poi.hssf.record.formula.eval.RefEval;
+
+/**
+ * Implementation for Excel COLUMNS function.
+ * 
+ * @author Josh Micich
+ */
+public final class Columns implements Function {
 
+	public Eval evaluate(Eval[] args, int srcCellRow, short srcCellCol) {
+		switch(args.length) {
+			case 1:
+				// expected
+				break;
+			case 0:
+				// too few arguments
+				return ErrorEval.VALUE_INVALID;
+			default:
+				// too many arguments
+				return ErrorEval.VALUE_INVALID;
+		}
+		Eval firstArg = args[0];
+		
+		int result;
+        if (firstArg instanceof AreaEval) {
+            AreaEval ae = (AreaEval) firstArg;
+            result = ae.getLastColumn() - ae.getFirstColumn() + 1;
+        } else if (firstArg instanceof RefEval) {
+            result = 1;
+        } else { // anything else is not valid argument
+            return ErrorEval.VALUE_INVALID;
+        }
+        return new NumberEval(result);
+	}
 }

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Counta.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Counta.java?rev=618230&r1=618229&r2=618230&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Counta.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Counta.java Mon Feb  4 02:48:29 2008
@@ -14,12 +14,107 @@
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
-/*
- * Created on May 15, 2005
+
+
+package org.apache.poi.hssf.record.formula.functions;
+
+import org.apache.poi.hssf.record.formula.eval.AreaEval;
+import org.apache.poi.hssf.record.formula.eval.BlankEval;
+import org.apache.poi.hssf.record.formula.eval.ErrorEval;
+import org.apache.poi.hssf.record.formula.eval.Eval;
+import org.apache.poi.hssf.record.formula.eval.NumberEval;
+import org.apache.poi.hssf.record.formula.eval.RefEval;
+import org.apache.poi.hssf.record.formula.eval.StringEval;
+import org.apache.poi.hssf.record.formula.eval.ValueEval;
+
+/**
+ * Counts the number of cells that contain data within the list of arguments. 
  *
+ * Excel Syntax
+ * COUNTA(value1,value2,...)
+ * Value1, value2, ...   are 1 to 30 arguments representing the values or ranges to be counted.
+ * 
+ * @author Josh Micich
  */
-package org.apache.poi.hssf.record.formula.functions;
+public final class Counta implements Function {
+
+	public Eval evaluate(Eval[] args, int srcCellRow, short srcCellCol) {
+		int nArgs = args.length;
+		if (nArgs < 1) {
+			// too few arguments
+			return ErrorEval.VALUE_INVALID;
+		}
+
+		if (nArgs > 30) {
+			// too many arguments
+			return ErrorEval.VALUE_INVALID;
+		}
+		
+		int temp = 0;
+		// Note - observed behavior of Excel:
+		// Error values like #VALUE!, #REF!, #DIV/0!, #NAME? etc don't cause this COUNTA to return an error
+		// in fact, they seem to get counted
+		
+		for(int i=0; i<nArgs; i++) {
+			temp += countArg(args[i]);
+			
+		}
+		return new NumberEval(temp);
+	}
+
+	private static int countArg(Eval eval) {
+        if (eval instanceof AreaEval) {
+            AreaEval ae = (AreaEval) eval;
+            return countAreaEval(ae);
+        }
+        if (eval instanceof RefEval) {
+            RefEval refEval = (RefEval)eval;
+			return countValue(refEval.getInnerValueEval());
+        }
+        if (eval instanceof NumberEval) {
+            return 1;
+        }
+        if (eval instanceof StringEval) {
+            return 1;
+        }
+        
+		
+		throw new RuntimeException("Unexpected eval type (" + eval.getClass().getName() + ")");
+	}
+
+	private static int countAreaEval(AreaEval ae) {
+		
+		int temp = 0;
+		ValueEval[] values = ae.getValues();
+		for (int i = 0; i < values.length; i++) {
+			ValueEval val = values[i];
+			if(val == null) {
+				// seems to occur.  Really we would have expected BlankEval
+				continue;
+			}
+			temp += countValue(val);
+			
+		}
+		return temp;
+	}
+
+	private static int countValue(ValueEval valueEval) {
+		
+		if(valueEval == BlankEval.INSTANCE) {
+			return 0;
+		}
+		
+		if(valueEval instanceof BlankEval) {
+			// wouldn't need this if BlankEval was final
+			return 0;
+		}
 
-public class Counta extends NotImplementedFunction {
+		if(valueEval instanceof ErrorEval) {
+			// note - error values are counted
+			return 1;
+		}
+		// also empty strings and zeros are counted too
 
+		return 1;
+	}
 }

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Countif.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Countif.java?rev=618230&r1=618229&r2=618230&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Countif.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Countif.java Mon Feb  4 02:48:29 2008
@@ -14,12 +14,231 @@
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
-/*
- * Created on May 15, 2005
- *
- */
+
+
 package org.apache.poi.hssf.record.formula.functions;
 
-public class Countif extends NotImplementedFunction {
+import org.apache.poi.hssf.record.formula.eval.AreaEval;
+import org.apache.poi.hssf.record.formula.eval.BoolEval;
+import org.apache.poi.hssf.record.formula.eval.ErrorEval;
+import org.apache.poi.hssf.record.formula.eval.Eval;
+import org.apache.poi.hssf.record.formula.eval.NumberEval;
+import org.apache.poi.hssf.record.formula.eval.RefEval;
+import org.apache.poi.hssf.record.formula.eval.StringEval;
+import org.apache.poi.hssf.record.formula.eval.ValueEval;
+
+/**
+ * Implementation for the function COUNTIF<p/>
+ * 
+ * Syntax: COUNTIF ( range, criteria )
+ *    <table border="0" cellpadding="1" cellspacing="0" summary="Parameter descriptions">
+ *      <tr><th>range&nbsp;&nbsp;&nbsp;</th><td>is the range of cells to be counted based on the criteria</td></tr>
+ *      <tr><th>criteria</th><td>is used to determine which cells to count</td></tr>
+ *    </table>
+ * <p/>
+ * 
+ * @author Josh Micich
+ */
+public final class Countif implements Function {
+	
+	/**
+	 * Common interface for the matching criteria.
+	 */
+	private interface I_MatchPredicate {
+		boolean matches(Eval x);
+	}
+	
+	private static final class NumberMatcher implements I_MatchPredicate {
+
+		private final double _value;
+
+		public NumberMatcher(double value) {
+			_value = value;
+		}
+
+		public boolean matches(Eval x) {
+			if(x instanceof StringEval) {
+				// if the target(x) is a string, but parses as a number
+				// it may still count as a match
+				StringEval se = (StringEval)x;
+				Double val = parseDouble(se.getStringValue());
+				if(val == null) {
+					// x is text that is not a number
+					return false;
+				}
+				return val.doubleValue() == _value;
+			}
+			if(!(x instanceof NumberEval)) {
+				return false;
+			}
+			NumberEval ne = (NumberEval) x;
+			return ne.getNumberValue() == _value;
+		}
+	}
+	private static final class BooleanMatcher implements I_MatchPredicate {
+
+		private final boolean _value;
+
+		public BooleanMatcher(boolean value) {
+			_value = value;
+		}
+
+		public boolean matches(Eval x) {
+			if(x instanceof StringEval) {
+				StringEval se = (StringEval)x;
+				Boolean val = parseBoolean(se.getStringValue());
+				if(val == null) {
+					// x is text that is not a boolean
+					return false;
+				}
+				if (true) { // change to false to observe more intuitive behaviour
+					// Note - Unlike with numbers, it seems that COUNTA never matches 
+					// boolean values when the target(x) is a string
+					return false;
+				}
+				return val.booleanValue() == _value;
+			}
+			if(!(x instanceof BoolEval)) {
+				return false;
+			}
+			BoolEval be = (BoolEval) x;
+			return be.getBooleanValue() == _value;
+		}
+	}
+	private static final class StringMatcher implements I_MatchPredicate {
+
+		private final String _value;
+
+		public StringMatcher(String value) {
+			_value = value;
+		}
+
+		public boolean matches(Eval x) {
+			if(!(x instanceof StringEval)) {
+				return false;
+			}
+			StringEval se = (StringEval) x;
+			return se.getStringValue() == _value;
+		}
+	}
+
+	public Eval evaluate(Eval[] args, int srcCellRow, short srcCellCol) {
+		switch(args.length) {
+			case 2:
+				// expected
+				break;
+			default:
+				// TODO - it doesn't seem to be possible to enter COUNTIF() into Excel with the wrong arg count
+				// perhaps this should be an exception
+				return ErrorEval.VALUE_INVALID;
+		}
+		
+		AreaEval range = (AreaEval) args[0];
+		Eval criteriaArg = args[1];
+		if(criteriaArg instanceof RefEval) {
+			// criteria is not a literal value, but a cell reference
+			// for example COUNTIF(B2:D4, E1)
+			RefEval re = (RefEval)criteriaArg;
+			criteriaArg = re.getInnerValueEval();
+		} else {
+			// other non literal tokens such as function calls, have been fully evaluated
+			// for example COUNTIF(B2:D4, COLUMN(E1))
+		}
+		I_MatchPredicate mp = createCriteriaPredicate(criteriaArg);
+		return countMatchingCellsInArea(range, mp);
+	}
+	/**
+	 * @return the number of evaluated cells in the range that match the specified criteria
+	 */
+	private Eval countMatchingCellsInArea(AreaEval range, I_MatchPredicate criteriaPredicate) {
+		ValueEval[] values = range.getValues();
+		int result = 0;
+		for (int i = 0; i < values.length; i++) {
+			if(criteriaPredicate.matches(values[i])) {
+				result++;
+			}
+		}
+		return new NumberEval(result);
+	}
+	
+	private static I_MatchPredicate createCriteriaPredicate(Eval evaluatedCriteriaArg) {
+		if(evaluatedCriteriaArg instanceof NumberEval) {
+			return new NumberMatcher(((NumberEval)evaluatedCriteriaArg).getNumberValue());
+		}
+		if(evaluatedCriteriaArg instanceof BoolEval) {
+			return new BooleanMatcher(((BoolEval)evaluatedCriteriaArg).getBooleanValue());
+		}
+		
+		if(evaluatedCriteriaArg instanceof StringEval) {
+			return createGeneralMatchPredicate((StringEval)evaluatedCriteriaArg);
+		}
+		throw new RuntimeException("Unexpected type for criteria (" 
+				+ evaluatedCriteriaArg.getClass().getName() + ")");
+	}
+
+	/**
+	 * When the second argument is a string, many things are possible
+	 */
+	private static I_MatchPredicate createGeneralMatchPredicate(StringEval stringEval) {
+		String value = stringEval.getStringValue();
+		char firstChar = value.charAt(0);
+		Boolean booleanVal = parseBoolean(value);
+		if(booleanVal != null) {
+			return new BooleanMatcher(booleanVal.booleanValue());
+		}
+		
+		Double doubleVal = parseDouble(value);
+		if(doubleVal != null) {
+			return new NumberMatcher(doubleVal.doubleValue());
+		}
+		switch(firstChar) {
+			case '>':
+			case '<':
+			case '=':
+				throw new RuntimeException("Incomplete code - criteria expressions such as '"
+						+ value + "' not supported yet");
+		}
+		
+		//else - just a plain string with no interpretation.
+		return new StringMatcher(value);
+	}
 
+	/**
+	 * Under certain circumstances COUNTA will equate a plain number with a string representation of that number
+	 */
+	/* package */ static Double parseDouble(String strRep) {
+		if(!Character.isDigit(strRep.charAt(0))) {
+			// avoid using NumberFormatException to tell when string is not a number
+			return null;
+		}
+		// TODO - support notation like '1E3' (==1000)
+		
+		double val;
+		try {
+			val = Double.parseDouble(strRep);
+		} catch (NumberFormatException e) {
+			return null;
+		}
+		return new Double(val);
+	}
+	/**
+	 * Boolean literals ('TRUE', 'FALSE') treated similarly but NOT same as numbers. 
+	 */
+	/* package */ static Boolean parseBoolean(String strRep) {
+		switch(strRep.charAt(0)) {
+			case 't':
+			case 'T':
+				if("TRUE".equalsIgnoreCase(strRep)) {
+					return Boolean.TRUE;
+				}
+				break;
+			case 'f':
+			case 'F':
+				if("FALSE".equalsIgnoreCase(strRep)) {
+					return Boolean.FALSE;
+				}
+				break;
+		}
+		return null;
+	}
 }

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Index.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Index.java?rev=618230&r1=618229&r2=618230&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Index.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Index.java Mon Feb  4 02:48:29 2008
@@ -14,12 +14,95 @@
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
-/*
- * Created on May 15, 2005
- *
- */
+
+
 package org.apache.poi.hssf.record.formula.functions;
 
-public class Index extends NotImplementedFunction {
+import org.apache.poi.hssf.record.formula.eval.AreaEval;
+import org.apache.poi.hssf.record.formula.eval.ErrorEval;
+import org.apache.poi.hssf.record.formula.eval.Eval;
+import org.apache.poi.hssf.record.formula.eval.NumberEval;
+import org.apache.poi.hssf.record.formula.eval.RefEval;
+
+/**
+ * Implementation for the Excel function INDEX<p/>
+ * 
+ * Syntax : <br/>
+ *  INDEX ( reference, row_num[, column_num [, area_num]])</br>
+ *  INDEX ( array, row_num[, column_num])
+ *    <table border="0" cellpadding="1" cellspacing="0" summary="Parameter descriptions">
+ *      <tr><th>reference</th><td>typically an area reference, possibly a union of areas</td></tr>
+ *      <tr><th>array</th><td>a literal array value (currently not supported)</td></tr>
+ *      <tr><th>row_num</th><td>selects the row within the array or area reference</td></tr>
+ *      <tr><th>column_num</th><td>selects column within the array or area reference. default is 1</td></tr>
+ *      <tr><th>area_num</th><td>used when reference is a union of areas</td></tr>
+ *    </table>
+ * <p/>
+ * 
+ * @author Josh Micich
+ */
+public final class Index implements Function {
 
+	// TODO - javadoc for interface method
+	public Eval evaluate(Eval[] args, int srcCellRow, short srcCellCol) {
+		int nArgs = args.length;
+		if(nArgs < 2) {
+			// too few arguments
+			return ErrorEval.VALUE_INVALID;
+		}
+		Eval firstArg = args[0];
+		if(firstArg instanceof AreaEval) {
+			AreaEval reference = (AreaEval) firstArg;
+			
+			int rowIx = 0;
+			int columnIx = 0;
+			int areaIx = 0;
+			switch(nArgs) {
+				case 4:
+					areaIx = convertIndexArgToZeroBase(args[3]);
+					throw new RuntimeException("Incomplete code" +
+							" - don't know how to support the 'area_num' parameter yet)");
+					// Excel expression might look like this "INDEX( (A1:B4, C3:D6, D2:E5 ), 1, 2, 3)
+					// In this example, the 3rd area would be used i.e. D2:E5, and the overall result would be E2
+					// Token array might be encoded like this: MemAreaPtg, AreaPtg, AreaPtg, UnionPtg, UnionPtg, ParenthesesPtg
+					// The formula parser doesn't seem to support this yet. Not sure if the evaluator does either
+					
+				case 3:
+					columnIx = convertIndexArgToZeroBase(args[2]);
+				case 2:
+					rowIx = convertIndexArgToZeroBase(args[1]);
+					break;
+				default:
+					// too many arguments
+					return ErrorEval.VALUE_INVALID;
+			}
+			
+	        int nColumns = reference.getLastColumn()-reference.getFirstColumn()+1;
+			int index = rowIx * nColumns + columnIx;
+			
+			return reference.getValues()[index];
+		}
+		
+		// else the other variation of this function takes an array as the first argument
+		// it seems like interface 'ArrayEval' does not even exist yet
+		
+		throw new RuntimeException("Incomplete code - cannot handle first arg of type ("
+				+ firstArg.getClass().getName() + ")");
+	}
+	
+	/**
+	 * takes a NumberEval representing a 1-based index and returns the zero-based int value
+	 */
+	private static int convertIndexArgToZeroBase(Eval ev) {
+		NumberEval ne;
+		if(ev instanceof RefEval) {
+			// TODO - write junit to justify this
+			RefEval re = (RefEval) ev;
+			ne = (NumberEval) re.getInnerValueEval();
+		} else {
+			ne = (NumberEval)ev;
+		}
+		
+		return (int)ne.getNumberValue() - 1;
+	}
 }

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Rows.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Rows.java?rev=618230&r1=618229&r2=618230&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Rows.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Rows.java Mon Feb  4 02:48:29 2008
@@ -14,12 +14,46 @@
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
-/*
- * Created on May 15, 2005
- *
- */
+
+
 package org.apache.poi.hssf.record.formula.functions;
 
-public class Rows extends NotImplementedFunction {
+import org.apache.poi.hssf.record.formula.eval.AreaEval;
+import org.apache.poi.hssf.record.formula.eval.ErrorEval;
+import org.apache.poi.hssf.record.formula.eval.Eval;
+import org.apache.poi.hssf.record.formula.eval.NumberEval;
+import org.apache.poi.hssf.record.formula.eval.RefEval;
+
+/**
+ * Implementation for Excel COLUMNS function.
+ * 
+ * @author Josh Micich
+ */
+public final class Rows implements Function {
 
+	public Eval evaluate(Eval[] args, int srcCellRow, short srcCellCol) {
+		switch(args.length) {
+			case 1:
+				// expected
+				break;
+			case 0:
+				// too few arguments
+				return ErrorEval.VALUE_INVALID;
+			default:
+				// too many arguments
+				return ErrorEval.VALUE_INVALID;
+		}
+		Eval firstArg = args[0];
+		
+		int result;
+        if (firstArg instanceof AreaEval) {
+            AreaEval ae = (AreaEval) firstArg;
+            result = ae.getLastRow() - ae.getFirstRow() + 1;
+        } else if (firstArg instanceof RefEval) {
+            result = 1;
+        } else { // anything else is not valid argument
+            return ErrorEval.VALUE_INVALID;
+        }
+        return new NumberEval(result);
+	}
 }

Added: poi/trunk/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/AllIndividualFunctionEvaluationTests.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/AllIndividualFunctionEvaluationTests.java?rev=618230&view=auto
==============================================================================
--- poi/trunk/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/AllIndividualFunctionEvaluationTests.java (added)
+++ poi/trunk/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/AllIndividualFunctionEvaluationTests.java Mon Feb  4 02:48:29 2008
@@ -0,0 +1,44 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+        
+
+package org.apache.poi.hssf.record.formula.functions;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * Direct tests for all implementors of <code>Function</code>.
+ * 
+ * @author Josh Micich
+ */
+public final class AllIndividualFunctionEvaluationTests {
+
+	// TODO - have this suite incorporated into a higher level one
+	public static Test suite() {
+		TestSuite result = new TestSuite("Tests for org.apache.poi.hssf.record.formula.functions");
+		result.addTestSuite(TestCountFuncs.class);
+		result.addTestSuite(TestDate.class);
+		result.addTestSuite(TestFinanceLib.class);
+		result.addTestSuite(TestIndex.class);
+		result.addTestSuite(TestMathX.class);
+		result.addTestSuite(TestRowCol.class);
+		result.addTestSuite(TestStatsLib.class);
+		return result;
+	}
+
+}

Propchange: poi/trunk/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/AllIndividualFunctionEvaluationTests.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: poi/trunk/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/AllIndividualFunctionEvaluationTests.java
------------------------------------------------------------------------------
    svn:executable = *

Added: poi/trunk/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/EvalFactory.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/EvalFactory.java?rev=618230&view=auto
==============================================================================
--- poi/trunk/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/EvalFactory.java (added)
+++ poi/trunk/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/EvalFactory.java Mon Feb  4 02:48:29 2008
@@ -0,0 +1,63 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+        
+
+package org.apache.poi.hssf.record.formula.functions;
+
+import org.apache.poi.hssf.record.formula.AreaPtg;
+import org.apache.poi.hssf.record.formula.ReferencePtg;
+import org.apache.poi.hssf.record.formula.eval.Area2DEval;
+import org.apache.poi.hssf.record.formula.eval.AreaEval;
+import org.apache.poi.hssf.record.formula.eval.NumberEval;
+import org.apache.poi.hssf.record.formula.eval.Ref2DEval;
+import org.apache.poi.hssf.record.formula.eval.RefEval;
+import org.apache.poi.hssf.record.formula.eval.ValueEval;
+
+/**
+ * Test helper class for creating mock <code>Eval</code> objects
+ * 
+ * @author Josh Micich
+ */
+final class EvalFactory {
+	private static final NumberEval ZERO = new NumberEval(0);
+
+	private EvalFactory() {
+		// no instances of this class
+	}
+
+	/**
+	 * Creates a dummy AreaEval (filled with zeros)
+	 * <p/>
+	 * nCols and nRows could have been derived
+	 */
+	public static AreaEval createAreaEval(String areaRefStr, int nCols, int nRows) {
+		int nValues = nCols * nRows;
+		ValueEval[] values = new ValueEval[nValues];
+		for (int i = 0; i < nValues; i++) {
+			values[i] = ZERO;
+		}
+		
+		return new Area2DEval(new AreaPtg(areaRefStr), values);
+	}
+
+	/**
+	 * Creates a single RefEval (with value zero)
+	 */
+	public static RefEval createRefEval(String refStr) {
+		return new Ref2DEval(new ReferencePtg(refStr), ZERO, true);
+	}
+}

Propchange: poi/trunk/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/EvalFactory.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: poi/trunk/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/EvalFactory.java
------------------------------------------------------------------------------
    svn:executable = *

Added: poi/trunk/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/NumericFunctionInvoker.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/NumericFunctionInvoker.java?rev=618230&view=auto
==============================================================================
--- poi/trunk/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/NumericFunctionInvoker.java (added)
+++ poi/trunk/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/NumericFunctionInvoker.java Mon Feb  4 02:48:29 2008
@@ -0,0 +1,101 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+        
+
+package org.apache.poi.hssf.record.formula.functions;
+
+import junit.framework.AssertionFailedError;
+
+import org.apache.poi.hssf.record.formula.eval.ErrorEval;
+import org.apache.poi.hssf.record.formula.eval.Eval;
+import org.apache.poi.hssf.record.formula.eval.NumericValueEval;
+
+/**
+ * Test helper class for invoking functions with numeric results.
+ * 
+ * @author Josh Micich
+ */
+final class NumericFunctionInvoker {
+
+	private NumericFunctionInvoker() {
+		// no instances of this class
+	}
+	
+	private static final class NumericEvalEx extends Exception {
+		public NumericEvalEx(String msg) {
+			super(msg);
+		}
+	}
+	
+	/**
+	 * Invokes the specified function with the arguments.
+	 * <p/>
+	 * Assumes that the cell coordinate parameters of
+	 *  <code>Function.evaluate(args, srcCellRow, srcCellCol)</code>
+	 * are not required.
+	 * <p/>
+	 * This method cannot be used for confirming error return codes.  Any non-numeric evaluation
+	 * result causes the current junit test to fail.
+	 */
+	public static double invoke(Function f, Eval[] args) {
+		try {
+			return invokeInternal(f, args, -1, -1);
+		} catch (NumericEvalEx e) {
+			throw new AssertionFailedError("Evaluation of function (" + f.getClass().getName() 
+					+ ") failed: " + e.getMessage());
+		}
+		
+	}
+	/**
+	 * Formats nicer error messages for the junit output
+	 */
+	private static double invokeInternal(Function f, Eval[] args, int srcCellRow, int srcCellCol)
+				throws NumericEvalEx {
+		Eval evalResult = f.evaluate(args, srcCellRow, (short)srcCellCol);
+		if(evalResult == null) {
+			throw new NumericEvalEx("Result object was null");
+		}
+		if(evalResult instanceof ErrorEval) {
+			ErrorEval ee = (ErrorEval) evalResult;
+			throw new NumericEvalEx(formatErrorMessage(ee));
+		}
+		if(!(evalResult instanceof NumericValueEval)) {
+			throw new NumericEvalEx("Result object type (" + evalResult.getClass().getName()
+					+ ") is invalid.  Expected implementor of (" 
+					+ NumericValueEval.class.getName() + ")");
+		}
+		
+		NumericValueEval result = (NumericValueEval) evalResult;
+		return result.getNumberValue();
+	}
+	private static String formatErrorMessage(ErrorEval ee) {
+		if(errorCodesAreEqual(ee, ErrorEval.FUNCTION_NOT_IMPLEMENTED)) {
+			return "Function not implemented";
+		}
+		if(errorCodesAreEqual(ee, ErrorEval.UNKNOWN_ERROR)) {
+			return "Unknown error";
+		}
+		return "Error code=" + ee.getErrorCode();
+	}
+	private static boolean errorCodesAreEqual(ErrorEval a, ErrorEval b) {
+		if(a==b) {
+			return true;
+		}
+		return a.getErrorCode() == b.getErrorCode();
+	}
+
+}

Propchange: poi/trunk/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/NumericFunctionInvoker.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: poi/trunk/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/NumericFunctionInvoker.java
------------------------------------------------------------------------------
    svn:executable = *

Added: poi/trunk/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/TestCountFuncs.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/TestCountFuncs.java?rev=618230&view=auto
==============================================================================
--- poi/trunk/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/TestCountFuncs.java (added)
+++ poi/trunk/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/TestCountFuncs.java Mon Feb  4 02:48:29 2008
@@ -0,0 +1,150 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+        
+
+package org.apache.poi.hssf.record.formula.functions;
+
+import junit.framework.TestCase;
+
+import org.apache.poi.hssf.record.formula.AreaPtg;
+import org.apache.poi.hssf.record.formula.ReferencePtg;
+import org.apache.poi.hssf.record.formula.eval.Area2DEval;
+import org.apache.poi.hssf.record.formula.eval.AreaEval;
+import org.apache.poi.hssf.record.formula.eval.BlankEval;
+import org.apache.poi.hssf.record.formula.eval.BoolEval;
+import org.apache.poi.hssf.record.formula.eval.Eval;
+import org.apache.poi.hssf.record.formula.eval.NumberEval;
+import org.apache.poi.hssf.record.formula.eval.Ref2DEval;
+import org.apache.poi.hssf.record.formula.eval.StringEval;
+import org.apache.poi.hssf.record.formula.eval.ValueEval;
+
+/**
+ * Test cases for COUNT(), COUNTA() COUNTIF(), COUNTBLANK()
+ * 
+ * @author Josh Micich
+ */
+public final class TestCountFuncs extends TestCase {
+
+	public TestCountFuncs(String testName) {
+		super(testName);
+	}
+	
+	public void testCountA() {
+		
+		Eval[] args;
+		
+		args = new Eval[] {
+			new NumberEval(0),	 
+		};
+		confirmCountA(1, args);
+		
+		args = new Eval[] {
+			new NumberEval(0),	
+			new NumberEval(0),
+			new StringEval(""),
+		};
+		confirmCountA(3, args);
+		
+		args = new Eval[] {
+			EvalFactory.createAreaEval("D2:F5", 3, 4),	
+		};
+		confirmCountA(12, args);
+		
+		args = new Eval[] {
+			EvalFactory.createAreaEval("D1:F5", 3, 5),	// 15
+			EvalFactory.createRefEval("A1"),	
+			EvalFactory.createAreaEval("A1:F6", 7, 6),	// 42
+			new NumberEval(0),
+		};
+		confirmCountA(59, args);
+	}
+
+	public void testCountIf() {
+		
+		AreaEval range;
+		ValueEval[] values;
+		
+		// when criteria is a boolean value
+		values = new ValueEval[] {
+				new NumberEval(0),	
+				new StringEval("TRUE"),	// note - does not match boolean TRUE
+				BoolEval.TRUE,
+				BoolEval.FALSE,
+				BoolEval.TRUE,
+				BlankEval.INSTANCE,
+		};
+		range = createAreaEval("A1:B2", values);
+		confirmCountIf(2, range, BoolEval.TRUE);
+		
+		// when criteria is numeric
+		values = new ValueEval[] {
+				new NumberEval(0),	
+				new StringEval("2"),	
+				new StringEval("2.001"),	
+				new NumberEval(2),	
+				new NumberEval(2),	
+				BoolEval.TRUE,
+				BlankEval.INSTANCE,
+		};
+		range = createAreaEval("A1:B2", values);
+		confirmCountIf(3, range, new NumberEval(2));
+		// note - same results when criteria is a string that parses as the number with the same value
+		confirmCountIf(3, range, new StringEval("2.00"));
+		
+		if (false) { // not supported yet: 
+			// when criteria is an expression (starting with a comparison operator)
+			confirmCountIf(4, range, new StringEval(">1"));
+		}
+	}
+	/**
+	 * special case where the criteria argument is a cell reference
+	 */
+	public void testCountIfWithCriteriaReference() {
+
+		ValueEval[] values = { 
+				new NumberEval(22),
+				new NumberEval(25),
+				new NumberEval(21),
+				new NumberEval(25),
+				new NumberEval(25),
+				new NumberEval(25),
+		};
+		Area2DEval arg0 = new Area2DEval(new AreaPtg("C1:C6"), values);
+		
+		Ref2DEval criteriaArg = new Ref2DEval(new ReferencePtg("A1"), new NumberEval(25), true);
+		Eval[] args=  { arg0, criteriaArg, };
+		
+		double actual = NumericFunctionInvoker.invoke(new Countif(), args);
+		assertEquals(4, actual, 0D);
+	}
+	
+
+	private static AreaEval createAreaEval(String areaRefStr, ValueEval[] values) {
+		return new Area2DEval(new AreaPtg(areaRefStr), values);
+	}
+
+	private static void confirmCountA(int expected, Eval[] args) {
+		double result = NumericFunctionInvoker.invoke(new Counta(), args);
+		assertEquals(expected, result, 0);
+	}
+	private static void confirmCountIf(int expected, AreaEval range, Eval criteria) {
+		
+		Eval[] args = { range, criteria, };
+		double result = NumericFunctionInvoker.invoke(new Countif(), args);
+		assertEquals(expected, result, 0);
+	}
+}

Propchange: poi/trunk/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/TestCountFuncs.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: poi/trunk/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/TestCountFuncs.java
------------------------------------------------------------------------------
    svn:executable = *

Added: poi/trunk/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/TestIndex.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/TestIndex.java?rev=618230&view=auto
==============================================================================
--- poi/trunk/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/TestIndex.java (added)
+++ poi/trunk/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/TestIndex.java Mon Feb  4 02:48:29 2008
@@ -0,0 +1,89 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+        
+
+package org.apache.poi.hssf.record.formula.functions;
+
+import junit.framework.TestCase;
+
+import org.apache.poi.hssf.record.formula.AreaPtg;
+import org.apache.poi.hssf.record.formula.eval.Area2DEval;
+import org.apache.poi.hssf.record.formula.eval.Eval;
+import org.apache.poi.hssf.record.formula.eval.NumberEval;
+import org.apache.poi.hssf.record.formula.eval.ValueEval;
+
+/**
+ * Tests for the INDEX() function
+ * 
+ * @author Josh Micich
+ */
+public final class TestIndex extends TestCase {
+
+	public TestIndex(String testName) {
+		super(testName);
+	}
+	
+	private static final double[] TEST_VALUES0 = {
+			1, 2,
+			3, 4,
+			5, 6,
+			7, 8,
+			9, 10,
+			11, 12,
+			13, // excess array element. TODO - Area2DEval currently has no validation to ensure correct size of values array
+	};
+	
+	/**
+	 * For the case when the first argument to INDEX() is an area reference
+	 */
+	public void testEvaluateAreaReference() {
+		
+		double[] values = TEST_VALUES0;
+		confirmAreaEval("C1:D6", values, 4, 1, 7);
+		confirmAreaEval("C1:D6", values, 6, 2, 12);
+		confirmAreaEval("C1:D6", values, 3, -1, 5);
+		
+		// now treat same data as 3 columns, 4 rows
+		confirmAreaEval("C10:E13", values, 2, 2, 5); 
+		confirmAreaEval("C10:E13", values, 4, -1, 10);
+	}
+	
+	/**
+	 * @param areaRefString in Excel notation e.g. 'D2:E97'
+	 * @param dValues array of evaluated values for the area reference
+	 * @param rowNum 1-based
+	 * @param colNum 1-based, pass -1 to signify argument not present
+	 */
+	private static void confirmAreaEval(String areaRefString, double[] dValues, 
+			int rowNum, int colNum, double expectedResult) {
+		ValueEval[] values = new ValueEval[dValues.length];
+		for (int i = 0; i < values.length; i++) {
+			values[i] = new NumberEval(dValues[i]);
+		}
+		Area2DEval arg0 = new Area2DEval(new AreaPtg(areaRefString), values);
+		
+		Eval[] args;
+		if (colNum > 0) {
+			args = new Eval[] { arg0, new NumberEval(rowNum), new NumberEval(colNum), };
+		} else {
+			args = new Eval[] { arg0, new NumberEval(rowNum), };
+		}
+		
+		double actual = NumericFunctionInvoker.invoke(new Index(), args);
+		assertEquals(expectedResult, actual, 0D);
+	}
+}

Propchange: poi/trunk/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/TestIndex.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: poi/trunk/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/TestIndex.java
------------------------------------------------------------------------------
    svn:executable = *

Added: poi/trunk/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/TestRowCol.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/TestRowCol.java?rev=618230&view=auto
==============================================================================
--- poi/trunk/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/TestRowCol.java (added)
+++ poi/trunk/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/TestRowCol.java Mon Feb  4 02:48:29 2008
@@ -0,0 +1,102 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+        
+
+package org.apache.poi.hssf.record.formula.functions;
+
+import junit.framework.TestCase;
+
+import org.apache.poi.hssf.record.formula.eval.Eval;
+
+/**
+ * Tests for ROW(), ROWS(), COLUMN(), COLUMNS()
+ * 
+ * @author Josh Micich
+ */
+public final class TestRowCol extends TestCase {
+
+	public TestRowCol(String testName) {
+		super(testName);
+	}
+	
+	public void testCol() {
+		Function target = new Column();
+		{
+			Eval[] args = { EvalFactory.createRefEval("C5"), };
+			double actual = NumericFunctionInvoker.invoke(target, args);
+			assertEquals(3, actual, 0D);
+		}
+		{
+			Eval[] args = { EvalFactory.createAreaEval("E2:H12", 4, 11), };
+			double actual = NumericFunctionInvoker.invoke(target, args);
+			assertEquals(5, actual, 0D);
+		}
+	}
+	
+	public void testRow() {
+		Function target = new Row();
+		{
+			Eval[] args = { EvalFactory.createRefEval("C5"), };
+			double actual = NumericFunctionInvoker.invoke(target, args);
+			assertEquals(5, actual, 0D);
+		}
+		{
+			Eval[] args = { EvalFactory.createAreaEval("E2:H12", 4, 11), };
+			double actual = NumericFunctionInvoker.invoke(target, args);
+			assertEquals(2, actual, 0D);
+		}
+	}
+	
+	public void testColumns() {
+		
+		confirmColumnsFunc("A1:F1", 6, 1);
+		confirmColumnsFunc("A1:C2", 3, 2);
+		confirmColumnsFunc("A1:B3", 2, 3);
+		confirmColumnsFunc("A1:A6", 1, 6);
+		
+		Eval[] args = { EvalFactory.createRefEval("C5"), };
+		double actual = NumericFunctionInvoker.invoke(new Columns(), args);
+		assertEquals(1, actual, 0D);
+	}
+	
+	public void testRows() {
+		
+		confirmRowsFunc("A1:F1", 6, 1);
+		confirmRowsFunc("A1:C2", 3, 2);
+		confirmRowsFunc("A1:B3", 2, 3);
+		confirmRowsFunc("A1:A6", 1, 6);
+		
+		Eval[] args = { EvalFactory.createRefEval("C5"), };
+		double actual = NumericFunctionInvoker.invoke(new Rows(), args);
+		assertEquals(1, actual, 0D);
+	}
+	
+	private static void confirmRowsFunc(String areaRefStr, int nCols, int nRows) {
+		Eval[] args = { EvalFactory.createAreaEval(areaRefStr, nCols, nRows), };
+
+		double actual = NumericFunctionInvoker.invoke(new Rows(), args);
+		assertEquals(nRows, actual, 0D);
+	}
+	
+
+	private static void confirmColumnsFunc(String areaRefStr, int nCols, int nRows) {
+		Eval[] args = { EvalFactory.createAreaEval(areaRefStr, nCols, nRows), };
+
+		double actual = NumericFunctionInvoker.invoke(new Columns(), args);
+		assertEquals(nCols, actual, 0D);
+	}
+}

Propchange: poi/trunk/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/TestRowCol.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: poi/trunk/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/TestRowCol.java
------------------------------------------------------------------------------
    svn:executable = *



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