FPSpreadsheet: Add more unit tests for formula AVERAGEIF .

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@9606 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz 2025-01-27 23:05:14 +00:00
parent e66040bd5c
commit 5c33ac9769
4 changed files with 132 additions and 13 deletions

View File

@ -5026,6 +5026,7 @@ begin
end;
rtInteger : Result := IntToStr(Arg.ResInteger);
rtFloat : Result := FloatToStr(Arg.ResFloat);
rtDateTime : Result := FloatToStr(Arg.ResDateTime);
rtBoolean : if Arg.ResBoolean then Result := '1' else Result := '0';
rtCell : begin
cell := ArgToCell(Arg);

View File

@ -241,11 +241,9 @@ begin
begin
if TryStrToFloat(cell^.UTF8StringValue, value) then
Result := CompareNumber(value);
{
if not TryStrToFloat(cell^.UTF8StringValue, value) then value := 0.0;
Result := CompareNumber(value);
}
end;
cctError:
Result := false;
end;
end;
ctString:
@ -270,7 +268,7 @@ begin
Result := true
else
if (cell <> nil) and (cell^.ContentType = cctError) then
REsult := CompareError(cell^.ErrorValue);
Result := CompareError(cell^.ErrorValue);
end;
end;
@ -367,7 +365,10 @@ begin
Result := ErrorResult(FError);
exit;
end;
sum := sum + val;
if IsNaN(val) then
dec(count)
else
sum := sum + val;
end;
end;
end;
@ -402,12 +403,20 @@ begin
begin
cell := TsWorksheet(ASheet).FindCell(ARow, ACol);
if cell <> nil then
case cell^.Contenttype of
cctNumber : Result := cell^.NumberValue;
cctDateTime: Result := cell^.DateTimeValue;
cctBool : if cell^.BoolValue then Result := 1.0;
cctUTF8String : if not TryStrToFloat(cell^.UTF8StringValue, Result) then Result := 0.0;
cctError: FError := cell^.ErrorValue;
case cell^.ContentType of
cctNumber:
Result := cell^.NumberValue;
cctDateTime:
Result := cell^.DateTimeValue;
cctBool:
Result := NaN;
cctUTF8String:
if not TryStrToFloat(cell^.UTF8StringValue, Result) then Result := NaN;
cctError:
begin
FError := cell^.ErrorValue;
Result := NaN;
end;
end;
end;
end;
@ -464,7 +473,7 @@ begin
end else
begin
s := ArgToString(FArgs[ArgIndex]);
if (Length(s) > 1) and (s[1] in ['=', '<', '>']) then
if (Length(s) >= 1) and (s[1] in ['=', '<', '>']) then
s := AnalyzeCompareStr(s, FCompareOperation);
if s = '' then
FCompareType := ctEmpty

View File

@ -2461,6 +2461,9 @@ begin
'=' : RemoveChars(1, coEqual);
else RemoveChars(0, coEqual);
end
else
if AString = '=' then
RemoveChars(1, coEqual)
else
RemoveChars(0, coEqual);
end;

View File

@ -23,6 +23,7 @@ type
procedure Test_AND;
procedure Test_AVEDEV;
procedure Test_AVERAGE;
procedure Test_AVERAGEIF;
procedure Test_CEILING;
procedure Test_COUNT;
procedure Test_COUNTA;
@ -326,6 +327,111 @@ begin
CheckEquals(STR_ERR_DIVIDE_BY_ZERO, FWorksheet.ReadAsText(0, 1), 'Formula #16 AVERAGE(A:A6) result mismatch');
end;
procedure TCalcFormulaTests.Test_AVERAGEIF;
const
EPS = 1E-8;
begin
// Test data, value range A1:B9
// A1:A9 - compare values // B1:B9 -- calculation values
FWorksheet.WriteText(0, 0, 'Abc'); FWorksheet.WriteNumber (0, 1, 100);
FWorksheet.WriteText(1, 0, 'Abc'); FWorksheet.WriteNumber (1, 1, 200);
FWorksheet.WriteText(2, 0, 'bc'); FWorksheet.WriteNumber (2, 1, 300);
FWorksheet.WriteText(3, 0, 'a'); FWorksheet.WriteNumber (3, 1, 400);
FWorksheet.WriteText(4, 0, 'bc'); FWorksheet.WriteText (4, 1, '500');
FWorksheet.WriteText(5, 0, 'abc'); FWorksheet.WriteText (5, 1, 'no number');
FWorksheet.WriteText(6, 0, ''); FWorksheet.WriteNumber (6, 1, 600);
FWorksheet.WriteDateTime(7, 0, EncodeDate(2025,2,1)); FWorksheet.WriteNumber (7, 1, 700);
FWorksheet.WriteText(8, 0, 'abc'); FWorksheet.WriteBoolValue (8, 1, TRUE);
FWorksheet.WriteText(9, 0, 'abc'); FWorksheet.WriteErrorValue(9, 1, errIllegalRef);
// *** two-argument calls
// Average value of all cells in the second column with are <=200
FWorksheet.WriteFormula(0, 2, '=AVERAGEIF(B1:B8,"<=200")');
FWorksheet.CalcFormulas;
CheckEquals(150, FWorksheet.ReadAsNumber(0, 2), 'Formula #1 AVERAGEIF(B1:B8,"<=200") result mismatch');
// Average value of all cells in the second column with are >=400
FWorksheet.WriteFormula(0, 2, '=AVERAGEIF(B1:B8,">=400")');
FWorksheet.CalcFormulas;
CheckEquals(550, FWorksheet.ReadAsNumber(0, 2), 'Formula #2 AVERAGEIF(B1:B8,">=400") result mismatch');
// Average value of all cells in the second column with are <0
FWorksheet.WriteFormula(0, 2, '=AVERAGEIF(B1:B9,"<0")');
FWorksheet.CalcFormulas;
CheckEquals(STR_ERR_DIVIDE_BY_ZERO, FWorksheet.ReadAsText(0, 2), 'Formula #3 AVERAGEIF(B1:B9,"<0") result mismatch');
// *** three-argument calls
// Average value of all cells in the second column for which the first column cell is 'abc' (case-insensitive)'
// ... numeric cells only (incl numeric text cell)
FWorksheet.WriteFormula(0, 2, '=AVERAGEIF(A1:A5,"abc",B1:B5)');
FWorksheet.CalcFormulas;
CheckEquals(150, FWorksheet.ReadAsNumber(0, 2), 'Formula #4 AVERAGEIF(A1:A5,"abc",B1:B5) result mismatch');
// ... dto, but check case-insensitivity of search phrase
FWorksheet.WriteFormula(0, 2, '=AVERAGEIF(A1:A5,"ABC",B1:B5)');
FWorksheet.CalcFormulas;
CheckEquals(150, FWorksheet.ReadAsNumber(0, 2), 'Formula #5 AVERAGEIF(A1:A5,"ABC",B1:B5) result mismatch');
// ... including non-numeric text cell
FWorksheet.WriteFormula(0, 2, '=AVERAGEIF(A1:A7,"abc",B1:B7)');
FWorksheet.CalcFormulas;
CheckEquals(150, FWorksheet.ReadAsNumber(0, 2), 'Formula #6 AVERAGEIF(A1:A7,"abc",B1:B7) result mismatch');
// ... including boolean cell
FWorksheet.WriteFormula(0, 2, '=AVERAGEIF(A1:A9,"abc",B1:B9)');
FWorksheet.CalcFormulas;
CheckEquals(150, FWorksheet.ReadAsNumber(0, 2), 'Formula #7 AVERAGEIF(A1:A9,"abc",B1:B9) result mismatch');
// ... including error cell
FWorksheet.WriteFormula(0, 2, '=AVERAGEIF(A1:A10,"abc",B1:B10)');
FWorksheet.CalcFormulas;
CheckEquals(STR_ERR_ILLEGAL_REF, FWorksheet.ReadAsText(0, 2), 'Formula #8 AVERAGEIF(A1:A10,"abc",B1:B10) result mismatch');
// ToDo: CompareStringsWithWildcards does not handle a mask such as "*b" like Excel
{
// Search for text cells by wildcards
FWorksheet.WriteFormula(0, 2, '=AVERAGEIF(A1:A8,"*bc",B1:B8)');
FWorksheet.CalcFormulas;
CheckEquals(275, FWorksheet.ReadAsNumber(0, 2), 'Formula #9 AVERAGEIF(A1:A8,"*bc",B1:B8) result mismatch');
}
// Search for date cells (matching cell found)
FWorksheet.WriteFormula(0, 2, '=AVERAGEIF(A1:A8,DATE(2025,2,1),B1:B8)');
FWorksheet.CalcFormulas;
CheckEquals(700, FWorksheet.ReadAsNumber(0, 2), 'Formula #9 AVERAGEIF(A1:A8,DATE(2025,2,1),B1:B8) result mismatch');
// Search for date cell (no matching cell found)
FWorksheet.WriteFormula(0, 2, '=AVERAGEIF(A1:A8,DATE(2000,2,1),B1:B8)');
FWorksheet.CalcFormulas;
CheckEquals(STR_ERR_DIVIDE_BY_ZERO, FWorksheet.ReadAsText(0, 2), 'Formula #9 AVERAGEIF(A1:A8,DATE(2000,2,1),B1:B8) result mismatch');
// Search for empty cells
FWorksheet.WriteFormula(0, 2, '=AVERAGEIF(A1:A8,"",B1:B8)');
FWorksheet.CalcFormulas;
CheckEquals(600, FWorksheet.ReadAsNumber(0, 2), 'Formula #10 AVERAGEIF(A1:A8,"",B1:B8) result mismatch');
FWorksheet.WriteFormula(0, 2, '=AVERAGEIF(A1:A8,"=",B1:B8)');
FWorksheet.CalcFormulas;
CheckEquals(600, FWorksheet.ReadAsNumber(0, 2), 'Formula #11 AVERAGEIF(A1:A8,"Abc",B1:B8) result mismatch');
// Search for non-empty cells
FWorksheet.WriteFormula(0, 2, '=AVERAGEIF(A1:A8,"<>",B1:B8)');
FWorksheet.CalcFormulas;
CheckEquals(2200/6, FWorksheet.ReadAsNumber(0, 2), EPS, 'Formula #12 AVERAGEIF(A1:A8,"<>",B1:B8) result mismatch');
// Compare with reference cell A20
FWorksheet.WriteText(19, 0, 'abc'); // A20 = "abc"
FWorksheet.WriteFormula(0, 2, '=AVERAGEIF(A1:A9,A20,B1:B9)');
FWorksheet.CalcFormulas;
CheckEquals(150, FWorksheet.ReadAsNumber(0, 2), 'Formula #13 AVERAGEIF(A1:A9,A20,B1:B9) (A20="abc") result mismatch');
FWorksheet.WriteFormula(0, 2, '=AVERAGEIF(A1:A9,"<>"&A20,B1:B9)');
FWorksheet.CalcFormulas;
CheckEquals(500, FWorksheet.ReadAsNumber(0, 2), 'Formula #13 AVERAGEIF(A1:A9,"<>"&A20,B1:B9) (A20="abc") result mismatch');
end;
procedure TCalcFormulaTests.Test_CEILING;
begin
// Examples from https://exceljet.net/functions/ceiling-function