Merge branch 'master' into CalcEngine-Feature_Structured_References

This commit is contained in:
Mark Baker
2022-11-23 17:08:29 +01:00
committed by GitHub
24 changed files with 301 additions and 228 deletions
@@ -0,0 +1,120 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Logical;
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcException;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Cell\DataType;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
use PHPUnit\Framework\TestCase;
class AllSetupTeardown extends TestCase
{
/**
* @var string
*/
private $compatibilityMode;
/**
* @var ?Spreadsheet
*/
private $spreadsheet;
/**
* @var ?Worksheet
*/
private $sheet;
protected function setUp(): void
{
$this->compatibilityMode = Functions::getCompatibilityMode();
}
protected function tearDown(): void
{
Functions::setCompatibilityMode($this->compatibilityMode);
$this->sheet = null;
if ($this->spreadsheet !== null) {
$this->spreadsheet->disconnectWorksheets();
$this->spreadsheet = 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);
}
}
/**
* @param mixed $value
*/
protected function setCell(string $cell, $value): void
{
if ($value !== null) {
if (is_string($value) && is_numeric($value)) {
$this->getSheet()->getCell($cell)->setValueExplicit($value, DataType::TYPE_STRING);
} else {
$this->getSheet()->getCell($cell)->setValue($value);
}
}
}
protected function getSpreadsheet(): Spreadsheet
{
if ($this->spreadsheet !== null) {
return $this->spreadsheet;
}
$this->spreadsheet = new Spreadsheet();
return $this->spreadsheet;
}
protected function getSheet(): Worksheet
{
if ($this->sheet !== null) {
return $this->sheet;
}
$this->sheet = $this->getSpreadsheet()->getActiveSheet();
return $this->sheet;
}
/**
* @param mixed $expectedResult
* @param array $args
*/
protected function runTestCase(string $functionName, $expectedResult, ...$args): void
{
$this->mightHaveException($expectedResult);
$sheet = $this->getSheet();
$formula = "=$functionName(";
$comma = '';
$row = 0;
foreach ($args as $arg) {
++$row;
$cellId = "A$row";
$formula .= "$comma$cellId";
$comma = ',';
$this->setCell($cellId, $arg);
}
$formula .= ')';
$this->setCell('B1', $formula);
self::assertSame($expectedResult, $sheet->getCell('B1')->getCalculatedValue());
}
}
@@ -2,17 +2,8 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Logical;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Calculation\Logical;
use PHPUnit\Framework\TestCase;
class AndTest extends TestCase
class AndTest extends AllSetupTeardown
{
protected function setUp(): void
{
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
}
/**
* @dataProvider providerAND
*
@@ -20,8 +11,7 @@ class AndTest extends TestCase
*/
public function testAND($expectedResult, ...$args): void
{
$result = Logical::logicalAnd(...$args);
self::assertEquals($expectedResult, $result);
$this->runTestCase('AND', $expectedResult, ...$args);
}
public function providerAND(): array
@@ -0,0 +1,30 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Logical;
use PhpOffice\PhpSpreadsheet\Calculation\Logical;
use PHPUnit\Framework\TestCase;
// Sanity tests for functions which have been moved out of Functions
// to their own classes. A deprecated version remains in Functions;
// this class contains cursory tests to ensure that those work properly.
// If Scrutinizer fails the PR because of these deprecations, I will
// remove this class from the PR.
class DeprecatedFunctionsTest extends TestCase
{
public function testDeprecated(): void
{
self::assertFalse(/** @scrutinizer ignore-deprecated */ Logical::false());
self::assertFalse(/** @scrutinizer ignore-deprecated */ Logical::logicalAnd(true, false));
self::assertTrue(/** @scrutinizer ignore-deprecated */ Logical::NOT(false));
self::assertTrue(/** @scrutinizer ignore-deprecated */ Logical::logicalOr(true, false));
self::assertTrue(/** @scrutinizer ignore-deprecated */ Logical::logicalXor(true, false));
self::assertTrue(/** @scrutinizer ignore-deprecated */ Logical::true());
self::assertFalse(/** @scrutinizer ignore-deprecated */ Logical::statementIf(false));
self::assertSame('error', /** @scrutinizer ignore-deprecated */ Logical::IFERROR('#VALUE!', 'error'));
self::assertSame('#VALUE!', /** @scrutinizer ignore-deprecated */ Logical::IFNA('#VALUE!', 'error'));
self::assertSame('two', /** @scrutinizer ignore-deprecated */ Logical::IFS(false, 'one', true, 'two', true, 'three'));
self::assertSame(31, /** @scrutinizer ignore-deprecated */ Logical::statementSwitch(30, 10, 11, 20, 21, 30, 31, 40, 41));
}
}
@@ -2,20 +2,10 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Logical;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Calculation\Logical;
use PHPUnit\Framework\TestCase;
class FalseTest extends TestCase
class FalseTest extends AllSetupTeardown
{
protected function setUp(): void
{
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
}
public function testFALSE(): void
{
$result = Logical::FALSE();
self::assertFalse($result);
$this->runTestCase('FALSE', false);
}
}
@@ -3,28 +3,17 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Logical;
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Calculation\Logical;
use PHPUnit\Framework\TestCase;
class IfErrorTest extends TestCase
class IfErrorTest extends AllSetupTeardown
{
protected function setUp(): void
{
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
}
/**
* @dataProvider providerIFERROR
*
* @param mixed $expectedResult
* @param mixed $value
* @param mixed $return
*/
public function testIFERROR($expectedResult, $value, $return): void
public function testIFERROR($expectedResult, ...$args): void
{
$result = Logical::IFERROR($value, $return);
self::assertEquals($expectedResult, $result);
$this->runTestCase('IFERROR', $expectedResult, ...$args);
}
public function providerIFERROR(): array
@@ -3,28 +3,17 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Logical;
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Calculation\Logical;
use PHPUnit\Framework\TestCase;
class IfNaTest extends TestCase
class IfNaTest extends AllSetupTeardown
{
protected function setUp(): void
{
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
}
/**
* @dataProvider providerIFNA
*
* @param mixed $expectedResult
* @param mixed $value
* @param mixed $return
*/
public function testIFNA($expectedResult, $value, $return): void
public function testIFNA($expectedResult, ...$args): void
{
$result = Logical::IFNA($value, $return);
self::assertEquals($expectedResult, $result);
$this->runTestCase('IFNA', $expectedResult, ...$args);
}
public function providerIFNA(): array
@@ -2,10 +2,7 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Logical;
use PhpOffice\PhpSpreadsheet\Calculation\Logical;
use PHPUnit\Framework\TestCase;
class IfTest extends TestCase
class IfTest extends AllSetupTeardown
{
/**
* @dataProvider providerIF
@@ -14,16 +11,7 @@ class IfTest extends TestCase
*/
public function testIF($expectedResult, ...$args): void
{
if (count($args) === 0) {
$result = Logical::statementIf();
} elseif (count($args) === 1) {
$result = Logical::statementIf($args[0]);
} elseif (count($args) === 2) {
$result = Logical::statementIf($args[0], $args[1]);
} else {
$result = Logical::statementIf($args[0], $args[1], $args[2]);
}
self::assertEquals($expectedResult, $result);
$this->runTestCase('IF', $expectedResult, ...$args);
}
public function providerIF(): array
@@ -2,17 +2,10 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Logical;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Calculation\Logical;
use PHPUnit\Framework\TestCase;
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
class IfsTest extends TestCase
class IfsTest extends AllSetupTeardown
{
protected function setUp(): void
{
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
}
/**
* @dataProvider providerIFS
*
@@ -21,12 +14,43 @@ class IfsTest extends TestCase
*/
public function testIFS($expectedResult, ...$args): void
{
$result = Logical::IFS(...$args);
self::assertEquals($expectedResult, $result);
$this->runTestCase('IFS', $expectedResult, ...$args);
}
public function providerIFS(): array
{
return require 'tests/data/Calculation/Logical/IFS.php';
}
/**
* @dataProvider providerIfsArray
*/
public function testIfsArray(array $expectedResult, string $bool1, string $argument1, string $bool2, string $argument2): void
{
$calculation = Calculation::getInstance();
$formula = "=IFS($bool1, {" . "$argument1}, $bool2, {" . "$argument2})";
$result = $calculation->_calculateFormulaValue($formula);
self::assertEquals($expectedResult, $result);
}
public function providerIfsArray(): array
{
return [
'array return first item' => [
[[1, 2, 3]],
'true',
'1, 2, 3',
'true',
'4, 5, 6',
],
'array return second item' => [
[[4, 5, 6]],
'false',
'1, 2, 3',
'true',
'4, 5, 6',
],
];
}
}
@@ -3,10 +3,8 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Logical;
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
use PhpOffice\PhpSpreadsheet\Calculation\Logical;
use PHPUnit\Framework\TestCase;
class NotTest extends TestCase
class NotTest extends AllSetupTeardown
{
/**
* @dataProvider providerNOT
@@ -15,12 +13,7 @@ class NotTest extends TestCase
*/
public function testNOT($expectedResult, ...$args): void
{
if (count($args) === 0) {
$result = Logical::NOT();
} else {
$result = Logical::NOT($args[0]);
}
self::assertEquals($expectedResult, $result);
$this->runTestCase('NOT', $expectedResult, ...$args);
}
public function providerNOT(): array
@@ -2,17 +2,8 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Logical;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Calculation\Logical;
use PHPUnit\Framework\TestCase;
class OrTest extends TestCase
class OrTest extends AllSetupTeardown
{
protected function setUp(): void
{
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
}
/**
* @dataProvider providerOR
*
@@ -20,8 +11,7 @@ class OrTest extends TestCase
*/
public function testOR($expectedResult, ...$args): void
{
$result = Logical::logicalOr(...$args);
self::assertEquals($expectedResult, $result);
$this->runTestCase('OR', $expectedResult, ...$args);
}
public function providerOR(): array
@@ -2,17 +2,10 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Logical;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Calculation\Logical;
use PHPUnit\Framework\TestCase;
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
class SwitchTest extends TestCase
class SwitchTest extends AllSetupTeardown
{
protected function setUp(): void
{
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
}
/**
* @dataProvider providerSwitch
*
@@ -20,12 +13,51 @@ class SwitchTest extends TestCase
*/
public function testSWITCH($expectedResult, ...$args): void
{
$result = Logical::statementSwitch(...$args);
self::assertEquals($expectedResult, $result);
$this->runTestCase('SWITCH', $expectedResult, ...$args);
}
public function providerSwitch(): array
{
return require 'tests/data/Calculation/Logical/SWITCH.php';
}
/**
* @dataProvider providerSwitchArray
*
* @param mixed $expression
* @param mixed $value1
* @param mixed $value2
*/
public function testIfsArray(array $expectedResult, $expression, $value1, string $result1, $value2, string $result2, string $default): void
{
$calculation = Calculation::getInstance();
$formula = "=SWITCH($expression, $value1, {" . "$result1}, $value2, {" . "$result2}, {" . "$default})";
$result = $calculation->_calculateFormulaValue($formula);
self::assertEquals($expectedResult, $result);
}
public function providerSwitchArray(): array
{
return [
'Array return' => [
[[4, 5, 6]],
2,
1,
'1, 2, 3',
2,
'4, 5, 6',
'7, 8, 9',
],
'Array return default' => [
[[7, 8, 9]],
3,
1,
'1, 2, 3',
2,
'4, 5, 6',
'7, 8, 9',
],
];
}
}
@@ -2,20 +2,10 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Logical;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Calculation\Logical;
use PHPUnit\Framework\TestCase;
class TrueTest extends TestCase
class TrueTest extends AllSetupTeardown
{
protected function setUp(): void
{
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
}
public function testTRUE(): void
{
$result = Logical::TRUE();
self::assertTrue($result);
$this->runTestCase('TRUE', true);
}
}
@@ -2,17 +2,8 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Logical;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Calculation\Logical;
use PHPUnit\Framework\TestCase;
class XorTest extends TestCase
class XorTest extends AllSetupTeardown
{
protected function setUp(): void
{
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
}
/**
* @dataProvider providerXOR
*
@@ -20,8 +11,7 @@ class XorTest extends TestCase
*/
public function testXOR($expectedResult, ...$args): void
{
$result = Logical::logicalXor(...$args);
self::assertEquals($expectedResult, $result);
$this->runTestCase('XOR', $expectedResult, ...$args);
}
public function providerXOR(): array
+2 -3
View File
@@ -1,9 +1,8 @@
<?php
return [
// No arguments
[
'#VALUE!',
'no arguments' => [
'exception',
],
// NULL
[
+10 -8
View File
@@ -1,27 +1,29 @@
<?php
return [
[
0,
'no arguments' => [
'exception',
],
[
0,
'1 argument true' => [
'exception',
true,
],
[
false,
'1 argument false' => [
'exception',
false,
],
[
'value_if_false omitted condtion is true' => [
'ABC',
true,
'ABC',
],
[
'value_if_false omitted condition is false' => [
false,
false,
'ABC',
],
'value_if_true omitted condition is true' => [0, true, null, 'error'],
'value_if_true omitted condition is false' => ['error', false, null, 'error'],
[
'ABC',
true,
+2 -2
View File
@@ -1,8 +1,8 @@
<?php
return [
[
null,
'empty cell treated as 0' => [
0,
null,
'Error',
],
+2
View File
@@ -9,4 +9,6 @@ return [
'not found',
'#N/A', 'not found',
],
'non-NA error' => ['#VALUE!', '#VALUE!', 'not found'],
'empty cell treated as 0' => [0, null, 'Error'],
];
+1 -10
View File
@@ -1,9 +1,7 @@
<?php
return [
[
'#N/A',
],
'no arguments' => ['exception'],
[
1,
true,
@@ -47,11 +45,4 @@ return [
true,
'ABC',
],
'array return' => [
[[4, 5, 6]],
false,
[[1, 2, 3]],
true,
[[4, 5, 6]],
],
];
+2 -2
View File
@@ -1,8 +1,8 @@
<?php
return [
[
true,
'no arguments' => [
'exception',
],
[
true,
+2 -3
View File
@@ -1,9 +1,8 @@
<?php
return [
// No arguments
[
'#VALUE!',
'no arguments' => [
'exception',
],
// NULL
[
+5 -30
View File
@@ -1,8 +1,7 @@
<?php
return [
// Must be C
[
'match value1 A result is C' => [
'C',
'A',
'A',
@@ -11,8 +10,7 @@ return [
'D',
'??',
],
// Must be Female
[
'match value2 2 result is female' => [
'Female',
2,
'1',
@@ -20,8 +18,7 @@ return [
'2',
'Female',
],
// Must be X using default
[
'defined default value' => [
'X',
'U',
'ABC',
@@ -30,8 +27,7 @@ return [
'Z',
'X',
],
// Must be N/A default value not defined
[
'undefined default value' => [
'#N/A',
'U',
'ABC',
@@ -39,26 +35,5 @@ return [
'DEF',
'Z',
],
'Array return' => [
[[4, 5, 6]],
2,
1,
[[1, 2, 3]],
2,
[[4, 5, 6]],
[[7, 8, 9]],
],
'Array return as default' => [
[[7, 8, 9]],
3,
1,
[[1, 2, 3]],
2,
[[4, 5, 6]],
[[7, 8, 9]],
],
// Must be value - no parameter
[
'#VALUE!',
],
'no arguments' => ['exception'],
];
+2 -3
View File
@@ -1,9 +1,8 @@
<?php
return [
// No arguments
[
'#VALUE!',
'no arguments' => [
'exception',
],
[
false,