Fixed 2 small bugs in RelationalOperationEval (added junits). Refactored hierarchy.

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@692239 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Josh Micich 2008-09-04 20:58:37 +00:00
parent 409941a8be
commit bd997b1376
13 changed files with 451 additions and 583 deletions

View File

@ -1,67 +1,34 @@
/*
* 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.
*/
/*
* Created on May 8, 2005
*
*/
package org.apache.poi.hssf.record.formula.eval;
/* ====================================================================
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
import org.apache.poi.hssf.record.formula.EqualPtg;
import org.apache.poi.hssf.record.formula.Ptg;
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;
/**
* @author Amol S. Deshmukh < amolweb at ya hoo dot com >
*
*/
public class EqualEval extends RelationalOperationEval {
public final class EqualEval extends RelationalOperationEval {
private EqualPtg delegate;
public static final OperationEval instance = new EqualEval();
public EqualEval(Ptg ptg) {
this.delegate = (EqualPtg) ptg;
}
private EqualEval() {
}
public Eval evaluate(Eval[] operands, int srcRow, short srcCol) {
ValueEval retval = null;
RelationalValues rvs = super.doEvaluate(operands, srcRow, srcCol);
retval = rvs.ee;
int result = 0;
if (retval == null) {
result = doComparison(rvs.bs);
if (result == 0) {
result = doComparison(rvs.ss);
}
if (result == 0) {
result = doComparison(rvs.ds);
}
retval = (result == 0) ? BoolEval.TRUE : BoolEval.FALSE;
}
return retval;
}
public int getNumberOfOperands() {
return delegate.getNumberOfOperands();
}
public int getType() {
return delegate.getType();
}
protected boolean convertComparisonResult(int cmpResult) {
return cmpResult == 0;
}
}

View File

@ -1,67 +1,34 @@
/*
* 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.
*/
/*
* Created on May 8, 2005
*
*/
package org.apache.poi.hssf.record.formula.eval;
/* ====================================================================
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
import org.apache.poi.hssf.record.formula.GreaterEqualPtg;
import org.apache.poi.hssf.record.formula.Ptg;
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;
/**
* @author Amol S. Deshmukh < amolweb at ya hoo dot com >
*
*/
public class GreaterEqualEval extends RelationalOperationEval {
public final class GreaterEqualEval extends RelationalOperationEval {
private GreaterEqualPtg delegate;
public static final OperationEval instance = new GreaterEqualEval();
public GreaterEqualEval(Ptg ptg) {
this.delegate = (GreaterEqualPtg) ptg;
}
public Eval evaluate(Eval[] operands, int srcRow, short srcCol) {
ValueEval retval = null;
RelationalValues rvs = super.doEvaluate(operands, srcRow, srcCol);
retval = rvs.ee;
int result = 0;
if (retval == null) {
result = doComparison(rvs.bs);
if (result == 0) {
result = doComparison(rvs.ss);
}
if (result == 0) {
result = doComparison(rvs.ds);
}
retval = (result >= 0) ? BoolEval.TRUE : BoolEval.FALSE;
}
return retval;
}
public int getNumberOfOperands() {
return delegate.getNumberOfOperands();
}
public int getType() {
return delegate.getType();
}
private GreaterEqualEval() {
}
protected boolean convertComparisonResult(int cmpResult) {
return cmpResult >= 0;
}
}

View File

@ -1,67 +1,34 @@
/*
* 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.
*/
/*
* Created on May 8, 2005
*
*/
package org.apache.poi.hssf.record.formula.eval;
/* ====================================================================
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
import org.apache.poi.hssf.record.formula.GreaterThanPtg;
import org.apache.poi.hssf.record.formula.Ptg;
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;
/**
* @author Amol S. Deshmukh < amolweb at ya hoo dot com >
*
*/
public class GreaterThanEval extends RelationalOperationEval {
public final class GreaterThanEval extends RelationalOperationEval {
private GreaterThanPtg delegate;
public static final OperationEval instance = new GreaterThanEval();
public GreaterThanEval(Ptg ptg) {
this.delegate = (GreaterThanPtg) ptg;
}
public Eval evaluate(Eval[] operands, int srcRow, short srcCol) {
ValueEval retval = null;
RelationalValues rvs = super.doEvaluate(operands, srcRow, srcCol);
retval = rvs.ee;
int result = 0;
if (retval == null) {
result = doComparison(rvs.bs);
if (result == 0) {
result = doComparison(rvs.ss);
}
if (result == 0) {
result = doComparison(rvs.ds);
}
retval = (result > 0) ? BoolEval.TRUE : BoolEval.FALSE;;
}
return retval;
}
public int getNumberOfOperands() {
return delegate.getNumberOfOperands();
}
public int getType() {
return delegate.getType();
}
private GreaterThanEval() {
}
protected boolean convertComparisonResult(int cmpResult) {
return cmpResult > 0;
}
}

View File

@ -1,33 +1,35 @@
/*
* 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.
*/
/* ====================================================================
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 org.apache.poi.hssf.record.formula.AreaI;
import org.apache.poi.hssf.record.formula.AreaI.OffsetArea;
import org.apache.poi.hssf.usermodel.EvaluationCache;
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.util.CellReference;
/**
* @author Amol S. Deshmukh < amolweb at ya hoo dot com >
*
* @author Josh Micich
*/
public final class LazyAreaEval extends AreaEvalBase {
@ -62,4 +64,18 @@ public final class LazyAreaEval extends AreaEvalBase {
return new LazyAreaEval(area, _sheet, _workbook);
}
public String toString() {
CellReference crA = new CellReference(getFirstRow(), getFirstColumn());
CellReference crB = new CellReference(getLastRow(), getLastColumn());
StringBuffer sb = new StringBuffer();
sb.append(getClass().getName()).append("[");
String sheetName = _workbook.getSheetName(_workbook.getSheetIndex(_sheet));
sb.append(sheetName);
sb.append('!');
sb.append(crA.formatAsString());
sb.append(':');
sb.append(crB.formatAsString());
sb.append("]");
return sb.toString();
}
}

View File

@ -1,15 +1,38 @@
/* ====================================================================
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 org.apache.poi.hssf.record.formula.AreaI;
import org.apache.poi.hssf.record.formula.AreaI.OffsetArea;
import org.apache.poi.hssf.record.formula.Ref3DPtg;
import org.apache.poi.hssf.record.formula.RefPtg;
import org.apache.poi.hssf.usermodel.EvaluationCache;
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.util.CellReference;
/**
*
* @author Josh Micich
*/
public final class LazyRefEval extends RefEvalBase {
private final HSSFSheet _sheet;
@ -49,4 +72,16 @@ public final class LazyRefEval extends RefEvalBase {
return new LazyAreaEval(area, _sheet, _workbook);
}
public String toString() {
CellReference cr = new CellReference(getRow(), getColumn());
StringBuffer sb = new StringBuffer();
sb.append(getClass().getName()).append("[");
String sheetName = _workbook.getSheetName(_workbook.getSheetIndex(_sheet));
sb.append(sheetName);
sb.append('!');
sb.append(cr.formatAsString());
sb.append("]");
return sb.toString();
}
}

View File

@ -1,67 +1,34 @@
/*
* 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.
*/
/*
* Created on May 8, 2005
*
*/
package org.apache.poi.hssf.record.formula.eval;
/* ====================================================================
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
import org.apache.poi.hssf.record.formula.LessEqualPtg;
import org.apache.poi.hssf.record.formula.Ptg;
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;
/**
* @author Amol S. Deshmukh < amolweb at ya hoo dot com >
*
*/
public class LessEqualEval extends RelationalOperationEval {
public final class LessEqualEval extends RelationalOperationEval {
private LessEqualPtg delegate;
public static final OperationEval instance = new LessEqualEval();
public LessEqualEval(Ptg ptg) {
this.delegate = (LessEqualPtg) ptg;
}
public Eval evaluate(Eval[] operands, int srcRow, short srcCol) {
ValueEval retval = null;
RelationalValues rvs = super.doEvaluate(operands, srcRow, srcCol);
retval = rvs.ee;
int result = 0;
if (retval == null) {
result = doComparison(rvs.bs);
if (result == 0) {
result = doComparison(rvs.ss);
}
if (result == 0) {
result = doComparison(rvs.ds);
}
retval = (result <= 0) ? BoolEval.TRUE : BoolEval.FALSE;;
}
return retval;
}
public int getNumberOfOperands() {
return delegate.getNumberOfOperands();
}
public int getType() {
return delegate.getType();
}
private LessEqualEval() {
}
protected boolean convertComparisonResult(int cmpResult) {
return cmpResult <= 0;
}
}

View File

@ -1,68 +1,34 @@
/*
* 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.
*/
/*
* Created on May 8, 2005
*
*/
package org.apache.poi.hssf.record.formula.eval;
/* ====================================================================
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
import org.apache.poi.hssf.record.formula.LessThanPtg;
import org.apache.poi.hssf.record.formula.Ptg;
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;
/**
* @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
*
*/
public class LessThanEval extends RelationalOperationEval {
public final class LessThanEval extends RelationalOperationEval {
private LessThanPtg delegate;
public static final OperationEval instance = new LessThanEval();
public LessThanEval(Ptg ptg) {
this.delegate = (LessThanPtg) ptg;
}
public Eval evaluate(Eval[] operands, int srcRow, short srcCol) {
ValueEval retval = null;
RelationalValues rvs = super.doEvaluate(operands, srcRow, srcCol);
retval = rvs.ee;
int result = 0;
if (retval == null) {
result = doComparison(rvs.bs);
if (result == 0) {
result = doComparison(rvs.ss);
}
if (result == 0) {
result = doComparison(rvs.ds);
}
retval = (result < 0) ? BoolEval.TRUE : BoolEval.FALSE;;
}
return retval;
}
public int getNumberOfOperands() {
return delegate.getNumberOfOperands();
}
public int getType() {
return delegate.getType();
}
private LessThanEval() {
}
protected boolean convertComparisonResult(int cmpResult) {
return cmpResult < 0;
}
}

View File

@ -1,68 +1,34 @@
/*
* 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.
*/
/*
* Created on May 8, 2005
*
*/
package org.apache.poi.hssf.record.formula.eval;
/* ====================================================================
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
import org.apache.poi.hssf.record.formula.NotEqualPtg;
import org.apache.poi.hssf.record.formula.Ptg;
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;
/**
* @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
*
*/
public class NotEqualEval extends RelationalOperationEval {
public final class NotEqualEval extends RelationalOperationEval {
private NotEqualPtg delegate;
public static final OperationEval instance = new NotEqualEval();
public NotEqualEval(Ptg ptg) {
this.delegate = (NotEqualPtg) ptg;
}
public Eval evaluate(Eval[] operands, int srcRow, short srcCol) {
ValueEval retval = null;
RelationalValues rvs = super.doEvaluate(operands, srcRow, srcCol);
retval = rvs.ee;
int result = 0;
if (retval == null) {
result = doComparison(rvs.bs);
if (result == 0) {
result = doComparison(rvs.ss);
}
if (result == 0) {
result = doComparison(rvs.ds);
}
retval = (result != 0) ? BoolEval.TRUE : BoolEval.FALSE;
}
return retval;
}
public int getNumberOfOperands() {
return delegate.getNumberOfOperands();
}
public int getType() {
return delegate.getType();
}
private NotEqualEval() {
}
protected boolean convertComparisonResult(int cmpResult) {
return cmpResult != 0;
}
}

View File

@ -1,216 +1,145 @@
/*
* 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.
*/
/*
* Created on May 10, 2005
*
*/
/* ====================================================================
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;
/**
* @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
* Base class for all comparison operator evaluators
*
* @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
*/
public abstract class RelationalOperationEval implements OperationEval {
protected class RelationalValues {
public Double[] ds = new Double[2];
public Boolean[] bs = new Boolean[2];
public String[] ss = new String[3];
public ErrorEval ee = null;
}
/**
* Converts a standard compare result (-1, 0, 1) to <code>true</code> or <code>false</code>
* according to subclass' comparison type.
*/
protected abstract boolean convertComparisonResult(int cmpResult);
/**
* This is a description of how the relational operators apply in MS Excel.
* Use this as a guideline when testing/implementing the evaluate methods
* for the relational operators Evals.
*
* <pre>
* Bool.TRUE > any number.
* Bool > any string. ALWAYS
* Bool.TRUE > Bool.FALSE
* Bool.FALSE == Blank
*
* Strings are never converted to numbers or booleans
* String > any number. ALWAYS
* Non-empty String > Blank
* Empty String == Blank
* String are sorted dictionary wise
*
* Blank > Negative numbers
* Blank == 0
* Blank < Positive numbers
* </pre>
*/
public final Eval evaluate(Eval[] operands, int srcRow, short srcCol) {
if (operands.length != 2) {
return ErrorEval.VALUE_INVALID;
}
/*
* This is a description of how the relational operators apply in MS Excel.
* Use this as a guideline when testing/implementing the evaluate methods
* for the relational operators Evals.
*
* Bool > any number. ALWAYS
* Bool > any string. ALWAYS
* Bool.TRUE > Bool.FALSE
*
* String > any number. ALWAYS
* String > Blank. ALWAYS
* String are sorted dictionary wise
*
* Blank == 0 (numeric)
*/
public RelationalValues doEvaluate(Eval[] operands, int srcRow, short srcCol) {
RelationalValues retval = new RelationalValues();
ValueEval vA;
ValueEval vB;
try {
vA = OperandResolver.getSingleValue(operands[0], srcRow, srcCol);
vB = OperandResolver.getSingleValue(operands[1], srcRow, srcCol);
} catch (EvaluationException e) {
return e.getErrorEval();
}
int cmpResult = doCompare(vA, vB);
boolean result = convertComparisonResult(cmpResult);
return BoolEval.valueOf(result);
}
switch (operands.length) {
default:
retval.ee = ErrorEval.VALUE_INVALID;
break;
case 2:
internalDoEvaluate(operands, srcRow, srcCol, retval, 0);
internalDoEvaluate(operands, srcRow, srcCol, retval, 1);
} // end switch
return retval;
}
private static int doCompare(ValueEval va, ValueEval vb) {
// special cases when one operand is blank
if (va == BlankEval.INSTANCE) {
return compareBlank(vb);
}
if (vb == BlankEval.INSTANCE) {
return -compareBlank(va);
}
/**
* convenience method to avoid code duplication for multiple operands
* @param operands
* @param srcRow
* @param srcCol
* @param retval
* @param index
*/
private void internalDoEvaluate(Eval[] operands, int srcRow, short srcCol, RelationalValues retval, int index) {
if (operands[index] instanceof BoolEval) {
BoolEval be = (BoolEval) operands[index];
retval.bs[index] = Boolean.valueOf(be.getBooleanValue());
}
else if (operands[index] instanceof NumericValueEval) {
NumericValueEval ne = (NumericValueEval) operands[index];
retval.ds[index] = new Double(ne.getNumberValue());
}
else if (operands[index] instanceof StringValueEval) {
StringValueEval se = (StringValueEval) operands[index];
retval.ss[index] = se.getStringValue();
}
else if (operands[index] instanceof RefEval) {
RefEval re = (RefEval) operands[index];
ValueEval ve = re.getInnerValueEval();
if (ve instanceof BoolEval) {
BoolEval be = (BoolEval) ve;
retval.bs[index] = Boolean.valueOf(be.getBooleanValue());
}
else if (ve instanceof BlankEval) {
retval.ds[index] = new Double(0);
}
else if (ve instanceof NumericValueEval) {
NumericValueEval ne = (NumericValueEval) ve;
retval.ds[index] = new Double(ne.getNumberValue());
}
else if (ve instanceof StringValueEval) {
StringValueEval se = (StringValueEval) ve;
retval.ss[index] = se.getStringValue();
}
}
else if (operands[index] instanceof AreaEval) {
AreaEval ae = (AreaEval) operands[index];
if (ae.isRow()) {
if (ae.containsColumn(srcCol)) {
ValueEval ve = ae.getValueAt(ae.getFirstRow(), srcCol);
if (ve instanceof BoolEval) {
BoolEval be = (BoolEval) ve;
retval.bs[index] = Boolean.valueOf(be.getBooleanValue());
}
else if (ve instanceof BlankEval) {
retval.ds[index] = new Double(0);
}
else if (ve instanceof NumericValueEval) {
NumericValueEval ne = (NumericValueEval) ve;
retval.ds[index] = new Double(ne.getNumberValue());
}
else if (ve instanceof StringValueEval) {
StringValueEval se = (StringValueEval) ve;
retval.ss[index] = se.getStringValue();
}
else {
retval.ee = ErrorEval.VALUE_INVALID;
}
}
else {
retval.ee = ErrorEval.VALUE_INVALID;
}
}
else if (ae.isColumn()) {
if (ae.containsRow(srcRow)) {
ValueEval ve = ae.getValueAt(srcRow, ae.getFirstColumn());
if (ve instanceof BoolEval) {
BoolEval be = (BoolEval) ve;
retval.bs[index] = Boolean.valueOf(be.getBooleanValue());
}
else if (ve instanceof BlankEval) {
retval.ds[index] = new Double(0);
}
else if (ve instanceof NumericValueEval) {
NumericValueEval ne = (NumericValueEval) ve;
retval.ds[index] = new Double(ne.getNumberValue());
}
else if (ve instanceof StringValueEval) {
StringValueEval se = (StringValueEval) ve;
retval.ss[index] = se.getStringValue();
}
else {
retval.ee = ErrorEval.VALUE_INVALID;
}
}
else {
retval.ee = ErrorEval.VALUE_INVALID;
}
}
else {
retval.ee = ErrorEval.VALUE_INVALID;
}
}
}
if (va instanceof BoolEval) {
if (vb instanceof BoolEval) {
BoolEval bA = (BoolEval) va;
BoolEval bB = (BoolEval) vb;
if (bA.getBooleanValue() == bB.getBooleanValue()) {
return 0;
}
return bA.getBooleanValue() ? 1 : -1;
}
return 1;
}
if (vb instanceof BoolEval) {
return -1;
}
if (va instanceof StringEval) {
if (vb instanceof StringEval) {
StringEval sA = (StringEval) va;
StringEval sB = (StringEval) vb;
return sA.getStringValue().compareTo(sB.getStringValue());
}
return 1;
}
if (vb instanceof StringEval) {
return -1;
}
if (va instanceof NumberEval) {
if (vb instanceof NumberEval) {
NumberEval nA = (NumberEval) va;
NumberEval nB = (NumberEval) vb;
return Double.compare(nA.getNumberValue(), nB.getNumberValue());
}
}
throw new IllegalArgumentException("Bad operand types (" + va.getClass().getName() + "), ("
+ vb.getClass().getName() + ")");
}
// if both null return 0, else non null wins, else TRUE wins
protected int doComparison(Boolean[] bs) {
int retval = 0;
if (bs[0] != null || bs[1] != null) {
retval = bs[0] != null
? bs[1] != null
? bs[0].booleanValue()
? bs[1].booleanValue()
? 0
: 1
: bs[1].booleanValue()
? -1
: 0
: 1
: bs[1] != null
? -1
: 0;
}
return retval;
}
private static int compareBlank(ValueEval v) {
if (v == BlankEval.INSTANCE) {
return 0;
}
if (v instanceof BoolEval) {
BoolEval boolEval = (BoolEval) v;
return boolEval.getBooleanValue() ? -1 : 0;
}
if (v instanceof NumberEval) {
NumberEval ne = (NumberEval) v;
return Double.compare(0, ne.getNumberValue());
}
if (v instanceof StringEval) {
StringEval se = (StringEval) v;
return se.getStringValue().length() < 1 ? 0 : -1;
}
throw new IllegalArgumentException("bad value class (" + v.getClass().getName() + ")");
}
// if both null return 0, else non null wins, else string compare
protected int doComparison(String[] ss) {
int retval = 0;
if (ss[0] != null || ss[1] != null) {
retval = ss[0] != null
? ss[1] != null
? ss[0].compareTo(ss[1])
: 1
: ss[1] != null
? -1
: 0;
}
return retval;
}
public final int getNumberOfOperands() {
return 2;
}
// if both null return 0, else non null wins, else doublevalue compare
protected int doComparison(Double[] ds) {
int retval = 0;
if (ds[0] != null || ds[1] != null) {
retval = ds[0] != null
? ds[1] != null
? ds[0].compareTo(ds[1])
: 1
: ds[1] != null
? -1
: 0;
}
return retval;
}
public final int getType() {
// TODO - get rid of this method
throw new RuntimeException("Obsolete code - should not be called");
}
}

View File

@ -69,8 +69,9 @@ import org.apache.poi.hssf.record.formula.eval.UnaryPlusEval;
*/
final class OperationEvaluatorFactory {
private static final Class[] OPERATION_CONSTRUCTOR_CLASS_ARRAY = new Class[] { Ptg.class };
// TODO - use singleton instances directly instead of reflection
private static final Map _constructorsByPtgClass = initialiseConstructorsMap();
private static final Map _instancesByPtgClass = initialiseInstancesMap();
private OperationEvaluatorFactory() {
// no instances of this class
@ -81,15 +82,9 @@ final class OperationEvaluatorFactory {
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);
@ -97,13 +92,30 @@ final class OperationEvaluatorFactory {
add(m, UnaryPlusPtg.class, UnaryPlusEval.class);
return m;
}
private static Map initialiseInstancesMap() {
Map m = new HashMap(32);
add(m, EqualPtg.class, EqualEval.instance);
add(m, GreaterEqualPtg.class, GreaterEqualEval.instance);
add(m, GreaterThanPtg.class, GreaterThanEval.instance);
add(m, LessEqualPtg.class, LessEqualEval.instance);
add(m, LessThanPtg.class, LessThanEval.instance);
add(m, NotEqualPtg.class, NotEqualEval.instance);
return m;
}
private static void add(Map m, Class ptgClass, OperationEval evalInstance) {
if(!Ptg.class.isAssignableFrom(ptgClass)) {
throw new IllegalArgumentException("Expected Ptg subclass");
}
m.put(ptgClass, evalInstance);
}
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");
}
@ -134,9 +146,16 @@ final class OperationEvaluatorFactory {
if(ptg == null) {
throw new IllegalArgumentException("ptg must not be null");
}
Object result;
Class ptgClass = ptg.getClass();
result = _instancesByPtgClass.get(ptgClass);
if (result != null) {
return (OperationEval) result;
}
Constructor constructor = (Constructor) _constructorsByPtgClass.get(ptgClass);
if(constructor == null) {
if(ptgClass == ExpPtg.class) {
@ -147,7 +166,6 @@ final class OperationEvaluatorFactory {
throw new RuntimeException("Unexpected operation ptg class (" + ptgClass.getName() + ")");
}
Object result;
Object[] initargs = { ptg };
try {
result = constructor.newInstance(initargs);

View File

@ -31,6 +31,7 @@ public class AllFormulaEvalTests {
TestSuite result = new TestSuite(AllFormulaEvalTests.class.getName());
result.addTestSuite(TestAreaEval.class);
result.addTestSuite(TestCircularReferences.class);
result.addTestSuite(TestEqualEval.class);
result.addTestSuite(TestExternalFunction.class);
result.addTestSuite(TestFormulaBugs.class);
result.addTestSuite(TestFormulasFromSpreadsheet.class);

View File

@ -0,0 +1,69 @@
/* ====================================================================
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.functions.EvalFactory;
/**
* Test for unary plus operator evaluator.
*
* @author Josh Micich
*/
public final class TestEqualEval extends TestCase {
/**
* Test for bug observable at svn revision 692218 (Sep 2008)<br/>
* The value from a 1x1 area should be taken immediately, regardless of srcRow and srcCol
*/
public void test1x1AreaOperand() {
ValueEval[] values = { BoolEval.FALSE, };
Eval[] args = {
EvalFactory.createAreaEval("B1:B1", values),
BoolEval.FALSE,
};
Eval result = EqualEval.instance.evaluate(args, 10, (short)20);
if (result instanceof ErrorEval) {
if (result == ErrorEval.VALUE_INVALID) {
throw new AssertionFailedError("Identified bug in evaluation of 1x1 area");
}
}
assertEquals(BoolEval.class, result.getClass());
assertTrue(((BoolEval)result).getBooleanValue());
}
/**
* Empty string is equal to blank
*/
public void testBlankEqualToEmptyString() {
Eval[] args = {
new StringEval(""),
BlankEval.INSTANCE,
};
Eval result = EqualEval.instance.evaluate(args, 10, (short)20);
assertEquals(BoolEval.class, result.getClass());
BoolEval be = (BoolEval) result;
if (!be.getBooleanValue()) {
throw new AssertionFailedError("Identified bug blank/empty string equality");
}
assertTrue(be.getBooleanValue());
}
}