Browse Source

Bug 57003: Add implementation of function FIXED

pull/79/head
antony-liu 10 years ago
parent
commit
a25919fad0
  1. 2
      main/Resources/functionMetadata.txt
  2. 2
      main/SS/Formula/Eval/FunctionEval.cs
  3. 118
      main/SS/Formula/Functions/Fixed.cs
  4. 1
      main/main vs10.csproj
  5. 130
      testcases/main/SS/Formula/Functions/TestFixed.cs
  6. 40
      testcases/main/SS/Formula/Functions/TestFixedFunctionsFromSpreadsheet.cs
  7. 2
      testcases/main/testcases vs10.csproj

2
main/Resources/functionMetadata.txt

@ -184,7 +184,7 @@
235 DGET 3 3 V R R R
244 INFO 1 1 V V
# New Built-In Sheet Functions in BIFF4
14 FIXED 2 3 V V V V x
14 FIXED 1 3 V V V V x
204 USDOLLAR 1 2 V V V x
215 DBCS 1 1 V V x
216 RANK 2 3 V V R V

2
main/SS/Formula/Eval/FunctionEval.cs

@ -108,7 +108,7 @@ namespace NPOI.SS.Formula.Eval
retval[11] = new Npv(); // NPV
retval[12] = AggregateFunction.STDEV; // STDEV
retval[13] = NumericFunction.DOLLAR; // DOLLAR
retval[14] = new NotImplementedFunction("FIXED"); // FIXED
retval[14] = new Fixed(); // FIXED
retval[15] = NumericFunction.SIN; // SIN
retval[16] = NumericFunction.COS; // COS
retval[17] = NumericFunction.TAN; // TAN

118
main/SS/Formula/Functions/Fixed.cs

@ -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();
}
}
}
}

1
main/main vs10.csproj

@ -214,6 +214,7 @@
<Compile Include="SS\Formula\Functions\Errortype.cs" />
<Compile Include="SS\Formula\Functions\FactDouble.cs" />
<Compile Include="SS\Formula\Functions\Finance.cs" />
<Compile Include="SS\Formula\Functions\Fixed.cs" />
<Compile Include="SS\Formula\Functions\Hex2Dec.cs" />
<Compile Include="SS\Formula\Functions\Hyperlink.cs" />
<Compile Include="SS\Formula\Functions\Imaginary.cs" />

130
testcases/main/SS/Formula/Functions/TestFixed.cs

@ -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());
}
}
}

40
testcases/main/SS/Formula/Functions/TestFixedFunctionsFromSpreadsheet.cs

@ -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";
}
}
}
}

2
testcases/main/testcases vs10.csproj

@ -172,6 +172,8 @@
<Compile Include="SS\Formula\Functions\BaseTestFunctionsFromSpreadsheet.cs" />
<Compile Include="SS\Formula\Functions\TestEOMonth.cs" />
<Compile Include="SS\Formula\Functions\TestFactDoubleFunctionsFromSpreadsheet.cs" />
<Compile Include="SS\Formula\Functions\TestFixed.cs" />
<Compile Include="SS\Formula\Functions\TestFixedFunctionsFromSpreadsheet.cs" />
<Compile Include="SS\Formula\Functions\TestHex2Dec.cs" />
<Compile Include="SS\Formula\Functions\TestImaginaryFunctionsFromSpreadsheet.cs" />
<Compile Include="SS\Formula\Functions\TestImRealFunctionsFromSpreadsheet.cs" />

Loading…
Cancel
Save