Commit Graph

83 Commits

Author SHA1 Message Date
Adrien Crivelli fcd9f10663
Update PHP-CS-Fixer rules 2020-05-18 13:49:57 +09:00
Owen Leibman 4f6d4af396
Save Excel 2010+ Functions Properly
For functions introduced in Excel 2010 and beyond, Excel saves them
in formulas with the xlfn_ prefix. PhpSpreadsheet does not do this;
as a result, when a spreadsheet so created is opened, the cells
which use the new functions display a #NAME? error.
This the cause of bug report 1246:
https://github.com/PHPOffice/PhpSpreadsheet/issues/1246
This change corrects that problem when the Xlsx writer encounters
a 2010+ formula for a cell or a conditional style. A new class
Writer/Xlsx/Xlfn, with 2 static methods,
is introduced to facilitate this change.

As part of the testing for this, I found some additional problems.
When an unknown function name is used, Excel generates a #NAME? error.
However, when an unknown function is used in PhpSpreadsheet:
  - if there are no parameters, it returns #VALUE!, which is wrong
  - if there are parameters, it throws an exception, which is horrible
Both of these situations will now return #NAME?
Tests have been added for these situations.

The MODE (and MODE.SNGL) function is not quite in alignment with Excel.
MODE(3, 3, 4, 4) returns 3 in both Excel and PhpSpreadsheet.
However, MODE(4, 3, 3, 4) returns 4 in Excel, but 3 in PhpSpreadsheet.
Both situations will now match Excel's result.
Also, Excel allows its parameters for MODE to be an array,
but PhpSpreadsheet did not; it now will.
There had not been any tests for MODE. Now there are.

The SHEET and SHEETS functions were introduced in Excel 2013,
but were not introduced in PhpSpreadsheet. They are now introduced
as DUMMY functions so that they can be parsed appropriately.

Finally, in common with the "rate" changes for which I am
creating a pull request at the same time as this one:
samples/Basic/13_CalculationCyclicFormulae
PhpUnit started reporting an error like "too much regression".
The test deals with an infinite cyclic formula, and allowed
the calculation engine to run for 100 cycles. The actual number of cycles
seems irrelevant for the purpose of this test. I changed it to 15,
and PhpUnit no longer complains.
2020-05-18 12:37:35 +09:00
Adrien Crivelli 414e5695ef
Update CHANGELOG 2020-05-17 19:52:34 +09:00
oleibman 9ae521cdd4
Fix RATE, PRICE, XIRR, and XNPV Functions (#1456)
There were about 20 skipped tests for RATE and PRICE marked
"This test should be fixed". This change does that by fixing
the code for those functions, validating the existing tests,
and adding new ones. XIRR and XNPV are also substantially changed.
As part of this change, the following functions also have minor changes:

  - isValidFrequency
  - COUPDAYBS
  - COUPNUM (additional tests)
  - DB
  - DDB

PhpUnit reports 100% coverage for all the changed functions.

Since I was dealing with skipped tests, I also fixed
tests/PhpSpreadsheetTests/Writer/Xlsx/LocaleFloatsTest,
which was being skipped in Windows. I also delete the temporary
file which it creates.
There is now only one remaining test which is skipped -
ODS Reader is not complete enough to run some tests against it.
Unfortunately, that test is too complicated for me to deal with now.

In researching this change, I found several places in the code where special code was added for Gnumeric claiming:

   - Gnumeric does not handle free-format string dates
   - Gnumeric adds extra options, not available in Excel,
     for the frequency parameter for functions such as YIELD
   - Gnumeric rounds the results for DB and DDB to 2 decimal places

None of these claims is true, at least not on a recent version
of Gnumeric, and the code which supports these differences is removed.
There did not appear to be any tests targeted for
these supposed properties of Gnumeric.

The PRICE function needed relatively minor changes - mostly
additional tests for invalid input. The main problem with the PRICE
tests is that Excel appears to have a bug. The algorithm is published:
https://support.office.com/en-us/article/price-function-3ea9deac-8dfa-436f-a7c8-17ea02c21b0a
The results that Excel returns for basis codes 2 and 3 appear to be
incorrect in many cases. I have segregated these tests into a
new test PRICE3. The results of these tests agree with the published
algorithm, and to the results for LibreOffice and Gnumeric.
The results returned by Excel do not agree with them.
The tests which remain in the test PRICE all use basis codes other
than 2 or 3, and all agree with Excel, LibreOffice, and Gnumeric.

For the RATE function, there appears to be a problem with how the
secant method was implemented. I studied the implementation of RATE
in Python numpy, and adapted its implementation of secant method.
The results now agree with numpy, and, more important, with Excel.

XIRR, which calls XNPV, permits its dates to be earlier than the
start date, whereas XNPV does not. I dealt with this by renaming
the existing XNPV function to xnpvOrdered, adding a parameter to
indicate whether start date has to be earliest. XNPV calls the new
function with that parameter set to TRUE, and XIRR calls it with
the parameter set to FALSE. Some additional error checking was
added to xnpvOrdered, and also to XIRR. XIRR tests benefited
from increasing the value of FINANCIAL_MAX_ITERATIONS.

Finally, since this change is very test-related:
samples/Basic/13_CalculationCyclicFormulae
PhpUnit started reporting an error like "too much regression".
The test deals with an infinite cyclic formula, and allowed
the calculation engine to run for 100 cycles. The actual number of cycles
seems irrelevant for the purpose of this test. I changed it to 15,
and PhpUnit no longer complains.
2020-05-17 19:50:01 +09:00
Adrien Crivelli e868e58d20
Allow to run an entire folder of tests
We now can do something like:

```sh
./vendor/bin/phpunit tests/PhpSpreadsheetTests/Reader/
```
2020-05-17 18:35:55 +09:00
Adrien Crivelli 7e79782dae
Remove @throws comment
Those are extremely hard to maintain properly and bring almost
no value, especially if they are outdated
2020-05-16 20:33:25 +09:00
Adrien Crivelli f1a019e492
Upgrad PHP deps 2020-04-27 19:29:45 +09:00
Paul Kievits a6c56d0f81
Added support for the FLOOR.MATH and FLOOR.PRECISE functions 2020-04-26 22:19:33 +09:00
Owen Leibman c4895b9468
MATCH with a static array should return the position of the found value based on the values submitted.
Returns #N/A, unless the element searched for is at the end of the array.

The problem is in Calculation.php line 4231:
                    if (!is_array($functionCall)) {
                        foreach ($args as &$arg) {
                            $arg = Functions::flattenSingleValue($arg);
                        }
                        unset($arg);
                    }

I believe this code is intended to handle functions where PhpSpreadsheet just passes
the call on to PHP without implementing the code on its own, e.g. for atan or acos.
In the bug report, the following code fails:
  $flat_rate = "=MATCH(6,{4,5,6,2}, 0)";
  $sheet->getCell('A1')->setValue($flat_rate);
The expected value is 3, but the actual result is "#N/A".
The reason for this result is that the parser replaces the braces with calls
to the MKMATRIX internal function, whose value for functioncall was:
'self::MKMATRIX'. Since this isn't an array, the flattening code is executed,
and the unintended result occurs. The fix is to change the definition for
functioncall in that case to [__CLASS__, 'mkMatrix'], avoiding the flattening.

However, there is also another part to this bug. The flattening should be
returning the first entry in the array, but is in fact returning the last.
This explains why the bug report specified "unless ... end of the array".
I confirmed that Excel does use the first item in the array rather than the last,
e.g. =atan({1,2,3}) entered into a cell will return atan(1), not atan(3).
The problem here is that flattenSingleValue, which says in its comments that
it is supposed to be returning the first item, uses array_pop rather than array_shift.
I have changed that as well. The same mistake was also present in
Cell.php function getCalculatedValue. The correct behavior can be verified
by entering =minverse({-2.5,1.5;2,-1}) into an Excel cell'
Excel flattens the result ({2,3;4,5}) to 2, and so should PhpSpreadsheet.

Fixes #1271
Closes #1332
2020-04-26 22:09:31 +09:00
paulkned 0c52f173aa
Added support for the base function (#1344) 2020-02-19 20:12:30 +01:00
paulkned 25e3e45eb6
Added support for the ARABIC excel function (#1343)
Updated changelog

Updated docprops

Fixed stylci
2020-02-11 22:59:19 +01:00
Owen Leibman 9552172b85
Do not confuse defined names and cell refs
CALCULATION_REGEXP_CELLREF is not sufficiently robust.
It treats some perfectly legal defined names, e.g. A1A, as cell refs.
When the Xlsx Writer tries to save a worksheet which uses such a name
in a formula in a cell, it throws an exception.

The new DefinedNameConfusedForCellTest is a simple demonstration.
The Regexp has been changed to ensure the name starts on a Word boundary,
and to make sure it is not followed by a word character or period.
This fixes the problem, and does not appear to cause any regression
problems in the test suite.

Closes #1263
2019-11-30 16:10:43 +01:00
Adrien Crivelli 9fa45f7e48
PHP 7.4 compatibility 2019-11-30 00:12:46 +01:00
Paul Blacknell 788f79c1bb
Validate XIRR inputs and return correct error values
Fix: Return #NUM! if values and dates contain a different number of values
Fix: Return #NUM! if there is not at least one positive cash flow and one negative cash flow
Fix: Return #NUM! if any number in dates precedes the starting date
Fix: Return #NUM! if a result that works cannot be found after max iteration tries
Fix: Correct DocBlocks for XIRR & XNPV
Add: Validate XIRR with unit tests

Closes #1177
2019-11-17 21:17:12 +01:00
Adrien Crivelli 99d4f185fb
Avoid test without assertion 2019-11-10 17:05:18 +01:00
Adrien Crivelli ee5134a954
Merge branch 'master' into Further-Test-Refactoring 2019-09-20 16:04:36 -07:00
yunjusu bbbfdb86a0
Fix `getCalculatedValue()` error with more than two INDIRECT
Closes #1115
2019-08-17 12:59:30 -07:00
Fräntz Miccoli 0b387e767e
Branch pruning around IF function calls to avoid resolution of every branches
Calculation engine was resolving every function by first resolving its arguments
including IFs, this was causing significant over evaluation when IFs were used
as it meant for every case to be evaluated.

Introduce elements to identify ifs and enable better branch resolution
(pruning). We tag parsed tokens to associate a branch identifier to them.

Closes #844
2019-08-11 18:23:47 -07:00
MarkBaker f14e5ea837 More refactoring Excel of Calculation Function Unit Tests 2019-07-27 16:35:27 +02:00
MarkBaker 905a697639 More work on refactoring Excel Calculation Function Unit Tests 2019-07-27 16:02:58 +02:00
Mark Baker 26e87c45ae
Test refactoring (#1112)
* Merge branch 'master' of C:\Projects\PHPOffice\PHPSpreadsheet\develop with conflicts.

* Argument fix

* Text Test functions refactored into individual test files

* Codestyle (line at eof)

* docblocks
2019-07-27 14:28:16 +02:00
Mark Baker 1c6f0b8a9d
Improved tests (#1110)
* Merge branch 'master' of C:\Projects\PHPOffice\PHPSpreadsheet\develop with conflicts.

* New statistical tests

* Sniffs

* Additional statistical function unit tests

* Additional statistical function unit tests

* Fix case-sensitivity

* Fix HARMEAN code logic

* Unit tests refactored into individual files for all logical functions
Implemented IFNA()

* Fix silly typo

* NOT needs ...args to allow for test when no argument passed

* Codestyle

* Use instance asserts
2019-07-26 22:21:17 +02:00
Mark Baker aaf996a165
Refactor engineering tests (#1106)
* Merge branch 'master' of C:\Projects\PHPOffice\PHPSpreadsheet\develop with conflicts.

* Bessels, and set some date tests to defined/named arguments

* Fix test class naming

* Names arguments for math/trig tests

* Docblock updates

* More engineering function unit test refactorings

* More engineering function unit test refactorings. This time, moving on to the Complex engineering functions

* Fix ImConjugate test

* Fix parseComplex test

* Fix parseComplex test

* More of the complex number function unit tests refactored

* Finish refactoring of the complex number function unit tests

* Newer phpunit assertions

* Add parsecomplex unit test back until we're ready to drop the deprecated function; but as it doesn't use the specified data provider at all, drop reference to that
2019-07-25 21:02:41 +02:00
Adrien Crivelli fa54ca79a3
Migrate away from deprecated PHPUnit asserts 2019-07-25 10:15:53 -07:00
Adrien Crivelli b2070fd181
Upgrade to phpunit 7.5 2019-07-24 23:45:43 -07:00
Mark Baker 342ffb629b
Refactoring of math trig tests (#1102)
* Merge branch 'master' of C:\Projects\PHPOffice\PHPSpreadsheet\develop with conflicts.

* First pass at moving MathTrig tests into individual test files

* Appeasement to the great goddess PHPCS

* Appeasement to the great goddess PHPCS

* Minor scrutinizer issue resolved

* More refactoring of tests into individual test files fr each math/trig function

* More work on the math/trig test refactoring, plus a bit of tidyup of date/time tests as well

* Fix test

* Fix docblock in test

* Finish refactoring Math/Trig tests into separate files

* Fix SubTotal Test

* Import additional classes for SubTotal test
2019-07-23 00:50:30 +02:00
Mark Baker 9ad6de620e
Refactoring of date time tests (#1101)
* Merge branch 'master' of C:\Projects\PHPOffice\PHPSpreadsheet\develop with conflicts.

* Separate out date/time tests into individual tests

* Need to update the version of phpunit at some point to deal with the new assertions and deprecated assertions

* Appease the CS Gods

* More refactoring of Date/Time tests

* Replace self assertions with instance assertions (looking forward to upgrading phpunit)

* Finish refactoring of date/time tests as individual tests

* Test for DateTimeInterface rather than for DateTime

* A few strict comparisons

* Fix to test names
2019-07-21 20:55:41 +02:00
Mark Baker 554684720d
Statistical issues (#1098)
* Merge branch 'master' of C:\Projects\PHPOffice\PHPSpreadsheet\develop with conflicts.

* Adjusted logic for COUNT() function to handle differences in EXCEL, GNUMERIC and OPENOFFICE modes for cells and for literal values

* Fix case-sensitivity in filenames

* Appeasing Codesniffer

* Resolve COUNTA() differences between cell values and literals

* Style fixes

* Start refactoring statistical function tests into individual tests rather than having a single, giant test for all statistical functions.... first step toward doing this for all tests

* More refactoring into separate tests
If all functions have their own individual test files, it should be a lot easier to identify which functions aren't covered by tests yet

* Missing last lines in files
2019-07-20 18:40:05 +02:00
Mark Baker a367f35438
Trend function unit tests (#1089)
* Merge branch 'master' of C:\Projects\PHPOffice\PHPSpreadsheet\develop with conflicts.

* More trend function unit tests

* Yet more trend function unit tests
2019-07-16 23:51:48 +02:00
Mark Baker 6d739f1fe6
Additional statistical work (#1088)
* Merge branch 'master' of C:\Projects\PHPOffice\PHPSpreadsheet\develop with conflicts.

* More statistical tests

* Further statistical tests

* Unit tests for some of the trend functions

* resolve scrutiniser objections

* Fix order of @return types :-(
2019-07-16 20:35:48 +02:00
Mark Baker f1e82a212f
Extended unit tests (#1087)
* Merge branch 'master' of C:\Projects\PHPOffice\PHPSpreadsheet\develop with conflicts.

* Additional unit tests for average functions, and fix to AVERAGEIF() function if third argument is passed

* Update change log

* Stricter typed comparisons in AVERAGEIF() conditions

* Unit tests for BETADIST() and BETAINV()
2019-07-16 16:18:42 +02:00
Mark Baker a91acec5d9
Countif strict comparison (#1078)
* Stricter-typed comparison testing in COUNTIF() and COUNTIFS() evaluation [Issue #1046](https://github.com/PHPOffice/PhpSpreadsheet/issues/1046)

* Codestyle

* Codestyle

* Codestyle in tests
2019-07-14 16:22:31 +02:00
Zdeněk Drahoš 42fc71f314 Calculation/Statistical :: Add MAXIFS, MINIFS, COUNTIFS and Remove MINIF, MAXIF (#1059)
* #1056 - replace invalid minif/maxif functions by not implemented minifs/maxifs

minif/maxif is not support in Excel, Google Spreadsheets, Libreoffice
https://support.office.com/en-us/article/excel-functions-alphabetical-b3944572-255d-4efb-bb96-c6d90033e188#bm13

* #1056 - implement minifs/maxifs

Copy-pasted sumifs...
https://github.com/PHPOffice/PhpSpreadsheet/blob/1.8.1/src/PhpSpreadsheet/Calculation/MathTrig.php#L1254

* #1056 - implement countifs

* #1056 - fix code style

composer check
composer fix

* #1056 - update changelog
2019-07-14 12:55:42 +02:00
Mark Baker 0ea97f14e1
Fixes to coupon functions (#1068)
* New Unit Tests for COUPNUM()

* COUPNUM should not return zero when settlement is in the last period

* Additional tests and fixes for COUPNCD() and COUPPCD() functions
2019-07-10 21:22:16 +02:00
Yigit Cukuren cce6e5976f Calculation :: Added switch function (#983) 2019-05-30 09:14:58 +02:00
Mark Baker 033ed16db5
Dde call safe handling (#891)
* Set handler for quoted text cells and DDE expressions in the Calculation engine
2019-02-18 22:56:32 +01:00
Fräntz Miccoli db2621c4fe
Add tests for the LOOKUP function
We were performing operations to patch for missing $result_vector
even when one was defined, this was causing bugs on edge cases.

Fixes #796
Closes #816
2018-12-15 16:23:45 +11:00
Mark Baker a5eb64c77f
Matrix (#790)
* Refactor Excel Matrix functions to use external Matrix library rather than JAMA
2018-11-29 22:25:31 +01:00
Adrien Crivelli 2fce5c4706
Update PHP dependencies to fix security issues
This fix CVE-2013-5958 and also
1861e33fe0
2018-11-11 18:21:31 +11:00
marcusblevin 98d10475f2
SUMIFS sum values only once
Values were summed multiple times if it matched several conditions
whereas it should only be summed once.

Fixes #704
Fixes #710
2018-10-28 13:09:08 +11:00
Adrien Crivelli 09eb05f367
OFFSET should allow omitted height and width
Commit 8dddf56 inadvertently removed the ability to omit the width
and height arguments to the OFFSET function. And #REF! is returned
because the function is validating that the new $pCell argument
is present. It is present, but it has been passed in the $height position.

We fixed this by always passing $pCell at the last position and filling
missing arguments with NULL values.

Fixes #561
Fixes #565
2018-10-21 17:45:02 +11:00
Biser Antonov 2c981e47a1
Added the DAYS() function
https://support.office.com/en-us/article/days-function-57740535-d549-4395-8728-0f07bff0b9df
2018-10-21 15:26:46 +11:00
Scorty ae9dd13aa0 Skip non numeric value in SUMIF
MS Excel skip non numeric values also. PhpSpreadsheet used to fail on string value with: Warning: A non-numeric value encountered.

Fixes  #618
2018-10-07 17:24:23 +11:00
Mark Baker 1b96c95a44
Add new Complex Number Functions introduced in MS Excel 2013 (#601)
* - Refactored Complex Engineering Functions to use external complex number library
- Added calculation engine support for the new complex number functions that were added in MS Excel 2013
    - IMCOSH()  Returns the hyperbolic cosine of a complex number
    - IMCOT()   Returns the cotangent of a complex number
    - IMCSC()   Returns the cosecant of a complex number
    - IMCSCH()  Returns the hyperbolic cosecant of a complex number
    - IMSEC()   Returns the secant of a complex number
    - IMSECH()  Returns the hyperbolic secant of a complex number
    - IMSINH()  Returns the hyperbolic sine of a complex number
    - IMTAN()   Returns the tangent of a complex number
* Simplified the parseComplex() method in the PhpOffice\PhpSpreadsheet\Calculation\Engineering class, using Complex\Complex; and docblock flagged as deprecated
2018-07-25 14:38:44 +01:00
Mark Baker 67cdee6033
Add new Bitwise Functions introduced in MS Excel 2013 (#603)
* - Added calculation engine support for the new bitwise functions that were added in MS Excel 2013
  - BITAND()     Returns a Bitwise 'And' of two numbers
  - BITOR()      Returns a Bitwise 'Or' of two number
  - BITXOR()     Returns a Bitwise 'Exclusive Or' of two numbers
  - BITLSHIFT()  Returns a number shifted left by a specified number of bits
  - BITRSHIFT()  Returns a number shifted right by a specified number of bits
2018-07-22 22:16:34 +01:00
Mark Baker 9b44cf3418
Add further new Functions introduced in MS Excel 2013 and 2016 (#608)
- Fix ISFORMULA() function to work with a cell reference to another worksheet
 - Added calculation engine support for the new functions that were added in MS Excel 2013 and MS Excel 2016
   - Text Functions
     - CONCAT()     Synonym for CONCATENATE()
     - NUMBERVALUE()  Converts text to a number, in a locale-independent way
     - UNICHAR()    Synonym for CHAR() in PHPSpreadsheet, which has always used UTF-8 internally
     - UNIORD()     Synonym for ORD() in PHPSpreadsheet, which has always used UTF-8 internally
     - TEXTJOIN()   Joins together two or more text strings, separated by a delimiter
   - Logical Functions
     - XOR()        Returns a logical Exclusive Or of all arguments
   - Date/Time Functions
     - ISOWEEKNUM()  Returns the ISO 8601 week number of the year for a given date
   - Lookup and Reference Functions
     - FORMULATEXT()  Returns a formula as a string
   - Engineering Functions
     - ERF.PRECISE()   Returns the error function integrated between 0 and a supplied limit
     - ERFC.PRECISE()  Synonym for ERFC
   - Math and Trig Functions
     - SEC()          Returns the secant of an angle
     - SECH()         Returns the hyperbolic secant of an angle
     - CSC()          Returns the cosecant of an angle
     - CSCH()         Returns the hyperbolic cosecant of an angle
     - COT()          Returns the cotangent of an angle
     - COTH()         Returns the hyperbolic cotangent of an angle
     - ACOT()         Returns the cotangent of an angle
     - ACOTH()        Returns the hyperbolic cotangent of an angle
  - Financial Functions
    - PDURATION()    Calculates the number of periods required for an investment to reach a specified value
    - RRI()          Calculates the interest rate required for an investment to grow to a specified future value
2018-07-22 19:17:04 +01:00
Rolands Usāns eb31899225 Function EXACT(arg1, arg2) support (#595) 2018-07-15 11:56:25 +09:00
Bill Blume e3fb160f5f
Fixed parsing of conditionals in COUNTIF functions
Conditional operators in the selection parameter of COUNTIF
functions were not being parsed properly, causing evaluations
of formulae with such functions to sometimes fail.

Fixes #526
Closes #528
2018-06-10 14:25:33 +09:00
Adrien Crivelli 064076ac6d
Fix unit tests for PHP 5.6 2018-05-07 11:53:55 +09:00
MarkBaker bbe11eed37 Full unit tests for SUBTOTAL function 2018-05-06 23:43:02 +01:00