fpspreadsheet: Ignore the order of indexes in cell ranges when parsing formulas. Add corresponding unit tests.

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@6420 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2018-05-16 08:45:28 +00:00
parent bb2bf8b3ca
commit 613c96821c
3 changed files with 77 additions and 14 deletions

View File

@ -3991,16 +3991,55 @@ end;
constructor TsCellRangeExprNode.Create(AParser: TsExpressionParser;
AWorksheet: TsWorksheet; ASheet1, ASheet2: String;
ARow1, ACol1, ARow2, ACol2: Cardinal; AFlags: tsRelFlags; Is3DRange: Boolean);
var
tmp: Integer;
begin
FParser := AParser;
FWorksheet := AWorksheet;
FFlags := [];
if (ASheet1 = '') and (ASheet2 <> '') then
raise Exception.Create('Invalid parameters in cell range');
FSheet[1] := GetWorkbook.GetWorksheetIndex(ASheet1);
if ASheet2 = '' then FSheet[2] := FSheet[1] else FSheet[2] := GetWorkbook.GetWorksheetIndex(ASheet2);
if ASheet2 <> '' then
FSheet[2] := GetWorkbook.GetWorksheetIndex(ASheet2)
else
FSheet[2] := FSheet[1];
EnsureOrder(FSheet[1], FSheet[2]);
if ARow2 = Cardinal(-1) then
ARow2 := ARow1;
if ARow1 <= ARow2 then
begin
FRow[1] := ARow1;
FRow[2] := ARow2;
FCol[1] := ACol1;
if ARow2 = Cardinal(-1) then FRow[2] := FRow[1] else FRow[2] := ARow2;
if ACol2 = Cardinal(-1) then FCol[2] := FCol[1] else FCol[2] := ACol2;
FFlags := AFlags;
if rfRelRow in AFlags then Include(FFlags, rfRelRow);
if rfRelRow2 in AFlags then Include(FFlags, rfRelRow2);
end else
begin
FRow[1] := ARow2;
FRow[2] := ARow1;
if rfRelRow in AFlags then Include(FFlags, rfRelRow2);
if rfRelRow2 in AFlags then Include(FFlags, rfRelRow);
end;
if ACol2 = Cardinal(-1) then
ACol2 := ACol1;
if ACol1 <= ACol2 then
begin
FCol[1] := ACol1;
FCol[2] := ACol2;
if (rfRelCol in AFlags) then Include(FFlags, rfRelCol);
if (rfRelCol2 in AFlags) then Include(FFlags, rfRelCol2);
end else
begin
FCol[1] := ACol2;
FCol[2] := ACol1;
if (rfRelCol in AFlags) then Include(FFlags, rfRelCol2);
if (rfRelCol2 in AFlags) then Include(FFlags, rfRelCol);
end;
F3dRange := Is3dRange;
end;

View File

@ -5731,12 +5731,12 @@ begin
parser := TsSpreadsheetParser.Create(self);
try
if ALocalized then begin
if ALocalized then
// Convert "localized" formula to standard format
parser.LocalizedExpression[Workbook.FormatSettings] := AFormula;
AFormula := parser.Expression;
end else
parser.LocalizedExpression[Workbook.FormatSettings] := AFormula
else
parser.Expression := AFormula;
AFormula := parser.Expression;
if parser.Has3DLinks
then ACell.Flags := ACell.Flags + [cf3dFormula]
else ACell.Flags := ACell.Flags - [cf3dFormula];

View File

@ -23,7 +23,8 @@ type
procedure SetUp; override;
procedure TearDown; override;
procedure TestFloatFormula(AFormula: String; AExpected: Double;
ATestKind: TFormulaTestKind; AFormat: TsSpreadsheetFormat);
ATestKind: TFormulaTestKind; AFormat: TsSpreadsheetFormat;
AExpectedFormula: String = '');
published
procedure AddConst_BIFF2;
@ -54,6 +55,10 @@ type
procedure SumMultiSheetRange_OOXML;
procedure SumMultiSheetRange_ODS;
procedure SumMultiSheetRange_FlippedCells_OOXML;
procedure SumMultiSheetRange_FlippedSheets_OOXML;
procedure SumMultiSheetRange_FlippedSheetsAndCells_OOXML;
end;
implementation
@ -78,7 +83,8 @@ begin
end;
procedure TSpreadSingleFormulaTests.TestFloatFormula(AFormula: String;
AExpected: Double; ATestKind: TFormulaTestKind; AFormat: TsSpreadsheetFormat);
AExpected: Double; ATestKind: TFormulaTestKind; AFormat: TsSpreadsheetFormat;
AExpectedFormula: String = '');
const
SHEET1 = 'Sheet1';
SHEET2 = 'Sheet2';
@ -95,6 +101,7 @@ var
actualValue: Double;
begin
TempFile := GetTempFileName;
if AExpectedFormula = '' then AExpectedFormula := AFormula;
try
// Create test workbook and write test formula and needed cells
@ -132,7 +139,7 @@ begin
// Read formula before saving
actualFormula := cell^.Formulavalue;
CheckEquals(AFormula, actualFormula, 'Unsaved formula text mismatch');
CheckEquals(AExpectedFormula, actualFormula, 'Unsaved formula text mismatch');
// Read calculated value before saving
actualvalue := worksheet.ReadAsNumber(TESTCELL_ROW, TESTCELL_COL);
@ -157,7 +164,7 @@ begin
cell := worksheet.FindCell(TESTCELL_ROW, TESTCELL_COL);
actualformula := cell^.FormulaValue;
CheckEquals(AFormula, actualformula, 'Saved formula text mismatch.');
CheckEquals(AExpectedFormula, actualformula, 'Saved formula text mismatch.');
finally
workbook.Free;
end;
@ -290,6 +297,23 @@ begin
TestFloatFormula('SUM(Sheet2:Sheet3!C3:C5)', 55.0, ftkCellRangeSheetRange, sfOpenDocument);
end;
{ --- }
procedure TSpreadSingleFormulaTests.SumMultiSheetRange_FlippedSheetsAndCells_OOXML;
begin
TestFloatFormula('SUM(Sheet3:Sheet2!C5:C3)', 55.0, ftkCellRangeSheetRange, sfOOXML, 'SUM(Sheet2:Sheet3!C3:C5)');
end;
procedure TSpreadSingleFormulaTests.SumMultiSheetRange_FlippedCells_OOXML;
begin
TestFloatFormula('SUM(Sheet2:Sheet3!C5:C3)', 55.0, ftkCellRangeSheetRange, sfOOXML, 'SUM(Sheet2:Sheet3!C3:C5)');
end;
procedure TSpreadSingleFormulaTests.SumMultiSheetRange_FlippedSheets_OOXML;
begin
TestFloatFormula('SUM(Sheet3:Sheet2!C3:C5)', 55.0, ftkCellRangeSheetRange, sfOOXML, 'SUM(Sheet2:Sheet3!C3:C5)');
end;
initialization
// Register to include these tests in a full run
RegisterTest(TSpreadSingleFormulaTests);