git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@829293 13f79535-47bb-0310-9956-ffa450edef68tags/REL_3_6
@@ -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> |
@@ -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(); | |||
@@ -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 </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; | |||
} | |||
}; | |||
} |
@@ -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"); | |||
} | |||
} | |||
} |