Commit Graph

139 Commits

Author SHA1 Message Date
oleibman a89572107a
Handling of #REF! Errors in Subtotal, and More (#2902)
* Handling of #REF! Errors in Subtotal, and More

This PR derives from, and supersedes, PR #2870, submitted by @ndench. The problem reported in the original is that SUBTOTAL does not handle #REF! errors in its arguments properly; however, my investigation has enlarged the scope.

The main problem is in Calculation, and it has a simple fix. When the calculation engine finds a reference to an uninitialized cell, it uses `null` as the value. This is appropriate when the cell belongs to a defined sheet; however, for an undefined sheet, #REF! is more appropriate.

With that fix in place, SUBTOTAL still needs a small fix of its own. It tries to parse its cell reference arguments into an array, but, if the reference does not match the expected format (as #REF! will not), this results in referencing undefined array indexes, with attendant messages. That assignment is changed to be more flexible, eliminating the problem and the messages.

Those 2 fixes are sufficient to ensure that the original problem is resolved. It also resolves a similar problem with some other functions (e.g. SUM). However, it does not resolve it for all functions. Or, to be more particular, many functions will return #VALUE! rather than #REF! if this arises, and the same is true for other errors in the function arguments, e.g. #DIV/0!. This PR does not attempt to address all functions; I need to think of a systematic way to pursue that. However, at least for most MathTrig functions, which validate their arguments using a common method, it is relatively easy to get the function to propagate the proper error result.

* Arrange Array The Way call_user_func_array Wants

Problem with Php8.0+ - array passed to call_user_func_array must have int keys before string keys, otherwise Php thinks we are passing positional parameters after keyword parameters.

7 other functions use flattenArrayIndexed, but Subtotal is the only one which uses that result to subsequently pass arguments to call_user_func_array. So the others should not require a change. A specific test is added for SUM to validate that conclusion.

* Change Needed for Hidden Row Filter

Same as change made to Formula Args filter.
2022-06-25 22:08:32 -07:00
MarkBaker 2ab582a707 Bugfix to returned column indexes for FILTER() by row 2022-03-24 22:12:08 +01:00
MarkBaker 9019523efc Additional unit testing
And a quick bugfix for cell ranges applied to both sort functions and to FILTER()
2022-03-24 17:51:06 +01:00
MarkBaker 7f00049fe8 Initial work on the SORT() and SORTBY() Lookup/Reference functions
The code could stil do with some cleaning up, and better optimisation for memory usage; but all tests are passing... that's for full multi-level sorting (including direction), and allowing for correct sorting of sting/numeric datatypes.
2022-03-24 12:21:27 +01:00
oleibman c112802023
Eliminate Most Scrutinizer Problems in Test Suite (#2699)
* Eliminate Most Scrutinizer Problems in Test Suite

Mostly minor code changes, with some annotations.

* Missed 2 php-cs-fixer Problems

They should be fixed now.
2022-03-21 13:58:42 -07:00
MarkBaker f3bb61f3e4 Initial work implementing the FILTER() Lookup/Reference function
Tighten up on vector formats; and provide a couple of helper methods for testing row/column vectors
2022-03-20 18:01:30 +01:00
MarkBaker 75e45057f3 Fix scrutinizer issue complaint 2022-03-18 15:07:13 +01:00
MarkBaker c8cf193301 Initial work implementing the new UNIQUE() Lookup/Reference array function 2022-03-18 14:18:37 +01:00
oleibman e87be5e16d
Failing Test Requiring Too Much Precision (#2647)
The new array tests for IMCSC fail on my system because of a rounding error in the 14th (!) decimal position. This is not a real failure. Change the test to use only the first 8 decimal positions.
2022-03-04 00:11:04 -08:00
Mark Baker 3c57d9e291
Fix for issue #2614 (#2615)
* Fix for issue #2614

* Unit test (in ISREF() tests) that covers issue #2614
2022-02-22 09:06:10 +01:00
Mark Baker c9f948bd91
Initial work on implementing Array-enabled for the HLOOKUP() and VLOOKUP() functions (#2611)
* Initial work on implementing Array-enabled for the HLOOKUP() and VLOOKUP() functions

* In the MATCH() function, we should also use `evaluateArrayArgumentsIgnore()` because the lookupvalue and matchType arguments can be array arguments, but lookupArray is always a dataset matrix
2022-02-21 19:56:21 +01:00
Mark Baker db21d043fe
Implementation of the ISREF() information function (#2613) 2022-02-21 18:47:23 +01:00
Mark Baker 0ee4d96576
Array-enable the ISFORMULA() function (#2610)
Implement Array-enabled for  ERROR.TYPE() function
Extract ERROR.TYPE() function tests into separate test file
Extract error function tests into separate test files

And thus complete the implemented Information functions
2022-02-20 19:32:13 +01:00
Mark Baker 35b65bef8c
First steps toward array-enabling the information functions (#2608)
* First steps toward array-enabling the information functions

Also includes moving unit tests out from Functions and into a separate, dedicated Information folder

* Resolve issue with IF(), branch pruning and calculation cache (ensure that we don't convert the if condition to a bool before we've tested to see if it evaluates to an error)
More refactoring
2022-02-20 16:46:25 +01:00
Mark Baker 71927f5591
Issue 2551 array enable lookup ref functions (#2606)
* Start work on array-enabling the Lookup and Reference functions

Requires a new method (`evaluateArrayArgumentsSubsetFrom()`) in the `ArrayEnabled` Trait to handle functions where the arguments that need special array handling are trailing rather than leading arguments
2022-02-19 18:49:01 +01:00
Mark Baker c10d86eb9c
Start work on array-enabling the Lookup and Reference functions (#2602)
* Start work on array-enabling the Lookup and Reference functions

Requires a new method (`evaluateArrayArgumentsSubsetFrom()`) in the `ArrayEnabled` Trait to handle functions where the arguments that need special array handling are trailing rather than leading arguments
2022-02-19 18:36:50 +01:00
Mark Baker d5dc58d20e
Extract information functions (#2605)
* Split Information functions into a dedicated class and namespace and categorise as Value or Error
* Refactor all error functions into the new ExcelError class
2022-02-19 13:53:17 +01:00
Mark Baker 9c473682bc
Set precision for Database function unit tests, for RowColumnReference and Dimension Helper unit tests (#2604) 2022-02-18 21:37:26 +01:00
Mark Baker 0371ccb686
Convert all relevant Logical functions to support array arguments (#2600) 2022-02-18 02:56:23 +01:00
Mark Baker 03993bce05
The last big block of Engineering functions; those involving complex numbers (#2597) 2022-02-17 15:17:33 +01:00
Mark Baker ef839f56be
Get started with array-enabling the Engineering functions - Erf, Bessel, bitwise, comparisons Unit of Measure and Number base conversions first (#2594) 2022-02-16 18:32:07 +01:00
Mark Baker cdbe5c7c9b
Converting Statistical functions to be array-enabled (phase #2) (#2593) 2022-02-15 20:34:39 +01:00
Mark Baker f1cb75eaec
Start work on Array-enabling the Statistical functions (#2588) 2022-02-15 14:41:17 +01:00
Mark Baker e3b7cb5f9d
I'm ignoring SUMIF() and SUMIFS() for the moment; so this should complete all the applicable Math/Trig functions;so the subset SERIESSUM() function and RANDBETWEEN() should complete Math/Trig (#2586) 2022-02-13 12:50:05 +01:00
Mark Baker 8f3c52a3cf
Enable array-readiness for more Math/Trig functions (#2584)
* Enable array-readiness for more Math/Trig functions; CEILING() FLOOR() (and variants), TRUNC(), BASE() and the various Logarithms
* Minor refactoring
2022-02-12 20:47:47 +01:00
MarkBaker 75213f5ee1 Enable array-readiness for more Math/Trig functions 2022-02-12 16:56:06 +01:00
MarkBaker b3ff2e347f All Text functions made array-ready 2022-02-12 12:22:31 +01:00
MarkBaker c41dd0afae FIND(), SEARCH(), LEFT(), RIGHT, MID(), CLEAN(), TRIM(), TEXTJOIN() and REPT() functions 2022-02-11 18:56:21 +01:00
MarkBaker c9886127c0 Style and phpstan cleanups 2022-02-11 13:55:52 +01:00
MarkBaker df12b06c59 Text function array value tests, plus some cleanup 2022-02-11 12:34:29 +01:00
MarkBaker 1e59b9113f Last of the work on array-enabling Date/Time functions; all completed in this category 2022-02-10 20:53:58 +01:00
MarkBaker ca81991728 phpcs cleanup 2022-02-10 15:40:30 +01:00
MarkBaker ec2ca1764f The `WORKDAY()` function accepts 2 "static" arguments that could be passed as arrays; but also accepts a set of trailing date arguments that are accepted as an array by the splat operator. Only the first two arguments should be tested for returning array values; but the logic still needs to work with the full argument set.
Provide a separate "subset" method in the `ArrayEnabled` Trait, that allows a subset of arguments to be tested for array returns.

Set up basic tests for `WORKDAY()`
2022-02-10 15:37:45 +01:00
MarkBaker 83ff74b97e Enable most of the Date/Time functions to accept array arguments 2022-02-10 15:37:45 +01:00
Mark Baker 291ea88a6c
Initial work enabling Excel function implementations for handling arrays as arguments when used in "array formulae". (#2562)
* Initial work enabling Excel function implementations for handling arrays as aguments when used in "array formulae".

So far:
 - handling for single argument functions
 - for functions where only one of the arguments is an array (a matrix or a row/column vector)
 - for when there are two array arguments, and one is a row vector, the other a column vector
 - for when there are either 2 row vectors, or 2 column vectors
 - for a matrix and either a row or column vector 

Will work ok, as long as there are no more than two array arguments; still need to identify the logic to apply when there are more than two arrays; or there are two that aren't an already supported row vector/column vector pairing (ie two matrices).

* Throw an exception if we have three or more array arguments (after flattening) passed to a supported function until we can identify the abstruse non-euclidian logic behind how Excel handles building, using and presenting those n-dimensional result arrays

* Implement array arguments for the DATE() function so that we can verify that paired arrays/vectors work with functions that support more than 2 arguments

* Implement array arguments for the many of the Math/Trig functions

* Update change log
2022-02-09 15:12:54 +01:00
Mark Baker d0965298d5
Additional unit tests for RANDARRAY() Math/Trig function implementation (#2563) 2022-02-07 10:19:19 +01:00
Mark Baker ebeed87db5
Initial implementation of the MS Excel RANDARRAY() MathTrig function (#2540)
* Initial implementation of the MS Excel RANDARRAY() MathTrig function
Update Change Log

* Unit Tests for RANDARRAY()
2022-01-31 22:29:03 +01:00
Mark Baker 26079174a0
Implementation of the SEQUENCE() Excel365 function (#2536)
* Implementation of the SEQUENCE() Excel365 function

Note that the Calculation Engine does not yet support the Spill operator, or spilling functions

* Handle the use-case of step = 0; and tests for exception handling for invalid arguments

* Update Change Log
2022-01-29 14:32:40 +01:00
oleibman 95d9cc965d
Refinement for XIRR (#2487)
* Refinement for XIRR

Fix #2469. The algorithm used for XIRR is known not to converge in some cases, some of which are because the value is legitimately unsolvable; for others, using a different guess might help.

The algorithm uses continual guesses at a rate to hopefully converge on the solution. The code in Python package xirr (https://github.com/tarioch/xirr/) suggests a refinement when this rate falls below -1. Adopting this refinement solves the problem for the data in issue 2469 without any adverse effect on the existing tests. My thanks to @tarioch for that refinement.

The data from 2469 is, of course, added to the test cases. The user also mentions that an initial guess equal to the actual result doesn't converge either. A test is also added to confirm that that case now works.

The test cases are changed to run in the context of a spreadsheet rather than by direct calls to XIRR calculation routine. This revealed some data validation errors which are also cleaned up with this PR. This suggests that other financial tests might benefit from the same change; I will look into that.

* More Unit Tests

From https://github.com/RayDeCampo/java-xirr/blob/master/src/test/java/org/decampo/xirr/XirrTest.java
https://github.com/tarioch/xirr/blob/master/tests/test_math.py

Note that there are some cases where the PHP tests do not converge, but the non-PHP tests do. I have confirmed in each of those cases that Excel does not converge, so the PhpSpreadsheet results are good, at least for now. The discrepancies are noted in comments in the test member.
2022-01-13 19:31:46 -08:00
oleibman 5d1ab39def
Replace Tests With Unneeded Mocking (#2465)
Replace mock tests with real ones when possible. The original tests are all still present; they just take place in a more representative scenario.

After this, there will be 4 remaining uses of mocking. Of these, 3 are needed for scenarios which are otherwise hard to test - WebServiceTest, CellsTest, and SampleCoverageTest. For the other one, AutoFilterTest, I just can't figure out what it's trying to accomplish, so have left it alone.

This change is almost entirely restricted to tests. There is a one-line change in src. When the first argument passed to OFFSET is null or nullstring, the returned value is currently 0. However, according to the documentation for Excel, it should be `#VALUE!`. The code is changed accordingly.
2021-12-31 13:24:43 -08:00
oleibman 3db0b2a2de
Corrections for HLOOKUP Function (#2330)
See issue #2123. HLOOKUP needs to do some conversions between column numbers and letters which it had not been doing.

HLOOKUP tests were performed using direct calls to the function in question rather than in the context of a spreadsheet. This contributed to keeping this error obscured even though there were, in theory, sufficient test cases. The tests are changed to perform in spreadsheet context. For the most part, the test cases are unchanged. One of the expected results was wrong; it has been changed, and a new case added to cover the case it was supposed to be testing.

After getting the HLOOKUP tests in order, it turned out that a test using literal arrays which had been succeeding now failed. The array constructed by the literals are considerably different than those constructed using spreadsheet cells; additional code was added to handle this situation.
2021-10-23 17:59:42 -07:00
oleibman cb8ee73355
Cache Results for Tests Involving NOW and TODAY Functions (#2311)
My bulletproofing of these tests was not yet sufficient. Although I have never had a failure in probably thousands of tests, one user submitted a PR which did fail testing NOW, fortunately not in a test that is required to pass. The problem is that it is not sufficient merely to set the cell value inside a do-while loop; it is necessary to calculate it in order to cache its result so that results based on that cell will be internally consistent.

No source code is changed for this PR, just some tests.
2021-10-03 11:06:47 -07:00
Owen Leibman b03544469b 2 Tests vs. Scrutinizer/Phpstan
Just reviewing Scrutinizer's list of "bugs". There are 19 ascribed to me. For some, I will definitely take no action (e.g. use of bitwise operators in AND, OR, and XOR functions). However, where I can clean things up so that Scrutinizer is satisfied and the resulting code is not too contorted, I will make an attempt.

This PR corrects 2 problems according to Scrutinizer, and 1 per Phpstan. Only test members are involved.
2021-07-01 11:15:02 +02:00
Mark Baker d2076fefab
Additional unit tests for negative interest rates in the financial functions, and also tests using negative present/future value arguments (#2166) 2021-06-16 14:16:48 +02:00
oleibman 1e74282259
Fix for Issue 2158 (AverageIf Calculation Problem) (#2160)
* Improve Identification of Samples in Coverage Report

The Phpunit coverage report currently contains bullet items like `PhpOffice\PhpSpreadsheetTests\Helper\SampleTest\testSample with data set "49"`. This extremely simple change takes advantage of Phpunit's ability to accept an array with keys which are either strings or integers, by using the sample filenames as the array keys rather than sequential but otherwise meaningless integers (e.g. `49` in the earlier cited item). The bullet item will now read `PhpOffice\PhpSpreadsheetTests\Helper\SampleTest\testSample with data set "Basic/38_Clone_worksheet.php"`.

* Fix for Issue 2158 (AverageIf Calculation Problem)

Issue #2158 reports an error calculating AverageIf because a function returns null rather than a string. There turn out to be several components to this problem:
- The nominal fix to the problem is to add some null-to-nullstring coercion in DatabaseAbstract.
- This fixes the error, but does not necessarily lead to the correct result because buildQuery treats values of null and null-string identically, whereas Excel does not. So change that to treat null-string as any other string.
- But that doesn't lead to the correct result either. That's because Functions/ifCondition recognizes a null string, but then continues to (over-)process it until it returns the wrong result. Fix this problem in conjunction with the other two, and we finally get the correct result.

A new unit test is added for AVERAGEIF, and new test cases are added for SUMIF. In each case, there are complementary tests for conditions of null and null-string, and the results agree with Excel. There may or may not be value in adding new tests to other functions, and I will be glad to do so for any functions which you care to identify, but no existing tests broke as a result of these changes.
2021-06-15 09:54:57 +02:00
oleibman 4f06d84248
TextData - Minor Changes, Test Coverage (#2151)
* PHP8.1 Deprecation Passing Null to String Function

For each of the files in this PR, one or more statements can pass a null to string functions like strlower. This is deprecated in PHP8.1, and, when deprecated messages are enabled, causes many tests to error out. In every case, use coercion to pass null string rather than null.

* TextData - Minor Changes, Test Coverage

Per agreement on a previous push, I looked into standardizing the initialization of the TextData functions (like Engineering and MathTrig), with particular regard for avoiding multiple later null coercions. This simplifies the code quite a bit. This PR also increases coverage to 100% for all TextData modules. All entries in Phpstan baseline for non-deprecated TEXTDATA functions are removed. There were some minor bugfixes.

Whereas Excel (and Gnumeric) treat booleans when supplied as strings as 'TRUE' or 'FALSE', ODS treats them as '1' or '0'. Unlike Excel, ODS generally does not allow bool for int arguments; it does, however, allow them for FIND and SEARCH. ODS allows boolean for into for SUBSTITUTE even though Excel doesn't. ODS allows bool for string for NUMBERVALUE and VALUE even though Excel doesn't. ODS accepts 0 as an argument for CHAR; Excel doesn't. Most of this seems like random decisions on the part of the developers; I've done my best to follow the products in each case. There is a new test member devoted to ODS tests.

Gnumeric has an anomaly vis-a-vis the others - if length is supplied to LEFT/MID/RIGHT as null, Gnumeric treats it as 0 rather than 1.

All tests now take place in the context of a spreadsheet ...

Except for RETURNSTRING, which is not the implementation of an Excel function, and is referred to in the rest of PhpSpreadsheet only in the unit tests for itself. It should probably be deprecated, but that is not part of this PR, just in case there is some reason for it that I couldn't discern.

I have tried to make the first line of each doc block identify the Excel function name rather than its name in PhpSpreadsheet. I think it makes things more comprehensible.

Some tests call Settings::setLocale, but there was no Settings::getLocale. At the end of the tests which do it, they invoke setLocale('EN-US'), which, in a practical sense, is sufficient. However, in theory it would be better for them to get the current locale before changing it, then changing it back to the original when the time came. I have added getLocale and made the appropriate testing change.

The CHAR function took an interesting turn. One can set the value of a cell to, say, CHAR(2), the ASCII/UTF-8 representation of a control character, which is not legal in certain contexts. The only Reader/Writer that could handle this without problems is Xls, which deals with binary data all the time. However, if you tried to write it to Xlsx, Excel would not be able to open the resulting file because of what it considers an illegal character. I changed the Xlsx writer to escape such characters when writing the value of a string function. I did not make any other changes to the Xlsx writer - it seems to me that setting a cell to CHAR(2) is legitimate, but setting it to say `"\x02"` seems less likely to be legitimate, so the latter will still fail (although `="\x02"` should work). The Xlsx reader already supports the escape mechanism that I added to the writer.

CHAR control character and Ods - not supported by either Reader or Writer. I did not attempt to add this now. There is lots still missing from ODS, and this item just can't be a high priority amongst all of those.

CHAR control character and Csv - it is supported by reader and writer if the file has a csv extension. However, trying to guess the mime type without an extension - the control character makes mime_get_type guess application/octet-stream, and PhpSpreadsheet therefore thinks that Csv can't read it.

CHAR control character and Html. Actual use of the control character in the file is subject to the same problems as Xml (i.e. Xlsx and Ods). It wasn't terribly difficult to get the Html Writer to change `"\x02"` to "``". I believe that this is technically legal; however, DOMDocument.loadHTML rejects it as an illegal entity, and I am not convinced that it is wrong to do so, so I haven't changed the Html writer.

* Scrutinizer

Correct 3 minor errors.
2021-06-15 08:37:17 +02:00
MarkBaker 65309dbe78 Fix unit tests for function list markdown, and style issues for DOLLAR/USDOLLAR 2021-05-20 20:41:09 +02:00
MarkBaker f89bfc9e02 Additional language data, and improved automated build of translation files for Calculation Engine locale 2021-05-20 20:41:09 +02:00
Owen Leibman 4bd506b414 Minor Improvement to Test Cleanup DateTime
Permit spreadsheet allocated as private member in test class to be garbage-collected after test completion.
2021-05-14 10:53:27 +02:00
Owen Leibman efe8f49123 Minor Improvement to Test Cleanup LookupRef
Permit spreadsheet allocated as private member in test class to be garbage-collected after test completion.
2021-05-14 10:30:49 +02:00