First steps toward array-enabling the information functions (#2608)

* First steps toward array-enabling the information functions

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

* Resolve issue with IF(), branch pruning and calculation cache (ensure that we don't convert the if condition to a bool before we've tested to see if it evaluates to an error)
More refactoring
This commit is contained in:
Mark Baker 2022-02-20 16:46:25 +01:00 committed by GitHub
parent 9893926ff9
commit 35b65bef8c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 817 additions and 341 deletions

View File

@ -4,6 +4,7 @@ namespace PhpOffice\PhpSpreadsheet\Calculation;
use PhpOffice\PhpSpreadsheet\Calculation\Engine\CyclicReferenceStack;
use PhpOffice\PhpSpreadsheet\Calculation\Engine\Logger;
use PhpOffice\PhpSpreadsheet\Calculation\Information\ErrorValue;
use PhpOffice\PhpSpreadsheet\Calculation\Information\Value;
use PhpOffice\PhpSpreadsheet\Calculation\Token\Stack;
use PhpOffice\PhpSpreadsheet\Cell\Cell;
@ -1463,12 +1464,12 @@ class Calculation
],
'ISERR' => [
'category' => Category::CATEGORY_INFORMATION,
'functionCall' => [Information\Value::class, 'isErr'],
'functionCall' => [Information\ErrorValue::class, 'isErr'],
'argumentCount' => '1',
],
'ISERROR' => [
'category' => Category::CATEGORY_INFORMATION,
'functionCall' => [Information\Value::class, 'isError'],
'functionCall' => [Information\ErrorValue::class, 'isError'],
'argumentCount' => '1',
],
'ISEVEN' => [
@ -1490,7 +1491,7 @@ class Calculation
],
'ISNA' => [
'category' => Category::CATEGORY_INFORMATION,
'functionCall' => [Information\Value::class, 'isNa'],
'functionCall' => [Information\ErrorValue::class, 'isNa'],
'argumentCount' => '1',
],
'ISNONTEXT' => [
@ -1765,7 +1766,7 @@ class Calculation
],
'NA' => [
'category' => Category::CATEGORY_INFORMATION,
'functionCall' => [Functions::class, 'NA'],
'functionCall' => [Information\ExcelError::class, 'NA'],
'argumentCount' => '0',
],
'NEGBINOMDIST' => [
@ -3894,8 +3895,8 @@ class Calculation
$regexpMatchString = '/^(' . self::CALCULATION_REGEXP_FUNCTION .
'|' . self::CALCULATION_REGEXP_CELLREF .
'|' . self::CALCULATION_REGEXP_COLUMN_RANGE .
'|' . self::CALCULATION_REGEXP_ROW_RANGE .
'|' . self::CALCULATION_REGEXP_COLUMN_RANGE .
'|' . self::CALCULATION_REGEXP_ROW_RANGE .
'|' . self::CALCULATION_REGEXP_NUMBER .
'|' . self::CALCULATION_REGEXP_STRING .
'|' . self::CALCULATION_REGEXP_OPENBRACE .
@ -4009,10 +4010,11 @@ class Calculation
--$parenthesisDepthMap[$pendingStoreKey];
}
if (is_array($d) && preg_match('/^' . self::CALCULATION_REGEXP_FUNCTION . '$/miu', $d['value'], $matches)) { // Did this parenthesis just close a function?
if (is_array($d) && preg_match('/^' . self::CALCULATION_REGEXP_FUNCTION . '$/miu', $d['value'], $matches)) {
// Did this parenthesis just close a function?
if (!empty($pendingStoreKey) && $parenthesisDepthMap[$pendingStoreKey] == -1) {
// we are closing an IF(
if ($d['value'] != 'IF(') {
if ($d['value'] !== 'IF(') {
return $this->raiseFormulaError('Parser bug we should be in an "IF("');
}
if ($expectingConditionMap[$pendingStoreKey]) {
@ -4427,11 +4429,7 @@ class Calculation
if (
isset($storeValue)
&& (
!$storeValueAsBool
|| Value::isError($storeValue)
|| ($storeValue === 'Pruned branch')
)
&& (!$storeValueAsBool || ErrorValue::isError($storeValue) || ($storeValue === 'Pruned branch'))
) {
// If branching value is not true, we don't need to compute
if (!isset($fakedForBranchPruning['onlyIf-' . $onlyIfStoreKey])) {
@ -4462,11 +4460,7 @@ class Calculation
}
if (
isset($storeValue)
&& (
$storeValueAsBool
|| Value::isError($storeValue)
|| ($storeValue === 'Pruned branch')
)
&& ($storeValueAsBool || ErrorValue::isError($storeValue) || ($storeValue === 'Pruned branch'))
) {
// If branching value is true, we don't need to compute
if (!isset($fakedForBranchPruning['onlyIfNot-' . $onlyIfNotStoreKey])) {

View File

@ -346,7 +346,7 @@ class Functions
* @see Information\Value::isBlank()
* Use the isBlank() method in the Information\Value class instead
*
* @return bool
* @return array|bool
*/
public static function isBlank($value = null)
{
@ -363,11 +363,11 @@ class Functions
* @see Information\Value::isErr()
* Use the isErr() method in the Information\Value class instead
*
* @return bool
* @return array|bool
*/
public static function isErr($value = '')
{
return Information\Value::isErr($value);
return Information\ErrorValue::isErr($value);
}
/**
@ -380,11 +380,11 @@ class Functions
* @see Information\Value::isError()
* Use the isError() method in the Information\Value class instead
*
* @return bool
* @return array|bool
*/
public static function isError($value = '')
{
return Information\Value::isError($value);
return Information\ErrorValue::isError($value);
}
/**
@ -397,11 +397,11 @@ class Functions
* @see Information\Value::isNa()
* Use the isNa() method in the Information\Value class instead
*
* @return bool
* @return array|bool
*/
public static function isNa($value = '')
{
return Information\Value::isNa($value);
return Information\ErrorValue::isNa($value);
}
/**
@ -414,7 +414,7 @@ class Functions
* @see Information\Value::isEven()
* Use the isEven() method in the Information\Value class instead
*
* @return bool|string
* @return array|bool|string
*/
public static function isEven($value = null)
{
@ -431,7 +431,7 @@ class Functions
* @see Information\Value::isOdd()
* Use the isOdd() method in the Information\Value class instead
*
* @return bool|string
* @return array|bool|string
*/
public static function isOdd($value = null)
{
@ -448,7 +448,7 @@ class Functions
* @see Information\Value::isNumber()
* Use the isNumber() method in the Information\Value class instead
*
* @return bool
* @return array|bool
*/
public static function isNumber($value = null)
{
@ -465,7 +465,7 @@ class Functions
* @see Information\Value::isLogical()
* Use the isLogical() method in the Information\Value class instead
*
* @return bool
* @return array|bool
*/
public static function isLogical($value = null)
{
@ -482,7 +482,7 @@ class Functions
* @see Information\Value::isText()
* Use the isText() method in the Information\Value class instead
*
* @return bool
* @return array|bool
*/
public static function isText($value = null)
{
@ -499,7 +499,7 @@ class Functions
* @see Information\Value::isNonText()
* Use the isNonText() method in the Information\Value class instead
*
* @return bool
* @return array|bool
*/
public static function isNonText($value = null)
{

View File

@ -0,0 +1,71 @@
<?php
namespace PhpOffice\PhpSpreadsheet\Calculation\Information;
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
class ErrorValue
{
use ArrayEnabled;
/**
* IS_ERR.
*
* @param mixed $value Value to check
* Or can be an array of values
*
* @return array|bool
* If an array of numbers is passed as an argument, then the returned result will also be an array
* with the same dimensions
*/
public static function isErr($value = '')
{
if (is_array($value)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $value);
}
return self::isError($value) && (!self::isNa(($value)));
}
/**
* IS_ERROR.
*
* @param mixed $value Value to check
* Or can be an array of values
*
* @return array|bool
* If an array of numbers is passed as an argument, then the returned result will also be an array
* with the same dimensions
*/
public static function isError($value = '')
{
if (is_array($value)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $value);
}
if (!is_string($value)) {
return false;
}
return in_array($value, ExcelError::$errorCodes);
}
/**
* IS_NA.
*
* @param mixed $value Value to check
* Or can be an array of values
*
* @return array|bool
* If an array of numbers is passed as an argument, then the returned result will also be an array
* with the same dimensions
*/
public static function isNa($value = '')
{
if (is_array($value)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $value);
}
return $value === ExcelError::NA();
}
}

View File

@ -2,21 +2,31 @@
namespace PhpOffice\PhpSpreadsheet\Calculation\Information;
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Cell\Cell;
class Value
{
use ArrayEnabled;
/**
* IS_BLANK.
*
* @param mixed $value Value to check
* Or can be an array of values
*
* @return bool
* @return array|bool
* If an array of numbers is passed as an argument, then the returned result will also be an array
* with the same dimensions
*/
public static function isBlank($value = null)
{
if (is_array($value)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $value);
}
if ($value !== null) {
$value = Functions::flattenSingleValue($value);
}
@ -28,12 +38,17 @@ class Value
* IS_EVEN.
*
* @param mixed $value Value to check
* Or can be an array of values
*
* @return bool|string
* @return array|bool|string
* If an array of numbers is passed as an argument, then the returned result will also be an array
* with the same dimensions
*/
public static function isEven($value = null)
{
$value = Functions::flattenSingleValue($value);
if (is_array($value)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $value);
}
if ($value === null) {
return ExcelError::NAME();
@ -48,12 +63,17 @@ class Value
* IS_ODD.
*
* @param mixed $value Value to check
* Or can be an array of values
*
* @return bool|string
* @return array|bool|string
* If an array of numbers is passed as an argument, then the returned result will also be an array
* with the same dimensions
*/
public static function isOdd($value = null)
{
$value = Functions::flattenSingleValue($value);
if (is_array($value)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $value);
}
if ($value === null) {
return ExcelError::NAME();
@ -68,12 +88,17 @@ class Value
* IS_NUMBER.
*
* @param mixed $value Value to check
* Or can be an array of values
*
* @return bool
* @return array|bool
* If an array of numbers is passed as an argument, then the returned result will also be an array
* with the same dimensions
*/
public static function isNumber($value = null)
{
$value = Functions::flattenSingleValue($value);
if (is_array($value)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $value);
}
if (is_string($value)) {
return false;
@ -86,12 +111,17 @@ class Value
* IS_LOGICAL.
*
* @param mixed $value Value to check
* Or can be an array of values
*
* @return bool
* @return array|bool
* If an array of numbers is passed as an argument, then the returned result will also be an array
* with the same dimensions
*/
public static function isLogical($value = null)
{
$value = Functions::flattenSingleValue($value);
if (is_array($value)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $value);
}
return is_bool($value);
}
@ -100,25 +130,37 @@ class Value
* IS_TEXT.
*
* @param mixed $value Value to check
* Or can be an array of values
*
* @return bool
* @return array|bool
* If an array of numbers is passed as an argument, then the returned result will also be an array
* with the same dimensions
*/
public static function isText($value = null)
{
$value = Functions::flattenSingleValue($value);
if (is_array($value)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $value);
}
return is_string($value) && !self::isError($value);
return is_string($value) && !ErrorValue::isError($value);
}
/**
* IS_NONTEXT.
*
* @param mixed $value Value to check
* Or can be an array of values
*
* @return bool
* @return array|bool
* If an array of numbers is passed as an argument, then the returned result will also be an array
* with the same dimensions
*/
public static function isNonText($value = null)
{
if (is_array($value)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $value);
}
return !self::isText($value);
}
@ -150,52 +192,6 @@ class Value
return ($worksheet !== null) ? $worksheet->getCell($cellReference)->isFormula() : ExcelError::REF();
}
/**
* IS_ERR.
*
* @param mixed $value Value to check
*
* @return bool
*/
public static function isErr($value = '')
{
$value = Functions::flattenSingleValue($value);
return self::isError($value) && (!self::isNa(($value)));
}
/**
* IS_ERROR.
*
* @param mixed $value Value to check
*
* @return bool
*/
public static function isError($value = '')
{
$value = Functions::flattenSingleValue($value);
if (!is_string($value)) {
return false;
}
return in_array($value, ExcelError::$errorCodes);
}
/**
* IS_NA.
*
* @param mixed $value Value to check
*
* @return bool
*/
public static function isNa($value = '')
{
$value = Functions::flattenSingleValue($value);
return $value === ExcelError::NA();
}
/**
* N.
*
@ -205,12 +201,12 @@ class Value
*
* @return number N converts values listed in the following table
* If value is or refers to N returns
* A number That number
* A date The serial number of that date
* A number That number value
* A date The Excel serialized number of that date
* TRUE 1
* FALSE 0
* An error value The error value
* Anything else 0
* FALSE 0
* An error value The error value
* Anything else 0
*/
public static function asNumber($value = null)
{
@ -248,9 +244,9 @@ class Value
* If value is or refers to N returns
* A number 1
* Text 2
* Logical Value 4
* An error value 16
* Array or Matrix 64
* Logical Value 4
* An error value 16
* Array or Matrix 64
*/
public static function type($value = null)
{
@ -269,8 +265,8 @@ class Value
// Empty Cell
return 1;
}
$value = Functions::flattenSingleValue($value);
$value = Functions::flattenSingleValue($value);
if (($value === null) || (is_float($value)) || (is_int($value))) {
return 1;
} elseif (is_bool($value)) {

View File

@ -5,6 +5,7 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\Logical;
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Calculation\Information\ErrorValue;
use PhpOffice\PhpSpreadsheet\Calculation\Information\ExcelError;
use PhpOffice\PhpSpreadsheet\Calculation\Information\Value;
@ -47,15 +48,16 @@ class Conditional
*/
public static function statementIf($condition = true, $returnIfTrue = 0, $returnIfFalse = false)
{
if (Value::isError($condition)) {
$condition = ($condition === null) ? true : Functions::flattenSingleValue($condition);
if (ErrorValue::isError($condition)) {
return $condition;
}
$condition = ($condition === null) ? true : (bool) Functions::flattenSingleValue($condition);
$returnIfTrue = $returnIfTrue ?? 0;
$returnIfFalse = $returnIfFalse ?? false;
return ($condition) ? $returnIfTrue : $returnIfFalse;
return ((bool) $condition) ? $returnIfTrue : $returnIfFalse;
}
/**
@ -138,7 +140,7 @@ class Conditional
$errorpart = $errorpart ?? '';
return self::statementIf(Value::isError($testValue), $errorpart, $testValue);
return self::statementIf(ErrorValue::isError($testValue), $errorpart, $testValue);
}
/**
@ -164,7 +166,7 @@ class Conditional
$napart = $napart ?? '';
return self::statementIf(Value::isNa($testValue), $napart, $testValue);
return self::statementIf(ErrorValue::isNa($testValue), $napart, $testValue);
}
/**

View File

@ -3,8 +3,8 @@
namespace PhpOffice\PhpSpreadsheet\Calculation\LookupRef;
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
use PhpOffice\PhpSpreadsheet\Calculation\Information\ErrorValue;
use PhpOffice\PhpSpreadsheet\Calculation\Information\ExcelError;
use PhpOffice\PhpSpreadsheet\Calculation\Information\Value;
class LookupRefValidations
{
@ -14,7 +14,7 @@ class LookupRefValidations
public static function validateInt($value): int
{
if (!is_numeric($value)) {
if (Value::isError($value)) {
if (ErrorValue::isError($value)) {
throw new Exception($value);
}

View File

@ -3,6 +3,7 @@
namespace PhpOffice\PhpSpreadsheet\Calculation\MathTrig;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Calculation\Information\ErrorValue;
use PhpOffice\PhpSpreadsheet\Calculation\Information\ExcelError;
use PhpOffice\PhpSpreadsheet\Calculation\Information\Value;
@ -29,7 +30,7 @@ class Sum
// Is it a numeric value?
if (is_numeric($arg)) {
$returnValue += $arg;
} elseif (Value::isError($arg)) {
} elseif (ErrorValue::isError($arg)) {
return $arg;
}
}
@ -63,7 +64,7 @@ class Sum
$returnValue += $arg;
} elseif (is_bool($arg)) {
$returnValue += (int) $arg;
} elseif (Value::isError($arg)) {
} elseif (ErrorValue::isError($arg)) {
return $arg;
// ignore non-numerics from cell, but fail as literals (except null)
} elseif ($arg !== null && !Functions::isCellValue($k)) {

View File

@ -1811,7 +1811,7 @@ class Statistical
* @param float $m0 Alpha Parameter
* @param float $sigma Beta Parameter
*
* @return float|string (string if result is an error)
* @return array|float|string (string if result is an error)
*/
public static function ZTEST($dataSet, $m0, $sigma = null)
{

View File

@ -117,16 +117,22 @@ class StandardNormal
*
* @param mixed $dataSet The dataset should be an array of float values for the observations
* @param mixed $m0 Alpha Parameter
* Or can be an array of values
* @param mixed $sigma A null or float value for the Beta (Standard Deviation) Parameter;
* if null, we use the standard deviation of the dataset
* Or can be an array of values
*
* @return float|string (string if result is an error)
* @return array|float|string (string if result is an error)
* If an array of numbers is passed as an argument, then the returned result will also be an array
* with the same dimensions
*/
public static function zTest($dataSet, $m0, $sigma = null)
{
if (is_array($m0) || is_array($sigma)) {
return self::evaluateArrayArgumentsSubsetFrom([self::class, __FUNCTION__], 1, $dataSet, $m0, $sigma);
}
$dataSet = Functions::flattenArrayIndexed($dataSet);
$m0 = Functions::flattenSingleValue($m0);
$sigma = Functions::flattenSingleValue($sigma);
if (!is_numeric($m0) || ($sigma !== null && !is_numeric($sigma))) {
return ExcelError::VALUE();

View File

@ -2,6 +2,7 @@
namespace PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use PhpOffice\PhpSpreadsheet\Calculation\Information\ErrorValue;
use PhpOffice\PhpSpreadsheet\Calculation\Information\Value;
use PhpOffice\PhpSpreadsheet\Cell\Cell;
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
@ -1251,7 +1252,7 @@ class Worksheet extends WriterPart
{
$calculatedValue = $this->getParentWriter()->getPreCalculateFormulas() ? $cell->getCalculatedValue() : $cellValue;
if (is_string($calculatedValue)) {
if (Value::isError($calculatedValue)) {
if (ErrorValue::isError($calculatedValue)) {
$this->writeCellError($objWriter, 'e', $cellValue, $calculatedValue);
return;

View File

@ -0,0 +1,54 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Information;
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PHPUnit\Framework\TestCase;
class IsBlankTest extends TestCase
{
public function testIsBlankNoArgument(): void
{
$result = Functions::isBlank();
self::assertTrue($result);
}
/**
* @dataProvider providerIsBlank
*
* @param mixed $value
*/
public function testIsBlank(bool $expectedResult, $value): void
{
$result = Functions::isBlank($value);
self::assertEquals($expectedResult, $result);
}
public function providerIsBlank(): array
{
return require 'tests/data/Calculation/Information/IS_BLANK.php';
}
/**
* @dataProvider providerIsBlankArray
*/
public function testIsBlankArray(array $expectedResult, string $values): void
{
$calculation = Calculation::getInstance();
$formula = "=ISBLANK({$values})";
$result = $calculation->_calculateFormulaValue($formula);
self::assertEquals($expectedResult, $result);
}
public function providerIsBlankArray(): array
{
return [
'vector' => [
[[false, true, false]],
'{12, NULL, ""}',
],
];
}
}

View File

@ -0,0 +1,54 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Information;
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PHPUnit\Framework\TestCase;
class IsErrTest extends TestCase
{
public function testIsErrNoArgument(): void
{
$result = Functions::isErr();
self::assertFalse($result);
}
/**
* @dataProvider providerIsErr
*
* @param mixed $value
*/
public function testIsErr(bool $expectedResult, $value): void
{
$result = Functions::isErr($value);
self::assertEquals($expectedResult, $result);
}
public function providerIsErr(): array
{
return require 'tests/data/Calculation/Information/IS_ERR.php';
}
/**
* @dataProvider providerIsErrArray
*/
public function testIsErrArray(array $expectedResult, string $values): void
{
$calculation = Calculation::getInstance();
$formula = "=ISERR({$values})";
$result = $calculation->_calculateFormulaValue($formula);
self::assertEquals($expectedResult, $result);
}
public function providerIsErrArray(): array
{
return [
'vector' => [
[[true, true, false, false, false, false]],
'{5/0, "#REF!", "#N/A", 1.2, TRUE, "PHP"}',
],
];
}
}

View File

@ -0,0 +1,54 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Information;
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PHPUnit\Framework\TestCase;
class IsErrorTest extends TestCase
{
public function testIsErrorNoArgument(): void
{
$result = Functions::isError();
self::assertFalse($result);
}
/**
* @dataProvider providerIsError
*
* @param mixed $value
*/
public function testIsError(bool $expectedResult, $value): void
{
$result = Functions::isError($value);
self::assertEquals($expectedResult, $result);
}
public function providerIsError(): array
{
return require 'tests/data/Calculation/Information/IS_ERROR.php';
}
/**
* @dataProvider providerIsErrorArray
*/
public function testIsErrorArray(array $expectedResult, string $values): void
{
$calculation = Calculation::getInstance();
$formula = "=ISERROR({$values})";
$result = $calculation->_calculateFormulaValue($formula);
self::assertEquals($expectedResult, $result);
}
public function providerIsErrorArray(): array
{
return [
'vector' => [
[[true, true, true, false, false, false]],
'{5/0, "#REF!", "#N/A", 1.2, TRUE, "PHP"}',
],
];
}
}

View File

@ -0,0 +1,56 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Information;
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Calculation\Information\ExcelError;
use PHPUnit\Framework\TestCase;
class IsEvenTest extends TestCase
{
public function testIsEvenNoArgument(): void
{
$result = Functions::isEven();
self::assertSame(ExcelError::NAME(), $result);
}
/**
* @dataProvider providerIsEven
*
* @param bool|string $expectedResult
* @param mixed $value
*/
public function testIsEven($expectedResult, $value): void
{
$result = Functions::isEven($value);
self::assertEquals($expectedResult, $result);
}
public function providerIsEven(): array
{
return require 'tests/data/Calculation/Information/IS_EVEN.php';
}
/**
* @dataProvider providerIsEvenArray
*/
public function testIsEvenArray(array $expectedResult, string $values): void
{
$calculation = Calculation::getInstance();
$formula = "=ISEVEN({$values})";
$result = $calculation->_calculateFormulaValue($formula);
self::assertEquals($expectedResult, $result);
}
public function providerIsEvenArray(): array
{
return [
'vector' => [
[[true, false, true, false, true]],
'{-2, -1, 0, 1, 2}',
],
];
}
}

View File

@ -0,0 +1,54 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Information;
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PHPUnit\Framework\TestCase;
class IsLogicalTest extends TestCase
{
public function testIsLogicalNoArgument(): void
{
$result = Functions::isLogical();
self::assertFalse($result);
}
/**
* @dataProvider providerIsLogical
*
* @param mixed $value
*/
public function testIsLogical(bool $expectedResult, $value): void
{
$result = Functions::isLogical($value);
self::assertEquals($expectedResult, $result);
}
public function providerIsLogical(): array
{
return require 'tests/data/Calculation/Information/IS_LOGICAL.php';
}
/**
* @dataProvider providerIsLogicalArray
*/
public function testIsLogicalArray(array $expectedResult, string $values): void
{
$calculation = Calculation::getInstance();
$formula = "=ISLOGICAL({$values})";
$result = $calculation->_calculateFormulaValue($formula);
self::assertEquals($expectedResult, $result);
}
public function providerIsLogicalArray(): array
{
return [
'vector' => [
[[true, false, false, false, true, false]],
'{true, -1, null, 1, false, "FALSE"}',
],
];
}
}

View File

@ -0,0 +1,54 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Information;
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PHPUnit\Framework\TestCase;
class IsNaTest extends TestCase
{
public function testIsNaNoArgument(): void
{
$result = Functions::isNa();
self::assertFalse($result);
}
/**
* @dataProvider providerIsNa
*
* @param mixed $value
*/
public function testIsNa(bool $expectedResult, $value): void
{
$result = Functions::isNa($value);
self::assertEquals($expectedResult, $result);
}
public function providerIsNa(): array
{
return require 'tests/data/Calculation/Information/IS_NA.php';
}
/**
* @dataProvider providerIsNaArray
*/
public function testIsNaArray(array $expectedResult, string $values): void
{
$calculation = Calculation::getInstance();
$formula = "=ISNA({$values})";
$result = $calculation->_calculateFormulaValue($formula);
self::assertEquals($expectedResult, $result);
}
public function providerIsNaArray(): array
{
return [
'vector' => [
[[false, false, true, false, false, false]],
'{5/0, "#REF!", "#N/A", 1.2, TRUE, "PHP"}',
],
];
}
}

View File

@ -0,0 +1,54 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Information;
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PHPUnit\Framework\TestCase;
class IsNonTextTest extends TestCase
{
public function testIsNonTextNoArgument(): void
{
$result = Functions::isNonText();
self::assertTrue($result);
}
/**
* @dataProvider providerIsNonText
*
* @param mixed $value
*/
public function testIsNonText(bool $expectedResult, $value): void
{
$result = Functions::isNonText($value);
self::assertEquals($expectedResult, $result);
}
public function providerIsNonText(): array
{
return require 'tests/data/Calculation/Information/IS_NONTEXT.php';
}
/**
* @dataProvider providerIsNonTextArray
*/
public function testIsNonTextArray(array $expectedResult, string $values): void
{
$calculation = Calculation::getInstance();
$formula = "=ISNONTEXT({$values})";
$result = $calculation->_calculateFormulaValue($formula);
self::assertEquals($expectedResult, $result);
}
public function providerIsNonTextArray(): array
{
return [
'vector' => [
[[true, false, false, true, true]],
'{-2, "PHP", "123.456", false, 2.34}',
],
];
}
}

View File

@ -0,0 +1,54 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Information;
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PHPUnit\Framework\TestCase;
class IsNumberTest extends TestCase
{
public function testIsNumberNoArgument(): void
{
$result = Functions::isNumber();
self::assertFalse($result);
}
/**
* @dataProvider providerIsNumber
*
* @param mixed $value
*/
public function testIsNumber(bool $expectedResult, $value): void
{
$result = Functions::isNumber($value);
self::assertEquals($expectedResult, $result);
}
public function providerIsNumber(): array
{
return require 'tests/data/Calculation/Information/IS_NUMBER.php';
}
/**
* @dataProvider providerIsNumberArray
*/
public function testIsNumberArray(array $expectedResult, string $values): void
{
$calculation = Calculation::getInstance();
$formula = "=ISNUMBER({$values})";
$result = $calculation->_calculateFormulaValue($formula);
self::assertEquals($expectedResult, $result);
}
public function providerIsNumberArray(): array
{
return [
'vector' => [
[[true, false, false, false, true]],
'{-2, "PHP", "123.456", false, 2.34}',
],
];
}
}

View File

@ -0,0 +1,56 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Information;
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Calculation\Information\ExcelError;
use PHPUnit\Framework\TestCase;
class IsOddTest extends TestCase
{
public function testIsOddNoArgument(): void
{
$result = Functions::isOdd();
self::assertSame(ExcelError::NAME(), $result);
}
/**
* @dataProvider providerIsOdd
*
* @param bool|string $expectedResult
* @param mixed $value
*/
public function testIsOdd($expectedResult, $value): void
{
$result = Functions::isOdd($value);
self::assertEquals($expectedResult, $result);
}
public function providerIsOdd(): array
{
return require 'tests/data/Calculation/Information/IS_ODD.php';
}
/**
* @dataProvider providerIsOddArray
*/
public function testIsOddArray(array $expectedResult, string $values): void
{
$calculation = Calculation::getInstance();
$formula = "=ISODD({$values})";
$result = $calculation->_calculateFormulaValue($formula);
self::assertEquals($expectedResult, $result);
}
public function providerIsOddArray(): array
{
return [
'vector' => [
[[false, true, false, true, false]],
'{-2, -1, 0, 1, 2}',
],
];
}
}

View File

@ -0,0 +1,54 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Information;
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PHPUnit\Framework\TestCase;
class IsTextTest extends TestCase
{
public function testIsTextNoArgument(): void
{
$result = Functions::isText();
self::assertFalse($result);
}
/**
* @dataProvider providerIsText
*
* @param mixed $value
*/
public function testIsText(bool $expectedResult, $value): void
{
$result = Functions::isText($value);
self::assertEquals($expectedResult, $result);
}
public function providerIsText(): array
{
return require 'tests/data/Calculation/Information/IS_TEXT.php';
}
/**
* @dataProvider providerIsTextArray
*/
public function testIsTextArray(array $expectedResult, string $values): void
{
$calculation = Calculation::getInstance();
$formula = "=ISTEXT({$values})";
$result = $calculation->_calculateFormulaValue($formula);
self::assertEquals($expectedResult, $result);
}
public function providerIsTextArray(): array
{
return [
'vector' => [
[[false, true, true, false, false]],
'{-2, "PHP", "123.456", false, 2.34}',
],
];
}
}

View File

@ -0,0 +1,32 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Information;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PHPUnit\Framework\TestCase;
class NTest extends TestCase
{
public function testNNoArgument(): void
{
$result = Functions::n();
self::assertSame(0, $result);
}
/**
* @dataProvider providerN
*
* @param mixed $expectedResult
* @param number|string $value
*/
public function testN($expectedResult, $value): void
{
$result = Functions::n($value);
self::assertEqualsWithDelta($expectedResult, $result, 1.0e-12);
}
public function providerN(): array
{
return require 'tests/data/Calculation/Information/N.php';
}
}

View File

@ -0,0 +1,31 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Information;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PHPUnit\Framework\TestCase;
class TypeTest extends TestCase
{
public function testTypeNoArgument(): void
{
$result = Functions::TYPE();
self::assertSame(1, $result);
}
/**
* @dataProvider providerTYPE
*
* @param mixed $value
*/
public function testTYPE(int $expectedResult, $value): void
{
$result = Functions::TYPE($value);
self::assertSame($expectedResult, $result);
}
public function providerTYPE(): array
{
return require 'tests/data/Calculation/Information/TYPE.php';
}
}

View File

@ -2,6 +2,7 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Statistical;
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
use PhpOffice\PhpSpreadsheet\Calculation\Statistical;
use PHPUnit\Framework\TestCase;
@ -25,4 +26,29 @@ class ZTestTest extends TestCase
{
return require 'tests/data/Calculation/Statistical/ZTEST.php';
}
/**
* @dataProvider providerZTestArray
*/
public function testZTestArray(array $expectedResult, string $dataSet, string $m0): void
{
$calculation = Calculation::getInstance();
$formula = "=ZTEST({$dataSet}, {$m0})";
$result = $calculation->_calculateFormulaValue($formula);
self::assertEqualsWithDelta($expectedResult, $result, 1.0e-14);
}
public function providerZTestArray(): array
{
return [
'row vector' => [
[
[0.09057419685136381, 0.4516213175273426, 0.8630433891295299],
],
'{3, 6, 7, 8, 6, 5, 4, 2, 1, 9}',
'{4, 5, 6}',
],
];
}
}

View File

@ -116,54 +116,6 @@ class FunctionsTest extends TestCase
self::assertEquals('#VALUE!', $result);
}
/**
* @dataProvider providerIsBlank
*
* @param mixed $expectedResult
*/
public function testIsBlank($expectedResult, ...$args): void
{
$result = Functions::isBlank(...$args);
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
}
public function providerIsBlank(): array
{
return require 'tests/data/Calculation/Functions/IS_BLANK.php';
}
/**
* @dataProvider providerIsErr
*
* @param mixed $expectedResult
*/
public function testIsErr($expectedResult, ...$args): void
{
$result = Functions::isErr(...$args);
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
}
public function providerIsErr(): array
{
return require 'tests/data/Calculation/Functions/IS_ERR.php';
}
/**
* @dataProvider providerIsError
*
* @param mixed $expectedResult
*/
public function testIsError($expectedResult, ...$args): void
{
$result = Functions::isError(...$args);
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
}
public function providerIsError(): array
{
return require 'tests/data/Calculation/Functions/IS_ERROR.php';
}
/**
* @dataProvider providerErrorType
*
@ -180,150 +132,6 @@ class FunctionsTest extends TestCase
return require 'tests/data/Calculation/Functions/ERROR_TYPE.php';
}
/**
* @dataProvider providerIsLogical
*
* @param mixed $expectedResult
*/
public function testIsLogical($expectedResult, ...$args): void
{
$result = Functions::isLogical(...$args);
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
}
public function providerIsLogical(): array
{
return require 'tests/data/Calculation/Functions/IS_LOGICAL.php';
}
/**
* @dataProvider providerIsNa
*
* @param mixed $expectedResult
*/
public function testIsNa($expectedResult, ...$args): void
{
$result = Functions::isNa(...$args);
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
}
public function providerIsNa(): array
{
return require 'tests/data/Calculation/Functions/IS_NA.php';
}
/**
* @dataProvider providerIsNumber
*
* @param mixed $expectedResult
*/
public function testIsNumber($expectedResult, ...$args): void
{
$result = Functions::isNumber(...$args);
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
}
public function providerIsNumber(): array
{
return require 'tests/data/Calculation/Functions/IS_NUMBER.php';
}
/**
* @dataProvider providerIsText
*
* @param mixed $expectedResult
*/
public function testIsText($expectedResult, ...$args): void
{
$result = Functions::isText(...$args);
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
}
public function providerIsText(): array
{
return require 'tests/data/Calculation/Functions/IS_TEXT.php';
}
/**
* @dataProvider providerIsNonText
*
* @param mixed $expectedResult
*/
public function testIsNonText($expectedResult, ...$args): void
{
$result = Functions::isNonText(...$args);
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
}
public function providerIsNonText(): array
{
return require 'tests/data/Calculation/Functions/IS_NONTEXT.php';
}
/**
* @dataProvider providerIsEven
*
* @param mixed $expectedResult
*/
public function testIsEven($expectedResult, ...$args): void
{
$result = Functions::isEven(...$args);
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
}
public function providerIsEven(): array
{
return require 'tests/data/Calculation/Functions/IS_EVEN.php';
}
/**
* @dataProvider providerIsOdd
*
* @param mixed $expectedResult
*/
public function testIsOdd($expectedResult, ...$args): void
{
$result = Functions::isOdd(...$args);
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
}
public function providerIsOdd(): array
{
return require 'tests/data/Calculation/Functions/IS_ODD.php';
}
/**
* @dataProvider providerTYPE
*
* @param mixed $expectedResult
*/
public function testTYPE($expectedResult, ...$args): void
{
$result = Functions::TYPE(...$args);
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
}
public function providerTYPE(): array
{
return require 'tests/data/Calculation/Functions/TYPE.php';
}
/**
* @dataProvider providerN
*
* @param mixed $expectedResult
*/
public function testN($expectedResult, ...$args): void
{
$result = Functions::n(...$args);
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
}
public function providerN(): array
{
return require 'tests/data/Calculation/Functions/N.php';
}
/**
* @dataProvider providerIfCondition
*

View File

@ -1,9 +1,6 @@
<?php
return [
[
true,
],
[
true,
null,

View File

@ -1,9 +1,6 @@
<?php
return [
[
false,
],
[
false,
null,

View File

@ -1,9 +1,6 @@
<?php
return [
[
false,
],
[
false,
null,

View File

@ -1,9 +1,6 @@
<?php
return [
[
'#NAME?',
],
[
'#NAME?',
null,

View File

@ -1,9 +1,6 @@
<?php
return [
[
false,
],
[
false,
null,

View File

@ -1,9 +1,6 @@
<?php
return [
[
false,
],
[
false,
null,

View File

@ -1,9 +1,6 @@
<?php
return [
[
true,
],
[
true,
null,

View File

@ -1,9 +1,6 @@
<?php
return [
[
false,
],
[
false,
null,

View File

@ -1,9 +1,6 @@
<?php
return [
[
'#NAME?',
],
[
'#NAME?',
null,

View File

@ -1,9 +1,6 @@
<?php
return [
[
false,
],
[
false,
null,

View File

@ -1,9 +1,6 @@
<?php
return [
[
0,
],
[
0,
null,

View File

@ -1,9 +1,6 @@
<?php
return [
[
1,
],
[
1,
null,