<!-- Don't forget to update status.xml too! -->
<release version="3.5-beta4" date="2008-??-??">
+ <action dev="POI-DEVELOPERS" type="add">46065 - added implementation for VALUE function</action>
+ <action dev="POI-DEVELOPERS" type="add">45966 - added implementation for FIND function</action>
<action dev="POI-DEVELOPERS" type="fix">45778 - fixed ObjRecord to read ftLbsData properly</action>
<action dev="POI-DEVELOPERS" type="fix">46053 - fixed evaluation cache dependency analysis when changing blank cells</action>
</release>
org.apache.poi.hssf.record.formula.FormulaParser</strong> class. This class implements a hand
written recursive descent parser.
</p>
- <p>Check out the <link href="http://poi.apache.org/javadocs/">javadocs </link> for details.
+ <p>Check out the <link href="http://poi.apache.org/apidocs/">javadocs </link> for details.
</p>
</section>
<!-- Don't forget to update changes.xml too! -->
<changes>
<release version="3.5-beta4" date="2008-??-??">
+ <action dev="POI-DEVELOPERS" type="add">46065 - added implementation for VALUE function</action>
+ <action dev="POI-DEVELOPERS" type="add">45966 - added implementation for FIND function</action>
<action dev="POI-DEVELOPERS" type="fix">45778 - fixed ObjRecord to read ftLbsData properly</action>
<action dev="POI-DEVELOPERS" type="fix">46053 - fixed evaluation cache dependency analysis when changing blank cells</action>
</release>
limitations under the License.
==================================================================== */
-
package org.apache.poi.hssf.dev;
import java.io.FileInputStream;
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.CellRangeAddress;
+import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.ss.util.Region;
if (args.length < 2)
{
-/* try
+ try
{
HSSF hssf = new HSSF(args[ 0 ]);
for (int k = 0; k < wb.getNumberOfSheets(); k++)
{
- System.out.println("Sheet " + k);
HSSFSheet sheet = wb.getSheetAt(k);
int rows = sheet.getPhysicalNumberOfRows();
-
+ System.out.println("Sheet " + k + " \""
+ + wb.getSheetName(k) + "\" has "
+ + rows + " row(s).");
for (int r = 0; r < rows; r++)
{
- HSSFRow row = sheet.getPhysicalRowAt(r);
- int cells = row.getPhysicalNumberOfCells();
-
- System.out.println("ROW " + row.getRowNum());
+ HSSFRow row = sheet.getRow(r);
+ int cells = (row != null) ? row.getPhysicalNumberOfCells() : 0;
+ if (row != null) {
+ System.out.println("\nROW " + row.getRowNum()
+ + " has " + cells + " cell(s).");
+ }
for (int c = 0; c < cells; c++)
{
- HSSFCell cell = row.getPhysicalCellAt(c);
+ HSSFCell cell = row.getCell(c);
String value = null;
switch (cell.getCellType())
{
case HSSFCell.CELL_TYPE_FORMULA :
- value = "FORMULA ";
+ value = "FORMULA value="
+ + cell.getCellFormula();
break;
case HSSFCell.CELL_TYPE_NUMERIC :
catch (Exception e)
{
e.printStackTrace();
- }*/
+ }
}
else if (args.length == 2)
{
import org.apache.poi.hssf.record.aggregates.RecordAggregate.PositionTrackingVisitor;
import org.apache.poi.hssf.record.aggregates.RecordAggregate.RecordVisitor;
import org.apache.poi.hssf.record.formula.FormulaShifter;
-import org.apache.poi.hssf.util.CellRangeAddress;
+import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.hssf.util.PaneInformation;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
{
field_1_numcf = in.readShort();
field_2_need_recalculation = in.readShort();
- field_3_enclosing_cell_range = new org.apache.poi.hssf.util.CellRangeAddress(in);
- field_4_cell_ranges = new org.apache.poi.hssf.util.CellRangeAddressList(in);
+ field_3_enclosing_cell_range = new CellRangeAddress(in);
+ field_4_cell_ranges = new CellRangeAddressList(in);
}
public int getNumberOfConditionalFormats()
int nRegions = in.readUShort();
CellRangeAddress[] cras = new CellRangeAddress[nRegions];
for (int i = 0; i < nRegions; i++) {
- cras[i] = new org.apache.poi.hssf.util.CellRangeAddress(in);
+ cras[i] = new CellRangeAddress(in);
}
_numberOfRegions = nRegions;
_startIndex = 0;
import org.apache.poi.hssf.model.RecordStream;
import org.apache.poi.hssf.record.MergeCellsRecord;
-import org.apache.poi.hssf.util.CellRangeAddress;
-import org.apache.poi.hssf.util.CellRangeAddressList;
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.ss.util.CellRangeAddressList;
/**
*
MergeCellsRecord mcr = (MergeCellsRecord) rs.getNext();
int nRegions = mcr.getNumAreas();
for (int i = 0; i < nRegions; i++) {
- temp.add(mcr.getAreaAt(i));
+ CellRangeAddress cra = mcr.getAreaAt(i);
+ temp.add(cra);
}
}
}
private void addMergeCellsRecord(MergeCellsRecord mcr) {
int nRegions = mcr.getNumAreas();
for (int i = 0; i < nRegions; i++) {
- _mergedRegions.add(mcr.getAreaAt(i));
+ CellRangeAddress cra = mcr.getAreaAt(i);
+ _mergedRegions.add(cra);
}
}
public int getNumberOfMergedRegions() {
return _mergedRegions.size();
}
-
}
+++ /dev/null
-/*
-* 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 14, 2005
- *
- */
-package org.apache.poi.hssf.record.formula.eval;
-
-/**
- * @author Amol S. Deshmukh < amolweb at ya hoo dot com >
- *
- */
-public abstract class StringOperationEval implements OperationEval {
-
-
-
- /**
- * Returns an instanceof StringValueEval or ErrorEval or BlankEval
- *
- * @param eval
- * @param srcRow
- * @param srcCol
- */
- protected ValueEval singleOperandEvaluate(Eval eval, int srcRow, short srcCol) {
- ValueEval retval;
- if (eval instanceof AreaEval) {
- AreaEval ae = (AreaEval) eval;
- if (ae.contains(srcRow, srcCol)) { // circular ref!
- retval = ErrorEval.CIRCULAR_REF_ERROR;
- }
- else if (ae.isRow()) {
- if (ae.containsColumn(srcCol)) {
- ValueEval ve = ae.getValueAt(ae.getFirstRow(), srcCol);
- retval = internalResolveEval(eval);
- }
- else {
- retval = ErrorEval.NAME_INVALID;
- }
- }
- else if (ae.isColumn()) {
- if (ae.containsRow(srcRow)) {
- ValueEval ve = ae.getValueAt(srcRow, ae.getFirstColumn());
- retval = internalResolveEval(eval);
- }
- else {
- retval = ErrorEval.NAME_INVALID;
- }
- }
- else {
- retval = ErrorEval.NAME_INVALID;
- }
- }
- else {
- retval = internalResolveEval(eval);
- }
- return retval;
- }
-
- private ValueEval internalResolveEval(Eval eval) {
- ValueEval retval;
- if (eval instanceof StringValueEval) {
- retval = (StringValueEval) eval;
- }
- else if (eval instanceof RefEval) {
- RefEval re = (RefEval) eval;
- ValueEval tve = re.getInnerValueEval();
- if (tve instanceof StringValueEval || tve instanceof BlankEval) {
- retval = tve;
- }
- else {
- retval = ErrorEval.NAME_INVALID;
- }
- }
- else if (eval instanceof BlankEval) {
- retval = (BlankEval) eval;
- }
- else {
- retval = ErrorEval.NAME_INVALID;
- }
- return retval;
- }
-}
-/*
-* 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 15, 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.functions;
+
+import org.apache.poi.hssf.record.formula.eval.Eval;
+import org.apache.poi.hssf.record.formula.eval.ErrorEval;
+import org.apache.poi.hssf.record.formula.eval.ValueEval;
+import org.apache.poi.hssf.record.formula.eval.NumberEval;
+import org.apache.poi.hssf.record.formula.eval.EvaluationException;
+
+/**
+ * Implementation of the FIND() function.<p/>
+ *
+ * <b>Syntax</b>:<br/>
+ * <b>FIND</b>(<b>find_text</b>, <b>within_text</b>, start_num)<p/>
*
+ * FIND returns the character position of the first occurrence of <tt>find_text</tt> inside
+ * <tt>within_text</tt>. The third parameter, <tt>start_num</tt>, is optional (default=1)
+ * and specifies where to start searching from. Character positions are 1-based.<p/>
+ *
+ * @author Torstein Tauno Svendsen (torstei@officenet.no)
*/
-package org.apache.poi.hssf.record.formula.functions;
+public class Find extends TextFunction {
-public class Find extends NotImplementedFunction {
+ protected ValueEval evaluateFunc(Eval[] args, int srcCellRow, short srcCellCol)
+ throws EvaluationException {
+ int nArgs = args.length;
+ if (nArgs < 2 || nArgs > 3) {
+ return ErrorEval.VALUE_INVALID;
+ }
+ String needle = evaluateStringArg(args[0], srcCellRow, srcCellCol);
+ String haystack = evaluateStringArg(args[1], srcCellRow, srcCellCol);
+ int startpos;
+ if (nArgs == 3) {
+ startpos = evaluateIntArg(args[2], srcCellRow, srcCellCol);
+ if (startpos <= 0) {
+ return ErrorEval.VALUE_INVALID;
+ }
+ startpos--; // convert 1-based to zero based
+ } else {
+ startpos = 0;
+ }
+ int result = haystack.indexOf(needle, startpos);
+ if (result == -1) {
+ return ErrorEval.VALUE_INVALID;
+ }
+ return new NumberEval(result + 1);
+ }
}
-/*
-* 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 15, 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.functions;
-public class Value extends NotImplementedFunction {
+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.EvaluationException;
+import org.apache.poi.hssf.record.formula.eval.NumberEval;
+import org.apache.poi.hssf.record.formula.eval.OperandResolver;
+import org.apache.poi.hssf.record.formula.eval.ValueEval;
+
+/**
+ * Implementation for Excel VALUE() function.<p/>
+ *
+ * <b>Syntax</b>:<br/> <b>VALUE</b>(<b>text</b>)<br/>
+ *
+ * Converts the text argument to a number. Leading and/or trailing whitespace is
+ * ignored. Currency symbols and thousands separators are stripped out.
+ * Scientific notation is also supported. If the supplied text does not convert
+ * properly the result is <b>#VALUE!</b> error. Blank string converts to zero.
+ *
+ * @author Josh Micich
+ */
+public final class Value implements Function {
+
+ /** "1,0000" is valid, "1,00" is not */
+ private static final int MIN_DISTANCE_BETWEEN_THOUSANDS_SEPARATOR = 4;
+ private static final Double ZERO = new Double(0.0);
+
+ public Eval evaluate(Eval[] args, int srcCellRow, short srcCellCol) {
+ if (args.length != 1) {
+ return ErrorEval.VALUE_INVALID;
+ }
+ ValueEval veText;
+ try {
+ veText = OperandResolver.getSingleValue(args[0], srcCellRow, srcCellCol);
+ } catch (EvaluationException e) {
+ return e.getErrorEval();
+ }
+ String strText = OperandResolver.coerceValueToString(veText);
+ Double result = convertTextToNumber(strText);
+ if (result == null) {
+ return ErrorEval.VALUE_INVALID;
+ }
+ return new NumberEval(result.doubleValue());
+ }
+
+ /**
+ * TODO see if the same functionality is needed in {@link OperandResolver#parseDouble(String)}
+ *
+ * @return <code>null</code> if there is any problem converting the text
+ */
+ private static Double convertTextToNumber(String strText) {
+ boolean foundCurrency = false;
+ boolean foundUnaryPlus = false;
+ boolean foundUnaryMinus = false;
+
+ int len = strText.length();
+ int i;
+ for (i = 0; i < len; i++) {
+ char ch = strText.charAt(i);
+ if (Character.isDigit(ch) || ch == '.') {
+ break;
+ }
+ switch (ch) {
+ case ' ':
+ // intervening spaces between '$', '-', '+' are OK
+ continue;
+ case '$':
+ if (foundCurrency) {
+ // only one currency symbols is allowed
+ return null;
+ }
+ foundCurrency = true;
+ continue;
+ case '+':
+ if (foundUnaryMinus || foundUnaryPlus) {
+ return null;
+ }
+ foundUnaryPlus = true;
+ continue;
+ case '-':
+ if (foundUnaryMinus || foundUnaryPlus) {
+ return null;
+ }
+ foundUnaryMinus = true;
+ continue;
+ default:
+ // all other characters are illegal
+ return null;
+ }
+ }
+ if (i >= len) {
+ // didn't find digits or '.'
+ if (foundCurrency || foundUnaryMinus || foundUnaryPlus) {
+ return null;
+ }
+ return ZERO;
+ }
+
+ // remove thousands separators
+
+ boolean foundDecimalPoint = false;
+ int lastThousandsSeparatorIndex = Short.MIN_VALUE;
+ StringBuffer sb = new StringBuffer(len);
+ for (; i < len; i++) {
+ char ch = strText.charAt(i);
+ if (Character.isDigit(ch)) {
+ sb.append(ch);
+ continue;
+ }
+ switch (ch) {
+ case ' ':
+ String remainingText = strText.substring(i);
+ if (remainingText.trim().length() > 0) {
+ // intervening spaces not allowed once the digits start
+ return null;
+ }
+ break;
+ case '.':
+ if (foundDecimalPoint) {
+ return null;
+ }
+ if (i - lastThousandsSeparatorIndex < MIN_DISTANCE_BETWEEN_THOUSANDS_SEPARATOR) {
+ return null;
+ }
+ foundDecimalPoint = true;
+ sb.append('.');
+ continue;
+ case ',':
+ if (foundDecimalPoint) {
+ // thousands separators not allowed after '.' or 'E'
+ return null;
+ }
+ int distanceBetweenThousandsSeparators = i - lastThousandsSeparatorIndex;
+ // as long as there are 3 or more digits between
+ if (distanceBetweenThousandsSeparators < MIN_DISTANCE_BETWEEN_THOUSANDS_SEPARATOR) {
+ return null;
+ }
+ lastThousandsSeparatorIndex = i;
+ // don't append ','
+ continue;
+
+ case 'E':
+ case 'e':
+ if (i - lastThousandsSeparatorIndex < MIN_DISTANCE_BETWEEN_THOUSANDS_SEPARATOR) {
+ return null;
+ }
+ // append rest of strText and skip to end of loop
+ sb.append(strText.substring(i));
+ i = len;
+ break;
+ default:
+ // all other characters are illegal
+ return null;
+ }
+ }
+ if (!foundDecimalPoint) {
+ if (i - lastThousandsSeparatorIndex < MIN_DISTANCE_BETWEEN_THOUSANDS_SEPARATOR) {
+ return null;
+ }
+ }
+ double d;
+ try {
+ d = Double.parseDouble(sb.toString());
+ } catch (NumberFormatException e) {
+ // still a problem parsing the number - probably out of range
+ return null;
+ }
+ return new Double(foundUnaryMinus ? -d : d);
+ }
}
/**
* @return the merged region at the specified index
*/
- public org.apache.poi.hssf.util.CellRangeAddress getMergedRegion(int index) {
+ public CellRangeAddress getMergedRegion(int index) {
return sheet.getMergedRegionAt(index);
}
\r
import org.apache.poi.hssf.record.RecordInputStream;\r
import org.apache.poi.hssf.record.SelectionRecord;\r
-import org.apache.poi.util.LittleEndian;\r
\r
/**\r
* See OOO documentation: excelfileformat.pdf sec 2.5.14 - 'Cell Range Address'<p/>\r
* \r
* Note - {@link SelectionRecord} uses the BIFF5 version of this structure\r
+ * @deprecated use {@link org.apache.poi.ss.util.CellRangeAddress}\r
* @author Dragos Buleandra (dragos.buleandra@trade2b.ro)\r
*/\r
public class CellRangeAddress extends org.apache.poi.ss.util.CellRangeAddress {\r
* range address (called an ADDR structure) contains 4 16-bit-values.
* </p>
*
+ * @deprecated use {@link org.apache.poi.ss.util.CellRangeAddressList}
+ *
* @author Dragos Buleandra (dragos.buleandra@trade2b.ro)
*/
public class CellRangeAddressList extends org.apache.poi.ss.util.CellRangeAddressList {
package org.apache.poi.ss.util;
+import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.hssf.record.SelectionRecord;
import org.apache.poi.util.LittleEndian;
LittleEndian.putUShort(data, offset + 6, getLastColumn());
return ENCODED_SIZE;
}
+ public CellRangeAddress(RecordInputStream in) {
+ super(readUShortAndCheck(in), in.readUShort(), in.readUShort(), in.readUShort());
+ }
+
+ private static int readUShortAndCheck(RecordInputStream in) {
+ if (in.remaining() < ENCODED_SIZE) {
+ // Ran out of data
+ throw new RuntimeException("Ran out of data reading CellRangeAddress");
+ }
+ return in.readUShort();
+ }
public CellRangeAddress copy() {
return new CellRangeAddress(getFirstRow(), getLastRow(), getFirstColumn(), getLastColumn());
import java.util.ArrayList;
import java.util.List;
+
+import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.util.LittleEndian;
/**
this();
addCellRangeAddress(firstRow, firstCol, lastRow, lastCol);
}
+ /**
+ * @param in the RecordInputstream to read the record from
+ */
+ public CellRangeAddressList(RecordInputStream in) {
+ this();
+ int nItems = in.readUShort();
+ for (int k = 0; k < nItems; k++) {
+ _list.add(new CellRangeAddress(in));
+ }
+ }
/**
* Get the number of following ADDR structures. The number of this
* structures is automatically set when reading an Excel file and/or
package org.apache.poi.hssf.record;
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.AssertionFailedError;
import junit.framework.TestCase;
+import org.apache.poi.hssf.model.RecordStream;
+import org.apache.poi.hssf.record.aggregates.MergedCellsTable;
+import org.apache.poi.hssf.record.aggregates.RecordAggregate.RecordVisitor;
import org.apache.poi.ss.util.CellRangeAddress;
+
/**
* Make sure the merge cells record behaves
* @author Danny Mui (dmui at apache dot org)
*/
public final class TestMergeCellsRecord extends TestCase {
- /**
- * Make sure when a clone is called, we actually clone it.
- * @throws Exception
- */
- public void testCloneReferences() throws Exception {
- CellRangeAddress[] cras = { new CellRangeAddress(0, 1, 0, 2), };
- MergeCellsRecord merge = new MergeCellsRecord(cras, 0, cras.length);
- MergeCellsRecord clone = (MergeCellsRecord)merge.clone();
-
- assertNotSame("Merged and cloned objects are the same", merge, clone);
-
- CellRangeAddress mergeRegion = merge.getAreaAt(0);
- CellRangeAddress cloneRegion = clone.getAreaAt(0);
- assertNotSame("Should not point to same objects when cloning", mergeRegion, cloneRegion);
- assertEquals("New Clone Row From doesnt match", mergeRegion.getFirstRow(), cloneRegion.getFirstRow());
- assertEquals("New Clone Row To doesnt match", mergeRegion.getLastRow(), cloneRegion.getLastRow());
- assertEquals("New Clone Col From doesnt match", mergeRegion.getFirstColumn(), cloneRegion.getFirstColumn());
- assertEquals("New Clone Col To doesnt match", mergeRegion.getLastColumn(), cloneRegion.getLastColumn());
+ /**
+ * Make sure when a clone is called, we actually clone it.
+ */
+ public void testCloneReferences() {
+ CellRangeAddress[] cras = { new CellRangeAddress(0, 1, 0, 2), };
+ MergeCellsRecord merge = new MergeCellsRecord(cras, 0, cras.length);
+ MergeCellsRecord clone = (MergeCellsRecord)merge.clone();
+
+ assertNotSame("Merged and cloned objects are the same", merge, clone);
+
+ CellRangeAddress mergeRegion = merge.getAreaAt(0);
+ CellRangeAddress cloneRegion = clone.getAreaAt(0);
+ assertNotSame("Should not point to same objects when cloning", mergeRegion, cloneRegion);
+ assertEquals("New Clone Row From doesnt match", mergeRegion.getFirstRow(), cloneRegion.getFirstRow());
+ assertEquals("New Clone Row To doesnt match", mergeRegion.getLastRow(), cloneRegion.getLastRow());
+ assertEquals("New Clone Col From doesnt match", mergeRegion.getFirstColumn(), cloneRegion.getFirstColumn());
+ assertEquals("New Clone Col To doesnt match", mergeRegion.getLastColumn(), cloneRegion.getLastColumn());
- assertFalse(merge.getAreaAt(0) == clone.getAreaAt(0));
- }
+ assertFalse(merge.getAreaAt(0) == clone.getAreaAt(0));
+ }
+
+ private static final RecordVisitor dummyRecordVisitor = new RecordVisitor() {
+ public void visitRecord(Record r) {
+ // do nothing
+ }
+ };
+ public void testMCTable_bug46009() {
+ MergedCellsTable mct = new MergedCellsTable();
+ List recList = new ArrayList();
+ CellRangeAddress[] cras = new CellRangeAddress[] {
+ new CellRangeAddress(0, 0, 0, 3),
+ };
+ recList.add(new MergeCellsRecord(cras, 0, 1));
+ RecordStream rs = new RecordStream(recList, 0);
+ mct.read(rs);
+ try {
+ mct.visitContainedRecords(dummyRecordVisitor);
+ } catch (ArrayStoreException e) {
+ throw new AssertionFailedError("Identified bug 46009");
+ }
+ }
}
result.addTestSuite(TestAverage.class);
result.addTestSuite(TestCountFuncs.class);
result.addTestSuite(TestDate.class);
+ result.addTestSuite(TestFind.class);
result.addTestSuite(TestFinanceLib.class);
result.addTestSuite(TestIndex.class);
result.addTestSuite(TestIndexFunctionFromSpreadsheet.class);
result.addTestSuite(TestStatsLib.class);
result.addTestSuite(TestTFunc.class);
result.addTestSuite(TestTrim.class);
+ result.addTestSuite(TestValue.class);
result.addTestSuite(TestXYNumericFunction.class);
return result;
}
--- /dev/null
+/* ====================================================================
+ 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 junit.framework.TestCase;
+
+import org.apache.poi.hssf.usermodel.HSSFCell;
+import org.apache.poi.hssf.usermodel.HSSFErrorConstants;
+import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.usermodel.CellValue;
+
+/**
+ * Tests for {@link Find}
+ *
+ * @author Torstein Svendsen (torstei@officenet.no)
+ */
+public final class TestFind extends TestCase {
+
+ public void testFind() {
+ HSSFWorkbook wb = new HSSFWorkbook();
+ HSSFCell cell = wb.createSheet().createRow(0).createCell(0);
+
+ HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb);
+
+ confirmResult(fe, cell, "find(\"h\", \"haystack\")", 1);
+ confirmResult(fe, cell, "find(\"a\", \"haystack\",2)", 2);
+ confirmResult(fe, cell, "find(\"a\", \"haystack\",3)", 6);
+
+ // number args converted to text
+ confirmResult(fe, cell, "find(7, 32768)", 3);
+ confirmResult(fe, cell, "find(\"34\", 1341235233412, 3)", 10);
+ confirmResult(fe, cell, "find(5, 87654)", 4);
+
+ // Errors
+ confirmError(fe, cell, "find(\"n\", \"haystack\")", HSSFErrorConstants.ERROR_VALUE);
+ confirmError(fe, cell, "find(\"k\", \"haystack\",9)", HSSFErrorConstants.ERROR_VALUE);
+ confirmError(fe, cell, "find(\"k\", \"haystack\",#REF!)", HSSFErrorConstants.ERROR_REF);
+ confirmError(fe, cell, "find(\"k\", \"haystack\",0)", HSSFErrorConstants.ERROR_VALUE);
+ confirmError(fe, cell, "find(#DIV/0!, #N/A, #REF!)", HSSFErrorConstants.ERROR_DIV_0);
+ confirmError(fe, cell, "find(2, #N/A, #REF!)", HSSFErrorConstants.ERROR_NA);
+ }
+
+ private static void confirmResult(HSSFFormulaEvaluator fe, HSSFCell cell, String formulaText,
+ int expectedResult) {
+ cell.setCellFormula(formulaText);
+ fe.notifyUpdateCell(cell);
+ CellValue result = fe.evaluate(cell);
+ assertEquals(result.getCellType(), HSSFCell.CELL_TYPE_NUMERIC);
+ assertEquals(expectedResult, result.getNumberValue(), 0.0);
+ }
+
+ private static void confirmError(HSSFFormulaEvaluator fe, HSSFCell cell, String formulaText,
+ int expectedErrorCode) {
+ cell.setCellFormula(formulaText);
+ fe.notifyUpdateCell(cell);
+ CellValue result = fe.evaluate(cell);
+ assertEquals(result.getCellType(), HSSFCell.CELL_TYPE_ERROR);
+ assertEquals(expectedErrorCode, result.getErrorValue());
+ }
+}
--- /dev/null
+/* ====================================================================
+ 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 junit.framework.TestCase;
+
+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.NumberEval;
+import org.apache.poi.hssf.record.formula.eval.StringEval;
+
+/**
+ * Tests for {@link Value}
+ *
+ * @author Josh Micich
+ */
+public final class TestValue extends TestCase {
+
+ private static Eval invokeValue(String strText) {
+ Eval[] args = new Eval[] { new StringEval(strText), };
+ return new Value().evaluate(args, -1, (short) -1);
+ }
+
+ private static void confirmValue(String strText, double expected) {
+ Eval result = invokeValue(strText);
+ assertEquals(NumberEval.class, result.getClass());
+ assertEquals(expected, ((NumberEval) result).getNumberValue(), 0.0);
+ }
+
+ private static void confirmValueError(String strText) {
+ Eval result = invokeValue(strText);
+ assertEquals(ErrorEval.class, result.getClass());
+ assertEquals(ErrorEval.VALUE_INVALID, result);
+ }
+
+ public void testBasic() {
+
+ confirmValue("100", 100);
+ confirmValue("-2.3", -2.3);
+ confirmValue(".5", 0.5);
+ confirmValue(".5e2", 50);
+ confirmValue(".5e-2", 0.005);
+ confirmValue(".5e+2", 50);
+ confirmValue("+5", 5);
+ confirmValue("$1,000", 1000);
+ confirmValue("100.5e1", 1005);
+ confirmValue("1,0000", 10000);
+ confirmValue("1,000,0000", 10000000);
+ confirmValue("1,000,0000,00000", 1000000000000.0);
+ confirmValue(" 100 ", 100);
+ confirmValue(" + 100", 100);
+ confirmValue("10000", 10000);
+ confirmValue("$-5", -5);
+ confirmValue("$.5", 0.5);
+ confirmValue("123e+5", 12300000);
+ confirmValue("1,000e2", 100000);
+ confirmValue("$10e2", 1000);
+ confirmValue("$1,000e2", 100000);
+ }
+
+ public void testErrors() {
+ confirmValueError("1+1");
+ confirmValueError("1 1");
+ confirmValueError("1,00.0");
+ confirmValueError("1,00");
+ confirmValueError("$1,00.5e1");
+ confirmValueError("1,00.5e1");
+ confirmValueError("1,0,000");
+ confirmValueError("1,00,000");
+ confirmValueError("++100");
+ confirmValueError("$$5");
+ confirmValueError("-");
+ confirmValueError("+");
+ confirmValueError("$");
+ confirmValueError(",300");
+ confirmValueError("0.233,4");
+ confirmValueError("1e2.5");
+ }
+}