FPSpreadsheet: Add more unit test cases for COUNTIF and SUMIF.
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@9605 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
parent
35839d3bc3
commit
e66040bd5c
@ -855,10 +855,11 @@ function TokenName(AToken: TsTokenType): String;
|
|||||||
function ResultTypeName(AResult: TsResultType): String;
|
function ResultTypeName(AResult: TsResultType): String;
|
||||||
function CharToResultType(C: Char): TsResultType;
|
function CharToResultType(C: Char): TsResultType;
|
||||||
function BuiltinIdentifiers: TsBuiltInExpressionManager;
|
function BuiltinIdentifiers: TsBuiltInExpressionManager;
|
||||||
function ArgToBoolean(Arg: TsExpressionResult): Boolean;
|
function ArgToBoolean(Arg: TsExpressionResult; Strict: Boolean): Boolean;
|
||||||
function ArgToCell(Arg: TsExpressionResult): PCell;
|
function ArgToCell(Arg: TsExpressionResult): PCell;
|
||||||
function ArgToDateTime(Arg: TsExpressionResult): TDateTime;
|
function ArgToDateTime(Arg: TsExpressionResult): TDateTime;
|
||||||
function ArgToInt(Arg: TsExpressionResult): Integer;
|
function ArgToInt(Arg: TsExpressionResult): Integer;
|
||||||
|
function ArgToError(Arg: TsExpressionResult): TsErrorValue;
|
||||||
function ArgToFloat(Arg: TsExpressionResult): TsExprFloat;
|
function ArgToFloat(Arg: TsExpressionResult): TsExprFloat;
|
||||||
function ArgToFloatOrNaN(Arg: TsExpressionResult): TsExprFloat;
|
function ArgToFloatOrNaN(Arg: TsExpressionResult): TsExprFloat;
|
||||||
function ArgToString(Arg: TsExpressionResult): String;
|
function ArgToString(Arg: TsExpressionResult): String;
|
||||||
@ -4786,7 +4787,7 @@ end;
|
|||||||
{ Conversion of arguments to simple data types }
|
{ Conversion of arguments to simple data types }
|
||||||
{------------------------------------------------------------------------------}
|
{------------------------------------------------------------------------------}
|
||||||
|
|
||||||
function ArgToBoolean(Arg: TsExpressionResult): Boolean;
|
function ArgToBoolean(Arg: TsExpressionResult; Strict: Boolean): Boolean;
|
||||||
var
|
var
|
||||||
cell: PCell;
|
cell: PCell;
|
||||||
x: Double;
|
x: Double;
|
||||||
@ -4804,10 +4805,14 @@ begin
|
|||||||
cctBool:
|
cctBool:
|
||||||
Result := cell^.BoolValue;
|
Result := cell^.BoolValue;
|
||||||
else
|
else
|
||||||
|
if not Strict then
|
||||||
|
begin
|
||||||
x := ArgToFloatOrNaN(Arg);
|
x := ArgToFloatOrNaN(Arg);
|
||||||
Result := not IsNaN(x) and (x <> 0.0);
|
Result := not IsNaN(x) and (x <> 0.0);
|
||||||
end;
|
end;
|
||||||
|
end;
|
||||||
end else
|
end else
|
||||||
|
if not Strict then
|
||||||
begin
|
begin
|
||||||
x := ArgToFloatOrNaN(Arg);
|
x := ArgToFloatOrNaN(Arg);
|
||||||
Result := not IsNaN(x) and (x <> 0.0);
|
Result := not IsNaN(x) and (x <> 0.0);
|
||||||
@ -4848,6 +4853,23 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function ArgToError(Arg: TsExpressionResult): TsErrorValue;
|
||||||
|
var
|
||||||
|
cell: PCell;
|
||||||
|
begin
|
||||||
|
Result := errOK;
|
||||||
|
case Arg.ResultType of
|
||||||
|
rtError:
|
||||||
|
Result := Arg.ResError;
|
||||||
|
rtCell:
|
||||||
|
begin
|
||||||
|
cell := ArgToCell(Arg);
|
||||||
|
if Assigned(cell) and (cell^.ContentType = cctError) then
|
||||||
|
Result := cell^.ErrorValue;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
{ Utility function for the built-in math functions. Accepts also integers and
|
{ Utility function for the built-in math functions. Accepts also integers and
|
||||||
other data types in place of floating point arguments. To be called in
|
other data types in place of floating point arguments. To be called in
|
||||||
builtins or user-defined callbacks having float results or arguments. }
|
builtins or user-defined callbacks having float results or arguments. }
|
||||||
|
@ -75,7 +75,7 @@ end;
|
|||||||
|
|
||||||
type
|
type
|
||||||
TsFuncType = (ftCountIF, ftCountIFS, ftSumIF, ftSUMIFS, ftAverageIF, ftAverageIFS);
|
TsFuncType = (ftCountIF, ftCountIFS, ftSumIF, ftSUMIFS, ftAverageIF, ftAverageIFS);
|
||||||
TsCompareType = (ctNumber, ctString, ctEmpty);
|
TsCompareType = (ctNumber, ctString, ctBoolean, ctEmpty, ctError);
|
||||||
|
|
||||||
{ Helper class for calculating COUNTIF(S) or SUMIF(S) or AVERAGEIF(S) formulas.
|
{ Helper class for calculating COUNTIF(S) or SUMIF(S) or AVERAGEIF(S) formulas.
|
||||||
|
|
||||||
@ -101,14 +101,19 @@ type
|
|||||||
FCompareOperation: TsCompareOperation;
|
FCompareOperation: TsCompareOperation;
|
||||||
FCompareType: TsCompareType;
|
FCompareType: TsCompareType;
|
||||||
FCompareNumber: Double;
|
FCompareNumber: Double;
|
||||||
|
FCompareBoolean: Boolean;
|
||||||
|
FCompareError: TsErrorValue;
|
||||||
FCompareString: String;
|
FCompareString: String;
|
||||||
FFormatSettings: TFormatSettings;
|
FFormatSettings: TFormatSettings;
|
||||||
|
FError: TsErrorValue;
|
||||||
protected
|
protected
|
||||||
function CompareArg(ArgIndex: Integer): Boolean;
|
function CompareArg(ArgIndex: Integer): Boolean;
|
||||||
|
function CompareBoolean(AValue: Boolean): Boolean;
|
||||||
function CompareCell(ASheet: TsBasicWorksheet; ARow, ACol: Integer): Boolean;
|
function CompareCell(ASheet: TsBasicWorksheet; ARow, ACol: Integer): Boolean;
|
||||||
|
function CompareEmpty(AEmpty: Boolean): Boolean;
|
||||||
|
function CompareError(AError: TsErrorValue): Boolean;
|
||||||
function CompareNumber(ANumber: Double): Boolean;
|
function CompareNumber(ANumber: Double): Boolean;
|
||||||
function CompareString(AString: String): Boolean;
|
function CompareString(AString: String): Boolean;
|
||||||
function CompareEmpty(AEmpty: Boolean): Boolean;
|
|
||||||
function GetArgValue(ArgIndex: Integer): Double;
|
function GetArgValue(ArgIndex: Integer): Double;
|
||||||
function GetCellValue(ASheet: TsBasicWorksheet; ARow, ACol: Integer): Double;
|
function GetCellValue(ASheet: TsBasicWorksheet; ARow, ACol: Integer): Double;
|
||||||
procedure GetCompareParams(ArgIndex: Integer);
|
procedure GetCompareParams(ArgIndex: Integer);
|
||||||
@ -136,6 +141,21 @@ begin
|
|||||||
FFuncType := AFuncType;
|
FFuncType := AFuncType;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TsFuncComparer.CompareBoolean(AValue: Boolean): Boolean;
|
||||||
|
var
|
||||||
|
val: Double;
|
||||||
|
begin
|
||||||
|
Result := false;
|
||||||
|
case FCompareOperation of
|
||||||
|
coEqual : if AValue = FCompareBoolean then Result := true;
|
||||||
|
coLess : if AValue < FCompareBoolean then Result := true;
|
||||||
|
coGreater : if AValue > FCompareBoolean then Result := true;
|
||||||
|
coLessEqual : if AValue <= FCompareBoolean then Result := true;
|
||||||
|
coGreaterEqual : if AValue >= FCompareBoolean then Result := true;
|
||||||
|
coNotEqual : if AValue <> FCompareBoolean then Result := true;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
function TsFuncComparer.CompareNumber(ANumber: Double): Boolean;
|
function TsFuncComparer.CompareNumber(ANumber: Double): Boolean;
|
||||||
begin
|
begin
|
||||||
Result := false;
|
Result := false;
|
||||||
@ -172,12 +192,23 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TsFuncComparer.CompareError(AError: TsErrorValue): Boolean;
|
||||||
|
begin
|
||||||
|
Result := false;
|
||||||
|
case FCompareOperation of
|
||||||
|
coEqual : Result := AError = FCompareError;
|
||||||
|
coNotEqual: Result := AError <> FCompareError;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
function TsFuncComparer.CompareArg(ArgIndex: Integer): Boolean;
|
function TsFuncComparer.CompareArg(ArgIndex: Integer): Boolean;
|
||||||
begin
|
begin
|
||||||
case FCompareType of
|
case FCompareType of
|
||||||
ctNumber : Result := CompareNumber(ArgToFloat(FArgs[ArgIndex]));
|
ctNumber : Result := CompareNumber(ArgToFloat(FArgs[ArgIndex]));
|
||||||
ctString : Result := CompareString(ArgToString(FArgs[ArgIndex]));
|
ctString : Result := CompareString(ArgToString(FArgs[ArgIndex]));
|
||||||
|
ctBoolean: Result := CompareBoolean(ArgToBoolean(FArgs[ArgIndex], true));
|
||||||
ctEmpty : Result := CompareEmpty((ArgToString(FArgs[ArgIndex])) = '');
|
ctEmpty : Result := CompareEmpty((ArgToString(FArgs[ArgIndex])) = '');
|
||||||
|
ctError : Result := CompareError(ArgToError(FArgs[ArgIndex]));
|
||||||
else Result := false;
|
else Result := false;
|
||||||
end
|
end
|
||||||
end;
|
end;
|
||||||
@ -185,6 +216,7 @@ end;
|
|||||||
function TsFuncComparer.CompareCell(ASheet: TsBasicWorksheet; ARow, ACol: Integer): Boolean;
|
function TsFuncComparer.CompareCell(ASheet: TsBasicWorksheet; ARow, ACol: Integer): Boolean;
|
||||||
var
|
var
|
||||||
cell: PCell;
|
cell: PCell;
|
||||||
|
value: Double;
|
||||||
begin
|
begin
|
||||||
Result := false;
|
Result := false;
|
||||||
cell := TsWorksheet(ASheet).FindCell(ARow, ACol);
|
cell := TsWorksheet(ASheet).FindCell(ARow, ACol);
|
||||||
@ -203,7 +235,17 @@ begin
|
|||||||
cctDateTime:
|
cctDateTime:
|
||||||
Result := CompareNumber(cell^.DateTimeValue);
|
Result := CompareNumber(cell^.DateTimeValue);
|
||||||
cctBool:
|
cctBool:
|
||||||
Result := CompareNumber(IfThen(cell^.Boolvalue, 1, 0));
|
if FFuncType <> ftCountIF then
|
||||||
|
Result := CompareBoolean(cell^.Boolvalue);
|
||||||
|
cctUTF8String:
|
||||||
|
begin
|
||||||
|
if TryStrToFloat(cell^.UTF8StringValue, value) then
|
||||||
|
Result := CompareNumber(value);
|
||||||
|
{
|
||||||
|
if not TryStrToFloat(cell^.UTF8StringValue, value) then value := 0.0;
|
||||||
|
Result := CompareNumber(value);
|
||||||
|
}
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
ctString:
|
ctString:
|
||||||
@ -215,8 +257,20 @@ begin
|
|||||||
if (cell^.ContentType = cctUTF8String) then
|
if (cell^.ContentType = cctUTF8String) then
|
||||||
Result := CompareString(cell^.Utf8StringValue);
|
Result := CompareString(cell^.Utf8StringValue);
|
||||||
end;
|
end;
|
||||||
|
ctBoolean:
|
||||||
|
if (FCompareOperation = coNotEqual) and ((cell = nil) or (cell^.ContentType <> cctBool)) then
|
||||||
|
Result := true
|
||||||
|
else
|
||||||
|
if (cell <> nil) and (cell^.ContentType = cctBool) then
|
||||||
|
Result := CompareBoolean(cell^.BoolValue);
|
||||||
ctEmpty:
|
ctEmpty:
|
||||||
Result := CompareEmpty((cell = nil) or ((cell <> nil) and (cell^.ContentType = cctEmpty)));
|
Result := CompareEmpty((cell = nil) or ((cell <> nil) and (cell^.ContentType = cctEmpty)));
|
||||||
|
ctError:
|
||||||
|
if (FCompareOperation = coNotEqual) and ((cell = nil) or (cell^.ContentType <> cctError)) then
|
||||||
|
Result := true
|
||||||
|
else
|
||||||
|
if (cell <> nil) and (cell^.ContentType = cctError) then
|
||||||
|
REsult := CompareError(cell^.ErrorValue);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -231,9 +285,10 @@ var
|
|||||||
valueSheet: TsBasicWorksheet;
|
valueSheet: TsBasicWorksheet;
|
||||||
matches: Boolean;
|
matches: Boolean;
|
||||||
count: Integer;
|
count: Integer;
|
||||||
sum: Double;
|
val, sum: Double;
|
||||||
begin
|
begin
|
||||||
Result := ErrorResult(errArgError);
|
Result := ErrorResult(errArgError);
|
||||||
|
FError := errOK;
|
||||||
|
|
||||||
if not ValidParams(Result) then
|
if not ValidParams(Result) then
|
||||||
exit;
|
exit;
|
||||||
@ -304,7 +359,16 @@ begin
|
|||||||
inc(count);
|
inc(count);
|
||||||
case FArgs[FValueRangeIndex].ResultType of
|
case FArgs[FValueRangeIndex].ResultType of
|
||||||
rtCell: sum := sum + GetArgValue(FValueRangeIndex);
|
rtCell: sum := sum + GetArgValue(FValueRangeIndex);
|
||||||
rtCellRange: sum := sum + GetCellValue(valuesheet, r, c);
|
rtCellRange:
|
||||||
|
begin
|
||||||
|
val := GetCellValue(valuesheet, r, c);
|
||||||
|
if not (FFuncType in [ftCountIF, ftCountIFS]) and (FError <> errOK) then
|
||||||
|
begin
|
||||||
|
Result := ErrorResult(FError);
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
sum := sum + val;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
end; // for c
|
end; // for c
|
||||||
@ -342,6 +406,8 @@ begin
|
|||||||
cctNumber : Result := cell^.NumberValue;
|
cctNumber : Result := cell^.NumberValue;
|
||||||
cctDateTime: Result := cell^.DateTimeValue;
|
cctDateTime: Result := cell^.DateTimeValue;
|
||||||
cctBool : if cell^.BoolValue then Result := 1.0;
|
cctBool : if cell^.BoolValue then Result := 1.0;
|
||||||
|
cctUTF8String : if not TryStrToFloat(cell^.UTF8StringValue, Result) then Result := 0.0;
|
||||||
|
cctError: FError := cell^.ErrorValue;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
@ -377,8 +443,8 @@ begin
|
|||||||
end;
|
end;
|
||||||
cctBool:
|
cctBool:
|
||||||
begin
|
begin
|
||||||
if cell^.BoolValue then FCompareNumber := 1.0 else FCompareNumber := 0.0;
|
FCompareBoolean := cell^.BoolValue;
|
||||||
FCompareType := ctNumber;
|
FCompareType := ctBoolean;
|
||||||
end;
|
end;
|
||||||
cctUTF8String:
|
cctUTF8String:
|
||||||
begin
|
begin
|
||||||
@ -390,7 +456,10 @@ begin
|
|||||||
FCompareType := ctEmpty;
|
FCompareType := ctEmpty;
|
||||||
end;
|
end;
|
||||||
cctError:
|
cctError:
|
||||||
; // what to do here?
|
begin
|
||||||
|
FCompareError := cell^.ErrorValue;
|
||||||
|
FCompareType := ctError;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
end else
|
end else
|
||||||
begin
|
begin
|
||||||
@ -400,6 +469,16 @@ begin
|
|||||||
if s = '' then
|
if s = '' then
|
||||||
FCompareType := ctEmpty
|
FCompareType := ctEmpty
|
||||||
else
|
else
|
||||||
|
if (FArgs[ArgIndex].ResultType = rtError) then
|
||||||
|
begin
|
||||||
|
FCompareError := FArgs[ArgIndex].ResError;
|
||||||
|
FCompareType := ctError;
|
||||||
|
end else
|
||||||
|
if (FArgs[ArgIndex].ResultType = rtBoolean) then
|
||||||
|
begin
|
||||||
|
FCompareBoolean := FArgs[ArgIndex].ResBoolean;
|
||||||
|
FCompareType := ctBoolean;
|
||||||
|
end else
|
||||||
if TryStrToInt(s, n) then
|
if TryStrToInt(s, n) then
|
||||||
begin
|
begin
|
||||||
FCompareNumber := n;
|
FCompareNumber := n;
|
||||||
@ -1965,7 +2044,7 @@ begin
|
|||||||
Result := ErrorResult(errWrongType);
|
Result := ErrorResult(errWrongType);
|
||||||
exit;
|
exit;
|
||||||
end;
|
end;
|
||||||
if not ArgToBoolean(Args[i]) then begin
|
if not ArgToBoolean(Args[i], false) then begin
|
||||||
b := false;
|
b := false;
|
||||||
break;
|
break;
|
||||||
end;
|
end;
|
||||||
@ -1997,13 +2076,13 @@ begin
|
|||||||
begin
|
begin
|
||||||
if IsError(Args[2], Result) then
|
if IsError(Args[2], Result) then
|
||||||
exit;
|
exit;
|
||||||
if ArgToBoolean(Args[0]) then
|
if ArgToBoolean(Args[0], false) then
|
||||||
Result := Args[1]
|
Result := Args[1]
|
||||||
else
|
else
|
||||||
Result := Args[2];
|
Result := Args[2];
|
||||||
end else
|
end else
|
||||||
begin
|
begin
|
||||||
if ArgToBoolean(Args[0]) then
|
if ArgToBoolean(Args[0], false) then
|
||||||
Result := Args[1]
|
Result := Args[1]
|
||||||
else
|
else
|
||||||
Result.ResBoolean := false;
|
Result.ResBoolean := false;
|
||||||
@ -2027,7 +2106,7 @@ begin
|
|||||||
Result := ErrorResult(errWrongType);
|
Result := ErrorResult(errWrongType);
|
||||||
exit;
|
exit;
|
||||||
end;
|
end;
|
||||||
if ArgToBoolean(Args[i]) then
|
if ArgToBoolean(Args[i], false) then
|
||||||
begin
|
begin
|
||||||
Result := Args[i+1];
|
Result := Args[i+1];
|
||||||
break;
|
break;
|
||||||
@ -2044,7 +2123,7 @@ begin
|
|||||||
if (Args[0].ResultType = rtString) then
|
if (Args[0].ResultType = rtString) then
|
||||||
Result := ErrorResult(errWrongType)
|
Result := ErrorResult(errWrongType)
|
||||||
else
|
else
|
||||||
Result.ResBoolean := not ArgToBoolean(Args[0]);
|
Result.ResBoolean := not ArgToBoolean(Args[0], false);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// OR( condition1, [condition2], ... )
|
// OR( condition1, [condition2], ... )
|
||||||
@ -2064,7 +2143,7 @@ begin
|
|||||||
Result := ErrorResult(errWrongType);
|
Result := ErrorResult(errWrongType);
|
||||||
exit;
|
exit;
|
||||||
end;
|
end;
|
||||||
if ArgToBoolean(Args[i]) then begin
|
if ArgToBoolean(Args[i], false) then begin
|
||||||
b := true;
|
b := true;
|
||||||
break;
|
break;
|
||||||
end;
|
end;
|
||||||
@ -2345,8 +2424,10 @@ var
|
|||||||
begin
|
begin
|
||||||
if IsError(Args[0], AResult) then
|
if IsError(Args[0], AResult) then
|
||||||
exit;
|
exit;
|
||||||
|
{ Excel still calculates the formula if the "condition" argument contains an error
|
||||||
if IsError(Args[1], AResult) then
|
if IsError(Args[1], AResult) then
|
||||||
exit;
|
exit;
|
||||||
|
}
|
||||||
if (Length(Args) = 3) and IsError(Args[0], AResult) then
|
if (Length(Args) = 3) and IsError(Args[0], AResult) then
|
||||||
exit;
|
exit;
|
||||||
|
|
||||||
@ -3018,7 +3099,7 @@ begin
|
|||||||
|
|
||||||
A1Dialect := true;
|
A1Dialect := true;
|
||||||
if (Length(Args) > 3) and (Args[3].ResultType <> rtMissingArg) then
|
if (Length(Args) > 3) and (Args[3].ResultType <> rtMissingArg) then
|
||||||
A1Dialect := ArgToBoolean(Args[3]);
|
A1Dialect := ArgToBoolean(Args[3], false);
|
||||||
|
|
||||||
sheet := '';
|
sheet := '';
|
||||||
if Length(Args) > 4 then
|
if Length(Args) > 4 then
|
||||||
|
@ -27,6 +27,7 @@ type
|
|||||||
procedure Test_COUNT;
|
procedure Test_COUNT;
|
||||||
procedure Test_COUNTA;
|
procedure Test_COUNTA;
|
||||||
procedure Test_COUNTBLANK;
|
procedure Test_COUNTBLANK;
|
||||||
|
procedure Test_COUNTIF;
|
||||||
procedure Test_DATE;
|
procedure Test_DATE;
|
||||||
procedure Test_ERRORTYPE;
|
procedure Test_ERRORTYPE;
|
||||||
procedure Test_EVEN;
|
procedure Test_EVEN;
|
||||||
@ -53,6 +54,7 @@ type
|
|||||||
procedure Test_STDEV;
|
procedure Test_STDEV;
|
||||||
procedure Test_STDEVP;
|
procedure Test_STDEVP;
|
||||||
procedure Test_SUM;
|
procedure Test_SUM;
|
||||||
|
procedure Test_SUMIF;
|
||||||
procedure Test_SUMSQ;
|
procedure Test_SUMSQ;
|
||||||
procedure Test_TIME;
|
procedure Test_TIME;
|
||||||
procedure Test_VAR;
|
procedure Test_VAR;
|
||||||
@ -87,10 +89,10 @@ begin
|
|||||||
CheckEquals(10, FWorksheet.ReadAsNumber(0, 1), 'Formula ABS(-10) result mismatch');
|
CheckEquals(10, FWorksheet.ReadAsNumber(0, 1), 'Formula ABS(-10) result mismatch');
|
||||||
|
|
||||||
// Error propagation
|
// Error propagation
|
||||||
FWorksheet.WriteFormula(0, 0, '=1/0');
|
FWorksheet.WriteErrorValue(0, 0, errIllegalRef);
|
||||||
FWorksheet.WriteFormula(0, 1, 'ABS(A1)');
|
FWorksheet.WriteFormula(0, 1, 'ABS(A1)');
|
||||||
FWorksheet.CalcFormulas;
|
FWorksheet.CalcFormulas;
|
||||||
CheckEquals(STR_ERR_DIVIDE_BY_ZERO, FWorksheet.ReadAsText(0, 1), 'Formula ABS(1/0) result mismatch');
|
CheckEquals(STR_ERR_ILLEGAL_REF, FWorksheet.ReadAsText(0, 1), 'Formula ABS(1/0) result mismatch');
|
||||||
|
|
||||||
// Empty argument
|
// Empty argument
|
||||||
FWorksheet.WriteBlank(0, 0);
|
FWorksheet.WriteBlank(0, 0);
|
||||||
@ -139,9 +141,13 @@ begin
|
|||||||
FWorksheet.CalcFormulas;
|
FWorksheet.CalcFormulas;
|
||||||
CheckEquals(STR_ERR_WRONG_TYPE, FWorksheet.ReadAsText(cell), 'Formula #9 AND("abc",TRUE) result mismatch');
|
CheckEquals(STR_ERR_WRONG_TYPE, FWorksheet.ReadAsText(cell), 'Formula #9 AND("abc",TRUE) result mismatch');
|
||||||
|
|
||||||
cell := FWorksheet.WriteFormula(0, 1, 'AND(1/0,1/0)');
|
cell := FWorksheet.WriteFormula(0, 1, 'AND(1/0,0)');
|
||||||
FWorksheet.CalcFormulas;
|
FWorksheet.CalcFormulas;
|
||||||
CheckEquals(STR_ERR_DIVIDE_BY_ZERO, FWorksheet.ReadAsText(cell), 'Formula #10 AND(1/0,1/0) result mismatch');
|
CheckEquals(STR_ERR_DIVIDE_BY_ZERO, FWorksheet.ReadAsText(cell), 'Formula #10 AND(1/0,0) result mismatch');
|
||||||
|
|
||||||
|
cell := FWorksheet.WriteFormula(0, 1, 'AND(#REF!,#DIV/0!)');
|
||||||
|
FWorksheet.CalcFormulas;
|
||||||
|
CheckEquals(STR_ERR_ILLEGAL_REF, FWorksheet.ReadAsText(cell), 'Formula #11 AND(#REF!,#DIV/0!) result mismatch');
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TCalcFormulaTests.Test_AVEDEV;
|
procedure TCalcFormulaTests.Test_AVEDEV;
|
||||||
@ -538,6 +544,74 @@ begin
|
|||||||
CheckEquals(1, FWorksheet.ReadAsNumber(4, 1), 'Formula #6 COUNTBLANK(A1:A4) result mismatch');
|
CheckEquals(1, FWorksheet.ReadAsNumber(4, 1), 'Formula #6 COUNTBLANK(A1:A4) result mismatch');
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TCalcFormulaTests.Test_COUNTIF;
|
||||||
|
begin
|
||||||
|
// Test data, range A1:B5
|
||||||
|
FWorksheet.WriteNumber (0, 0, 10); FWorksheet.WriteFormula(0, 1, '=SQRT(-1)'); // --> #NUM!
|
||||||
|
FWorksheet.WriteNumber (1, 0, -20); FWorksheet.WriteBlank (1, 1);
|
||||||
|
FWorksheet.WriteFormula(2, 0, '=(1=1)'); FWorksheet.WriteNumber (2, 1, 0);
|
||||||
|
FWorksheet.WriteText (3, 0, ''); FWorksheet.WriteText (3, 1, '5');
|
||||||
|
FWorksheet.WriteText (4, 0, 'abc'); FWorksheet.WriteText (4, 1, 'ABC');
|
||||||
|
FWorksheet.WriteBoolValue(5, 0, false); FWorksheet.WriteErrorValue(5, 1, errOverflow); // --> #NUM!
|
||||||
|
|
||||||
|
// Counts the elements in A1:B6 which are equal to "abc" (case-insensitive)
|
||||||
|
FWorksheet.WriteFormula(0, 2, '=COUNTIF(A1:B6,"abc")');
|
||||||
|
FWorksheet.CalcFormulas;
|
||||||
|
CheckEquals(2, FWorksheet.ReadAsNumber(0, 2), 'Formula #1 COUNTIF(A1:B6,"abc") result mismatch');
|
||||||
|
|
||||||
|
// Counts the elements in A1:B6 which are < 0
|
||||||
|
FWorksheet.WriteFormula(0, 2, '=COUNTIF(A1:B6,"<0")');
|
||||||
|
FWorksheet.CalcFormulas;
|
||||||
|
CheckEquals(1, FWorksheet.ReadAsNumber(0, 2), 'Formula #2 COUNTIF(A1:B6,"<0") result mismatch');
|
||||||
|
|
||||||
|
// Counts empty elements in A1:B6
|
||||||
|
FWorksheet.WriteFormula(0, 2, '=COUNTIF(A1:B6,"")');
|
||||||
|
FWorksheet.CalcFormulas;
|
||||||
|
CheckEquals(2, FWorksheet.ReadAsNumber(0, 2), 'Formula #3 COUNTIF(A1:B6,"") result mismatch');
|
||||||
|
|
||||||
|
// Counts the elements in A1:B6 which are equal to 0
|
||||||
|
FWorksheet.WriteFormula(0, 2, '=COUNTIF(A1:B6,0)');
|
||||||
|
FWorksheet.CalcFormulas;
|
||||||
|
CheckEquals(1, FWorksheet.ReadAsNumber(0, 2), 'Formula #4 COUNTIF(A1:B6,0) result mismatch');
|
||||||
|
|
||||||
|
// Counts the elements in A1:B6 which are TRUE
|
||||||
|
FWorksheet.WriteFormula(0, 2, '=COUNTIF(A1:B6,TRUE)');
|
||||||
|
FWorksheet.CalcFormulas;
|
||||||
|
CheckEquals(1, FWorksheet.ReadAsNumber(0, 2), 'Formula #5 COUNTIF(A1:B6,TRUE) result mismatch');
|
||||||
|
|
||||||
|
// Counts the elements in A1:B6 which are FALSE
|
||||||
|
FWorksheet.WriteFormula(0, 2, '=COUNTIF(A1:B6,FALSE)');
|
||||||
|
FWorksheet.CalcFormulas;
|
||||||
|
CheckEquals(1, FWorksheet.ReadAsNumber(0, 2), 'Formula #4 COUNTIF(A1:B6,FALSE) result mismatch');
|
||||||
|
|
||||||
|
// Counts the elements in A1:B5 which are #NUM!
|
||||||
|
FWorksheet.WriteFormula(0, 2, '=COUNTIF(A1:B6,#NUM!)');
|
||||||
|
FWorksheet.CalcFormulas;
|
||||||
|
CheckEquals(2, FWorksheet.ReadAsNumber(0, 2), 'Formula #6 COUNTIF(A1:B6,#NUM!) result mismatch');
|
||||||
|
|
||||||
|
// Count the elements in A1:B6 which are equal to cell A15 (empty)
|
||||||
|
FWorksheet.WriteFormula(0, 2, '=COUNTIF(A1:B6,A15)');
|
||||||
|
FWorksheet.CalcFormulas;
|
||||||
|
CheckEquals(2, FWorksheet.ReadAsNumber(0, 2), 'Formula #7 COUNTIF(A1:B6,A15) (A15 empty) result mismatch');
|
||||||
|
|
||||||
|
// Count the elements in A1:B6 which are equal to cell A15 (value 10)
|
||||||
|
FWorksheet.WriteNumber(14, 0, 10);
|
||||||
|
FWorksheet.WriteFormula(0, 2, '=COUNTIF(A1:B6,A15)');
|
||||||
|
FWorksheet.CalcFormulas;
|
||||||
|
CheckEquals(1, FWorksheet.ReadAsNumber(0, 2), 'Formula #8 COUNTIF(A1:B6,A15) (A15 = 10) result mismatch');
|
||||||
|
|
||||||
|
// Count the elements in A1:B6 which are < cell A15 (value 10)
|
||||||
|
FWorksheet.WriteFormula(0, 2, '=COUNTIF(A1:B6,"<"&A15)');
|
||||||
|
FWorksheet.CalcFormulas;
|
||||||
|
CheckEquals(3, FWorksheet.ReadAsNumber(0, 2), 'Formula #9 COUNTIF(A1:B6,"<"&A15) (A15 = 10) result mismatch');
|
||||||
|
|
||||||
|
// Count the elements in A1:B6 which are equal to cell A15 (error value #NUM!)
|
||||||
|
FWorksheet.WriteErrorValue(14, 0, errOverflow);
|
||||||
|
FWorksheet.WriteFormula(0, 2, '=COUNTIF(A1:B6,A15)');
|
||||||
|
FWorksheet.CalcFormulas;
|
||||||
|
CheckEquals(2, FWorksheet.ReadAsNumber(0, 2), 'Formula #10 COUNTIF(A1:B6,A15) (A15 = #NUM!) result mismatch');
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TCalcFormulaTests.Test_DATE;
|
procedure TCalcFormulaTests.Test_DATE;
|
||||||
var
|
var
|
||||||
actualDate, expectedDate: TDate;
|
actualDate, expectedDate: TDate;
|
||||||
@ -1843,43 +1917,7 @@ begin
|
|||||||
FWorksheet.CalcFormulas;
|
FWorksheet.CalcFormulas;
|
||||||
CheckEquals(STR_ERR_DIVIDE_BY_ZERO, FWorksheet.ReadAsText(0, 1), 'Formula #16 PRODUCT(A:A6) result mismatch');
|
CheckEquals(STR_ERR_DIVIDE_BY_ZERO, FWorksheet.ReadAsText(0, 1), 'Formula #16 PRODUCT(A:A6) result mismatch');
|
||||||
end;
|
end;
|
||||||
(*
|
|
||||||
procedure TCalcFormulaTests.Test_PRODUCT;
|
|
||||||
begin
|
|
||||||
FWorksheet.WriteFormula(0, 1, '=PRODUCT(1)');
|
|
||||||
FWorksheet.CalcFormulas;
|
|
||||||
CheckEquals(1, FWorksheet.ReadAsNumber(0, 1), 'Formula #1 PRODUCT(1) result mismatch');
|
|
||||||
|
|
||||||
FWorksheet.WriteFormula(0, 1, '=PRODUCT(1,2,3,4)');
|
|
||||||
FWorksheet.CalcFormulas;
|
|
||||||
CheckEquals(24, FWorksheet.ReadAsNumber(0, 1), 'Formula #2 PRODUCT(1,2,3,4) result mismatch');
|
|
||||||
|
|
||||||
FWorksheet.WriteNumber(0, 0, 1);
|
|
||||||
FWorksheet.WriteNumber(1, 0, 2);
|
|
||||||
FWorksheet.WriteNumber(2, 0, 3);
|
|
||||||
FWorksheet.WriteNumber(3, 0, 4);
|
|
||||||
|
|
||||||
FWorksheet.WriteFormula(4, 0, '=PRODUCT(A1)');
|
|
||||||
FWorksheet.CalcFormulas;
|
|
||||||
CheckEquals(1, FWorksheet.ReadAsNumber(4, 0), 'Formula #3 PRODUCT(A1) result mismatch');
|
|
||||||
|
|
||||||
FWorksheet.WriteFormula(4, 0, '=PRODUCT(A1,A2)');
|
|
||||||
FWorksheet.CalcFormulas;
|
|
||||||
CheckEquals(2, FWorksheet.ReadAsNumber(4, 0), 'Formula #4 PRODUCT(A1,A2) result mismatch');
|
|
||||||
|
|
||||||
FWorksheet.WriteFormula(4, 0, '=PRODUCT(A1:A4)');
|
|
||||||
FWorksheet.CalcFormulas;
|
|
||||||
CheckEquals(24, FWorksheet.ReadAsNumber(4, 0), 'Formula #5 PRODUCT(A1:A4) result mismatch');
|
|
||||||
|
|
||||||
FWorksheet.WriteFormula(4, 0, '=PRODUCT(A1,A2:A4)');
|
|
||||||
FWorksheet.CalcFormulas;
|
|
||||||
CheckEquals(24, FWorksheet.ReadAsNumber(4, 0), 'Formula #6 PRODUCT(A1,A2:A4) result mismatch');
|
|
||||||
|
|
||||||
FWorksheet.WriteFormula(4, 0, '=PRODUCT(A1, 1/0, A2)');
|
|
||||||
FWorksheet.CalcFormulas;
|
|
||||||
CheckEquals(STR_ERR_DIVIDE_BY_ZERO, FWorksheet.ReadAsText(4, 0), 'Formula #7 PRODUCT(A1, 1/0, A2) result mismatch');
|
|
||||||
end;
|
|
||||||
*)
|
|
||||||
procedure TCalcFormulaTests.Test_ROUND;
|
procedure TCalcFormulaTests.Test_ROUND;
|
||||||
begin
|
begin
|
||||||
// Round positive value.
|
// Round positive value.
|
||||||
@ -2188,8 +2226,137 @@ begin
|
|||||||
CheckEquals(STR_ERR_DIVIDE_BY_ZERO, FWorksheet.ReadAsText(0, 1), 'Formula #16 SUM(A:A6) result mismatch');
|
CheckEquals(STR_ERR_DIVIDE_BY_ZERO, FWorksheet.ReadAsText(0, 1), 'Formula #16 SUM(A:A6) result mismatch');
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ Counts the sum of numeric elements.
|
procedure TCalcFormulaTests.Test_SUMIF;
|
||||||
Cases checked with Excel }
|
begin
|
||||||
|
// Test data, range A1:B5
|
||||||
|
FWorksheet.WriteNumber (0, 0, 10); FWorksheet.WriteNumber (0, 1, -1);
|
||||||
|
FWorksheet.WriteNumber (1, 0, 20); FWorksheet.WriteNumber (1, 1, -2);
|
||||||
|
FWorksheet.WriteNumber (2, 0, 40); FWorksheet.WriteNumber (2, 1, 6);
|
||||||
|
FWorksheet.WriteText (3, 0, '-40'); FWorksheet.WriteText (3, 1, '5');
|
||||||
|
FWorksheet.WriteText (4, 0, 'abc'); FWorksheet.WriteText (4, 1, 'ABC');
|
||||||
|
|
||||||
|
// Work data, range A8:B12
|
||||||
|
FWorksheet.WriteNumber ( 7, 0, 100); FWorksheet.WriteNumber ( 7, 1, -100);
|
||||||
|
FWorksheet.WriteNumber ( 8, 0, 200); FWorksheet.WriteNumber ( 8, 1, -200);
|
||||||
|
FWorksheet.WriteNumber ( 9, 0, 300); FWorksheet.WriteNumber ( 9, 1, -300);
|
||||||
|
FWorksheet.WriteText (10, 0, '400'); FWorksheet.WriteText (10, 1, '-500');
|
||||||
|
FWorksheet.WriteText (11, 0, 'xyz'); FWorksheet.WriteText (11, 1, 'XYZ');
|
||||||
|
|
||||||
|
|
||||||
|
// *** Range contains numbers only ***
|
||||||
|
|
||||||
|
// Calculate sum of the elements in A1:B3 which are equal to 0
|
||||||
|
FWorksheet.WriteFormula(0, 2, '=SUMIF(A1:B3,0)');
|
||||||
|
FWorksheet.CalcFormulas;
|
||||||
|
CheckEquals(0, FWorksheet.ReadAsNumber(0, 2), 'Formula #1 SUMIF(A1:B3,0) result mismatch');
|
||||||
|
|
||||||
|
// Calculate sum of the elements in A1:B3 which are < 0
|
||||||
|
FWorksheet.WriteFormula(0, 2, '=SUMIF(A1:B3,"<0")');
|
||||||
|
FWorksheet.CalcFormulas;
|
||||||
|
CheckEquals(-3, FWorksheet.ReadAsNumber(0, 2), 'Formula #2 SUMIF(A1:B3,"<0") result mismatch');
|
||||||
|
|
||||||
|
// Calculate sum of the elements in A8:B10 for which the elements in A1:B3 are equal to 10
|
||||||
|
FWorksheet.WriteFormula(0, 2, '=SUMIF(A1:B3,10,A8:B10)');
|
||||||
|
FWorksheet.CalcFormulas;
|
||||||
|
CheckEquals(100, FWorksheet.ReadAsNumber(0, 2), 'Formula #3 SUMIF(A1:B3,10,A8:B10) result mismatch');
|
||||||
|
|
||||||
|
// Compare cell A15
|
||||||
|
FWorksheet.WriteNumber( 14, 0, 10);
|
||||||
|
|
||||||
|
// Calculate sum of the elements in A1:B3 which are equal to cell A15 (value 10)
|
||||||
|
FWorksheet.WriteFormula(0, 2, '=SUMIF(A1:B3,A15)');
|
||||||
|
FWorksheet.CalcFormulas;
|
||||||
|
CheckEquals(10, FWorksheet.ReadAsNumber(0, 2), 'Formula #4 SUMIF(A1:B3,A15) result mismatch');
|
||||||
|
|
||||||
|
// Calculate sum of the elements in A1:B3 which are < cell A15
|
||||||
|
FWorksheet.WriteFormula(0, 2, '=SUMIF(A1:B3,"<"&A15)');
|
||||||
|
FWorksheet.CalcFormulas;
|
||||||
|
CheckEquals(3, FWorksheet.ReadAsNumber(0, 2), 'Formula #5 SUMIF(A1:B3,"<"&A15) result mismatch');
|
||||||
|
|
||||||
|
// Calculate sum of the elements in A8:B10 for which the elements in A1:B3 are equal to 10
|
||||||
|
FWorksheet.WriteFormula(0, 2, '=SUMIF(A1:B3,"<"&A15,A8:B10)');
|
||||||
|
FWorksheet.CalcFormulas;
|
||||||
|
CheckEquals(-600, FWorksheet.ReadAsNumber(0, 2), 'Formula #6 SUMIF(A1:B3,"<"&A15,A8:B10) result mismatch');
|
||||||
|
|
||||||
|
|
||||||
|
// *** Range contains also numeric strings ***
|
||||||
|
|
||||||
|
// Calculate sum of the elements in A1:B4 which are equal to -40
|
||||||
|
FWorksheet.WriteFormula(0, 2, '=SUMIF(A1:B4,-40)');
|
||||||
|
FWorksheet.CalcFormulas;
|
||||||
|
CheckEquals(-40, FWorksheet.ReadAsNumber(0, 2), 'Formula #7 SUMIF(A1:B4,-40) result mismatch');
|
||||||
|
|
||||||
|
// Calculate sum of the elements in A1:B4 which are < 0
|
||||||
|
FWorksheet.WriteFormula(0, 2, '=SUMIF(A1:B4,"<0")');
|
||||||
|
FWorksheet.CalcFormulas;
|
||||||
|
CheckEquals(-43, FWorksheet.ReadAsNumber(0, 2), 'Formula #8 SUMIF(A1:B4,"<0") result mismatch');
|
||||||
|
|
||||||
|
// Calculate sum of the elements in A8:B11 for which the elements in A1:B4 are equal to -40
|
||||||
|
FWorksheet.WriteFormula(0, 2, '=SUMIF(A1:B4,-40,A8:B11)');
|
||||||
|
FWorksheet.CalcFormulas;
|
||||||
|
CheckEquals(400, FWorksheet.ReadAsNumber(0, 2), 'Formula #9 SUMIF(A1:B4,-40,A8:B11) result mismatch');
|
||||||
|
|
||||||
|
// Compare cell A15
|
||||||
|
FWorksheet.WriteNumber( 14, 0, -40);
|
||||||
|
|
||||||
|
// Calculate sum of the elements in A1:B4 which are equal to cell A15
|
||||||
|
FWorksheet.WriteFormula(0, 2, '=SUMIF(A1:B4,A15)');
|
||||||
|
FWorksheet.CalcFormulas;
|
||||||
|
CheckEquals(-40, FWorksheet.ReadAsNumber(0, 2), 'Formula #10 SUMIF(A1:B4,A15) result mismatch');
|
||||||
|
|
||||||
|
// Calculate sum of the elements in A1:B4 which are equal <= cell A15
|
||||||
|
FWorksheet.WriteFormula(0, 2, '=SUMIF(A1:B4,"<="&A15)');
|
||||||
|
FWorksheet.CalcFormulas;
|
||||||
|
CheckEquals(-40, FWorksheet.ReadAsNumber(0, 2), 'Formula #11 SUMIF(A1:B4,"<="&A15) result mismatch');
|
||||||
|
|
||||||
|
// Calculate sum of the elements in A8:B11 for which the elements in A1:B4 are equal to cell A15
|
||||||
|
FWorksheet.WriteFormula(0, 2, '=SUMIF(A1:B4,A15,A8:B11)');
|
||||||
|
FWorksheet.CalcFormulas;
|
||||||
|
CheckEquals(400, FWorksheet.ReadAsNumber(0, 2), 'Formula #12 SUMIF(A1:B4,A15,A8:B11) result mismatch');
|
||||||
|
|
||||||
|
|
||||||
|
// *** Range contains also non-numeric strings ***
|
||||||
|
|
||||||
|
// Calculate sum of the elements in A1:B5 which are equal to -40
|
||||||
|
FWorksheet.WriteFormula(0, 2, '=SUMIF(A1:B5,-40)');
|
||||||
|
FWorksheet.CalcFormulas;
|
||||||
|
CheckEquals(-40, FWorksheet.ReadAsNumber(0, 2), 'Formula #13 SUMIF(A1:B5,-40) result mismatch');
|
||||||
|
|
||||||
|
// Calculate sum of the elements in A1:B5 which are < 0
|
||||||
|
FWorksheet.WriteFormula(0, 2, '=SUMIF(A1:B5,"<0")');
|
||||||
|
FWorksheet.CalcFormulas;
|
||||||
|
CheckEquals(-43, FWorksheet.ReadAsNumber(0, 2), 'Formula #14 SUMIF(A1:B5,"<0") result mismatch');
|
||||||
|
|
||||||
|
// Calculate sum of the elements in A8:B12 for which the elements in A1:B5 are equal to -40
|
||||||
|
FWorksheet.WriteFormula(0, 2, '=SUMIF(A1:B5,-40,A8:B12)');
|
||||||
|
FWorksheet.CalcFormulas;
|
||||||
|
CheckEquals(400, FWorksheet.ReadAsNumber(0, 2), 'Formula #15 SUMIF(A1:B5,-40,A8:B12) result mismatch');
|
||||||
|
|
||||||
|
|
||||||
|
// *** Range contains also error cells ***
|
||||||
|
|
||||||
|
// Calculate sum of the elements in A1:B5 which are equal to -40 --> error cell must be ignored
|
||||||
|
FWorksheet.WriteErrorValue(0, 0, errIllegalRef); // add error to A1
|
||||||
|
FWorksheet.WriteFormula(0, 2, '=SUMIF(A1:B5,-40)');
|
||||||
|
FWorksheet.CalcFormulas;
|
||||||
|
CheckEquals(-40, FWorksheet.ReadAsNumber(0, 2), 'Formula #16 SUMIF(A1:B5,-40) result mismatch');
|
||||||
|
|
||||||
|
// Calculate sum of the elements in A8:B13 for which the elements in A1:B6 are equal to 40
|
||||||
|
FWorksheet.WriteErrorValue(9, 0, errIllegalRef); // The value corresponding to 40 is an error now
|
||||||
|
FWorksheet.WriteFormula(0, 2, '=SUMIF(A1:B5,40,A8:B12)');
|
||||||
|
FWorksheet.CalcFormulas;
|
||||||
|
CheckEquals(STR_ERR_ILLEGAL_REF, FWorksheet.ReadAsText(0, 2), 'Formula #17 SUMIF(A1:B5,40,A8:B12) result mismatch');
|
||||||
|
|
||||||
|
|
||||||
|
// *** Compare cell contains an error (A15)
|
||||||
|
FWorksheet.WriteFormula( 14, 0, '=1/0');
|
||||||
|
|
||||||
|
// Calculate sum of the elements in A1:B5 which are equal to cell A15 (containing #DIV/0!)
|
||||||
|
FWorksheet.WriteFormula(0, 2, '=SUMIF(A1:B5,A15)');
|
||||||
|
FWorksheet.CalcFormulas;
|
||||||
|
CheckEquals(0, FWorksheet.ReadAsNumber(0, 2), 'Formula #18 SUMIF(A1:B5,A15) result mismatch');
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TCalcFormulaTests.Test_SUMSQ;
|
procedure TCalcFormulaTests.Test_SUMSQ;
|
||||||
begin
|
begin
|
||||||
// Test data
|
// Test data
|
||||||
|
Loading…
Reference in New Issue
Block a user