From 74624c0cddaf168e5140608755ef8024d3be2fac Mon Sep 17 00:00:00 2001
From: Josh Micich
Date: Sat, 24 Oct 2009 00:41:30 +0000
Subject: [PATCH] Bugzilla 48044 - added implementation for CountBlank function
(patch from Mads Mohr Christensen)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@829293 13f79535-47bb-0310-9956-ffa450edef68
---
src/documentation/content/xdocs/status.xml | 1 +
.../record/formula/eval/FunctionEval.java | 1 +
.../record/formula/functions/Countblank.java | 67 ++++++++++++++++++
.../formula/functions/TestCountFuncs.java | 49 +++++++++++--
test-data/spreadsheet/countblankExamples.xls | Bin 0 -> 6656 bytes
5 files changed, 113 insertions(+), 5 deletions(-)
create mode 100644 src/java/org/apache/poi/hssf/record/formula/functions/Countblank.java
create mode 100644 test-data/spreadsheet/countblankExamples.xls
diff --git a/src/documentation/content/xdocs/status.xml b/src/documentation/content/xdocs/status.xml
index 6dac6eac4..99d07c91f 100644
--- a/src/documentation/content/xdocs/status.xml
+++ b/src/documentation/content/xdocs/status.xml
@@ -33,6 +33,7 @@
+ 48044 - added implementation for CountBlank function
48036 - added IntersectionEval to allow evaluation of the intersection formula operator
47999 - avoid un-needed call to the JVM Garbage Collector when working on OOXML OPC Packages
47922 - added example HSMF application that converts a .msg file to text and extracts attachments
diff --git a/src/java/org/apache/poi/hssf/record/formula/eval/FunctionEval.java b/src/java/org/apache/poi/hssf/record/formula/eval/FunctionEval.java
index 583cf88b8..dc5d6c5fe 100644
--- a/src/java/org/apache/poi/hssf/record/formula/eval/FunctionEval.java
+++ b/src/java/org/apache/poi/hssf/record/formula/eval/FunctionEval.java
@@ -203,6 +203,7 @@ public final class FunctionEval implements OperationEval {
retval[345] = new Sumif();
retval[346] = new Countif();
+ retval[347] = new Countblank();
retval[359] = new Hyperlink();
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Countblank.java b/src/java/org/apache/poi/hssf/record/formula/functions/Countblank.java
new file mode 100644
index 000000000..f7d7538a9
--- /dev/null
+++ b/src/java/org/apache/poi/hssf/record/formula/functions/Countblank.java
@@ -0,0 +1,67 @@
+/* ====================================================================
+ 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.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.NumberEval;
+import org.apache.poi.hssf.record.formula.eval.RefEval;
+import org.apache.poi.hssf.record.formula.eval.ValueEval;
+import org.apache.poi.hssf.record.formula.functions.CountUtils.I_MatchPredicate;
+
+/**
+ * Implementation for the function COUNTBLANK
+ *
+ * Syntax: COUNTBLANK ( range )
+ *
+ * range | is the range of cells to count blanks |
+ *
+ *
+ *
+ * @author Mads Mohr Christensen
+ */
+public final class Countblank implements Function {
+
+ public ValueEval evaluate(ValueEval[] args, int srcRowIndex, short srcColumnIndex) {
+ if (args.length != 1) {
+ // TODO - it doesn't seem to be possible to enter COUNTBLANK() into Excel with the wrong arg count
+ // perhaps this should be an exception
+ return ErrorEval.VALUE_INVALID;
+ }
+
+ double result;
+ ValueEval arg0 = args[0];
+ if (arg0 instanceof RefEval) {
+ result = CountUtils.countMatchingCell((RefEval) arg0, predicate);
+ } else if (arg0 instanceof AreaEval) {
+ result = CountUtils.countMatchingCellsInArea((AreaEval) arg0, predicate);
+ } else {
+ throw new IllegalArgumentException("Bad range arg type (" + arg0.getClass().getName() + ")");
+ }
+ return new NumberEval(result);
+ }
+
+ private static final I_MatchPredicate predicate = new I_MatchPredicate() {
+
+ public boolean matches(ValueEval valueEval) {
+ // Note - only BlankEval counts
+ return valueEval == BlankEval.INSTANCE;
+ }
+ };
+}
diff --git a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestCountFuncs.java b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestCountFuncs.java
index e07f2c245..e3ee50e0a 100644
--- a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestCountFuncs.java
+++ b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestCountFuncs.java
@@ -46,6 +46,34 @@ public final class TestCountFuncs extends TestCase {
private static final String NULL = null;
+ public void testCountBlank() {
+
+ AreaEval range;
+ ValueEval[] values;
+
+ values = new ValueEval[] {
+ new NumberEval(0),
+ new StringEval(""), // note - does not match blank
+ BoolEval.TRUE,
+ BoolEval.FALSE,
+ ErrorEval.DIV_ZERO,
+ BlankEval.INSTANCE,
+ };
+ range = EvalFactory.createAreaEval("A1:B3", values);
+ confirmCountBlank(1, range);
+
+ values = new ValueEval[] {
+ new NumberEval(0),
+ new StringEval(""), // note - does not match blank
+ BlankEval.INSTANCE,
+ BoolEval.FALSE,
+ BoolEval.TRUE,
+ BlankEval.INSTANCE,
+ };
+ range = EvalFactory.createAreaEval("A1:B3", values);
+ confirmCountBlank(2, range);
+ }
+
public void testCountA() {
ValueEval[] args;
@@ -196,6 +224,12 @@ public final class TestCountFuncs extends TestCase {
double result = NumericFunctionInvoker.invoke(new Countif(), args);
assertEquals(expected, result, 0);
}
+ private static void confirmCountBlank(int expected, AreaEval range) {
+
+ ValueEval[] args = { range };
+ double result = NumericFunctionInvoker.invoke(new Countblank(), args);
+ assertEquals(expected, result, 0);
+ }
private static I_MatchPredicate createCriteriaPredicate(ValueEval ev) {
return Countif.createCriteriaPredicate(ev, 0, 0);
@@ -388,10 +422,14 @@ public final class TestCountFuncs extends TestCase {
}
public void testCountifFromSpreadsheet() {
- final String FILE_NAME = "countifExamples.xls";
- final int START_ROW_IX = 1;
- final int COL_IX_ACTUAL = 2;
- final int COL_IX_EXPECTED = 3;
+ testCountFunctionFromSpreadsheet("countifExamples.xls", 1, 2, 3, "countif");
+ }
+
+ public void testCountBlankFromSpreadsheet() {
+ testCountFunctionFromSpreadsheet("countblankExamples.xls", 1, 3, 4, "countblank");
+ }
+
+ private static void testCountFunctionFromSpreadsheet(String FILE_NAME, int START_ROW_IX, int COL_IX_ACTUAL, int COL_IX_EXPECTED, String functionName) {
int failureCount = 0;
HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook(FILE_NAME);
@@ -415,7 +453,8 @@ public final class TestCountFuncs extends TestCase {
}
if (failureCount > 0) {
- throw new AssertionFailedError(failureCount + " countif evaluations failed. See stderr for more details");
+ throw new AssertionFailedError(failureCount + " " + functionName
+ + " evaluations failed. See stderr for more details");
}
}
}
diff --git a/test-data/spreadsheet/countblankExamples.xls b/test-data/spreadsheet/countblankExamples.xls
new file mode 100644
index 0000000000000000000000000000000000000000..19b4e17b4bcee58778c02af149e5cf4f07be82cb
GIT binary patch
literal 6656
zcmeHLU2IfE6h8OvPq(Ge9}xMGdaVL2E!4_`D8X)Ni;_?w1tKVkY`3?tvfU-!ZBie^
zMd8gK3=h7L7!m}Di9azx6G<#@#AqZYJZO9l7h5Wd~zdKEqV1XV<;+Ganx+H;eP+r7Jm!9UsW4vNY
z8RN0gC{O0rvrx0O|nu11!J;fO^1#fQJA}0m}f(0S$mg0QGHhOV(GR-s0k|
zZaHp&nc8$LP#(f61_Sc>?5}v_>)C$^9`TX?ochIO(00jw`bI}29<~0dv|e?H81&6`
z$PGCL${hF;DYcr<)%-*4b5`@PQeM}5o%$s@hs9chf_If2X1%t}L2k&WI_7(&w8ATY
zK%bBtakoU7(IF9uOH6ukD#oN0etaH1axZHS)B;Akwy@XjwdQ4?<>UZ`vg`bna)L4W
z$*!lndfGP;e|G}DNKSI^)o<(B-c`RgUumO(x@Z
zBw_VO;wjteOWG+bkxX0BHlvD`KVgN20dHt`SHd%;C9KDUDE;Ghi5Zj{E8f$9*NN
z)dwr`NUTxIRl`2lPG9-9yLU_5^GeU~_;AxwuAx*I2hnoQzd}beY5t1#&0hmvRoWrV
zmtlOrrXSmud+H5ie1B?d^wf__J+$eA9Imn{%|^2^>&$NaN89qHA=}Xsl9zOLB0DO1
zDG|jvW}OEQ;F|hoyVEWvFEGv%#|d~LldI2q1sw)LtAsQI*P=iHjh);S
z=@m<9UKue*+MhEHm=!?$@C4e27<*M=bRIKZjQmVUst
za`1UL$hbx%dpP)%1ARAOmZQ$AB~*40L+_c;upTXw>f`5-k+Jy^bu^%b{IJeAMoU%c
z!z%p)tHvS=CFk~UZ%2U4c;3xfMXU1{}h4mwgy`mH4v_N-xhkz7E8bOsUXu
z5Wz{v6K1WPp~@0w=B6d&SEd~d7z(uj7v^@7f!nKi}d2yv(=*OWBvWkbU=zI^epDNI~|(Zlcjes%NS
z>i6FYNz?LAzT-k10pK*(1q!32Lv!KiTH64$=WYNOHV)vyJq+Nx>kxpFe!lL!p;)&7
zd{42y8W0A^<8qSnwN4x<%&g_Y>9v>78(RNt!yAvR`O+w+Klzy#zrJ{E)#B=-Z$tm)
zs~>cN7ATV&
zwi}Qe7ki4{Q#Ub4JCdDz>fTOkGYVePm;$m@hA{sDymk5QZzH|}_UoFElE%9?2}<$Q
y;L2yvD0TiT(RajU8IVp$h^h{@eu12xK5K4a{yc}%uKYVuOxOP2?{ELM{J#NM14YyT
literal 0
HcmV?d00001