
7 changed files with 293 additions and 2 deletions
-
2main/Resources/functionMetadata.txt
-
2main/SS/Formula/Eval/FunctionEval.cs
-
118main/SS/Formula/Functions/Fixed.cs
-
1main/main vs10.csproj
-
130testcases/main/SS/Formula/Functions/TestFixed.cs
-
40testcases/main/SS/Formula/Functions/TestFixedFunctionsFromSpreadsheet.cs
-
2testcases/main/testcases vs10.csproj
@ -0,0 +1,118 @@ |
|||
/* ==================================================================== |
|||
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. |
|||
==================================================================== */ |
|||
|
|||
namespace NPOI.SS.Formula.Functions |
|||
{ |
|||
using NPOI.SS.Formula.Eval; |
|||
using System; |
|||
|
|||
public class Fixed : Function1Arg, Function2Arg, Function3Arg |
|||
{ |
|||
|
|||
public ValueEval Evaluate( |
|||
int srcRowIndex, int srcColumnIndex, |
|||
ValueEval arg0, ValueEval arg1, ValueEval arg2) |
|||
{ |
|||
return doFixed(arg0, arg1, arg2, srcRowIndex, srcColumnIndex); |
|||
} |
|||
|
|||
|
|||
public ValueEval Evaluate( |
|||
int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1) |
|||
{ |
|||
return doFixed(arg0, arg1, BoolEval.FALSE, srcRowIndex, srcColumnIndex); |
|||
} |
|||
|
|||
|
|||
public ValueEval Evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0) |
|||
{ |
|||
return doFixed(arg0, new NumberEval(2), BoolEval.FALSE, srcRowIndex, srcColumnIndex); |
|||
} |
|||
|
|||
|
|||
public ValueEval Evaluate(ValueEval[] args, int srcRowIndex, int srcColumnIndex) |
|||
{ |
|||
switch (args.Length) |
|||
{ |
|||
case 1: |
|||
return doFixed(args[0], new NumberEval(2), BoolEval.FALSE, |
|||
srcRowIndex, srcColumnIndex); |
|||
case 2: |
|||
return doFixed(args[0], args[1], BoolEval.FALSE, |
|||
srcRowIndex, srcColumnIndex); |
|||
case 3: |
|||
return doFixed(args[0], args[1], args[2], srcRowIndex, srcColumnIndex); |
|||
} |
|||
return ErrorEval.VALUE_INVALID; |
|||
} |
|||
|
|||
private ValueEval doFixed( |
|||
ValueEval numberParam, ValueEval placesParam, |
|||
ValueEval skipThousandsSeparatorParam, |
|||
int srcRowIndex, int srcColumnIndex) |
|||
{ |
|||
try |
|||
{ |
|||
ValueEval numberValueEval = |
|||
OperandResolver.GetSingleValue( |
|||
numberParam, srcRowIndex, srcColumnIndex); |
|||
decimal number = (decimal)OperandResolver.CoerceValueToDouble(numberValueEval); |
|||
ValueEval placesValueEval = |
|||
OperandResolver.GetSingleValue( |
|||
placesParam, srcRowIndex, srcColumnIndex); |
|||
int places = OperandResolver.CoerceValueToInt(placesValueEval); |
|||
ValueEval skipThousandsSeparatorValueEval = |
|||
OperandResolver.GetSingleValue( |
|||
skipThousandsSeparatorParam, srcRowIndex, srcColumnIndex); |
|||
bool? skipThousandsSeparator = |
|||
OperandResolver.CoerceValueToBoolean( |
|||
skipThousandsSeparatorValueEval, false); |
|||
|
|||
// Round number to respective places.
|
|||
//number = number.SetScale(places, RoundingMode.HALF_UP);
|
|||
if (places < 0) |
|||
{ |
|||
number = number / (decimal)Math.Pow(10, -places); |
|||
number = Math.Round(number, 0); |
|||
number = number * (decimal)Math.Pow(10, -places); |
|||
} |
|||
else |
|||
number = Math.Round(number, places); |
|||
|
|||
// Format number conditionally using a thousands separator.
|
|||
/*NumberFormat nf = NumberFormat.GetNumberInstance(Locale.US); |
|||
DecimalFormat formatter = (DecimalFormat)nf; |
|||
formatter.setGroupingUsed(!skipThousandsSeparator); |
|||
formatter.setMinimumFractionDigits(places >= 0 ? places : 0); |
|||
formatter.setMaximumFractionDigits(places >= 0 ? places : 0); |
|||
String numberString = formatter.Format(number);*/ |
|||
//System.Globalization.CultureInfo culture = System.Globalization.CultureInfo.CurrentCulture;
|
|||
string numberString = skipThousandsSeparator!=null && skipThousandsSeparator.Value ? |
|||
number.ToString(places > 0 ? "F" + places : "F0") |
|||
: number.ToString(places > 0 ? "N" + places : "N0", System.Globalization.CultureInfo.InvariantCulture); |
|||
// Return the result as a StringEval.
|
|||
|
|||
return new StringEval(numberString); |
|||
} |
|||
catch (EvaluationException e) |
|||
{ |
|||
return e.GetErrorEval(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
} |
@ -0,0 +1,130 @@ |
|||
/* ==================================================================== |
|||
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. |
|||
==================================================================== */ |
|||
|
|||
namespace NPOI.SS.Formula.Functions |
|||
{ |
|||
using System; |
|||
using NPOI.HSSF.UserModel; |
|||
using NPOI.SS.Formula.Eval; |
|||
using NPOI.SS.UserModel; |
|||
using NUnit.Framework; |
|||
|
|||
[TestFixture] |
|||
public class TestFixed |
|||
{ |
|||
|
|||
private HSSFCell cell11; |
|||
private HSSFFormulaEvaluator Evaluator; |
|||
|
|||
[SetUp] |
|||
public void SetUp() |
|||
{ |
|||
HSSFWorkbook wb = new HSSFWorkbook(); |
|||
try |
|||
{ |
|||
HSSFSheet sheet = wb.CreateSheet("new sheet") as HSSFSheet; |
|||
cell11 = sheet.CreateRow(0).CreateCell(0) as HSSFCell; |
|||
cell11.SetCellType(CellType.Formula); |
|||
Evaluator = new HSSFFormulaEvaluator(wb); |
|||
} |
|||
finally |
|||
{ |
|||
//wb.Close();
|
|||
} |
|||
} |
|||
|
|||
[Test] |
|||
public void TestValid() |
|||
{ |
|||
// thousands separator
|
|||
Confirm("FIXED(1234.56789,2,TRUE)", "1234.57"); |
|||
Confirm("FIXED(1234.56789,2,FALSE)", "1,234.57"); |
|||
// rounding
|
|||
Confirm("FIXED(1.8,0,TRUE)", "2"); |
|||
Confirm("FIXED(1.2,0,TRUE)", "1"); |
|||
Confirm("FIXED(1.5,0,TRUE)", "2"); |
|||
Confirm("FIXED(1,0,TRUE)", "1"); |
|||
// fractional digits
|
|||
Confirm("FIXED(1234.56789,7,TRUE)", "1234.5678900"); |
|||
Confirm("FIXED(1234.56789,0,TRUE)", "1235"); |
|||
Confirm("FIXED(1234.56789,-1,TRUE)", "1230"); |
|||
// less than three arguments
|
|||
Confirm("FIXED(1234.56789)", "1,234.57"); |
|||
Confirm("FIXED(1234.56789,3)", "1,234.568"); |
|||
// invalid arguments
|
|||
ConfirmValueError("FIXED(\"invalid\")"); |
|||
ConfirmValueError("FIXED(1,\"invalid\")"); |
|||
ConfirmValueError("FIXED(1,2,\"invalid\")"); |
|||
// strange arguments
|
|||
Confirm("FIXED(1000,2,8)", "1000.00"); |
|||
Confirm("FIXED(1000,2,0)", "1,000.00"); |
|||
// corner cases
|
|||
Confirm("FIXED(1.23456789012345,15,TRUE)", "1.234567890123450"); |
|||
// Seems POI accepts longer numbers than Excel does, excel Trims the
|
|||
// number to 15 digits and Removes the "9" in the formula itself.
|
|||
// Not the fault of FIXED though.
|
|||
// Confirm("FIXED(1.234567890123459,15,TRUE)", "1.234567890123450");
|
|||
Confirm("FIXED(60,-2,TRUE)", "100"); |
|||
Confirm("FIXED(10,-2,TRUE)", "0"); |
|||
// rounding propagation
|
|||
Confirm("FIXED(99.9,0,TRUE)", "100"); |
|||
} |
|||
|
|||
[Test] |
|||
public void TestOptionalParams() |
|||
{ |
|||
Fixed fixedFunc = new Fixed(); |
|||
ValueEval Evaluate = fixedFunc.Evaluate(0, 0, new NumberEval(1234.56789)); |
|||
Assert.IsTrue(Evaluate is StringEval); |
|||
Assert.AreEqual("1,234.57", ((StringEval)Evaluate).StringValue); |
|||
|
|||
Evaluate = fixedFunc.Evaluate(0, 0, new NumberEval(1234.56789), new NumberEval(1)); |
|||
Assert.IsTrue(Evaluate is StringEval); |
|||
Assert.AreEqual("1,234.6", ((StringEval)Evaluate).StringValue); |
|||
|
|||
Evaluate = fixedFunc.Evaluate(0, 0, new NumberEval(1234.56789), new NumberEval(1), BoolEval.TRUE); |
|||
Assert.IsTrue(Evaluate is StringEval); |
|||
Assert.AreEqual("1234.6", ((StringEval)Evaluate).StringValue); |
|||
|
|||
Evaluate = fixedFunc.Evaluate(new ValueEval[] { }, 1, 1); |
|||
Assert.IsTrue(Evaluate is ErrorEval); |
|||
|
|||
Evaluate = fixedFunc.Evaluate(new ValueEval[] { new NumberEval(1), new NumberEval(1), new NumberEval(1), new NumberEval(1) }, 1, 1); |
|||
Assert.IsTrue(Evaluate is ErrorEval); |
|||
} |
|||
|
|||
private void Confirm(String formulaText, String expectedResult) |
|||
{ |
|||
cell11.CellFormula = (/*setter*/formulaText); |
|||
Evaluator.ClearAllCachedResultValues(); |
|||
CellValue cv = Evaluator.Evaluate(cell11); |
|||
Assert.AreEqual(CellType.String, cv.CellType, "Wrong result type: " + cv.FormatAsString()); |
|||
String actualValue = cv.StringValue; |
|||
Assert.AreEqual(expectedResult, actualValue); |
|||
} |
|||
|
|||
private void ConfirmValueError(String formulaText) |
|||
{ |
|||
cell11.CellFormula = (/*setter*/formulaText); |
|||
Evaluator.ClearAllCachedResultValues(); |
|||
CellValue cv = Evaluator.Evaluate(cell11); |
|||
Assert.IsTrue(cv.CellType == CellType.Error |
|||
&& cv.ErrorValue == ErrorConstants.ERROR_VALUE, "Wrong result type: " + cv.FormatAsString()); |
|||
} |
|||
} |
|||
} |
|||
|
@ -0,0 +1,40 @@ |
|||
/* ==================================================================== |
|||
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. |
|||
==================================================================== */ |
|||
|
|||
namespace TestCases.SS.Formula.Functions |
|||
{ |
|||
using System; |
|||
using NUnit.Framework; |
|||
|
|||
/** |
|||
* Tests FIXED() as loaded from a test data spreadsheet. |
|||
*/ |
|||
[TestFixture] |
|||
public class TestFixedFunctionsFromSpreadsheet : BaseTestFunctionsFromSpreadsheet |
|||
{ |
|||
|
|||
|
|||
protected override String Filename |
|||
{ |
|||
get |
|||
{ |
|||
return "57003-FixedFunctionTestCaseData.xls"; |
|||
} |
|||
} |
|||
} |
|||
|
|||
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue