Continue MathTrig Breakup - Problem Children (#1954)

Continuing the process of breaking MathTrip.php up into smaller classes. This round takes care of all functions which might be an impediment to installing due to either uncovered code or "complexity":
- BASE
- FACT
- LCM
- MDETERM, MINVERSE, MMULT
- MULTINOMIAL
- PRODUCT
- QUOTIENT
- SERIESSUM
- SUM
- SUMPRODUCT

MathTrig and the members in directory MathTrig are now 100% covered. Many tests have been added, and some edge-case bugs are corrected. Some cases where PhpSpreadsheet had rejected numeric values stored as strings have been changed to accept them whenever Excel does; there had been no tests for that condition.

Boolean arguments are now accepted as arguments wherever Excel accpets them. Taking a cue from what has been done in Engineering, the parameter validation now happens in a routine which issues Exceptions for invalid values; this simplifies the code in the functions themselves. Thank you for doing that; I did not foresee how useful that was when I first looked at it.

Consistent with earlier changes of this nature, the versions in the MathTrig class remain, with a doc block indicating deprecation, and a stub call to the new routines.

All tests except for MINVERSE and MMULT are now handled in the context of a spreadsheet rather than a direct call to the calculation function which implements it. PhpSpreadsheet would need to handle dynamic arrays in order to test MINVERSE and MMULT in a spreadsheet context. Implementing that looks like it might be *very* challenging. It is not something I plan to look at, at least not in the near future.

One parsing problem turned up in the test conversion. It is in one of the SUMIF tests. It takes me to an area in Calculation where the comment says "I don't even want to know what you did to get here". It did not show up in the previous incarnation because, by using a direct call, the previous test managed to bypass the parsing. I have confirmed that this problem shows up in earlier releases of PhpSpreadsheet, so the changes in this PR did not cause it - they merely exposed it. I have left the test intact, but marked it "incomplete" for documentation purposes. I have not been able to get a handle on what's going wrong yet. I will probably open an issue on it if I can't resolve it soon. However, the test in question isn't a "real world" issue, and the error wasn't caused by this change, so I see no reason to delay this pending a resolution of the problem.

SUM had an idiosyncratic moment of its own. It had been ignoring non-numeric values, but Excel returns VALUE in that situation. So I changed it and wrote some new tests, which worked, but ... SUMIF uses several levels of indirection to get to SUM, and SUMIF *does* ignore non-numeric values, so a SUMIF test broke. SUM is a really simple function; the most practical approach seemed to be to clone it, with the string-accepting version being used by the Legacy version (which is called by SUMIF), and the non-string-accepting version being used in the Calculation Function table. That seems far easier and more practical than, for instance, adding a boolean parameter to the variable parameter list. As a follow-up, I will change SUMIF to explicitly call the appropriate new version, but I did not want to add that to this already large change.

SUM again - although it was fully covered beforehand, there was not a specific test member for it. There is now.

FACT had been coded to fail Gnumeric requests where the numeric argument has a decimal portion. However, Gnumeric does accept such an argument, and, unlike Excel and ODS, does not truncate it, but returns the result of a Gamma function call instead. This has been corrected.

When LCM included arguments which contained both 0 and a negative number, it returned 0 or NUM, whichever it found first. It is changed to always return NUM in that circumstance, as Excel does.

QUOTIENT had been documented as taking a variadic list of arguments. In fact, it takes exactly 2 - numerator and denominator - and the docblock and signature is fixed, even in the deprecated version.

The SERIESSUM docbock and signature are more accurate, even in the deprecated version. It is changed to ignore nulls, as Excel does, rather than return VALUE, and is one of the routines which previously rejected numbers in string form.

SUBTOTAL tests had used mocking for some reason. These are replaced with normal tests. And SUBTOTAL had a big surprise in store. That part of it which deals with hidden cells cares only whether the row is hidden, and doesn't care about the column's visibility.

I struggled with whether it should be SubTotal or Subtotal. I think the latter is correct, so that's how I proceeded. I don't think there are likely to be any other capitalization controversies.
This commit is contained in:
oleibman 2021-03-26 01:35:30 -07:00 committed by GitHub
parent c380b25d3c
commit 9239b3deca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
88 changed files with 1559 additions and 1378 deletions

View File

@ -358,7 +358,7 @@ class Calculation
],
'BASE' => [
'category' => Category::CATEGORY_MATH_AND_TRIG,
'functionCall' => [MathTrig::class, 'BASE'],
'functionCall' => [MathTrig\Base::class, 'funcBase'],
'argumentCount' => '2,3',
],
'BESSELI' => [
@ -990,7 +990,7 @@ class Calculation
],
'FACT' => [
'category' => Category::CATEGORY_MATH_AND_TRIG,
'functionCall' => [MathTrig::class, 'FACT'],
'functionCall' => [MathTrig\Fact::class, 'funcFact'],
'argumentCount' => '1',
],
'FACTDOUBLE' => [
@ -1536,7 +1536,7 @@ class Calculation
],
'LCM' => [
'category' => Category::CATEGORY_MATH_AND_TRIG,
'functionCall' => [MathTrig::class, 'LCM'],
'functionCall' => [MathTrig\Lcm::class, 'funcLcm'],
'argumentCount' => '1+',
],
'LEFT' => [
@ -1636,7 +1636,7 @@ class Calculation
],
'MDETERM' => [
'category' => Category::CATEGORY_MATH_AND_TRIG,
'functionCall' => [MathTrig::class, 'MDETERM'],
'functionCall' => [MathTrig\MatrixFunctions::class, 'funcMDeterm'],
'argumentCount' => '1',
],
'MDURATION' => [
@ -1686,7 +1686,7 @@ class Calculation
],
'MINVERSE' => [
'category' => Category::CATEGORY_MATH_AND_TRIG,
'functionCall' => [MathTrig::class, 'MINVERSE'],
'functionCall' => [MathTrig\MatrixFunctions::class, 'funcMinverse'],
'argumentCount' => '1',
],
'MIRR' => [
@ -1696,7 +1696,7 @@ class Calculation
],
'MMULT' => [
'category' => Category::CATEGORY_MATH_AND_TRIG,
'functionCall' => [MathTrig::class, 'MMULT'],
'functionCall' => [MathTrig\MatrixFunctions::class, 'funcMMult'],
'argumentCount' => '2',
],
'MOD' => [
@ -1731,7 +1731,7 @@ class Calculation
],
'MULTINOMIAL' => [
'category' => Category::CATEGORY_MATH_AND_TRIG,
'functionCall' => [MathTrig::class, 'MULTINOMIAL'],
'functionCall' => [MathTrig\Multinomial::class, 'funcMultinomial'],
'argumentCount' => '1+',
],
'MUNIT' => [
@ -2003,7 +2003,7 @@ class Calculation
],
'PRODUCT' => [
'category' => Category::CATEGORY_MATH_AND_TRIG,
'functionCall' => [MathTrig::class, 'PRODUCT'],
'functionCall' => [MathTrig\Product::class, 'funcProduct'],
'argumentCount' => '1+',
],
'PROPER' => [
@ -2033,7 +2033,7 @@ class Calculation
],
'QUOTIENT' => [
'category' => Category::CATEGORY_MATH_AND_TRIG,
'functionCall' => [MathTrig::class, 'QUOTIENT'],
'functionCall' => [MathTrig\Quotient::class, 'funcQuotient'],
'argumentCount' => '2',
],
'RADIANS' => [
@ -2305,13 +2305,13 @@ class Calculation
],
'SUBTOTAL' => [
'category' => Category::CATEGORY_MATH_AND_TRIG,
'functionCall' => [MathTrig::class, 'SUBTOTAL'],
'functionCall' => [MathTrig\Subtotal::class, 'funcSubtotal'],
'argumentCount' => '2+',
'passCellReference' => true,
],
'SUM' => [
'category' => Category::CATEGORY_MATH_AND_TRIG,
'functionCall' => [MathTrig::class, 'SUM'],
'functionCall' => [MathTrig\Sum::class, 'funcSumNoStrings'],
'argumentCount' => '1+',
],
'SUMIF' => [
@ -2326,7 +2326,7 @@ class Calculation
],
'SUMPRODUCT' => [
'category' => Category::CATEGORY_MATH_AND_TRIG,
'functionCall' => [MathTrig::class, 'SUMPRODUCT'],
'functionCall' => [MathTrig\SumProduct::class, 'funcSumProduct'],
'argumentCount' => '1+',
],
'SUMSQ' => [

View File

@ -245,7 +245,7 @@ class Database
* the column label in which you specify a condition for the
* column.
*
* @return float
* @return float|string
*/
public static function DPRODUCT($database, $field, $criteria)
{
@ -349,7 +349,7 @@ class Database
* the column label in which you specify a condition for the
* column.
*
* @return float
* @return float|string
*/
public static function DSUM($database, $field, $criteria)
{

View File

@ -29,7 +29,7 @@ class DProduct extends DatabaseAbstract
* the column label in which you specify a condition for the
* column.
*
* @return float
* @return float|string
*/
public static function evaluate($database, $field, $criteria)
{

View File

@ -29,7 +29,7 @@ class DSum extends DatabaseAbstract
* the column label in which you specify a condition for the
* column.
*
* @return float
* @return float|string
*/
public static function evaluate($database, $field, $criteria)
{

View File

@ -3,37 +3,9 @@
namespace PhpOffice\PhpSpreadsheet\Calculation;
use Exception;
use Matrix\Exception as MatrixException;
use Matrix\Matrix;
class MathTrig
{
//
// Private method to return an array of the factors of the input value
//
private static function factors($value)
{
$startVal = floor(sqrt($value));
$factorArray = [];
for ($i = $startVal; $i > 1; --$i) {
if (($value % $i) == 0) {
$factorArray = array_merge($factorArray, self::factors($value / $i));
$factorArray = array_merge($factorArray, self::factors($i));
if ($i <= sqrt($value)) {
break;
}
}
}
if (!empty($factorArray)) {
rsort($factorArray);
return $factorArray;
}
return [(int) $value];
}
private static function strSplit(string $roman): array
{
$rslt = str_split($roman);
@ -153,6 +125,8 @@ class MathTrig
*
* Converts a number into a text representation with the given radix (base).
*
* @Deprecated 2.0.0 Use the funcBase method in the MathTrig\Base class instead
*
* Excel Function:
* BASE(Number, Radix [Min_length])
*
@ -164,29 +138,7 @@ class MathTrig
*/
public static function BASE($number, $radix, $minLength = null)
{
$number = Functions::flattenSingleValue($number);
$radix = Functions::flattenSingleValue($radix);
$minLength = Functions::flattenSingleValue($minLength);
if (is_numeric($number) && is_numeric($radix) && ($minLength === null || is_numeric($minLength))) {
// Truncate to an integer
$number = (int) $number;
$radix = (int) $radix;
$minLength = (int) $minLength;
if ($number < 0 || $number >= 2 ** 53 || $radix < 2 || $radix > 36) {
return Functions::NAN(); // Numeric range constraints
}
$outcome = strtoupper((string) base_convert($number, 10, $radix));
if ($minLength !== null) {
$outcome = str_pad($outcome, $minLength, '0', STR_PAD_LEFT); // String padding
}
return $outcome;
}
return Functions::VALUE();
return MathTrig\Base::funcBase($number, $radix, $minLength);
}
/**
@ -240,7 +192,7 @@ class MathTrig
return Functions::NAN();
}
return round(self::FACT($numObjs) / self::FACT($numObjs - $numInSet)) / self::FACT($numInSet);
return round(MathTrig\Fact::funcFact($numObjs) / MathTrig\Fact::funcFact($numObjs - $numInSet)) / MathTrig\Fact::funcFact($numInSet);
}
return Functions::VALUE();
@ -285,6 +237,8 @@ class MathTrig
* Returns the factorial of a number.
* The factorial of a number is equal to 1*2*3*...* number.
*
* @Deprecated 2.0.0 Use the funcFact method in the MathTrig\Fact class instead
*
* Excel Function:
* FACT(factVal)
*
@ -294,29 +248,7 @@ class MathTrig
*/
public static function FACT($factVal)
{
$factVal = Functions::flattenSingleValue($factVal);
if (is_numeric($factVal)) {
if ($factVal < 0) {
return Functions::NAN();
}
$factLoop = floor($factVal);
if (
(Functions::getCompatibilityMode() == Functions::COMPATIBILITY_GNUMERIC) &&
($factVal > $factLoop)
) {
return Functions::NAN();
}
$factorial = 1;
while ($factLoop > 1) {
$factorial *= $factLoop--;
}
return $factorial;
}
return Functions::VALUE();
return MathTrig\Fact::funcFact($factVal);
}
/**
@ -487,6 +419,8 @@ class MathTrig
* of all integer arguments number1, number2, and so on. Use LCM to add fractions
* with different denominators.
*
* @Deprecated 2.0.0 Use the funcLcm method in the MathTrig\Lcm class instead
*
* Excel Function:
* LCM(number1[,number2[, ...]])
*
@ -496,39 +430,7 @@ class MathTrig
*/
public static function LCM(...$args)
{
$returnValue = 1;
$allPoweredFactors = [];
// Loop through arguments
foreach (Functions::flattenArray($args) as $value) {
if (!is_numeric($value)) {
return Functions::VALUE();
}
if ($value == 0) {
return 0;
} elseif ($value < 0) {
return Functions::NAN();
}
$myFactors = self::factors(floor($value));
$myCountedFactors = array_count_values($myFactors);
$myPoweredFactors = [];
foreach ($myCountedFactors as $myCountedFactor => $myCountedPower) {
$myPoweredFactors[$myCountedFactor] = $myCountedFactor ** $myCountedPower;
}
foreach ($myPoweredFactors as $myPoweredValue => $myPoweredFactor) {
if (isset($allPoweredFactors[$myPoweredValue])) {
if ($allPoweredFactors[$myPoweredValue] < $myPoweredFactor) {
$allPoweredFactors[$myPoweredValue] = $myPoweredFactor;
}
} else {
$allPoweredFactors[$myPoweredValue] = $myPoweredFactor;
}
}
}
foreach ($allPoweredFactors as $allPoweredFactor) {
$returnValue *= (int) $allPoweredFactor;
}
return $returnValue;
return MathTrig\Lcm::funcLcm(...$args);
}
/**
@ -564,6 +466,8 @@ class MathTrig
*
* Returns the matrix determinant of an array.
*
* @Deprecated 2.0.0 Use the funcMDeterm method in the MathTrig\MatrixFuncs class instead
*
* Excel Function:
* MDETERM(array)
*
@ -573,40 +477,7 @@ class MathTrig
*/
public static function MDETERM($matrixValues)
{
$matrixData = [];
if (!is_array($matrixValues)) {
$matrixValues = [[$matrixValues]];
}
$row = $maxColumn = 0;
foreach ($matrixValues as $matrixRow) {
if (!is_array($matrixRow)) {
$matrixRow = [$matrixRow];
}
$column = 0;
foreach ($matrixRow as $matrixCell) {
if ((is_string($matrixCell)) || ($matrixCell === null)) {
return Functions::VALUE();
}
$matrixData[$row][$column] = $matrixCell;
++$column;
}
if ($column > $maxColumn) {
$maxColumn = $column;
}
++$row;
}
$matrix = new Matrix($matrixData);
if (!$matrix->isSquare()) {
return Functions::VALUE();
}
try {
return $matrix->determinant();
} catch (MatrixException $ex) {
return Functions::VALUE();
}
return MathTrig\MatrixFunctions::funcMDeterm($matrixValues);
}
/**
@ -614,6 +485,8 @@ class MathTrig
*
* Returns the inverse matrix for the matrix stored in an array.
*
* @Deprecated 2.0.0 Use the funcMInverse method in the MathTrig\MatrixFuncs class instead
*
* Excel Function:
* MINVERSE(array)
*
@ -623,49 +496,14 @@ class MathTrig
*/
public static function MINVERSE($matrixValues)
{
$matrixData = [];
if (!is_array($matrixValues)) {
$matrixValues = [[$matrixValues]];
}
$row = $maxColumn = 0;
foreach ($matrixValues as $matrixRow) {
if (!is_array($matrixRow)) {
$matrixRow = [$matrixRow];
}
$column = 0;
foreach ($matrixRow as $matrixCell) {
if ((is_string($matrixCell)) || ($matrixCell === null)) {
return Functions::VALUE();
}
$matrixData[$row][$column] = $matrixCell;
++$column;
}
if ($column > $maxColumn) {
$maxColumn = $column;
}
++$row;
}
$matrix = new Matrix($matrixData);
if (!$matrix->isSquare()) {
return Functions::VALUE();
}
if ($matrix->determinant() == 0.0) {
return Functions::NAN();
}
try {
return $matrix->inverse()->toArray();
} catch (MatrixException $ex) {
return Functions::VALUE();
}
return MathTrig\MatrixFunctions::funcMInverse($matrixValues);
}
/**
* MMULT.
*
* @Deprecated 2.0.0 Use the funcMMult method in the MathTrig\MatrixFuncs class instead
*
* @param array $matrixData1 A matrix of values
* @param array $matrixData2 A matrix of values
*
@ -673,56 +511,7 @@ class MathTrig
*/
public static function MMULT($matrixData1, $matrixData2)
{
$matrixAData = $matrixBData = [];
if (!is_array($matrixData1)) {
$matrixData1 = [[$matrixData1]];
}
if (!is_array($matrixData2)) {
$matrixData2 = [[$matrixData2]];
}
try {
$rowA = 0;
foreach ($matrixData1 as $matrixRow) {
if (!is_array($matrixRow)) {
$matrixRow = [$matrixRow];
}
$columnA = 0;
foreach ($matrixRow as $matrixCell) {
if ((!is_numeric($matrixCell)) || ($matrixCell === null)) {
return Functions::VALUE();
}
$matrixAData[$rowA][$columnA] = $matrixCell;
++$columnA;
}
++$rowA;
}
$matrixA = new Matrix($matrixAData);
$rowB = 0;
foreach ($matrixData2 as $matrixRow) {
if (!is_array($matrixRow)) {
$matrixRow = [$matrixRow];
}
$columnB = 0;
foreach ($matrixRow as $matrixCell) {
if ((!is_numeric($matrixCell)) || ($matrixCell === null)) {
return Functions::VALUE();
}
$matrixBData[$rowB][$columnB] = $matrixCell;
++$columnB;
}
++$rowB;
}
$matrixB = new Matrix($matrixBData);
if ($columnA != $rowB) {
return Functions::VALUE();
}
return $matrixA->multiply($matrixB)->toArray();
} catch (MatrixException $ex) {
return Functions::VALUE();
}
return MathTrig\MatrixFunctions::funcMMult($matrixData1, $matrixData2);
}
/**
@ -779,30 +568,7 @@ class MathTrig
*/
public static function MULTINOMIAL(...$args)
{
$summer = 0;
$divisor = 1;
// Loop through arguments
foreach (Functions::flattenArray($args) as $arg) {
// Is it a numeric value?
if (is_numeric($arg)) {
if ($arg < 1) {
return Functions::NAN();
}
$summer += floor($arg);
$divisor *= self::FACT($arg);
} else {
return Functions::VALUE();
}
}
// Return
if ($summer > 0) {
$summer = self::FACT($summer);
return $summer / $divisor;
}
return 0;
return MathTrig\Multinomial::funcMultinomial(...$args);
}
/**
@ -854,36 +620,18 @@ class MathTrig
*
* PRODUCT returns the product of all the values and cells referenced in the argument list.
*
* @Deprecated 2.0.0 Use the funcProduct method in the MathTrig\Product class instead
*
* Excel Function:
* PRODUCT(value1[,value2[, ...]])
*
* @param mixed ...$args Data values
*
* @return float
* @return float|string
*/
public static function PRODUCT(...$args)
{
// Return value
$returnValue = null;
// Loop through arguments
foreach (Functions::flattenArray($args) as $arg) {
// Is it a numeric value?
if ((is_numeric($arg)) && (!is_string($arg))) {
if ($returnValue === null) {
$returnValue = $arg;
} else {
$returnValue *= $arg;
}
}
}
// Return
if ($returnValue === null) {
return 0;
}
return $returnValue;
return MathTrig\Product::funcProduct(...$args);
}
/**
@ -892,36 +640,19 @@ class MathTrig
* QUOTIENT function returns the integer portion of a division. Numerator is the divided number
* and denominator is the divisor.
*
* @Deprecated 2.0.0 Use the funcQuotient method in the MathTrig\Quotient class instead
*
* Excel Function:
* QUOTIENT(value1[,value2[, ...]])
*
* @param mixed ...$args Data values
* @param mixed $numerator
* @param mixed $denominator
*
* @return float
* @return int|string
*/
public static function QUOTIENT(...$args)
public static function QUOTIENT($numerator, $denominator)
{
// Return value
$returnValue = null;
// Loop through arguments
foreach (Functions::flattenArray($args) as $arg) {
// Is it a numeric value?
if ((is_numeric($arg)) && (!is_string($arg))) {
if ($returnValue === null) {
$returnValue = ($arg == 0) ? 0 : $arg;
} else {
if (($returnValue == 0) || ($arg == 0)) {
$returnValue = 0;
} else {
$returnValue /= $arg;
}
}
}
}
// Return
return (int) $returnValue;
return MathTrig\Quotient::funcQuotient($numerator, $denominator);
}
/**
@ -1006,37 +737,18 @@ class MathTrig
*
* Returns the sum of a power series
*
* @param mixed[] $args An array of mixed values for the Data Series
* @Deprecated 2.0.0 Use the funcSeriesSum method in the MathTrig\SeriesSum class instead
*
* @param mixed $x Input value
* @param mixed $n Initial power
* @param mixed $m Step
* @param mixed[] $args An array of coefficients for the Data Series
*
* @return float|string The result, or a string containing an error
*/
public static function SERIESSUM(...$args)
public static function SERIESSUM($x, $n, $m, ...$args)
{
$returnValue = 0;
// Loop through arguments
$aArgs = Functions::flattenArray($args);
$x = array_shift($aArgs);
$n = array_shift($aArgs);
$m = array_shift($aArgs);
if ((is_numeric($x)) && (is_numeric($n)) && (is_numeric($m))) {
// Calculate
$i = 0;
foreach ($aArgs as $arg) {
// Is it a numeric value?
if ((is_numeric($arg)) && (!is_string($arg))) {
$returnValue += $arg * $x ** ($n + ($m * $i++));
} else {
return Functions::VALUE();
}
}
return $returnValue;
}
return Functions::VALUE();
return MathTrig\SeriesSum::funcSeriesSum($x, $n, $m, ...$args);
}
/**
@ -1090,45 +802,13 @@ class MathTrig
return Functions::VALUE();
}
protected static function filterHiddenArgs($cellReference, $args)
{
return array_filter(
$args,
function ($index) use ($cellReference) {
[, $row, $column] = explode('.', $index);
return $cellReference->getWorksheet()->getRowDimension($row)->getVisible() &&
$cellReference->getWorksheet()->getColumnDimension($column)->getVisible();
},
ARRAY_FILTER_USE_KEY
);
}
protected static function filterFormulaArgs($cellReference, $args)
{
return array_filter(
$args,
function ($index) use ($cellReference) {
[, $row, $column] = explode('.', $index);
if ($cellReference->getWorksheet()->cellExists($column . $row)) {
//take this cell out if it contains the SUBTOTAL or AGGREGATE functions in a formula
$isFormula = $cellReference->getWorksheet()->getCell($column . $row)->isFormula();
$cellFormula = !preg_match('/^=.*\b(SUBTOTAL|AGGREGATE)\s*\(/i', $cellReference->getWorksheet()->getCell($column . $row)->getValue());
return !$isFormula || $cellFormula;
}
return true;
},
ARRAY_FILTER_USE_KEY
);
}
/**
* SUBTOTAL.
*
* Returns a subtotal in a list or database.
*
* @Deprecated 2.0.0 Use the funcSubtotal method in the MathTrig\Subtotal class instead
*
* @param int $functionType
* A number 1 to 11 that specifies which function to
* use in calculating subtotals within a range
@ -1142,45 +822,7 @@ class MathTrig
*/
public static function SUBTOTAL($functionType, ...$args)
{
$cellReference = array_pop($args);
$aArgs = Functions::flattenArrayIndexed($args);
$subtotal = Functions::flattenSingleValue($functionType);
// Calculate
if ((is_numeric($subtotal)) && (!is_string($subtotal))) {
if ($subtotal > 100) {
$aArgs = self::filterHiddenArgs($cellReference, $aArgs);
$subtotal -= 100;
}
$aArgs = self::filterFormulaArgs($cellReference, $aArgs);
switch ($subtotal) {
case 1:
return Statistical\Averages::average($aArgs);
case 2:
return Statistical\Counts::COUNT($aArgs);
case 3:
return Statistical\Counts::COUNTA($aArgs);
case 4:
return Statistical\Maximum::MAX($aArgs);
case 5:
return Statistical\Minimum::MIN($aArgs);
case 6:
return self::PRODUCT($aArgs);
case 7:
return Statistical\StandardDeviations::STDEV($aArgs);
case 8:
return Statistical\StandardDeviations::STDEVP($aArgs);
case 9:
return self::SUM($aArgs);
case 10:
return Statistical\Variances::VAR($aArgs);
case 11:
return Statistical\Variances::VARP($aArgs);
}
}
return Functions::VALUE();
return MathTrig\Subtotal::funcSubtotal($functionType, ...$args);
}
/**
@ -1188,28 +830,18 @@ class MathTrig
*
* SUM computes the sum of all the values and cells referenced in the argument list.
*
* @Deprecated 2.0.0 Use the funcSumNoStrings method in the MathTrig\Sum class instead
*
* Excel Function:
* SUM(value1[,value2[, ...]])
*
* @param mixed ...$args Data values
*
* @return float
* @return float|string
*/
public static function SUM(...$args)
{
$returnValue = 0;
// Loop through the arguments
foreach (Functions::flattenArray($args) as $arg) {
// Is it a numeric value?
if ((is_numeric($arg)) && (!is_string($arg))) {
$returnValue += $arg;
} elseif (Functions::isError($arg)) {
return $arg;
}
}
return $returnValue;
return MathTrig\Sum::funcSum(...$args);
}
/**
@ -1229,7 +861,7 @@ class MathTrig
* @param string $criteria the criteria that defines which cells will be summed
* @param mixed $sumRange
*
* @return float
* @return float|string
*/
public static function SUMIF($range, $criteria, $sumRange = [])
{
@ -1251,7 +883,7 @@ class MathTrig
*
* @param mixed $args Data values
*
* @return float
* @return float|string
*/
public static function SUMIFS(...$args)
{
@ -1264,39 +896,15 @@ class MathTrig
* Excel Function:
* SUMPRODUCT(value1[,value2[, ...]])
*
* @Deprecated 2.0.0 Use the funcSumProduct method in the MathTrig\SumProduct class instead
*
* @param mixed ...$args Data values
*
* @return float|string The result, or a string containing an error
*/
public static function SUMPRODUCT(...$args)
{
$arrayList = $args;
$wrkArray = Functions::flattenArray(array_shift($arrayList));
$wrkCellCount = count($wrkArray);
for ($i = 0; $i < $wrkCellCount; ++$i) {
if ((!is_numeric($wrkArray[$i])) || (is_string($wrkArray[$i]))) {
$wrkArray[$i] = 0;
}
}
foreach ($arrayList as $matrixData) {
$array2 = Functions::flattenArray($matrixData);
$count = count($array2);
if ($wrkCellCount != $count) {
return Functions::VALUE();
}
foreach ($array2 as $i => $val) {
if ((!is_numeric($val)) || (is_string($val))) {
$val = 0;
}
$wrkArray[$i] *= $val;
}
}
return array_sum($wrkArray);
return MathTrig\SumProduct::funcSumProduct(...$args);
}
/**

View File

@ -0,0 +1,49 @@
<?php
namespace PhpOffice\PhpSpreadsheet\Calculation\MathTrig;
use Exception;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
class Base
{
/**
* BASE.
*
* Converts a number into a text representation with the given radix (base).
*
* Excel Function:
* BASE(Number, Radix [Min_length])
*
* @param mixed $number expect float
* @param mixed $radix expect float
* @param mixed $minLength expect int or null
*
* @return string the text representation with the given radix (base)
*/
public static function funcBase($number, $radix, $minLength = null)
{
try {
$number = (int) Helpers::validateNumericNullBool($number);
$radix = (int) Helpers::validateNumericNullBool($radix);
} catch (Exception $e) {
return $e->getMessage();
}
$minLength = Functions::flattenSingleValue($minLength);
if ($minLength === null || is_numeric($minLength)) {
if ($number < 0 || $number >= 2 ** 53 || $radix < 2 || $radix > 36) {
return Functions::NAN(); // Numeric range constraints
}
$outcome = strtoupper((string) base_convert($number, 10, $radix));
if ($minLength !== null) {
$outcome = str_pad($outcome, (int) $minLength, '0', STR_PAD_LEFT); // String padding
}
return $outcome;
}
return Functions::VALUE();
}
}

View File

@ -0,0 +1,47 @@
<?php
namespace PhpOffice\PhpSpreadsheet\Calculation\MathTrig;
use Exception;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Calculation\Statistical;
class Fact
{
/**
* FACT.
*
* Returns the factorial of a number.
* The factorial of a number is equal to 1*2*3*...* number.
*
* Excel Function:
* FACT(factVal)
*
* @param float $factVal Factorial Value
*
* @return int|string Factorial, or a string containing an error
*/
public static function funcFact($factVal)
{
try {
$factVal = Helpers::validateNumericNullBool($factVal);
Helpers::validateNotNegative($factVal);
} catch (Exception $e) {
return $e->getMessage();
}
$factLoop = floor($factVal);
if ($factVal > $factLoop) {
if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_GNUMERIC) {
return Statistical::GAMMAFunction($factVal + 1);
}
}
$factorial = 1;
while ($factLoop > 1) {
$factorial *= $factLoop--;
}
return $factorial;
}
}

View File

@ -61,6 +61,34 @@ class Helpers
throw new Exception(Functions::VALUE());
}
/**
* Confirm number >= 0.
*
* @param float|int $number
*/
public static function validateNotNegative($number): void
{
if ($number >= 0) {
return;
}
throw new Exception(Functions::NAN());
}
/**
* Confirm number != 0.
*
* @param float|int $number
*/
public static function validateNotZero($number): void
{
if ($number) {
return;
}
throw new Exception(Functions::DIV0());
}
public static function returnSign(float $number): int
{
return $number ? (($number > 0) ? 1 : -1) : 0;

View File

@ -0,0 +1,95 @@
<?php
namespace PhpOffice\PhpSpreadsheet\Calculation\MathTrig;
use Exception;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
class Lcm
{
//
// Private method to return an array of the factors of the input value
//
private static function factors($value)
{
$startVal = floor(sqrt($value));
$factorArray = [];
for ($i = $startVal; $i > 1; --$i) {
if (($value % $i) == 0) {
$factorArray = array_merge($factorArray, self::factors($value / $i));
$factorArray = array_merge($factorArray, self::factors($i));
if ($i <= sqrt($value)) {
break;
}
}
}
if (!empty($factorArray)) {
rsort($factorArray);
return $factorArray;
}
return [(int) $value];
}
/**
* LCM.
*
* Returns the lowest common multiplier of a series of numbers
* The least common multiple is the smallest positive integer that is a multiple
* of all integer arguments number1, number2, and so on. Use LCM to add fractions
* with different denominators.
*
* Excel Function:
* LCM(number1[,number2[, ...]])
*
* @param mixed ...$args Data values
*
* @return int|string Lowest Common Multiplier, or a string containing an error
*/
public static function funcLcm(...$args)
{
try {
$arrayArgs = [];
$anyZeros = 0;
foreach (Functions::flattenArray($args) as $value1) {
$value = Helpers::validateNumericNullSubstitution($value1, 1);
Helpers::validateNotNegative($value);
$arrayArgs[] = (int) $value;
$anyZeros += (int) !((bool) $value);
}
if ($anyZeros) {
return 0;
}
} catch (Exception $e) {
return $e->getMessage();
}
$returnValue = 1;
$allPoweredFactors = [];
// Loop through arguments
foreach ($arrayArgs as $value) {
$myFactors = self::factors(floor($value));
$myCountedFactors = array_count_values($myFactors);
$myPoweredFactors = [];
foreach ($myCountedFactors as $myCountedFactor => $myCountedPower) {
$myPoweredFactors[$myCountedFactor] = $myCountedFactor ** $myCountedPower;
}
foreach ($myPoweredFactors as $myPoweredValue => $myPoweredFactor) {
if (isset($allPoweredFactors[$myPoweredValue])) {
if ($allPoweredFactors[$myPoweredValue] < $myPoweredFactor) {
$allPoweredFactors[$myPoweredValue] = $myPoweredFactor;
}
} else {
$allPoweredFactors[$myPoweredValue] = $myPoweredFactor;
}
}
}
foreach ($allPoweredFactors as $allPoweredFactor) {
$returnValue *= (int) $allPoweredFactor;
}
return $returnValue;
}
}

View File

@ -0,0 +1,114 @@
<?php
namespace PhpOffice\PhpSpreadsheet\Calculation\MathTrig;
use Exception;
use Matrix\Exception as MatrixException;
use Matrix\Matrix;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
class MatrixFunctions
{
/**
* Convert parameter to matrix.
*
* @param mixed $matrixValues A matrix of values
*/
private static function getMatrix($matrixValues): Matrix
{
$matrixData = [];
if (!is_array($matrixValues)) {
$matrixValues = [[$matrixValues]];
}
$row = 0;
foreach ($matrixValues as $matrixRow) {
if (!is_array($matrixRow)) {
$matrixRow = [$matrixRow];
}
$column = 0;
foreach ($matrixRow as $matrixCell) {
if ((is_string($matrixCell)) || ($matrixCell === null)) {
throw new Exception(Functions::VALUE());
}
$matrixData[$row][$column] = $matrixCell;
++$column;
}
++$row;
}
return new Matrix($matrixData);
}
/**
* MDETERM.
*
* Returns the matrix determinant of an array.
*
* Excel Function:
* MDETERM(array)
*
* @param mixed $matrixValues A matrix of values
*
* @return float|string The result, or a string containing an error
*/
public static function funcMDeterm($matrixValues)
{
try {
$matrix = self::getMatrix($matrixValues);
return $matrix->determinant();
} catch (MatrixException $ex) {
return Functions::VALUE();
} catch (Exception $e) {
return $e->getMessage();
}
}
/**
* MINVERSE.
*
* Returns the inverse matrix for the matrix stored in an array.
*
* Excel Function:
* MINVERSE(array)
*
* @param mixed $matrixValues A matrix of values
*
* @return array|string The result, or a string containing an error
*/
public static function funcMInverse($matrixValues)
{
try {
$matrix = self::getMatrix($matrixValues);
return $matrix->inverse()->toArray();
} catch (MatrixException $e) {
return (strpos($e->getMessage(), 'determinant') === false) ? Functions::VALUE() : Functions::NAN();
} catch (Exception $e) {
return $e->getMessage();
}
}
/**
* MMULT.
*
* @param mixed $matrixData1 A matrix of values
* @param mixed $matrixData2 A matrix of values
*
* @return array|string The result, or a string containing an error
*/
public static function funcMMult($matrixData1, $matrixData2)
{
try {
$matrixA = self::getMatrix($matrixData1);
$matrixB = self::getMatrix($matrixData2);
return $matrixA->multiply($matrixB)->toArray();
} catch (MatrixException $ex) {
return Functions::VALUE();
} catch (Exception $e) {
return $e->getMessage();
}
}
}

View File

@ -0,0 +1,41 @@
<?php
namespace PhpOffice\PhpSpreadsheet\Calculation\MathTrig;
use Exception;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
class Multinomial
{
/**
* MULTINOMIAL.
*
* Returns the ratio of the factorial of a sum of values to the product of factorials.
*
* @param mixed[] $args An array of mixed values for the Data Series
*
* @return float|string The result, or a string containing an error
*/
public static function funcMultinomial(...$args)
{
$summer = 0;
$divisor = 1;
try {
// Loop through arguments
foreach (Functions::flattenArray($args) as $argx) {
$arg = Helpers::validateNumericNullSubstitution($argx, null);
Helpers::validateNotNegative($arg);
$arg = (int) $arg;
$summer += $arg;
$divisor *= Fact::funcFact($arg);
}
} catch (Exception $e) {
return $e->getMessage();
}
$summer = Fact::funcFact($summer);
return $summer / $divisor;
}
}

View File

@ -0,0 +1,47 @@
<?php
namespace PhpOffice\PhpSpreadsheet\Calculation\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
class Product
{
/**
* PRODUCT.
*
* PRODUCT returns the product of all the values and cells referenced in the argument list.
*
* Excel Function:
* PRODUCT(value1[,value2[, ...]])
*
* @param mixed ...$args Data values
*
* @return float|string
*/
public static function funcProduct(...$args)
{
// Return value
$returnValue = null;
// Loop through arguments
foreach (Functions::flattenArray($args) as $arg) {
// Is it a numeric value?
if (is_numeric($arg)) {
if ($returnValue === null) {
$returnValue = $arg;
} else {
$returnValue *= $arg;
}
} else {
return Functions::VALUE();
}
}
// Return
if ($returnValue === null) {
return 0;
}
return $returnValue;
}
}

View File

@ -0,0 +1,35 @@
<?php
namespace PhpOffice\PhpSpreadsheet\Calculation\MathTrig;
use Exception;
class Quotient
{
/**
* QUOTIENT.
*
* QUOTIENT function returns the integer portion of a division. Numerator is the divided number
* and denominator is the divisor.
*
* Excel Function:
* QUOTIENT(value1,value2)
*
* @param mixed $numerator Expect float|int
* @param mixed $denominator Expect float|int
*
* @return int|string
*/
public static function funcQuotient($numerator, $denominator)
{
try {
$numerator = Helpers::validateNumericNullSubstitution($numerator, 0);
$denominator = Helpers::validateNumericNullSubstitution($denominator, 0);
Helpers::validateNotZero($denominator);
} catch (Exception $e) {
return $e->getMessage();
}
return (int) ($numerator / $denominator);
}
}

View File

@ -0,0 +1,46 @@
<?php
namespace PhpOffice\PhpSpreadsheet\Calculation\MathTrig;
use Exception;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
class SeriesSum
{
/**
* SERIESSUM.
*
* Returns the sum of a power series
*
* @param mixed $x Input value
* @param mixed $n Initial power
* @param mixed $m Step
* @param mixed[] $args An array of coefficients for the Data Series
*
* @return float|string The result, or a string containing an error
*/
public static function funcSeriesSum($x, $n, $m, ...$args)
{
try {
$x = Helpers::validateNumericNullSubstitution($x, 0);
$n = Helpers::validateNumericNullSubstitution($n, 0);
$m = Helpers::validateNumericNullSubstitution($m, 0);
// Loop through arguments
$aArgs = Functions::flattenArray($args);
$returnValue = 0;
$i = 0;
foreach ($aArgs as $argx) {
if ($argx !== null) {
$arg = Helpers::validateNumericNullSubstitution($argx, 0);
$returnValue += $arg * $x ** ($n + ($m * $i));
++$i;
}
}
} catch (Exception $e) {
return $e->getMessage();
}
return $returnValue;
}
}

View File

@ -0,0 +1,99 @@
<?php
namespace PhpOffice\PhpSpreadsheet\Calculation\MathTrig;
use Exception;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Calculation\Statistical;
class Subtotal
{
protected static function filterHiddenArgs($cellReference, $args)
{
return array_filter(
$args,
function ($index) use ($cellReference) {
[, $row, ] = explode('.', $index);
return $cellReference->getWorksheet()->getRowDimension($row)->getVisible();
},
ARRAY_FILTER_USE_KEY
);
}
protected static function filterFormulaArgs($cellReference, $args)
{
return array_filter(
$args,
function ($index) use ($cellReference) {
[, $row, $column] = explode('.', $index);
$retVal = true;
if ($cellReference->getWorksheet()->cellExists($column . $row)) {
//take this cell out if it contains the SUBTOTAL or AGGREGATE functions in a formula
$isFormula = $cellReference->getWorksheet()->getCell($column . $row)->isFormula();
$cellFormula = !preg_match('/^=.*\b(SUBTOTAL|AGGREGATE)\s*\(/i', $cellReference->getWorksheet()->getCell($column . $row)->getValue());
$retVal = !$isFormula || $cellFormula;
}
return $retVal;
},
ARRAY_FILTER_USE_KEY
);
}
private const CALL_FUNCTIONS = [
1 => [Statistical\Averages::class, 'AVERAGE'],
[Statistical\Counts::class, 'COUNT'], // 2
[Statistical\Counts::class, 'COUNTA'], // 3
[Statistical\Maximum::class, 'MAX'], // 4
[Statistical\Minimum::class, 'MIN'], // 5
[Product::class, 'funcProduct'], // 6
[Statistical\StandardDeviations::class, 'STDEV'], // 7
[Statistical\StandardDeviations::class, 'STDEVP'], // 8
[Sum::class, 'funcSum'], // 9
[Statistical\Variances::class, 'VAR'], // 10
[Statistical\Variances::class, 'VARP'], // 11
];
/**
* SUBTOTAL.
*
* Returns a subtotal in a list or database.
*
* @param mixed $functionType
* A number 1 to 11 that specifies which function to
* use in calculating subtotals within a range
* list
* Numbers 101 to 111 shadow the functions of 1 to 11
* but ignore any values in the range that are
* in hidden rows or columns
* @param mixed[] $args A mixed data series of values
*
* @return float|string
*/
public static function funcSubtotal($functionType, ...$args)
{
$cellReference = array_pop($args);
$aArgs = Functions::flattenArrayIndexed($args);
try {
$subtotal = (int) Helpers::validateNumericNullBool($functionType);
} catch (Exception $e) {
return $e->getMessage();
}
// Calculate
if ($subtotal > 100) {
$aArgs = self::filterHiddenArgs($cellReference, $aArgs);
$subtotal -= 100;
}
$aArgs = self::filterFormulaArgs($cellReference, $aArgs);
if (array_key_exists($subtotal, self::CALL_FUNCTIONS)) {
return call_user_func_array(self::CALL_FUNCTIONS[$subtotal], $aArgs);
}
return Functions::VALUE();
}
}

View File

@ -0,0 +1,68 @@
<?php
namespace PhpOffice\PhpSpreadsheet\Calculation\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
class Sum
{
/**
* SUM, ignoring non-numeric non-error strings. This is eventually used by SUMIF.
*
* SUM computes the sum of all the values and cells referenced in the argument list.
*
* Excel Function:
* SUM(value1[,value2[, ...]])
*
* @param mixed ...$args Data values
*
* @return float|string
*/
public static function funcSum(...$args)
{
$returnValue = 0;
// Loop through the arguments
foreach (Functions::flattenArray($args) as $arg) {
// Is it a numeric value?
if (is_numeric($arg)) {
$returnValue += $arg;
} elseif (Functions::isError($arg)) {
return $arg;
}
}
return $returnValue;
}
/**
* SUM, returning error for non-numeric strings. This is used by Excel SUM function.
*
* SUM computes the sum of all the values and cells referenced in the argument list.
*
* Excel Function:
* SUM(value1[,value2[, ...]])
*
* @param mixed ...$args Data values
*
* @return float|string
*/
public static function funcSumNoStrings(...$args)
{
$returnValue = 0;
// Loop through the arguments
foreach (Functions::flattenArray($args) as $arg) {
// Is it a numeric value?
if (is_numeric($arg)) {
$returnValue += $arg;
} elseif (Functions::isError($arg)) {
return $arg;
} else {
return Functions::VALUE();
}
}
return $returnValue;
}
}

View File

@ -0,0 +1,49 @@
<?php
namespace PhpOffice\PhpSpreadsheet\Calculation\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
class SumProduct
{
/**
* SUMPRODUCT.
*
* Excel Function:
* SUMPRODUCT(value1[,value2[, ...]])
*
* @param mixed ...$args Data values
*
* @return float|string The result, or a string containing an error
*/
public static function funcSumProduct(...$args)
{
$arrayList = $args;
$wrkArray = Functions::flattenArray(array_shift($arrayList));
$wrkCellCount = count($wrkArray);
for ($i = 0; $i < $wrkCellCount; ++$i) {
if ((!is_numeric($wrkArray[$i])) || (is_string($wrkArray[$i]))) {
$wrkArray[$i] = 0;
}
}
foreach ($arrayList as $matrixData) {
$array2 = Functions::flattenArray($matrixData);
$count = count($array2);
if ($wrkCellCount != $count) {
return Functions::VALUE();
}
foreach ($array2 as $i => $val) {
if ((!is_numeric($val)) || (is_string($val))) {
$val = 0;
}
$wrkArray[$i] *= $val;
}
}
return array_sum($wrkArray);
}
}

View File

@ -178,7 +178,7 @@ class Conditional
* @param mixed $sumRange
* @param mixed $condition
*
* @return float
* @return float|string
*/
public static function SUMIF($range, $condition, $sumRange = [])
{

View File

@ -2,11 +2,7 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PHPUnit\Framework\TestCase;
class AcosTest extends TestCase
class AcosTest extends AllSetupTeardown
{
/**
* @dataProvider providerAcos
@ -15,11 +11,8 @@ class AcosTest extends TestCase
*/
public function testAcos($expectedResult, string $formula): void
{
if ($expectedResult === 'exception') {
$this->expectException(CalcExp::class);
}
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
$sheet->getCell('A2')->setValue(0.5);
$sheet->getCell('A1')->setValue("=ACOS($formula)");
$result = $sheet->getCell('A1')->getCalculatedValue();

View File

@ -2,11 +2,7 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PHPUnit\Framework\TestCase;
class AcoshTest extends TestCase
class AcoshTest extends AllSetupTeardown
{
/**
* @dataProvider providerAcosh
@ -15,11 +11,8 @@ class AcoshTest extends TestCase
*/
public function testAcosh($expectedResult, string $formula): void
{
if ($expectedResult === 'exception') {
$this->expectException(CalcExp::class);
}
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
$sheet->getCell('A2')->setValue('1.5');
$sheet->getCell('A1')->setValue("=ACOSH($formula)");
$result = $sheet->getCell('A1')->getCalculatedValue();

View File

@ -2,11 +2,7 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PHPUnit\Framework\TestCase;
class AcotTest extends TestCase
class AcotTest extends AllSetupTeardown
{
/**
* @dataProvider providerACOT
@ -16,11 +12,8 @@ class AcotTest extends TestCase
*/
public function testACOT($expectedResult, $number): void
{
if ($expectedResult === 'exception') {
$this->expectException(CalcExp::class);
}
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
$sheet->setCellValue('A2', 1.3);
$sheet->setCellValue('A3', 2.7);
$sheet->setCellValue('A4', -3.8);

View File

@ -2,11 +2,7 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PHPUnit\Framework\TestCase;
class AcothTest extends TestCase
class AcothTest extends AllSetupTeardown
{
/**
* @dataProvider providerACOTH
@ -16,11 +12,8 @@ class AcothTest extends TestCase
*/
public function testACOTH($expectedResult, $number): void
{
if ($expectedResult === 'exception') {
$this->expectException(CalcExp::class);
}
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
$sheet->setCellValue('A2', 1.3);
$sheet->setCellValue('A3', 2.7);
$sheet->setCellValue('A4', -3.8);

View File

@ -0,0 +1,52 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcException;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PHPUnit\Framework\TestCase;
class AllSetupTeardown extends TestCase
{
protected $compatibilityMode;
protected $spreadsheet;
protected $sheet;
protected function setUp(): void
{
$this->compatibilityMode = Functions::getCompatibilityMode();
$this->spreadsheet = new Spreadsheet();
$this->sheet = $this->spreadsheet->getActiveSheet();
}
protected function tearDown(): void
{
Functions::setCompatibilityMode($this->compatibilityMode);
$this->spreadsheet->disconnectWorksheets();
$this->spreadsheet = null;
$this->sheet = null;
}
protected static function setOpenOffice(): void
{
Functions::setCompatibilityMode(Functions::COMPATIBILITY_OPENOFFICE);
}
protected static function setGnumeric(): void
{
Functions::setCompatibilityMode(Functions::COMPATIBILITY_GNUMERIC);
}
/**
* @param mixed $expectedResult
*/
protected function mightHaveException($expectedResult): void
{
if ($expectedResult === 'exception') {
$this->expectException(CalcException::class);
}
}
}

View File

@ -2,11 +2,7 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PHPUnit\Framework\TestCase;
class AsinTest extends TestCase
class AsinTest extends AllSetupTeardown
{
/**
* @dataProvider providerAsin
@ -15,11 +11,8 @@ class AsinTest extends TestCase
*/
public function testAsin($expectedResult, string $formula): void
{
if ($expectedResult === 'exception') {
$this->expectException(CalcExp::class);
}
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
$sheet->getCell('A2')->setValue(0.5);
$sheet->getCell('A1')->setValue("=ASIN($formula)");
$result = $sheet->getCell('A1')->getCalculatedValue();

View File

@ -2,11 +2,7 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PHPUnit\Framework\TestCase;
class AsinhTest extends TestCase
class AsinhTest extends AllSetupTeardown
{
/**
* @dataProvider providerAsinh
@ -15,11 +11,8 @@ class AsinhTest extends TestCase
*/
public function testAsinh($expectedResult, string $formula): void
{
if ($expectedResult === 'exception') {
$this->expectException(CalcExp::class);
}
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
$sheet->getCell('A2')->setValue(0.5);
$sheet->getCell('A1')->setValue("=ASINH($formula)");
$result = $sheet->getCell('A1')->getCalculatedValue();

View File

@ -2,11 +2,7 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PHPUnit\Framework\TestCase;
class Atan2Test extends TestCase
class Atan2Test extends AllSetupTeardown
{
/**
* @dataProvider providerATAN2
@ -15,11 +11,8 @@ class Atan2Test extends TestCase
*/
public function testATAN2($expectedResult, string $formula): void
{
if ($expectedResult === 'exception') {
$this->expectException(CalcExp::class);
}
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
$sheet->getCell('A2')->setValue(5);
$sheet->getCell('A3')->setValue(6);
$sheet->getCell('A1')->setValue("=ATAN2($formula)");

View File

@ -2,11 +2,7 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PHPUnit\Framework\TestCase;
class AtanTest extends TestCase
class AtanTest extends AllSetupTeardown
{
/**
* @dataProvider providerAtan
@ -15,11 +11,8 @@ class AtanTest extends TestCase
*/
public function testAtan($expectedResult, string $formula): void
{
if ($expectedResult === 'exception') {
$this->expectException(CalcExp::class);
}
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
$sheet->getCell('A2')->setValue(5);
$sheet->getCell('A1')->setValue("=ATAN($formula)");
$result = $sheet->getCell('A1')->getCalculatedValue();

View File

@ -2,11 +2,7 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PHPUnit\Framework\TestCase;
class AtanhTest extends TestCase
class AtanhTest extends AllSetupTeardown
{
/**
* @dataProvider providerAtanh
@ -15,11 +11,8 @@ class AtanhTest extends TestCase
*/
public function testAtanh($expectedResult, string $formula): void
{
if ($expectedResult === 'exception') {
$this->expectException(CalcExp::class);
}
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
$sheet->getCell('A2')->setValue(0.8);
$sheet->getCell('A1')->setValue("=ATANH($formula)");
$result = $sheet->getCell('A1')->getCalculatedValue();

View File

@ -2,25 +2,39 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Calculation\MathTrig;
use PHPUnit\Framework\TestCase;
class BaseTest extends TestCase
class BaseTest extends AllSetupTeardown
{
protected function setUp(): void
{
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
}
/**
* @dataProvider providerBASE
*
* @param mixed $expectedResult
* @param mixed $arg1
* @param mixed $arg2
* @param mixed $arg3
*/
public function testBASE($expectedResult, ...$args): void
public function testBASE($expectedResult, $arg1 = 'omitted', $arg2 = 'omitted', $arg3 = 'omitted'): void
{
$result = MathTrig::BASE(...$args);
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
if ($arg1 !== null) {
$sheet->getCell('A1')->setValue($arg1);
}
if ($arg2 !== null) {
$sheet->getCell('A2')->setValue($arg2);
}
if ($arg3 !== null) {
$sheet->getCell('A3')->setValue($arg3);
}
if ($arg1 === 'omitted') {
$sheet->getCell('B1')->setValue('=BASE()');
} elseif ($arg2 === 'omitted') {
$sheet->getCell('B1')->setValue('=BASE(A1)');
} elseif ($arg3 === 'omitted') {
$sheet->getCell('B1')->setValue('=BASE(A1, A2)');
} else {
$sheet->getCell('B1')->setValue('=BASE(A1, A2, A3)');
}
$result = $sheet->getCell('B1')->getCalculatedValue();
self::assertEquals($expectedResult, $result);
}

View File

@ -2,11 +2,7 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PHPUnit\Framework\TestCase;
class CeilingMathTest extends TestCase
class CeilingMathTest extends AllSetupTeardown
{
/**
* @dataProvider providerCEILINGMATH
@ -16,11 +12,8 @@ class CeilingMathTest extends TestCase
*/
public function testCEILINGMATH($expectedResult, $formula): void
{
if ($expectedResult === 'exception') {
$this->expectException(CalcExp::class);
}
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
$sheet->setCellValue('A2', 1.3);
$sheet->setCellValue('A3', 2.7);
$sheet->setCellValue('A4', -3.8);

View File

@ -2,11 +2,7 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PHPUnit\Framework\TestCase;
class CeilingPreciseTest extends TestCase
class CeilingPreciseTest extends AllSetupTeardown
{
/**
* @dataProvider providerFLOORPRECISE
@ -16,11 +12,8 @@ class CeilingPreciseTest extends TestCase
*/
public function testCEILINGPRECISE($expectedResult, $formula): void
{
if ($expectedResult === 'exception') {
$this->expectException(CalcExp::class);
}
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
$sheet->setCellValue('A2', 1.3);
$sheet->setCellValue('A3', 2.7);
$sheet->setCellValue('A4', -3.8);

View File

@ -2,26 +2,8 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PHPUnit\Framework\TestCase;
class CeilingTest extends TestCase
class CeilingTest extends AllSetupTeardown
{
private $compatibilityMode;
protected function setUp(): void
{
$this->compatibilityMode = Functions::getCompatibilityMode();
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
}
protected function tearDown(): void
{
Functions::setCompatibilityMode($this->compatibilityMode);
}
/**
* @dataProvider providerCEILING
*
@ -30,11 +12,8 @@ class CeilingTest extends TestCase
*/
public function testCEILING($expectedResult, $formula): void
{
if ($expectedResult === 'exception') {
$this->expectException(CalcExp::class);
}
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
$sheet->setCellValue('A2', 1.3);
$sheet->setCellValue('A3', 2.7);
$sheet->setCellValue('A4', -3.8);
@ -51,9 +30,8 @@ class CeilingTest extends TestCase
public function testCEILINGGnumeric1Arg(): void
{
Functions::setCompatibilityMode(Functions::COMPATIBILITY_GNUMERIC);
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
self::setGnumeric();
$sheet = $this->sheet;
$sheet->getCell('A1')->setValue('=CEILING(5.1)');
$result = $sheet->getCell('A1')->getCalculatedValue();
self::assertEqualsWithDelta(6, $result, 1E-12);
@ -61,20 +39,17 @@ class CeilingTest extends TestCase
public function testCELINGOpenOffice1Arg(): void
{
Functions::setCompatibilityMode(Functions::COMPATIBILITY_OPENOFFICE);
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
self::setOpenOffice();
$sheet = $this->sheet;
$sheet->getCell('A1')->setValue('=CEILING(5.1)');
$result = $sheet->getCell('A1')->getCalculatedValue();
self::assertEqualsWithDelta(6, $result, 1E-12);
}
public function testFLOORExcel1Arg(): void
public function testCEILINGExcel1Arg(): void
{
$this->expectException(CalcExp::class);
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
$this->mightHaveException('exception');
$sheet = $this->sheet;
$sheet->getCell('A1')->setValue('=CEILING(5.1)');
$result = $sheet->getCell('A1')->getCalculatedValue();
self::assertEqualsWithDelta(6, $result, 1E-12);

View File

@ -2,11 +2,7 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PHPUnit\Framework\TestCase;
class CosTest extends TestCase
class CosTest extends AllSetupTeardown
{
/**
* @dataProvider providerCos
@ -15,11 +11,8 @@ class CosTest extends TestCase
*/
public function testCos($expectedResult, string $formula): void
{
if ($expectedResult === 'exception') {
$this->expectException(CalcExp::class);
}
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
$sheet->setCellValue('A2', 2);
$sheet->getCell('A1')->setValue("=COS($formula)");
$result = $sheet->getCell('A1')->getCalculatedValue();

View File

@ -2,11 +2,7 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PHPUnit\Framework\TestCase;
class CoshTest extends TestCase
class CoshTest extends AllSetupTeardown
{
/**
* @dataProvider providerCosh
@ -15,11 +11,8 @@ class CoshTest extends TestCase
*/
public function testCosh($expectedResult, string $formula): void
{
if ($expectedResult === 'exception') {
$this->expectException(CalcExp::class);
}
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
$sheet->setCellValue('A2', 2);
$sheet->getCell('A1')->setValue("=COSH($formula)");
$result = $sheet->getCell('A1')->getCalculatedValue();

View File

@ -2,11 +2,7 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PHPUnit\Framework\TestCase;
class CotTest extends TestCase
class CotTest extends AllSetupTeardown
{
/**
* @dataProvider providerCOT
@ -16,11 +12,8 @@ class CotTest extends TestCase
*/
public function testCOT($expectedResult, $angle): void
{
if ($expectedResult === 'exception') {
$this->expectException(CalcExp::class);
}
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
$sheet->setCellValue('A2', 1.3);
$sheet->setCellValue('A3', 2.7);
$sheet->setCellValue('A4', -3.8);

View File

@ -2,11 +2,7 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PHPUnit\Framework\TestCase;
class CothTest extends TestCase
class CothTest extends AllSetupTeardown
{
/**
* @dataProvider providerCOTH
@ -16,11 +12,8 @@ class CothTest extends TestCase
*/
public function testCOTH($expectedResult, $angle): void
{
if ($expectedResult === 'exception') {
$this->expectException(CalcExp::class);
}
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
$sheet->setCellValue('A2', 1.3);
$sheet->setCellValue('A3', 2.7);
$sheet->setCellValue('A4', -3.8);

View File

@ -2,11 +2,7 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PHPUnit\Framework\TestCase;
class CscTest extends TestCase
class CscTest extends AllSetupTeardown
{
/**
* @dataProvider providerCSC
@ -16,11 +12,8 @@ class CscTest extends TestCase
*/
public function testCSC($expectedResult, $angle): void
{
if ($expectedResult === 'exception') {
$this->expectException(CalcExp::class);
}
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
$sheet->setCellValue('A2', 1.3);
$sheet->setCellValue('A3', 2.7);
$sheet->setCellValue('A4', -3.8);

View File

@ -2,11 +2,7 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PHPUnit\Framework\TestCase;
class CschTest extends TestCase
class CschTest extends AllSetupTeardown
{
/**
* @dataProvider providerCSCH
@ -16,11 +12,8 @@ class CschTest extends TestCase
*/
public function testCSCH($expectedResult, $angle): void
{
if ($expectedResult === 'exception') {
$this->expectException(CalcExp::class);
}
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
$sheet->setCellValue('A2', 1.3);
$sheet->setCellValue('A3', 2.7);
$sheet->setCellValue('A4', -3.8);

View File

@ -2,11 +2,7 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PHPUnit\Framework\TestCase;
class EvenTest extends TestCase
class EvenTest extends AllSetupTeardown
{
/**
* @dataProvider providerEVEN
@ -16,11 +12,8 @@ class EvenTest extends TestCase
*/
public function testEVEN($expectedResult, $value): void
{
if ($expectedResult === 'exception') {
$this->expectException(CalcExp::class);
}
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
$sheet->getCell('A1')->setValue("=EVEN($value)");
$sheet->getCell('A2')->setValue(3.7);
self::assertEquals($expectedResult, $sheet->getCell('A1')->getCalculatedValue());

View File

@ -2,31 +2,60 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Calculation\MathTrig;
use PHPUnit\Framework\TestCase;
class FactTest extends TestCase
class FactTest extends AllSetupTeardown
{
protected function setUp(): void
{
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
}
/**
* @dataProvider providerFACT
*
* @param mixed $expectedResult
* @param $value
* @param mixed $arg1
*/
public function testFACT($expectedResult, $value): void
public function testFACT($expectedResult, $arg1): void
{
$result = MathTrig::FACT($value);
self::assertEqualsWithDelta($expectedResult, $result, 1E-12);
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
if ($arg1 !== null) {
$sheet->getCell('A1')->setValue($arg1);
}
if ($arg1 === 'omitted') {
$sheet->getCell('B1')->setValue('=FACT()');
} else {
$sheet->getCell('B1')->setValue('=FACT(A1)');
}
$result = $sheet->getCell('B1')->getCalculatedValue();
self::assertEquals($expectedResult, $result);
}
public function providerFACT()
{
return require 'tests/data/Calculation/MathTrig/FACT.php';
}
/**
* @dataProvider providerFACTGnumeric
*
* @param mixed $expectedResult
* @param mixed $arg1
*/
public function testFACTGnumeric($expectedResult, $arg1): void
{
$this->mightHaveException($expectedResult);
self::setGnumeric();
$sheet = $this->sheet;
if ($arg1 !== null) {
$sheet->getCell('A1')->setValue($arg1);
}
if ($arg1 === 'omitted') {
$sheet->getCell('B1')->setValue('=FACT()');
} else {
$sheet->getCell('B1')->setValue('=FACT(A1)');
}
$result = $sheet->getCell('B1')->getCalculatedValue();
self::assertEquals($expectedResult, $result);
}
public function providerFACTGnumeric()
{
return require 'tests/data/Calculation/MathTrig/FACTGNUMERIC.php';
}
}

View File

@ -2,11 +2,7 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PHPUnit\Framework\TestCase;
class FloorMathTest extends TestCase
class FloorMathTest extends AllSetupTeardown
{
/**
* @dataProvider providerFLOORMATH
@ -16,11 +12,8 @@ class FloorMathTest extends TestCase
*/
public function testFLOORMATH($expectedResult, $formula): void
{
if ($expectedResult === 'exception') {
$this->expectException(CalcExp::class);
}
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
$sheet->setCellValue('A2', 1.3);
$sheet->setCellValue('A3', 2.7);
$sheet->setCellValue('A4', -3.8);

View File

@ -2,11 +2,7 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PHPUnit\Framework\TestCase;
class FloorPreciseTest extends TestCase
class FloorPreciseTest extends AllSetupTeardown
{
/**
* @dataProvider providerFLOORPRECISE
@ -16,11 +12,8 @@ class FloorPreciseTest extends TestCase
*/
public function testFLOORPRECISE($expectedResult, $formula): void
{
if ($expectedResult === 'exception') {
$this->expectException(CalcExp::class);
}
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
$sheet->setCellValue('A2', 1.3);
$sheet->setCellValue('A3', 2.7);
$sheet->setCellValue('A4', -3.8);

View File

@ -2,26 +2,8 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PHPUnit\Framework\TestCase;
class FloorTest extends TestCase
class FloorTest extends AllSetupTeardown
{
private $compatibilityMode;
protected function setUp(): void
{
$this->compatibilityMode = Functions::getCompatibilityMode();
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
}
protected function tearDown(): void
{
Functions::setCompatibilityMode($this->compatibilityMode);
}
/**
* @dataProvider providerFLOOR
*
@ -30,11 +12,8 @@ class FloorTest extends TestCase
*/
public function testFLOOR($expectedResult, $formula): void
{
if ($expectedResult === 'exception') {
$this->expectException(CalcExp::class);
}
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
$sheet->setCellValue('A2', 1.3);
$sheet->setCellValue('A3', 2.7);
$sheet->setCellValue('A4', -3.8);
@ -51,9 +30,8 @@ class FloorTest extends TestCase
public function testFLOORGnumeric1Arg(): void
{
Functions::setCompatibilityMode(Functions::COMPATIBILITY_GNUMERIC);
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
self::setGnumeric();
$sheet = $this->sheet;
$sheet->getCell('A1')->setValue('=FLOOR(5.1)');
$result = $sheet->getCell('A1')->getCalculatedValue();
self::assertEqualsWithDelta(5, $result, 1E-12);
@ -61,9 +39,8 @@ class FloorTest extends TestCase
public function testFLOOROpenOffice1Arg(): void
{
Functions::setCompatibilityMode(Functions::COMPATIBILITY_OPENOFFICE);
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
self::setOpenOffice();
$sheet = $this->sheet;
$sheet->getCell('A1')->setValue('=FLOOR(5.1)');
$result = $sheet->getCell('A1')->getCalculatedValue();
self::assertEqualsWithDelta(5, $result, 1E-12);
@ -71,10 +48,8 @@ class FloorTest extends TestCase
public function testFLOORExcel1Arg(): void
{
$this->expectException(CalcExp::class);
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
$this->mightHaveException('exception');
$sheet = $this->sheet;
$sheet->getCell('A1')->setValue('=FLOOR(5.1)');
$result = $sheet->getCell('A1')->getCalculatedValue();
self::assertEqualsWithDelta(5, $result, 1E-12);

View File

@ -2,11 +2,7 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PHPUnit\Framework\TestCase;
class IntTest extends TestCase
class IntTest extends AllSetupTeardown
{
/**
* @dataProvider providerINT
@ -16,11 +12,8 @@ class IntTest extends TestCase
*/
public function testINT($expectedResult, $formula): void
{
if ($expectedResult === 'exception') {
$this->expectException(CalcExp::class);
}
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
$sheet->setCellValue('A2', 1.3);
$sheet->setCellValue('A3', 2.7);
$sheet->setCellValue('A4', -3.8);

View File

@ -2,17 +2,8 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Calculation\MathTrig;
use PHPUnit\Framework\TestCase;
class LcmTest extends TestCase
class LcmTest extends AllSetupTeardown
{
protected function setUp(): void
{
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
}
/**
* @dataProvider providerLCM
*
@ -20,7 +11,14 @@ class LcmTest extends TestCase
*/
public function testLCM($expectedResult, ...$args): void
{
$result = MathTrig::LCM(...$args);
$sheet = $this->sheet;
$row = 0;
foreach ($args as $arg) {
++$row;
$sheet->getCell("A$row")->setValue($arg);
}
$sheet->getCell('B1')->setValue("=LCM(A1:A$row)");
$result = $sheet->getCell('B1')->getCalculatedValue();
self::assertEqualsWithDelta($expectedResult, $result, 1E-12);
}

View File

@ -2,17 +2,10 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Calculation\MathTrig;
use PHPUnit\Framework\TestCase;
class MInverseTest extends TestCase
class MInverseTest extends AllSetupTeardown
{
protected function setUp(): void
{
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
}
/**
* @dataProvider providerMINVERSE
*
@ -28,4 +21,12 @@ class MInverseTest extends TestCase
{
return require 'tests/data/Calculation/MathTrig/MINVERSE.php';
}
public function testOnSpreadsheet(): void
{
// very limited ability to test this in the absence of dynamic arrays
$sheet = $this->sheet;
$sheet->getCell('A1')->setValue('=MINVERSE({1,2,3})'); // not square
self::assertSame('#VALUE!', $sheet->getCell('A1')->getCalculatedValue());
}
}

View File

@ -2,17 +2,10 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Calculation\MathTrig;
use PHPUnit\Framework\TestCase;
class MMultTest extends TestCase
class MMultTest extends AllSetupTeardown
{
protected function setUp(): void
{
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
}
/**
* @dataProvider providerMMULT
*
@ -28,4 +21,12 @@ class MMultTest extends TestCase
{
return require 'tests/data/Calculation/MathTrig/MMULT.php';
}
public function testOnSpreadsheet(): void
{
// very limited ability to test this in the absence of dynamic arrays
$sheet = $this->sheet;
$sheet->getCell('A1')->setValue('=MMULT({1,2,3}, {1,2,3})'); // incompatible dimensions
self::assertSame('#VALUE!', $sheet->getCell('A1')->getCalculatedValue());
}
}

View File

@ -2,11 +2,7 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PHPUnit\Framework\TestCase;
class MRoundTest extends TestCase
class MRoundTest extends AllSetupTeardown
{
/**
* @dataProvider providerMROUND
@ -16,11 +12,8 @@ class MRoundTest extends TestCase
*/
public function testMROUND($expectedResult, $formula): void
{
if ($expectedResult === 'exception') {
$this->expectException(CalcExp::class);
}
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
$sheet->setCellValue('A2', 1.3);
$sheet->setCellValue('A3', 2.7);
$sheet->setCellValue('A4', -3.8);

View File

@ -2,25 +2,27 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Calculation\MathTrig;
use PHPUnit\Framework\TestCase;
class MdeTermTest extends TestCase
class MdeTermTest extends AllSetupTeardown
{
protected function setUp(): void
{
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
}
/**
* @dataProvider providerMDETERM
*
* @param mixed $expectedResult
* @param mixed $matrix expect a matrix
*/
public function testMDETERM($expectedResult, ...$args): void
public function testMDETERM2($expectedResult, $matrix): void
{
$result = MathTrig::MDETERM(...$args);
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
if (is_array($matrix)) {
$sheet->fromArray($matrix, null, 'A1', true);
$maxCol = $sheet->getHighestColumn();
$maxRow = $sheet->getHighestRow();
$sheet->getCell('Z1')->setValue("=MDETERM(A1:$maxCol$maxRow)");
} else {
$sheet->getCell('Z1')->setValue("=MDETERM($matrix)");
}
$result = $sheet->getCell('Z1')->getCalculatedValue();
self::assertEqualsWithDelta($expectedResult, $result, 1E-12);
}

View File

@ -25,6 +25,7 @@ class MovedFunctionsTest extends TestCase
self::assertEqualsWithDelta(0, MathTrig::builtinATAN(0), 1E-9);
self::assertEqualsWithDelta(0, MathTrig::builtinATANH(0), 1E-9);
self::assertEqualsWithDelta('#DIV/0!', MathTrig::ATAN2(0, 0), 1E-9);
self::assertEquals('12', MathTrig::BASE(10, 8));
self::assertEquals(-6, MathTrig::CEILING(-4.5, -2));
self::assertEquals(1, MathTrig::builtinCOS(0));
self::assertEquals(1, MathTrig::builtinCOSH(0));
@ -33,20 +34,40 @@ class MovedFunctionsTest extends TestCase
self::assertEquals('#DIV/0!', MathTrig::CSC(0));
self::assertEquals('#DIV/0!', MathTrig::CSCH(0));
self::assertEquals(6, MathTrig::EVEN(4.5));
self::assertEquals(6, MathTrig::FACT(3));
self::assertEquals(-6, MathTrig::FLOOR(-4.5, 2));
self::assertEquals(0.23, MathTrig::FLOORMATH(0.234, 0.01));
self::assertEquals(-4, MathTrig::FLOORPRECISE(-2.5, 2));
self::assertEquals(-9, MathTrig::INT(-8.3));
self::assertEquals(12, MathTrig::LCM(4, 6));
self::assertEquals(1, MathTrig::MDETERM([1]));
self::assertEquals(
[[2, 2], [2, 1]],
MathTrig::MINVERSE([[-0.5, 1.0], [1.0, -1.0]])
);
self::assertEquals(
[[23], [53]],
MathTrig::MMULT([[1, 2], [3, 4]], [[7], [8]])
);
self::assertEquals(6, MathTrig::MROUND(7.3, 3));
self::assertEquals(1, MathTrig::MULTINOMIAL(1));
self::assertEquals(5, MathTrig::ODD(4.5));
self::assertEquals(8, MathTrig::PRODUCT(1, 2, 4));
self::assertEquals(8, MathTrig::QUOTIENT(17, 2));
self::assertEquals('I', MathTrig::ROMAN(1));
self::assertEquals(3.3, MathTrig::builtinROUND(3.27, 1));
self::assertEquals(662, MathTrig::ROUNDDOWN(662.79, 0));
self::assertEquals(663, MathTrig::ROUNDUP(662.79, 0));
self::assertEquals(1, MathTrig::SEC(0));
self::assertEquals(1, MathTrig::SECH(0));
self::assertEquals(3780, MathTrig::SERIESSUM(5, 1, 1, [1, 1, 0, 1, 1]));
self::assertEquals(1, MathTrig::SIGN(79.2));
self::assertEquals(0, MathTrig::builtinSIN(0));
self::assertEquals(0, MathTrig::builtinSINH(0));
self::assertEquals(0, MathTrig::SUBTOTAL(2, [0, 0]));
self::assertEquals(7, MathTrig::SUM(1, 2, 4));
self::assertEquals(4, MathTrig::SUMIF([[2], [4]], '>2'));
self::assertEquals(17, MathTrig::SUMPRODUCT([1, 2, 3], [5, 0, 4]));
self::assertEquals(0, MathTrig::builtinTAN(0));
self::assertEquals(0, MathTrig::builtinTANH(0));
self::assertEquals(70, MathTrig::TRUNC(79.2, -1));

View File

@ -2,17 +2,8 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Calculation\MathTrig;
use PHPUnit\Framework\TestCase;
class MultinomialTest extends TestCase
class MultinomialTest extends AllSetupTeardown
{
protected function setUp(): void
{
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
}
/**
* @dataProvider providerMULTINOMIAL
*
@ -20,7 +11,19 @@ class MultinomialTest extends TestCase
*/
public function testMULTINOMIAL($expectedResult, ...$args): void
{
$result = MathTrig::MULTINOMIAL(...$args);
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
$row = 0;
$excelArg = '';
foreach ($args as $arg) {
++$row;
$excelArg = "A1:A$row";
if ($arg !== null) {
$sheet->getCell("A$row")->setValue($arg);
}
}
$sheet->getCell('B1')->setValue("=MULTINOMIAL($excelArg)");
$result = $sheet->getCell('B1')->getCalculatedValue();
self::assertEqualsWithDelta($expectedResult, $result, 1E-12);
}

View File

@ -2,11 +2,7 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PHPUnit\Framework\TestCase;
class OddTest extends TestCase
class OddTest extends AllSetupTeardown
{
/**
* @dataProvider providerODD
@ -16,11 +12,8 @@ class OddTest extends TestCase
*/
public function testODD($expectedResult, $value): void
{
if ($expectedResult === 'exception') {
$this->expectException(CalcExp::class);
}
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
$sheet->getCell('A1')->setValue("=ODD($value)");
$sheet->getCell('A2')->setValue(3.7);
self::assertEquals($expectedResult, $sheet->getCell('A1')->getCalculatedValue());

View File

@ -2,17 +2,8 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Calculation\MathTrig;
use PHPUnit\Framework\TestCase;
class ProductTest extends TestCase
class ProductTest extends AllSetupTeardown
{
protected function setUp(): void
{
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
}
/**
* @dataProvider providerPRODUCT
*
@ -20,7 +11,14 @@ class ProductTest extends TestCase
*/
public function testPRODUCT($expectedResult, ...$args): void
{
$result = MathTrig::PRODUCT(...$args);
$sheet = $this->sheet;
$row = 0;
foreach ($args as $arg) {
++$row;
$sheet->getCell("A$row")->setValue($arg);
}
$sheet->getCell('B1')->setValue("=PRODUCT(A1:A$row)");
$result = $sheet->getCell('B1')->getCalculatedValue();
self::assertEqualsWithDelta($expectedResult, $result, 1E-12);
}

View File

@ -2,26 +2,34 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Calculation\MathTrig;
use PHPUnit\Framework\TestCase;
class QuotientTest extends TestCase
class QuotientTest extends AllSetupTeardown
{
protected function setUp(): void
{
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
}
/**
* @dataProvider providerQUOTIENT
*
* @param mixed $expectedResult
* @param mixed $arg1
* @param mixed $arg2
*/
public function testQUOTIENT($expectedResult, ...$args): void
public function testQUOTIENT($expectedResult, $arg1 = 'omitted', $arg2 = 'omitted'): void
{
$result = MathTrig::QUOTIENT(...$args);
self::assertEqualsWithDelta($expectedResult, $result, 1E-12);
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
if ($arg1 !== null) {
$sheet->getCell('A1')->setValue($arg1);
}
if ($arg2 !== null) {
$sheet->getCell('A2')->setValue($arg2);
}
if ($arg1 === 'omitted') {
$sheet->getCell('B1')->setValue('=QUOTIENT()');
} elseif ($arg2 === 'omitted') {
$sheet->getCell('B1')->setValue('=QUOTIENT(A1)');
} else {
$sheet->getCell('B1')->setValue('=QUOTIENT(A1, A2)');
}
$result = $sheet->getCell('B1')->getCalculatedValue();
self::assertSame($expectedResult, $result);
}
public function providerQUOTIENT()

View File

@ -2,11 +2,7 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PHPUnit\Framework\TestCase;
class RomanTest extends TestCase
class RomanTest extends AllSetupTeardown
{
/**
* @dataProvider providerROMAN
@ -16,11 +12,8 @@ class RomanTest extends TestCase
*/
public function testROMAN($expectedResult, $formula): void
{
if ($expectedResult === 'exception') {
$this->expectException(CalcExp::class);
}
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
$sheet->setCellValue('A3', 49);
$sheet->getCell('A1')->setValue("=ROMAN($formula)");
$result = $sheet->getCell('A1')->getCalculatedValue();
@ -31,11 +24,4 @@ class RomanTest extends TestCase
{
return require 'tests/data/Calculation/MathTrig/ROMAN.php';
}
// Confirm that deprecated stub left in MathTrig works.
// Delete this test when stub is finally deleted.
public function testDeprecated(): void
{
self::assertEquals('I', \PhpOffice\PhpSpreadsheet\Calculation\MathTrig::ROMAN(1));
}
}

View File

@ -2,11 +2,7 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PHPUnit\Framework\TestCase;
class RoundDownTest extends TestCase
class RoundDownTest extends AllSetupTeardown
{
/**
* @dataProvider providerRoundDown
@ -16,11 +12,8 @@ class RoundDownTest extends TestCase
*/
public function testRoundDown($expectedResult, $formula): void
{
if ($expectedResult === 'exception') {
$this->expectException(CalcExp::class);
}
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
$sheet->setCellValue('A2', 1.3);
$sheet->setCellValue('A3', 2.7);
$sheet->setCellValue('A4', -3.8);

View File

@ -2,11 +2,7 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PHPUnit\Framework\TestCase;
class RoundTest extends TestCase
class RoundTest extends AllSetupTeardown
{
/**
* @dataProvider providerRound
@ -16,11 +12,8 @@ class RoundTest extends TestCase
*/
public function testRound($expectedResult, $formula): void
{
if ($expectedResult === 'exception') {
$this->expectException(CalcExp::class);
}
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
$sheet->setCellValue('A2', 1.3);
$sheet->setCellValue('A3', 2.7);
$sheet->setCellValue('A4', -3.8);

View File

@ -2,11 +2,7 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PHPUnit\Framework\TestCase;
class RoundUpTest extends TestCase
class RoundUpTest extends AllSetupTeardown
{
/**
* @dataProvider providerRoundUp
@ -16,11 +12,8 @@ class RoundUpTest extends TestCase
*/
public function testRoundUp($expectedResult, $formula): void
{
if ($expectedResult === 'exception') {
$this->expectException(CalcExp::class);
}
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
$sheet->setCellValue('A2', 1.3);
$sheet->setCellValue('A3', 2.7);
$sheet->setCellValue('A4', -3.8);

View File

@ -2,11 +2,7 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PHPUnit\Framework\TestCase;
class SecTest extends TestCase
class SecTest extends AllSetupTeardown
{
/**
* @dataProvider providerSEC
@ -16,11 +12,8 @@ class SecTest extends TestCase
*/
public function testSEC($expectedResult, $angle): void
{
if ($expectedResult === 'exception') {
$this->expectException(CalcExp::class);
}
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
$sheet->setCellValue('A2', 1.3);
$sheet->setCellValue('A3', 2.7);
$sheet->setCellValue('A4', -3.8);

View File

@ -2,11 +2,7 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PHPUnit\Framework\TestCase;
class SechTest extends TestCase
class SechTest extends AllSetupTeardown
{
/**
* @dataProvider providerSECH
@ -16,11 +12,8 @@ class SechTest extends TestCase
*/
public function testSECH($expectedResult, $angle): void
{
if ($expectedResult === 'exception') {
$this->expectException(CalcExp::class);
}
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
$sheet->setCellValue('A2', 1.3);
$sheet->setCellValue('A3', 2.7);
$sheet->setCellValue('A4', -3.8);

View File

@ -3,24 +3,39 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Calculation\MathTrig;
use PHPUnit\Framework\TestCase;
class SeriesSumTest extends TestCase
class SeriesSumTest extends AllSetupTeardown
{
protected function setUp(): void
{
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
}
/**
* @dataProvider providerSERIESSUM
*
* @param mixed $expectedResult
* @param mixed $arg1
* @param mixed $arg2
* @param mixed $arg3
*/
public function testSERIESSUM($expectedResult, ...$args): void
public function testSERIESSUM($expectedResult, $arg1, $arg2, $arg3, ...$args): void
{
$result = MathTrig::SERIESSUM(...$args);
$sheet = $this->sheet;
if ($arg1 !== null) {
$sheet->getCell('C1')->setValue($arg1);
}
if ($arg2 !== null) {
$sheet->getCell('C2')->setValue($arg2);
}
if ($arg3 !== null) {
$sheet->getCell('C3')->setValue($arg3);
}
$row = 0;
$aArgs = Functions::flattenArray($args);
foreach ($aArgs as $arg) {
++$row;
if ($arg !== null) {
$sheet->getCell("A$row")->setValue($arg);
}
}
$sheet->getCell('B1')->setValue("=SERIESSUM(C1, C2, C3, A1:A$row)");
$result = $sheet->getCell('B1')->getCalculatedValue();
self::assertEqualsWithDelta($expectedResult, $result, 1E-12);
}

View File

@ -2,11 +2,7 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PHPUnit\Framework\TestCase;
class SignTest extends TestCase
class SignTest extends AllSetupTeardown
{
/**
* @dataProvider providerSIGN
@ -16,11 +12,8 @@ class SignTest extends TestCase
*/
public function testSIGN($expectedResult, $value): void
{
if ($expectedResult === 'exception') {
$this->expectException(CalcExp::class);
}
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
$sheet->setCellValue('A2', 1.3);
$sheet->setCellValue('A3', 0);
$sheet->setCellValue('A4', -3.8);

View File

@ -2,11 +2,7 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PHPUnit\Framework\TestCase;
class SinTest extends TestCase
class SinTest extends AllSetupTeardown
{
/**
* @dataProvider providerSin
@ -15,11 +11,8 @@ class SinTest extends TestCase
*/
public function testSin($expectedResult, string $formula): void
{
if ($expectedResult === 'exception') {
$this->expectException(CalcExp::class);
}
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
$sheet->setCellValue('A2', 2);
$sheet->getCell('A1')->setValue("=SIN($formula)");
$result = $sheet->getCell('A1')->getCalculatedValue();

View File

@ -2,11 +2,7 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PHPUnit\Framework\TestCase;
class SinhTest extends TestCase
class SinhTest extends AllSetupTeardown
{
/**
* @dataProvider providerCosh
@ -15,11 +11,8 @@ class SinhTest extends TestCase
*/
public function testSinh($expectedResult, string $formula): void
{
if ($expectedResult === 'exception') {
$this->expectException(CalcExp::class);
}
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
$sheet->setCellValue('A2', 2);
$sheet->getCell('A1')->setValue("=SINH($formula)");
$result = $sheet->getCell('A1')->getCalculatedValue();

View File

@ -2,53 +2,23 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Calculation\MathTrig;
use PhpOffice\PhpSpreadsheet\Cell\Cell;
use PhpOffice\PhpSpreadsheet\Worksheet\ColumnDimension;
use PhpOffice\PhpSpreadsheet\Worksheet\RowDimension;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
use PHPUnit\Framework\TestCase;
class SubTotalTest extends TestCase
class SubTotalTest extends AllSetupTeardown
{
protected function setUp(): void
{
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
}
/**
* @dataProvider providerSUBTOTAL
*
* @param mixed $expectedResult
* @param mixed $type expect an integer
*/
public function testSUBTOTAL($expectedResult, ...$args): void
public function testSubtotal($expectedResult, $type): void
{
$cell = $this->getMockBuilder(Cell::class)
->onlyMethods(['getValue', 'isFormula'])
->disableOriginalConstructor()
->getMock();
$cell->method('getValue')
->willReturn(null);
$cell->method('getValue')
->willReturn(false);
$worksheet = $this->getMockBuilder(Worksheet::class)
->onlyMethods(['cellExists', 'getCell'])
->disableOriginalConstructor()
->getMock();
$worksheet->method('cellExists')
->willReturn(true);
$worksheet->method('getCell')
->willReturn($cell);
$cellReference = $this->getMockBuilder(Cell::class)
->onlyMethods(['getWorksheet'])
->disableOriginalConstructor()
->getMock();
$cellReference->method('getWorksheet')
->willReturn($worksheet);
array_push($args, $cellReference);
$result = MathTrig::SUBTOTAL(...$args);
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
$sheet->fromArray([[0], [1], [1], [2], [3], [5], [8], [13], [21], [34], [55], [89]], null, 'A1', true);
$maxCol = $sheet->getHighestColumn();
$maxRow = $sheet->getHighestRow();
$sheet->getCell('D2')->setValue("=SUBTOTAL($type, A1:$maxCol$maxRow)");
$result = $sheet->getCell('D2')->getCalculatedValue();
self::assertEqualsWithDelta($expectedResult, $result, 1E-12);
}
@ -57,142 +27,102 @@ class SubTotalTest extends TestCase
return require 'tests/data/Calculation/MathTrig/SUBTOTAL.php';
}
protected function rowVisibility($data)
{
foreach ($data as $row => $visibility) {
yield $row => $visibility;
}
}
/**
* @dataProvider providerHiddenSUBTOTAL
* @dataProvider providerSUBTOTAL
*
* @param mixed $expectedResult
* @param mixed $hiddenRows
* @param mixed $type expect an integer
*/
public function testHiddenSUBTOTAL($expectedResult, $hiddenRows, ...$args): void
public function testSubtotalColumnHidden($expectedResult, $type): void
{
$visibilityGenerator = $this->rowVisibility($hiddenRows);
$rowDimension = $this->getMockBuilder(RowDimension::class)
->onlyMethods(['getVisible'])
->disableOriginalConstructor()
->getMock();
$rowDimension->method('getVisible')
->willReturnCallback(function () use ($visibilityGenerator) {
$result = $visibilityGenerator->current();
$visibilityGenerator->next();
return $result;
});
$columnDimension = $this->getMockBuilder(ColumnDimension::class)
->onlyMethods(['getVisible'])
->disableOriginalConstructor()
->getMock();
$columnDimension->method('getVisible')
->willReturn(true);
$cell = $this->getMockBuilder(Cell::class)
->onlyMethods(['getValue', 'isFormula'])
->disableOriginalConstructor()
->getMock();
$cell->method('getValue')
->willReturn('');
$cell->method('getValue')
->willReturn(false);
$worksheet = $this->getMockBuilder(Worksheet::class)
->onlyMethods(['cellExists', 'getCell', 'getRowDimension', 'getColumnDimension'])
->disableOriginalConstructor()
->getMock();
$worksheet->method('cellExists')
->willReturn(true);
$worksheet->method('getCell')
->willReturn($cell);
$worksheet->method('getRowDimension')
->willReturn($rowDimension);
$worksheet->method('getColumnDimension')
->willReturn($columnDimension);
$cellReference = $this->getMockBuilder(Cell::class)
->onlyMethods(['getWorksheet'])
->disableOriginalConstructor()
->getMock();
$cellReference->method('getWorksheet')
->willReturn($worksheet);
array_push($args, $cellReference);
$result = MathTrig::SUBTOTAL(...$args);
// Hidden columns don't affect calculation, only hidden rows
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
$sheet->fromArray([0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89], null, 'A1', true);
$maxCol = $sheet->getHighestColumn();
$maxRow = $sheet->getHighestRow();
$hiddenColumns = [
'A' => false,
'B' => true,
'C' => false,
'D' => true,
'E' => false,
'F' => false,
'G' => false,
'H' => true,
'I' => false,
'J' => true,
'K' => true,
'L' => false,
];
foreach ($hiddenColumns as $col => $hidden) {
$sheet->getColumnDimension($col)->setVisible($hidden);
}
$sheet->getCell('D2')->setValue("=SUBTOTAL($type, A1:$maxCol$maxRow)");
$result = $sheet->getCell('D2')->getCalculatedValue();
self::assertEqualsWithDelta($expectedResult, $result, 1E-12);
}
public function providerHiddenSUBTOTAL()
/**
* @dataProvider providerSUBTOTALHIDDEN
*
* @param mixed $expectedResult
* @param mixed $type expect an integer
*/
public function testSubtotalRowHidden($expectedResult, $type): void
{
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
$sheet->fromArray([[0], [1], [1], [2], [3], [5], [8], [13], [21], [34], [55], [89]], null, 'A1', true);
$maxCol = $sheet->getHighestColumn();
$maxRow = $sheet->getHighestRow();
$visibleRows = [
'1' => false,
'2' => true,
'3' => false,
'4' => true,
'5' => false,
'6' => false,
'7' => false,
'8' => true,
'9' => false,
'10' => true,
'11' => true,
'12' => false,
];
foreach ($visibleRows as $row => $visible) {
$sheet->getRowDimension($row)->setVisible($visible);
}
$sheet->getCell('D2')->setValue("=SUBTOTAL($type, A1:$maxCol$maxRow)");
$result = $sheet->getCell('D2')->getCalculatedValue();
self::assertEqualsWithDelta($expectedResult, $result, 1E-12);
}
public function providerSUBTOTALHIDDEN()
{
return require 'tests/data/Calculation/MathTrig/SUBTOTALHIDDEN.php';
}
protected function cellValues(array $cellValues)
public function testSubtotalNested(): void
{
foreach ($cellValues as $k => $v) {
yield $k => $v;
}
}
protected function cellIsFormula(array $cellValues)
{
foreach ($cellValues as $cellValue) {
yield is_string($cellValue) && $cellValue[0] === '=';
}
}
/**
* @dataProvider providerNestedSUBTOTAL
*
* @param mixed $expectedResult
*/
public function testNestedSUBTOTAL($expectedResult, ...$args): void
{
$cellValueGenerator = $this->cellValues(Functions::flattenArray(array_slice($args, 1)));
$cellIsFormulaGenerator = $this->cellIsFormula(Functions::flattenArray(array_slice($args, 1)));
$cell = $this->getMockBuilder(Cell::class)
->onlyMethods(['getValue', 'isFormula'])
->disableOriginalConstructor()
->getMock();
$cell->method('getValue')
->willReturnCallback(function () use ($cellValueGenerator) {
$result = $cellValueGenerator->current();
$cellValueGenerator->next();
return $result;
});
$cell->method('isFormula')
->willReturnCallback(function () use ($cellIsFormulaGenerator) {
$result = $cellIsFormulaGenerator->current();
$cellIsFormulaGenerator->next();
return $result;
});
$worksheet = $this->getMockBuilder(Worksheet::class)
->onlyMethods(['cellExists', 'getCell'])
->disableOriginalConstructor()
->getMock();
$worksheet->method('cellExists')
->willReturn(true);
$worksheet->method('getCell')
->willReturn($cell);
$cellReference = $this->getMockBuilder(Cell::class)
->onlyMethods(['getWorksheet'])
->disableOriginalConstructor()
->getMock();
$cellReference->method('getWorksheet')
->willReturn($worksheet);
array_push($args, $cellReference);
$result = MathTrig::SUBTOTAL(...$args);
self::assertEqualsWithDelta($expectedResult, $result, 1E-12);
}
public function providerNestedSUBTOTAL()
{
return require 'tests/data/Calculation/MathTrig/SUBTOTALNESTED.php';
$sheet = $this->sheet;
$sheet->fromArray(
[
[123],
[234],
['=SUBTOTAL(1,A1:A2)'],
['=ROMAN(SUBTOTAL(1, A1:A2))'],
['This is text containing "=" and "SUBTOTAL("'],
['=AGGREGATE(1, 0, A1:A2)'],
['=SUM(2, 3)'],
],
null,
'A1',
true
);
$maxCol = $sheet->getHighestColumn();
$maxRow = $sheet->getHighestRow();
$sheet->getCell('H1')->setValue("=SUBTOTAL(9, A1:$maxCol$maxRow)");
self::assertEquals(362, $sheet->getCell('H1')->getCalculatedValue());
}
}

View File

@ -2,25 +2,36 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Calculation\MathTrig;
use PHPUnit\Framework\TestCase;
class SumIfTest extends TestCase
class SumIfTest extends AllSetupTeardown
{
protected function setUp(): void
{
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
}
/**
* @dataProvider providerSUMIF
*
* @param mixed $expectedResult
* @param mixed $condition
*/
public function testSUMIF($expectedResult, ...$args): void
public function testSUMIF2($expectedResult, array $array1, $condition, ?array $array2 = null): void
{
$result = MathTrig::SUMIF(...$args);
$this->mightHaveException($expectedResult);
if ($expectedResult === 'incomplete') {
self::markTestIncomplete('Raises formula error - researching solution');
}
$sheet = $this->sheet;
$sheet->fromArray($array1, null, 'A1', true);
$maxARow = count($array1);
$firstArg = "A1:A$maxARow";
//$secondArg = is_string($condition) ? "\"$condition\"" : $condition;
$sheet->getCell('B1')->setValue($condition);
$secondArg = 'B1';
if (empty($array2)) {
$sheet->getCell('D1')->setValue("=SUMIF($firstArg, $secondArg)");
} else {
$sheet->fromArray($array2, null, 'C1', true);
$maxCRow = count($array2);
$thirdArg = "C1:C$maxCRow";
$sheet->getCell('D1')->setValue("=SUMIF($firstArg, $secondArg, $thirdArg)");
}
$result = $sheet->getCell('D1')->getCalculatedValue();
self::assertEqualsWithDelta($expectedResult, $result, 1E-12);
}

View File

@ -3,16 +3,9 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Calculation\MathTrig;
use PHPUnit\Framework\TestCase;
class SumProductTest extends TestCase
class SumProductTest extends AllSetupTeardown
{
protected function setUp(): void
{
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
}
/**
* @dataProvider providerSUMPRODUCT
*
@ -20,7 +13,24 @@ class SumProductTest extends TestCase
*/
public function testSUMPRODUCT($expectedResult, ...$args): void
{
$result = MathTrig::SUMPRODUCT(...$args);
$sheet = $this->sheet;
$row = 0;
$arrayArg = '';
foreach ($args as $arr) {
$arr2 = Functions::flattenArray($arr);
$startRow = 0;
foreach ($arr2 as $arr3) {
++$row;
if (!$startRow) {
$startRow = $row;
}
$sheet->getCell("A$row")->setValue($arr3);
}
$arrayArg .= "A$startRow:A$row,";
}
$arrayArg = substr($arrayArg, 0, -1); // strip trailing comma
$sheet->getCell('B1')->setValue("=SUMPRODUCT($arrayArg)");
$result = $sheet->getCell('B1')->getCalculatedValue();
self::assertEqualsWithDelta($expectedResult, $result, 1E-12);
}

View File

@ -0,0 +1,29 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
class SumTest extends AllSetupTeardown
{
/**
* @dataProvider providerSUM
*
* @param mixed $expectedResult
*/
public function testSUM($expectedResult, ...$args): void
{
$sheet = $this->sheet;
$row = 0;
foreach ($args as $arg) {
++$row;
$sheet->getCell("A$row")->setValue($arg);
}
$sheet->getCell('B1')->setValue("=SUM(A1:A$row)");
$result = $sheet->getCell('B1')->getCalculatedValue();
self::assertEqualsWithDelta($expectedResult, $result, 1E-12);
}
public function providerSUM()
{
return require 'tests/data/Calculation/MathTrig/SUM.php';
}
}

View File

@ -2,11 +2,7 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PHPUnit\Framework\TestCase;
class TanTest extends TestCase
class TanTest extends AllSetupTeardown
{
/**
* @dataProvider providerTan
@ -15,11 +11,8 @@ class TanTest extends TestCase
*/
public function testTan($expectedResult, string $formula): void
{
if ($expectedResult === 'exception') {
$this->expectException(CalcExp::class);
}
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
$sheet->setCellValue('A2', 1);
$sheet->getCell('A1')->setValue("=TAN($formula)");
$result = $sheet->getCell('A1')->getCalculatedValue();

View File

@ -2,11 +2,7 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PHPUnit\Framework\TestCase;
class TanhTest extends TestCase
class TanhTest extends AllSetupTeardown
{
/**
* @dataProvider providerTanh
@ -15,11 +11,8 @@ class TanhTest extends TestCase
*/
public function testTanh($expectedResult, string $formula): void
{
if ($expectedResult === 'exception') {
$this->expectException(CalcExp::class);
}
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
$sheet->setCellValue('A2', 1);
$sheet->getCell('A1')->setValue("=TANH($formula)");
$result = $sheet->getCell('A1')->getCalculatedValue();

View File

@ -2,11 +2,7 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PHPUnit\Framework\TestCase;
class TruncTest extends TestCase
class TruncTest extends AllSetupTeardown
{
/**
* @dataProvider providerTRUNC
@ -16,11 +12,8 @@ class TruncTest extends TestCase
*/
public function testTRUNC($expectedResult, $formula): void
{
if ($expectedResult === 'exception') {
$this->expectException(CalcExp::class);
}
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
$sheet->setCellValue('A2', 1.3);
$sheet->setCellValue('A3', 2.7);
$sheet->setCellValue('A4', -3.8);

View File

@ -56,4 +56,10 @@ return [
15,
-1,
],
['#VALUE!', 15, -1, '"X"'],
['#NUM!', 15, 37], // radix > 36
['#NUM!', 2 ** 54, 16], // number > 2 ** 53
['00000120', 15, 3, 8.1],
['exception'],
['exception', 1],
];

View File

@ -7,7 +7,7 @@ return [
],
[
1,
1.8999999999999999,
1.9,
],
[
1,
@ -35,7 +35,7 @@ return [
],
[
6,
3.2000000000000002,
3.2,
],
[
'#VALUE!',

View File

@ -0,0 +1,44 @@
<?php
return [
[
120,
5,
],
[
1.82735508062404,
1.9,
],
[
1,
0,
],
[
'#NUM!',
-4,
],
[
1,
1,
],
[
6,
3,
],
[
720,
6,
],
[
3628800,
10,
],
[
7.75668953579318,
3.2,
],
[
'#VALUE!',
'ABC',
],
];

View File

@ -65,4 +65,9 @@ return [
7,
2,
],
['#NUM!', 7, 0, -1],
['#VALUE!', 7, 0, 'X'],
[18, 9.1, 6.7],
[12, 6, null, 4],
['#VALUE!', 6, false, 4],
];

View File

@ -95,7 +95,14 @@ return [
],
],
[
'#VALUE!',
-3,
[
[3, '=6'],
[1, 1],
],
],
[
'#VALUE!', // null in array
[
[0.20, 1.00, -0.90],
[0.35, 10.80, 4.00],
@ -103,10 +110,33 @@ return [
],
],
[
'#VALUE!',
'#VALUE!', // string in array
[
[0.20, 1.00, -0.90],
[0.35, 10.80, '="4.00"'],
[-3.15, 5.00, 6.00],
],
],
[
'#VALUE!', // string in array
[
[0.20, 1.00, -0.90],
[0.35, 10.80, 'Y'],
[-3.15, 5.00, 6.00],
],
],
[
'#VALUE!', // not square
[
[1, 3, 8, 5],
[1, 3, 6, 1],
],
],
[1, '{3,6,1;1,1,0;3,10,2}'], // bracket notation
[2, 2], // scalar treated as 1x1
['#VALUE!', '"y"'], // invalid scalar treated as 1x1
['#VALUE!', '"2"'], // invalid scalar treated as 1x1
['#VALUE!', '{3,6,1;1,1,0}'], // not square
['#VALUE!', '{3,6, "y";1,1,0;3,10,2}'], // first row has string entry
['exception', ''],
];

View File

@ -111,4 +111,32 @@ return [
[1.0, -1.0],
],
],
[
'#VALUE!', // Not Square
[
[-0.5, 1.0, 1.5],
[1.0, -1.0, 2.0],
],
],
[
'#NUM!', // Determinant is 0
[
[3, 4],
[6, 8],
],
],
[
'#VALUE!', // null in array
[
[3, null],
[6, 8],
],
],
[
'#VALUE!', // string in array
[
[3, 4],
['6', 8],
],
],
];

View File

@ -90,6 +90,28 @@ return [
[6],
],
],
[
'#VALUE!', // null in first array
[
[1, 2],
[null, 4],
],
[
[5],
[6],
],
],
[
'#VALUE!', // string in second array
[
[1, 2],
[3, 4],
],
[
['5'],
[6],
],
],
// Mismatched dimensions (2x2) and (1x1)
[
'#VALUE!',

View File

@ -14,4 +14,10 @@ return [
2,
5,
],
[1, 0],
['#NUM!', 3, -1],
['#VALUE!', 3, 'X'],
['#VALUE!', 3, null],
['#VALUE!', 3, true],
['exception'],
];

View File

@ -48,4 +48,6 @@ return [
-6.7800000000000002,
-2,
],
['#VALUE!', 1, 'y', 3],
[6, 1, '2', 3],
];

View File

@ -31,4 +31,12 @@ return [
-7,
2,
],
['#VALUE!', 'X', 5],
['#VALUE!', 5, 'X'],
['#DIV/0!', 5, 0],
['#DIV/0!', 5, null],
['#DIV/0!', 0, 0],
[0, 0, 5],
['exception'],
['exception', 1],
];

View File

@ -31,4 +31,16 @@ return [
],
],
],
['#VALUE!', 'X', 1, 2, [1, 2, 3, 4, 5]],
['#VALUE!', 2, 'X', 2, [1, 2, 3, 4, 5]],
['#VALUE!', 2, 1, 'X', [1, 2, 3, 4, 5]],
['#VALUE!', 2, 1, 2, [1, 'X', 3, 4, 5]],
['#VALUE!', true, 1, 2, [1, 'X', 3, 4, 5]],
['#VALUE!', 2, 1, 2, [1, false, 3, 4, 5]],
[780, 5, 1, 1, [1, 1, null, 1, 1]],
[3780, 5, 1, 1, [1, 1, 0, 1, 1]],
[756, 5, 0, 1, [1, 1, 0, 1, 1]],
[756, 5, null, 1, [1, 1, 0, 1, 1]],
[151.2, 5, -1, 1, [1, 1, 0, 1, 1]],
[138.7, 5, -1, 1, [1, 1, -2.5, 1, 1]],
];

View File

@ -1,74 +1,19 @@
<?php
$baseTestData = [
1 => ['A' => 0],
2 => ['A' => 1],
3 => ['A' => 1],
4 => ['A' => 2],
5 => ['A' => 3],
6 => ['A' => 5],
7 => ['A' => 8],
8 => ['A' => 13],
9 => ['A' => 21],
10 => ['A' => 34],
11 => ['A' => 55],
12 => ['A' => 89],
];
return [
[
19.3333333333333,
1,
$baseTestData,
],
[
12,
2,
$baseTestData,
],
[
12,
3,
$baseTestData,
],
[
89,
4,
$baseTestData,
],
[
0,
5,
$baseTestData,
],
[
0,
6,
$baseTestData,
],
[
27.5196899207337,
7,
$baseTestData,
],
[
26.3480971271593,
8,
$baseTestData,
],
[
232,
9,
$baseTestData,
],
[
757.3333333333330,
10,
$baseTestData,
],
[
694.2222222222220,
11,
$baseTestData,
],
[19.3333333333333, 1],
[12, 2],
[12, 3],
[89, 4],
[0, 5],
[0, 6],
[27.5196899207337, 7],
[26.3480971271593, 8],
[232, 9],
[757.3333333333330, '10'],
[694.2222222222220, 11.1],
['#VALUE!', 0],
['#VALUE!', -1],
['#VALUE!', 12],
['#VALUE!', '"X"'],
];

View File

@ -1,100 +1,15 @@
<?php
$baseTestData = [
1 => ['A' => 0],
2 => ['A' => 1],
3 => ['A' => 1],
4 => ['A' => 2],
5 => ['A' => 3],
6 => ['A' => 5],
7 => ['A' => 8],
8 => ['A' => 13],
9 => ['A' => 21],
10 => ['A' => 34],
11 => ['A' => 55],
12 => ['A' => 89],
];
$hiddenRows = [
1 => false,
2 => true,
3 => false,
4 => true,
5 => false,
6 => false,
7 => false,
8 => true,
9 => false,
10 => true,
11 => true,
12 => false,
];
return [
[
21,
$hiddenRows,
101,
$baseTestData,
],
[
5,
$hiddenRows,
102,
$baseTestData,
],
[
5,
$hiddenRows,
103,
$baseTestData,
],
[
55,
$hiddenRows,
104,
$baseTestData,
],
[
1,
$hiddenRows,
105,
$baseTestData,
],
[
48620,
$hiddenRows,
106,
$baseTestData,
],
[
23.1840462387393,
$hiddenRows,
107,
$baseTestData,
],
[
20.7364413533277,
$hiddenRows,
108,
$baseTestData,
],
[
105,
$hiddenRows,
109,
$baseTestData,
],
[
537.5,
$hiddenRows,
110,
$baseTestData,
],
[
430,
$hiddenRows,
111,
$baseTestData,
],
[21, 101],
[5, 102],
[5, 103],
[55, 104],
[1, 105],
[48620, 106],
[23.1840462387393, 107],
[20.7364413533277, 108],
[105, 109],
[537.5, 110],
[430, 111],
];

View File

@ -1,18 +0,0 @@
<?php
$baseTestData = [
1 => ['A' => 123],
2 => ['A' => 234],
3 => ['A' => '=SUBTOTAL(1, A1:A2)'],
4 => ['A' => '=ROMAN(SUBTOTAL(1, A1:A2))'],
5 => ['A' => 'This is text containing "=" and "SUBTOTAL("'],
6 => ['A' => '=AGGREGATE(1, A1:A2)'],
];
return [
[
357,
9,
$baseTestData,
],
];

View File

@ -0,0 +1,8 @@
<?php
return [
[50, 5, 15, 30],
[52, 5, 15, 30, 2],
[53.1, 5.7, 15, 30, 2.4],
['#VALUE!', 5.7, 'X', 30, 2.4], // error here conflicts with SUMIF
];

View File

@ -16,19 +16,19 @@ return [
['text'],
[2],
],
'=text',
'text',
[
[10],
[100],
],
],
[
10,
'incomplete', // 10,
[
['"text with quotes"'],
[2],
],
'="text with quotes"',
'"text with quotes"',
[
[10],
[100],
@ -122,20 +122,32 @@ return [
],
[
157559,
['Jan', 'Jan', 'Jan', 'Jan', 'Feb', 'Feb', 'Feb', 'Feb'],
[['Jan'], ['Jan'], ['Jan'], ['Jan'], ['Feb'], ['Feb'], ['Feb'], ['Feb']],
'Feb',
[36693, 22100, 53321, 34440, 29889, 50090, 32080, 45500],
[[36693], [22100], [53321], [34440], [29889], [50090], [32080], [45500]],
],
[
66582,
['North 1', 'North 2', 'South 1', 'South 2', 'North 1', 'North 2', 'South 1', 'South 2,'],
[['North 1'], ['North 2'], ['South 1'], ['South 2'], ['North 1'], ['North 2'], ['South 1'], ['South 2']],
'North 1',
[36693, 22100, 53321, 34440, 29889, 50090, 32080, 45500],
[[36693], [22100], [53321], [34440], [29889], [50090], [32080], [45500]],
],
[
138772,
['North 1', 'North 2', 'South 1', 'South 2', 'North 1', 'North 2', 'South 1', 'South 2,'],
[['North 1'], ['North 2'], ['South 1'], ['South 2'], ['North 1'], ['North 2'], ['South 1'], ['South 2']],
'North ?',
[36693, 22100, 53321, 34440, 29889, 50090, 32080, 45500],
[[36693], [22100], [53321], [34440], [29889], [50090], [32080], [45500]],
],
[
'#DIV/0!',
[['North 1'], ['North 2'], ['South 1'], ['South 2'], ['North 1'], ['North 2'], ['South 1'], ['South 2']],
'North ?',
[['=3/0'], [22100], [53321], [34440], [29889], [50090], [32080], [45500]],
],
[
138772,
[['North 1'], ['North 2'], ['South 1'], ['South 2'], ['North 1'], ['North 2'], ['South 1'], ['South 2']],
'North ?',
[[36693], [22100], ['=3/0'], [34440], [29889], [50090], [32080], [45500]],
],
];

View File

@ -16,4 +16,14 @@ return [
[[1, 2], [3, 4]],
[[5, 6], [7, 8]],
],
['#VALUE!', [1, 2], [5, 6, 4]], // mismatched dimensions
[17, [1, 2, 3], [5, 'y', 4]],
[17, [1, 2, 3], [5, 0, 4]],
[19, [1, 2, 3], [5, 1, 4]],
[145, [1, 2, 3], [5, 1, 4], [9, 8, 7]],
[61, [1, 2, 3], [5, 1, 4], [9, 8, '="7"']], // string treated as 0
[100, ['="1"', 2, 3], [5, 1, 4], [9, 8, 7]], // string treated as 0
[100, [null, 2, 3], [5, 1, 4], [9, 8, 7]], // null treated as 0
[100, [true, 2, 3], [5, 1, 4], [9, 8, 7]], // true treated as 0
[61, [1, 2, 3], [5, 1, 4], [9, 8, true]], // true treated as 0
];