From 03d869414223a652e71140b655152bf512153ba5 Mon Sep 17 00:00:00 2001 From: wp_xxyyzz Date: Tue, 26 Jun 2018 23:08:01 +0000 Subject: [PATCH] fpspreadsheet: Add unit tests for some of the recently fixed formulas. git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@6541 8e941d3f-bd1b-0410-a28a-d453659cc2b4 --- .../source/common/fpsexprparser.pas | 16 +- .../fpspreadsheet/source/common/fpsfunc.pas | 61 ++++--- .../tests/singleformulatests.pas | 155 +++++++++++++++++- .../tests/testcases_calcrpnformula.inc | 2 +- 4 files changed, 196 insertions(+), 38 deletions(-) diff --git a/components/fpspreadsheet/source/common/fpsexprparser.pas b/components/fpspreadsheet/source/common/fpsexprparser.pas index 20d0c90ac..f6c4d1c05 100644 --- a/components/fpspreadsheet/source/common/fpsexprparser.pas +++ b/components/fpspreadsheet/source/common/fpsexprparser.pas @@ -4445,16 +4445,15 @@ begin rtInteger : Result := Arg.ResInteger; rtFloat : Result := Arg.ResFloat; rtBoolean : if Arg.ResBoolean then Result := 1.0; - rtString, - rtHyperlink : begin - fs := (Arg.Worksheet as TsWorksheet).Workbook.FormatSettings; + rtHyperlink, + rtString : begin + fs := ExprFormatSettings; //(Arg.Worksheet as TsWorksheet).Workbook.FormatSettings; TryStrToDateTime(ArgToString(Arg), Result, fs); end; rtCell : begin cell := ArgToCell(Arg); - if Assigned(cell) then - if (cell^.ContentType = cctDateTime) then - Result := cell^.DateTimeValue; + if Assigned(cell) and (cell^.ContentType = cctDateTime) then + Result := cell^.DateTimeValue; end; end; end; @@ -4712,6 +4711,11 @@ initialization ExprFormatSettings := DefaultFormatSettings; ExprFormatSettings.DecimalSeparator := '.'; ExprFormatSettings.ListSeparator := ','; + ExprFormatSettings.DateSeparator := '/'; + ExprFormatSettings.TimeSeparator := ':'; + ExprFormatSettings.ShortDateFormat := 'yyyy/m/d'; // the parser returns single digits + ExprFormatSettings.LongTimeFormat := 'h:n:s'; + ExprFormatSettings.ShortTimeFormat := 'h:n'; RegisterStdBuiltins(BuiltinIdentifiers); diff --git a/components/fpspreadsheet/source/common/fpsfunc.pas b/components/fpspreadsheet/source/common/fpsfunc.pas index 7371636f6..48580cda6 100644 --- a/components/fpspreadsheet/source/common/fpsfunc.pas +++ b/components/fpspreadsheet/source/common/fpsfunc.pas @@ -421,13 +421,15 @@ procedure fpsDAY(var Result: TsExpressionResult; const Args: TsExprParameterArra // date_value can be a serial number or a string var y,m,d: Word; + dt: TDateTime; begin - if (Args[0].ResultType in [rtDateTime, rtFloat, rtInteger, rtString, rtCell]) - then begin - DecodeDate(ArgToFloat(Args[0]), y, m, d); + Result := ErrorResult(errWrongType); + if (Args[0].ResultType in [rtDateTime, rtFloat, rtInteger, rtString, rtCell]) then + begin + dt := ArgToDateTime(Args[0]); + DecodeDate(dt, y, m, d); Result := IntegerResult(d); - end else - Result := ErrorResult(errWrongType); + end; end; procedure fpsHOUR(var Result: TsExpressionResult; const Args: TsExprParameterArray); @@ -435,28 +437,30 @@ procedure fpsHOUR(var Result: TsExpressionResult; const Args: TsExprParameterArr // time_value can be a number or a string. var h, m, s, ms: Word; - t: double; + dt: TDateTime; begin + Result := ErrorResult(errWrongType); if (Args[0].ResultType in [rtDateTime, rtFloat, rtInteger, rtString, rtCell]) then begin - DecodeTime(trunc(ArgToFloat(Args[0])), h,m,s,ms); + dt := ArgToDateTime(Args[0]); + DecodeTime(dt, h, m, s, ms); Result := IntegerResult(h); - end else - Result := ErrorResult(errWrongType); + end; end; procedure fpsMINUTE(var Result: TsExpressionResult; const Args: TsExprParameterArray); // MINUTE( serial_number or string ) var h, m, s, ms: Word; - t: double; + dt: TDateTime; begin + Result := ErrorResult(errWrongType); if (Args[0].ResultType in [rtDateTime, rtFloat, rtInteger, rtString, rtCell]) then begin - DecodeTime(ArgToFloat(Args[0]), h,m,s,ms); + dt := ArgToDateTime(Args[0]); + DecodeTime(dt, h, m, s, ms); Result := IntegerResult(m); - end else - Result := ErrorResult(errWrongType); + end; end; procedure fpsMONTH(var Result: TsExpressionResult; const Args: TsExprParameterArray); @@ -465,12 +469,13 @@ var y,m,d: Word; dt: TDateTime; begin + Result := ErrorResult(errWrongType); if (Args[0].ResultType in [rtDateTime, rtFloat, rtInteger, rtString, rtCell]) then begin - DecodeDate(ArgToFloat(Args[0]), y,m,d); + dt := ArgToDateTime(Args[0]); + DecodeDate(dt, y, m, d); Result := IntegerResult(m); - end else - Result := ErrorResult(errWrongType); + end; end; procedure fpsNOW(var Result: TsExpressionResult; const Args: TsExprParameterArray); @@ -486,14 +491,15 @@ procedure fpsSECOND(var Result: TsExpressionResult; const Args: TsExprParameterA // SECOND( serial_number ) var h, m, s, ms: Word; - t: Double; + dt: TDateTime; begin - if (Args[0].ResultType in [rtDateTime, rtFloat, rtInteger, rtString, rtCell]) - then begin - DecodeTime(ArgToFloat(Args[0]), h,m,s,ms); + Result := ErrorResult(errWrongType); + if (Args[0].ResultType in [rtDateTime, rtFloat, rtInteger, rtString, rtCell]) then + begin + dt := ArgToDateTime(Args[0]); + DecodeTime(dt, h, m, s, ms); Result := IntegerResult(s); - end else - Result := ErrorResult(errWrongType); + end; end; procedure fpsTIME(var Result: TsExpressionResult; const Args: TsExprParameterArray); @@ -563,12 +569,13 @@ var y,m,d: Word; dt: TDateTime; begin - if Args[0].ResultType in [rtDateTime, rtFloat, rtInteger, rtString, rtCell] - then begin - DecodeDate(ArgToFloat(Args[0]), y,m,d); + Result := ErrorResult(errWrongType); + if (Args[0].ResultType in [rtDateTime, rtFloat, rtInteger, rtString, rtCell]) then + begin + dt := ArgToDateTime(Args[0]); + DecodeDate(dt, y, m, d); Result := IntegerResult(y); - end else - Result := ErrorResult(errWrongType); + end; end; diff --git a/components/fpspreadsheet/tests/singleformulatests.pas b/components/fpspreadsheet/tests/singleformulatests.pas index c7d353fb7..9f88dace9 100644 --- a/components/fpspreadsheet/tests/singleformulatests.pas +++ b/components/fpspreadsheet/tests/singleformulatests.pas @@ -41,6 +41,25 @@ type procedure AddCells_OOXML; procedure AddCells_ODS; + procedure RoundConst1_ODS; + procedure RoundConst2_ODS; + procedure RoundCell1_ODS; + procedure RoundCell2_ODS; + + procedure YearConst_BIFF8; + procedure YearCell_BIFF8; + procedure MonthConst_BIFF8; + procedure MonthCell_BIFF8; + procedure DayConst_BIFF8; + procedure DayCell_BIFF8; + + procedure HourConst_BIFF8; + procedure HourCell_BIFF8; + procedure MinuteConst_BIFF8; + procedure MinuteCell_BIFF8; + procedure SecondConst_BIFF8; + procedure SecondCell_BIFF8; + procedure SumRange_BIFF2; procedure SumRange_BIFF5; procedure SumRange_BIFF8; @@ -63,6 +82,11 @@ type procedure SumMultiSheetRange_FlippedSheetsAndCells_OOXML; procedure SumMultiSheetRange_FlippedSheetsAndCells_ODS; + procedure CountIfRange_BIFF8; + procedure CountIfRangeSheet_BIFF8; + + procedure SumIfRangeSheetSheet_BIFF8; + procedure NonExistantSheet_BIFF5; procedure NonExistantSheet_BIFF8; procedure NonExistantSheet_OOXML; @@ -137,7 +161,7 @@ begin // Create test workbook and write test formula and needed cells workbook := TsWorkbook.Create; try - workbook.FormatSettings.DecimalSeparator := '.'; + workbook.FormatSettings := ExprFormatSettings; workbook.Options := workbook.Options + [boCalcBeforeSaving, boAutoCalc]; workSheet:= workBook.AddWorksheet(SHEET1); @@ -147,6 +171,9 @@ begin worksheet.WriteNumber(3, 2, -2.0); // C4 worksheet.WriteNumber(4, 2, 1.5); // C5 worksheet.WriteNumber(2, 3, 15.0); // D3 + + worksheet.WriteDateTime( 9, 1, EncodeDate(2012, 2, 5), nfShortDate); // B10 + worksheet.WriteDateTime(10, 1, EncodeTime(14, 20, 41, 0), nfLongTime); // B11 end; if ATestKind in [ftkCellRangeSheet, ftkCellRangeSheetRange] then begin @@ -185,7 +212,7 @@ begin // Read file workbook := TsWorkbook.Create; try - workbook.FormatSettings.DecimalSeparator := '.'; + workbook.FormatSettings := ExprFormatSettings; workbook.Options := workbook.Options + [boReadFormulas, boAutoCalc]; workbook.ReadFromFile(TempFile, AFormat); worksheet := workbook.GetFirstWorksheet; @@ -261,6 +288,110 @@ end; { ------ } +procedure TSpreadSingleFormulaTests.RoundConst1_ODS; +begin + TestFormula('ROUND(1234.56789,2)', '1234.57', ftkConstants, sfOpenDocument); +end; + +procedure TSpreadSingleFormulaTests.RoundConst2_ODS; +begin + TestFormula('ROUND(1234.56789,-2)', '1200', ftkConstants, sfOpenDocument); +end; + +procedure TSpreadSingleFormulaTests.RoundCell1_ODS; +begin + TestFormula('ROUND(1234.56789,C3)', '1234.6', ftkCells, sfOpenDocument); // C3 = 1 +end; + +procedure TSpreadSingleFormulaTests.RoundCell2_ODS; +begin + TestFormula('ROUND(1234.56789,C4)', '1200', ftkCells, sfOpenDocument); // C4 = -2 +end; + +{ ------ } + +procedure TSpreadSingleFormulaTests.YearConst_BIFF8; +var + s: String; +begin + s := FormatDateTime(ExprFormatSettings.ShortDateFormat, EncodeDate(2012,2,5), ExprFormatSettings); + TestFormula(Format('YEAR("%s")', [s]), '2012', ftkConstants, sfExcel8); +end; + +procedure TSpreadSingleFormulaTests.YearCell_BIFF8; +begin + TestFormula('YEAR(B10)', '2012', ftkCells, sfExcel8); // B10: 2012/02/05 +end; + +procedure TSpreadSingleFormulaTests.MonthConst_BIFF8; +var + s: String; +begin + s := FormatDateTime(ExprFormatSettings.ShortDateFormat, EncodeDate(2012,2,5), ExprFormatSettings); + TestFormula(Format('MONTH("%s")', [s]), '2', ftkConstants, sfExcel8); +end; + +procedure TSpreadSingleFormulaTests.MonthCell_BIFF8; +begin + TestFormula('MONTH(B10)', '2', ftkCells, sfExcel8); // B10: 2012/02/05 +end; + +procedure TSpreadSingleFormulaTests.DayConst_BIFF8; +var + s: String; +begin + s := FormatDateTime(ExprFormatSettings.ShortDateFormat, EncodeDate(2012,2,5), ExprFormatSettings); + TestFormula(Format('DAY("%s")', [s]), '5', ftkConstants, sfExcel8); +end; + +procedure TSpreadSingleFormulaTests.DayCell_BIFF8; +begin + TestFormula('DAY(B10)', '5', ftkCells, sfExcel8); // B10: 2012/02/05 +end; + +{ ----- } + +procedure TSpreadSingleFormulaTests.HourConst_BIFF8; +var + s: String; +begin + s := FormatDateTime(ExprFormatSettings.LongTimeFormat, EncodeTime(14, 20, 41, 0), ExprFormatSettings); + TestFormula(Format('HOUR("%s")', [s]), '14', ftkConstants, sfExcel8); +end; + +procedure TSpreadSingleFormulaTests.HourCell_BIFF8; +begin + TestFormula('HOUR(B11)', '14', ftkCells, sfExcel8); // B11: 14:20:41 +end; + +procedure TSpreadSingleFormulaTests.MinuteConst_BIFF8; +var + s: String; +begin + s := FormatDateTime(ExprFormatSettings.LongTimeFormat, EncodeTime(14, 20, 41, 0), ExprFormatSettings); + TestFormula(Format('MINUTE("%s")', [s]), '20', ftkConstants, sfExcel8); +end; + +procedure TSpreadSingleFormulaTests.MinuteCell_BIFF8; +begin + TestFormula('MINUTE(B11)', '20', ftkCells, sfExcel8); // B11: 14:20:41 +end; + +procedure TSpreadSingleFormulaTests.SecondConst_BIFF8; +var + s: String; +begin + s := FormatDateTime(ExprFormatSettings.LongTimeFormat, EncodeTime(14, 20, 41, 0), ExprFormatSettings); + TestFormula(Format('SECOND("%s")', [s]), '41', ftkConstants, sfExcel8); +end; + +procedure TSpreadSingleFormulaTests.SecondCell_BIFF8; +begin + TestFormula('SECOND(B11)', '41', ftkCells, sfExcel8); // B11: 14:20:41 +end; + +{ ---- } + procedure TSpreadSingleFormulaTests.SumRange_BIFF2; begin TestFormula('SUM(C3:C5)', '0.5', ftkCellRange, sfExcel2); @@ -363,6 +494,23 @@ end; { --- } +procedure TSpreadSingleFormulaTests.CountIfRange_BIFF8; +begin + TestFormula('COUNTIF(C3:C5,">1")', '1', ftkCellRange, sfExcel8); +end; + +procedure TSpreadSingleFormulaTests.CountIfRangeSheet_BIFF8; +begin + TestFormula('COUNTIF(Sheet2!C3:C5,">10")', '1', ftkCellRangeSheet, sfExcel8); +end; + +procedure TSpreadSingleFormulaTests.SumIfRangeSheetSheet_BIFF8; +begin + TestFormula('SUMIF(Sheet2!C3:C5,">10",Sheet3!C3:C5)', '150', ftkCellRangeSheetRange, sfExcel8); +end; + +{ ---- } + procedure TSpreadSingleFormulaTests.NonExistantSheet_BIFF5; begin TestFormula('Missing!C3', '#REF!', ftkCellRangeSheet, sfExcel5, '#REF!'); @@ -703,11 +851,10 @@ begin end; - - initialization // Register to include these tests in a full run RegisterTest(TSpreadSingleFormulaTests); + end. diff --git a/components/fpspreadsheet/tests/testcases_calcrpnformula.inc b/components/fpspreadsheet/tests/testcases_calcrpnformula.inc index 299e5026c..9a4fcd5a7 100644 --- a/components/fpspreadsheet/tests/testcases_calcrpnformula.inc +++ b/components/fpspreadsheet/tests/testcases_calcrpnformula.inc @@ -1810,7 +1810,7 @@ RPNFunc('DATE', nil)))))) else MyWorksheet.WriteFormula(Row, 1, formula); - MyWorksheet.WriteDateTime(Row, 2, EncodeDate(2014,7,1)); + MyWorksheet.WriteDateTime(Row, 2, EncodeDate(2014,7,1), nfShortDate); SetLength(sollValues, Row+1); sollValues[Row] := DateTimeResult(EncodeDate(2014,7,1));