You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@poi.apache.org by ye...@apache.org on 2019/01/07 14:34:19 UTC

svn commit: r1850646 - in /poi/trunk: src/java/org/apache/poi/ss/formula/ src/java/org/apache/poi/ss/formula/eval/ src/java/org/apache/poi/ss/formula/functions/ src/testcases/org/apache/poi/ss/formula/functions/ test-data/spreadsheet/

Author: yegor
Date: Mon Jan  7 14:34:19 2019
New Revision: 1850646

URL: http://svn.apache.org/viewvc?rev=1850646&view=rev
Log:
Bug 62904: Support array arguments in IF and logical IS*** functions

Added:
    poi/trunk/src/testcases/org/apache/poi/ss/formula/functions/TestIFFunctionFromSpreadsheet.java   (with props)
    poi/trunk/src/testcases/org/apache/poi/ss/formula/functions/TestLogicalFunctionsFromSpreadsheet.java   (with props)
    poi/trunk/test-data/spreadsheet/IfFunctionTestCaseData.xls   (with props)
    poi/trunk/test-data/spreadsheet/LogicalFunctionsTestCaseData.xls   (with props)
Modified:
    poi/trunk/src/java/org/apache/poi/ss/formula/OperationEvaluatorFactory.java
    poi/trunk/src/java/org/apache/poi/ss/formula/WorkbookEvaluator.java
    poi/trunk/src/java/org/apache/poi/ss/formula/eval/RelationalOperationEval.java
    poi/trunk/src/java/org/apache/poi/ss/formula/eval/TwoOperandNumericOperation.java
    poi/trunk/src/java/org/apache/poi/ss/formula/eval/UnaryMinusEval.java
    poi/trunk/src/java/org/apache/poi/ss/formula/eval/UnaryPlusEval.java
    poi/trunk/src/java/org/apache/poi/ss/formula/functions/ArrayFunction.java
    poi/trunk/src/java/org/apache/poi/ss/formula/functions/IfFunc.java
    poi/trunk/src/java/org/apache/poi/ss/formula/functions/LogicalFunction.java

Modified: poi/trunk/src/java/org/apache/poi/ss/formula/OperationEvaluatorFactory.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/ss/formula/OperationEvaluatorFactory.java?rev=1850646&r1=1850645&r2=1850646&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/ss/formula/OperationEvaluatorFactory.java (original)
+++ poi/trunk/src/java/org/apache/poi/ss/formula/OperationEvaluatorFactory.java Mon Jan  7 14:34:19 2019
@@ -56,6 +56,7 @@ import org.apache.poi.ss.formula.functio
 import org.apache.poi.ss.formula.functions.ArrayFunction;
 import org.apache.poi.ss.formula.functions.Function;
 import org.apache.poi.ss.formula.functions.Indirect;
+import org.apache.poi.ss.util.CellRangeAddress;
 
 /**
  * This class creates <tt>OperationEval</tt> instances to help evaluate <tt>OperationPtg</tt>
@@ -138,8 +139,16 @@ final class OperationEvaluatorFactory {
 			EvaluationSheet evalSheet = ec.getWorkbook().getSheet(ec.getSheetIndex());
 			EvaluationCell evalCell = evalSheet.getCell(ec.getRowIndex(), ec.getColumnIndex());
 
-		    if (evalCell != null && (evalCell.isPartOfArrayFormulaGroup() || ec.isArraymode()) && result instanceof ArrayFunction)
-		        return ((ArrayFunction) result).evaluateArray(args, ec.getRowIndex(), ec.getColumnIndex());
+		    if (evalCell != null && result instanceof ArrayFunction) {
+				ArrayFunction func = (ArrayFunction) result;
+				if(evalCell.isPartOfArrayFormulaGroup()){
+					// array arguments must be evaluated relative to the function defining range
+					CellRangeAddress ca = evalCell.getArrayFormulaRange();
+					return func.evaluateArray(args, ca.getFirstRow(), ca.getFirstColumn());
+				} else if (ec.isArraymode()){
+					return func.evaluateArray(args, ec.getRowIndex(), ec.getColumnIndex());
+				}
+			}
 		                
 			return  result.evaluate(args, ec.getRowIndex(), ec.getColumnIndex());
 		} else if (udfFunc != null){

Modified: poi/trunk/src/java/org/apache/poi/ss/formula/WorkbookEvaluator.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/ss/formula/WorkbookEvaluator.java?rev=1850646&r1=1850645&r2=1850646&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/ss/formula/WorkbookEvaluator.java (original)
+++ poi/trunk/src/java/org/apache/poi/ss/formula/WorkbookEvaluator.java Mon Jan  7 14:34:19 2019
@@ -453,15 +453,24 @@ public final class WorkbookEvaluator {
                         // nothing to skip - true param follows
                     } else {
                         int dist = attrPtg.getData();
+                        Ptg currPtg = ptgs[i+1];
                         i+= countTokensToBeSkipped(ptgs, i, dist);
                         Ptg nextPtg = ptgs[i+1];
-                        if (ptgs[i] instanceof AttrPtg && nextPtg instanceof FuncVarPtg && 
-                                // in order to verify that there is no third param, we need to check 
+
+                        if (ptgs[i] instanceof AttrPtg && nextPtg instanceof FuncVarPtg &&
+                                // in order to verify that there is no third param, we need to check
                                 // if we really have the IF next or some other FuncVarPtg as third param, e.g. ROW()/COLUMN()!
                                 ((FuncVarPtg)nextPtg).getFunctionIndex() == FunctionMetadataRegistry.FUNCTION_INDEX_IF) {
                             // this is an if statement without a false param (as opposed to MissingArgPtg as the false param)
-                            i++;
-                            stack.push(BoolEval.FALSE);
+                            //i++;
+                            stack.push(arg0);
+                            if(currPtg instanceof AreaPtg){
+                                // IF in array mode. See Bug 62904
+                                ValueEval currEval = getEvalForPtg(currPtg, ec);
+                                stack.push(currEval);
+                            } else {
+                                stack.push(BoolEval.FALSE);
+                            }
                         }
                     }
                     continue;
@@ -759,7 +768,7 @@ public final class WorkbookEvaluator {
             return evaluateNameFormula(nameRecord.getNameDefinition(), ec);
         }
 
-        throw new RuntimeException("Don't now how to evalate name '" + nameRecord.getNameText() + "'");
+        throw new RuntimeException("Don't now how to evaluate name '" + nameRecord.getNameText() + "'");
     }
     
     /**

Modified: poi/trunk/src/java/org/apache/poi/ss/formula/eval/RelationalOperationEval.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/ss/formula/eval/RelationalOperationEval.java?rev=1850646&r1=1850645&r2=1850646&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/ss/formula/eval/RelationalOperationEval.java (original)
+++ poi/trunk/src/java/org/apache/poi/ss/formula/eval/RelationalOperationEval.java Mon Jan  7 14:34:19 2019
@@ -17,7 +17,6 @@
 
 package org.apache.poi.ss.formula.eval;
 
-import org.apache.poi.ss.formula.CacheAreaEval;
 import org.apache.poi.ss.formula.functions.ArrayFunction;
 import org.apache.poi.ss.formula.functions.Fixed2ArgFunction;
 import org.apache.poi.ss.formula.functions.Function;
@@ -74,84 +73,16 @@ public abstract class RelationalOperatio
 		return BoolEval.valueOf(result);
 	}
 
+	@Override
 	public ValueEval evaluateArray(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
 		ValueEval arg0 = args[0];
 		ValueEval arg1 = args[1];
+		return evaluateTwoArrayArgs(arg0, arg1, srcRowIndex, srcColumnIndex, (vA, vB) -> {
+			int cmpResult = doCompare(vA, vB);
+			boolean result = convertComparisonResult(cmpResult);
+			return BoolEval.valueOf(result);
+		});
 
-		int w1, w2, h1, h2;
-		int a1FirstCol = 0, a1FirstRow = 0;
-		if (arg0 instanceof AreaEval) {
-			AreaEval ae = (AreaEval)arg0;
-			w1 = ae.getWidth();
-			h1 = ae.getHeight();
-			a1FirstCol = ae.getFirstColumn();
-			a1FirstRow = ae.getFirstRow();
-		} else if (arg0 instanceof RefEval){
-			RefEval ref = (RefEval)arg0;
-			w1 = 1;
-			h1 = 1;
-			a1FirstCol = ref.getColumn();
-			a1FirstRow = ref.getRow();
-		} else {
-			w1 = 1;
-			h1 = 1;
-		}
-		int a2FirstCol = 0, a2FirstRow = 0;
-		if (arg1 instanceof AreaEval) {
-			AreaEval ae = (AreaEval)arg1;
-			w2 = ae.getWidth();
-			h2 = ae.getHeight();
-			a2FirstCol = ae.getFirstColumn();
-			a2FirstRow = ae.getFirstRow();
-		} else if (arg1 instanceof RefEval){
-			RefEval ref = (RefEval)arg1;
-			w2 = 1;
-			h2 = 1;
-			a2FirstCol = ref.getColumn();
-			a2FirstRow = ref.getRow();
-		} else {
-			w2 = 1;
-			h2 = 1;
-		}
-
-		int width = Math.max(w1, w2);
-		int height = Math.max(h1, h2);
-
-		ValueEval[] vals = new ValueEval[height * width];
-
-		int idx = 0;
-		for(int i = 0; i < height; i++){
-			for(int j = 0; j < width; j++){
-				ValueEval vA;
-				try {
-					vA = OperandResolver.getSingleValue(arg0, a1FirstRow + i, a1FirstCol + j);
-				} catch (EvaluationException e) {
-					vA = e.getErrorEval();
-				}
-				ValueEval vB;
-				try {
-					vB = OperandResolver.getSingleValue(arg1, a2FirstRow + i, a2FirstCol + j);
-				} catch (EvaluationException e) {
-					vB = e.getErrorEval();
-				}
-				if(vA instanceof ErrorEval){
-					vals[idx++] = vA;
-				} else if (vB instanceof ErrorEval) {
-					vals[idx++] = vB;
-				} else {
-					int cmpResult = doCompare(vA, vB);
-					boolean result = convertComparisonResult(cmpResult);
-					vals[idx++] = BoolEval.valueOf(result);
-				}
-
-			}
-		}
-
-		if (vals.length == 1) {
-			return vals[0];
-		}
-
-		return new CacheAreaEval(srcRowIndex, srcColumnIndex, srcRowIndex + height - 1, srcColumnIndex + width - 1, vals);
 	}
 
 	private static int doCompare(ValueEval va, ValueEval vb) {

Modified: poi/trunk/src/java/org/apache/poi/ss/formula/eval/TwoOperandNumericOperation.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/ss/formula/eval/TwoOperandNumericOperation.java?rev=1850646&r1=1850645&r2=1850646&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/ss/formula/eval/TwoOperandNumericOperation.java (original)
+++ poi/trunk/src/java/org/apache/poi/ss/formula/eval/TwoOperandNumericOperation.java Mon Jan  7 14:34:19 2019
@@ -37,7 +37,20 @@ public abstract class TwoOperandNumericO
 	    if (args.length != 2) {
 	        return ErrorEval.VALUE_INVALID;
 	    }
-	    return new ArrayEval().evaluate(srcRowIndex, srcColumnIndex, args[0], args[1]);
+	    //return new ArrayEval().evaluate(srcRowIndex, srcColumnIndex, args[0], args[1]);
+
+		return evaluateTwoArrayArgs(args[0], args[1], srcRowIndex, srcColumnIndex,
+				(vA, vB) -> {
+					try {
+						double d0 = OperandResolver.coerceValueToDouble(vA);
+						double d1 = OperandResolver.coerceValueToDouble(vB);
+						double result = evaluate(d0, d1);
+						return new NumberEval(result);
+					} catch (EvaluationException e){
+						return e.getErrorEval();
+					}
+				});
+
 	}
 	
 	public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1) {

Modified: poi/trunk/src/java/org/apache/poi/ss/formula/eval/UnaryMinusEval.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/ss/formula/eval/UnaryMinusEval.java?rev=1850646&r1=1850645&r2=1850646&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/ss/formula/eval/UnaryMinusEval.java (original)
+++ poi/trunk/src/java/org/apache/poi/ss/formula/eval/UnaryMinusEval.java Mon Jan  7 14:34:19 2019
@@ -17,13 +17,14 @@
 
 package org.apache.poi.ss.formula.eval;
 
+import org.apache.poi.ss.formula.functions.ArrayFunction;
 import org.apache.poi.ss.formula.functions.Fixed1ArgFunction;
 import org.apache.poi.ss.formula.functions.Function;
 
 /**
  * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
  */
-public final class UnaryMinusEval extends Fixed1ArgFunction {
+public final class UnaryMinusEval extends Fixed1ArgFunction  implements ArrayFunction {
 
 	public static final Function instance = new UnaryMinusEval();
 
@@ -44,4 +45,12 @@ public final class UnaryMinusEval extend
 		}
 		return new NumberEval(-d);
 	}
+
+	@Override
+	public ValueEval evaluateArray(ValueEval[] args, int srcRowIndex, int srcColumnIndex){
+		return evaluateOneArrayArg(args, srcRowIndex, srcColumnIndex, (valA) ->
+				evaluate(srcRowIndex, srcColumnIndex, valA)
+		);
+	}
+
 }

Modified: poi/trunk/src/java/org/apache/poi/ss/formula/eval/UnaryPlusEval.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/ss/formula/eval/UnaryPlusEval.java?rev=1850646&r1=1850645&r2=1850646&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/ss/formula/eval/UnaryPlusEval.java (original)
+++ poi/trunk/src/java/org/apache/poi/ss/formula/eval/UnaryPlusEval.java Mon Jan  7 14:34:19 2019
@@ -17,6 +17,7 @@
 
 package org.apache.poi.ss.formula.eval;
 
+import org.apache.poi.ss.formula.functions.ArrayFunction;
 import org.apache.poi.ss.formula.functions.Fixed1ArgFunction;
 import org.apache.poi.ss.formula.functions.Function;
 
@@ -24,7 +25,7 @@ import org.apache.poi.ss.formula.functio
 /**
  * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
  */
-public final class UnaryPlusEval extends Fixed1ArgFunction {
+public final class UnaryPlusEval extends Fixed1ArgFunction  implements ArrayFunction {
 
 	public static final Function instance = new UnaryPlusEval();
 
@@ -48,4 +49,12 @@ public final class UnaryPlusEval extends
 		}
 		return new NumberEval(+d);
 	}
+
+	@Override
+	public ValueEval evaluateArray(ValueEval[] args, int srcRowIndex, int srcColumnIndex){
+		return evaluateOneArrayArg(args, srcRowIndex, srcColumnIndex, (valA) ->
+				evaluate(srcRowIndex, srcColumnIndex, valA)
+		);
+	}
+
 }

Modified: poi/trunk/src/java/org/apache/poi/ss/formula/functions/ArrayFunction.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/ss/formula/functions/ArrayFunction.java?rev=1850646&r1=1850645&r2=1850646&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/ss/formula/functions/ArrayFunction.java (original)
+++ poi/trunk/src/java/org/apache/poi/ss/formula/functions/ArrayFunction.java Mon Jan  7 14:34:19 2019
@@ -17,10 +17,11 @@
 
 package org.apache.poi.ss.formula.functions;
 
-import org.apache.poi.ss.formula.eval.BlankEval;
-import org.apache.poi.ss.formula.eval.ErrorEval;
-import org.apache.poi.ss.formula.eval.MissingArgEval;
-import org.apache.poi.ss.formula.eval.ValueEval;
+import org.apache.poi.ss.formula.CacheAreaEval;
+import org.apache.poi.ss.formula.FormulaParseException;
+import org.apache.poi.ss.formula.eval.*;
+
+import java.util.function.BiFunction;
 
 /**
  * @author Robert Hulbert
@@ -41,4 +42,153 @@ public interface ArrayFunction {
      */
 
     ValueEval evaluateArray(ValueEval[] args, int srcRowIndex, int srcColumnIndex);
+
+    /**
+     * Evaluate an array function with two arguments.
+     *
+     * @param arg0 the first function argument. Empty values are represented with
+     *        {@link BlankEval} or {@link MissingArgEval}, never <code>null</code>
+     * @param arg1 the first function argument. Empty values are represented with
+     *      @link BlankEval} or {@link MissingArgEval}, never <code>null</code>
+     *
+     * @param srcRowIndex row index of the cell containing the formula under evaluation
+     * @param srcColumnIndex column index of the cell containing the formula under evaluation
+     * @return The evaluated result, possibly an {@link ErrorEval}, never <code>null</code>.
+     * <b>Note</b> - Excel uses the error code <i>#NUM!</i> instead of IEEE <i>NaN</i>, so when
+     * numeric functions evaluate to {@link Double#NaN} be sure to translate the result to {@link
+     * ErrorEval#NUM_ERROR}.
+     */
+    default ValueEval evaluateTwoArrayArgs(ValueEval arg0, ValueEval arg1, int srcRowIndex, int srcColumnIndex,
+                                           BiFunction<ValueEval, ValueEval, ValueEval> evalFunc) {
+        int w1, w2, h1, h2;
+        int a1FirstCol = 0, a1FirstRow = 0;
+        if (arg0 instanceof AreaEval) {
+            AreaEval ae = (AreaEval)arg0;
+            w1 = ae.getWidth();
+            h1 = ae.getHeight();
+            a1FirstCol = ae.getFirstColumn();
+            a1FirstRow = ae.getFirstRow();
+        } else if (arg0 instanceof RefEval){
+            RefEval ref = (RefEval)arg0;
+            w1 = 1;
+            h1 = 1;
+            a1FirstCol = ref.getColumn();
+            a1FirstRow = ref.getRow();
+        } else {
+            w1 = 1;
+            h1 = 1;
+        }
+        int a2FirstCol = 0, a2FirstRow = 0;
+        if (arg1 instanceof AreaEval) {
+            AreaEval ae = (AreaEval)arg1;
+            w2 = ae.getWidth();
+            h2 = ae.getHeight();
+            a2FirstCol = ae.getFirstColumn();
+            a2FirstRow = ae.getFirstRow();
+        } else if (arg1 instanceof RefEval){
+            RefEval ref = (RefEval)arg1;
+            w2 = 1;
+            h2 = 1;
+            a2FirstCol = ref.getColumn();
+            a2FirstRow = ref.getRow();
+        } else {
+            w2 = 1;
+            h2 = 1;
+        }
+
+        int width = Math.max(w1, w2);
+        int height = Math.max(h1, h2);
+
+        ValueEval[] vals = new ValueEval[height * width];
+
+        int idx = 0;
+        for(int i = 0; i < height; i++){
+            for(int j = 0; j < width; j++){
+                ValueEval vA;
+                try {
+                    vA = OperandResolver.getSingleValue(arg0, a1FirstRow + i, a1FirstCol + j);
+                } catch (FormulaParseException e) {
+                    vA = ErrorEval.NAME_INVALID;
+                } catch (EvaluationException e) {
+                    vA = e.getErrorEval();
+                }
+                ValueEval vB;
+                try {
+                    vB = OperandResolver.getSingleValue(arg1, a2FirstRow + i, a2FirstCol + j);
+                } catch (FormulaParseException e) {
+                    vB = ErrorEval.NAME_INVALID;
+                } catch (EvaluationException e) {
+                    vB = e.getErrorEval();
+                }
+                if(vA instanceof ErrorEval){
+                    vals[idx++] = vA;
+                } else if (vB instanceof ErrorEval) {
+                    vals[idx++] = vB;
+                } else {
+                    vals[idx++] = evalFunc.apply(vA, vB);
+                }
+
+            }
+        }
+
+        if (vals.length == 1) {
+            return vals[0];
+        }
+
+        return new CacheAreaEval(srcRowIndex, srcColumnIndex, srcRowIndex + height - 1, srcColumnIndex + width - 1, vals);
+    }
+
+    default ValueEval evaluateOneArrayArg(ValueEval[] args, int srcRowIndex, int srcColumnIndex,
+                                          java.util.function.Function<ValueEval, ValueEval> evalFunc){
+        ValueEval arg0 = args[0];
+
+        int w1, w2, h1, h2;
+        int a1FirstCol = 0, a1FirstRow = 0;
+        if (arg0 instanceof AreaEval) {
+            AreaEval ae = (AreaEval)arg0;
+            w1 = ae.getWidth();
+            h1 = ae.getHeight();
+            a1FirstCol = ae.getFirstColumn();
+            a1FirstRow = ae.getFirstRow();
+        } else if (arg0 instanceof RefEval){
+            RefEval ref = (RefEval)arg0;
+            w1 = 1;
+            h1 = 1;
+            a1FirstCol = ref.getColumn();
+            a1FirstRow = ref.getRow();
+        } else {
+            w1 = 1;
+            h1 = 1;
+        }
+        w2 = 1;
+        h2 = 1;
+
+        int width = Math.max(w1, w2);
+        int height = Math.max(h1, h2);
+
+        ValueEval[] vals = new ValueEval[height * width];
+
+        int idx = 0;
+        for(int i = 0; i < height; i++){
+            for(int j = 0; j < width; j++){
+                ValueEval vA;
+                try {
+                    vA = OperandResolver.getSingleValue(arg0, a1FirstRow + i, a1FirstCol + j);
+                } catch (FormulaParseException e) {
+                    vA = ErrorEval.NAME_INVALID;
+                } catch (EvaluationException e) {
+                    vA = e.getErrorEval();
+                }
+                vals[idx++] = evalFunc.apply(vA);
+            }
+        }
+
+        if (vals.length == 1) {
+            return vals[0];
+        }
+
+        return new CacheAreaEval(srcRowIndex, srcColumnIndex, srcRowIndex + height - 1, srcColumnIndex + width - 1, vals);
+
+    }
+
 }

Modified: poi/trunk/src/java/org/apache/poi/ss/formula/functions/IfFunc.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/ss/formula/functions/IfFunc.java?rev=1850646&r1=1850645&r2=1850646&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/ss/formula/functions/IfFunc.java (original)
+++ poi/trunk/src/java/org/apache/poi/ss/formula/functions/IfFunc.java Mon Jan  7 14:34:19 2019
@@ -17,12 +17,7 @@
 
 package org.apache.poi.ss.formula.functions;
 
-import org.apache.poi.ss.formula.eval.BlankEval;
-import org.apache.poi.ss.formula.eval.BoolEval;
-import org.apache.poi.ss.formula.eval.EvaluationException;
-import org.apache.poi.ss.formula.eval.MissingArgEval;
-import org.apache.poi.ss.formula.eval.OperandResolver;
-import org.apache.poi.ss.formula.eval.ValueEval;
+import org.apache.poi.ss.formula.eval.*;
 import org.apache.poi.ss.formula.ptg.Ptg;
 import org.apache.poi.ss.formula.ptg.RefPtg;
 
@@ -36,8 +31,9 @@ import org.apache.poi.ss.formula.ptg.Ref
  * See bug numbers #55324 and #55747 for the full details on this.
  * TODO Fix this...
  */
-public final class IfFunc extends Var2or3ArgFunction {
+public final class IfFunc extends Var2or3ArgFunction implements ArrayFunction {
 
+    @Override
 	public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1) {
 		boolean b;
 		try {
@@ -54,6 +50,7 @@ public final class IfFunc extends Var2or
 		return BoolEval.FALSE;
 	}
 
+    @Override
 	public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1,
 			ValueEval arg2) {
 		boolean b;
@@ -83,4 +80,29 @@ public final class IfFunc extends Var2or
 		}
 		return b.booleanValue();
 	}
+
+
+ 	@Override
+	public ValueEval evaluateArray(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
+		ValueEval arg0 = args[0];
+		ValueEval arg1 = args[1];
+		return evaluateTwoArrayArgs(arg0, arg1, srcRowIndex, srcColumnIndex,
+                (vA, vB) -> {
+					Boolean b;
+					try {
+						b = OperandResolver.coerceValueToBoolean(vA, false);
+					} catch (EvaluationException e) {
+						return e.getErrorEval();
+					}
+					if (b != null && b) {
+						if (vB == MissingArgEval.instance) {
+							return BlankEval.instance;
+						}
+						return vB;
+					}
+					return BoolEval.FALSE;
+				}
+        );
+	}
+
 }

Modified: poi/trunk/src/java/org/apache/poi/ss/formula/functions/LogicalFunction.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/ss/formula/functions/LogicalFunction.java?rev=1850646&r1=1850645&r2=1850646&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/ss/formula/functions/LogicalFunction.java (original)
+++ poi/trunk/src/java/org/apache/poi/ss/formula/functions/LogicalFunction.java Mon Jan  7 14:34:19 2019
@@ -23,7 +23,7 @@ import org.apache.poi.ss.formula.eval.*;
  * Implementation of the various ISxxx Logical Functions, which
  *  take a single expression argument, and return True or False.
  */
-public abstract class LogicalFunction extends Fixed1ArgFunction {
+public abstract class LogicalFunction extends Fixed1ArgFunction implements ArrayFunction{
 
     @SuppressWarnings("unused")
     public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0) {
@@ -41,6 +41,14 @@ public abstract class LogicalFunction ex
 		return BoolEval.valueOf(evaluate(ve));
 
 	}
+
+	@Override
+	public ValueEval evaluateArray(ValueEval[] args, int srcRowIndex, int srcColumnIndex){
+		return evaluateOneArrayArg(args, srcRowIndex, srcColumnIndex, (valA) ->
+				BoolEval.valueOf(evaluate(valA))
+		);
+	}
+
 	/**
 	 * @param arg any {@link ValueEval}, potentially {@link BlankEval} or {@link ErrorEval}.
 	 */

Added: poi/trunk/src/testcases/org/apache/poi/ss/formula/functions/TestIFFunctionFromSpreadsheet.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/testcases/org/apache/poi/ss/formula/functions/TestIFFunctionFromSpreadsheet.java?rev=1850646&view=auto
==============================================================================
--- poi/trunk/src/testcases/org/apache/poi/ss/formula/functions/TestIFFunctionFromSpreadsheet.java (added)
+++ poi/trunk/src/testcases/org/apache/poi/ss/formula/functions/TestIFFunctionFromSpreadsheet.java Mon Jan  7 14:34:19 2019
@@ -0,0 +1,32 @@
+/* ====================================================================
+   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.ss.formula.functions;
+
+import org.junit.runners.Parameterized.Parameters;
+
+import java.util.Collection;
+
+/**
+ * Tests IF() as loaded from a test data spreadsheet.<p>
+ */
+public class TestIFFunctionFromSpreadsheet extends BaseTestFunctionsFromSpreadsheet {
+    @Parameters(name="{0}")
+    public static Collection<Object[]> data() throws Exception {
+        return data(TestIFFunctionFromSpreadsheet.class, "IfFunctionTestCaseData.xls");
+    }
+}

Propchange: poi/trunk/src/testcases/org/apache/poi/ss/formula/functions/TestIFFunctionFromSpreadsheet.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: poi/trunk/src/testcases/org/apache/poi/ss/formula/functions/TestLogicalFunctionsFromSpreadsheet.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/testcases/org/apache/poi/ss/formula/functions/TestLogicalFunctionsFromSpreadsheet.java?rev=1850646&view=auto
==============================================================================
--- poi/trunk/src/testcases/org/apache/poi/ss/formula/functions/TestLogicalFunctionsFromSpreadsheet.java (added)
+++ poi/trunk/src/testcases/org/apache/poi/ss/formula/functions/TestLogicalFunctionsFromSpreadsheet.java Mon Jan  7 14:34:19 2019
@@ -0,0 +1,32 @@
+/* ====================================================================
+   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.ss.formula.functions;
+
+import org.junit.runners.Parameterized.Parameters;
+
+import java.util.Collection;
+
+/**
+ * Tests for logical ISxxx functions as loaded from a test data spreadsheet.<p>
+ */
+public class TestLogicalFunctionsFromSpreadsheet extends BaseTestFunctionsFromSpreadsheet {
+    @Parameters(name="{0}")
+    public static Collection<Object[]> data() throws Exception {
+        return data(TestLogicalFunctionsFromSpreadsheet.class, "LogicalFunctionsTestCaseData.xls");
+    }
+}

Propchange: poi/trunk/src/testcases/org/apache/poi/ss/formula/functions/TestLogicalFunctionsFromSpreadsheet.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: poi/trunk/test-data/spreadsheet/IfFunctionTestCaseData.xls
URL: http://svn.apache.org/viewvc/poi/trunk/test-data/spreadsheet/IfFunctionTestCaseData.xls?rev=1850646&view=auto
==============================================================================
Binary file - no diff available.

Propchange: poi/trunk/test-data/spreadsheet/IfFunctionTestCaseData.xls
------------------------------------------------------------------------------
    svn:mime-type = application/vnd.ms-excel

Added: poi/trunk/test-data/spreadsheet/LogicalFunctionsTestCaseData.xls
URL: http://svn.apache.org/viewvc/poi/trunk/test-data/spreadsheet/LogicalFunctionsTestCaseData.xls?rev=1850646&view=auto
==============================================================================
Binary file - no diff available.

Propchange: poi/trunk/test-data/spreadsheet/LogicalFunctionsTestCaseData.xls
------------------------------------------------------------------------------
    svn:mime-type = application/vnd.ms-excel



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