mirror of https://github.com/apache/poi.git
Patch from Josh from bug #44608 - Support for PercentPtg in the formula evaluator
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@637598 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
f3f4773f28
commit
f60c47e3b2
|
@ -36,6 +36,7 @@
|
||||||
|
|
||||||
<!-- Don't forget to update status.xml too! -->
|
<!-- Don't forget to update status.xml too! -->
|
||||||
<release version="3.1-beta1" date="2008-??-??">
|
<release version="3.1-beta1" date="2008-??-??">
|
||||||
|
<action dev="POI-DEVELOPERS" type="add">44608 - Support for PercentPtg in the formula evaluator</action>
|
||||||
<action dev="POI-DEVELOPERS" type="fix">44606 - Support calculated string values for evaluated formulas</action>
|
<action dev="POI-DEVELOPERS" type="fix">44606 - Support calculated string values for evaluated formulas</action>
|
||||||
<action dev="POI-DEVELOPERS" type="add">Add accessors to horizontal and vertical alignment in HSSFTextbox</action>
|
<action dev="POI-DEVELOPERS" type="add">Add accessors to horizontal and vertical alignment in HSSFTextbox</action>
|
||||||
<action dev="POI-DEVELOPERS" type="add">44593 - Improved handling of short DVRecords</action>
|
<action dev="POI-DEVELOPERS" type="add">44593 - Improved handling of short DVRecords</action>
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
<!-- Don't forget to update changes.xml too! -->
|
<!-- Don't forget to update changes.xml too! -->
|
||||||
<changes>
|
<changes>
|
||||||
<release version="3.1-beta1" date="2008-??-??">
|
<release version="3.1-beta1" date="2008-??-??">
|
||||||
|
<action dev="POI-DEVELOPERS" type="add">44608 - Support for PercentPtg in the formula evaluator</action>
|
||||||
<action dev="POI-DEVELOPERS" type="fix">44606 - Support calculated string values for evaluated formulas</action>
|
<action dev="POI-DEVELOPERS" type="fix">44606 - Support calculated string values for evaluated formulas</action>
|
||||||
<action dev="POI-DEVELOPERS" type="add">Add accessors to horizontal and vertical alignment in HSSFTextbox</action>
|
<action dev="POI-DEVELOPERS" type="add">Add accessors to horizontal and vertical alignment in HSSFTextbox</action>
|
||||||
<action dev="POI-DEVELOPERS" type="add">44593 - Improved handling of short DVRecords</action>
|
<action dev="POI-DEVELOPERS" type="add">44593 - Improved handling of short DVRecords</action>
|
||||||
|
|
|
@ -24,71 +24,40 @@ import java.util.Stack;
|
||||||
|
|
||||||
import org.apache.poi.hssf.model.FormulaParser;
|
import org.apache.poi.hssf.model.FormulaParser;
|
||||||
import org.apache.poi.hssf.model.Workbook;
|
import org.apache.poi.hssf.model.Workbook;
|
||||||
import org.apache.poi.hssf.record.formula.AddPtg;
|
|
||||||
import org.apache.poi.hssf.record.formula.Area3DPtg;
|
import org.apache.poi.hssf.record.formula.Area3DPtg;
|
||||||
import org.apache.poi.hssf.record.formula.AreaPtg;
|
import org.apache.poi.hssf.record.formula.AreaPtg;
|
||||||
import org.apache.poi.hssf.record.formula.AttrPtg;
|
import org.apache.poi.hssf.record.formula.AttrPtg;
|
||||||
import org.apache.poi.hssf.record.formula.BoolPtg;
|
import org.apache.poi.hssf.record.formula.BoolPtg;
|
||||||
import org.apache.poi.hssf.record.formula.ConcatPtg;
|
|
||||||
import org.apache.poi.hssf.record.formula.ControlPtg;
|
import org.apache.poi.hssf.record.formula.ControlPtg;
|
||||||
import org.apache.poi.hssf.record.formula.DividePtg;
|
|
||||||
import org.apache.poi.hssf.record.formula.EqualPtg;
|
|
||||||
import org.apache.poi.hssf.record.formula.FuncPtg;
|
|
||||||
import org.apache.poi.hssf.record.formula.FuncVarPtg;
|
|
||||||
import org.apache.poi.hssf.record.formula.GreaterEqualPtg;
|
|
||||||
import org.apache.poi.hssf.record.formula.GreaterThanPtg;
|
|
||||||
import org.apache.poi.hssf.record.formula.IntPtg;
|
import org.apache.poi.hssf.record.formula.IntPtg;
|
||||||
import org.apache.poi.hssf.record.formula.LessEqualPtg;
|
|
||||||
import org.apache.poi.hssf.record.formula.LessThanPtg;
|
|
||||||
import org.apache.poi.hssf.record.formula.MemErrPtg;
|
import org.apache.poi.hssf.record.formula.MemErrPtg;
|
||||||
import org.apache.poi.hssf.record.formula.MissingArgPtg;
|
import org.apache.poi.hssf.record.formula.MissingArgPtg;
|
||||||
import org.apache.poi.hssf.record.formula.MultiplyPtg;
|
|
||||||
import org.apache.poi.hssf.record.formula.NamePtg;
|
import org.apache.poi.hssf.record.formula.NamePtg;
|
||||||
import org.apache.poi.hssf.record.formula.NameXPtg;
|
import org.apache.poi.hssf.record.formula.NameXPtg;
|
||||||
import org.apache.poi.hssf.record.formula.NotEqualPtg;
|
|
||||||
import org.apache.poi.hssf.record.formula.NumberPtg;
|
import org.apache.poi.hssf.record.formula.NumberPtg;
|
||||||
import org.apache.poi.hssf.record.formula.OperationPtg;
|
import org.apache.poi.hssf.record.formula.OperationPtg;
|
||||||
import org.apache.poi.hssf.record.formula.ParenthesisPtg;
|
import org.apache.poi.hssf.record.formula.ParenthesisPtg;
|
||||||
import org.apache.poi.hssf.record.formula.PowerPtg;
|
|
||||||
import org.apache.poi.hssf.record.formula.Ptg;
|
import org.apache.poi.hssf.record.formula.Ptg;
|
||||||
import org.apache.poi.hssf.record.formula.Ref3DPtg;
|
import org.apache.poi.hssf.record.formula.Ref3DPtg;
|
||||||
import org.apache.poi.hssf.record.formula.ReferencePtg;
|
import org.apache.poi.hssf.record.formula.ReferencePtg;
|
||||||
import org.apache.poi.hssf.record.formula.StringPtg;
|
import org.apache.poi.hssf.record.formula.StringPtg;
|
||||||
import org.apache.poi.hssf.record.formula.SubtractPtg;
|
|
||||||
import org.apache.poi.hssf.record.formula.UnaryMinusPtg;
|
|
||||||
import org.apache.poi.hssf.record.formula.UnaryPlusPtg;
|
|
||||||
import org.apache.poi.hssf.record.formula.UnionPtg;
|
import org.apache.poi.hssf.record.formula.UnionPtg;
|
||||||
import org.apache.poi.hssf.record.formula.UnknownPtg;
|
import org.apache.poi.hssf.record.formula.UnknownPtg;
|
||||||
import org.apache.poi.hssf.record.formula.eval.AddEval;
|
|
||||||
import org.apache.poi.hssf.record.formula.eval.Area2DEval;
|
import org.apache.poi.hssf.record.formula.eval.Area2DEval;
|
||||||
import org.apache.poi.hssf.record.formula.eval.Area3DEval;
|
import org.apache.poi.hssf.record.formula.eval.Area3DEval;
|
||||||
import org.apache.poi.hssf.record.formula.eval.AreaEval;
|
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.BlankEval;
|
||||||
import org.apache.poi.hssf.record.formula.eval.BoolEval;
|
import org.apache.poi.hssf.record.formula.eval.BoolEval;
|
||||||
import org.apache.poi.hssf.record.formula.eval.ConcatEval;
|
|
||||||
import org.apache.poi.hssf.record.formula.eval.DivideEval;
|
|
||||||
import org.apache.poi.hssf.record.formula.eval.EqualEval;
|
|
||||||
import org.apache.poi.hssf.record.formula.eval.ErrorEval;
|
import org.apache.poi.hssf.record.formula.eval.ErrorEval;
|
||||||
import org.apache.poi.hssf.record.formula.eval.Eval;
|
import org.apache.poi.hssf.record.formula.eval.Eval;
|
||||||
import org.apache.poi.hssf.record.formula.eval.FuncVarEval;
|
|
||||||
import org.apache.poi.hssf.record.formula.eval.FunctionEval;
|
import org.apache.poi.hssf.record.formula.eval.FunctionEval;
|
||||||
import org.apache.poi.hssf.record.formula.eval.GreaterEqualEval;
|
|
||||||
import org.apache.poi.hssf.record.formula.eval.GreaterThanEval;
|
|
||||||
import org.apache.poi.hssf.record.formula.eval.LessEqualEval;
|
|
||||||
import org.apache.poi.hssf.record.formula.eval.LessThanEval;
|
|
||||||
import org.apache.poi.hssf.record.formula.eval.MultiplyEval;
|
|
||||||
import org.apache.poi.hssf.record.formula.eval.NameEval;
|
import org.apache.poi.hssf.record.formula.eval.NameEval;
|
||||||
import org.apache.poi.hssf.record.formula.eval.NotEqualEval;
|
|
||||||
import org.apache.poi.hssf.record.formula.eval.NumberEval;
|
import org.apache.poi.hssf.record.formula.eval.NumberEval;
|
||||||
import org.apache.poi.hssf.record.formula.eval.OperationEval;
|
import org.apache.poi.hssf.record.formula.eval.OperationEval;
|
||||||
import org.apache.poi.hssf.record.formula.eval.PowerEval;
|
|
||||||
import org.apache.poi.hssf.record.formula.eval.Ref2DEval;
|
import org.apache.poi.hssf.record.formula.eval.Ref2DEval;
|
||||||
import org.apache.poi.hssf.record.formula.eval.Ref3DEval;
|
import org.apache.poi.hssf.record.formula.eval.Ref3DEval;
|
||||||
import org.apache.poi.hssf.record.formula.eval.RefEval;
|
import org.apache.poi.hssf.record.formula.eval.RefEval;
|
||||||
import org.apache.poi.hssf.record.formula.eval.StringEval;
|
import org.apache.poi.hssf.record.formula.eval.StringEval;
|
||||||
import org.apache.poi.hssf.record.formula.eval.SubtractEval;
|
|
||||||
import org.apache.poi.hssf.record.formula.eval.UnaryMinusEval;
|
|
||||||
import org.apache.poi.hssf.record.formula.eval.UnaryPlusEval;
|
|
||||||
import org.apache.poi.hssf.record.formula.eval.ValueEval;
|
import org.apache.poi.hssf.record.formula.eval.ValueEval;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -98,8 +67,6 @@ import org.apache.poi.hssf.record.formula.eval.ValueEval;
|
||||||
public class HSSFFormulaEvaluator {
|
public class HSSFFormulaEvaluator {
|
||||||
|
|
||||||
// params to lookup the right constructor using reflection
|
// params to lookup the right constructor using reflection
|
||||||
private static final Class[] OPERATION_CONSTRUCTOR_CLASS_ARRAY = new Class[] { Ptg.class };
|
|
||||||
|
|
||||||
private static final Class[] VALUE_CONTRUCTOR_CLASS_ARRAY = new Class[] { Ptg.class };
|
private static final Class[] VALUE_CONTRUCTOR_CLASS_ARRAY = new Class[] { Ptg.class };
|
||||||
|
|
||||||
private static final Class[] AREA3D_CONSTRUCTOR_CLASS_ARRAY = new Class[] { Ptg.class, ValueEval[].class };
|
private static final Class[] AREA3D_CONSTRUCTOR_CLASS_ARRAY = new Class[] { Ptg.class, ValueEval[].class };
|
||||||
|
@ -111,8 +78,6 @@ public class HSSFFormulaEvaluator {
|
||||||
// Maps for mapping *Eval to *Ptg
|
// Maps for mapping *Eval to *Ptg
|
||||||
private static final Map VALUE_EVALS_MAP = new HashMap();
|
private static final Map VALUE_EVALS_MAP = new HashMap();
|
||||||
|
|
||||||
private static final Map OPERATION_EVALS_MAP = new HashMap();
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Following is the mapping between the Ptg tokens returned
|
* Following is the mapping between the Ptg tokens returned
|
||||||
* by the FormulaParser and the *Eval classes that are used
|
* by the FormulaParser and the *Eval classes that are used
|
||||||
|
@ -124,26 +89,6 @@ public class HSSFFormulaEvaluator {
|
||||||
VALUE_EVALS_MAP.put(NumberPtg.class, NumberEval.class);
|
VALUE_EVALS_MAP.put(NumberPtg.class, NumberEval.class);
|
||||||
VALUE_EVALS_MAP.put(StringPtg.class, StringEval.class);
|
VALUE_EVALS_MAP.put(StringPtg.class, StringEval.class);
|
||||||
|
|
||||||
OPERATION_EVALS_MAP.put(AddPtg.class, AddEval.class);
|
|
||||||
OPERATION_EVALS_MAP.put(ConcatPtg.class, ConcatEval.class);
|
|
||||||
OPERATION_EVALS_MAP.put(DividePtg.class, DivideEval.class);
|
|
||||||
OPERATION_EVALS_MAP.put(EqualPtg.class, EqualEval.class);
|
|
||||||
//OPERATION_EVALS_MAP.put(ExpPtg.class, ExpEval.class); // TODO: check
|
|
||||||
// this
|
|
||||||
OPERATION_EVALS_MAP.put(FuncPtg.class, FuncVarEval.class); // TODO:
|
|
||||||
// check this
|
|
||||||
OPERATION_EVALS_MAP.put(FuncVarPtg.class, FuncVarEval.class);
|
|
||||||
OPERATION_EVALS_MAP.put(GreaterEqualPtg.class, GreaterEqualEval.class);
|
|
||||||
OPERATION_EVALS_MAP.put(GreaterThanPtg.class, GreaterThanEval.class);
|
|
||||||
OPERATION_EVALS_MAP.put(LessEqualPtg.class, LessEqualEval.class);
|
|
||||||
OPERATION_EVALS_MAP.put(LessThanPtg.class, LessThanEval.class);
|
|
||||||
OPERATION_EVALS_MAP.put(MultiplyPtg.class, MultiplyEval.class);
|
|
||||||
OPERATION_EVALS_MAP.put(NotEqualPtg.class, NotEqualEval.class);
|
|
||||||
OPERATION_EVALS_MAP.put(PowerPtg.class, PowerEval.class);
|
|
||||||
OPERATION_EVALS_MAP.put(SubtractPtg.class, SubtractEval.class);
|
|
||||||
OPERATION_EVALS_MAP.put(UnaryMinusPtg.class, UnaryMinusEval.class);
|
|
||||||
OPERATION_EVALS_MAP.put(UnaryPlusPtg.class, UnaryPlusEval.class);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -402,7 +347,7 @@ public class HSSFFormulaEvaluator {
|
||||||
if (optg instanceof AttrPtg) { continue; }
|
if (optg instanceof AttrPtg) { continue; }
|
||||||
if (optg instanceof UnionPtg) { continue; }
|
if (optg instanceof UnionPtg) { continue; }
|
||||||
|
|
||||||
OperationEval operation = (OperationEval) getOperationEvalForPtg(optg);
|
OperationEval operation = OperationEvaluatorFactory.create(optg);
|
||||||
|
|
||||||
int numops = operation.getNumberOfOperands();
|
int numops = operation.getNumberOfOperands();
|
||||||
Eval[] ops = new Eval[numops];
|
Eval[] ops = new Eval[numops];
|
||||||
|
@ -557,25 +502,6 @@ public class HSSFFormulaEvaluator {
|
||||||
return values;
|
return values;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* returns the OperationEval concrete impl instance corresponding
|
|
||||||
* to the suplied operationPtg
|
|
||||||
* @param ptg
|
|
||||||
*/
|
|
||||||
protected static Eval getOperationEvalForPtg(OperationPtg ptg) {
|
|
||||||
Eval retval = null;
|
|
||||||
|
|
||||||
Class clazz = (Class) OPERATION_EVALS_MAP.get(ptg.getClass());
|
|
||||||
try {
|
|
||||||
Constructor constructor = clazz.getConstructor(OPERATION_CONSTRUCTOR_CLASS_ARRAY);
|
|
||||||
retval = (OperationEval) constructor.newInstance(new Ptg[] { ptg });
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
throw new RuntimeException("Fatal Error: ", e);
|
|
||||||
}
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* returns an appropriate Eval impl instance for the Ptg. The Ptg must be
|
* returns an appropriate Eval impl instance for the Ptg. The Ptg must be
|
||||||
* one of: Area3DPtg, AreaPtg, ReferencePtg, Ref3DPtg, IntPtg, NumberPtg,
|
* one of: Area3DPtg, AreaPtg, ReferencePtg, Ref3DPtg, IntPtg, NumberPtg,
|
||||||
|
|
|
@ -0,0 +1,165 @@
|
||||||
|
/* ====================================================================
|
||||||
|
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.usermodel;
|
||||||
|
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.poi.hssf.record.formula.AddPtg;
|
||||||
|
import org.apache.poi.hssf.record.formula.ConcatPtg;
|
||||||
|
import org.apache.poi.hssf.record.formula.DividePtg;
|
||||||
|
import org.apache.poi.hssf.record.formula.EqualPtg;
|
||||||
|
import org.apache.poi.hssf.record.formula.ExpPtg;
|
||||||
|
import org.apache.poi.hssf.record.formula.FuncPtg;
|
||||||
|
import org.apache.poi.hssf.record.formula.FuncVarPtg;
|
||||||
|
import org.apache.poi.hssf.record.formula.GreaterEqualPtg;
|
||||||
|
import org.apache.poi.hssf.record.formula.GreaterThanPtg;
|
||||||
|
import org.apache.poi.hssf.record.formula.LessEqualPtg;
|
||||||
|
import org.apache.poi.hssf.record.formula.LessThanPtg;
|
||||||
|
import org.apache.poi.hssf.record.formula.MultiplyPtg;
|
||||||
|
import org.apache.poi.hssf.record.formula.NotEqualPtg;
|
||||||
|
import org.apache.poi.hssf.record.formula.OperationPtg;
|
||||||
|
import org.apache.poi.hssf.record.formula.PercentPtg;
|
||||||
|
import org.apache.poi.hssf.record.formula.PowerPtg;
|
||||||
|
import org.apache.poi.hssf.record.formula.Ptg;
|
||||||
|
import org.apache.poi.hssf.record.formula.SubtractPtg;
|
||||||
|
import org.apache.poi.hssf.record.formula.UnaryMinusPtg;
|
||||||
|
import org.apache.poi.hssf.record.formula.UnaryPlusPtg;
|
||||||
|
import org.apache.poi.hssf.record.formula.eval.AddEval;
|
||||||
|
import org.apache.poi.hssf.record.formula.eval.ConcatEval;
|
||||||
|
import org.apache.poi.hssf.record.formula.eval.DivideEval;
|
||||||
|
import org.apache.poi.hssf.record.formula.eval.EqualEval;
|
||||||
|
import org.apache.poi.hssf.record.formula.eval.FuncVarEval;
|
||||||
|
import org.apache.poi.hssf.record.formula.eval.GreaterEqualEval;
|
||||||
|
import org.apache.poi.hssf.record.formula.eval.GreaterThanEval;
|
||||||
|
import org.apache.poi.hssf.record.formula.eval.LessEqualEval;
|
||||||
|
import org.apache.poi.hssf.record.formula.eval.LessThanEval;
|
||||||
|
import org.apache.poi.hssf.record.formula.eval.MultiplyEval;
|
||||||
|
import org.apache.poi.hssf.record.formula.eval.NotEqualEval;
|
||||||
|
import org.apache.poi.hssf.record.formula.eval.OperationEval;
|
||||||
|
import org.apache.poi.hssf.record.formula.eval.PercentEval;
|
||||||
|
import org.apache.poi.hssf.record.formula.eval.PowerEval;
|
||||||
|
import org.apache.poi.hssf.record.formula.eval.SubtractEval;
|
||||||
|
import org.apache.poi.hssf.record.formula.eval.UnaryMinusEval;
|
||||||
|
import org.apache.poi.hssf.record.formula.eval.UnaryPlusEval;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class creates <tt>OperationEval</tt> instances to help evaluate <tt>OperationPtg</tt>
|
||||||
|
* formula tokens.
|
||||||
|
*
|
||||||
|
* @author Josh Micich
|
||||||
|
*/
|
||||||
|
final class OperationEvaluatorFactory {
|
||||||
|
private static final Class[] OPERATION_CONSTRUCTOR_CLASS_ARRAY = new Class[] { Ptg.class };
|
||||||
|
|
||||||
|
private static final Map _constructorsByPtgClass = initialiseConstructorsMap();
|
||||||
|
|
||||||
|
private OperationEvaluatorFactory() {
|
||||||
|
// no instances of this class
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Map initialiseConstructorsMap() {
|
||||||
|
Map m = new HashMap(32);
|
||||||
|
add(m, AddPtg.class, AddEval.class);
|
||||||
|
add(m, ConcatPtg.class, ConcatEval.class);
|
||||||
|
add(m, DividePtg.class, DivideEval.class);
|
||||||
|
add(m, EqualPtg.class, EqualEval.class);
|
||||||
|
add(m, FuncPtg.class, FuncVarEval.class);
|
||||||
|
add(m, FuncVarPtg.class, FuncVarEval.class);
|
||||||
|
add(m, GreaterEqualPtg.class, GreaterEqualEval.class);
|
||||||
|
add(m, GreaterThanPtg.class, GreaterThanEval.class);
|
||||||
|
add(m, LessEqualPtg.class, LessEqualEval.class);
|
||||||
|
add(m, LessThanPtg.class, LessThanEval.class);
|
||||||
|
add(m, MultiplyPtg.class, MultiplyEval.class);
|
||||||
|
add(m, NotEqualPtg.class, NotEqualEval.class);
|
||||||
|
add(m, PercentPtg.class, PercentEval.class);
|
||||||
|
add(m, PowerPtg.class, PowerEval.class);
|
||||||
|
add(m, SubtractPtg.class, SubtractEval.class);
|
||||||
|
add(m, UnaryMinusPtg.class, UnaryMinusEval.class);
|
||||||
|
add(m, UnaryPlusPtg.class, UnaryPlusEval.class);
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void add(Map m, Class ptgClass, Class evalClass) {
|
||||||
|
|
||||||
|
// perform some validation now, to keep later exception handlers simple
|
||||||
|
if(!Ptg.class.isAssignableFrom(ptgClass)) {
|
||||||
|
throw new IllegalArgumentException("Expected Ptg subclass");
|
||||||
|
}
|
||||||
|
if(!OperationEval.class.isAssignableFrom(evalClass)) {
|
||||||
|
throw new IllegalArgumentException("Expected OperationEval subclass");
|
||||||
|
}
|
||||||
|
if (!Modifier.isPublic(evalClass.getModifiers())) {
|
||||||
|
throw new RuntimeException("Eval class must be public");
|
||||||
|
}
|
||||||
|
if (Modifier.isAbstract(evalClass.getModifiers())) {
|
||||||
|
throw new RuntimeException("Eval class must not be abstract");
|
||||||
|
}
|
||||||
|
|
||||||
|
Constructor constructor;
|
||||||
|
try {
|
||||||
|
constructor = evalClass.getDeclaredConstructor(OPERATION_CONSTRUCTOR_CLASS_ARRAY);
|
||||||
|
} catch (NoSuchMethodException e) {
|
||||||
|
throw new RuntimeException("Missing constructor");
|
||||||
|
}
|
||||||
|
if (!Modifier.isPublic(constructor.getModifiers())) {
|
||||||
|
throw new RuntimeException("Eval constructor must be public");
|
||||||
|
}
|
||||||
|
m.put(ptgClass, constructor);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the OperationEval concrete impl instance corresponding
|
||||||
|
* to the supplied operationPtg
|
||||||
|
*/
|
||||||
|
public static OperationEval create(OperationPtg ptg) {
|
||||||
|
if(ptg == null) {
|
||||||
|
throw new IllegalArgumentException("ptg must not be null");
|
||||||
|
}
|
||||||
|
|
||||||
|
Class ptgClass = ptg.getClass();
|
||||||
|
|
||||||
|
Constructor constructor = (Constructor) _constructorsByPtgClass.get(ptgClass);
|
||||||
|
if(constructor == null) {
|
||||||
|
if(ptgClass == ExpPtg.class) {
|
||||||
|
// ExpPtg is used for array formulas and shared formulas.
|
||||||
|
// it is currently unsupported, and may not even get implemented here
|
||||||
|
throw new RuntimeException("ExpPtg currently not supported");
|
||||||
|
}
|
||||||
|
throw new RuntimeException("Unexpected operation ptg class (" + ptgClass.getName() + ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
Object result;
|
||||||
|
Object[] initargs = { ptg };
|
||||||
|
try {
|
||||||
|
result = constructor.newInstance(initargs);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} catch (InstantiationException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} catch (InvocationTargetException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
return (OperationEval) result;
|
||||||
|
}
|
||||||
|
}
|
|
@ -33,6 +33,7 @@ public class AllFormulaEvalTests {
|
||||||
result.addTestSuite(TestExternalFunction.class);
|
result.addTestSuite(TestExternalFunction.class);
|
||||||
result.addTestSuite(TestFormulaBugs.class);
|
result.addTestSuite(TestFormulaBugs.class);
|
||||||
result.addTestSuite(TestFormulasFromSpreadsheet.class);
|
result.addTestSuite(TestFormulasFromSpreadsheet.class);
|
||||||
|
result.addTestSuite(TestPercentEval.class);
|
||||||
result.addTestSuite(TestUnaryPlusEval.class);
|
result.addTestSuite(TestUnaryPlusEval.class);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
package org.apache.poi.hssf.record.formula.eval;
|
package org.apache.poi.hssf.record.formula.eval;
|
||||||
|
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
|
@ -59,36 +58,36 @@ public final class TestFormulasFromSpreadsheet extends TestCase {
|
||||||
* Name of the test spreadsheet (found in the standard test data folder)
|
* Name of the test spreadsheet (found in the standard test data folder)
|
||||||
*/
|
*/
|
||||||
public final static String FILENAME = "FormulaEvalTestData.xls";
|
public final static String FILENAME = "FormulaEvalTestData.xls";
|
||||||
/**
|
/**
|
||||||
* Row (zero-based) in the test spreadsheet where the operator examples start.
|
* Row (zero-based) in the test spreadsheet where the operator examples start.
|
||||||
*/
|
*/
|
||||||
public static final int START_OPERATORS_ROW_INDEX = 22; // Row '23'
|
public static final int START_OPERATORS_ROW_INDEX = 22; // Row '23'
|
||||||
/**
|
/**
|
||||||
* Row (zero-based) in the test spreadsheet where the function examples start.
|
* Row (zero-based) in the test spreadsheet where the function examples start.
|
||||||
*/
|
*/
|
||||||
public static final int START_FUNCTIONS_ROW_INDEX = 83; // Row '84'
|
public static final int START_FUNCTIONS_ROW_INDEX = 87; // Row '88'
|
||||||
/**
|
/**
|
||||||
* Index of the column that contains the function names
|
* Index of the column that contains the function names
|
||||||
*/
|
*/
|
||||||
public static final short COLUMN_INDEX_FUNCTION_NAME = 1; // Column 'B'
|
public static final short COLUMN_INDEX_FUNCTION_NAME = 1; // Column 'B'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to indicate when there are no more functions left
|
* Used to indicate when there are no more functions left
|
||||||
*/
|
*/
|
||||||
public static final String FUNCTION_NAMES_END_SENTINEL = "<END-OF-FUNCTIONS>";
|
public static final String FUNCTION_NAMES_END_SENTINEL = "<END-OF-FUNCTIONS>";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Index of the column where the test values start (for each function)
|
* Index of the column where the test values start (for each function)
|
||||||
*/
|
*/
|
||||||
public static final short COLUMN_INDEX_FIRST_TEST_VALUE = 3; // Column 'D'
|
public static final short COLUMN_INDEX_FIRST_TEST_VALUE = 3; // Column 'D'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Each function takes 4 rows in the test spreadsheet
|
* Each function takes 4 rows in the test spreadsheet
|
||||||
*/
|
*/
|
||||||
public static final int NUMBER_OF_ROWS_PER_FUNCTION = 4;
|
public static final int NUMBER_OF_ROWS_PER_FUNCTION = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
private HSSFWorkbook workbook;
|
private HSSFWorkbook workbook;
|
||||||
private HSSFSheet sheet;
|
private HSSFSheet sheet;
|
||||||
// Note - multiple failures are aggregated before ending.
|
// Note - multiple failures are aggregated before ending.
|
||||||
// If one or more functions fail, a single AssertionFailedError is thrown at the end
|
// If one or more functions fail, a single AssertionFailedError is thrown at the end
|
||||||
|
@ -97,138 +96,138 @@ public final class TestFormulasFromSpreadsheet extends TestCase {
|
||||||
private int _evaluationFailureCount;
|
private int _evaluationFailureCount;
|
||||||
private int _evaluationSuccessCount;
|
private int _evaluationSuccessCount;
|
||||||
|
|
||||||
private static final HSSFCell getExpectedValueCell(HSSFRow row, short columnIndex) {
|
private static final HSSFCell getExpectedValueCell(HSSFRow row, short columnIndex) {
|
||||||
if (row == null) {
|
if (row == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return row.getCell(columnIndex);
|
return row.getCell(columnIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static void confirmExpectedResult(String msg, HSSFCell expected, HSSFFormulaEvaluator.CellValue actual) {
|
private static void confirmExpectedResult(String msg, HSSFCell expected, HSSFFormulaEvaluator.CellValue actual) {
|
||||||
if (expected == null) {
|
if (expected == null) {
|
||||||
throw new AssertionFailedError(msg + " - Bad setup data expected value is null");
|
throw new AssertionFailedError(msg + " - Bad setup data expected value is null");
|
||||||
}
|
}
|
||||||
if(actual == null) {
|
if(actual == null) {
|
||||||
throw new AssertionFailedError(msg + " - actual value was null");
|
throw new AssertionFailedError(msg + " - actual value was null");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (expected.getCellType() == HSSFCell.CELL_TYPE_STRING) {
|
if (expected.getCellType() == HSSFCell.CELL_TYPE_STRING) {
|
||||||
String value = expected.getRichStringCellValue().getString();
|
String value = expected.getRichStringCellValue().getString();
|
||||||
if (value.startsWith("#")) {
|
if (value.startsWith("#")) {
|
||||||
// TODO - this code never called
|
// TODO - this code never called
|
||||||
expected.setCellType(HSSFCell.CELL_TYPE_ERROR);
|
expected.setCellType(HSSFCell.CELL_TYPE_ERROR);
|
||||||
// expected.setCellErrorValue(...?);
|
// expected.setCellErrorValue(...?);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (expected.getCellType()) {
|
switch (expected.getCellType()) {
|
||||||
case HSSFCell.CELL_TYPE_BLANK:
|
case HSSFCell.CELL_TYPE_BLANK:
|
||||||
assertEquals(msg, HSSFCell.CELL_TYPE_BLANK, actual.getCellType());
|
assertEquals(msg, HSSFCell.CELL_TYPE_BLANK, actual.getCellType());
|
||||||
break;
|
break;
|
||||||
case HSSFCell.CELL_TYPE_BOOLEAN:
|
case HSSFCell.CELL_TYPE_BOOLEAN:
|
||||||
assertEquals(msg, HSSFCell.CELL_TYPE_BOOLEAN, actual.getCellType());
|
assertEquals(msg, HSSFCell.CELL_TYPE_BOOLEAN, actual.getCellType());
|
||||||
assertEquals(msg, expected.getBooleanCellValue(), actual.getBooleanValue());
|
assertEquals(msg, expected.getBooleanCellValue(), actual.getBooleanValue());
|
||||||
break;
|
break;
|
||||||
case HSSFCell.CELL_TYPE_ERROR:
|
case HSSFCell.CELL_TYPE_ERROR:
|
||||||
assertEquals(msg, HSSFCell.CELL_TYPE_ERROR, actual.getCellType());
|
assertEquals(msg, HSSFCell.CELL_TYPE_ERROR, actual.getCellType());
|
||||||
if(false) { // TODO: fix ~45 functions which are currently returning incorrect error values
|
if(false) { // TODO: fix ~45 functions which are currently returning incorrect error values
|
||||||
assertEquals(msg, expected.getErrorCellValue(), actual.getErrorValue());
|
assertEquals(msg, expected.getErrorCellValue(), actual.getErrorValue());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case HSSFCell.CELL_TYPE_FORMULA: // will never be used, since we will call method after formula evaluation
|
case HSSFCell.CELL_TYPE_FORMULA: // will never be used, since we will call method after formula evaluation
|
||||||
throw new AssertionFailedError("Cannot expect formula as result of formula evaluation: " + msg);
|
throw new AssertionFailedError("Cannot expect formula as result of formula evaluation: " + msg);
|
||||||
case HSSFCell.CELL_TYPE_NUMERIC:
|
case HSSFCell.CELL_TYPE_NUMERIC:
|
||||||
assertEquals(msg, HSSFCell.CELL_TYPE_NUMERIC, actual.getCellType());
|
assertEquals(msg, HSSFCell.CELL_TYPE_NUMERIC, actual.getCellType());
|
||||||
TestMathX.assertEquals(msg, expected.getNumericCellValue(), actual.getNumberValue(), TestMathX.POS_ZERO, TestMathX.DIFF_TOLERANCE_FACTOR);
|
TestMathX.assertEquals(msg, expected.getNumericCellValue(), actual.getNumberValue(), TestMathX.POS_ZERO, TestMathX.DIFF_TOLERANCE_FACTOR);
|
||||||
// double delta = Math.abs(expected.getNumericCellValue()-actual.getNumberValue());
|
// double delta = Math.abs(expected.getNumericCellValue()-actual.getNumberValue());
|
||||||
// double pctExpected = Math.abs(0.00001*expected.getNumericCellValue());
|
// double pctExpected = Math.abs(0.00001*expected.getNumericCellValue());
|
||||||
// assertTrue(msg, delta <= pctExpected);
|
// assertTrue(msg, delta <= pctExpected);
|
||||||
break;
|
break;
|
||||||
case HSSFCell.CELL_TYPE_STRING:
|
case HSSFCell.CELL_TYPE_STRING:
|
||||||
assertEquals(msg, HSSFCell.CELL_TYPE_STRING, actual.getCellType());
|
assertEquals(msg, HSSFCell.CELL_TYPE_STRING, actual.getCellType());
|
||||||
assertEquals(msg, expected.getRichStringCellValue().getString(), actual.getRichTextStringValue().getString());
|
assertEquals(msg, expected.getRichStringCellValue().getString(), actual.getRichTextStringValue().getString());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected void setUp() throws Exception {
|
protected void setUp() throws Exception {
|
||||||
if (workbook == null) {
|
if (workbook == null) {
|
||||||
String filePath = System.getProperty("HSSF.testdata.path")+ "/" + SS.FILENAME;
|
String filePath = System.getProperty("HSSF.testdata.path")+ "/" + SS.FILENAME;
|
||||||
FileInputStream fin = new FileInputStream( filePath );
|
FileInputStream fin = new FileInputStream( filePath );
|
||||||
workbook = new HSSFWorkbook( fin );
|
workbook = new HSSFWorkbook( fin );
|
||||||
sheet = workbook.getSheetAt( 0 );
|
sheet = workbook.getSheetAt( 0 );
|
||||||
}
|
}
|
||||||
_functionFailureCount = 0;
|
_functionFailureCount = 0;
|
||||||
_functionSuccessCount = 0;
|
_functionSuccessCount = 0;
|
||||||
_evaluationFailureCount = 0;
|
_evaluationFailureCount = 0;
|
||||||
_evaluationSuccessCount = 0;
|
_evaluationSuccessCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testFunctionsFromTestSpreadsheet() {
|
public void testFunctionsFromTestSpreadsheet() {
|
||||||
|
|
||||||
processFunctionGroup(SS.START_OPERATORS_ROW_INDEX, null);
|
processFunctionGroup(SS.START_OPERATORS_ROW_INDEX, null);
|
||||||
processFunctionGroup(SS.START_FUNCTIONS_ROW_INDEX, null);
|
processFunctionGroup(SS.START_FUNCTIONS_ROW_INDEX, null);
|
||||||
// example for debugging individual functions/operators:
|
// example for debugging individual functions/operators:
|
||||||
// processFunctionGroup(SS.START_OPERATORS_ROW_INDEX, "ConcatEval");
|
// processFunctionGroup(SS.START_OPERATORS_ROW_INDEX, "ConcatEval");
|
||||||
// processFunctionGroup(SS.START_FUNCTIONS_ROW_INDEX, "AVERAGE");
|
// processFunctionGroup(SS.START_FUNCTIONS_ROW_INDEX, "AVERAGE");
|
||||||
|
|
||||||
// confirm results
|
// confirm results
|
||||||
String successMsg = "There were "
|
String successMsg = "There were "
|
||||||
+ _evaluationSuccessCount + " successful evaluation(s) and "
|
+ _evaluationSuccessCount + " successful evaluation(s) and "
|
||||||
+ _functionSuccessCount + " function(s) without error";
|
+ _functionSuccessCount + " function(s) without error";
|
||||||
if(_functionFailureCount > 0) {
|
if(_functionFailureCount > 0) {
|
||||||
String msg = _functionFailureCount + " function(s) failed in "
|
String msg = _functionFailureCount + " function(s) failed in "
|
||||||
+ _evaluationFailureCount + " evaluation(s). " + successMsg;
|
+ _evaluationFailureCount + " evaluation(s). " + successMsg;
|
||||||
throw new AssertionFailedError(msg);
|
throw new AssertionFailedError(msg);
|
||||||
}
|
}
|
||||||
if(false) { // normally no output for successful tests
|
if(false) { // normally no output for successful tests
|
||||||
System.out.println(getClass().getName() + ": " + successMsg);
|
System.out.println(getClass().getName() + ": " + successMsg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param startRowIndex row index in the spreadsheet where the first function/operator is found
|
* @param startRowIndex row index in the spreadsheet where the first function/operator is found
|
||||||
* @param testFocusFunctionName name of a single function/operator to test alone.
|
* @param testFocusFunctionName name of a single function/operator to test alone.
|
||||||
* Typically pass <code>null</code> to test all functions
|
* Typically pass <code>null</code> to test all functions
|
||||||
*/
|
*/
|
||||||
private void processFunctionGroup(int startRowIndex, String testFocusFunctionName) {
|
private void processFunctionGroup(int startRowIndex, String testFocusFunctionName) {
|
||||||
|
|
||||||
HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(sheet, workbook);
|
HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(sheet, workbook);
|
||||||
|
|
||||||
int rowIndex = startRowIndex;
|
int rowIndex = startRowIndex;
|
||||||
while (true) {
|
while (true) {
|
||||||
HSSFRow r = sheet.getRow(rowIndex);
|
HSSFRow r = sheet.getRow(rowIndex);
|
||||||
String targetFunctionName = getTargetFunctionName(r);
|
String targetFunctionName = getTargetFunctionName(r);
|
||||||
if(targetFunctionName == null) {
|
if(targetFunctionName == null) {
|
||||||
throw new AssertionFailedError("Test spreadsheet cell empty on row ("
|
throw new AssertionFailedError("Test spreadsheet cell empty on row ("
|
||||||
+ (rowIndex+1) + "). Expected function name or '"
|
+ (rowIndex+1) + "). Expected function name or '"
|
||||||
+ SS.FUNCTION_NAMES_END_SENTINEL + "'");
|
+ SS.FUNCTION_NAMES_END_SENTINEL + "'");
|
||||||
}
|
}
|
||||||
if(targetFunctionName.equals(SS.FUNCTION_NAMES_END_SENTINEL)) {
|
if(targetFunctionName.equals(SS.FUNCTION_NAMES_END_SENTINEL)) {
|
||||||
// found end of functions list
|
// found end of functions list
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(testFocusFunctionName == null || targetFunctionName.equalsIgnoreCase(testFocusFunctionName)) {
|
if(testFocusFunctionName == null || targetFunctionName.equalsIgnoreCase(testFocusFunctionName)) {
|
||||||
|
|
||||||
// expected results are on the row below
|
// expected results are on the row below
|
||||||
HSSFRow expectedValuesRow = sheet.getRow(rowIndex + 1);
|
HSSFRow expectedValuesRow = sheet.getRow(rowIndex + 1);
|
||||||
if(expectedValuesRow == null) {
|
if(expectedValuesRow == null) {
|
||||||
int missingRowNum = rowIndex + 2; //+1 for 1-based, +1 for next row
|
int missingRowNum = rowIndex + 2; //+1 for 1-based, +1 for next row
|
||||||
throw new AssertionFailedError("Missing expected values row for function '"
|
throw new AssertionFailedError("Missing expected values row for function '"
|
||||||
+ targetFunctionName + " (row " + missingRowNum + ")");
|
+ targetFunctionName + " (row " + missingRowNum + ")");
|
||||||
}
|
}
|
||||||
switch(processFunctionRow(evaluator, targetFunctionName, r, expectedValuesRow)) {
|
switch(processFunctionRow(evaluator, targetFunctionName, r, expectedValuesRow)) {
|
||||||
case Result.ALL_EVALUATIONS_SUCCEEDED: _functionSuccessCount++; break;
|
case Result.ALL_EVALUATIONS_SUCCEEDED: _functionSuccessCount++; break;
|
||||||
case Result.SOME_EVALUATIONS_FAILED: _functionFailureCount++; break;
|
case Result.SOME_EVALUATIONS_FAILED: _functionFailureCount++; break;
|
||||||
default:
|
default:
|
||||||
throw new RuntimeException("unexpected result");
|
throw new RuntimeException("unexpected result");
|
||||||
case Result.NO_EVALUATIONS_FOUND: // do nothing
|
case Result.NO_EVALUATIONS_FOUND: // do nothing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rowIndex += SS.NUMBER_OF_ROWS_PER_FUNCTION;
|
rowIndex += SS.NUMBER_OF_ROWS_PER_FUNCTION;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -236,16 +235,16 @@ public final class TestFormulasFromSpreadsheet extends TestCase {
|
||||||
* @return a constant from the local Result class denoting whether there were any evaluation
|
* @return a constant from the local Result class denoting whether there were any evaluation
|
||||||
* cases, and whether they all succeeded.
|
* cases, and whether they all succeeded.
|
||||||
*/
|
*/
|
||||||
private int processFunctionRow(HSSFFormulaEvaluator evaluator, String targetFunctionName,
|
private int processFunctionRow(HSSFFormulaEvaluator evaluator, String targetFunctionName,
|
||||||
HSSFRow formulasRow, HSSFRow expectedValuesRow) {
|
HSSFRow formulasRow, HSSFRow expectedValuesRow) {
|
||||||
|
|
||||||
int result = Result.NO_EVALUATIONS_FOUND; // so far
|
int result = Result.NO_EVALUATIONS_FOUND; // so far
|
||||||
short endcolnum = formulasRow.getLastCellNum();
|
short endcolnum = formulasRow.getLastCellNum();
|
||||||
evaluator.setCurrentRow(formulasRow);
|
evaluator.setCurrentRow(formulasRow);
|
||||||
|
|
||||||
// iterate across the row for all the evaluation cases
|
// iterate across the row for all the evaluation cases
|
||||||
for (short colnum=SS.COLUMN_INDEX_FIRST_TEST_VALUE; colnum < endcolnum; colnum++) {
|
for (short colnum=SS.COLUMN_INDEX_FIRST_TEST_VALUE; colnum < endcolnum; colnum++) {
|
||||||
HSSFCell c = formulasRow.getCell(colnum);
|
HSSFCell c = formulasRow.getCell(colnum);
|
||||||
if (c == null || c.getCellType() != HSSFCell.CELL_TYPE_FORMULA) {
|
if (c == null || c.getCellType() != HSSFCell.CELL_TYPE_FORMULA) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -265,13 +264,13 @@ public final class TestFormulasFromSpreadsheet extends TestCase {
|
||||||
printShortStackTrace(System.err, e);
|
printShortStackTrace(System.err, e);
|
||||||
result = Result.SOME_EVALUATIONS_FAILED;
|
result = Result.SOME_EVALUATIONS_FAILED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Useful to keep output concise when expecting many failures to be reported by this test case
|
* Useful to keep output concise when expecting many failures to be reported by this test case
|
||||||
*/
|
*/
|
||||||
private static void printShortStackTrace(PrintStream ps, AssertionFailedError e) {
|
private static void printShortStackTrace(PrintStream ps, AssertionFailedError e) {
|
||||||
StackTraceElement[] stes = e.getStackTrace();
|
StackTraceElement[] stes = e.getStackTrace();
|
||||||
|
|
||||||
|
@ -304,8 +303,8 @@ public final class TestFormulasFromSpreadsheet extends TestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return <code>null</code> if cell is missing, empty or blank
|
* @return <code>null</code> if cell is missing, empty or blank
|
||||||
*/
|
*/
|
||||||
private static String getTargetFunctionName(HSSFRow r) {
|
private static String getTargetFunctionName(HSSFRow r) {
|
||||||
if(r == null) {
|
if(r == null) {
|
||||||
System.err.println("Warning - given null row, can't figure out function name");
|
System.err.println("Warning - given null row, can't figure out function name");
|
||||||
|
|
|
@ -0,0 +1,82 @@
|
||||||
|
/* ====================================================================
|
||||||
|
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.eval;
|
||||||
|
|
||||||
|
import junit.framework.AssertionFailedError;
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
import org.apache.poi.hssf.record.formula.PercentPtg;
|
||||||
|
import org.apache.poi.hssf.record.formula.functions.NumericFunctionInvoker;
|
||||||
|
import org.apache.poi.hssf.usermodel.HSSFCell;
|
||||||
|
import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
|
||||||
|
import org.apache.poi.hssf.usermodel.HSSFRow;
|
||||||
|
import org.apache.poi.hssf.usermodel.HSSFSheet;
|
||||||
|
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||||
|
import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator.CellValue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test for percent operator evaluator.
|
||||||
|
*
|
||||||
|
* @author Josh Micich
|
||||||
|
*/
|
||||||
|
public final class TestPercentEval extends TestCase {
|
||||||
|
|
||||||
|
private static void confirm(ValueEval arg, double expectedResult) {
|
||||||
|
Eval[] args = {
|
||||||
|
arg,
|
||||||
|
};
|
||||||
|
|
||||||
|
PercentEval opEval = new PercentEval(new PercentPtg());
|
||||||
|
double result = NumericFunctionInvoker.invoke(opEval, args, -1, (short)-1);
|
||||||
|
|
||||||
|
assertEquals(expectedResult, result, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testBasic() {
|
||||||
|
confirm(new NumberEval(5), 0.05);
|
||||||
|
confirm(new NumberEval(3000), 30.0);
|
||||||
|
confirm(new NumberEval(-150), -1.5);
|
||||||
|
confirm(new StringEval("0.2"), 0.002);
|
||||||
|
confirm(BoolEval.TRUE, 0.01);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testInSpreadSheet() {
|
||||||
|
HSSFWorkbook wb = new HSSFWorkbook();
|
||||||
|
HSSFSheet sheet = wb.createSheet("Sheet1");
|
||||||
|
HSSFRow row = sheet.createRow(0);
|
||||||
|
HSSFCell cell = row.createCell((short)0);
|
||||||
|
cell.setCellFormula("B1%");
|
||||||
|
row.createCell((short)1).setCellValue(50.0);
|
||||||
|
|
||||||
|
HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(sheet, wb);
|
||||||
|
fe.setCurrentRow(row);
|
||||||
|
CellValue cv;
|
||||||
|
try {
|
||||||
|
cv = fe.evaluate(cell);
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
if(e.getCause() instanceof NullPointerException) {
|
||||||
|
throw new AssertionFailedError("Identified bug 44608");
|
||||||
|
}
|
||||||
|
// else some other unexpected error
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
assertEquals(HSSFCell.CELL_TYPE_NUMERIC, cv.getCellType());
|
||||||
|
assertEquals(0.5, cv.getNumberValue(), 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Binary file not shown.
Loading…
Reference in New Issue