diff --git a/components/fpspreadsheet/fpsexprparser.pas b/components/fpspreadsheet/fpsexprparser.pas
index 0f6ebf730..63ce1f46f 100644
--- a/components/fpspreadsheet/fpsexprparser.pas
+++ b/components/fpspreadsheet/fpsexprparser.pas
@@ -815,6 +815,8 @@ function ArgToFloat(Arg: TsExpressionResult): TsExprFloat;
function ArgToString(Arg: TsExpressionResult): String;
procedure ArgsToFloatArray(const Args: TsExprParameterArray; out AData: TsExprFloatArray);
function BooleanResult(AValue: Boolean): TsExpressionResult;
+function CellResult(AValue: String): TsExpressionResult; overload;
+function CellResult(ACellRow, ACellCol: Cardinal): TsExpressionResult; overload;
function DateTimeResult(AValue: TDateTime): TsExpressionResult;
function EmptyResult: TsExpressionResult;
function ErrorResult(const AValue: TsErrorValue): TsExpressionResult;
@@ -4120,6 +4122,19 @@ begin
Result.ResBoolean := AValue;
end;
+function CellResult(AValue: String): TsExpressionResult;
+begin
+ Result.ResultType := rtCell;
+ ParseCellString(AValue, Result.ResRow, Result.ResCol);
+end;
+
+function CellResult(ACellRow, ACellCol: Cardinal): TsExpressionResult;
+begin
+ Result.ResultType := rtCell;
+ Result.ResRow := ACellRow;
+ Result.ResCol := ACellCol;
+end;
+
function DateTimeResult(AValue: TDateTime): TsExpressionResult;
begin
Result.ResultType := rtDateTime;
diff --git a/components/fpspreadsheet/tests/formulatests.pas b/components/fpspreadsheet/tests/formulatests.pas
index d750df432..a5c933ccf 100644
--- a/components/fpspreadsheet/tests/formulatests.pas
+++ b/components/fpspreadsheet/tests/formulatests.pas
@@ -30,12 +30,16 @@ type
// Set up expected values:
procedure SetUp; override;
procedure TearDown; override;
- // Test formula strings
- procedure TestWriteReadFormulaStrings(AFormat: TsSpreadsheetFormat;
+ // Test reconstruction of formula strings
+ procedure Test_Write_Read_FormulaStrings(AFormat: TsSpreadsheetFormat;
UseRPNFormula: Boolean);
+ // Test reconstruction of shared formula strings
procedure Test_Write_Read_SharedFormulaStrings(AFormat: TsSpreadsheetFormat);
- // Test calculation of rpn formulas
- procedure TestCalcFormulas(AFormat: TsSpreadsheetformat; UseRPNFormula: Boolean);
+ // Test calculation of formulas
+ procedure Test_Write_Read_CalcFormulas(AFormat: TsSpreadsheetformat;
+ UseRPNFormula: Boolean);
+ // Test calculation of shared formulas
+ procedure Test_Write_Read_CalcSharedFormulas(AFormat: TsSpreadsheetformat);
published
// Writes out formulas & reads them back.
@@ -85,6 +89,19 @@ type
procedure Test_Write_Read_CalcStringFormula_OOXML;
{ ODS Tests }
procedure Test_Write_Read_CalcStringFormula_ODS;
+
+ // Writes out and calculates shared formulas, read back
+ { BIFF2 Tests }
+ procedure Test_Write_Read_CalcSharedFormula_BIFF2;
+ { BIFF5 Tests }
+ procedure Test_Write_Read_CalcSharedFormula_BIFF5;
+ { BIFF8 Tests }
+ procedure Test_Write_Read_CalcSharedFormula_BIFF8;
+ { OOXML Tests }
+ procedure Test_Write_Read_CalcSharedFormula_OOXML;
+ { ODS Tests }
+ procedure Test_Write_Read_CalcSharedFormula_ODS;
+
end;
implementation
@@ -116,7 +133,7 @@ begin
inherited TearDown;
end;
-procedure TSpreadWriteReadFormulaTests.TestWriteReadFormulaStrings(
+procedure TSpreadWriteReadFormulaTests.Test_Write_Read_FormulaStrings(
AFormat: TsSpreadsheetFormat; UseRPNFormula: Boolean);
{ If UseRPNFormula is true the test formulas are generated from RPN formulas.
Otherwise they are generated from string formulas. }
@@ -185,27 +202,27 @@ end;
procedure TSpreadWriteReadFormulaTests.Test_Write_Read_FormulaStrings_BIFF2;
begin
- TestWriteReadFormulaStrings(sfExcel2, true);
+ Test_Write_Read_FormulaStrings(sfExcel2, true);
end;
procedure TSpreadWriteReadFormulaTests.Test_Write_Read_FormulaStrings_BIFF5;
begin
- TestWriteReadFormulaStrings(sfExcel5, true);
+ Test_Write_Read_FormulaStrings(sfExcel5, true);
end;
procedure TSpreadWriteReadFormulaTests.Test_Write_Read_FormulaStrings_BIFF8;
begin
- TestWriteReadFormulaStrings(sfExcel8, true);
+ Test_Write_Read_FormulaStrings(sfExcel8, true);
end;
procedure TSpreadWriteReadFormulaTests.Test_Write_Read_FormulaStrings_OOXML;
begin
- TestWriteReadFormulaStrings(sfOOXML, true);
+ Test_Write_Read_FormulaStrings(sfOOXML, true);
end;
procedure TSpreadWriteReadFormulaTests.Test_Write_Read_FormulaStrings_ODS;
begin
- TestWriteReadFormulaStrings(sfOpenDocument, true);
+ Test_Write_Read_FormulaStrings(sfOpenDocument, true);
end;
@@ -222,7 +239,7 @@ var
row, col: Cardinal;
TempFile: String;
actual, expected: String;
- sollValues: array[1..4, 0..5] of string;
+ sollValues: array[1..4, 0..4] of string;
begin
TempFile := GetTempFileName;
@@ -338,8 +355,8 @@ end;
{ Test calculation of formulas }
-procedure TSpreadWriteReadFormulaTests.TestCalcFormulas(AFormat: TsSpreadsheetFormat;
- UseRPNFormula: Boolean);
+procedure TSpreadWriteReadFormulaTests.Test_Write_Read_CalcFormulas(
+ AFormat: TsSpreadsheetFormat; UseRPNFormula: Boolean);
{ If UseRPNFormula is TRUE, the test formulas are generated from RPN syntax,
otherwise string formulas are used. }
const
@@ -482,52 +499,213 @@ end;
procedure TSpreadWriteReadFormulaTests.Test_Write_Read_CalcRPNFormula_BIFF2;
begin
- TestCalcFormulas(sfExcel2, true);
+ Test_Write_Read_CalcFormulas(sfExcel2, true);
end;
procedure TSpreadWriteReadFormulaTests.Test_Write_Read_CalcRPNFormula_BIFF5;
begin
- TestCalcFormulas(sfExcel5, true);
+ Test_Write_Read_CalcFormulas(sfExcel5, true);
end;
procedure TSpreadWriteReadFormulaTests.Test_Write_Read_CalcRPNFormula_BIFF8;
begin
- TestCalcFormulas(sfExcel8, true);
+ Test_Write_Read_CalcFormulas(sfExcel8, true);
end;
procedure TSpreadWriteReadFormulaTests.Test_Write_Read_CalcRPNFormula_OOXML;
begin
- TestCalcFormulas(sfOOXML, true);
+ Test_Write_Read_CalcFormulas(sfOOXML, true);
end;
procedure TSpreadWriteReadFormulaTests.Test_Write_Read_CalcRPNFormula_ODS;
begin
- TestCalcFormulas(sfOpenDocument, true);
+ Test_Write_Read_CalcFormulas(sfOpenDocument, true);
end;
procedure TSpreadWriteReadFormulaTests.Test_Write_Read_CalcStringFormula_BIFF2;
begin
- TestCalcFormulas(sfExcel2, false);
+ Test_Write_Read_CalcFormulas(sfExcel2, false);
end;
procedure TSpreadWriteReadFormulaTests.Test_Write_Read_CalcStringFormula_BIFF5;
begin
- TestCalcFormulas(sfExcel5, false);
+ Test_Write_Read_CalcFormulas(sfExcel5, false);
end;
procedure TSpreadWriteReadFormulaTests.Test_Write_Read_CalcStringFormula_BIFF8;
begin
- TestCalcFormulas(sfExcel8, false);
+ Test_Write_Read_CalcFormulas(sfExcel8, false);
end;
procedure TSpreadWriteReadFormulaTests.Test_Write_Read_CalcStringFormula_OOXML;
begin
- TestCalcFormulas(sfOOXML, false);
+ Test_Write_Read_CalcFormulas(sfOOXML, false);
end;
procedure TSpreadWriteReadFormulaTests.Test_Write_Read_CalcStringFormula_ODS;
begin
- TestCalcFormulas(sfOpenDocument, false);
+ Test_Write_Read_CalcFormulas(sfOpenDocument, false);
+end;
+
+//------------------------------------------------------------------------------
+// Calculation of shared formulas
+//------------------------------------------------------------------------------
+procedure TSpreadWriteReadFormulaTests.Test_Write_Read_CalcSharedFormulas(
+ AFormat: TsSpreadsheetFormat);
+const
+ SHEET = 'SharedFormulaSheet';
+ vA1 = 1.0;
+ vB1 = 2.0;
+ vC1 = 3.0;
+ vD1 = 4.0;
+ vE1 = 5.0;
+ vF1 = 'A';
+var
+ MyWorksheet: TsWorksheet;
+ MyWorkbook: TsWorkbook;
+ cell: PCell;
+ row, col: Cardinal;
+ TempFile: String;
+ actual, expected: String;
+ sollValues: array[1..8, 0..5] of String;
+begin
+ TempFile := GetTempFileName;
+
+ // Create test workbook
+ MyWorkbook := TsWorkbook.Create;
+ try
+ MyWorkbook.Options := MyWorkbook.Options + [boCalcBeforeSaving];
+ MyWorkSheet:= MyWorkBook.AddWorksheet(SHEET);
+
+ // Write out test values
+ MyWorksheet.WriteNumber(0, 0, vA1); // A1
+ MyWorksheet.WriteNumber(0, 1, vB1); // B1
+ MyWorksheet.WriteNumber(0, 2, vC1); // C1
+ MyWorksheet.WriteNumber(0, 3, vD1); // D1
+ MyWorksheet.WriteNumber(0, 4, vE1); // E1
+ MyWorksheet.WriteUTF8Text(0, 5, vF1); // F1
+
+ // Write out all test formulas
+ // sollValues contains the expected formula as seen from each cell in the
+ // shared formula block.
+ MyWorksheet.WriteSharedFormula('A2:F2', 'A1');
+ sollValues[1, 0] := Format('%g', [vA1]);
+ sollValues[1, 1] := Format('%g', [vB1]);
+ sollValues[1, 2] := Format('%g', [vC1]);
+ sollValues[1, 3] := Format('%g', [vD1]);
+ sollValues[1, 4] := Format('%g', [vE1]);
+ sollValues[1, 5] := vF1; // is a string
+ MyWorksheet.WriteSharedFormula('A3:F3', '$A1');
+ sollValues[2, 0] := Format('%g', [vA1]);
+ sollValues[2, 1] := Format('%g', [vA1]);
+ sollValues[2, 2] := Format('%g', [vA1]);
+ sollValues[2, 3] := Format('%g', [vA1]);
+ sollValues[2, 4] := Format('%g', [vA1]);
+ sollValues[2, 5] := Format('%g', [vA1]);
+ MyWorksheet.WriteSharedFormula('A4:F4', 'A$1');
+ sollValues[3, 0] := Format('%g', [vA1]);
+ sollValues[3, 1] := Format('%g', [vB1]);
+ sollValues[3, 2] := Format('%g', [vC1]);
+ sollValues[3, 3] := Format('%g', [vD1]);
+ sollValues[3, 4] := Format('%g', [vE1]);
+ sollValues[3, 5] := vF1; // is a string
+ MyWorksheet.WriteSharedFormula('A5:F5', '$A$1');
+ sollValues[4, 0] := Format('%g', [vA1]);
+ sollValues[4, 1] := Format('%g', [vA1]);
+ sollValues[4, 2] := Format('%g', [vA1]);
+ sollValues[4, 3] := Format('%g', [vA1]);
+ sollValues[4, 4] := Format('%g', [vA1]);
+ sollValues[4, 5] := Format('%g', [vA1]);
+
+ MyWorksheet.WriteSharedFormula('A6:F6', 'SIN(A1)');
+ sollValues[5, 0] := FloatToStr(sin(vA1)); // Using "FloatToStr" here like in ReadAsUTF8Text
+ sollValues[5, 1] := FloatToStr(sin(vB1));
+ sollValues[5, 2] := FloatToStr(sin(vC1));
+ sollValues[5, 3] := FloatToStr(sin(vD1));
+ sollValues[5, 4] := FloatToStr(sin(vE1));
+ sollValues[5, 5] := FloatToStr(sin(0.0)); // vF1 is a string
+ MyWorksheet.WriteSharedFormula('A7:F7', 'SIN($A1)');
+ sollValues[6, 0] := FloatToStr(sin(vA1));
+ sollValues[6, 1] := FloatToStr(sin(vA1));
+ sollValues[6, 2] := FloatToStr(sin(vA1));
+ sollValues[6, 3] := FloatToStr(sin(vA1));
+ sollValues[6, 4] := FloatToStr(sin(vA1));
+ sollValues[6, 5] := FloatToStr(sin(vA1));
+ MyWorksheet.WriteSharedFormula('A8:F8', 'SIN(A$1)');
+ sollValues[7, 0] := FloatToStr(sin(vA1));
+ sollValues[7, 1] := FloatToStr(sin(vB1));
+ sollValues[7, 2] := FloatToStr(sin(vC1));
+ sollValues[7, 3] := FloatToStr(sin(vD1));
+ sollValues[7, 4] := FloatToStr(sin(vE1));
+ sollValues[7, 5] := FloatToStr(sin(0.0)); // vF1 is a string
+ MyWorksheet.WriteSharedFormula('A9:F9', 'SIN($A$1)');
+ sollValues[8, 0] := FloatToStr(sin(vA1));
+ sollValues[8, 1] := FloatToStr(sin(vA1));
+ sollValues[8, 2] := FloatToStr(sin(vA1));
+ sollValues[8, 3] := FloatToStr(sin(vA1));
+ sollValues[8, 4] := FloatToStr(sin(vA1));
+ sollValues[8, 5] := FloatToStr(sin(vA1));
+
+ MyWorkBook.WriteToFile(TempFile, AFormat, true);
+ finally
+ MyWorkbook.Free;
+ end;
+
+ // Open the spreadsheet
+ MyWorkbook := TsWorkbook.Create;
+ try
+ MyWorkbook.Options := MyWorkbook.Options + [boReadFormulas, boAutoCalc];
+
+ MyWorkbook.ReadFromFile(TempFile, AFormat);
+ if AFormat = sfExcel2 then
+ MyWorksheet := MyWorkbook.GetFirstWorksheet
+ else
+ MyWorksheet := GetWorksheetByName(MyWorkBook, SHEET);
+ if MyWorksheet=nil then
+ fail('Error in test code. Failed to get named worksheet');
+
+ for row := 1 to 8 do begin
+ for col := 0 to MyWorksheet.GetLastColIndex do begin
+ cell := Myworksheet.FindCell(row, col);
+ if HasFormula(cell) then begin
+ actual := copy(MyWorksheet.ReadAsUTF8Text(cell), 1, 6); // cutting converted numbers off after some digits, certainly not always correct
+ expected := copy(SollValues[row, col], 1, 6);
+ CheckEquals(expected, actual, 'Test read formula mismatch, cell '+CellNotation(MyWorkSheet,Row,Col));
+ end else
+ fail('No formula found in cell ' + CellNotation(MyWorksheet, Row, Col));
+ end;
+ end;
+
+ finally
+ MyWorkbook.Free;
+ DeleteFile(TempFile);
+ end;
+end;
+
+
+procedure TSpreadWriteReadFormulaTests.Test_Write_Read_CalcSharedFormula_BIFF2;
+begin
+ Test_Write_Read_CalcSharedFormulas(sfExcel2);
+end;
+
+procedure TSpreadWriteReadFormulaTests.Test_Write_Read_CalcSharedFormula_BIFF5;
+begin
+ Test_Write_Read_CalcSharedFormulas(sfExcel5);
+end;
+
+procedure TSpreadWriteReadFormulaTests.Test_Write_Read_CalcSharedFormula_BIFF8;
+begin
+ Test_Write_Read_CalcSharedFormulas(sfExcel8);
+end;
+
+procedure TSpreadWriteReadFormulaTests.Test_Write_Read_CalcSharedFormula_OOXML;
+begin
+ Test_Write_Read_CalcSharedFormulas(sfOOXML);
+end;
+
+procedure TSpreadWriteReadFormulaTests.Test_Write_Read_CalcSharedFormula_ODS;
+begin
+ Test_Write_Read_CalcSharedFormulas(sfOpenDocument);
end;
diff --git a/components/fpspreadsheet/tests/spreadtestgui.lpi b/components/fpspreadsheet/tests/spreadtestgui.lpi
index 251664efc..f4f30ee59 100644
--- a/components/fpspreadsheet/tests/spreadtestgui.lpi
+++ b/components/fpspreadsheet/tests/spreadtestgui.lpi
@@ -56,7 +56,6 @@
-
@@ -66,20 +65,20 @@
-
+
-
+
@@ -110,10 +109,12 @@
+
+