ASF Bugzilla – Attachment 32046 Details for
Bug 57007
[patch] Implement DGET and DMIN functions
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
dget_dmin.diff
dget_dmin.diff (text/plain), 54.68 KB, created by
Patrick Böker
on 2014-09-23 13:56:22 UTC
(
hide
)
Description:
dget_dmin.diff
Filename:
MIME Type:
Creator:
Patrick Böker
Created:
2014-09-23 13:56:22 UTC
Size:
54.68 KB
patch
obsolete
>From a129fba2102fb510b0eaf610474c299e455c375e Mon Sep 17 00:00:00 2001 >From: Patrick Sebastian Zimmermann <patrick.zimmermann@haltec.de> >Date: Fri, 19 Sep 2014 15:57:58 +0200 >Subject: [PATCH] Implementation of DGet/DMin. > >--- > .../apache/poi/ss/formula/eval/FunctionEval.java | 7 + > .../org/apache/poi/ss/formula/functions/DGet.java | 52 +++ > .../org/apache/poi/ss/formula/functions/DMin.java | 59 ++++ > .../poi/ss/formula/functions/DStarRunner.java | 374 +++++++++++++++++++++ > .../poi/ss/formula/functions/IDStarAlgorithm.java | 27 ++ > .../TestDGetFunctionsFromSpreadsheet.java | 27 ++ > .../TestDStarFunctionsFromSpreadsheet.java | 27 ++ > test-data/spreadsheet/DGet.xls | Bin 0 -> 39936 bytes > test-data/spreadsheet/DStar.xls | Bin 0 -> 31232 bytes > 9 files changed, 573 insertions(+) > create mode 100644 src/java/org/apache/poi/ss/formula/functions/DGet.java > create mode 100644 src/java/org/apache/poi/ss/formula/functions/DMin.java > create mode 100644 src/java/org/apache/poi/ss/formula/functions/DStarRunner.java > create mode 100644 src/java/org/apache/poi/ss/formula/functions/IDStarAlgorithm.java > create mode 100644 src/testcases/org/apache/poi/ss/formula/functions/TestDGetFunctionsFromSpreadsheet.java > create mode 100644 src/testcases/org/apache/poi/ss/formula/functions/TestDStarFunctionsFromSpreadsheet.java > create mode 100644 test-data/spreadsheet/DGet.xls > create mode 100644 test-data/spreadsheet/DStar.xls > >diff --git a/src/java/org/apache/poi/ss/formula/eval/FunctionEval.java b/src/java/org/apache/poi/ss/formula/eval/FunctionEval.java >index e828aad..a9c59ac 100644 >--- a/src/java/org/apache/poi/ss/formula/eval/FunctionEval.java >+++ b/src/java/org/apache/poi/ss/formula/eval/FunctionEval.java >@@ -36,6 +36,9 @@ import org.apache.poi.ss.formula.functions.Count; > import org.apache.poi.ss.formula.functions.Counta; > import org.apache.poi.ss.formula.functions.Countblank; > import org.apache.poi.ss.formula.functions.Countif; >+import org.apache.poi.ss.formula.functions.DGet; >+import org.apache.poi.ss.formula.functions.DMin; >+import org.apache.poi.ss.formula.functions.DStarRunner; > import org.apache.poi.ss.formula.functions.DateFunc; > import org.apache.poi.ss.formula.functions.Days360; > import org.apache.poi.ss.formula.functions.Errortype; >@@ -160,6 +163,8 @@ public final class FunctionEval { > retval[37] = BooleanFunction.OR; > retval[38] = BooleanFunction.NOT; > retval[39] = NumericFunction.MOD; >+ >+ retval[43] = new DStarRunner(new DMin()); > > retval[46] = AggregateFunction.VAR; > retval[48] = TextFunction.TEXT; >@@ -253,6 +258,8 @@ public final class FunctionEval { > retval[233] = NumericFunction.ACOSH; > retval[234] = NumericFunction.ATANH; > >+ retval[235] = new DStarRunner(new DGet()); >+ > retval[ID.EXTERNAL_FUNC] = null; // ExternalFunction is a FreeREfFunction > > retval[261] = new Errortype(); >diff --git a/src/java/org/apache/poi/ss/formula/functions/DGet.java b/src/java/org/apache/poi/ss/formula/functions/DGet.java >new file mode 100644 >index 0000000..32c411a >--- /dev/null >+++ b/src/java/org/apache/poi/ss/formula/functions/DGet.java >@@ -0,0 +1,52 @@ >+/* ==================================================================== >+ 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.ss.formula.functions; >+ >+import org.apache.poi.ss.formula.eval.ErrorEval; >+import org.apache.poi.ss.formula.eval.ValueEval; >+ >+/** >+ * Implementation of the DGet function: >+ * Finds the value of a column in an area with given conditions. >+ */ >+public final class DGet implements IDStarAlgorithm { >+ ValueEval result; >+ public void reset() { >+ result = null; >+ } >+ >+ public boolean processMatch(ValueEval eval) { >+ if(result == null) // First match, just set the value. >+ { >+ result = eval; >+ } >+ else // There was a previous match, since there is only exactly one allowed, bail out. >+ { >+ result = ErrorEval.NUM_ERROR; >+ return false; >+ } >+ return true; >+ } >+ >+ public ValueEval getResult() { >+ if(result == null) >+ return ErrorEval.VALUE_INVALID; >+ else >+ return result; >+ } >+} >diff --git a/src/java/org/apache/poi/ss/formula/functions/DMin.java b/src/java/org/apache/poi/ss/formula/functions/DMin.java >new file mode 100644 >index 0000000..de79ee1 >--- /dev/null >+++ b/src/java/org/apache/poi/ss/formula/functions/DMin.java >@@ -0,0 +1,59 @@ >+/* ==================================================================== >+ 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.ss.formula.functions; >+ >+import org.apache.poi.ss.formula.eval.NumberEval; >+import org.apache.poi.ss.formula.eval.NumericValueEval; >+import org.apache.poi.ss.formula.eval.ValueEval; >+ >+/** >+ * Implementation of the DMin function: >+ * Finds the minimum value of a column in an area with given conditions. >+ */ >+public final class DMin implements IDStarAlgorithm { >+ ValueEval minimumValue; >+ >+ public void reset() { >+ minimumValue = null; >+ } >+ >+ public boolean processMatch(ValueEval eval) { >+ if(eval instanceof NumericValueEval) >+ { >+ if(minimumValue == null) // First match, just set the value. >+ { >+ minimumValue = eval; >+ } >+ else // There was a previous match, find the new minimum. >+ { >+ double currentValue = ((NumericValueEval)eval).getNumberValue(); >+ double oldValue = ((NumericValueEval)minimumValue).getNumberValue(); >+ if(currentValue < oldValue) >+ minimumValue = eval; >+ } >+ } >+ return true; >+ } >+ >+ public ValueEval getResult() { >+ if(minimumValue == null) >+ return NumberEval.ZERO; >+ else >+ return minimumValue; >+ } >+} >diff --git a/src/java/org/apache/poi/ss/formula/functions/DStarRunner.java b/src/java/org/apache/poi/ss/formula/functions/DStarRunner.java >new file mode 100644 >index 0000000..0031e51 >--- /dev/null >+++ b/src/java/org/apache/poi/ss/formula/functions/DStarRunner.java >@@ -0,0 +1,374 @@ >+/* ==================================================================== >+ 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.ss.formula.functions; >+ >+import org.apache.poi.ss.formula.TwoDEval; >+import org.apache.poi.ss.formula.eval.BlankEval; >+import org.apache.poi.ss.formula.eval.ErrorEval; >+import org.apache.poi.ss.formula.eval.EvaluationException; >+import org.apache.poi.ss.formula.eval.NotImplementedException; >+import org.apache.poi.ss.formula.eval.NumericValueEval; >+import org.apache.poi.ss.formula.eval.RefEval; >+import org.apache.poi.ss.formula.eval.StringValueEval; >+import org.apache.poi.ss.formula.eval.ValueEval; >+import org.apache.poi.ss.util.NumberComparer; >+ >+/** >+ * This class performs a D* calculation. It takes an {@link IDStarAlgorithm} object and >+ * uses it for calculating the result value. Iterating a database and checking the >+ * entries against the set of conditions is done here. >+ */ >+public final class DStarRunner implements Function3Arg { >+ private IDStarAlgorithm algorithm; >+ >+ public DStarRunner(IDStarAlgorithm algorithm) { >+ this.algorithm = algorithm; >+ } >+ >+ public final ValueEval evaluate(ValueEval[] args, int srcRowIndex, int srcColumnIndex) { >+ if(args.length == 3) { >+ return evaluate(srcRowIndex, srcColumnIndex, args[0], args[1], args[2]); >+ } >+ else { >+ return ErrorEval.VALUE_INVALID; >+ } >+ } >+ >+ public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, >+ ValueEval database, ValueEval filterColumn, ValueEval conditionDatabase) { >+ // Input processing and error checks. >+ if(!(database instanceof TwoDEval) || !(conditionDatabase instanceof TwoDEval)) { >+ return ErrorEval.VALUE_INVALID; >+ } >+ TwoDEval db = (TwoDEval)database; >+ TwoDEval cdb = (TwoDEval)conditionDatabase; >+ >+ int fc; >+ try { >+ fc = getColumnForName(filterColumn, db); >+ } >+ catch (EvaluationException e) { >+ return ErrorEval.VALUE_INVALID; >+ } >+ if(fc == -1) { // column not found >+ return ErrorEval.VALUE_INVALID; >+ } >+ >+ // Reset algorithm. >+ algorithm.reset(); >+ >+ // Iterate over all db entries. >+ for(int row = 1; row < db.getHeight(); ++row) { >+ boolean matches = true; >+ try { >+ matches = fullfillsConditions(db, row, cdb); >+ } >+ catch (EvaluationException e) { >+ return ErrorEval.VALUE_INVALID; >+ } >+ // Filter each entry. >+ if(matches) { >+ try { >+ ValueEval currentValueEval = solveReference(db.getValue(row, fc)); >+ // Pass the match to the algorithm and conditionally abort the search. >+ boolean shouldContinue = algorithm.processMatch(currentValueEval); >+ if(! shouldContinue) { >+ break; >+ } >+ } catch (EvaluationException e) { >+ return e.getErrorEval(); >+ } >+ } >+ } >+ >+ // Return the result of the algorithm. >+ return algorithm.getResult(); >+ } >+ >+ private enum operator { >+ largerThan, >+ largerEqualThan, >+ smallerThan, >+ smallerEqualThan, >+ equal >+ } >+ >+ /** >+ * Resolve reference(-chains) until we have a normal value. >+ * >+ * @param field a ValueEval which can be a RefEval. >+ * @return a ValueEval which is guaranteed not to be a RefEval >+ * @throws EvaluationException If a multi-sheet reference was found along the way. >+ */ >+ private static ValueEval solveReference(ValueEval field) throws EvaluationException { >+ if (field instanceof RefEval) { >+ RefEval refEval = (RefEval)field; >+ if (refEval.getNumberOfSheets() > 1) { >+ throw new EvaluationException(ErrorEval.VALUE_INVALID); >+ } >+ return solveReference(refEval.getInnerValueEval(refEval.getFirstSheetIndex())); >+ } >+ else { >+ return field; >+ } >+ } >+ >+ /** >+ * Returns the first column index that matches the given name. The name can either be >+ * a string or an integer, when it's an integer, then the respective column >+ * (1 based index) is returned. >+ * @param nameValueEval >+ * @param db >+ * @return the first column index that matches the given name (or int) >+ * @throws EvaluationException >+ */ >+ @SuppressWarnings("unused") >+ private static int getColumnForTag(ValueEval nameValueEval, TwoDEval db) >+ throws EvaluationException { >+ int resultColumn = -1; >+ >+ // Numbers as column indicator are allowed, check that. >+ if(nameValueEval instanceof NumericValueEval) { >+ double doubleResultColumn = ((NumericValueEval)nameValueEval).getNumberValue(); >+ resultColumn = (int)doubleResultColumn; >+ // Floating comparisions are usually not possible, but should work for 0.0. >+ if(doubleResultColumn - resultColumn != 0.0) >+ throw new EvaluationException(ErrorEval.VALUE_INVALID); >+ resultColumn -= 1; // Numbers are 1-based not 0-based. >+ } >+ else { >+ resultColumn = getColumnForName(nameValueEval, db); >+ } >+ return resultColumn; >+ } >+ >+ private static int getColumnForName(ValueEval nameValueEval, TwoDEval db) >+ throws EvaluationException { >+ String name = getStringFromValueEval(nameValueEval); >+ return getColumnForString(db, name); >+ } >+ >+ /** >+ * For a given database returns the column number for a column heading. >+ * >+ * @param db Database. >+ * @param name Column heading. >+ * @return Corresponding column number. >+ * @throws EvaluationException If it's not possible to turn all headings into strings. >+ */ >+ private static int getColumnForString(TwoDEval db,String name) >+ throws EvaluationException { >+ int resultColumn = -1; >+ for(int column = 0; column < db.getWidth(); ++column) { >+ ValueEval columnNameValueEval = db.getValue(0, column); >+ String columnName = getStringFromValueEval(columnNameValueEval); >+ if(name.equals(columnName)) { >+ resultColumn = column; >+ break; >+ } >+ } >+ return resultColumn; >+ } >+ >+ /** >+ * Checks a row in a database against a condition database. >+ * >+ * @param db Database. >+ * @param row The row in the database to check. >+ * @param cdb The condition database to use for checking. >+ * @return Whether the row matches the conditions. >+ * @throws EvaluationException If references could not be resolved or comparison >+ * operators and operands didn't match. >+ */ >+ private static boolean fullfillsConditions(TwoDEval db, int row, TwoDEval cdb) >+ throws EvaluationException { >+ // Only one row must match to accept the input, so rows are ORed. >+ // Each row is made up of cells where each cell is a condition, >+ // all have to match, so they are ANDed. >+ for(int conditionRow = 1; conditionRow < cdb.getHeight(); ++conditionRow) { >+ boolean matches = true; >+ for(int column = 0; column < cdb.getWidth(); ++column) { // columns are ANDed >+ // Whether the condition column matches a database column, if not it's a >+ // special column that accepts formulas. >+ boolean columnCondition = true; >+ ValueEval condition = null; >+ try { >+ // The condition to apply. >+ condition = solveReference(cdb.getValue(conditionRow, column)); >+ } >+ catch (java.lang.RuntimeException e) { >+ // It might be a special formula, then it is ok if it fails. >+ columnCondition = false; >+ } >+ // If the condition is empty it matches. >+ if(condition instanceof BlankEval) >+ continue; >+ // The column in the DB to apply the condition to. >+ ValueEval targetHeader = solveReference(cdb.getValue(0, column)); >+ targetHeader = solveReference(targetHeader); >+ >+ >+ if(!(targetHeader instanceof StringValueEval)) >+ columnCondition = false; >+ else if (getColumnForName(targetHeader, db) == -1) >+ // No column found, it's again a special column that accepts formulas. >+ columnCondition = false; >+ >+ if(columnCondition == true) { // normal column condition >+ // Should not throw, checked above. >+ ValueEval target = db.getValue( >+ row, getColumnForName(targetHeader, db)); >+ // Must be a string. >+ String conditionString = getStringFromValueEval(condition); >+ if(!testNormalCondition(target, conditionString)) { >+ matches = false; >+ break; >+ } >+ } >+ else { // It's a special formula condition. >+ throw new NotImplementedException( >+ "D* function with formula conditions"); >+ } >+ } >+ if (matches == true) { >+ return true; >+ } >+ } >+ return false; >+ } >+ >+ /** >+ * Test a value against a simple (< > <= >= = starts-with) condition string. >+ * >+ * @param value The value to check. >+ * @param condition The condition to check for. >+ * @return Whether the condition holds. >+ * @throws EvaluationException If comparison operator and operands don't match. >+ */ >+ private static boolean testNormalCondition(ValueEval value, String condition) >+ throws EvaluationException { >+ if(condition.startsWith("<")) { // It's a </<= condition. >+ String number = condition.substring(1); >+ if(number.startsWith("=")) { >+ number = number.substring(1); >+ return testNumericCondition(value, operator.smallerEqualThan, number); >+ } >+ else >+ return testNumericCondition(value, operator.smallerThan, number); >+ } >+ else if(condition.startsWith(">")) { // It's a >/>= condition. >+ String number = condition.substring(1); >+ if(number.startsWith("=")) { >+ number = number.substring(1); >+ return testNumericCondition(value, operator.largerEqualThan, number); >+ } >+ else >+ return testNumericCondition(value, operator.largerThan, number); >+ } >+ else if(condition.startsWith("=")) { // It's a = condition. >+ String stringOrNumber = condition.substring(1); >+ // Distinguish between string and number. >+ boolean itsANumber = false; >+ try { >+ Integer.parseInt(stringOrNumber); >+ itsANumber = true; >+ } catch (NumberFormatException e) { // It's not an int. >+ try { >+ Double.parseDouble(stringOrNumber); >+ itsANumber = true; >+ } catch (NumberFormatException e2) { // It's a string. >+ itsANumber = false; >+ } >+ } >+ if(itsANumber) { >+ return testNumericCondition(value, operator.equal, stringOrNumber); >+ } >+ else { // It's a string. >+ String valueString = getStringFromValueEval(value); >+ return stringOrNumber.equals(valueString); >+ } >+ } >+ else { // It's a text starts-with condition. >+ String valueString = getStringFromValueEval(value); >+ return valueString.startsWith(condition); >+ } >+ } >+ >+ /** >+ * Test whether a value matches a numeric condition. >+ * @param valueEval Value to check. >+ * @param op Comparator to use. >+ * @param condition Value to check against. >+ * @return whether the condition holds. >+ * @throws EvaluationException If it's impossible to turn the condition into a number. >+ */ >+ private static boolean testNumericCondition( >+ ValueEval valueEval, operator op, String condition) >+ throws EvaluationException { >+ // Construct double from ValueEval. >+ if(!(valueEval instanceof NumericValueEval)) >+ return false; >+ double value = ((NumericValueEval)valueEval).getNumberValue(); >+ >+ // Construct double from condition. >+ double conditionValue = 0.0; >+ try { >+ int intValue = Integer.parseInt(condition); >+ conditionValue = intValue; >+ } catch (NumberFormatException e) { // It's not an int. >+ try { >+ conditionValue = Double.parseDouble(condition); >+ } catch (NumberFormatException e2) { // It's not a double. >+ throw new EvaluationException(ErrorEval.VALUE_INVALID); >+ } >+ } >+ >+ int result = NumberComparer.compare(value, conditionValue); >+ switch(op) { >+ case largerThan: >+ return result > 0; >+ case largerEqualThan: >+ return result >= 0; >+ case smallerThan: >+ return result < 0; >+ case smallerEqualThan: >+ return result <= 0; >+ case equal: >+ return result == 0; >+ } >+ return false; // Can not be reached. >+ } >+ >+ /** >+ * Takes a ValueEval and tries to retrieve a String value from it. >+ * It tries to resolve references if there are any. >+ * >+ * @param value ValueEval to retrieve the string from. >+ * @return String corresponding to the given ValueEval. >+ * @throws EvaluationException If it's not possible to retrieve a String value. >+ */ >+ private static String getStringFromValueEval(ValueEval value) >+ throws EvaluationException { >+ value = solveReference(value); >+ if(value instanceof BlankEval) >+ return ""; >+ if(!(value instanceof StringValueEval)) >+ throw new EvaluationException(ErrorEval.VALUE_INVALID); >+ return ((StringValueEval)value).getStringValue(); >+ } >+} >diff --git a/src/java/org/apache/poi/ss/formula/functions/IDStarAlgorithm.java b/src/java/org/apache/poi/ss/formula/functions/IDStarAlgorithm.java >new file mode 100644 >index 0000000..21e7f94 >--- /dev/null >+++ b/src/java/org/apache/poi/ss/formula/functions/IDStarAlgorithm.java >@@ -0,0 +1,27 @@ >+package org.apache.poi.ss.formula.functions; >+ >+import org.apache.poi.ss.formula.eval.ValueEval; >+ >+/** >+ * Interface specifying how an algorithm to be used by {@link DStarRunner} should look like. >+ * Each implementing class should correspond to one of the D* functions. >+ */ >+public interface IDStarAlgorithm { >+ /** >+ * Reset the state of this algorithm. >+ * This is called before each run through a database. >+ */ >+ void reset(); >+ /** >+ * Process a match that is found during a run through a database. >+ * @param eval ValueEval of the cell in the matching row. References will already be resolved. >+ * @return Whether we should continue iterating through the database. >+ */ >+ boolean processMatch(ValueEval eval); >+ /** >+ * Return a result ValueEval that will be the result of the calculation. >+ * This is always called at the end of a run through the database. >+ * @return a ValueEval >+ */ >+ ValueEval getResult(); >+} >diff --git a/src/testcases/org/apache/poi/ss/formula/functions/TestDGetFunctionsFromSpreadsheet.java b/src/testcases/org/apache/poi/ss/formula/functions/TestDGetFunctionsFromSpreadsheet.java >new file mode 100644 >index 0000000..ebc9f7a >--- /dev/null >+++ b/src/testcases/org/apache/poi/ss/formula/functions/TestDGetFunctionsFromSpreadsheet.java >@@ -0,0 +1,27 @@ >+/* ==================================================================== >+ 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.ss.formula.functions; >+ >+/** >+* Tests DGET() as loaded from a test data spreadsheet. >+*/ >+public class TestDGetFunctionsFromSpreadsheet extends BaseTestFunctionsFromSpreadsheet { >+ >+ protected String getFilename() { >+ return "DGet.xls"; >+ } >+} >diff --git a/src/testcases/org/apache/poi/ss/formula/functions/TestDStarFunctionsFromSpreadsheet.java b/src/testcases/org/apache/poi/ss/formula/functions/TestDStarFunctionsFromSpreadsheet.java >new file mode 100644 >index 0000000..da9375d >--- /dev/null >+++ b/src/testcases/org/apache/poi/ss/formula/functions/TestDStarFunctionsFromSpreadsheet.java >@@ -0,0 +1,27 @@ >+/* ==================================================================== >+ 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.ss.formula.functions; >+ >+/** >+* Tests D*() functions as loaded from a test data spreadsheet. >+*/ >+public class TestDStarFunctionsFromSpreadsheet extends BaseTestFunctionsFromSpreadsheet { >+ >+ protected String getFilename() { >+ return "DStar.xls"; >+ } >+} >diff --git a/test-data/spreadsheet/DGet.xls b/test-data/spreadsheet/DGet.xls >new file mode 100644 >index 0000000000000000000000000000000000000000..e576d73a0327a5e5574f07e272ac0480f14d5586 >GIT binary patch >literal 39936 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 > >literal 0 >HcmV?d00001 > >diff --git a/test-data/spreadsheet/DStar.xls b/test-data/spreadsheet/DStar.xls >new file mode 100644 >index 0000000000000000000000000000000000000000..0c89261426a89341c1521de4db5a393b5fa3ee9a >GIT binary patch >literal 31232 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 > >literal 0 >HcmV?d00001 > >-- >1.8.4.msysgit.0 >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Raw
Actions:
View
Attachments on
bug 57007
: 32046