FPSpreadsheet: Fix error propagation in ISERROR formula. Fix Excel pecularities in DATE and TIME formulas. Add formula calculation unit tests.
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@9597 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
parent
e5e12455ea
commit
c5b8b6077c
@ -522,7 +522,7 @@ type
|
||||
FArgumentNodes: TsExprArgumentArray;
|
||||
FargumentParams: TsExprParameterArray;
|
||||
protected
|
||||
function CalcParams: TsErrorValue;
|
||||
procedure CalcParams;
|
||||
public
|
||||
constructor CreateFunction(AParser: TsExpressionParser;
|
||||
AID: TsExprIdentifierDef; const Args: TsExprArgumentArray); virtual;
|
||||
@ -858,9 +858,9 @@ function BuiltinIdentifiers: TsBuiltInExpressionManager;
|
||||
function ArgToBoolean(Arg: TsExpressionResult): Boolean;
|
||||
function ArgToCell(Arg: TsExpressionResult): PCell;
|
||||
function ArgToDateTime(Arg: TsExpressionResult): TDateTime;
|
||||
function ArgToError(Arg: TsExpressionResult): TsErrorValue;
|
||||
function ArgToInt(Arg: TsExpressionResult): Integer;
|
||||
function ArgToFloat(Arg: TsExpressionResult): TsExprFloat;
|
||||
function ArgToFloatOrNaN(Arg: TsExpressionResult): TsExprFloat;
|
||||
function ArgToString(Arg: TsExpressionResult): String;
|
||||
procedure ArgsToFloatArray(const Args: TsExprParameterArray;
|
||||
out AData: TsExprFloatArray; out AError: TsErrorValue);
|
||||
@ -875,6 +875,7 @@ function ErrorResult(const AValue: TsErrorValue): TsExpressionResult;
|
||||
function FloatResult(const AValue: TsExprFloat): TsExpressionResult;
|
||||
function IntegerResult(const AValue: Integer): TsExpressionResult;
|
||||
function IsBlank(const AValue: TsExpressionResult): Boolean;
|
||||
function IsError(const AValue: TsExpressionResult; out AError: TsExpressionResult): boolean;
|
||||
function IsInteger(const AValue: TsExpressionResult): Boolean;
|
||||
function IsString(const AValue: TsExpressionResult): Boolean;
|
||||
function StringResult(const AValue: String): TsExpressionResult;
|
||||
@ -4134,21 +4135,13 @@ begin
|
||||
Result := FID.Name + S;
|
||||
end;
|
||||
|
||||
function TsFunctionExprNode.CalcParams: TsErrorValue;
|
||||
procedure TsFunctionExprNode.CalcParams;
|
||||
var
|
||||
i : Integer;
|
||||
begin
|
||||
for i := 0 to Length(FArgumentParams)-1 do
|
||||
if FArgumentNodes[i] <> nil then
|
||||
begin
|
||||
FArgumentNodes[i].GetNodeValue(FArgumentParams[i]);
|
||||
if FArgumentParams[i].ResultType = rtError then
|
||||
begin
|
||||
Result := FArgumentParams[i].ResError;
|
||||
exit;
|
||||
end;
|
||||
end;
|
||||
Result := errOK;
|
||||
end;
|
||||
|
||||
procedure TsFunctionExprNode.Check;
|
||||
@ -4219,19 +4212,10 @@ begin
|
||||
end;
|
||||
|
||||
procedure TsFunctionCallBackExprNode.GetNodeValue(out AResult: TsExpressionResult);
|
||||
var
|
||||
err: TsErrorValue = errOK;
|
||||
begin
|
||||
AResult.ResultType := NodeType;
|
||||
if Length(FArgumentParams) > 0 then
|
||||
begin
|
||||
err := CalcParams;
|
||||
if err <> errOK then
|
||||
begin
|
||||
AResult := ErrorResult(err);
|
||||
exit;
|
||||
end;
|
||||
end;
|
||||
CalcParams;
|
||||
FCallBack(AResult, FArgumentParams)
|
||||
end;
|
||||
|
||||
@ -4246,19 +4230,10 @@ begin
|
||||
end;
|
||||
|
||||
procedure TFPFunctionEventHandlerExprNode.GetNodeValue(out AResult: TsExpressionResult);
|
||||
var
|
||||
err: TsErrorValue = errOK;
|
||||
begin
|
||||
AResult.ResultType := NodeType;
|
||||
if Length(FArgumentParams) > 0 then
|
||||
begin
|
||||
err := CalcParams;
|
||||
if err <> errOK then
|
||||
begin
|
||||
AResult := ErrorResult(err);
|
||||
exit;
|
||||
end;
|
||||
end;
|
||||
CalcParams;
|
||||
FCallBack(AResult, FArgumentParams)
|
||||
end;
|
||||
|
||||
@ -4874,7 +4849,7 @@ begin
|
||||
rtInteger : result := Arg.ResInteger;
|
||||
rtDateTime : result := Arg.ResDateTime;
|
||||
rtFloat : result := Arg.ResFloat;
|
||||
rtBoolean : if Arg.ResBoolean then Result := 1.0;
|
||||
rtBoolean : if Arg.ResBoolean then Result := 1.0 else Result := 0.0;
|
||||
rtString,
|
||||
rtHyperlink : TryStrToFloat(ArgToString(Arg), Result);
|
||||
rtError : Result := NaN;
|
||||
@ -4887,7 +4862,7 @@ begin
|
||||
cctDateTime:
|
||||
Result := cell^.DateTimeValue;
|
||||
cctBool:
|
||||
if cell^.BoolValue then result := 1.0;
|
||||
if cell^.BoolValue then Result := 1.0 else Result := 0.0;
|
||||
cctUTF8String:
|
||||
begin
|
||||
fs := (Arg.Worksheet as TsWorksheet).Workbook.FormatSettings;
|
||||
@ -4902,6 +4877,47 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
{ Converts the expression result to a floating point value. Unlike ArgToFloat,
|
||||
the return value is NaN in case of non-numeric results.
|
||||
Booleans are rejected, strings are accepted only when they represent a number.
|
||||
DateTimes are accepted. }
|
||||
function ArgToFloatOrNaN(Arg: TsExpressionResult): TsExprFloat;
|
||||
var
|
||||
cell: PCell;
|
||||
s: String;
|
||||
fs: TFormatSettings;
|
||||
begin
|
||||
Result := NaN;
|
||||
case Arg.ResultType of
|
||||
rtInteger : Result := Arg.ResInteger;
|
||||
rtDateTime : Result := Arg.ResDateTime;
|
||||
rtFloat : Result := Arg.ResFloat;
|
||||
rtString,
|
||||
rtHyperlink : if not TryStrToFloat(ArgToString(Arg), Result, fs) then Result := NaN;
|
||||
rtCell : begin
|
||||
cell := ArgToCell(Arg);
|
||||
if Assigned(cell) then
|
||||
case cell^.ContentType of
|
||||
cctNumber:
|
||||
Result := cell^.NumberValue;
|
||||
cctDateTime:
|
||||
Result := cell^.DateTimeValue;
|
||||
cctUTF8String:
|
||||
begin
|
||||
fs := (Arg.Worksheet as TsWorksheet).Workbook.FormatSettings;
|
||||
s := cell^.UTF8StringValue;
|
||||
if not TryStrToFloat(s, Result, fs) then
|
||||
Result := NaN;
|
||||
end;
|
||||
otherwise // bool, error
|
||||
;
|
||||
end;
|
||||
end;
|
||||
otherwise // bool, error
|
||||
;
|
||||
end;
|
||||
end;
|
||||
|
||||
function ArgToDateTime(Arg: TsExpressionResult): TDateTime;
|
||||
var
|
||||
cell: PCell;
|
||||
@ -4927,20 +4943,29 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
function ArgToError(Arg: TsExpressionResult): TsErrorValue;
|
||||
{ Returns true, if AValue contains an error result, and the error result code
|
||||
is passed on to AError.
|
||||
Otherweise the return value is false, and AError is undefined. }
|
||||
function IsError(const AValue: TsExpressionResult; out AError: TsExpressionResult): Boolean;
|
||||
var
|
||||
cell: PCell;
|
||||
begin
|
||||
Result := errOK;
|
||||
if Arg.ResultType = rtError then
|
||||
Result := Arg.ResError
|
||||
else
|
||||
if Arg.ResultType = rtCell then
|
||||
Result := true;
|
||||
if AValue.ResultType = rtError then
|
||||
begin
|
||||
cell := ArgToCell(Arg);
|
||||
if Assigned(cell) and (cell^.ContentType = cctError) then
|
||||
Result := cell^.ErrorValue;
|
||||
AError := ErrorResult(AValue.ResError);
|
||||
exit;
|
||||
end;
|
||||
if AValue.ResultType = rtCell then
|
||||
begin
|
||||
cell := ArgToCell(AValue);
|
||||
if Assigned(cell) and (cell^.ContentType = cctError) then
|
||||
begin
|
||||
AError := ErrorResult(cell^.ErrorValue);
|
||||
exit;
|
||||
end;
|
||||
end;
|
||||
Result := false;
|
||||
end;
|
||||
|
||||
function ArgToString(Arg: TsExpressionResult): String;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -194,6 +194,7 @@ type
|
||||
function ReadBiDiMode(ACell: PCell): TsBiDiMode;
|
||||
function ReadCellProtection(ACell: PCell): TsCellProtections;
|
||||
function ReadDoNotPrintCell(ACell: PCell): Boolean;
|
||||
function IsTrueValue(ACell: PCell): Boolean;
|
||||
|
||||
function IsEmpty: Boolean;
|
||||
|
||||
|
@ -118,6 +118,13 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
Returns TRUE only if the cell value is a boolean with value TRUE.
|
||||
-------------------------------------------------------------------------------}
|
||||
function TsWorksheet.IsTrueValue(ACell: PCell): Boolean;
|
||||
begin
|
||||
Result := (ACell <> nil) and (ACell^.ContentType = cctBool) and ACell^.BoolValue;
|
||||
end;
|
||||
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
Determines which borders are drawn around a specific cell
|
||||
|
610
components/fpspreadsheet/unit-tests/common/calcformulatests.pas
Normal file
610
components/fpspreadsheet/unit-tests/common/calcformulatests.pas
Normal file
@ -0,0 +1,610 @@
|
||||
unit calcformulatests;
|
||||
|
||||
{$mode objfpc}{$H+}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils, fpcunit, testutils, testregistry,
|
||||
fpstypes, fpspreadsheet, fpsexprparser;
|
||||
|
||||
type
|
||||
|
||||
TCalcFormulaTests = class(TTestCase)
|
||||
private
|
||||
FWorkbook: TsWorkbook;
|
||||
FWorksheet: TsWorksheet;
|
||||
protected
|
||||
// Set up expected values:
|
||||
procedure SetUp; override;
|
||||
procedure TearDown; override;
|
||||
published
|
||||
procedure Test_ABS;
|
||||
procedure Test_CEILING;
|
||||
procedure Test_DATE;
|
||||
procedure Test_EVEN;
|
||||
procedure Test_FLOOR;
|
||||
procedure Test_ISERROR;
|
||||
procedure Test_MATCH;
|
||||
procedure Test_ROUND;
|
||||
procedure Test_TIME;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
procedure TCalcFormulaTests.Setup;
|
||||
begin
|
||||
FWorkbook := TsWorkbook.Create;
|
||||
FWorksheet := FWorkbook.AddWorksheet('Sheet1');
|
||||
end;
|
||||
|
||||
procedure TCalcFormulaTests.TearDown;
|
||||
begin
|
||||
FWorkbook.Free;
|
||||
end;
|
||||
|
||||
procedure TCalcFormulaTests.Test_ABS;
|
||||
begin
|
||||
// Positive value
|
||||
FWorksheet.WriteNumber(0, 0, +10);
|
||||
FWorksheet.WriteFormula(0, 1, 'ABS(A1)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(10, FWorksheet.ReadAsNumber(0, 1), 'Formula ABS(10) result mismatch');
|
||||
|
||||
// Negative value
|
||||
FWorksheet.WriteNumber(0, 0, -10);
|
||||
FWorksheet.WriteFormula(0, 1, 'ABS(A1)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(10, FWorksheet.ReadAsNumber(0, 1), 'Formula ABS(-10) result mismatch');
|
||||
|
||||
// Error propagation
|
||||
FWorksheet.WriteFormula(0, 0, '=1/0');
|
||||
FWorksheet.WriteFormula(0, 1, 'ABS(A1)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(STR_ERR_DIVIDE_BY_ZERO, FWorksheet.ReadAsText(0, 1), 'Formula ABS(1/0) result mismatch');
|
||||
|
||||
// Empty argument
|
||||
FWorksheet.WriteBlank(0, 0);
|
||||
FWorksheet.WriteFormula(0, 1, 'ABS(A1)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(0, FWorksheet.ReadAsNumber(0, 1), 'Formula ABS([blank_cell]) result mismatch');
|
||||
end;
|
||||
|
||||
procedure TCalcFormulaTests.Test_CEILING;
|
||||
begin
|
||||
// Examples from https://exceljet.net/functions/ceiling-function
|
||||
FWorksheet.WriteFormula(0, 1, '=CEILING(10,3)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(12, FWorksheet.ReadAsNumber(0, 1), 'Formula #1 CEILING(10,3) result mismatch');
|
||||
|
||||
FWorksheet.WriteFormula(0, 1, '=CEILING(36,7)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(42, FWorksheet.ReadAsNumber(0, 1), 'Formula #2 CEILING(36,7) result mismatch');
|
||||
|
||||
FWorksheet.WriteFormula(0, 1, '=CEILING(610,100)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(700, FWorksheet.ReadAsNumber(0, 1), 'Formula #3 CEILING(610,100) result mismatch');
|
||||
|
||||
// Negative arguments
|
||||
FWorksheet.WriteFormula(0, 1, '=CEILING(-5.4,-1)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(-5, FWorksheet.ReadAsNumber(0, 1), 'Formula #4 CEILING(-5.4,-1) result mismatch');
|
||||
|
||||
// Zero significance
|
||||
FWorksheet.WriteFormula(0, 1, '=CEILING(-5.4,0)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(0, FWorksheet.ReadAsNumber(0, 1), 'Formula #5 CEILING(-5.4,0) result mismatch');
|
||||
|
||||
// Different signs of the arguments
|
||||
FWorksheet.WriteFormula(0, 1, '=CEILING(-5.4,1)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(STR_ERR_OVERFLOW, FWorksheet.ReadAsText(0, 1), 'Formula #6 CEILING(-5.4,1) result mismatch');
|
||||
|
||||
// Arguments as string
|
||||
FWorksheet.WriteFormula(0, 1, '=CEILING("A",1)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(STR_ERR_WRONG_TYPE, FWorksheet.ReadAsText(0, 1), 'Formula #7 CEILING("A",1) result mismatch');
|
||||
FWorksheet.WriteFormula(0, 1, '=CEILING(5.4,"A")');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(STR_ERR_WRONG_TYPE, FWorksheet.ReadAsText(0, 1), 'Formula #8 CEILING(5.4,"A") result mismatch');
|
||||
|
||||
// Arguments as boolean
|
||||
FWorksheet.WriteFormula(0, 1, '=CEILING(TRUE(),1)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(STR_ERR_WRONG_TYPE, FWorksheet.ReadAsText(0, 1), 'Formula #9 CEILING(TRUE(),1) result mismatch');
|
||||
FWorksheet.WriteFormula(0, 1, '=CEILING(5.4, TRUE())');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(STR_ERR_WRONG_TYPE, FWorksheet.ReadAsText(0, 1), 'Formula #10 CEILING(5.4, TRUE()) result mismatch');
|
||||
|
||||
// Arguments with errors
|
||||
FWorksheet.WriteFormula(0, 1, '=CEILING(1/0,1)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(STR_ERR_DIVIDE_BY_ZERO, FWorksheet.ReadAsText(0, 1), 'Formula #11 CEILING(1/0, 1) result mismatch');
|
||||
FWorksheet.WriteFormula(0, 1, '=CEILING(5.4, 1/0)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(STR_ERR_DIVIDE_BY_ZERO, FWorksheet.ReadAsText(0, 1), 'Formula #12 CEILING(5.4, 1/0) result mismatch');
|
||||
end;
|
||||
|
||||
|
||||
procedure TCalcFormulaTests.Test_DATE;
|
||||
var
|
||||
actualDate, expectedDate: TDate;
|
||||
begin
|
||||
// Normal date
|
||||
FWorksheet.WriteFormula(0, 1, '=DATE(2025,1,22)');
|
||||
FWorksheet.CalcFormulas;
|
||||
expectedDate := EncodeDate(2025, 1, 22);
|
||||
FWorksheet.ReadAsDateTime(0, 1, actualDate);
|
||||
CheckEquals(DateToStr(expectedDate), DateToStr(actualDate), '#1 Formula DATE(2025,1,22) result mismatch');
|
||||
|
||||
// Two-digit year
|
||||
FWorksheet.WriteFormula(0, 1, '=DATE(90,1,22)');
|
||||
FWorksheet.CalcFormulas;
|
||||
expectedDate := EncodeDate(1990, 1, 22);
|
||||
FWorksheet.ReadAsDateTime(0, 1, actualDate);
|
||||
CheckEquals(DateToStr(expectedDate), DateToStr(actualDate), '#2 Formula DATE(90,1,22) result mismatch');
|
||||
|
||||
// Negative year
|
||||
FWorksheet.WriteFormula(0, 1, '=DATE(-2000,1,22)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(STR_ERR_OVERFLOW, FWorksheet.ReadAsText(0, 1), '#3 Formula DATE(90,1,22) result mismatch');
|
||||
|
||||
// Too-large year
|
||||
FWorksheet.WriteFormula(0, 1, '=DATE(10000,1,22)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(STR_ERR_OVERFLOW, FWorksheet.ReadAsText(0, 1), '#4 Formula DATE(10000,1,22) result mismatch');
|
||||
|
||||
// Month > 12
|
||||
FWorksheet.WriteFormula(0, 1, '=DATE(2008,14,2)');
|
||||
FWorksheet.CalcFormulas;
|
||||
expectedDate := EncodeDate(2009, 2, 2);
|
||||
FWorksheet.ReadAsDateTime(0, 1, actualDate);
|
||||
CheckEquals(DateToStr(expectedDate), DateToStr(actualDate), '#5 Formula DATE(2008,14,2) result mismatch');
|
||||
|
||||
// Month < 1
|
||||
FWorksheet.WriteFormula(0, 1, '=DATE(2008,-3,2)');
|
||||
FWorksheet.CalcFormulas;
|
||||
expectedDate := EncodeDate(2007, 9, 2);
|
||||
FWorksheet.ReadAsDateTime(0, 1, actualDate);
|
||||
CheckEquals(DateToStr(expectedDate), DateToStr(actualDate), '#6 Formula DATE(2008,-3,2) result mismatch');
|
||||
|
||||
// Day > Days in month
|
||||
FWorksheet.WriteFormula(0, 1, '=DATE(2008,1,35)');
|
||||
FWorksheet.CalcFormulas;
|
||||
expectedDate := EncodeDate(2008, 2, 4);
|
||||
FWorksheet.ReadAsDateTime(0, 1, actualDate);
|
||||
CheckEquals(DateToStr(expectedDate), DateToStr(actualDate), '#7 Formula DATE(2008,1,35) result mismatch');
|
||||
|
||||
// Day < 1
|
||||
FWorksheet.WriteFormula(0, 1, '=DATE(2008,1,-15)');
|
||||
FWorksheet.CalcFormulas;
|
||||
expectedDate := EncodeDate(2007, 12, 16);
|
||||
FWorksheet.ReadAsDateTime(0, 1, actualDate);
|
||||
CheckEquals(DateToStr(expectedDate), DateToStr(actualDate), '#8 Formula DATE(2008,1,-15) result mismatch');
|
||||
|
||||
// Month > 12 and Day > Days in month
|
||||
FWorksheet.WriteFormula(0, 1, '=DATE(2008,14,50)');
|
||||
FWorksheet.CalcFormulas;
|
||||
expectedDate := EncodeDate(2009, 3, 22);
|
||||
FWorksheet.ReadAsDateTime(0, 1, actualDate);
|
||||
CheckEquals(DateToStr(expectedDate), DateToStr(actualDate), '#9 Formula DATE(2008,14,50) result mismatch');
|
||||
|
||||
// Month > 12 and Day < 1
|
||||
FWorksheet.WriteFormula(0, 1, '=DATE(2008,14,-10)');
|
||||
FWorksheet.CalcFormulas;
|
||||
expectedDate := EncodeDate(2009, 1, 21);
|
||||
FWorksheet.ReadAsDateTime(0, 1, actualDate);
|
||||
CheckEquals(DateToStr(expectedDate), DateToStr(actualDate), '#10 Formula DATE(2008,14,-10) result mismatch');
|
||||
|
||||
// Month < 1 and Day > Days in month
|
||||
FWorksheet.WriteFormula(0, 1, '=DATE(2008,-3,50)');
|
||||
FWorksheet.CalcFormulas;
|
||||
expectedDate := EncodeDate(2007,10,20);
|
||||
FWorksheet.ReadAsDateTime(0, 1, actualDate);
|
||||
CheckEquals(DateToStr(expectedDate), DateToStr(actualDate), '#11 Formula DATE(2008,-3,50) result mismatch');
|
||||
|
||||
// Month < 1 and Day < 1 in month
|
||||
FWorksheet.WriteFormula(0, 1, '=DATE(2008,-3,-10)');
|
||||
FWorksheet.CalcFormulas;
|
||||
expectedDate := EncodeDate(2007,8,21);
|
||||
FWorksheet.ReadAsDateTime(0, 1, actualDate);
|
||||
CheckEquals(DateToStr(expectedDate), DateToStr(actualDate), '#12 Formula DATE(2008,-3,-10) result mismatch');
|
||||
|
||||
// Error in year
|
||||
FWorksheet.WriteFormula(0, 1, '=DATE(1/0,1,22)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(STR_ERR_DIVIDE_BY_ZERO, FWorksheet.ReadAsText(0, 1), '#13 Formula DATE(1/0,1,22) result mismatch');
|
||||
|
||||
// Error in month
|
||||
FWorksheet.WriteFormula(0, 1, '=DATE(2025, 1/0, 22)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(STR_ERR_DIVIDE_BY_ZERO, FWorksheet.ReadAsText(0, 1), '#14 Formula DATE(2025, 1/0, 22) result mismatch');
|
||||
|
||||
// Error in day
|
||||
FWorksheet.WriteFormula(0, 1, '=DATE(2025, 1, 1/0)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(STR_ERR_DIVIDE_BY_ZERO, FWorksheet.ReadAsText(0, 1), '#15 Formula DATE(2025, 1, 1/0) result mismatch');
|
||||
end;
|
||||
|
||||
procedure TCalcFormulaTests.Test_EVEN;
|
||||
begin
|
||||
FWorksheet.WriteFormula(0, 1, '=EVEN(1.23)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(2, FWorksheet.ReadAsNumber(0, 1), 'Formula EVEN(1.23) result mismatch');
|
||||
|
||||
FWorksheet.WriteFormula(0, 1, '=EVEN(2.34)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(4, FWorksheet.ReadAsNumber(0, 1), 'Formula EVEN(2.34) result mismatch');
|
||||
|
||||
FWorksheet.WriteFormula(0, 1, '=EVEN(-1.23)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(-2, FWorksheet.ReadAsNumber(0, 1), 'Formula EVEN(-1.23) result mismatch');
|
||||
|
||||
FWorksheet.WriteFormula(0, 1, '=EVEN(-2.34)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(-4, FWorksheet.ReadAsNumber(0, 1), 'Formula EVEN(-2.34) result mismatch');
|
||||
|
||||
FWorksheet.WriteFormula(0, 1, '=EVEN(1/0)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(STR_ERR_DIVIDE_BY_ZERO, FWorksheet.ReadAsText(0, 1), 'Formula EVEN(1/0) result mismatch');
|
||||
end;
|
||||
|
||||
procedure TCalcFormulaTests.Test_FLOOR;
|
||||
begin
|
||||
FWorksheet.WriteFormula(0, 1, '=FLOOR(10,3)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(9, FWorksheet.ReadAsNumber(0, 1), 'Formula #1 FLOOR(10,3) result mismatch');
|
||||
|
||||
FWorksheet.WriteFormula(0, 1, '=FLOOR(36,7)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(35, FWorksheet.ReadAsNumber(0, 1), 'Formula #2 FLOOR(36,7) result mismatch');
|
||||
|
||||
FWorksheet.WriteFormula(0, 1, '=FLOOR(610,100)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(600, FWorksheet.ReadAsNumber(0, 1), 'Formula #3 FLOOR(610,100) result mismatch');
|
||||
|
||||
// Negative value, negative significance
|
||||
FWorksheet.WriteFormula(0, 1, '=FLOOR(-5.4,-2)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(-4, FWorksheet.ReadAsNumber(0, 1), 'Formula #4 FLOOR(-5.4,-2) result mismatch');
|
||||
|
||||
// Negative value, positive significance
|
||||
FWorksheet.WriteFormula(0, 1, '=FLOOR(-5.4,2)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(-6, FWorksheet.ReadAsNumber(0, 1), 'Formula #5 FLOOR(-5.4,2) result mismatch');
|
||||
|
||||
// Positive value, negative significance
|
||||
FWorksheet.WriteFormula(0, 1, '=FLOOR(5.4,-2)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(STR_ERR_OVERFLOW, FWorksheet.ReadAsText(0, 1), 'Formula #6 FLOOR(5.4,-2) result mismatch');
|
||||
|
||||
// Zero significance
|
||||
FWorksheet.WriteFormula(0, 1, '=FLOOR(-5.4,0)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(0, FWorksheet.ReadAsNumber(0, 1), 'Formula #7 FLOOR(-5.4,0) result mismatch');
|
||||
|
||||
// Arguments as string
|
||||
FWorksheet.WriteFormula(0, 1, '=FLOOR("A",1)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(STR_ERR_WRONG_TYPE, FWorksheet.ReadAsText(0, 1), 'Formula #8 FLOOR("A",1) result mismatch');
|
||||
FWorksheet.WriteFormula(0, 1, '=FLOOR(5.4,"A")');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(STR_ERR_WRONG_TYPE, FWorksheet.ReadAsText(0, 1), 'Formula #9 FLOOR(5.4,"A") result mismatch');
|
||||
|
||||
// Arguments as boolean
|
||||
FWorksheet.WriteFormula(0, 1, '=FLOOR(TRUE(),1)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(STR_ERR_WRONG_TYPE, FWorksheet.ReadAsText(0, 1), 'Formula #10 FLOOR(TRUE(),1) result mismatch');
|
||||
FWorksheet.WriteFormula(0, 1, '=FLOOR(5.4, TRUE())');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(STR_ERR_WRONG_TYPE, FWorksheet.ReadAsText(0, 1), 'Formula #11 FLOOR(5.4, TRUE()) result mismatch');
|
||||
|
||||
// Arguments with errors
|
||||
FWorksheet.WriteFormula(0, 1, '=FLOOR(1/0,1)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(STR_ERR_DIVIDE_BY_ZERO, FWorksheet.ReadAsText(0, 1), 'Formula #12 FLOOR(1/0, 1) result mismatch');
|
||||
FWorksheet.WriteFormula(0, 1, '=FLOOR(5.4, 1/0)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(STR_ERR_DIVIDE_BY_ZERO, FWorksheet.ReadAsText(0, 1), 'Formula #13 FLOOR(5.4, 1/0) result mismatch');
|
||||
|
||||
end;
|
||||
|
||||
procedure TCalcFormulaTests.Test_ISERROR;
|
||||
var
|
||||
res: Boolean;
|
||||
begin
|
||||
// Hard coded expression with error
|
||||
FWorksheet.WriteFormula(0, 1, '=ISERROR(1/0)');
|
||||
FWorksheet.CalcFormulas;
|
||||
res := FWorksheet.IsTrueValue(FWorksheet.FindCell(0, 1));
|
||||
CheckEquals(true, res, 'Formula #1 ISERROR(1/0) result mismatch');
|
||||
|
||||
// Hard coded expression without error
|
||||
FWorksheet.WriteFormula(0, 1, '=ISERROR(0/1)');
|
||||
FWorksheet.CalcFormulas;
|
||||
res := FWorksheet.IsTrueValue(FWorksheet.FindCell(0, 1));
|
||||
CheckEquals(false, res, 'Formula #2 ISERROR(0/1) result mismatch');
|
||||
|
||||
// Reference to cell with error
|
||||
FWorksheet.WriteFormula(0, 0, '=1/0');
|
||||
FWorksheet.WriteFormula(0, 1, '=ISERROR(A1)');
|
||||
FWorksheet.CalcFormulas;
|
||||
res := FWorksheet.IsTrueValue(FWorksheet.FindCell(0, 1));
|
||||
CheckEquals(true, res, 'Formula #3 ISERROR(A1) result mismatch');
|
||||
|
||||
// Reference to cell without error
|
||||
FWorksheet.WriteText(0, 0, 'abc');
|
||||
FWorksheet.WriteFormula(0, 1, '=ISERROR(A1)');
|
||||
FWorksheet.CalcFormulas;
|
||||
res := FWorksheet.IsTrueValue(FWorksheet.FindCell(0, 1));
|
||||
CheckEquals(false, res, 'Formula #4 ISERROR(A1) result mismatch');
|
||||
end;
|
||||
|
||||
procedure TCalcFormulaTests.Test_MATCH;
|
||||
begin
|
||||
// *** Match_Type 0, unsorted data in search range
|
||||
|
||||
// Search range to be checked: B1:B4
|
||||
FWorksheet.WriteNumber(0, 1, 10);
|
||||
FWorksheet.WriteNumber(1, 1, 20);
|
||||
FWorksheet.WriteNumber(2, 1, 30);
|
||||
FWorksheet.WriteNumber(3, 1, 15);
|
||||
|
||||
// Search for constant, contained in search range
|
||||
FWorksheet.WriteFormula(0, 2, '=MATCH(10, B1:B4, 0)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(1, FWorksheet.ReadAsNumber(0, 2), 'Formula #1 MATCH mismatch, match_type 0, in range');
|
||||
|
||||
// Search for constant, below search range
|
||||
FWorksheet.WriteFormula(0, 2, '=MATCH(0, B1:B4, 0)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(STR_ERR_ARG_ERROR, FWorksheet.ReadAsText(0, 2), 'Formula #2 MATCH mismatch, match_type 0, below range');
|
||||
|
||||
// Search for constant, above search range
|
||||
FWorksheet.WriteFormula(0, 2, '=MATCH(90, B1:B4, 0)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(STR_ERR_ARG_ERROR, FWorksheet.ReadAsText(0, 2), 'Formula #3 MATCH mismatch, match_type 0, above range');
|
||||
|
||||
// Search for cell with value in range
|
||||
FWorksheet.WriteNumber(0, 0, 20);
|
||||
FWorksheet.WriteFormula(0, 2, '=MATCH(A1, B1:B4, 0)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(2, FWorksheet.ReadAsNumber(0, 2), 'Formula #4 MATCH mismatch, match_type 0, cell in range');
|
||||
FWorksheet.WriteBlank(0, 0);
|
||||
|
||||
// Search for cell, but cell is empty
|
||||
FWorksheet.WriteFormula(0, 2, '=MATCH(A1, B1:B4, 0)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(STR_ERR_ARG_ERROR, FWorksheet.ReadAsText(0, 2), 'Formula #5 MATCH mismatch, match_type 0, empty cell');
|
||||
|
||||
// Search range is empty
|
||||
FWorksheet.WriteFormula(0, 2, '=MATCH(28, D1:D3, 0)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(STR_ERR_ARG_ERROR, FWorksheet.ReadAsText(0, 2), 'Formula #6 MATCH mismatch, match_type -1, empty search range');
|
||||
|
||||
|
||||
// *** Match_Type 1 (find largest value in range <= value), ascending values in search range
|
||||
|
||||
// Search range to be checked: B1:B3
|
||||
FWorksheet.WriteNumber(0, 1, 10);
|
||||
FWorksheet.WriteNumber(1, 1, 20);
|
||||
FWorksheet.WriteNumber(2, 1, 30);
|
||||
FWorksheet.WriteBlank(3, 1);
|
||||
|
||||
// Search for constant, contained in search range
|
||||
FWorksheet.WriteFormula(0, 2, '=MATCH(28, B1:B3, 1)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(2, FWorksheet.ReadAsNumber(0, 2), 'Formula #7 MATCH mismatch, match_type 1, in range');
|
||||
|
||||
// Search for constant, below search range
|
||||
FWorksheet.WriteFormula(0, 2, '=MATCH(8, B1:B3, 1)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(STR_ERR_ARG_ERROR, FWorksheet.ReadAsText(0, 2), 'Formula #8 MATCH mismatch, match_type 1, below range');
|
||||
|
||||
// Search for constant, above search range
|
||||
FWorksheet.WriteFormula(0, 2, '=MATCH(123, B1:B3, 1)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(3, FWorksheet.ReadAsNumber(0, 2), 'Formula MATCH #9 mismatch, match_type 1, above range');
|
||||
|
||||
// Search for cell with value in range
|
||||
FWorksheet.WriteNumber(0, 0, 28);
|
||||
FWorksheet.WriteFormula(0, 2, '=MATCH(A1, B1:B3, 1)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(2, FWorksheet.ReadAsNumber(0, 2), 'Formula MATCH #10 mismatch, match_type 1, cell in range');
|
||||
FWorksheet.WriteBlank(0, 0);
|
||||
|
||||
// Search for cell, but cell is empty
|
||||
FWorksheet.WriteBlank(0, 0);
|
||||
FWorksheet.WriteFormula(0, 2, '=MATCH(A1, B1:B3, 1)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(STR_ERR_ARG_ERROR, FWorksheet.ReadAsText(0, 2), 'Formula #11 MATCH mismatch, match_type 1, empty cell');
|
||||
|
||||
// Search range is empty
|
||||
FWorksheet.WriteFormula(0, 2, '=MATCH(28, D1:D3, -1)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(STR_ERR_ARG_ERROR, FWorksheet.ReadAsText(0, 2), 'Formula MATCH #12 mismatch, match_type -1, empty search range');
|
||||
|
||||
|
||||
// *** Match_Type -1 (find smallest value in range >= value), descending values in search range
|
||||
|
||||
// Search range to be checked: B1:B3
|
||||
FWorksheet.WriteNumber(0, 1, 30);
|
||||
FWorksheet.WriteNumber(1, 1, 20);
|
||||
FWorksheet.WriteNumber(2, 1, 10);
|
||||
|
||||
// Search for constant, contained in search range
|
||||
FWorksheet.WriteFormula(0, 2, '=MATCH(28, B1:B3, -1)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(1, FWorksheet.ReadAsNumber(0, 2), 'Formula #13 MATCH mismatch, match_type -1, in range');
|
||||
|
||||
// Search for constant, below search range
|
||||
FWorksheet.WriteFormula(0, 2, '=MATCH(8, B1:B3, -1)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(3, FWorksheet.ReadAsNumber(0, 2), 'Formula #14 MATCH mismatch, match_type -1, below range');
|
||||
|
||||
// Search for constant, above search range
|
||||
FWorksheet.WriteFormula(0, 2, '=MATCH(123, B1:B3, -1)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(STR_ERR_ARG_ERROR, FWorksheet.ReadAsText(0, 2), 'Formula #15 MATCH mismatch, match_type -1, above range');
|
||||
|
||||
// Search for cell with value in range
|
||||
FWorksheet.WriteNumber(0, 0, 28);
|
||||
FWorksheet.WriteFormula(0, 2, '=MATCH(A1, B1:B3, -1)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(1, FWorksheet.ReadAsNumber(0, 2), 'Formula #16 MATCH mismatch, match_type -1, cell in range');
|
||||
FWorksheet.WriteBlank(0, 0);
|
||||
|
||||
// Search for cell, but cell is empty
|
||||
FWorksheet.WriteBlank(0, 0);
|
||||
FWorksheet.WriteFormula(0, 2, '=MATCH(A1, B1:B3, -1)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(STR_ERR_ARG_ERROR, FWorksheet.ReadAsText(0, 2), 'Formula #17 MATCH mismatch, match_type -1, empty cell');
|
||||
|
||||
// Search range is empty
|
||||
FWorksheet.WriteFormula(0, 2, '=MATCH(28, D1:D3, -1)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(STR_ERR_ARG_ERROR, FWorksheet.ReadAsText(0, 2), 'Formula #18 MATCH mismatch, match_type -1, empty search range');
|
||||
|
||||
|
||||
// **** Error propagation
|
||||
|
||||
// Search for cell, but cell contains error
|
||||
FWorksheet.WriteFormula(0, 0, '=1/0');
|
||||
FWorksheet.WriteNumber(1, 1, 20);
|
||||
FWorksheet.WriteNumber(2, 1, 30);
|
||||
FWorksheet.WriteFormula(0, 2, '=MATCH(A1, B1:B4, 0)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(STR_ERR_DIVIDE_BY_ZERO, FWorksheet.ReadAsText(0, 2), 'Formula #19 MATCH mismatch, match_type 0, error cell');
|
||||
|
||||
// Match_type parameter contains error
|
||||
FWorksheet.WriteNumber(0, 1, 10);
|
||||
FWorksheet.WriteFormula(0, 5, '=1/0'); // F1
|
||||
FWorksheet.WriteFormula(0, 2, '=MATCH(A1, B1:B3, F1)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(STR_ERR_DIVIDE_BY_ZERO, FWorksheet.ReadAsText(0, 2), 'Formula #20 MATCH mismatch, match_type 0, error in search range');
|
||||
|
||||
// Cell range contains error
|
||||
FWorksheet.WriteNumber(0, 1, 10);
|
||||
FWorksheet.WriteFormula(1, 1, '=1/0'); // B2 contains a #DIV/0! error now
|
||||
FWorksheet.WriteNumber(2, 1, 30);
|
||||
// Search for constant, contained in search range
|
||||
FWorksheet.WriteFormula(0, 2, '=MATCH(20, B1:B3, 0)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(STR_ERR_ARG_ERROR, FWorksheet.ReadAsText(0, 2), 'Formula #21 MATCH mismatch, match_type 0, error in search range');
|
||||
// ArgError because search value is not found
|
||||
end;
|
||||
|
||||
procedure TCalcFormulaTests.Test_ROUND;
|
||||
begin
|
||||
// Round positive value.
|
||||
FWorksheet.WriteFormula(0, 1, '=ROUND(123.432, 1)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(123.4, FWorksheet.ReadAsNumber(0, 1), 1e-8, 'Formula #1 ROUND(123.432,1) result mismatch');
|
||||
|
||||
// Round positive value. Check that Banker's rounding is not applied
|
||||
FWorksheet.WriteFormula(0, 1, '=ROUND(123.456, 2)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(123.46, FWorksheet.ReadAsNumber(0, 1), 1e-8, 'Formula #2 ROUND(123.3456,2) result mismatch');
|
||||
|
||||
// Round negative value.
|
||||
FWorksheet.WriteFormula(0, 1, '=ROUND(-123.432, 1)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(-123.4, FWorksheet.ReadAsNumber(0, 1), 1e-8, 'Formula #3 ROUND(-123.432,1) result mismatch');
|
||||
|
||||
// Round negative value. Check that Banker's rounding is not applied
|
||||
FWorksheet.WriteFormula(0, 1, '=ROUND(-123.456, 2)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(-123.46, FWorksheet.ReadAsNumber(0, 1), 1e-8, 'Formula #4 ROUND(-123.456,2) result mismatch');
|
||||
|
||||
// Negative number of decimals for positive value
|
||||
FWorksheet.WriteFormula(0, 1, '=ROUND(123.456, -2)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(100, FWorksheet.ReadAsNumber(0, 1), 'Formula #5 ROUND(123.3456,-2) result mismatch');
|
||||
|
||||
// Negative number of decimals for negative value
|
||||
FWorksheet.WriteFormula(0, 1, '=ROUND(-123.456, -2)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(-100, FWorksheet.ReadAsNumber(0, 1), 'Formula #6 ROUND(123.3456,-2) result mismatch');
|
||||
|
||||
// Error in 1st argument
|
||||
FWorksheet.WriteFormula(0, 1, '=Round(1/0, 2)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(STR_ERR_DIVIDE_BY_ZERO, FWorksheet.ReadAsText(0, 1), 'Formula #7 ROUND(1/0,2) result mismatch');
|
||||
|
||||
// Error in 2nd argument
|
||||
FWorksheet.WriteFormula(0, 1, '=Round(123.456, 1/0)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(STR_ERR_DIVIDE_BY_ZERO, FWorksheet.ReadAsText(0, 1), 'Formula #8 ROUND(123.456, 1/0) result mismatch');
|
||||
end;
|
||||
|
||||
procedure TCalcFormulaTests.Test_TIME;
|
||||
var
|
||||
actualTime, expectedTime: TTime;
|
||||
begin
|
||||
// Normal time
|
||||
FWorksheet.WriteFormula(0, 1, '=Time(6,32,57)');
|
||||
FWorksheet.CalcFormulas;
|
||||
expectedTime := EncodeTime(6, 32, 57, 0);
|
||||
FWorksheet.ReadAsDateTime(0, 1, actualTime);
|
||||
CheckEquals(TimeToStr(expectedTime), TimeToStr(actualTime), 'Formula #1 TIME(6,32,57) result mismatch');
|
||||
|
||||
// Hours < 0
|
||||
FWorksheet.WriteFormula(0, 1, '=Time(-6,32,57)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(STR_ERR_OVERFLOW, FWorksheet.ReadAsText(0, 1), 'Formula #2 TIME(-6,32,57) result mismatch');
|
||||
|
||||
// Hours > 23
|
||||
FWorksheet.WriteFormula(0, 1, '=Time(15,32,57)');
|
||||
FWorksheet.CalcFormulas;
|
||||
expectedTime := 0.647881944; // Value read from Excel
|
||||
FWorksheet.ReadAsDateTime(0, 1, actualTime);
|
||||
CheckEquals(TimeToStr(expectedTime), TimeToStr(actualTime), 'Formula #3 TIME(15,32,57) result mismatch');
|
||||
|
||||
// Minutes > 59
|
||||
FWorksheet.WriteFormula(0, 1, '=Time(6,100,57)');
|
||||
FWorksheet.CalcFormulas;
|
||||
expectedTime := 0.320104167; // Value read from Excel
|
||||
FWorksheet.ReadAsDateTime(0, 1, actualTime);
|
||||
CheckEquals(TimeToStr(expectedTime), TimeToStr(actualTime), 'Formula #4 TIME(6,100,57) result mismatch');
|
||||
|
||||
// Minutes < 0
|
||||
FWorksheet.WriteFormula(0, 1, '=Time(6,-100,57)');
|
||||
FWorksheet.CalcFormulas;
|
||||
expectedTime := 0.181215278; // Value read from Excel
|
||||
FWorksheet.ReadAsDateTime(0, 1, actualTime);
|
||||
CheckEquals(TimeToStr(expectedTime), TimeToStr(actualTime), 'Formula #5 TIME(6,-100,57) result mismatch');
|
||||
|
||||
// Seconds > 59
|
||||
FWorksheet.WriteFormula(0, 1, '=Time(6,32,100)');
|
||||
FWorksheet.CalcFormulas;
|
||||
expectedTime := 0.27337963; // Value read from Excel
|
||||
FWorksheet.ReadAsDateTime(0, 1, actualTime);
|
||||
CheckEquals(TimeToStr(expectedTime), TimeToStr(actualTime), 'Formula #6 TIME(6,32,100) result mismatch');
|
||||
|
||||
// Seconds < 0
|
||||
FWorksheet.WriteFormula(0, 1, '=Time(6,32,-100)');
|
||||
FWorksheet.CalcFormulas;
|
||||
expectedTime := 0.271064815; // Value read from Excel
|
||||
FWorksheet.ReadAsDateTime(0, 1, actualTime);
|
||||
CheckEquals(TimeToStr(expectedTime), TimeToStr(actualTime), 'Formula #7 TIME(6,32,-100) result mismatch');
|
||||
|
||||
// Error in hours
|
||||
FWorksheet.WriteFormula(0, 1, '=Time(1/0,32,57)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(STR_ERR_DIVIDE_BY_ZERO, FWorksheet.ReadAsText(0, 1), 'Formula #8 TIME(1/0,32,57) result mismatch');
|
||||
|
||||
// Error in minutes
|
||||
FWorksheet.WriteFormula(0, 1, '=Time(6,1/0,57)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(STR_ERR_DIVIDE_BY_ZERO, FWorksheet.ReadAsText(0, 1), 'Formula #9 TIME(6,1/0,57) result mismatch');
|
||||
|
||||
// Error in seconds
|
||||
FWorksheet.WriteFormula(0, 1, '=Time(6,32,1/0)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(STR_ERR_DIVIDE_BY_ZERO, FWorksheet.ReadAsText(0, 1), 'Formula #10 TIME(6,32,1/0) result mismatch');
|
||||
end;
|
||||
|
||||
initialization
|
||||
RegisterTest(TCalcFormulaTests);
|
||||
end.
|
||||
|
Loading…
Reference in New Issue
Block a user