From 6b5cc615d37ce5a510b864c64603834626d695cd Mon Sep 17 00:00:00 2001 From: wp_xxyyzz Date: Mon, 8 Sep 2014 11:09:23 +0000 Subject: [PATCH] fpspreadsheet: Add test cases for shared formulas git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@3529 8e941d3f-bd1b-0410-a28a-d453659cc2b4 --- components/fpspreadsheet/fpsexprparser.pas | 15 ++ .../fpspreadsheet/tests/formulatests.pas | 224 ++++++++++++++++-- .../fpspreadsheet/tests/spreadtestgui.lpi | 7 +- 3 files changed, 220 insertions(+), 26 deletions(-) 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 @@ + +