aboutsummaryrefslogtreecommitdiffstats
path: root/src/testcases/org/apache/poi/ss/formula
diff options
context:
space:
mode:
authorPJ Fanning <fanningpj@apache.org>2018-12-16 18:51:09 +0000
committerPJ Fanning <fanningpj@apache.org>2018-12-16 18:51:09 +0000
commite399507710813886ec1f50291d378e282dfe6ce8 (patch)
tree93784a6dea15ce2114a7147b652780b664d99530 /src/testcases/org/apache/poi/ss/formula
parent8d51a39edd0e9836c633c35e8f8cd483284ed564 (diff)
downloadpoi-e399507710813886ec1f50291d378e282dfe6ce8.tar.gz
poi-e399507710813886ec1f50291d378e282dfe6ce8.zip
Implemented GEOMEAN function. Thanks to gallonfizik. This closes #136
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1849042 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/testcases/org/apache/poi/ss/formula')
-rw-r--r--src/testcases/org/apache/poi/ss/formula/functions/TestGeomean.java112
-rw-r--r--src/testcases/org/apache/poi/ss/formula/functions/TestMultiOperandNumericFunction.java23
2 files changed, 135 insertions, 0 deletions
diff --git a/src/testcases/org/apache/poi/ss/formula/functions/TestGeomean.java b/src/testcases/org/apache/poi/ss/formula/functions/TestGeomean.java
new file mode 100644
index 0000000000..0eedbee7e1
--- /dev/null
+++ b/src/testcases/org/apache/poi/ss/formula/functions/TestGeomean.java
@@ -0,0 +1,112 @@
+package org.apache.poi.ss.formula.functions;
+
+import org.apache.poi.ss.formula.eval.*;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * From Excel documentation at https://support.office.com/en-us/article/geomean-function-db1ac48d-25a5-40a0-ab83-0b38980e40d5:
+ * 1. Arguments can either be numbers or names, arrays, or references that contain numbers.
+ * 2. Logical values and text representations of numbers that you type directly into the list of arguments are counted.
+ * 3. If an array or reference argument contains text, logical values, or empty cells, those values are ignored; however, cells with the value zero are included.
+ * 4. Arguments that are error values or text that cannot be translated into numbers cause errors.
+ * 5. If any data point ≤ 0, GEOMEAN returns the #NUM! error value.
+ *
+ * Remarks:
+ * Actually, 5. is not true. If an error is encountered before a 0 value, the error is returned.
+ */
+public class TestGeomean {
+ @Test
+ public void acceptanceTest() {
+ Function geomean = getInstance();
+
+ final ValueEval result = geomean.evaluate(new ValueEval[]{new NumberEval(2), new NumberEval(3)}, 0, 0);
+ verifyNumericResult(2.449489742783178, result);
+ }
+
+ @Test
+ public void booleansByValueAreCoerced() {
+ final ValueEval[] args = {BoolEval.TRUE};
+ final ValueEval result = getInstance().evaluate(args, 0, 0);
+ verifyNumericResult(1.0, result);
+ }
+
+ @Test
+ public void stringsByValueAreCoerced() {
+ final ValueEval[] args = {new StringEval("2")};
+ final ValueEval result = getInstance().evaluate(args, 0, 0);
+ verifyNumericResult(2.0, result);
+ }
+
+ @Test
+ public void nonCoerceableStringsByValueCauseValueInvalid() {
+ final ValueEval[] args = {new StringEval("foo")};
+ final ValueEval result = getInstance().evaluate(args, 0, 0);
+ assertEquals(ErrorEval.VALUE_INVALID, result);
+ }
+
+ @Test
+ public void booleansByReferenceAreSkipped() {
+ final ValueEval[] args = new ValueEval[]{new NumberEval(2.0), EvalFactory.createRefEval("A1", BoolEval.TRUE)};
+ final ValueEval result = getInstance().evaluate(args, 0, 0);
+ verifyNumericResult(2.0, result);
+ }
+
+ @Test
+ public void booleansStringsAndBlanksByReferenceAreSkipped() {
+ ValueEval ref = EvalFactory.createAreaEval("A1:A3", new ValueEval[]{new StringEval("foo"), BoolEval.FALSE, BlankEval.instance});
+ final ValueEval[] args = {ref, new NumberEval(2.0)};
+ final ValueEval result = getInstance().evaluate(args, 0, 0);
+ verifyNumericResult(2.0, result);
+ }
+
+ @Test
+ public void stringsByValueAreCounted() {
+ final ValueEval[] args = {new StringEval("2.0")};
+ final ValueEval result = getInstance().evaluate(args, 0, 0);
+ verifyNumericResult(2.0, result);
+ }
+
+ @Test
+ public void missingArgCountAsZero() {
+ // and, naturally, produces a NUM_ERROR
+ final ValueEval[] args = {new NumberEval(1.0), MissingArgEval.instance};
+ final ValueEval result = getInstance().evaluate(args, 0, 0);
+ assertEquals(ErrorEval.NUM_ERROR, result);
+ }
+
+ /**
+ * Implementation-specific: the math lib returns 0 for the input [1.0, 0.0], but a NUM_ERROR should be returned.
+ */
+ @Test
+ public void sequence_1_0_shouldReturnError() {
+ final ValueEval[] args = {new NumberEval(1.0), new NumberEval(0)};
+ final ValueEval result = getInstance().evaluate(args, 0, 0);
+ assertEquals(ErrorEval.NUM_ERROR, result);
+ }
+
+ @Test
+ public void minusOneShouldReturnError() {
+ final ValueEval[] args = {new NumberEval(1.0), new NumberEval(-1.0)};
+ final ValueEval result = getInstance().evaluate(args, 0, 0);
+ assertEquals(ErrorEval.NUM_ERROR, result);
+ }
+
+ @Test
+ public void firstErrorPropagates() {
+ final ValueEval[] args = {ErrorEval.DIV_ZERO, ErrorEval.NUM_ERROR};
+ final ValueEval result = getInstance().evaluate(args, 0, 0);
+ assertEquals(ErrorEval.DIV_ZERO, result);
+ }
+
+ private void verifyNumericResult(double expected, ValueEval result) {
+ assertTrue(result instanceof NumberEval);
+ assertEquals(expected, ((NumberEval) result).getNumberValue(), 1e-15);
+ }
+
+ private Function getInstance() {
+ return AggregateFunction.GEOMEAN;
+ }
+}
diff --git a/src/testcases/org/apache/poi/ss/formula/functions/TestMultiOperandNumericFunction.java b/src/testcases/org/apache/poi/ss/formula/functions/TestMultiOperandNumericFunction.java
index 31490a0547..a54a69f85d 100644
--- a/src/testcases/org/apache/poi/ss/formula/functions/TestMultiOperandNumericFunction.java
+++ b/src/testcases/org/apache/poi/ss/formula/functions/TestMultiOperandNumericFunction.java
@@ -18,9 +18,13 @@
package org.apache.poi.ss.formula.functions;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
import org.apache.poi.ss.SpreadsheetVersion;
import org.apache.poi.ss.formula.eval.EvaluationException;
+import org.apache.poi.ss.formula.eval.MissingArgEval;
+import org.apache.poi.ss.formula.eval.NumberEval;
+import org.apache.poi.ss.formula.eval.ValueEval;
import org.junit.Test;
public class TestMultiOperandNumericFunction {
@@ -36,4 +40,23 @@ public class TestMultiOperandNumericFunction {
};
assertEquals(SpreadsheetVersion.EXCEL2007.getMaxFunctionArgs(), fun.getMaxNumOperands());
}
+
+ @Test
+ public void missingArgEvalsAreCountedAsZero() {
+ MultiOperandNumericFunction instance = new Stub(true, true);
+ ValueEval result = instance.evaluate(new ValueEval[]{MissingArgEval.instance}, 0, 0);
+ assertTrue(result instanceof NumberEval);
+ assertEquals(0.0, ((NumberEval)result).getNumberValue(), 0);
+ }
+
+ private static class Stub extends MultiOperandNumericFunction {
+ protected Stub(boolean isReferenceBoolCounted, boolean isBlankCounted) {
+ super(isReferenceBoolCounted, isBlankCounted);
+ }
+
+ @Override
+ protected double evaluate(double[] values) throws EvaluationException {
+ return values[0];
+ }
+ }
}