313 Commits

Author SHA1 Message Date
oleibman ab420f4499 Coerce Bool to Int for Mathematical Operators on Arrays (#3392)
* Coerce Bool to Int for Unary Operation on Arrays

Fix #3389. It seems some functionality was left behind when JAMA was eliminated (PR #3260). In particular, it is apparently a known trick to use double negation on boolean values as arguments to functions like SUMPRODUCT.

* Fix 3396

Treat booleans in arrays as int for mathematical operators as well.

* Edge Case

When array operand was neither numeric nor boolean, PhpSpreadsheet had always been evaluating the operand as #NUM!. It will now propagate an error string like #DIV/0!, and treat non-error strings as #VALUE!, consistent with Excel.
2023-02-23 23:11:22 -08:00
MarkBaker 3d7964f568 Improve support for locale settings in the Calculation Engine formatted number matcher 2023-02-17 08:03:28 +01:00
MarkBaker 4aaf1f61b9 Allow a range of different potential currency codes (including the locale code) in the currency matcher regexp
(dollar, euro, pound sterling and yen)
2023-02-17 06:16:10 +01:00
MarkBaker ea3be3b53b Unit tests for evaluation of defined name with a quote-prefixed cell 2023-02-01 21:10:19 +01:00
oleibman a0e6e09557 Resolve Phpstan Messages LookupRef TextData Coordinate ReferenceHelpe… (#3298)
* Resolve Phpstan Messages LookupRef TextData Coordinate ReferenceHelper RichText

Reduce number of Phpstan messages by addressing their issues.

* Scrutinizer

One legitimate observation, one unfathomable false positive.

* Scrutinizer (legitimate)

Reasonable simplification suggestion.
2023-01-27 09:15:08 -08:00
oleibman 8d3097517e Additional Unit Tests for XIRR and XNPV (#3307)
* Additional Unit Tests for XIRR and XNPV

See discussion in issue #3297. Excel result disagreed with PhpSpreadsheet, but it seems apparent that the error is Excel's. Although we have other test cases where Excel and PhpSpreadsheet disagree, those have so far been cases where Excel cannot give an answer because its algorithm does not converge, which is possible for any algorithm. In the issue in question, Excel seems to converge to a different answer; this is different than the other exceptions, and so deserves documentation with a formal test case. The discussion also mentions some cases where XNPV seems to give the wrong result in Excel, and those cases are added for XNPV.

* Scrutinizer

Whatever.
2023-01-24 19:06:22 -08:00
MarkBaker d0910bd263 Additional unit tests for invalid column name 2023-01-21 02:47:33 +01:00
MarkBaker e02439aeb1 For Structured References, an Invalid column reference should return an Excel #REF! error 2023-01-21 02:42:12 +01:00
oleibman 8497a320ea Resolve Phpstan Messages in Calculation Statistical (#3290)
* Resolve Phpstan Messages in Calculation Statistical

Reduce number of Phpstan messages by addressing their issues.

I did not eliminate the messages for Trends, because I did not understand why it is working as it does, so felt it was better to leave it alone.

* Scrutinizer

A new false positive.
2023-01-16 07:19:39 -08:00
oleibman ac5299b5df Minor Fix for AND/OR/XOR (#3287)
* Minor Fix for AND/OR/XOR

These 3 fall into the set of functions where Excel treats string literals differently depending on whether they are passed to the function directly or as a cell reference. PhpSpreadsheet is updated to try to duplicate that logic. New tests are added. Some existing test results had to change as a result of this code change.

* Adopt A Suggestion From Mark Baker

Reduce if statements by adding functions.
2023-01-16 05:35:28 -08:00
oleibman a5f1de02e3 Resolve Phpstan Messages in Calculation Financial (#3284)
Reduce number of Phpstan messages by addressing their issues.
2023-01-15 08:18:33 -08:00
oleibman a3f3d2c9ad Clean Up Documentation for Worksheet (#3281)
* Clean Up Documentation for Worksheet

This PR was intended to clean up Phpstan/Scrutinizer messages regarding Worksheet. It is, for the most part, straightforward, but there is one problem which complicates things. The frequently-called public method `getParent` returns `Worksheet` or `null` but is documented to return only `Worksheet`. This can be addressed in either of two ways - change the code to match the documentation (smaller number of changes but a backwards compatibility break), or change the documentation to match the code (larger number of changes but no compatibility break). I have prepared a PR for each approach, but avoiding a compatibility break seems better, so I am pushing the latter. I can switch to the other if preferred. Most existing internal calls to `getParent` are changed to use a new method `getParentOrThrow`, which will throw an exception if parent is null. These calls would all have thrown a null pointer exception anyhow in that situation, so this should not cause any new breaks.

* Scrutinizer

One false positive, and one message leading to a minor code improvement.
2023-01-11 23:34:52 -08:00
MarkBaker 0e3f1f187d Use exception code rather than exception message to identify whether the Calc Engine should throw an exception or push to stack for Structured Reference Exceptions 2023-01-03 12:27:20 +01:00
Mark Baker 23c7b952c5 Merge branch 'master' into Structured-Reference_Header-Reference-when-Disabled 2023-01-02 22:22:44 +01:00
MarkBaker 1bb0d56b15 Unhappy path for Structured References (referencing #Headers when headers are hidden) 2023-01-02 22:01:10 +01:00
oleibman 4adafecea9 Eliminate Shared\JAMA (#3260)
* Eliminate Shared\JAMA

The code under `Shared\JAMA` is called from exactly 3 places in Calculation, and exactly 1 other place (see next paragraph). These places are inadequately covered in the test suite, so it is not clear that the existing code works. In addition, see PR #2964 for commentary decrying the continued used of JAMA. I will also note that it has a pitiful 8.20% coverage in the test suite. There seems to already be a perfectly adequate equivalent in Calculation for those parts of JAMA which are used (e.g. we don't use any decompositions, so the fact that no decomposition code is present in Calculation is not a problem). This PR replaces the uses of JAMA within Calculation with `checkMatrixOperands`, and deletes Shared/JAMA entirely (which, among other thing, makes many Phpstan reported problems go away). The test suite is enhanced to ensure coverage of all the changed statements. A side benefit of deleting Shared/Jama is that the only function which PhpSpreadsheet has added to the global namespace (hypo in Maths.php) goes away.

There is one additional use in Shared/Trend/PolynomialBestFit. That use is best replaced with Matrix/Matrix, which is already a requirement for PhpSpreadsheet. PolynomialBestFit has zero test coverage, and I didn't add any for this change. There seem to be existing errors which both Phpstan and Scrutinizer complain about, and I am quite convinced that they are not false positives. Fixing those problems will be a project for another day.

Calculation has many calls to `Information\ErrorValue` and `Information\ExcelError`. It is inconsistent in how it does so - most invoke `Information\E...` but a small number take advantage of additional `use` statements to just invoke `E...`. I have made the usage consistent by changing the small number to act like the majority and eliminating the `use` statements.

Some of the test cases exposed the fact that MAX, MAXA, MIN, and MINA do not properly handle error strings in their input. For example, if cell A1 contains 2, and A2 contains `=5/0`, `=MAX(A1, A2)` should return `#DIV/0!`. They are changed to handle them properly.

`Shared\JAMA` was normally omitted from code coverage. Since it is being deleted, there is no longer a reason to explicitly exclude it. `Writer\PDF` was also on the exclude list, probably for historical reasons, but there is no reason to exclude it now (it is, in fact, 100% covered), so it will no longer be excluded.

* Scrutinizer

Eliminate some newly dead code.
2022-12-30 07:22:58 -08:00
Mark Baker 5649541a68 Merge branch 'master' into CalcEngine_Structured-References 2022-12-29 17:38:13 +01:00
MarkBaker adbc981a2c Unit tests for calculations with Structured References 2022-12-27 21:49:22 +01:00
MarkBaker fda996e192 Initial work on handling Structured References in the Calculation Engine 2022-12-24 00:20:10 +01:00
oleibman dd9a922b02 Minor Coverage Improvements (#3238)
No source code is changed.
2022-12-22 15:11:58 -08:00
MarkBaker ca7226e9d7 Ensure that Full Table Structured References are correctly recognised, and don't throw an error 2022-12-19 04:44:24 +01:00
MarkBaker 6fd24cad58 Refactor database tests to execute the test itself and check assertions in the main test function, not in the base class
Test both the function implementation (directly), and when the function is called in a formula from a spreadsheet
Replace error strings in expected result for providers with the value returned from the ExcelErrors class
2022-12-08 12:49:19 +01:00
oleibman 057572ee90 Change Additional Statistical Tests to Use Spreadsheet Context (#3217)
* Change Additional Statistical Tests to Use Spreadsheet Context

With an earlier change, I made all but 18 Statistical tests run in spreadsheet context. This PR changes 12 of those 18. The remaining 6 usually return array results, so it is a tougher task to handle them. I will continue to think on it.

AVERAGEIF, AVERAGEIFS, and COUNTBLANK are changed to throw an Exception when a range is specified as a literal. They previously accepted array (enclosed in braces) literals, and bumbled along till they threw an error for non-array literals. Throwing an exception appears to be analogous to how Excel operates, rather than something more friendly like a VALUE error. There may be other functions which require similar treatment.

There also remains a TODO for COUNTIFS, and possibly other functions. It appears that PhpSpreadsheet counts booleans for both integer and string compares and probably shouldn't. Again, this is a problem for another day.

* Scrutinizer

Fix one problem.

* Scrutinizer Ignores Its Own Suggested Remedy

Try another approach.
2022-12-02 14:14:43 -08:00
oleibman d2deb133bc Fix Unintential Deprecated Calls in Tests - STATISTICAL (#3181)
* Fix Unintential Deprecated Calls in Tests - STATISTICAL

I think it's best to install these before PR #3166. There are no changes to source code, only to doc-blocks and to test members which continue to inadvertently use calls to deprecated functions.

* Missed One Deprecation

Fix it now.

* Run Tests in Spreadsheet Context

This is quite a bit more difficult for Statistical than for the other Calculation categories. This is partly because of the use of multi-dimensional matrices, and also because some arguments are interpreted differently when they come from a cell rather than entered directly in a formula. This push leaves 18 out of 89 test members unchanged, except that they are marked with a TODO to show that the work isn't finished. I will not revisit them as part of this PR, but probably will take a look in a subsequent ticket.
2022-11-25 13:57:17 -08:00
oleibman 1fcfadc4b8 Fix Unintential Deprecated Calls - Everything Else (#3183)
* Fix Unintential Deprecated Calls - Everything Else

I think it's best to install these before PR #3166. This one, which I hope to be the last in this series, does have some minor changes to source code, as well as to doc-blocks and to test members which continue to inadvertently use calls to deprecated functions.

* Some Remaining Deprecations in Tests

Fix them now.

* Minor Docblock Updates

Worksheet::unprotectCellsByColumnAndRow was incorrect. Other changes are cosmetic, leading to slightly better documentation.

* Update Worksheet.php
2022-11-25 13:06:52 -08:00
MarkBaker 04be65aee8 Allow thousands separator in formatted numeric strings to be handled as numbers by the Calculation Engine 2022-11-25 20:03:48 +01:00
MarkBaker 12581cbb72 Allow thousands separator in percentage formatted strings used as numbers by the Calculation Engine 2022-11-25 19:13:20 +01:00
oleibman a884013d00 Fix Unintential Deprecated Calls in Tests - FINANCIAL (#3180)
* Fix Unintential Deprecated Calls in Tests - FINANCIAL

I think it's best to install these before PR #3166. There are no changes to source code, only to doc-blocks and to test members which continue to inadvertently use calls to deprecated functions.

* Change Tests to Run in Spreadsheet Context

Found and fixed some problems with how MIRR handles errors.
2022-11-25 07:19:19 -08:00
Mark Baker 80e4d3a4ed Merge branch 'master' into currencies_stored_as_strings 2022-11-25 14:04:15 +01:00
MarkBaker 171d7684d6 Allow currency numeric strings with thousands separator 2022-11-25 13:15:10 +01:00
Mark Baker 1152196e32 Merge branch 'master' into CalcEngine-Feature_Structured_References 2022-11-24 23:56:08 +01:00
oleibman d93a303371 Fix Unintential Deprecated Calls in Tests - ENGINEERING (#3176)
* Fix Unintential Deprecated Calls in Tests - ENGINEERING

I think it's best to install these before PR #3166. There are no changes to source code, only to test members which continue to inadvertently use calls to deprecated functions.

* Fix deprecation DocBlocks

Deprecated->deprecated, adjust see and comments

* Fix Deliberate Deprecated Tests

Add annotations.

* Run Unit Tests in Spreadsheet Context

This turned up only one error, in IMSUB. The only group that still needs this is Statistical. Not sure if I will get to that quickly.
2022-11-24 07:57:41 -08:00
Mark Baker 7d2772ea2d Merge branch 'master' into CalcEngine-Feature_Structured_References 2022-11-23 17:08:29 +01:00
oleibman 3697352e28 Fix Unintential Deprecated Calls in Tests - LOGICAL (#3178)
* Fix Unintential Deprecated Calls in Tests - LOGICAL

I think it's best to install these before PR #3166. There are no changes to source code, only to doc-blocks and to test members which continue to inadvertently use calls to deprecated functions.

* Change Unit Tests to Run in Spreadsheet Context

They had been run as direct calls, which is not how most users would use them. Making this change exposed some minor coding errors - SWITCH needs to flatten its arguments, and IFERROR and IFNA were not handling a null testValue in the same manner as Excel.
2022-11-23 07:49:28 -08:00
Mark Baker b6fda7fd78 Merge branch 'master' into CalcEngine-Feature_Structured_References 2022-11-23 16:10:40 +01:00
oleibman ca1ff07fbe Fix Unintential Deprecated Calls in Tests - DATABASE (#3175)
* Fix Unintential Deprecated Calls in Tests - DATABASE

I think it's best to install these before PR #3166. There are no changes to source code, only to test members which continue to inadvertently use calls to deprecated functions.

* Fix deprecation Blocks

Deprecated->deprecated, adjust see and comments

* Fix Deliberate Deprecated Tests

Add annotations.

* Change Unit Tests to Run in Spreadsheet Context

... rather than as direct calls. The major difference is that specifying an invalid column should result in an Excel error, not null. Minor code changes were needed, including to Statistical/Conditional which sometimes calls Database.

* Correct Some DocBlocks

Null is no longer a possible output for most of these functions.

* 2 Overlooked Tests

Change to run in spreadsheet context.

* T Function Should Return Null-String, not Null

Fix it.
2022-11-23 06:54:51 -08:00
Mark Baker fa6e1791f8 Merge branch 'master' into CalcEngine-Feature_Structured_References 2022-11-23 13:33:50 +01:00
oleibman fe79f7b02c Fix Unintential Deprecated Calls in Tests - INFORMATION (#3177)
* Fix Unintential Deprecated Calls in Tests - INFORMATION

I think it's best to install these before PR #3166. There are no changes to source code, only to doc-blocks and to test members which continue to inadvertently use calls to deprecated functions.

* Missed Some Deprecated Calls

Fix them now.
2022-11-22 07:14:19 -08:00
oleibman c2bf9cdf9e Restore Cyclic Error Messages (#3170)
Fix #3169. Insufficient detail when calculation fails due to cyclic reference.
2022-11-22 06:32:08 -08:00
MarkBaker 0244fb4fc8 Store StructuredReference object in the stack rather than simply the Structured Reference string, so that we don't have to create the object for both lexer and parser 2022-11-22 13:31:35 +01:00
Mark Baker a16ce29e2a Merge branch 'master' into CalcEngine-Feature_Structured_References 2022-11-22 10:21:38 +01:00
oleibman 704a7b9fd1 Fix Unintential Deprecated Calls in Tests - LOOKUPREF (#3174)
* Fix Unintential Deprecated Calls in Tests - LOOKUPREF

I think it's best to install these before PR #3166. There are no changes to source code, only to test members which continue to inadvertently use calls to deprecated functions.

* Fix deprecation DocBlocks

Deprecated->deprecated, adjust see and comments

* One Intentional Deprecation

Annotate it.
2022-11-21 19:54:14 -08:00
fjohnston@avatarasoftware.com 66da98ebb8 Handle Currencies Stored as Strings in Formulas
Added a function to the new `FormattedNumber` helper that will use the currency code pulled from `localeconv` by `StringHelper::getCurrencyCode()`.  The currency code is `preg_quoted` and then dropped into a regexp that is modelled on the expression developed for `convertToNumberIfPercent`.  This will allow locale independent operation.
Unfortunately `localeconv` only provides information about standard currency formats and not accounting formats.  This means that we can't say for sure whether or not a locale has an accounting format where the currency symbol shows up in a non-standard position (eg. left justified for some countries instead of appearing directly in front of the value).  The regexp should handle these cases.

The primary issue with this approach is that the regexp will incorrectly match invalid currency formats for some locals as it checks for the symbol before and after the value.

A possible improvement would be to pull `p_cs_precedes` and `n_cs_precedes` from `localeconv` and using them to determine if the currency symbol should appear before or after the value for the current locale.  Since white-space is ignored by the regexp, accounting formats should still work, as long as the accounting format doesn't involve moving the symbol to the opposite side of the value.
2022-11-18 14:54:48 -05:00
MarkBaker 3e81da48f7 Initial parsing for Structured References 2022-11-15 20:00:36 +01:00
MarkBaker d7a2315c8e Additional unit tests 2022-11-11 12:28:26 +01:00
MarkBaker f5beafd845 Refactoring for checks on strings containing formatted numeric values when used in mathematical operations in the Calculation Engine 2022-11-11 12:28:26 +01:00
Mark Baker 04fb3bb37a Merge branch 'master' into master 2022-11-10 10:55:29 +01:00
oleibman fac0e46c91 MATCH Problems with Int/Float Compare and Wildcards (#3142)
* MATCH Problems with Int/Float Compare and Wildcards

Fix #3141. Function matchSmallestValue did not recognize that an integer could match a float. Adding test cases, it seems that matchFirstValue had the same problem. However, matchLargestValue seemed to handle things correctly - but see below.

In addition, the wildcard logic in matchFirstValue is faulty. It ignored tilde as a wildcard character. Although it would have been easy to just add that, I think it was wrong to determine on its own if a wildcard was in use. Just using the already available wildcard functions whenever comparing two strings is sufficient.

I note that Excel doesn't seem to follow its own rules for MATCH (https://support.microsoft.com/en-us/office/match-function-e8dffd45-c762-47d6-bf89-533f4a37673a?ns=excel&version=90&syslcid=1033&uilcid=1033&appver=zxl900&helpid=xlmain11.chm60112&ui=en-us&rs=en-us&ad=us). PhpSpreadsheet's results match Excel's, so no problem. However, when match_type is not zero, the match array is supposed to be sorted, so I would expect `#N/A` when it isn't; but that's not how Excel operates. I have no idea what Excel is doing. If `MATCH(2,{2,0,4,3},1)` isn't `#N/A` because of the unsorted array, then surely it should be `1` (item 1 of the array is the largest number less than or equal to the lookup value); but Excel and PhpSpreadsheet (before and after changes) return `2`. I have moved this example to be the first of the test cases.

One would think strings would behave similarly. But, no - see the second test case. This time Excel does look for an exact match. But the existing logic doesn't get the matching result in PhpSpreadsheet. It requires a whole new block of code, one which doesn't work correctly for numeric lookup value. Ugh.

LibreOffice doesn't always agree with Excel. It seems that it will use wildcard matching even when the match type is not zero (Excel documentation says wildcards are only for type zero, which is just as well because I don't really know what greater/less mean when wildcards are involved). I have not attempted to duplicate this behavior. For the record, Gnumeric agrees with Excel here.

* More Changes - LibreOffice

Add support for LibreOffice matching wildcard strings when type is not zero. Add support for type to be specified as integer other than 0/1/-1, or as float, or as numeric string; non-numeric string should case `#VALUE!` error.

I have found an example of undefined behavior (unsorted array where type is non-zero) where PhpSpreadsheet does not produce the same result as Excel. It is present as a new `incomplete` test case. I can fix it, but not without breaking other tests where the proper behavior is undefined. IMO, this is not a problem we should be concerned about.

Many test cases are added. Chances are I will add some more before merging this change.
2022-11-04 15:51:00 -07:00
fjohnston@avatarasoftware.com 21772479e1 Adding tests for conversion of string percentage to numeric
Adding two test cases:
1) Test the function in `StringHelper.php`.  Modeled this test on the test for the `convertToNumberIfFraction` function.
2) Test a spreadsheet with a string percentage in a formula to see if it  calculates the formula correctly.
2022-11-03 22:03:24 -04:00
oleibman 66695881e4 Calculation suppressFormulaErrors - Minor Break and Deprecation (#3092)
Fix #1531. This is a replacement for PR #3081 (see last paragraph below), which I will close.

Calculation has a property `suppressFormulaErrors`, which really doesn't work as one might expect. If a calculation throws an exception, the setting of this property might prevent the Exception from being thrown, but it will still trigger an Error. I do not think this makes sense, and will change it so the calculation will return `false`, which is part of the original design but which would essentially never happen. This allows the user to save a corrupt spreadsheet, but this was already possible through the use of `setPreCalculateFormulas(false)` on the Writer, so this doesn't really open any new exposures. It nevertheless might be considered a breaking change because of the difference in behavior.

Deprecation - the visibility of the existing property is public, which means it can be changed directly. A new private property is added with a public setter/getter. The new property will be used when the existing property is null (default), which will allow the existing property to be deprecated.

Function getFunctions is changed to static - the array which it returns is static. Existing callers using it as non-static will still function correctly.

Although I am enabling this ability, I don't necessarily think it's a good idea to make use of it. See the original issue for a discussion of why. It is not mentioned in the official documentation, and I will not be adding documentation for it. The originator discovered it by reading the code, and I think that is sufficient for what will often be an ill-advised choice.

Many of the large number of problems with Calculation.php in phpstan baseline are addressed. PR 3081 ran afoul of something in phpstan. The changes in this ticket are more limited, adding a number of doc blocks but leaving executable code unchanged.
2022-10-01 08:40:27 -07:00