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
This commit is contained in:
Josh Micich 2009-10-24 00:41:30 +00:00
parent db9e3cd754
commit 46441487c7
5 changed files with 113 additions and 5 deletions

View File

@ -33,6 +33,7 @@
<changes>
<release version="3.6-beta1" date="2009-??-??">
<action dev="POI-DEVELOPERS" type="add">48044 - added implementation for CountBlank function</action>
<action dev="POI-DEVELOPERS" type="fix">48036 - added IntersectionEval to allow evaluation of the intersection formula operator</action>
<action dev="POI-DEVELOPERS" type="fix">47999 - avoid un-needed call to the JVM Garbage Collector when working on OOXML OPC Packages</action>
<action dev="POI-DEVELOPERS" type="add">47922 - added example HSMF application that converts a .msg file to text and extracts attachments</action>

View File

@ -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();

View File

@ -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
* <p>
* Syntax: COUNTBLANK ( range )
* <table border="0" cellpadding="1" cellspacing="0" summary="Parameter descriptions">
* <tr><th>range&nbsp;&nbsp;&nbsp;</th><td>is the range of cells to count blanks</td></tr>
* </table>
* </p>
*
* @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;
}
};
}

View File

@ -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");
}
}
}

Binary file not shown.