fpspreadsheet: Clip cell ranges at the sheet dimension limits. Add some test cases for it.
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@9651 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
parent
31951b323a
commit
cfe6c14a8f
@ -5153,6 +5153,7 @@ const
|
||||
var
|
||||
i, n: Integer;
|
||||
r, c: Cardinal;
|
||||
r1, c1, r2, c2: Cardinal;
|
||||
cell: PCell;
|
||||
sheet: TsWorksheet;
|
||||
book: TsWorkbook;
|
||||
@ -5215,8 +5216,11 @@ begin
|
||||
for idx := idx1 to idx2 do
|
||||
begin
|
||||
sheet := (arg.Worksheet as TsWorksheet).Workbook.GetWorksheetByIndex(idx);
|
||||
for r := arg.ResCellRange.Row1 to arg.ResCellRange.Row2 do
|
||||
for c := arg.ResCellRange.Col1 to arg.ResCellRange.Col2 do
|
||||
r2 := sheet.GetLastOccupiedRowIndex;
|
||||
sheet.GetSheetDim(r1, c1, r2, c2);
|
||||
TrimCellRange(arg.ResCellRange, r1, c1, r2, c2);
|
||||
for r := r1 to r2 do
|
||||
for c := c1 to c2 do
|
||||
begin
|
||||
cell := sheet.FindCell(r, c);
|
||||
if (cell <> nil) then
|
||||
|
@ -117,7 +117,8 @@ type
|
||||
function GetArgValue(ArgIndex: Integer): Double;
|
||||
function GetCellValue(ASheet: TsBasicWorksheet; ARow, ACol: Integer): Double;
|
||||
procedure GetCompareParams(ArgIndex: Integer);
|
||||
procedure GetRangeLimits(ArgIndex: Integer; out ARow1, ACol1, ARow2, ACol2: Integer);
|
||||
procedure GetRangeLimits(ArgIndex: Integer; ASheet: TsBasicWorksheet;
|
||||
out ARow1, ACol1, ARow2, ACol2: Cardinal);
|
||||
function GetWorkbook: TsBasicWorkbook;
|
||||
function GetWorksheet(ArgIndex: Integer): TsBasicWorksheet;
|
||||
function SameRangeSize(ARange1, ARange2: TsCellRange3D): Boolean;
|
||||
@ -276,7 +277,8 @@ end;
|
||||
returns the result to be used by the formula engine. }
|
||||
function TsFuncComparer.Execute: TsExpressionResult;
|
||||
var
|
||||
r, r1, r2, c, c1, c2, rIdx, cIdx: Integer;
|
||||
r, r1, r2, c, c1, c2: Cardinal;
|
||||
rIdx, cIdx: Integer;
|
||||
critIdx: Integer;
|
||||
critRangeIdx: Integer;
|
||||
critSheet: TsBasicWorksheet;
|
||||
@ -302,7 +304,7 @@ begin
|
||||
sum := 0.0;
|
||||
|
||||
// Iterate over all value range cells
|
||||
GetRangeLimits(FValueRangeIndex, r1, c1, r2, c2);
|
||||
GetRangeLimits(FValueRangeIndex, valueSheet, r1, c1, r2, c2);
|
||||
for r := r1 to r2 do
|
||||
begin
|
||||
for c := c1 to c2 do
|
||||
@ -522,7 +524,8 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TsFuncComparer.GetRangeLimits(ArgIndex: Integer; out ARow1, ACol1, ARow2, ACol2: Integer);
|
||||
procedure TsFuncComparer.GetRangeLimits(ArgIndex: Integer; ASheet: TsBasicWorksheet;
|
||||
out ARow1, ACol1, ARow2, ACol2: Cardinal);
|
||||
begin
|
||||
case FArgs[ArgIndex].ResultType of
|
||||
rtCell:
|
||||
@ -532,10 +535,8 @@ begin
|
||||
end;
|
||||
rtCellRange:
|
||||
begin
|
||||
ARow1 := FArgs[ArgIndex].ResCellRange.Row1;
|
||||
ARow2 := FArgs[ArgIndex].ResCellRange.Row2;
|
||||
ACol1 := FArgs[ArgIndex].ResCellRange.Col1;
|
||||
ACol2 := FArgs[ArgIndex].ResCellRange.Col2;
|
||||
TsWorksheet(ASheet).GetSheetDim(ARow1, ACol1, ARow2, ACol2);
|
||||
TrimCellRange(FArgs[ArgIndex].ResCellRange, ARow1, ACol1, ARow2, ACol2);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
@ -487,6 +487,8 @@ type
|
||||
function GetLastOccupiedRowIndex: Cardinal;
|
||||
function GetLastRowIndex(AForceCalculation: Boolean = false): Cardinal;
|
||||
function GetLastRowNumber: Cardinal; deprecated 'Use GetLastRowIndex';
|
||||
procedure GetSheetDim(out AFirstRow, AFirstCol, ALastRow, ALastCol: Cardinal;
|
||||
AForceCalculation: Boolean = false);
|
||||
|
||||
{ Data manipulation methods - For Rows and Cols }
|
||||
function AddCol(ACol: Cardinal): PCol;
|
||||
@ -2744,7 +2746,7 @@ begin
|
||||
end;
|
||||
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
Deprecated, use GetLastColIndex instead
|
||||
Deprecated, use GetLastRowIndex instead
|
||||
|
||||
@seeAlso GetLastColIndex
|
||||
-------------------------------------------------------------------------------}
|
||||
@ -2753,6 +2755,44 @@ begin
|
||||
Result := GetLastRowIndex;
|
||||
end;
|
||||
|
||||
procedure TsWorksheet.GetSheetDim(out AFirstRow, AFirstCol, ALastRow, ALastCol: Cardinal;
|
||||
AForceCalculation: Boolean = false);
|
||||
var
|
||||
cell: PCell;
|
||||
begin
|
||||
if AForceCalculation then
|
||||
begin
|
||||
cell := FCells.GetFirstCell;
|
||||
if cell <> nil then
|
||||
begin
|
||||
AFirstRow := cell^.Row;
|
||||
AFirstCol := cell^.Col;
|
||||
end else
|
||||
begin
|
||||
AFirstRow := 0;
|
||||
AfirstCol := 0;
|
||||
end;
|
||||
|
||||
cell := FCells.GetLastCell;
|
||||
if cell <> nil then
|
||||
begin
|
||||
ALastRow := cell^.Row;
|
||||
ALastCol := cell^.Col;
|
||||
end else
|
||||
begin
|
||||
ALastRow := AFirstRow;
|
||||
ALastCol := AFirstCol;
|
||||
end;
|
||||
end else
|
||||
begin
|
||||
AFirstRow := FFirstRowIndex;
|
||||
AFirstCol := FFirstColIndex;
|
||||
ALastRow := FLastRowIndex;
|
||||
ALastCol := FLastColIndex;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
Reads the contents of a cell and returns an user readable text
|
||||
representing the contents of the cell.
|
||||
|
@ -255,6 +255,9 @@ function Range(ARow, ACol: Cardinal): TsCellRange; overload;
|
||||
function Range(ARow1, ACol1, ARow2, ACol2: Cardinal): TsCellRange; overload;
|
||||
function Range3D(ASheetIdx1, ASheetIdx2: Integer; ARow1, ACol1, ARow2, ACol2: Cardinal): TsCellRange3D;
|
||||
|
||||
procedure TrimCellRange(ARange: TsCellRange; var ARow1, ACol1, ARow2, ACol2: Cardinal);
|
||||
procedure TrimCellRange(ARange: TsCellRange3D; var ARow1, ACol1, ARow2, ACol2: Cardinal);
|
||||
|
||||
{$IF FPC_FullVersion < 30200}
|
||||
function FMod(const a, b: Double): Double; inline; overload;
|
||||
{$IFEND}
|
||||
@ -3060,6 +3063,22 @@ begin
|
||||
Result.Sheet2 := ASheetIdx2;
|
||||
end;
|
||||
|
||||
procedure TrimCellRange(ARange: TsCellRange; var ARow1, ACol1, ARow2, ACol2: Cardinal);
|
||||
begin
|
||||
if ARange.Row1 > ARow1 then ARow1 := ARange.Row1;
|
||||
if ARange.Col1 > ACol1 then ACol1 := ARange.Col1;
|
||||
if ARange.Row2 < ARow2 then ARow2 := ARange.Row2;
|
||||
if ARange.Col2 < ACol2 then ACol2 := ARange.Col2;
|
||||
end;
|
||||
|
||||
procedure TrimCellRange(ARange: TsCellRange3D; var ARow1, ACol1, ARow2, ACol2: Cardinal);
|
||||
begin
|
||||
if ARange.Row1 > ARow1 then ARow1 := ARange.Row1;
|
||||
if ARange.Col1 > ACol1 then ACol1 := ARange.Col1;
|
||||
if ARange.Row2 < ARow2 then ARow2 := ARange.Row2;
|
||||
if ARange.Col2 < ACol2 then ACol2 := ARange.Col2;
|
||||
end;
|
||||
|
||||
{$IF FPC_FullVersion < 30200}
|
||||
function FMod(const a, b: Double): Double;
|
||||
begin
|
||||
|
@ -71,7 +71,8 @@ type
|
||||
procedure Test_ADDRESS;
|
||||
procedure Test_COLUMN;
|
||||
// procedure Test_HYPERLINK -- to be written
|
||||
procedure Test_INDEX;
|
||||
procedure Test_INDEX_1;
|
||||
procedure Test_INDEX_2;
|
||||
procedure Test_INDIRECT;
|
||||
procedure Test_MATCH;
|
||||
procedure Test_ROW;
|
||||
|
@ -109,7 +109,7 @@ begin
|
||||
CheckEquals(2, FWorksheet.ReadAsNumber(0, 2), 'Formula #4 COLUMN(B2) (B2 contains error) result mismatch');
|
||||
end;
|
||||
|
||||
procedure TCalcLookupFormulaTests.Test_INDEX;
|
||||
procedure TCalcLookupFormulaTests.Test_INDEX_1;
|
||||
var
|
||||
sh: TsWorksheet;
|
||||
begin
|
||||
@ -126,9 +126,11 @@ begin
|
||||
FWorksheet.WriteFormula(10, 0, '=INDEX(B2:C6,3,1)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(42, FWorksheet.ReadAsNumber(10,0), 'Formula #1 INDEX(B2:F3,3,1) result mismatch');
|
||||
end;
|
||||
|
||||
procedure TCalcLookupFormulaTests.Test_INDEX_2;
|
||||
begin
|
||||
// Sample similar to that in unit formulatests:
|
||||
|
||||
FWorksheet.Clear;
|
||||
FWorksheet.WriteText (0, 0, 'A'); // A1
|
||||
FWorksheet.WriteText (0, 1, 'B'); // B1
|
||||
@ -183,11 +185,11 @@ begin
|
||||
|
||||
FOtherWorksheet.WriteFormula(0, 5, 'SUM(INDEX(Sheet1!A1:C3,0,2))'); // Sum of numbers in 2nd column of A1:C3
|
||||
FWorkbook.CalcFormulas;
|
||||
CheckEquals(42, FOtherWorksheet.ReadAsNumber(0, 5), 'Formula #6 SUM(Sheet1!INDEX(A1:C3,0,2)) result mismatch');
|
||||
CheckEquals(42, FOtherWorksheet.ReadAsNumber(0, 5), 'Formula #12 SUM(Sheet1!INDEX(A1:C3,0,2)) result mismatch');
|
||||
|
||||
FOtherWorksheet.WriteFormula(0, 5, 'SUM(INDEX(Sheet1!A1:C3,2,0))'); // Sum of numbers in 2nd row of A1:C3
|
||||
FWorkbook.CalcFormulas;
|
||||
CheckEquals(60, FOtherWorksheet.ReadAsNumber(0, 5), 'Formula #7 SUM(Sheet1!INDEX(A1:C3,2,0)) result mismatch');
|
||||
CheckEquals(60, FOtherWorksheet.ReadAsNumber(0, 5), 'Formula #13 SUM(Sheet1!INDEX(A1:C3,2,0)) result mismatch');
|
||||
end;
|
||||
|
||||
procedure TCalcLookupFormulaTests.Test_INDIRECT;
|
||||
|
@ -238,7 +238,7 @@ begin
|
||||
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
|
||||
// ToDo: CompareStringsWithWildcards does not handle a mask such as "*b" like Excel // wp: really? I thought this was fixed!
|
||||
{
|
||||
// Search for text cells by wildcards
|
||||
FWorksheet.WriteFormula(0, 2, '=AVERAGEIF(A1:A8,"*bc",B1:B8)');
|
||||
@ -461,13 +461,15 @@ begin
|
||||
end;
|
||||
|
||||
procedure TCalcStatsFormulaTests.Test_COUNTIF;
|
||||
var
|
||||
t: TDateTime;
|
||||
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.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)
|
||||
@ -498,44 +500,52 @@ begin
|
||||
// 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');
|
||||
CheckEquals(1, FWorksheet.ReadAsNumber(0, 2), 'Formula #6 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');
|
||||
CheckEquals(2, FWorksheet.ReadAsNumber(0, 2), 'Formula #7 COUNTIF(A1:B6,#NUM!) result mismatch');
|
||||
|
||||
// Error in 1st argument
|
||||
FWorksheet.WriteFormula(0, 2, '=COUNTIF(#REF!,1)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(STR_ERR_ILLEGAL_REF, FWorksheet.ReadAsText(0, 2), 'Formula #7 COUNTIF(#REF!,1) result mismatch');
|
||||
CheckEquals(STR_ERR_ILLEGAL_REF, FWorksheet.ReadAsText(0, 2), 'Formula #8 COUNTIF(#REF!,1) result mismatch');
|
||||
|
||||
// Error in both arguments
|
||||
FWorksheet.WriteFormula(0, 2, '=COUNTIF(#REF!,#REF!)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(STR_ERR_ILLEGAL_REF, FWorksheet.ReadAsText(0, 2), 'Formula #8 COUNTIF(#REF!,#REF!) result mismatch');
|
||||
CheckEquals(STR_ERR_ILLEGAL_REF, FWorksheet.ReadAsText(0, 2), 'Formula #9 COUNTIF(#REF!,#REF!) 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 #9 COUNTIF(A1:B6,A15) (A15 empty) result mismatch');
|
||||
CheckEquals(2, FWorksheet.ReadAsNumber(0, 2), 'Formula #10 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 #10 COUNTIF(A1:B6,A15) (A15 = 10) result mismatch');
|
||||
CheckEquals(1, FWorksheet.ReadAsNumber(0, 2), 'Formula #11 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 #11 COUNTIF(A1:B6,"<"&A15) (A15 = 10) result mismatch');
|
||||
CheckEquals(3, FWorksheet.ReadAsNumber(0, 2), 'Formula #12 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 #12 COUNTIF(A1:B6,A15) (A15 = #NUM!) result mismatch');
|
||||
CheckEquals(2, FWorksheet.ReadAsNumber(0, 2), 'Formula #13 COUNTIF(A1:B6,A15) (A15 = #NUM!) result mismatch');
|
||||
|
||||
// Huge range
|
||||
FWorksheet.WriteFormula(0, 1, '=COUNTIF(A2:AZ999999,"abc")'); // A2: do not include formula cell in range
|
||||
t := Now;
|
||||
FWorksheet.CalcFormulas;
|
||||
t := Now-t;
|
||||
CheckEquals(2, FWorksheet.ReadAsNumber(0, 1), 'Formula #14 COUNTIF(A2:AZ999999,"abc") result mismatch');
|
||||
CheckEquals(true, t < 0.1/(24*60*60), 'Formula #14 COUNTIF(A2:AZ999999,"abc") takes too long');
|
||||
end;
|
||||
|
||||
procedure TCalcStatsFormulaTests.Test_MAX;
|
||||
@ -978,6 +988,8 @@ begin
|
||||
end;
|
||||
|
||||
procedure TCalcStatsFormulaTests.Test_SUM;
|
||||
var
|
||||
t: TDateTime;
|
||||
begin
|
||||
// Test data
|
||||
FWorksheet.WriteNumber (0, 0, 10);
|
||||
@ -1021,50 +1033,63 @@ begin
|
||||
CheckEquals(STR_ERR_DIVIDE_BY_ZERO, FWorksheet.ReadAsText(0, 1), 'Formula #8 SUM(1/0) result mismatch');
|
||||
|
||||
// Count in cell references
|
||||
|
||||
FWorksheet.WriteFormula(0, 1, '=SUM(A1)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(10, FWorksheet.ReadAsNumber(0, 1), 'Formula #7 SUM(A1) result mismatch');
|
||||
CheckEquals(10, FWorksheet.ReadAsNumber(0, 1), 'Formula #9 SUM(A1) result mismatch');
|
||||
|
||||
FWorksheet.WriteFormula(0, 1, '=SUM(A10)'); // empty cell
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(0, FWorksheet.ReadAsNumber(0, 1), 'Formula #8 SUM(A10) result mismatch');
|
||||
CheckEquals(0, FWorksheet.ReadAsNumber(0, 1), 'Formula #10 SUM(A10) result mismatch');
|
||||
|
||||
FWorksheet.WriteFormula(0, 1, '=SUM(A1,A2)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(30, FWorksheet.ReadAsNumber(0, 1), 'Formula #9 SUM(A1,A2) result mismatch');
|
||||
CheckEquals(30, FWorksheet.ReadAsNumber(0, 1), 'Formula #11 SUM(A1,A2) result mismatch');
|
||||
|
||||
FWorksheet.WriteFormula(0, 1, '=SUM(A1:A3)'); // "real" numeric values
|
||||
// "real" numeric values
|
||||
FWorksheet.WriteFormula(0, 1, '=SUM(A1:A3)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(60, FWorksheet.ReadAsNumber(0, 1), 'Formula #10 SUM(A1:A3) result mismatch');
|
||||
CheckEquals(60, FWorksheet.ReadAsNumber(0, 1), 'Formula #12 SUM(A1:A3) result mismatch');
|
||||
|
||||
FWorksheet.WriteFormula(0, 1, '=SUM(A1,A2:A3)'); // several ranges
|
||||
// Several ranges
|
||||
FWorksheet.WriteFormula(0, 1, '=SUM(A1,A2:A3)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(60, FWorksheet.ReadAsNumber(0, 1), 'Formula #11 SUM(A1,A2:A3) result mismatch');
|
||||
CheckEquals(60, FWorksheet.ReadAsNumber(0, 1), 'Formula #13 SUM(A1,A2:A3) result mismatch');
|
||||
|
||||
// Huge range
|
||||
FWorksheet.WriteFormula(0, 1, '=SUM(A1:A3,A10:A999999)');
|
||||
t := Now;
|
||||
FWorksheet.CalcFormulas;
|
||||
t := Now-t;
|
||||
CheckEquals(60, FWorksheet.ReadAsNumber(0, 1), 'Formula #14 SUM(A1:A3,A10:A999999) result mismatch');
|
||||
CheckEquals(true, t < 0.1/(24*60*60), 'Formula #14 SUM(A1:A3,A10:A999999) takes too long');
|
||||
|
||||
// Cell references pointing to string cells
|
||||
FWorksheet.WriteFormula(0, 1, '=SUM(A1:A4)'); // real and string numeric values
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(100, FWorksheet.ReadAsNumber(0, 1), 'Formula #12 SUM(A1:A4) result mismatch');
|
||||
CheckEquals(100, FWorksheet.ReadAsNumber(0, 1), 'Formula #15 SUM(A1:A4) result mismatch');
|
||||
|
||||
FWorksheet.WriteFormula(0, 1, '=SUM(A1:A5)'); // real and string values --> ignore string
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(100, FWorksheet.ReadAsNumber(0, 1), 'Formula #13 SUM(A1:A5) result mismatch');
|
||||
CheckEquals(100, FWorksheet.ReadAsNumber(0, 1), 'Formula #16 SUM(A1:A5) result mismatch');
|
||||
|
||||
FWorksheet.WriteFormula(0, 1, '=SUM(A1:A4,A8:A10)'); // real and string values and blanks
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(100, FWorksheet.ReadAsNumber(0, 1), 'Formula #14 SUM(A1:A4,A8:A10) result mismatch');
|
||||
CheckEquals(100, FWorksheet.ReadAsNumber(0, 1), 'Formula #17 SUM(A1:A4,A8:A10) result mismatch');
|
||||
|
||||
// Error propagation
|
||||
FWorksheet.WriteFormula(0, 1, '=SUM(A1, 1/0, A2)'); // error in argument
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(STR_ERR_DIVIDE_BY_ZERO, FWorksheet.ReadAsText(0, 1), 'Formula #15 SUM(A1, 1/0, A2) result mismatch');
|
||||
CheckEquals(STR_ERR_DIVIDE_BY_ZERO, FWorksheet.ReadAsText(0, 1), 'Formula #18 SUM(A1, 1/0, A2) result mismatch');
|
||||
|
||||
FWorksheet.WriteFormula(0, 1, '=SUM(A1:A6)'); // error in cell
|
||||
FWorksheet.CalcFormulas;
|
||||
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 #19 SUM(A:A6) result mismatch');
|
||||
end;
|
||||
|
||||
procedure TCalcStatsFormulaTests.Test_SUMIF;
|
||||
var
|
||||
t: TDateTime;
|
||||
begin
|
||||
// Test data, range A1:B5
|
||||
FWorksheet.WriteNumber (0, 0, 10); FWorksheet.WriteNumber (0, 1, -1);
|
||||
@ -1217,6 +1242,14 @@ begin
|
||||
CheckEquals(1, FWorksheet.ReadAsNumber(0, 2), 'Formula #22 SUMIF(A1:B5,A15) (A1=A15=#DIV/0!) result mismatch');
|
||||
//CheckEquals(STR_ERR_DIVIDE_BY_ZERO, FWorksheet.ReadAsText(0, 2), 'Formula #21 SUMIF(A1:B5,A15) (A15=#DIV/0!) result mismatch');
|
||||
|
||||
// Huge range
|
||||
FWorksheet.WriteFormula(0, 1, '=SUMIF(A2:Z999999,0)'); // A2: do not include formula cell in range
|
||||
t := Now;
|
||||
FWorksheet.CalcFormulas;
|
||||
t := Now-t;
|
||||
CheckEquals(0, FWorksheet.ReadAsNumber(0, 1), 'Formula #22 SUMIF(A2:Z999999,0) result mismatch');
|
||||
CheckEquals(true, t < 0.1/(24*60*60), 'Formula #22 SUMIF(A2:Z999999,0) takes too long');
|
||||
|
||||
end;
|
||||
|
||||
procedure TCalcStatsFormulaTests.Test_SUMSQ;
|
||||
@ -1265,50 +1298,52 @@ begin
|
||||
// Count in cell references
|
||||
FWorksheet.WriteFormula(0, 1, '=SUMSQ(A1)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(1, FWorksheet.ReadAsNumber(0, 1), 'Formula #7 SUMSQ(A1) result mismatch');
|
||||
CheckEquals(1, FWorksheet.ReadAsNumber(0, 1), 'Formula #9 SUMSQ(A1) result mismatch');
|
||||
|
||||
FWorksheet.WriteFormula(0, 1, '=SUMSQ(A10)'); // empty cell
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(0, FWorksheet.ReadAsNumber(0, 1), 'Formula #8 SUMSQ(A10) result mismatch');
|
||||
CheckEquals(0, FWorksheet.ReadAsNumber(0, 1), 'Formula #10 SUMSQ(A10) result mismatch');
|
||||
|
||||
FWorksheet.WriteFormula(0, 1, '=SUMSQ(A1,A2)');
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(5, FWorksheet.ReadAsNumber(0, 1), 'Formula #9 SUMSQ(A1,A2) result mismatch');
|
||||
CheckEquals(5, FWorksheet.ReadAsNumber(0, 1), 'Formula #11 SUMSQ(A1,A2) result mismatch');
|
||||
|
||||
FWorksheet.WriteFormula(0, 1, '=SUMSQ(A1:A3)'); // "real" numeric values
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(14, FWorksheet.ReadAsNumber(0, 1), 'Formula #10 SUMSQ(A1:A3) result mismatch');
|
||||
CheckEquals(14, FWorksheet.ReadAsNumber(0, 1), 'Formula #12 SUMSQ(A1:A3) result mismatch');
|
||||
|
||||
FWorksheet.WriteFormula(0, 1, '=SUMSQ(A1,A2:A3)'); // several ranges
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(14, FWorksheet.ReadAsNumber(0, 1), 'Formula #11 SUMSQ(A1,A2:A3) result mismatch');
|
||||
CheckEquals(14, FWorksheet.ReadAsNumber(0, 1), 'Formula #13 SUMSQ(A1,A2:A3) result mismatch');
|
||||
|
||||
// Cell references pointing to string cells
|
||||
FWorksheet.WriteFormula(0, 1, '=SUMSQ(A1:A4)'); // "real" and string numeric values
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(30, FWorksheet.ReadAsNumber(0, 1), 'Formula #12 SUMSQ(A1:A4) result mismatch');
|
||||
CheckEquals(30, FWorksheet.ReadAsNumber(0, 1), 'Formula #14 SUMSQ(A1:A4) result mismatch');
|
||||
|
||||
FWorksheet.WriteFormula(0, 1, '=SUMSQ(A1:A5)'); // "real" and string values --> ignore string
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(30, FWorksheet.ReadAsNumber(0, 1), 'Formula #13 SUMSQ(A1:A5) result mismatch');
|
||||
CheckEquals(30, FWorksheet.ReadAsNumber(0, 1), 'Formula #15 SUMSQ(A1:A5) result mismatch');
|
||||
|
||||
FWorksheet.WriteFormula(0, 1, '=SUMSQ(A1:A4,A8:A10)'); // real and string values and blanks
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(30, FWorksheet.ReadAsNumber(0, 1), 'Formula #14 SUMSQ(A1:A4,A8:A10) result mismatch');
|
||||
CheckEquals(30, FWorksheet.ReadAsNumber(0, 1), 'Formula #16 SUMSQ(A1:A4,A8:A10) result mismatch');
|
||||
|
||||
// Error propagation
|
||||
FWorksheet.WriteFormula(0, 1, '=SUMSQ(A1:A5,1/0)'); // error in argument --> error in result
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(STR_ERR_DIVIDE_BY_ZERO, FWorksheet.ReadAsText(0, 1), 'Formula #15 SUMSQ(A1, 1/0, A2) result mismatch');
|
||||
CheckEquals(STR_ERR_DIVIDE_BY_ZERO, FWorksheet.ReadAsText(0, 1), 'Formula #17 SUMSQ(A1, 1/0, A2) result mismatch');
|
||||
|
||||
FWorksheet.WriteFormula(0, 1, '=SUMSQ(A1:A6)'); // error in cell --> error in result
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(STR_ERR_DIVIDE_BY_ZERO, FWorksheet.ReadAsText(0, 1), 'Formula #16 SUMSQ(A1:A6) result mismatch');
|
||||
CheckEquals(STR_ERR_DIVIDE_BY_ZERO, FWorksheet.ReadAsText(0, 1), 'Formula #18 SUMSQ(A1:A6) result mismatch');
|
||||
end;
|
||||
|
||||
procedure TCalcStatsFormulaTests.Test_VAR;
|
||||
const
|
||||
EPS = 1E-8;
|
||||
var
|
||||
t: TDateTime;
|
||||
begin
|
||||
// Test data
|
||||
FWorksheet.WriteNumber (0, 0, 1);
|
||||
@ -1393,6 +1428,14 @@ begin
|
||||
FWorksheet.WriteFormula(0, 1, '=VAR(A1:A6)'); // error in cell
|
||||
FWorksheet.CalcFormulas;
|
||||
CheckEquals(STR_ERR_DIVIDE_BY_ZERO, FWorksheet.ReadAsText(0, 1), 'Formula #16 VAR(A:A6) result mismatch');
|
||||
|
||||
// Huge range
|
||||
FWorksheet.WriteFormula(0, 1, '=VAR(A1:A3,A10:A9999999)');
|
||||
t := Now();
|
||||
FWorksheet.CalcFormulas;
|
||||
t := Now() - t;
|
||||
CheckEquals(4.333333333, FWorksheet.ReadAsNumber(0, 1), EPS, 'Formula #17 VAR(A1:A3,A10:9999999) result mismatch');
|
||||
CheckEquals(true, t < 0.1/(24*60*60), 'Formula #17 VAR(A1:A3,A10:A9999999) takes too long');
|
||||
end;
|
||||
|
||||
procedure TCalcStatsFormulaTests.Test_VARP;
|
||||
|
Loading…
Reference in New Issue
Block a user