From 016a7136bb83916224dd47225e97e75bf2ae9995 Mon Sep 17 00:00:00 2001 From: wp_xxyyzz Date: Thu, 6 Feb 2025 21:26:55 +0000 Subject: [PATCH] FPSpreadsheet: Fix error in IF formula when second argument contains an error and is selected. See https://forum.lazarus.freepascal.org/index.php/topic,70117.msg546252. Update unit test. git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@9620 8e941d3f-bd1b-0410-a28a-d453659cc2b4 --- .../fpspreadsheet/source/common/fpsfunc.pas | 22 ++++++++----------- .../unit-tests/common/calcformulatests.pas | 22 ++++++++++++++----- 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/components/fpspreadsheet/source/common/fpsfunc.pas b/components/fpspreadsheet/source/common/fpsfunc.pas index 6277d9c58..f0a362483 100644 --- a/components/fpspreadsheet/source/common/fpsfunc.pas +++ b/components/fpspreadsheet/source/common/fpsfunc.pas @@ -2070,29 +2070,25 @@ end; // IF( condition, value_if_true, [value_if_false] ) procedure fpsIF(var Result: TsExpressionResult; const Args: TsExprParameterArray); +var + res: Boolean; begin if IsError(Args[0], Result) then exit; - if IsError(Args[1], Result) then - exit; + if (Args[0].ResultType = rtString) then begin Result := ErrorResult(errWrongType); exit; end; - if Length(Args) > 2 then + res := ArgToBoolean(Args[0], false); + if res then + Result := Args[1] + else begin - if IsError(Args[2], Result) then - exit; - if ArgToBoolean(Args[0], false) then - Result := Args[1] - else - Result := Args[2]; - end else - begin - if ArgToBoolean(Args[0], false) then - Result := Args[1] + if Length(Args) > 2 then + Result := Args[2] else Result.ResBoolean := false; end; diff --git a/components/fpspreadsheet/unit-tests/common/calcformulatests.pas b/components/fpspreadsheet/unit-tests/common/calcformulatests.pas index ea99cf546..cf0a961e0 100644 --- a/components/fpspreadsheet/unit-tests/common/calcformulatests.pas +++ b/components/fpspreadsheet/unit-tests/common/calcformulatests.pas @@ -1158,21 +1158,31 @@ begin FWorksheet.CalcFormulas; CheckEquals('FALSE', FWorksheet.ReadAsText(0, 1), 'Formula #7 IF(A1<100,"ok") result mismatch'); - // Error propagation: error in 3rd argument + // Error propagation: error in 3rd argument - result is non-error argument FWorksheet.WriteFormula(0, 1, '=IF(A1>=100, "ok", 1/0)'); FWorksheet.CalcFormulas; - CheckEquals(STR_ERR_DIVIDE_BY_ZERO, FWorksheet.ReadAsText(0, 1), 'Formula #8 IF(A1>=100,"ok",1/0) result mismatch'); + CheckEquals('ok', FWorksheet.ReadAsText(0, 1), 'Formula #8 IF(A1>=100,"ok",1/0) result mismatch'); - // Error propagation: error in 2nd argument - FWorksheet.WriteFormula(0, 1, '=IF(A1>=100, 1/0,"not ok")'); + // Error propagation: error in 3rd argument - result is error argument + FWorksheet.WriteFormula(0, 1, '=IF(A1<100, "ok", 1/0)'); FWorksheet.CalcFormulas; - CheckEquals(STR_ERR_DIVIDE_BY_ZERO, FWorksheet.ReadAsText(0, 1), 'Formula #9 IF(A1>=100,1/0,"not ok") result mismatch'); + CheckEquals(STR_ERR_DIVIDE_BY_ZERO, FWorksheet.ReadAsText(0, 1), 'Formula #9 IF(A1<100,"ok",1/0) result mismatch'); + + // Error propagation: error in 2nd argument - result is error argument + FWorksheet.WriteFormula(0, 1, '=IF(A1>=100, 1/0,"abc")'); + FWorksheet.CalcFormulas; + CheckEquals(STR_ERR_DIVIDE_BY_ZERO, FWorksheet.ReadAsText(0, 1), 'Formula #10 IF(A1>=100,1/0,"abc") result mismatch'); + + // Error propagation: error in 2nd argument - result is 3rd argument + FWorksheet.WriteFormula(0, 1, '=IF(A1<100, 1/0,"abc")'); + FWorksheet.CalcFormulas; + CheckEquals('abc', FWorksheet.ReadAsText(0, 1), 'Formula #11 IF(A1<100,1/0,"abc") result mismatch'); // Error propagaton: error in 1st argument FWorksheet.WriteFormula(0, 0, '=1/0'); FWorksheet.WriteFormula(0, 1, '=IF(A1>=100,"ok","not ok")'); FWorksheet.CalcFormulas; - CheckEquals(STR_ERR_DIVIDE_BY_ZERO, FWorksheet.ReadAsText(0, 1), 'Formula #10 IF(A1>=100,"ok","not ok") with A1=1/0 result mismatch'); + CheckEquals(STR_ERR_DIVIDE_BY_ZERO, FWorksheet.ReadAsText(0, 1), 'Formula #12 IF(A1>=100,"ok","not ok") with A1=1/0 result mismatch'); end; procedure TCalcFormulaTests.Test_IFERROR;