FPSpreadsheet: Fix MATCH finding wrong duplicate value. See https://forum.lazarus.freepascal.org/index.php/topic,70130.0.html. Update unit test.

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@9621 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz 2025-02-08 11:02:16 +00:00
parent 016a7136bb
commit 8959750876
2 changed files with 65 additions and 38 deletions

View File

@ -3286,7 +3286,7 @@ var
match_type: Integer;
searchString: String;
numSearchValue: Double = 0.0;
r1,c1,r2,c2: Cardinal;
r1, c1, r2, c2: Cardinal;
r, c: Integer;
IsCol: Boolean;
arg: TsExpressionResult;
@ -3400,17 +3400,39 @@ begin
if IsCol then
begin
for r := r2 downto r1 do
if Matches(sheet.FindCell(r, c1)) then begin
Result := IntegerResult(r - integer(r1) + 1);
exit;
end;
if match_type = 0 then
begin
for r := r1 to r2 do
if Matches(sheet.Findcell(r, c1)) then
begin
Result := IntegerResult(r - integer(r1) + 1);
exit;
end;
end else
begin
for r := r2 downto r1 do
if Matches(sheet.FindCell(r, c1)) then begin
Result := IntegerResult(r - integer(r1) + 1);
exit;
end;
end;
end else
begin
for c := c2 downto c1 do
if Matches(sheet.FindCell(r1, c)) then begin
Result := IntegerResult(c - Integer(c1) + 1);
exit;
if match_type = 0 then
begin
for c := c1 to c2 do
if Matches(sheet.Findcell(r1, c)) then
begin
Result := IntegerResult(c - Integer(c1) + 1);
exit;
end;
end else
begin
for c := c2 downto c1 do
if Matches(sheet.FindCell(r1, c)) then begin
Result := IntegerResult(c - Integer(c1) + 1);
exit;
end;
end;
end;

View File

@ -1786,45 +1786,50 @@ end;
procedure TCalcFormulaTests.Test_MATCH;
begin
// *** Match_Type 0, unsorted data in search range
// *** Match_Type 0, unsorted data in search range, find first value
// 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);
FWorksheet.WriteNumber(4, 1, 20);
// Search for constant, contained in search range
FWorksheet.WriteFormula(0, 2, '=MATCH(10, B1:B4, 0)');
FWorksheet.WriteFormula(0, 2, '=MATCH(10, B1:B5, 0)');
FWorksheet.CalcFormulas;
CheckEquals(1, FWorksheet.ReadAsNumber(0, 2), 'Formula #1 MATCH mismatch, match_type 0, in range');
CheckEquals(1, FWorksheet.ReadAsNumber(0, 2), 'Formula #1 MATCH(10,B1_B5,0) mismatch, value in range');
// Search for constant, contained several times in search range
FWorksheet.WriteFormula(0, 2, '=MATCH(20, B1:B5, 0)');
FWorksheet.CalcFormulas;
CheckEquals(2, FWorksheet.ReadAsNumber(0, 2), 'Formula #2 MATCH(20,B1:B5,0) mismatch, value above range');
// Search for constant, below search range
FWorksheet.WriteFormula(0, 2, '=MATCH(0, B1:B4, 0)');
FWorksheet.WriteFormula(0, 2, '=MATCH(0, B1:B5, 0)');
FWorksheet.CalcFormulas;
CheckEquals(STR_ERR_ARG_ERROR, FWorksheet.ReadAsText(0, 2), 'Formula #2 MATCH mismatch, match_type 0, below range');
CheckEquals(STR_ERR_ARG_ERROR, FWorksheet.ReadAsText(0, 2), 'Formula #3 MATCH(0,B1:B5,0) mismatch, value below range');
// Search for constant, above search range
FWorksheet.WriteFormula(0, 2, '=MATCH(90, B1:B4, 0)');
FWorksheet.WriteFormula(0, 2, '=MATCH(90, B1:B5, 0)');
FWorksheet.CalcFormulas;
CheckEquals(STR_ERR_ARG_ERROR, FWorksheet.ReadAsText(0, 2), 'Formula #3 MATCH mismatch, match_type 0, above range');
CheckEquals(STR_ERR_ARG_ERROR, FWorksheet.ReadAsText(0, 2), 'Formula #4 MATCH(90,B1:B5,0) mismatch, value above range');
// Search for cell with value in range
FWorksheet.WriteNumber(0, 0, 20);
FWorksheet.WriteFormula(0, 2, '=MATCH(A1, B1:B4, 0)');
FWorksheet.WriteFormula(0, 2, '=MATCH(A1, B1:B5, 0)');
FWorksheet.CalcFormulas;
CheckEquals(2, FWorksheet.ReadAsNumber(0, 2), 'Formula #4 MATCH mismatch, match_type 0, cell in range');
FWorksheet.WriteBlank(0, 0);
CheckEquals(2, FWorksheet.ReadAsNumber(0, 2), 'Formula #5 MATCH(A1,B1:B5,0) mismatch, cell value in range');
// Search for cell, but cell is empty
FWorksheet.WriteFormula(0, 2, '=MATCH(A1, B1:B4, 0)');
FWorksheet.WriteFormula(0, 2, '=MATCH(A99, B1:B5, 0)');
FWorksheet.CalcFormulas;
CheckEquals(STR_ERR_ARG_ERROR, FWorksheet.ReadAsText(0, 2), 'Formula #5 MATCH mismatch, match_type 0, empty cell');
CheckEquals(STR_ERR_ARG_ERROR, FWorksheet.ReadAsText(0, 2), 'Formula #6 MATCH(A99,B1:B5,0) mismatch, 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');
CheckEquals(STR_ERR_ARG_ERROR, FWorksheet.ReadAsText(0, 2), 'Formula #7 MATCH mismatch, match_type -1, empty search range');
// *** Match_Type 1 (find largest value in range <= value), ascending values in search range
@ -1838,35 +1843,35 @@ begin
// 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');
CheckEquals(2, FWorksheet.ReadAsNumber(0, 2), 'Formula #8 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');
CheckEquals(STR_ERR_ARG_ERROR, FWorksheet.ReadAsText(0, 2), 'Formula #9 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');
CheckEquals(3, FWorksheet.ReadAsNumber(0, 2), 'Formula MATCH #10 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');
CheckEquals(2, FWorksheet.ReadAsNumber(0, 2), 'Formula MATCH #11 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');
CheckEquals(STR_ERR_ARG_ERROR, FWorksheet.ReadAsText(0, 2), 'Formula #12 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');
CheckEquals(STR_ERR_ARG_ERROR, FWorksheet.ReadAsText(0, 2), 'Formula MATCH #13 mismatch, match_type -1, empty search range');
// *** Match_Type -1 (find smallest value in range >= value), descending values in search range
@ -1879,35 +1884,35 @@ begin
// 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');
CheckEquals(1, FWorksheet.ReadAsNumber(0, 2), 'Formula #14 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');
CheckEquals(3, FWorksheet.ReadAsNumber(0, 2), 'Formula #15 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');
CheckEquals(STR_ERR_ARG_ERROR, FWorksheet.ReadAsText(0, 2), 'Formula #16 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');
CheckEquals(1, FWorksheet.ReadAsNumber(0, 2), 'Formula #17 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');
CheckEquals(STR_ERR_ARG_ERROR, FWorksheet.ReadAsText(0, 2), 'Formula #18 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');
CheckEquals(STR_ERR_ARG_ERROR, FWorksheet.ReadAsText(0, 2), 'Formula #19 MATCH mismatch, match_type -1, empty search range');
// **** Error propagation
@ -1918,14 +1923,14 @@ begin
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');
CheckEquals(STR_ERR_DIVIDE_BY_ZERO, FWorksheet.ReadAsText(0, 2), 'Formula #20 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');
CheckEquals(STR_ERR_DIVIDE_BY_ZERO, FWorksheet.ReadAsText(0, 2), 'Formula #21 MATCH mismatch, match_type 0, error in search range');
// Cell range contains error
FWorksheet.WriteNumber(0, 1, 10);
@ -1934,7 +1939,7 @@ begin
// 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');
CheckEquals(STR_ERR_ARG_ERROR, FWorksheet.ReadAsText(0, 2), 'Formula #22 MATCH mismatch, match_type 0, error in search range');
// ArgError because search value is not found
end;